[gtk/wip/otte/lottie: 4/11] path: Introduce gskpathop




commit 23e3cf2d5d9ea39367fe7e9320647dfbe97631da
Author: Benjamin Otte <otte redhat com>
Date:   Fri Dec 4 17:02:42 2020 +0100

    path: Introduce gskpathop
    
    A gskpathop is a pointer to a graphene_point_t* with the low bits used
    to encode the GskPathOperation. It's an easy way to introduce API for
    operations.
    
    So far it's just used to replace GskStandardOperation.

 gsk/gskcontour.c        | 112 ++++++++++++++----------------
 gsk/gskcontourprivate.h |  16 ++---
 gsk/gskpathbuilder.c    |  26 +++++--
 gsk/gskpathopprivate.h  | 178 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 256 insertions(+), 76 deletions(-)
---
diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c
index 76595e1145..359356d838 100644
--- a/gsk/gskcontour.c
+++ b/gsk/gskcontour.c
@@ -871,7 +871,7 @@ struct _GskStandardContour
   gsize n_ops;
   gsize n_points;
   graphene_point_t *points;
-  GskStandardOperation ops[];
+  gskpathop ops[];
 };
 
 static gsize
@@ -879,7 +879,7 @@ gsk_standard_contour_compute_size (gsize n_ops,
                                    gsize n_points)
 {
   return sizeof (GskStandardContour)
-       + sizeof (GskStandardOperation) * n_ops
+       + sizeof (gskpathop) * n_ops
        + sizeof (graphene_point_t) * n_points;
 }
 
