[gtk/path-work-rebased: 975/1045] path: Add flags to gsk_path_foreach()




commit 19fa088fb09d8a4d4acfd24a64f21c8386877553
Author: Benjamin Otte <otte redhat com>
Date:   Tue Dec 1 14:43:07 2020 +0100

    path: Add flags to gsk_path_foreach()
    
    This way we can default to the siplest possible foreach() output - like
    cairo_copy_path_flat() decomposing everything into lines - and add flags
    to get more and more fancy.
    
    This will be useful to have conics automatically decomposed for Cairo
    drawing or if we want to add more line types in the future.

 demos/gtk-demo/path_text.c |  2 +-
 gsk/gskpath.c              | 93 ++++++++++++++++++++++++++++++++++++++++++----
 gsk/gskpath.h              | 21 ++++++++++-
 gsk/gskpathprivate.h       |  1 +
 testsuite/gsk/path.c       |  6 ++-
 5 files changed, 111 insertions(+), 12 deletions(-)
---
diff --git a/demos/gtk-demo/path_text.c b/demos/gtk-demo/path_text.c
index aba6a6396a..75e7d100d0 100644
--- a/demos/gtk-demo/path_text.c
+++ b/demos/gtk-demo/path_text.c
@@ -160,7 +160,7 @@ gtk_path_transform (GskPathMeasure *measure,
   else
     transform.scale = 1.0f;
 
-  gsk_path_foreach (path, gtk_path_transform_op, &transform);
+  gsk_path_foreach (path, GSK_PATH_FOREACH_ALLOW_CURVES, gtk_path_transform_op, &transform);
 
   return gsk_path_builder_free_to_path (transform.builder);
 }
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index bfa53b2f41..1585e8f954 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -2010,6 +2010,7 @@ gsk_path_to_cairo (GskPath *self,
   g_return_if_fail (cr != NULL);
 
   gsk_path_foreach_with_tolerance (self,
+                                   GSK_PATH_FOREACH_ALLOW_CURVES,
                                    cairo_get_tolerance (cr),
                                    gsk_path_to_cairo_add_op,
                                    cr);
@@ -2103,6 +2104,8 @@ gsk_path_get_bounds (GskPath         *self,
 /**
  * gsk_path_foreach:
  * @self: a `GskPath`
+ * @flags: flags to pass to the foreach function. See `GskPathForeachFlags` for
+ *   details about flags.
  * @func: (scope call) (closure user_data): the function to call for operations
  * @user_data: (nullable): user data passed to @func
  *
@@ -2114,24 +2117,98 @@ gsk_path_get_bounds (GskPath         *self,
  * Returns: %FALSE if @func returned %FALSE, %TRUE otherwise.
  **/
 gboolean
-gsk_path_foreach (GskPath            *self,
-                  GskPathForeachFunc  func,
-                  gpointer            user_data)
+gsk_path_foreach (GskPath             *self,
+                  GskPathForeachFlags  flags,
+                  GskPathForeachFunc   func,
+                  gpointer             user_data)
 {
   g_return_val_if_fail (self != NULL, FALSE);
   g_return_val_if_fail (func, FALSE);
 
-  return gsk_path_foreach_with_tolerance (self, GSK_PATH_TOLERANCE_DEFAULT, func, user_data);
+  return gsk_path_foreach_with_tolerance (self,
+                                          flags,
+                                          GSK_PATH_TOLERANCE_DEFAULT,
+                                          func,
+                                          user_data);
+}
+
+typedef struct _GskPathForeachTrampoline GskPathForeachTrampoline;
+struct _GskPathForeachTrampoline
+{
+  GskPathForeachFlags flags;
+  double tolerance;
+  GskPathForeachFunc func;
+  gpointer user_data;
+  gboolean retval;
+};
+
+static void
+gsk_path_foreach_trampoline_add_point (const graphene_point_t *from,
+                                       const graphene_point_t *to,
+                                       float                   from_progress,
+                                       float                   to_progress,
+                                       gpointer                data)
+{
+  GskPathForeachTrampoline *trampoline = data;
+
+  if (!trampoline->retval)
+    return;
+
+  trampoline->retval = trampoline->func (GSK_PATH_LINE,
+                                         (graphene_point_t[2]) { *from, *to },
+                                         2,
+                                         trampoline->user_data);
+}
+
+static gboolean
+gsk_path_foreach_trampoline (GskPathOperation        op,
+                             const graphene_point_t *pts,
+                             gsize                   n_pts,
+                             gpointer                data)
+{
+  GskPathForeachTrampoline *trampoline = data;
+
+  switch (op)
+  {
+    case GSK_PATH_MOVE:
+    case GSK_PATH_CLOSE:
+    case GSK_PATH_LINE:
+      return trampoline->func (op, pts, n_pts, trampoline->user_data);
+
+    case GSK_PATH_CURVE:
+      if (trampoline->flags & GSK_PATH_FOREACH_ALLOW_CURVES)
+        return trampoline->func (op, pts, n_pts, trampoline->user_data);
+
+      gsk_spline_decompose_cubic (pts,
+                                  trampoline->tolerance,
+                                  gsk_path_foreach_trampoline_add_point,
+                                  trampoline);
+      return trampoline->retval;
+
+    default:
+      g_assert_not_reached ();
+      return FALSE;
+  }
 }
 
 gboolean
-gsk_path_foreach_with_tolerance (GskPath            *self,
-                                 double              tolerance,
-                                 GskPathForeachFunc  func,
-                                 gpointer            user_data)
+gsk_path_foreach_with_tolerance (GskPath             *self,
+                                 GskPathForeachFlags  flags,
+                                 double               tolerance,
+                                 GskPathForeachFunc   func,
+                                 gpointer             user_data)
 {
+  GskPathForeachTrampoline trampoline;
   gsize i;
 
+  /* If we need to massage the data, set up a trampoline here */
+  if (flags != GSK_PATH_FOREACH_ALLOW_CURVES)
+    {
+      trampoline = (GskPathForeachTrampoline) { flags, tolerance, func, user_data, TRUE };
+      func = gsk_path_foreach_trampoline;
+      user_data = &trampoline;
+    }
+
   for (i = 0; i < self->n_contours; i++)
     {
       if (!gsk_contour_foreach (self->contours[i], tolerance, func, user_data))
diff --git a/gsk/gskpath.h b/gsk/gskpath.h
index 73068126e6..c4a6d1cebc 100644
--- a/gsk/gskpath.h
+++ b/gsk/gskpath.h
@@ -29,6 +29,24 @@
 
 G_BEGIN_DECLS
 
+/**
+ * GskPathForeachFlags:
+ * @GSK_PATH_FOREACH_ALLOW_CURVES: Allow emission of `GSK_PATH_CURVE`
+ *   operations.
+ *
+ * Flags that can be passed to gsk_path_foreach() to enable additional
+ * features.
+ *
+ * By default, [method Gsk Path.foreach] will only emit a path with all
+ * operations flattened to straight lines to allow for maximum compatibility.
+ * The only operations emitted will be `GSK_PATH_MOVE`, `GSK_PATH_LINE` and
+ * `GSK_PATH_CLOSE`.
+ */
+typedef enum
+{
+  GSK_PATH_FOREACH_ALLOW_CURVES = (1 << 0)
+} GskPathForeachFlags;
+
 /**
  * GskPathForeachFunc:
  * @op: The operation to perform
@@ -40,7 +58,7 @@ G_BEGIN_DECLS
  * a path.
  *
  * Returns: %TRUE to continue evaluating the path, %FALSE to
- *     immediately abort and not call the function again.
+ *   immediately abort and not call the function again.
  */
 typedef gboolean (* GskPathForeachFunc) (GskPathOperation        op,
                                          const graphene_point_t *pts,
@@ -80,6 +98,7 @@ gboolean                gsk_path_get_bounds                     (GskPath
 
 GDK_AVAILABLE_IN_ALL
 gboolean                gsk_path_foreach                        (GskPath                *self,
+                                                                 GskPathForeachFlags     flags,
                                                                  GskPathForeachFunc      func,
                                                                  gpointer                user_data);
 
diff --git a/gsk/gskpathprivate.h b/gsk/gskpathprivate.h
index 6ea2c2c6d3..310fa38b45 100644
--- a/gsk/gskpathprivate.h
+++ b/gsk/gskpathprivate.h
@@ -61,6 +61,7 @@ gsize                   gsk_path_get_n_contours                 (GskPath
 const GskContour *      gsk_path_get_contour                    (GskPath              *path,
                                                                  gsize                 i);
 gboolean                gsk_path_foreach_with_tolerance         (GskPath              *self,
+                                                                 GskPathForeachFlags   flags,
                                                                  double                tolerance,
                                                                  GskPathForeachFunc    func,
                                                                  gpointer              user_data);
diff --git a/testsuite/gsk/path.c b/testsuite/gsk/path.c
index 8cef3bc632..1390fd4364 100644
--- a/testsuite/gsk/path.c
+++ b/testsuite/gsk/path.c
@@ -412,7 +412,8 @@ collect_path (GskPath *path)
 {
   GArray *array = g_array_new (FALSE, FALSE, sizeof (PathOperation));
 
-  gsk_path_foreach (path, collect_path_operation_cb, array);
+  /* Use -1 here because we want all the flags, even future additions */
+  gsk_path_foreach (path, -1, collect_path_operation_cb, array);
 
   return array;
 }
@@ -1019,7 +1020,8 @@ test_in_fill_rotated (void)
       path = create_random_path (G_MAXUINT);
       builders[0] = gsk_path_builder_new ();
       builders[1] = gsk_path_builder_new ();
-      gsk_path_foreach (path, rotate_path_cb, builders);
+      /* Use -1 here because we want all the flags, even future additions */
+      gsk_path_foreach (path, -1, rotate_path_cb, builders);
       gsk_path_unref (path);
 
       path = gsk_path_builder_free_to_path (builders[0]);


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