[gtk/path-work-rebased: 12/118] pathmeasure: Add gsk_path_measure_add_segment()




commit 4f70e294eb20468efdec857c06098da4aab4bc25
Author: Benjamin Otte <otte redhat com>
Date:   Thu Nov 12 05:35:14 2020 +0100

    pathmeasure: Add gsk_path_measure_add_segment()
    
    This allows chunking paths, weeee.

 gsk/gskpath.c        | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 gsk/gskpathmeasure.c |  58 ++++++++++++++++
 gsk/gskpathmeasure.h |   7 +-
 gsk/gskpathprivate.h |   6 ++
 4 files changed, 253 insertions(+), 3 deletions(-)
---
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index aeb63e920c..9a02ebfd97 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -48,6 +48,11 @@ struct _GskContourClass
                                                  gpointer                measure_data);
   void                  (* copy)                (const GskContour       *contour,
                                                  GskContour             *dest);
+  void                  (* add_segment)         (const GskContour       *contour,
+                                                 GskPathBuilder         *builder,
+                                                 gpointer                measure_data,
+                                                 float                   start,
+                                                 float                   end);
 };
 
 struct _GskPath
@@ -182,6 +187,71 @@ gsk_rect_contour_copy (const GskContour *contour,
   *target = *self;
 }
 
+static void
+gsk_rect_contour_add_segment (const GskContour *contour,
+                              GskPathBuilder   *builder,
+                              gpointer          measure_data,
+                              float             start,
+                              float             end)
+{
+  const GskRectContour *self = (const GskRectContour *) contour;
+  float w = ABS (self->width);
+  float h = ABS (self->height);
+
+  if (start < w)
+    {
+      gsk_path_builder_move_to (builder, self->x + start * (w / self->width), self->y);
+      if (end <= w)
+        {
+          gsk_path_builder_line_to (builder, self->x + end * (w / self->width), self->y);
+          return;
+        }
+      gsk_path_builder_line_to (builder, self->x + self->width, self->y);
+    }
+  start -= w;
+  end -= w;
+
+  if (start < h)
+    {
+      if (start >= 0)
+        gsk_path_builder_move_to (builder, self->x + self->width, self->y + start * (h / self->height));
+      if (end <= h)
+        {
+          gsk_path_builder_line_to (builder, self->x + self->width, self->y + end * (h / self->height));
+          return;
+        }
+      gsk_path_builder_line_to (builder, self->x + self->width, self->y + self->height);
+    }
+  start -= h;
+  end -= h;
+
+  if (start < w)
+    {
+      if (start >= 0)
+        gsk_path_builder_move_to (builder, self->x + (w - start) * (w / self->width), self->y + 
self->height);
+      if (end <= w)
+        {
+          gsk_path_builder_line_to (builder, self->x + (w - end) * (w / self->width), self->y + 
self->height);
+          return;
+        }
+      gsk_path_builder_line_to (builder, self->x, self->y + self->height);
+    }
+  start -= w;
+  end -= w;
+
+  if (start < h)
+    {
+      if (start >= 0)
+        gsk_path_builder_move_to (builder, self->x, self->y + (h - start) * (h / self->height));
+      if (end <= h)
+        {
+          gsk_path_builder_line_to (builder, self->x, self->y + (h - end) * (h / self->height));
+          return;
+        }
+      gsk_path_builder_line_to (builder, self->x, self->y);
+    }
+}
+
 static const GskContourClass GSK_RECT_CONTOUR_CLASS =
 {
   sizeof (GskRectContour),
@@ -192,7 +262,8 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
   gsk_rect_contour_get_bounds,
   gsk_rect_contour_init_measure,
   gsk_rect_contour_free_measure,
-  gsk_rect_contour_copy
+  gsk_rect_contour_copy,
+  gsk_rect_contour_add_segment
 };
 
 static void
