[gtk/wip/otte/lottie: 12/17] path: Change data structure for standard path



commit 12dad94553248d6671db3be0d6d6086d602fafbe
Author: Benjamin Otte <otte redhat com>
Date:   Sun Nov 15 15:58:59 2020 +0100

    path: Change data structure for standard path
    
    Instead of the Cairo method and imitating cairo_path_data_t, use the
    Skia method and keep points and operations separate.
    
    That way we get a points array that includes the starting point -
    because it's always the end point of the previous operation.

 gsk/gskpath.c | 232 ++++++++++++++++++++++++++++++----------------------------
 1 file changed, 119 insertions(+), 113 deletions(-)
---
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index c2e52d3199..b446f1fd69 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -161,43 +161,37 @@ gsk_rect_contour_init (GskContour *contour,
 
 typedef enum
 {
-  GSK_PATH_VERB_MOVE,
-  GSK_PATH_VERB_CLOSE,
-  GSK_PATH_VERB_LINE,
-  GSK_PATH_VERB_CURVE,
-} GskPathVerb;
+  GSK_PATH_MOVE,
+  GSK_PATH_CLOSE,
+  GSK_PATH_LINE,
+  GSK_PATH_CURVE,
+} GskPathOperation;
 
-typedef union {
-  GskPathVerb verb;
-  graphene_point_t point;
-} GskStandardPoint;
+typedef struct _GskStandardOperation GskStandardOperation;
+
+struct _GskStandardOperation {
+  GskPathOperation op;
+  gsize point; /* index into points array of the start point (last point of previous op) */
+};
 
 typedef struct _GskStandardContour GskStandardContour;
 struct _GskStandardContour
 {
   GskContour contour;
 
+  gsize n_ops;
   gsize n_points;
-  GskStandardPoint path[];
+  graphene_point_t *points;
+  GskStandardOperation ops[];
 };
 
 static gsize
-gsk_path_verb_n_elements (GskPathVerb verb)
+gsk_standard_contour_compute_size (gsize n_ops,
+                                   gsize n_points)
 {
-  switch (verb)
-  {
-    case GSK_PATH_VERB_MOVE:
-    case GSK_PATH_VERB_LINE:
-    case GSK_PATH_VERB_CLOSE:
-      return 2;
-
-    case GSK_PATH_VERB_CURVE:
-      return 4;
-
-    default:
-      g_assert_not_reached();
-      return 0;
-  }
+  return sizeof (GskStandardContour)
+       + sizeof (GskStandardOperation) * n_ops
+       + sizeof (graphene_point_t) * n_points;
 }
 
 static gsize
@@ -205,7 +199,7 @@ gsk_standard_contour_get_size (const GskContour *contour)
 {
   const GskStandardContour *self = (const GskStandardContour *) contour;
 
-  return sizeof (GskStandardContour) + sizeof (GskStandardPoint) * self->n_points;
+  return gsk_standard_contour_compute_size (self->n_ops, self->n_points);
 }
 
 static void
