[gtk/path-ops: 2/8] path: Add gsk_path_reverse




commit 67c4833d2c84d7468db456ae133e260eb957bedb
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Mar 25 16:48:09 2022 -0400

    path: Add gsk_path_reverse
    
    This is a natural operation, and useful for debugging things.

 gsk/gskcontour.c        | 98 +++++++++++++++++++++++++++++++++++++++++++++----
 gsk/gskcontourprivate.h |  2 +
 gsk/gskpath.c           | 22 +++++++++++
 gsk/gskpath.h           |  3 ++
 4 files changed, 118 insertions(+), 7 deletions(-)
---
diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c
index c978e91401..f90e4cea21 100644
--- a/gsk/gskcontour.c
+++ b/gsk/gskcontour.c
@@ -98,6 +98,7 @@ struct _GskContourClass
                                                  float                   distance,
                                                  GskLineJoin             line_join,
                                                  float                   miter_limit);
+  GskContour *          (* reverse)             (const GskContour       *contour);
 };
 
 static gsize
@@ -328,7 +329,7 @@ gsk_rect_contour_get_closest_point (const GskContour       *contour,
   const GskRectContour *self = (const GskRectContour *) contour;
   graphene_point_t t, p;
   float distance;
- 
+
   /* offset coords to be relative to rectangle */
   t.x = point->x - self->x;
   t.y = point->y - self->y;
@@ -385,7 +386,7 @@ gsk_rect_contour_get_closest_point (const GskContour       *contour,
     *out_pos = p;
 
   if (out_offset)
-    *out_offset = (t.x == 0.0 && self->width > 0 ? 2 - t.y : t.y) * ABS (self->height) + 
+    *out_offset = (t.x == 0.0 && self->width > 0 ? 2 - t.y : t.y) * ABS (self->height) +
                   (t.y == 1.0 ? 2 - t.x : t.x) * ABS (self->width);
 
   if (out_tangent)
@@ -564,6 +565,17 @@ gsk_rect_contour_offset (const GskContour *contour,
   gsk_contour_default_offset (contour, builder, distance, line_join, miter_limit);
 }
 
+static GskContour *
+gsk_rect_contour_reverse (const GskContour *contour)
+{
+  const GskRectContour *self = (const GskRectContour *) contour;
+
+  return gsk_rect_contour_new (&GRAPHENE_RECT_INIT (self->x + self->width,
+                                                    self->y,
+                                                    - self->width,
+                                                    self->height));
+}
+
 static const GskContourClass GSK_RECT_CONTOUR_CLASS =
 {
   sizeof (GskRectContour),
@@ -584,7 +596,8 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
   gsk_rect_contour_get_winding,
   gsk_rect_contour_get_stroke_bounds,
   gsk_rect_contour_add_stroke,
-  gsk_rect_contour_offset
+  gsk_rect_contour_offset,
+  gsk_rect_contour_reverse,
 };
 
 GskContour *
@@ -965,6 +978,17 @@ gsk_circle_contour_offset (const GskContour *contour,
   gsk_contour_default_offset (contour, builder, distance, line_join, miter_limit);
 }
 
+static GskContour *
+gsk_circle_contour_reverse (const GskContour *contour)
+{
+  const GskCircleContour *self = (const GskCircleContour *) contour;
+
+  return gsk_circle_contour_new (&self->center,
+                                 self->radius,
+                                 self->end_angle,
+                                 self->start_angle);
+}
+
 static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
 {
   sizeof (GskCircleContour),
@@ -985,7 +1009,8 @@ static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
   gsk_circle_contour_get_winding,
   gsk_circle_contour_get_stroke_bounds,
   gsk_circle_contour_add_stroke,
-  gsk_circle_contour_offset
+  gsk_circle_contour_offset,
+  gsk_circle_contour_reverse,
 };
 
 GskContour *
@@ -1445,7 +1470,7 @@ gsk_standard_contour_get_closest_point (const GskContour       *contour,
             dist = test_dist;
           }
           //g_print ("!!! %zu: (%g-%g @ %g) dist %g\n", i, measure->start_progress, measure->end_progress, 
progress, dist);
-          /* double check that the point actually is closer */ 
+          /* double check that the point actually is closer */
           if (dist <= threshold)
             {
               if (out_distance)
@@ -1555,7 +1580,7 @@ gsk_standard_contour_add_segment (const GskContour *contour,
       gsk_curve_builder_to (&cut, builder);
       i = start_measure->op + 1;
     }
-  else 
+  else
     i = emit_move_to ? 0 : 1;
 
   for (; i < (end_measure ? end_measure->op : self->n_ops - 1); i++)
@@ -1740,6 +1765,59 @@ gsk_standard_contour_offset (const GskContour *contour,
   gsk_contour_default_offset (contour, builder, distance, line_join, miter_limit);
 }
 
+static gboolean
+add_reverse (GskPathOperation        op,
+             const graphene_point_t *pts,
+             gsize                   n_pts,
+             float                   weight,
+             gpointer                user_data)
+{
+  GskPathBuilder *builder = user_data;
+  GskCurve c, r;
+
+  if (op == GSK_PATH_MOVE)
+    return TRUE;
+
+  if (op == GSK_PATH_CLOSE)
+    op = GSK_PATH_LINE;
+
+  gsk_curve_init_foreach (&c, op, pts, n_pts, weight);
+  gsk_curve_reverse (&c, &r);
+  gsk_curve_builder_to (&r, builder);
+
+  return TRUE;
+}
+
+static GskContour *
+gsk_standard_contour_reverse (const GskContour *contour)
+{
+  const GskStandardContour *self = (const GskStandardContour *) contour;
+  GskPathBuilder *builder;
+  GskPath *path;
+  GskContour *res;
+
+  builder = gsk_path_builder_new ();
+
+  gsk_path_builder_move_to (builder, self->points[self->n_points - 1].x,
+                                     self->points[self->n_points - 1].y);
+
+  for (int i = self->n_ops - 1; i >= 0; i--)
+    gsk_pathop_foreach (self->ops[i], add_reverse, builder);
+
+  if (self->flags & GSK_PATH_CLOSED)
+    gsk_path_builder_close (builder);
+
+  path = gsk_path_builder_free_to_path (builder);
+
+  g_assert (gsk_path_get_n_contours (path) == 1);
+
+  res = gsk_contour_dup (gsk_path_get_contour (path, 0));
+
+  gsk_path_unref (path);
+
+  return res;
+}
+
 static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
 {
   sizeof (GskStandardContour),
@@ -1760,7 +1838,8 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
   gsk_standard_contour_get_winding,
   gsk_standard_contour_get_stroke_bounds,
   gsk_standard_contour_add_stroke,
-  gsk_standard_contour_offset
+  gsk_standard_contour_offset,
+  gsk_standard_contour_reverse,
 };
 
 /* You must ensure the contour has enough size allocated,
@@ -1977,3 +2056,8 @@ gsk_contour_dup (const GskContour *src)
   return copy;
 }
 
+GskContour *
+gsk_contour_reverse (const GskContour *src)
+{
+  return src->klass->reverse (src);
+}
diff --git a/gsk/gskcontourprivate.h b/gsk/gskcontourprivate.h
index 5219eb448a..842e4e04a1 100644
--- a/gsk/gskcontourprivate.h
+++ b/gsk/gskcontourprivate.h
@@ -55,6 +55,8 @@ void                    gsk_contour_copy                        (GskContour *
                                                                  const GskContour       *src);
 GskContour *            gsk_contour_dup                         (const GskContour       *src);
 
+GskContour *            gsk_contour_reverse                     (const GskContour       *src);
+
 gsize                   gsk_contour_get_size                    (const GskContour       *self);
 GskPathFlags            gsk_contour_get_flags                   (const GskContour       *self);
 void                    gsk_contour_print                       (const GskContour       *self,
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index 4d5961bf94..deac50531e 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -1240,6 +1240,28 @@ gsk_path_get_stroke_bounds (GskPath         *path,
   return TRUE;
 }
 
+/**
+ * gsk_path_reverse:
+ * @self: a `GskPath`
+ *
+ * Creates a path that traverses the same contours as
+ * @self, in the opposite direction.
+ *
+ * Returns: the reverse of @self
+ */
+GskPath *
+gsk_path_reverse (GskPath *self)
+{
+  GskPathBuilder *builder;
+
+  builder = gsk_path_builder_new ();
+
+  for (int i = self->n_contours - 1; i >= 0; i--)
+    gsk_path_builder_add_contour (builder, gsk_contour_reverse (gsk_path_get_contour (self, i)));
+
+  return gsk_path_builder_free_to_path (builder);
+}
+
 /**
  * gsk_path_stroke:
  * @self: a `GskPath`
diff --git a/gsk/gskpath.h b/gsk/gskpath.h
index 1f208ae339..a94101fd80 100644
--- a/gsk/gskpath.h
+++ b/gsk/gskpath.h
@@ -109,6 +109,9 @@ gboolean                gsk_path_foreach                        (GskPath
                                                                  GskPathForeachFunc      func,
                                                                  gpointer                user_data);
 
+GDK_AVAILABLE_IN_ALL
+GskPath *               gsk_path_reverse                        (GskPath                *self);
+
 GDK_AVAILABLE_IN_ALL
 GskPath *               gsk_path_stroke                         (GskPath                *self,
                                                                  GskStroke              *stroke);


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