@@ -899,30 +899,11 @@ gsk_standard_contour_foreach (const GskContour   *contour,
 {
   const GskStandardContour *self = (const GskStandardContour *) contour;
   gsize i;
-  const gsize n_points[] = {
-    [GSK_PATH_MOVE] = 1,
-    [GSK_PATH_CLOSE] = 2,
-    [GSK_PATH_LINE] = 2,
-    [GSK_PATH_CURVE] = 4
-  };
 
   for (i = 0; i < self->n_ops; i ++)
     {
-      if (self->ops[i].op == GSK_PATH_CONIC)
-        {
-          graphene_point_t pts[3] = { self->points[self->ops[i].point],
-                                      self->points[self->ops[i].point + 1],
-                                      self->points[self->ops[i].point + 3] };
-          float weight = self->points[self->ops[i].point + 2].x;
-
-          if (!func (GSK_PATH_CONIC, pts, 3, weight, user_data))
-            return FALSE;
-        }
-      else
-        {
-          if (!func (self->ops[i].op, &self->points[self->ops[i].point], n_points[self->ops[i].op], 0, 
user_data))
-            return FALSE;
-        }
+      if (!gsk_pathop_foreach (self->ops[i], func, user_data))
+        return FALSE;
     }
 
   return TRUE;
@@ -945,9 +926,9 @@ gsk_standard_contour_print (const GskContour *contour,
 
   for (i = 0; i < self->n_ops; i ++)
     {
-      graphene_point_t *pt = &self->points[self->ops[i].point];
+      const graphene_point_t *pt = gsk_pathop_points (self->ops[i]);
 
-      switch (self->ops[i].op)
+      switch (gsk_pathop_op (self->ops[i]))
       {
         case GSK_PATH_MOVE:
           g_string_append (string, "M ");
@@ -1102,9 +1083,9 @@ gsk_standard_contour_init_measure (const GskContour *contour,
 
   for (i = 1; i < self->n_ops; i ++)
     {
-      graphene_point_t *pt = &self->points[self->ops[i].point];
+      const graphene_point_t *pt = gsk_pathop_points (self->ops[i]);
 
-      switch (self->ops[i].op)
+      switch (gsk_pathop_op (self->ops[i]))
       {
         case GSK_PATH_MOVE:
           break;
@@ -1184,8 +1165,8 @@ gsk_standard_contour_measure_get_point (GskStandardContour        *self,
 {
   const graphene_point_t *pts;
 
-  pts = &self->points[self->ops[op].point];
-  switch (self->ops[op].op)
+  pts = gsk_pathop_points (self->ops[op]);
+  switch (gsk_pathop_op (self->ops[op]))
     {
       case GSK_PATH_LINE:
       case GSK_PATH_CLOSE:
@@ -1229,7 +1210,7 @@ gsk_standard_contour_get_point (const GskContour *contour,
   if (array->len == 0)
     {
       g_assert (distance == 0);
-      g_assert (self->ops[0].op == GSK_PATH_MOVE);
+      g_assert (gsk_pathop_op (self->ops[0]) == GSK_PATH_MOVE);
       if (pos)
         *pos = self->points[0];
       if (tangent)
@@ -1266,7 +1247,7 @@ gsk_standard_contour_get_closest_point (const GskContour       *contour,
   gsize i;
   gboolean result = FALSE;
 
-  g_assert (self->ops[0].op == GSK_PATH_MOVE);
+  g_assert (gsk_pathop_op (self->ops[0]) == GSK_PATH_MOVE);
   last_point = self->points[0];
 
   if (array->len == 0)
@@ -1338,12 +1319,13 @@ gsk_standard_contour_get_closest_point (const GskContour       *contour,
 }
 
 static void
-gsk_standard_contour_init (GskContour *contour,
-                           GskPathFlags flags,
-                           const GskStandardOperation *ops,
-                           gsize n_ops,
+gsk_standard_contour_init (GskContour             *contour,
+                           GskPathFlags            flags,
                            const graphene_point_t *points,
-                           gsize n_points);
+                           gsize                   n_points,
+                           const gskpathop        *ops,
+                           gsize                   n_ops,
+                           ptrdiff_t               offset);
 
 static void
 gsk_standard_contour_copy (const GskContour *contour,
@@ -1351,7 +1333,7 @@ gsk_standard_contour_copy (const GskContour *contour,
 {
   const GskStandardContour *self = (const GskStandardContour *) contour;
 
-  gsk_standard_contour_init (dest, self->flags, self->ops, self->n_ops, self->points, self->n_points);
+  gsk_standard_contour_init (dest, self->flags, self->points, self->n_points, self->ops, self->n_ops, 0);
 }
 
 static void
@@ -1400,12 +1382,12 @@ gsk_standard_contour_add_segment (const GskContour *contour,
    * taking care that first and last operation might be identical */
   if (start_measure)
     {
-      switch (self->ops[start_measure->op].op)
+      switch (gsk_pathop_op (self->ops[start_measure->op]))
       {
         case GSK_PATH_CLOSE:
         case GSK_PATH_LINE:
           {
-            graphene_point_t *pts = &self->points[self->ops[start_measure->op].point];
+            const graphene_point_t *pts = gsk_pathop_points (self->ops[start_measure->op]);
             graphene_point_t point;
 
             graphene_point_interpolate (&pts[0], &pts[1], start_progress, &point);
@@ -1422,7 +1404,7 @@ gsk_standard_contour_add_segment (const GskContour *contour,
 
         case GSK_PATH_CURVE:
           {
-            graphene_point_t *pts = &self->points[self->ops[start_measure->op].point];
+            const graphene_point_t *pts = gsk_pathop_points (self->ops[start_measure->op]);
             graphene_point_t curve[4], discard[4];
 
             gsk_spline_split_cubic (pts, discard, curve, start_progress);
@@ -1441,7 +1423,7 @@ gsk_standard_contour_add_segment (const GskContour *contour,
 
         case GSK_PATH_CONIC:
           {
-            graphene_point_t *pts = &self->points[self->ops[start_measure->op].point];
+            const graphene_point_t *pts = gsk_pathop_points (self->ops[start_measure->op]);
             graphene_point_t curve[4], discard[4];
 
             gsk_spline_split_conic (pts, discard, curve, start_progress);
@@ -1470,9 +1452,9 @@ gsk_standard_contour_add_segment (const GskContour *contour,
 
   for (; i < (end_measure ? end_measure->op : self->n_ops); i++)
     {
-      graphene_point_t *pt = &self->points[self->ops[i].point];
+      const graphene_point_t *pt = gsk_pathop_points (self->ops[i]);
 
-      switch (self->ops[i].op)
+      switch (gsk_pathop_op (self->ops[i]))
       {
         case GSK_PATH_MOVE:
           gsk_path_builder_move_to (builder, pt[0].x, pt[0].y);
@@ -1500,12 +1482,12 @@ gsk_standard_contour_add_segment (const GskContour *contour,
   /* Add the last partial operation */
   if (end_measure)
     {
-      switch (self->ops[end_measure->op].op)
+      switch (gsk_pathop_op (self->ops[end_measure->op]))
       {
         case GSK_PATH_CLOSE:
         case GSK_PATH_LINE:
           {
-            graphene_point_t *pts = &self->points[self->ops[end_measure->op].point];
+            const graphene_point_t *pts = gsk_pathop_points (self->ops[end_measure->op]);
             graphene_point_t point;
 
             graphene_point_interpolate (&pts[0], &pts[1], end_progress, &point);
@@ -1515,7 +1497,7 @@ gsk_standard_contour_add_segment (const GskContour *contour,
 
         case GSK_PATH_CURVE:
           {
-            graphene_point_t *pts = &self->points[self->ops[end_measure->op].point];
+            const graphene_point_t *pts = gsk_pathop_points (self->ops[end_measure->op]);
             graphene_point_t curve[4], discard[4];
 
             gsk_spline_split_cubic (pts, curve, discard, end_progress);
@@ -1525,7 +1507,7 @@ gsk_standard_contour_add_segment (const GskContour *contour,
 
         case GSK_PATH_CONIC:
           {
-            graphene_point_t *pts = &self->points[self->ops[end_measure->op].point];
+            const graphene_point_t *pts = gsk_pathop_points (self->ops[end_measure->op]);
             graphene_point_t curve[4], discard[4];
 
             gsk_spline_split_conic (pts, curve, discard, end_progress);
@@ -1637,37 +1619,47 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
  * see gsk_standard_contour_compute_size()
  */
 static void
-gsk_standard_contour_init (GskContour   *contour,
-                           GskPathFlags  flags,
-                           const         GskStandardOperation *ops,
-                           gsize         n_ops,
-                           const         graphene_point_t *points,
-                           gsize         n_points)
+gsk_standard_contour_init (GskContour             *contour,
+                           GskPathFlags            flags,
+                           const graphene_point_t *points,
+                           gsize                   n_points,
+                           const gskpathop        *ops,
+                           gsize                   n_ops,
+                           gssize                  offset)
+
 {
   GskStandardContour *self = (GskStandardContour *) contour;
+  gsize i;
 
   self->contour.klass = &GSK_STANDARD_CONTOUR_CLASS;
 
   self->flags = flags;
   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);
+
+  offset += self->points - points;
+  for (i = 0; i < n_ops; i++)
+    {
+      self->ops[i] = gsk_pathop_encode (gsk_pathop_op (ops[i]),
+                                        gsk_pathop_points (ops[i]) + offset);
+    }
 }
 
 GskContour *
-gsk_standard_contour_new (GskPathFlags flags,
-                          const        GskStandardOperation *ops,
-                          gsize        n_ops,
-                          const        graphene_point_t *points,
-                          gsize        n_points)
+gsk_standard_contour_new (GskPathFlags            flags,
+                          const graphene_point_t *points,
+                          gsize                   n_points,
+                          const gskpathop        *ops,
+                          gsize                   n_ops,
+                          gssize                  offset)
 {
   GskContour *contour;
 
   contour = g_malloc0 (gsk_standard_contour_compute_size (n_ops, n_points));
 
-  gsk_standard_contour_init (contour, flags, ops, n_ops, points, n_points);
+  gsk_standard_contour_init (contour, flags, points, n_points, ops, n_ops, offset);
 
   return contour;
 }
diff --git a/gsk/gskcontourprivate.h b/gsk/gskcontourprivate.h
index 13e54a8e5d..bce0689d17 100644
--- a/gsk/gskcontourprivate.h
+++ b/gsk/gskcontourprivate.h
@@ -23,6 +23,8 @@
 
 #include <gskpath.h>
 
+#include "gskpathopprivate.h"
+
 G_BEGIN_DECLS
 
 typedef enum 
@@ -33,23 +35,17 @@ typedef enum
 
 typedef struct _GskContour GskContour;
 
-typedef struct _GskStandardOperation GskStandardOperation;
-
-struct _GskStandardOperation {
-  GskPathOperation op;
-  gsize point; /* index into points array of the start point (last point of previous op) */
-};
-
 GskContour *            gsk_rect_contour_new                    (const graphene_rect_t  *rect);
 GskContour *            gsk_circle_contour_new                  (const graphene_point_t *center,
                                                                  float                   radius,
                                                                  float                   start_angle,
                                                                  float                   end_angle);
 GskContour *            gsk_standard_contour_new                (GskPathFlags            flags,
-                                                                 const                   
GskStandardOperation *ops,
+                                                                 const graphene_point_t *points,
+                                                                 gsize                   n_points,
+                                                                 const gskpathop        *ops,
                                                                  gsize                   n_ops,
-                                                                 const                   graphene_point_t 
*points,
-                                                                 gsize                   n_points);
+                                                                 gssize                  offset);
 
 void                    gsk_contour_copy                        (GskContour *            dest,
                                                                  const GskContour       *src);
diff --git a/gsk/gskpathbuilder.c b/gsk/gskpathbuilder.c
index f98fb6398a..d155bf9ff7 100644
--- a/gsk/gskpathbuilder.c
+++ b/gsk/gskpathbuilder.c
@@ -105,7 +105,7 @@ gsk_path_builder_new (void)
   builder = g_slice_new0 (GskPathBuilder);
   builder->ref_count = 1;
 
-  builder->ops = g_array_new (FALSE, FALSE, sizeof (GskStandardOperation));
+  builder->ops = g_array_new (FALSE, FALSE, sizeof (gskpathop));
   builder->points = g_array_new (FALSE, FALSE, sizeof (graphene_point_t));
 
   /* Be explicit here */
@@ -137,6 +137,19 @@ gsk_path_builder_ref (GskPathBuilder *builder)
   return builder;
 }
 
+/* We're cheating here. Out pathops are relative to the NULL pointer,
+ * so that we can not care about the points GArray reallocating itself
+ * until we create the contour.
+ * This does however mean that we need to not use gsk_pathop_get_points()
+ * without offsetting the returned pointer.
+ */
+static inline gskpathop
+gsk_pathop_encode_index (GskPathOperation op,
+                         gsize            index)
+{
+  return gsk_pathop_encode (op, ((graphene_point_t *) NULL) + index);
+}
+
 static void
 gsk_path_builder_ensure_current (GskPathBuilder *builder)
 {
@@ -144,7 +157,7 @@ gsk_path_builder_ensure_current (GskPathBuilder *builder)
     return;
 
   builder->flags = GSK_PATH_FLAT;
-  g_array_append_vals (builder->ops, &(GskStandardOperation) { GSK_PATH_MOVE, 0 }, 1);
+  g_array_append_vals (builder->ops, (gskpathop[1]) { gsk_pathop_encode_index (GSK_PATH_MOVE, 0) }, 1);
   g_array_append_val (builder->points, builder->current_point);
 }
 
@@ -156,7 +169,7 @@ gsk_path_builder_append_current (GskPathBuilder         *builder,
 {
   gsk_path_builder_ensure_current (builder);
 
-  g_array_append_vals (builder->ops, &(GskStandardOperation) { op, builder->points->len - 1 }, 1);
+  g_array_append_vals (builder->ops, (gskpathop[1]) { gsk_pathop_encode_index (op, builder->points->len - 1) 
}, 1);
   g_array_append_vals (builder->points, points, n_points);
 
   builder->current_point = points[n_points - 1];
@@ -171,10 +184,11 @@ gsk_path_builder_end_current (GskPathBuilder *builder)
    return;
 
   contour = gsk_standard_contour_new (builder->flags,
-                                      (GskStandardOperation *) builder->ops->data,
-                                      builder->ops->len,
                                       (graphene_point_t *) builder->points->data,
-                                      builder->points->len);
+                                      builder->points->len,
+                                      (gskpathop *) builder->ops->data,
+                                      builder->ops->len,
+                                      (graphene_point_t *) builder->points->data - (graphene_point_t *) 
NULL);
 
   g_array_set_size (builder->ops, 0);
   g_array_set_size (builder->points, 0);
diff --git a/gsk/gskpathopprivate.h b/gsk/gskpathopprivate.h
new file mode 100644
index 0000000000..864e97e2ea
--- /dev/null
+++ b/gsk/gskpathopprivate.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright © 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+
+#ifndef __GSK_PATHOP_PRIVATE_H__
+#define __GSK_PATHOP_PRIVATE_H__
+
+#include <gsk/gskpath.h>
+#include <gsk/gskpathbuilder.h>
+
+G_BEGIN_DECLS
+
+typedef gpointer gskpathop;
+
+static inline
+gskpathop               gsk_pathop_encode                       (GskPathOperation        op,
+                                                                 const graphene_point_t *pts);
+static inline
+const graphene_point_t *gsk_pathop_points                       (gskpathop               pop);
+static inline
+GskPathOperation        gsk_pathop_op                           (gskpathop               pop);
+
+static inline
+gboolean                gsk_pathop_foreach                      (gskpathop               pop,
+                                                                 GskPathForeachFunc      func,
+                                                                 gpointer                user_data);
+
+/* included inline so tests can use them */
+static inline
+void                    gsk_path_builder_pathop_to              (GskPathBuilder         *builder,
+                                                                 gskpathop               op);
+static inline
+void                    gsk_path_builder_pathop_reverse_to      (GskPathBuilder         *builder,
+                                                                 gskpathop               op);
+
+/* IMPLEMENTATION */
+
+#define GSK_PATHOP_OPERATION_MASK (0x7)
+
+static inline gskpathop
+gsk_pathop_encode (GskPathOperation        op,
+                   const graphene_point_t *pts)
+{
+  /* g_assert (op & GSK_PATHOP_OPERATION_MASK == op); */
+
+  return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (pts) | op);
+}
+
+static inline const graphene_point_t *
+gsk_pathop_points (gskpathop pop)
+{
+  return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (pop) & ~GSK_PATHOP_OPERATION_MASK);
+}
+
+static inline
+GskPathOperation gsk_pathop_op (gskpathop pop)
+{
+  return GPOINTER_TO_SIZE (pop) & GSK_PATHOP_OPERATION_MASK;
+}
+
+static inline gboolean
+gsk_pathop_foreach (gskpathop          pop,
+                    GskPathForeachFunc func,
+                    gpointer           user_data)
+{
+  switch (gsk_pathop_op (pop))
+  {
+    case GSK_PATH_MOVE:
+      return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 1, 0, user_data);
+
+    case GSK_PATH_CLOSE:
+    case GSK_PATH_LINE:
+      return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 2, 0, user_data);
+
+    case GSK_PATH_CURVE:
+      return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 4, 0, user_data);
+
+    case GSK_PATH_CONIC:
+      {
+        const graphene_point_t *pts = gsk_pathop_points (pop);
+        return func (gsk_pathop_op (pop), (graphene_point_t[3]) { pts[0], pts[1], pts[3] }, 3, pts[2].x, 
user_data);
+      }
+
+    default:
+      g_assert_not_reached ();
+      return TRUE;
+    }
+}
+
+static inline void
+gsk_path_builder_pathop_to (GskPathBuilder *builder,
+                            gskpathop       op)
+{
+  const graphene_point_t *pts = gsk_pathop_points (op);
+
+  switch (gsk_pathop_op (op))
+  {
+    case GSK_PATH_MOVE:
+      gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
+      break;
+
+    case GSK_PATH_CLOSE:
+      gsk_path_builder_close (builder);
+      break;
+
+    case GSK_PATH_LINE:
+      gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
+      break;
+
+    case GSK_PATH_CURVE:
+      gsk_path_builder_curve_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
+      break;
+
+    case GSK_PATH_CONIC:
+      gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[3].x, pts[3].y, pts[2].x);
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static inline void
+gsk_path_builder_pathop_reverse_to (GskPathBuilder *builder,
+                                    gskpathop       op)
+{
+  const graphene_point_t *pts = gsk_pathop_points (op);
+
+  switch (gsk_pathop_op (op))
+  {
+    case GSK_PATH_MOVE:
+      gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
+      break;
+
+    case GSK_PATH_CLOSE:
+      gsk_path_builder_line_to (builder, pts[0].x, pts[0].y);
+      break;
+
+    case GSK_PATH_LINE:
+      gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
+      break;
+
+    case GSK_PATH_CURVE:
+      gsk_path_builder_curve_to (builder, pts[2].x, pts[2].y, pts[1].x, pts[1].y, pts[0].x, pts[0].y);
+      break;
+
+    case GSK_PATH_CONIC:
+      gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[0].x, pts[0].y, pts[2].x);
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+
+G_END_DECLS
+
+#endif /* __GSK_PATHOP_PRIVATE_H__ */
+


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