[gtk/matthiasc/lottie] path: Deserialize
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/matthiasc/lottie] path: Deserialize
- Date: Mon, 23 Nov 2020 06:10:18 +0000 (UTC)
commit e2f8231ca1a3e529574f5e0f45f5039ade9b9047
Author: Matthias Clasen <mclasen redhat com>
Date: Mon Nov 23 00:43:37 2020 -0500
path: Deserialize
Implement enough of a parse for the SVG path syntax
to read back the strings that we generate when
serializing paths. This is very far from complete.
gsk/gskpath.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++
gsk/gskpathprivate.h | 2 +
gsk/gskrendernodeparser.c | 22 +++++++-
3 files changed, 158 insertions(+), 3 deletions(-)
---
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index b1ec0c8665..6187527feb 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -1919,3 +1919,140 @@ gsk_path_builder_close (GskPathBuilder *builder)
gsk_path_builder_end_current (builder);
}
+static const char *
+skip_whitespace (const char *p)
+{
+ while (g_ascii_isspace (*p))
+ p++;
+ return p;
+}
+
+static void
+parse_point (const char *p,
+ char **end,
+ double *x,
+ double *y)
+{
+ char *e;
+ *x = g_ascii_strtod (p, &e);
+ *y = g_ascii_strtod (e, end);
+}
+
+GskPath *
+gsk_path_from_string (const char *s)
+{
+ GskPathBuilder *builder;
+ double x0, y0, x1, y1, x2, y2;
+ double w, h, r;
+ const char *p;
+ char *end;
+ int i;
+
+ builder = gsk_path_builder_new ();
+
+ /* Commands that we produce:
+ * M x y h w v h h -w z (rectangle)
+ * M x y A r r 0 i i x1 y1 (circle)
+ * M x y (move)
+ * Z (close)
+ * L x y (line)
+ * C x0 y0, x1 y1, x2 y2 (curve)
+ */
+ p = s;
+ while (p)
+ {
+ p = skip_whitespace (p);
+ if (*p == '\0')
+ break;
+
+ switch (*p)
+ {
+ case 'M':
+ p++;
+ parse_point (p, &end, &x0, &y0);
+ p = skip_whitespace (end);
+ switch (*p)
+ {
+ case 'h':
+ p++;
+ w = g_ascii_strtod (p, &end);
+ p = skip_whitespace (end);
+ if (*p != 'v')
+ goto error;
+ p++;
+ h = g_ascii_strtod (p, &end);
+ p = skip_whitespace (end);
+ if (*p != 'h')
+ goto error;
+ p++;
+ g_ascii_strtod (p, &end);
+ p = skip_whitespace (end);
+ if (*p != 'z')
+ goto error;
+ p++;
+
+ gsk_path_builder_add_rect (builder, x0, y0, w, h);
+ break;
+
+ case 'A':
+ p++;
+ parse_point (p, &end, &r, &r);
+ p = skip_whitespace (end);
+ /* FIXME reconstruct partial circles */
+ for (i = 0; i < 5; i++)
+ {
+ g_ascii_strtod (p, &end);
+ p = skip_whitespace (end);
+ }
+
+ gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (x0 - r, y0), r);
+ break;
+
+ default:
+ gsk_path_builder_move_to (builder, x0, y0);
+ break;
+ }
+ break;
+
+ case 'Z':
+ p++;
+ gsk_path_builder_close (builder);
+ break;
+
+ case 'L':
+ p++;
+ parse_point (p, &end, &x0, &y0);
+ p = skip_whitespace (end);
+
+ gsk_path_builder_line_to (builder, x0, y0);
+ break;
+
+ case 'C':
+ p++;
+ parse_point (p, &end, &x0, &y0);
+ p = skip_whitespace (end);
+ if (*p == ',')
+ p++;
+ parse_point (p, &end, &x1, &y1);
+ p = skip_whitespace (end);
+ if (*p == ',')
+ p++;
+ parse_point (p, &end, &x2, &y2);
+ p = skip_whitespace (end);
+
+ gsk_path_builder_curve_to (builder, x0, y0, x1, y1, x2, y2);
+ break;
+
+ default:
+ goto error;
+ }
+ }
+
+ return gsk_path_builder_free_to_path (builder);
+
+error:
+ g_warning ("Can't parse string as GskPath, error at %ld", p - s);
+ gsk_path_builder_unref (builder);
+
+ return NULL;
+}
diff --git a/gsk/gskpathprivate.h b/gsk/gskpathprivate.h
index 7af9dbcaff..101db67423 100644
--- a/gsk/gskpathprivate.h
+++ b/gsk/gskpathprivate.h
@@ -58,6 +58,8 @@ void gsk_path_builder_add_contour_segment (GskPathBuilder
float start,
float end);
+GskPath * gsk_path_from_string (const char *string);
+
G_END_DECLS
#endif /* __GSK_PATH_PRIVATE_H__ */
diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c
index 613b503bcc..ca2f7a0a41 100644
--- a/gsk/gskrendernodeparser.c
+++ b/gsk/gskrendernodeparser.c
@@ -24,6 +24,7 @@
#include "gskrendernodeparserprivate.h"
#include "gskpath.h"
+#include "gskpathprivate.h"
#include "gskroundedrectprivate.h"
#include "gskrendernodeprivate.h"
#include "gskstroke.h"
@@ -1732,7 +1733,22 @@ static gboolean
parse_path (GtkCssParser *parser,
gpointer out_path)
{
- return FALSE;
+ char *str = NULL;
+
+ if (!parse_string (parser, &str))
+ return FALSE;
+
+ *((GskPath **) out_path) = gsk_path_from_string (str);
+
+ g_free (str);
+
+ return TRUE;
+}
+
+static void
+clear_path (gpointer inout_path)
+{
+ g_clear_pointer ((GskPath **) inout_path, gsk_path_unref);
}
static gboolean
@@ -1789,7 +1805,7 @@ parse_fill_node (GtkCssParser *parser)
GskFillRule rule = GSK_FILL_RULE_WINDING;
const Declaration declarations[] = {
{ "child", parse_node, clear_node, &child },
- { "path", parse_path, NULL, &path },
+ { "path", parse_path, clear_path, &path },
{ "fill-rule", parse_fill_rule, NULL, &rule },
};
GskRenderNode *result;
@@ -1817,7 +1833,7 @@ parse_stroke_node (GtkCssParser *parser)
const Declaration declarations[] = {
{ "child", parse_node, clear_node, &child },
- { "path", parse_path, NULL, &path },
+ { "path", parse_path, clear_path, &path },
{ "line-width", parse_double, NULL, &line_width },
{ "line-cap", parse_line_cap, NULL, &line_cap },
{ "line-join", parse_line_join, NULL, &line_join },
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]