[gtk/wip/otte/lottie: 15/30] path: Add gsk_path_foreach()




commit bdfe4792099ca994341df46bae5d2ef4a1b9e023
Author: Benjamin Otte <otte redhat com>
Date:   Wed Nov 18 05:15:28 2020 +0100

    path: Add gsk_path_foreach()

 gsk/gskenums.h       |  22 +++++++++++
 gsk/gskpath.c        | 102 +++++++++++++++++++++++++++++++++++++++++++++++----
 gsk/gskpath.h        |  23 ++++++++++++
 gsk/gskpathprivate.h |   3 ++
 4 files changed, 142 insertions(+), 8 deletions(-)
---
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 5d78c05912..8ca577563d 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -232,6 +232,28 @@ typedef enum {
   GSK_LINE_JOIN_BEVEL
 } GskLineJoin;
 
+/**
+ * GskPathOperation:
+ * @GSK_PATH_MOVE: A move-to operation, with 1 point describing the
+ *     target point.
+ * @GSK_PATH_LINE: A line-to operation, with 2 points describing the
+ *     start and end point of a straight line.
+ * @GSK_PATH_CLOSE: A close operation ending the current contour with
+ *     a line back to the starting point. Two points describe the start
+ *     and end of the line.
+ * @GSK_PATH_CURVE: A curve-to operation describing a cubic bezier curve
+ *     with 4 points describing the start point, the two control points
+ *     and the end point of the curve.
+ *
+ * Path operations can be used to approximate a #GskPath.
+ **/
+typedef enum {
+  GSK_PATH_MOVE,
+  GSK_PATH_CLOSE,
+  GSK_PATH_LINE,
+  GSK_PATH_CURVE,
+} GskPathOperation;
+
 /**
  * GskSerializationError:
  * @GSK_SERIALIZATION_UNSUPPORTED_FORMAT: The format can not be
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index 524610bb06..94b66ce7ff 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -62,6 +62,10 @@ struct _GskContourClass
                                                  cairo_t                *cr);
   gboolean              (* get_bounds)          (const GskContour       *contour,
                                                  graphene_rect_t        *bounds);
+  gboolean              (* foreach)             (const GskContour       *contour,
+                                                 float                   tolerance,
+                                                 GskPathForeachFunc      func,
+                                                 gpointer                user_data);
   gpointer              (* init_measure)        (const GskContour       *contour,
                                                  float                  *out_length);
   void                  (* free_measure)        (const GskContour       *contour,
@@ -157,6 +161,29 @@ gsk_rect_contour_get_bounds (const GskContour *contour,
   return TRUE;
 }
 
+static gboolean
+gsk_rect_contour_foreach (const GskContour   *contour,
+                          float               tolerance,
+                          GskPathForeachFunc  func,
+                          gpointer            user_data)
+{
+  const GskRectContour *self = (const GskRectContour *) contour;
+
+  graphene_point_t pts[] = {
+    GRAPHENE_POINT_INIT (self->x,               self->y),
+    GRAPHENE_POINT_INIT (self->x + self->width, self->y),
+    GRAPHENE_POINT_INIT (self->x + self->width, self->y + self->height),
+    GRAPHENE_POINT_INIT (self->x,               self->y + self->height),
+    GRAPHENE_POINT_INIT (self->x,               self->y)
+  };
+
+  return func (GSK_PATH_MOVE, &pts[0], 1, user_data)
+      && func (GSK_PATH_LINE, &pts[0], 2, user_data)
+      && func (GSK_PATH_LINE, &pts[1], 2, user_data)
+      && func (GSK_PATH_LINE, &pts[2], 2, user_data)
+      && func (GSK_PATH_CLOSE, &pts[3], 2, user_data);
+}
+
 static gpointer
 gsk_rect_contour_init_measure (const GskContour *contour,
                                float            *out_length)
@@ -258,6 +285,7 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
   gsk_rect_contour_print,
   gsk_rect_contour_to_cairo,
   gsk_rect_contour_get_bounds,
+  gsk_rect_contour_foreach,
   gsk_rect_contour_init_measure,
   gsk_rect_contour_free_measure,
   gsk_rect_contour_copy,
@@ -282,14 +310,6 @@ gsk_rect_contour_init (GskContour *contour,
 
 /* STANDARD CONTOUR */
 
-typedef enum
-{
-  GSK_PATH_MOVE,
-  GSK_PATH_CLOSE,
-  GSK_PATH_LINE,
-  GSK_PATH_CURVE,
-} GskPathOperation;
-
 typedef struct _GskStandardOperation GskStandardOperation;
 
 struct _GskStandardOperation {
@@ -327,6 +347,30 @@ gsk_standard_contour_get_size (const GskContour *contour)
   return gsk_standard_contour_compute_size (self->n_ops, self->n_points);
 }
 
