[gtk/wip/otte/lottie: 17/82] path: Add gsk_path_foreach()




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

    path: Add gsk_path_foreach()

 docs/reference/gsk/gsk4-sections.txt |   4 ++
 gsk/gskenums.h                       |  24 +++++++++
 gsk/gskpath.c                        | 102 ++++++++++++++++++++++++++++++++---
 gsk/gskpath.h                        |  23 ++++++++
 gsk/gskpathprivate.h                 |   3 ++
 5 files changed, 148 insertions(+), 8 deletions(-)
---
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt
index 183844b725..cf5af86e3b 100644
--- a/docs/reference/gsk/gsk4-sections.txt
+++ b/docs/reference/gsk/gsk4-sections.txt
@@ -329,6 +329,10 @@ gsk_path_to_cairo
 <SUBSECTION>
 gsk_path_is_empty
 gsk_path_get_bounds
+<SUBSECTION>
+GskPathOperation
+GskPathForeachFunc
+gsk_path_foreach
 <SUBSECTION Private>
 GSK_TYPE_PATH
 gsk_path_get_type
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 62ecc89d70..35ac09e999 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -234,6 +234,30 @@ 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.
+ *
+ * More values may be added in the future.
+ **/
+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 050ecad391..c7b1b1a285 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,
@@ -181,6 +185,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)
@@ -282,6 +309,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,
@@ -306,14 +334,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 {
@@ -351,6 +371,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)
 {
@@ -655,6 +699,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,
@@ -710,6 +755,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,
@@ -1008,6 +1062,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]