@@ -446,6 +517,102 @@ gsk_standard_contour_copy (const GskContour *contour,
   gsk_standard_contour_init (dest, self->ops, self->n_ops, self->points, self->n_points);
 }
 
+static void
+gsk_standard_contour_add_segment (const GskContour *contour,
+                                  GskPathBuilder   *builder,
+                                  gpointer          measure_data,
+                                  float             start,
+                                  float             end)
+{
+  GskStandardContour *self = (GskStandardContour *) contour;
+  gsize i;
+  float length;
+
+  for (i = 0; end > 0 && i < self->n_ops; i ++)
+    {
+      graphene_point_t *pt = &self->points[self->ops[i].point];
+
+      switch (self->ops[i].op)
+      {
+        case GSK_PATH_MOVE:
+          if (start <= 0.0)
+            {
+              gsk_path_builder_move_to (builder, pt[0].x, pt[0].y);
+              start = -1;
+            }
+          break;
+
+        case GSK_PATH_CLOSE:
+        case GSK_PATH_LINE:
+          length = graphene_point_distance (&pt[0], &pt[1], NULL, NULL);
+          if (length <= start)
+            {
+              start -= length;
+              end -= length;
+            }
+          else
+            {
+              if (start >= 0)
+                {
+                  graphene_point_t start_pt;
+                  graphene_point_interpolate (&pt[0], &pt[1], start / length, &start_pt);
+                  gsk_path_builder_move_to (builder, start_pt.x, start_pt.y);
+                  start = -1;
+                }
+              if (length <= end)
+                {
+                  gsk_path_builder_line_to (builder, pt[1].x, pt[1].y);
+                  end -= length;
+                }
+              else
+                {
+                  graphene_point_t end_pt;
+                  graphene_point_interpolate (&pt[0], &pt[1], end / length, &end_pt);
+                  gsk_path_builder_line_to (builder, end_pt.x, end_pt.y);
+                  return;
+                }
+            }
+          break;
+
+        case GSK_PATH_CURVE:
+          g_warning ("i'm not fat!");
+          length = graphene_point_distance (&pt[0], &pt[3], NULL, NULL);
+          if (length <= start)
+            {
+              start -= length;
+              end -= length;
+            }
+          else
+            {
+              if (start >= 0)
+                {
+                  graphene_point_t start_pt;
+                  graphene_point_interpolate (&pt[0], &pt[3], start / length, &start_pt);
+                  gsk_path_builder_move_to (builder, start_pt.x, start_pt.y);
+                  start = -1;
+                }
+              if (length <= end)
+                {
+                  gsk_path_builder_line_to (builder, pt[3].x, pt[3].y);
+                  end -= length;
+                }
+              else
+                {
+                  graphene_point_t end_pt;
+                  graphene_point_interpolate (&pt[0], &pt[3], end / length, &end_pt);
+                  gsk_path_builder_line_to (builder, end_pt.x, end_pt.y);
+                  return;
+                }
+            }
+          break;
+
+        default:
+          g_assert_not_reached();
+          return;
+      }
+    }
+}
+
 static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
 {
   sizeof (GskStandardContour),
@@ -456,7 +623,8 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
   gsk_standard_contour_get_bounds,
   gsk_standard_contour_init_measure,
   gsk_standard_contour_free_measure,
-  gsk_standard_contour_copy
+  gsk_standard_contour_copy,
+  gsk_standard_contour_add_segment
 };
 
 /* You must ensure the contour has enough size allocated,
@@ -841,6 +1009,19 @@ gsk_path_builder_add_contour (GskPathBuilder *builder,
   builder->contours = g_slist_prepend (builder->contours, copy);
 }
 
+void
+gsk_path_builder_add_contour_segment (GskPathBuilder *builder,
+                                      GskPath        *path,
+                                      gsize           i,
+                                      gpointer        measure_data,
+                                      float           start,
+                                      float           end)
+{
+  const GskContour *self = path->contours[i];
+
+  self->klass->add_segment (self, builder, measure_data, start, end);
+}
+
 /**
  * gsk_path_builder_new:
  *
diff --git a/gsk/gskpathmeasure.c b/gsk/gskpathmeasure.c
index 99759a47b0..28375051f4 100644
--- a/gsk/gskpathmeasure.c
+++ b/gsk/gskpathmeasure.c
@@ -154,3 +154,61 @@ gsk_path_measure_get_length (GskPathMeasure *self)
 
   return self->length;
 }
+
+/**
+ * gsk_path_measure_add_segment:
+ * @self: a `GskPathMeasure`
+ * @builder: the builder to add the segment to
+ * @start: start distance into the path
+ * @end: end distance into the path
+ *
+ * Adds to @builder the segment of @path inbetween @start and @end.
+ *
+ * The distances are given relative to the length of @self's path,
+ * from 0 for the beginning of the path to [method@Gsk.PathMeasure.get_length]
+ * for the end of the path. The values will be clamped to that range.
+ *
+ * If @start >= @end after clamping, no path will be added.
+ **/
+void
+gsk_path_measure_add_segment (GskPathMeasure *self,
+                              GskPathBuilder *builder,
+                              float           start,
+                              float           end)
+{
+  gsize i;
+
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (builder != NULL);
+
+  start = CLAMP (start, 0, self->length);
+  end = CLAMP (end, 0, self->length);
+  if (start >= end)
+    return;
+
+  for (i = 0; i < self->n_contours; i++)
+    {
+      if (self->measures[i].length < start)
+        {
+          start -= self->measures[i].length;
+          end -= self->measures[i].length;
+        }
+      else if (start > 0 || end < self->measures[i].length)
+        {
+          float len = MIN (end, self->measures[i].length);
+          gsk_path_builder_add_contour_segment (builder,
+                                                self->path,
+                                                i,
+                                                self->measures[i].contour_data,
+                                                start,
+                                                len);
+          start = 0;
+          end -= len;
+        }
+      else
+        {
+          end -= self->measures[i].length;
+          gsk_path_builder_add_contour (builder, self->path, i);
+        }
+    }
+}
diff --git a/gsk/gskpathmeasure.h b/gsk/gskpathmeasure.h
index 2941176e60..abf4202eb6 100644
--- a/gsk/gskpathmeasure.h
+++ b/gsk/gskpathmeasure.h
@@ -25,7 +25,7 @@
 #endif
 
 
