[gtk/path-work-rebased: 74/118] path: Change semantics of gtk_path_builder_add_segment()




commit 44e62df2aea0783e28fbf7c5c8bd15ac63519896
Author: Benjamin Otte <otte redhat com>
Date:   Thu Dec 17 06:55:54 2020 +0100

    path: Change semantics of gtk_path_builder_add_segment()
    
    Allow start >= end to mean that the path continues at the beginning
    after reaching the end until it reaches the point at @end.

 gsk/gskcontour.c        | 28 ++++++++++-----
 gsk/gskcontourprivate.h |  1 +
 gsk/gskpathmeasure.c    | 91 ++++++++++++++++++++++++++++++++++---------------
 testsuite/gsk/path.c    | 23 ++++++++++---
 4 files changed, 102 insertions(+), 41 deletions(-)
---
diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c
index 5283bc4c2a..ab8d967f9c 100644
--- a/gsk/gskcontour.c
+++ b/gsk/gskcontour.c
@@ -76,6 +76,7 @@ struct _GskContourClass
   void                  (* add_segment)         (const GskContour       *contour,
                                                  GskPathBuilder         *builder,
                                                  gpointer                measure_data,
+                                                 gboolean                emit_move_to,
                                                  float                   start,
                                                  float                   end);
   int                   (* get_winding)         (const GskContour       *contour,
@@ -395,6 +396,7 @@ static void
 gsk_rect_contour_add_segment (const GskContour *contour,
                               GskPathBuilder   *builder,
                               gpointer          measure_data,
+                              gboolean          emit_move_to,
                               float             start,
                               float             end)
 {
@@ -404,7 +406,8 @@ gsk_rect_contour_add_segment (const GskContour *contour,
 
   if (start < w)
     {
-      gsk_path_builder_move_to (builder, self->x + start * (w / self->width), self->y);
+      if (emit_move_to)
+        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);
@@ -417,7 +420,7 @@ gsk_rect_contour_add_segment (const GskContour *contour,
 
   if (start < h)
     {
-      if (start >= 0)
+      if (start >= 0 && emit_move_to)
         gsk_path_builder_move_to (builder, self->x + self->width, self->y + start * (h / self->height));
       if (end <= h)
         {
@@ -431,7 +434,7 @@ gsk_rect_contour_add_segment (const GskContour *contour,
 
   if (start < w)
     {
-      if (start >= 0)
+      if (start >= 0 && emit_move_to)
         gsk_path_builder_move_to (builder, self->x + (w - start) * (w / self->width), self->y + 
self->height);
       if (end <= w)
         {
@@ -445,7 +448,7 @@ gsk_rect_contour_add_segment (const GskContour *contour,
 
   if (start < h)
     {
-      if (start >= 0)
+      if (start >= 0 && emit_move_to)
         gsk_path_builder_move_to (builder, self->x, self->y + (h - start) * (h / self->height));
       if (end <= h)
         {
@@ -781,6 +784,7 @@ static void
 gsk_circle_contour_add_segment (const GskContour *contour,
                                 GskPathBuilder   *builder,
                                 gpointer          measure_data,
+                                gboolean          emit_move_to,
                                 float             start,
                                 float             end)
 {
@@ -789,6 +793,8 @@ gsk_circle_contour_add_segment (const GskContour *contour,
   float length = self->radius * DEG_TO_RAD (delta);
   GskContour *segment;
 
+  if (!emit_move_to)
+    g_warning ("FIXME: somebody needs to decompose contours into segments differently");
   segment = gsk_circle_contour_new (&self->center, self->radius,
                                     self->start_angle + start/length * delta,
                                     self->start_angle + end/length * delta);
@@ -1323,6 +1329,7 @@ static void
 gsk_standard_contour_add_segment (const GskContour *contour,
                                   GskPathBuilder   *builder,
                                   gpointer          measure_data,
+                                  gboolean          emit_move_to,
                                   float             start,
                                   float             end)
 {
@@ -1374,7 +1381,8 @@ gsk_standard_contour_add_segment (const GskContour *contour,
         {
           gsk_curve_segment (&curve, start_progress, end_progress, &cut);
           start_point = gsk_curve_get_start_point (&cut);
-          gsk_path_builder_move_to (builder, start_point->x, start_point->y);
+          if (emit_move_to)
+            gsk_path_builder_move_to (builder, start_point->x, start_point->y);
           gsk_curve_builder_to (&cut, builder);
           return;
         }
@@ -1382,12 +1390,13 @@ gsk_standard_contour_add_segment (const GskContour *contour,
       gsk_curve_split (&curve, start_progress, NULL, &cut);
 
       start_point = gsk_curve_get_start_point (&cut);
-      gsk_path_builder_move_to (builder, start_point->x, start_point->y);
+      if (emit_move_to)
+        gsk_path_builder_move_to (builder, start_point->x, start_point->y);
       gsk_curve_builder_to (&cut, builder);
       i = start_measure->op + 1;
     }
-  else
-    i = 0;
+  else 
+    i = emit_move_to ? 0 : 1;
 
   for (; i < (end_measure ? end_measure->op : self->n_ops - 1); i++)
     {
@@ -1701,10 +1710,11 @@ void
 gsk_contour_add_segment (const GskContour *self,
                          GskPathBuilder   *builder,
                          gpointer          measure_data,
+                         gboolean          emit_move_to,
                          float             start,
                          float             end)
 {
-  self->klass->add_segment (self, builder, measure_data, start, end);
+  self->klass->add_segment (self, builder, measure_data, emit_move_to, start, end);
 }
 
 int
diff --git a/gsk/gskcontourprivate.h b/gsk/gskcontourprivate.h
index d9d80b898d..927205fdac 100644
--- a/gsk/gskcontourprivate.h
+++ b/gsk/gskcontourprivate.h
@@ -90,6 +90,7 @@ int                     gsk_contour_get_winding                 (const GskContou
 void                    gsk_contour_add_segment                 (const GskContour       *self,
                                                                  GskPathBuilder         *builder,
                                                                  gpointer                measure_data,
+                                                                 gboolean                emit_move_to,
                                                                  float                   start,
                                                                  float                   end);
 gboolean                gsk_contour_get_stroke_bounds           (const GskContour       *self,
diff --git a/gsk/gskpathmeasure.c b/gsk/gskpathmeasure.c
index 7fd599f948..595a16a586 100644
--- a/gsk/gskpathmeasure.c
+++ b/gsk/gskpathmeasure.c
@@ -525,6 +525,44 @@ gsk_path_measure_in_fill (GskPathMeasure   *self,
     }
 }
 
+static void
+gsk_path_builder_add_segment_chunk (GskPathBuilder *self,
+                                    GskPathMeasure *measure,
+                                    gboolean        emit_move_to,
+                                    float           start,
+                                    float           end)
+{
+  g_assert (start < end);
+
+  for (gsize i = measure->first; i < measure->last; i++)
+    {
+      if (measure->measures[i].length < start)
+        {
+          start -= measure->measures[i].length;
+          end -= measure->measures[i].length;
+        }
+      else if (start > 0 || end < measure->measures[i].length)
+        {
+          float len = MIN (end, measure->measures[i].length);
+          gsk_contour_add_segment (gsk_path_get_contour (measure->path, i),
+                                   self,
+                                   measure->measures[i].contour_data,
+                                   emit_move_to,
+                                   start,
+                                   len);
+          end -= len;
+          start = 0;
+          if (end <= 0)
+            break;
+        }
+      else
+        {
+          end -= measure->measures[i].length;
+          gsk_path_builder_add_contour (self, gsk_contour_dup (gsk_path_get_contour (measure->path, i)));
+        }
+      emit_move_to = TRUE;
+    }
+}
 
 /**
  * gsk_path_builder_add_segment:
@@ -539,7 +577,10 @@ gsk_path_measure_in_fill (GskPathMeasure   *self,
  * 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.
+ * If @start >= @end after clamping, the path will first add the segment
+ * from @start to the end of the path, and then add the segment from
+ * the beginning to @end. If the path is closed, these segments will
+ * be connected.
  **/
 void
 gsk_path_builder_add_segment (GskPathBuilder *builder,
@@ -547,40 +588,34 @@ gsk_path_builder_add_segment (GskPathBuilder *builder,
                               float           start,
                               float           end)
 {
-  gsize i;
-
   g_return_if_fail (builder != NULL);
   g_return_if_fail (measure != NULL);
 
   start = gsk_path_measure_clamp_distance (measure, start);
   end = gsk_path_measure_clamp_distance (measure, end);
-  if (start >= end)
-    return;
 
-  for (i = measure->first; i < measure->last; i++)
+  if (start < end)
     {
-      if (measure->measures[i].length < start)
-        {
-          start -= measure->measures[i].length;
-          end -= measure->measures[i].length;
-        }
-      else if (start > 0 || end < measure->measures[i].length)
-        {
-          float len = MIN (end, measure->measures[i].length);
-          gsk_contour_add_segment (gsk_path_get_contour (measure->path, i),
-                                   builder,
-                                   measure->measures[i].contour_data,
-                                   start,
-                                   len);
-          end -= len;
-          start = 0;
-          if (end <= 0)
-            break;
-        }
+      gsk_path_builder_add_segment_chunk (builder, measure, TRUE, start, end);
+    }
+  else
+    {
+      /* If the path is closed, we can connect the 2 subpaths. */
+      gboolean closed = gsk_path_measure_is_closed (measure);
+      gboolean need_move_to = !closed;
+
+      if (start < measure->length)
+        gsk_path_builder_add_segment_chunk (builder, measure,
+                                            TRUE,
+                                            start, measure->length);
       else
-        {
-          end -= measure->measures[i].length;
-          gsk_path_builder_add_contour (builder, gsk_contour_dup (gsk_path_get_contour (measure->path, i)));
-        }
+        need_move_to = TRUE;
+
+      if (end > 0)
+        gsk_path_builder_add_segment_chunk (builder, measure,
+                                            need_move_to,
+                                            0, end);
+      if (start == end && closed)
+        gsk_path_builder_close (builder);
     }
 }
diff --git a/testsuite/gsk/path.c b/testsuite/gsk/path.c
index 90b9ec922b..0f5d1e670a 100644
--- a/testsuite/gsk/path.c
+++ b/testsuite/gsk/path.c
@@ -609,7 +609,10 @@ test_segment_start (void)
       path1 = gsk_path_builder_free_to_path (builder);
       measure1 = gsk_path_measure_new (path1);
 
-      g_assert_cmpfloat_with_epsilon (seg_length, gsk_path_measure_get_length (measure1), epsilon);
+      if (seg_length == 0)
+        g_assert_cmpfloat_with_epsilon (gsk_path_measure_get_length (measure), gsk_path_measure_get_length 
(measure1), epsilon);
+      else
+        g_assert_cmpfloat_with_epsilon (seg_length, gsk_path_measure_get_length (measure1), epsilon);
 
       gsk_path_measure_unref (measure1);
       gsk_path_unref (path1);
@@ -642,7 +645,10 @@ test_segment_end (void)
       path1 = gsk_path_builder_free_to_path (builder);
       measure1 = gsk_path_measure_new (path1);
 
-      g_assert_cmpfloat_with_epsilon (seg_length, gsk_path_measure_get_length (measure1), epsilon);
+      if (seg_length == 0)
+        g_assert_cmpfloat_with_epsilon (gsk_path_measure_get_length (measure), gsk_path_measure_get_length 
(measure1), epsilon);
+      else
+        g_assert_cmpfloat_with_epsilon (seg_length, gsk_path_measure_get_length (measure1), epsilon);
 
       gsk_path_measure_unref (measure1);
       gsk_path_unref (path1);
@@ -655,8 +661,8 @@ test_segment_end (void)
 static void
 test_segment_chunk (void)
 {
-  GskPath *path, *path1;
-  GskPathMeasure *measure, *measure1;
+  GskPath *path, *path1, *path2;
+  GskPathMeasure *measure, *measure1, *measure2;
   GskPathBuilder *builder;
   float epsilon, length;
   guint i;
@@ -677,6 +683,15 @@ test_segment_chunk (void)
 
       g_assert_cmpfloat_with_epsilon (length / 2, gsk_path_measure_get_length (measure1), epsilon);
 
+      builder = gsk_path_builder_new ();
+      gsk_path_builder_add_segment (builder, measure, seg_start + length / 2, seg_start);
+      path2 = gsk_path_builder_free_to_path (builder);
+      measure2 = gsk_path_measure_new (path2);
+
+      g_assert_cmpfloat_with_epsilon (length / 2, gsk_path_measure_get_length (measure2), epsilon);
+
+      gsk_path_measure_unref (measure2);
+      gsk_path_unref (path2);
       gsk_path_measure_unref (measure1);
       gsk_path_unref (path1);
     }


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