+static gboolean
+gsk_standard_contour_foreach (const GskContour   *contour,
+                              float               tolerance,
+                              GskPathForeachFunc  func,
+                              gpointer            user_data)
+{
+  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 (!func (self->ops[i].op, &self->points[self->ops[i].point], n_points[self->ops[i].op], user_data))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
 static GskPathFlags
 gsk_standard_contour_get_flags (const GskContour *contour)
 {
@@ -627,6 +671,7 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
   gsk_standard_contour_print,
   gsk_standard_contour_to_cairo,
   gsk_standard_contour_get_bounds,
+  gsk_standard_contour_foreach,
   gsk_standard_contour_init_measure,
   gsk_standard_contour_free_measure,
   gsk_standard_contour_copy,
@@ -682,6 +727,15 @@ gsk_contour_dup (const GskContour *src)
   return copy;
 }
 
+static gboolean
+gsk_contour_foreach (const GskContour   *contour,
+                     float               tolerance,
+                     GskPathForeachFunc  func,
+                     gpointer            user_data)
+{
+  return contour->klass->foreach (contour, tolerance, func, user_data);
+}
+
 gpointer
 gsk_contour_init_measure (GskPath *path,
                           gsize    i,
@@ -970,6 +1024,38 @@ gsk_path_get_bounds (GskPath         *self,
   return TRUE;
 }
 
+/**
+ * gsk_path_foreach:
+ * @self: a #GskPath
+ * @func: (scope call) (closure user_data): the function to call for operations
+ * @user_data: (nullable): user data passed to @func
+ *
+ * Calls @func for every operation of the path. Note that this only approximates
+ * @self, because paths can contain optimizations for various specialized contours.
+ *
+ * Returns: %FALSE if @func returned %FALSE, %TRUE otherwise.
+ **/
+gboolean
+gsk_path_foreach (GskPath            *self,
+                  GskPathForeachFunc  func,
+                  gpointer            user_data)
+{
+  gsize i;
+
+  g_return_val_if_fail (self != NULL, FALSE);
+  g_return_val_if_fail (func, FALSE);
+
+  for (i = 0; i < self->n_contours; i++)
+    {
+      if (!gsk_contour_foreach (self->contours[i], GSK_PATH_TOLERANCE_DEFAULT, func, user_data))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* BUILDER */
+
 /**
  * GskPathBuilder:
  *
diff --git a/gsk/gskpath.h b/gsk/gskpath.h
index 0d4666ee81..83493f18a0 100644
--- a/gsk/gskpath.h
+++ b/gsk/gskpath.h
@@ -29,6 +29,24 @@
 
 G_BEGIN_DECLS
 
+/**
+ * GskPathForeachFunc:
+ * @op: The operation to perform
+ * @pts: The points of the operation
+ * @n_pts: The number of points
+ * @user_data: The user data provided with the function
+ *
+ * Prototype of the callback to iterate throught the operations of
+ * a path.
+ *
+ * Returns: %TRUE to continue evaluating the path, %FALSE to
+ *     immediately abort and not call the function again.
+ */
+typedef gboolean (* GskPathForeachFunc) (GskPathOperation        op,
+                                         const graphene_point_t *pts,
+                                         gsize                   n_pts,
+                                         gpointer                user_data);
+
 #define GSK_TYPE_PATH (gsk_path_get_type ())
 
 GDK_AVAILABLE_IN_ALL
@@ -56,6 +74,11 @@ GDK_AVAILABLE_IN_ALL
 gboolean                gsk_path_get_bounds                     (GskPath                *path,
                                                                  graphene_rect_t        *bounds);
 
+GDK_AVAILABLE_IN_ALL
+gboolean                gsk_path_foreach                        (GskPath              *path,
+                                                                 GskPathForeachFunc    func,
+                                                                 gpointer              user_data);
+
 #define GSK_TYPE_PATH_BUILDER (gsk_path_builder_get_type ())
 
 typedef struct _GskPathBuilder GskPathBuilder;
diff --git a/gsk/gskpathprivate.h b/gsk/gskpathprivate.h
index 7238c44418..2e47ac465f 100644
--- a/gsk/gskpathprivate.h
+++ b/gsk/gskpathprivate.h
@@ -25,6 +25,9 @@
 
 G_BEGIN_DECLS
 
+/* Same as Cairo, so looks like a good value. ¯\_(ツ)_/¯ */
+#define GSK_PATH_TOLERANCE_DEFAULT (0.1)
+
 gsize                   gsk_path_get_n_contours                 (GskPath              *path);
 
 gpointer                gsk_contour_init_measure                (GskPath              *path,


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