-#include <gsk/gsktypes.h>
+#include <gsk/gskpath.h>
 
 G_BEGIN_DECLS
 
@@ -44,6 +44,11 @@ void                    gsk_path_measure_unref                  (GskPathMeasure
 GDK_AVAILABLE_IN_ALL
 float                   gsk_path_measure_get_length             (GskPathMeasure         *self);
 
+GDK_AVAILABLE_IN_ALL
+void                    gsk_path_measure_add_segment            (GskPathMeasure         *self,
+                                                                 GskPathBuilder         *builder,
+                                                                 float                   start,
+                                                                 float                   end);
 G_END_DECLS
 
 #endif /* __GSK_PATH_MEASURE_H__ */
diff --git a/gsk/gskpathprivate.h b/gsk/gskpathprivate.h
index aae06f1dd3..7238c44418 100644
--- a/gsk/gskpathprivate.h
+++ b/gsk/gskpathprivate.h
@@ -37,6 +37,12 @@ void                    gsk_contour_free_measure                (GskPath
 void                    gsk_path_builder_add_contour            (GskPathBuilder       *builder,
                                                                  GskPath              *path,
                                                                  gsize                 i);
+void                    gsk_path_builder_add_contour_segment    (GskPathBuilder       *builder,
+                                                                 GskPath              *path,
+                                                                 gsize                 i,
+                                                                 gpointer              measure_data,
+                                                                 float                 start,
+                                                                 float                 end);
 
 G_END_DECLS
 


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