[gtk/matthiasc/lottie] path: Deserialize



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]