[gtk/path-ops: 5/8] path: Add gsk_path_transform




commit 20022682e48bc8dbe99ca352031b0a13e8c08acb
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Apr 6 22:27:55 2022 -0400

    path: Add gsk_path_transform
    
    This is an obvious operation to want for paths.

 gsk/gskpath.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gsk/gskpath.h |   4 +++
 2 files changed, 112 insertions(+)
---
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index 0762ceab1e..0dbbbbb468 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -24,6 +24,7 @@
 #include "gskcurveprivate.h"
 #include "gskpathbuilder.h"
 #include "gskstrokeprivate.h"
+#include "gsktransform.h"
 
 #include "gdk/gdk-private.h"
 
@@ -1290,6 +1291,113 @@ gsk_path_is_convex (GskPath *self)
   return gsk_contour_is_convex (gsk_path_get_contour (self, 0));
 }
 
+/**
+ * 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);
+}
+
+typedef struct
+{
+  GskTransform *transform;
+  GskPathBuilder *builder;
+} TransformData;
+
+static gboolean
+transform_cb (GskPathOperation        op,
+              const graphene_point_t *pts,
+              gsize                   n_pts,
+              float                   weight,
+              gpointer                user_data)
+{
+  TransformData *data = user_data;
+  graphene_point_t tp[4];
+
+  switch (op)
+    {
+    case GSK_PATH_CLOSE:
+      gsk_path_builder_close (data->builder);
+      break;
+
+    case GSK_PATH_MOVE:
+      gsk_transform_transform_point (data->transform, &pts[0], &tp[0]);
+      gsk_path_builder_move_to (data->builder, tp[0].x, tp[0].y);
+      break;
+
+    case GSK_PATH_LINE:
+      gsk_transform_transform_point (data->transform, &pts[1], &tp[1]);
+      gsk_path_builder_line_to (data->builder, tp[1].x, tp[1].y);
+      break;
+
+    case GSK_PATH_CURVE:
+      gsk_transform_transform_point (data->transform, &pts[1], &tp[1]);
+      gsk_transform_transform_point (data->transform, &pts[2], &tp[2]);
+      gsk_transform_transform_point (data->transform, &pts[3], &tp[3]);
+      gsk_path_builder_curve_to (data->builder,
+                                 tp[1].x, tp[1].y,
+                                 tp[2].x, tp[2].y,
+                                 tp[3].x, tp[3].y);
+      break;
+
+    case GSK_PATH_CONIC:
+      gsk_transform_transform_point (data->transform, &pts[1], &tp[1]);
+      gsk_transform_transform_point (data->transform, &pts[3], &tp[3]);
+      gsk_path_builder_conic_to (data->builder,
+                                 tp[1].x, tp[1].y,
+                                 tp[3].x, tp[3].y,
+                                 weight);
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  return TRUE;
+}
+
+/**
+ * gsk_path_transform:
+ * @self: a `GskPath`
+ * @transform: the transform to apply
+ *
+ * Applies the transform to all points of @self
+ * and returns the resulting path.
+ *
+ * Returns: a new `GskPath`
+ */
+GskPath *
+gsk_path_transform (GskPath      *self,
+                    GskTransform *transform)
+{
+  TransformData data;
+
+  data.transform = transform;
+  data.builder = gsk_path_builder_new ();
+
+  gsk_path_foreach (self,
+                    GSK_PATH_FOREACH_ALLOW_CURVE | GSK_PATH_FOREACH_ALLOW_CONIC,
+                    transform_cb,
+                    &data);
+
+  return gsk_path_builder_free_to_path (data.builder);
+}
+
 /**
  * gsk_path_stroke:
  * @self: a `GskPath`
diff --git a/gsk/gskpath.h b/gsk/gskpath.h
index bbc8b39884..80159669e8 100644
--- a/gsk/gskpath.h
+++ b/gsk/gskpath.h
@@ -115,6 +115,10 @@ gboolean                gsk_path_foreach                        (GskPath
 GDK_AVAILABLE_IN_ALL
 GskPath *               gsk_path_reverse                        (GskPath                *self);
 
+GDK_AVAILABLE_IN_ALL
+GskPath *               gsk_path_transform                      (GskPath                *self,
+                                                                 GskTransform           *transform);
+
 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]