@@ -215,27 +209,29 @@ gsk_standard_contour_print (const GskContour *contour,
   const GskStandardContour *self = (const GskStandardContour *) contour;
   gsize i;
 
-  for (i = 0; i < self->n_points; i += gsk_path_verb_n_elements (self->path[i].verb))
+  for (i = 0; i < self->n_ops; i ++)
     {
-      switch (self->path[i].verb)
+      graphene_point_t *pt = &self->points [self->ops[i].point];
+
+      switch (self->ops[i].op)
       {
-        case GSK_PATH_VERB_MOVE:
-          g_string_append_printf (string, "M %g %g", self->path[i + 1].point.x, self->path[i + 1].point.y);
+        case GSK_PATH_MOVE:
+          g_string_append_printf (string, "M %g %g", pt[0].x, pt[0].y);
           break;
 
-        case GSK_PATH_VERB_CLOSE:
+        case GSK_PATH_CLOSE:
           g_string_append (string, " Z");
           break;
 
-        case GSK_PATH_VERB_LINE:
-          g_string_append_printf (string, " L %g %g", self->path[i + 1].point.x, self->path[i + 1].point.y);
+        case GSK_PATH_LINE:
+          g_string_append_printf (string, " L %g %g", pt[1].x, pt[1].y);
           break;
 
-        case GSK_PATH_VERB_CURVE:
+        case GSK_PATH_CURVE:
           g_string_append_printf (string, " C %g %g, %g %g, %g %g",
-                                  self->path[i + 1].point.x, self->path[i + 1].point.y,
-                                  self->path[i + 2].point.x, self->path[i + 2].point.y,
-                                  self->path[i + 3].point.x, self->path[i + 3].point.y);
+                                  pt[1].x, pt[1].y,
+                                  pt[2].x, pt[2].y,
+                                  pt[3].x, pt[3].y);
           break;
 
         default:
@@ -254,27 +250,26 @@ gsk_standard_contour_to_cairo (const GskContour *contour,
 
   cairo_new_sub_path (cr);
 
-  for (i = 0; i < self->n_points; i += gsk_path_verb_n_elements (self->path[i].verb))
+  for (i = 0; i < self->n_ops; i ++)
     {
-      switch (self->path[i].verb)
+      graphene_point_t *pt = &self->points [self->ops[i].point];
+
+      switch (self->ops[i].op)
       {
-        case GSK_PATH_VERB_MOVE:
-          cairo_move_to (cr, self->path[i + 1].point.x, self->path[i + 1].point.y);
+        case GSK_PATH_MOVE:
+          cairo_move_to (cr, pt[0].x, pt[0].y);
           break;
 
-        case GSK_PATH_VERB_CLOSE:
+        case GSK_PATH_CLOSE:
           cairo_close_path (cr);
           break;
 
-        case GSK_PATH_VERB_LINE:
-          cairo_line_to (cr, self->path[i + 1].point.x, self->path[i + 1].point.y);
+        case GSK_PATH_LINE:
+          cairo_line_to (cr, pt[1].x, pt[1].y);
           break;
 
-        case GSK_PATH_VERB_CURVE:
-          cairo_curve_to (cr,
-                          self->path[i + 1].point.x, self->path[i + 1].point.y,
-                          self->path[i + 2].point.x, self->path[i + 2].point.y,
-                          self->path[i + 3].point.x, self->path[i + 3].point.y);
+        case GSK_PATH_CURVE:
+          cairo_curve_to (cr, pt[1].x, pt[1].y, pt[2].x, pt[2].y, pt[3].x, pt[3].y);
           break;
 
         default:
@@ -316,33 +311,16 @@ gsk_standard_contour_get_bounds (const GskContour *contour,
   const GskStandardContour *self = (const GskStandardContour *) contour;
   gsize i;
 
-  for (i = 0; i < self->n_points; i += gsk_path_verb_n_elements (self->path[i].verb))
-    {
-      switch (self->path[i].verb)
-      {
-        case GSK_PATH_VERB_MOVE:
-          graphene_rect_init (bounds,
-                              self->path[i + 1].point.x, self->path[i + 1].point.y,
-                              0, 0);
-          break;
-
-        case GSK_PATH_VERB_CLOSE:
-          break;
-
-        case GSK_PATH_VERB_LINE:
-          rect_add_point (bounds, &self->path[i + 1].point);
-          break;
+  if (self->n_points == 0)
+    return FALSE;
 
-        case GSK_PATH_VERB_CURVE:
-          rect_add_point (bounds, &self->path[i + 1].point);
-          rect_add_point (bounds, &self->path[i + 2].point);
-          rect_add_point (bounds, &self->path[i + 3].point);
-          break;
+  graphene_rect_init (bounds,
+                      self->points[0].x, self->points[0].y,
+                      0, 0);
 
-        default:
-          g_assert_not_reached();
-          return FALSE;
-      }
+  for (i = 1; i < self->n_points; i ++)
+    {
+      rect_add_point (bounds, &self->points[i]);
     }
 
   return bounds->size.width > 0 && bounds->size.height > 0;
@@ -358,10 +336,25 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
   gsk_standard_contour_get_bounds
 };
 
+/* You must ensure the contour has enough size allocated,
+ * see gsk_standard_contour_compute_size()
+ */
 static void
-gsk_standard_contour_init (GskContour *contour)
+gsk_standard_contour_init (GskContour *contour,
+                           const GskStandardOperation *ops,
+                           gsize n_ops,
+                           const graphene_point_t *points,
+                           gsize n_points)
 {
-  contour->klass = &GSK_STANDARD_CONTOUR_CLASS;
+  GskStandardContour *self = (GskStandardContour *) contour;
+
+  self->contour.klass = &GSK_STANDARD_CONTOUR_CLASS;
+
+  self->n_ops = n_ops;
+  memcpy (self->ops, ops, sizeof (GskStandardOperation) * n_ops);
+  self->n_points = n_points;
+  self->points = (graphene_point_t *) &self->ops[n_ops];
+  memcpy (self->points, points, sizeof (graphene_point_t) * n_points);
 }
 
 /* PATH */
@@ -672,8 +665,10 @@ struct _GskPathBuilder
 {
   int ref_count;
 
-  GSList *contours;
-  GskStandardContour *current;
+  GSList *contours; /* (reverse) list of already recorded contours */
+
+  GArray *ops; /* operations for current contour - size == 0 means no current contour */
+  GArray *points; /* points for the operations */
 };
 
 G_DEFINE_BOXED_TYPE (GskPathBuilder,
@@ -699,6 +694,8 @@ gsk_path_builder_new (void)
   builder = g_slice_new0 (GskPathBuilder);
   builder->ref_count = 1;
 
+  builder->ops = g_array_new (FALSE, FALSE, sizeof (GskStandardOperation));
+  builder->points = g_array_new (FALSE, FALSE, sizeof (graphene_point_t));
   return builder;
 }
 
@@ -726,28 +723,37 @@ gsk_path_builder_ref (GskPathBuilder *builder)
 }
 
 static void
-gsk_path_builder_append_current (GskPathBuilder   *builder,
-                                 gsize             n_points,
-                                 GskStandardPoint *points)
+gsk_path_builder_append_current (GskPathBuilder         *builder,
+                                 GskPathOperation        op,
+                                 gsize                   n_points,
+                                 const graphene_point_t *points)
 {
-  gsize size;
-
-  g_assert (builder->current);
+  g_assert (builder->ops->len > 0);
+  g_assert (builder->points->len > 0);
+  g_assert (n_points > 0);
 
-  size = sizeof (GskStandardContour) + sizeof (GskStandardPoint) * builder->current->n_points;
-  builder->current = g_realloc (builder->current, size + sizeof (GskStandardPoint) * n_points);
-  memcpy ((guint8 *) builder->current + size, points, sizeof (GskStandardPoint) * n_points);
-  builder->current->n_points += n_points;
+  g_array_append_vals (builder->ops, &(GskStandardOperation) { op, builder->points->len - 1 }, 1);
+  g_array_append_vals (builder->points, points, n_points);
 }
 
 static void
 gsk_path_builder_end_current (GskPathBuilder *builder)
 {
-  if (builder->current == NULL)
+  GskContour *contour;
+
+  if (builder->ops->len == 0)
    return;
 
-  builder->contours = g_slist_prepend (builder->contours, builder->current);
-  builder->current = NULL;
+  contour = g_malloc0 (gsk_standard_contour_compute_size (builder->ops->len, builder->points->len));
+  gsk_standard_contour_init (contour,
+                             (GskStandardOperation *) builder->ops->data,
+                             builder->ops->len,
+                             (graphene_point_t *) builder->points->data,
+                             builder->points->len);
+  builder->contours = g_slist_prepend (builder->contours, contour);
+
+  g_array_set_size (builder->ops, 0);
+  g_array_set_size (builder->points, 0);
 }
 
 static void
@@ -777,6 +783,8 @@ gsk_path_builder_unref (GskPathBuilder *builder)
     return;
 
   gsk_path_builder_clear (builder);
+  g_array_unref (builder->ops);
+  g_array_unref (builder->points);
   g_slice_free (GskPathBuilder, builder);
 }
 
@@ -901,18 +909,12 @@ gsk_path_builder_move_to (GskPathBuilder *builder,
                           float           x,
                           float           y)
 {
-  gsize size;
-
   g_return_if_fail (builder != NULL);
 
   gsk_path_builder_end_current (builder);
 
-  size = GSK_STANDARD_CONTOUR_CLASS.struct_size + 2 * sizeof (GskStandardPoint);
-  builder->current = g_malloc0 (size);
-  gsk_standard_contour_init ((GskContour *) builder->current);
-  builder->current->n_points = 2;
-  builder->current->path[0].verb = GSK_PATH_VERB_MOVE;
-  builder->current->path[1].point = GRAPHENE_POINT_INIT (x, y);
+  g_array_append_vals (builder->ops, &(GskStandardOperation) { GSK_PATH_MOVE, 0 }, 1);
+  g_array_append_val (builder->points, GRAPHENE_POINT_INIT(x, y));
 }
 
 void
@@ -922,15 +924,16 @@ gsk_path_builder_line_to (GskPathBuilder *builder,
 {
   g_return_if_fail (builder != NULL);
 
-  if (builder->current == NULL)
+  if (builder->ops->len == 0)
     {
       gsk_path_builder_move_to (builder, x, y);
       return;
     }
 
-  gsk_path_builder_append_current (builder, 2, (GskStandardPoint[2]) {
-                                     { .verb = GSK_PATH_VERB_LINE },
-                                     { .point = GRAPHENE_POINT_INIT (x, y) }
+  gsk_path_builder_append_current (builder,
+                                   GSK_PATH_LINE,
+                                   1, (graphene_point_t[1]) {
+                                     GRAPHENE_POINT_INIT (x, y)
                                    });
 }
 
@@ -945,14 +948,15 @@ gsk_path_builder_curve_to (GskPathBuilder *builder,
 {
   g_return_if_fail (builder != NULL);
 
-  if (builder->current == NULL)
+  if (builder->ops->len == 0)
     gsk_path_builder_move_to (builder, x1, y1);
 
-  gsk_path_builder_append_current (builder, 4, (GskStandardPoint[4]) {
-                                     { .verb = GSK_PATH_VERB_CURVE },
-                                     { .point = GRAPHENE_POINT_INIT (x1, y1) },
-                                     { .point = GRAPHENE_POINT_INIT (x2, y2) },
-                                     { .point = GRAPHENE_POINT_INIT (x3, y3) }
+  gsk_path_builder_append_current (builder,
+                                   GSK_PATH_CURVE,
+                                   3, (graphene_point_t[3]) {
+                                     GRAPHENE_POINT_INIT (x1, y1),
+                                     GRAPHENE_POINT_INIT (x2, y2),
+                                     GRAPHENE_POINT_INIT (x3, y3)
                                    });
 }
 
@@ -961,13 +965,15 @@ gsk_path_builder_close (GskPathBuilder *builder)
 {
   g_return_if_fail (builder != NULL);
 
-  if (builder->current == NULL)
+  if (builder->ops->len == 0)
     return;
 
-  gsk_path_builder_append_current (builder, 2, (GskStandardPoint[2]) {
-                                     { .verb = GSK_PATH_VERB_CLOSE },
-                                     { .point = builder->current->path[1].point },
+  gsk_path_builder_append_current (builder,
+                                   GSK_PATH_LINE,
+                                   1, (graphene_point_t[1]) {
+                                     g_array_index (builder->points, graphene_point_t, 0)
                                    });
+
   gsk_path_builder_end_current (builder);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]