[gtk/wip/otte/lottie: 42/46] path: Special-case rects and circles
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/lottie: 42/46] path: Special-case rects and circles
- Date: Mon, 30 Nov 2020 07:59:35 +0000 (UTC)
commit 1aa87e045ac84619fcc7879c589c494aea5e39d9
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Nov 25 01:03:13 2020 -0500
path: Special-case rects and circles
Write out the commands for rects and circles in a special
way, and add code in the parser to recognize this, so we
can successfully round-trip these through the SVG path format.
The special way - for people who want to use it for debugging -
for now is that we use uppercase "Z" to close standard paths, but
lowercase "z" to close our special paths.
A test is included, but the random path serializations should take care
of it, too.
gsk/gskpath.c | 101 ++++++++++++++++++++++++++++++++++++-
testsuite/gsk/path-special-cases.c | 31 ++++++++++++
2 files changed, 130 insertions(+), 2 deletions(-)
---
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index 43000b759a..9f42c4dff4 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -2186,6 +2186,81 @@ parse_command (const char **p,
return FALSE;
}
+static gboolean
+parse_string (const char **p,
+ const char *s)
+{
+ int len = strlen (s);
+ if (strncmp (*p, s, len) != 0)
+ return FALSE;
+ (*p) += len;
+ return TRUE;
+}
+
+static gboolean
+parse_rectangle (const char **p,
+ double *x,
+ double *y,
+ double *w,
+ double *h)
+{
+ const char *o = *p;
+ double w2;
+
+ /* Check for M%g,%gh%gv%gh%gz without any intervening whitespace */
+ if (parse_coordinate_pair (p, x, y) &&
+ parse_string (p, "h") &&
+ parse_coordinate (p, w) &&
+ parse_string (p, "v") &&
+ parse_coordinate (p, h) &&
+ parse_string (p, "h") &&
+ parse_coordinate (p, &w2) &&
+ parse_string (p, "z") &&
+ w2 == - *w)
+ {
+ skip_whitespace (p);
+
+ return TRUE;
+ }
+
+ *p = o;
+ return FALSE;
+}
+
+static gboolean
+parse_circle (const char **p,
+ double *sx,
+ double *sy,
+ double *r)
+{
+ const char *o = *p;
+ double r1, r2, r3, mx, my, ex, ey;
+
+ /* Check for M%g,%gA%g,%g,0,1,0,%g,%gA%g,%g,0,1,0,%g,%g
+ * without any intervening whitespace
+ */
+ if (parse_coordinate_pair (p, sx, sy) &&
+ parse_string (p, "A") &&
+ parse_coordinate_pair (p, r, &r1) &&
+ parse_string (p, "0 0 0") &&
+ parse_coordinate_pair (p, &mx, &my) &&
+ parse_string (p, "A") &&
+ parse_coordinate_pair (p, &r2, &r3) &&
+ parse_string (p, "0 0 0") &&
+ parse_coordinate_pair (p, &ex, &ey) &&
+ parse_string (p, "z") &&
+ *r == r1 && r1 == r2 && r2 == r3 &&
+ *sx == ex && *sy == ey)
+ {
+ skip_whitespace (p);
+
+ return TRUE;
+ }
+
+ *p = o;
+ return FALSE;
+}
+
/**
* gsk_path_parse:
* @string: a string
@@ -2247,9 +2322,31 @@ gsk_path_parse (const char *string)
case 'M':
case 'm':
{
- double x1, y1;
+ double x1, y1, w, h, r;
- if (parse_coordinate_pair (&p, &x1, &y1))
+ if (parse_rectangle (&p, &x1, &y1, &w, &h))
+ {
+ gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (x1, y1, w, h));
+ if (strchr ("zZX", prev_cmd))
+ {
+ path_x = x1;
+ path_y = y1;
+ }
+ x = x1;
+ y = y1;
+ }
+ else if (parse_circle (&p, &x1, &y1, &r))
+ {
+ gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (x1 - r, y1), r);
+ if (strchr ("zZX", prev_cmd))
+ {
+ path_x = x1;
+ path_y = y1;
+ }
+ x = x1;
+ y = y1;
+ }
+ else if (parse_coordinate_pair (&p, &x1, &y1))
{
if (cmd == 'm')
{
diff --git a/testsuite/gsk/path-special-cases.c b/testsuite/gsk/path-special-cases.c
index 23f08d59d0..04a575ac1f 100644
--- a/testsuite/gsk/path-special-cases.c
+++ b/testsuite/gsk/path-special-cases.c
@@ -276,6 +276,36 @@ test_rsvg_parse (void)
}
}
+/* Test that circles and rectangles serialize as expected and can be
+ * round-tripped through strings.
+ */
+static void
+test_serialize_custom_contours (void)
+{
+ GskPathBuilder *builder;
+ GskPath *path;
+ GskPath *path1;
+ char *string;
+ char *string1;
+
+ builder = gsk_path_builder_new ();
+ gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (100, 100), 50);
+ gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (111, 222, 333, 444));
+ path = gsk_path_builder_free_to_path (builder);
+
+ string = gsk_path_to_string (path);
+ g_assert_cmpstr ("M 150 100 A 50 50 0 0 0 50 100 A 50 50 0 0 0 150 100 z M 111 222 h 333 v 444 h -333 z",
==, string);
+
+ path1 = gsk_path_parse (string);
+ string1 = gsk_path_to_string (path1);
+ g_assert_cmpstr (string, ==, string1);
+
+ g_free (string);
+ g_free (string1);
+ gsk_path_unref (path);
+ gsk_path_unref (path1);
+}
+
int
main (int argc,
char *argv[])
@@ -283,6 +313,7 @@ main (int argc,
gtk_test_init (&argc, &argv, NULL);
g_test_add_func ("/path/rsvg-parse", test_rsvg_parse);
+ g_test_add_func ("/path/serialize-custom-contours", test_serialize_custom_contours);
return g_test_run ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]