[gtk/path-work-rebased: 10/105] path: Split GskPathBuilder into its own file




commit 4bcc4529dac8656b57dfa8174ab4fb71e5a529b4
Author: Benjamin Otte <otte redhat com>
Date:   Sat Nov 28 05:36:53 2020 +0100

    path: Split GskPathBuilder into its own file
    
    ... and add missing API docs.

 gsk/gsk.h            |   1 +
 gsk/gskpath.c        | 632 +++++++++++----------------------------------------
 gsk/gskpath.h        |  48 ----
 gsk/gskpathbuilder.c | 458 +++++++++++++++++++++++++++++++++++++
 gsk/gskpathbuilder.h |  80 +++++++
 gsk/gskpathmeasure.c |  13 +-
 gsk/gskpathprivate.h |  48 +++-
 gsk/gsktypes.h       |   1 +
 gsk/meson.build      |   2 +
 9 files changed, 715 insertions(+), 568 deletions(-)
---
diff --git a/gsk/gsk.h b/gsk/gsk.h
index 9b9ddaceae..b26fdc66be 100644
--- a/gsk/gsk.h
+++ b/gsk/gsk.h
@@ -23,6 +23,7 @@
 #include <gsk/gskenums.h>
 #include <gsk/gskglshader.h>
 #include <gsk/gskpath.h>
+#include <gsk/gskpathbuilder.h>
 #include <gsk/gskpathmeasure.h>
 #include <gsk/gskrenderer.h>
 #include <gsk/gskrendernode.h>
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index ae7cad3590..7c86ccaf50 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -21,15 +21,10 @@
 
 #include "gskpathprivate.h"
 
+#include "gskpathbuilder.h"
 #include "gsksplineprivate.h"
 
 
-typedef enum
-{
-  GSK_PATH_FLAT,
-  GSK_PATH_CLOSED
-} GskPathFlags;
-
 typedef struct _GskContour GskContour;
 typedef struct _GskContourClass GskContourClass;
 
@@ -117,10 +112,6 @@ gsk_contour_get_size_default (const GskContour *contour)
   return contour->klass->struct_size;
 }
 
-static GskContour *
-gsk_path_builder_add_contour_by_klass (GskPathBuilder        *builder,
-                                       const GskContourClass *klass);
-
 static void
 gsk_find_point_on_line (const graphene_point_t *a,
                         const graphene_point_t *b,
@@ -320,7 +311,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;
@@ -377,7 +368,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)
@@ -487,20 +478,21 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
   gsk_rect_contour_add_segment
 };
 
-static void
-gsk_rect_contour_init (GskContour *contour,
-                       float       x,
-                       float       y,
-                       float       width,
-                       float       height)
+GskContour *
+gsk_rect_contour_new (const graphene_rect_t *rect)
 {
-  GskRectContour *self = (GskRectContour *) contour;
+  GskRectContour *self;
+
+  self = g_new0 (GskRectContour, 1);
 
   self->contour.klass = &GSK_RECT_CONTOUR_CLASS;
-  self->x = x;
-  self->y = y;
-  self->width = width;
-  self->height = height;
+
+  self->x = rect->origin.x;
+  self->y = rect->origin.y;
+  self->width = rect->size.width;
+  self->height = rect->size.height;
+
+  return (GskContour *) self;
 }
 
 /* CIRCLE CONTOUR */
@@ -737,13 +729,6 @@ gsk_circle_contour_copy (const GskContour *contour,
   *target = *self;
 }
 
-static void
-gsk_circle_contour_init (GskContour             *contour,
-                         const graphene_point_t *center,
-                         float                   radius,
-                         float                   start_angle,
-                         float                   end_angle);
-
 static void
 gsk_circle_contour_add_segment (const GskContour *contour,
                                 GskPathBuilder   *builder,
@@ -756,12 +741,10 @@ gsk_circle_contour_add_segment (const GskContour *contour,
   float length = self->radius * DEG_TO_RAD (delta);
   GskContour *segment;
 
-  segment = gsk_path_builder_add_contour_by_klass (builder, contour->klass);
-
-  gsk_circle_contour_init (segment,
-                           &self->center, self->radius,
-                           self->start_angle + start/length * delta,
-                           self->start_angle + end/length * delta);
+  segment = gsk_circle_contour_new (&self->center, self->radius,
+                                    self->start_angle + start/length * delta,
+                                    self->start_angle + end/length * delta);
+  gsk_path_builder_add_contour (builder, segment);
 }
 
 static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
@@ -781,14 +764,17 @@ static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
   gsk_circle_contour_add_segment
 };
 
-static void
-gsk_circle_contour_init (GskContour             *contour,
-                         const graphene_point_t *center,
-                         float                   radius,
-                         float                   start_angle,
-                         float                   end_angle)
+GskContour *
+gsk_circle_contour_new (const graphene_point_t *center,
+                        float                   radius,
+                        float                   start_angle,
+                        float                   end_angle)
 {
-  GskCircleContour *self = (GskCircleContour *) contour;
+  GskCircleContour *self;
+
+  self = g_new0 (GskCircleContour, 1);
+
+  self->contour.klass = &GSK_CIRCLE_CONTOUR_CLASS;
 
   g_assert (fabs (start_angle - end_angle) <= 360);
 
@@ -797,17 +783,12 @@ gsk_circle_contour_init (GskContour             *contour,
   self->radius = radius;
   self->start_angle = start_angle;
   self->end_angle = end_angle;
+
+  return (GskContour *) self;
 }
 
 /* STANDARD CONTOUR */
 
-typedef struct _GskStandardOperation GskStandardOperation;
-
-struct _GskStandardOperation {
-  GskPathOperation op;
-  gsize point; /* index into points array of the start point (last point of previous op) */
-};
-
 typedef struct _GskStandardContour GskStandardContour;
 struct _GskStandardContour
 {
@@ -1212,7 +1193,7 @@ gsk_standard_contour_get_closest_point (const GskContour       *contour,
 
           gsk_standard_contour_measure_get_point (self, measure->op, found_progress, &p, out_tangent ? &t : 
NULL);
           dist = graphene_point_distance (point, &p, NULL, NULL);
-          /* double check that the point actually is closer */ 
+          /* double check that the point actually is closer */
           //g_print ("!!! %zu: (%g-%g) dist %g\n", i, measure->start, measure->end, dist);
           if (dist <= threshold)
             {
@@ -1427,12 +1408,12 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
  * see gsk_standard_contour_compute_size()
  */
 static void
-gsk_standard_contour_init (GskContour *contour,
-                           GskPathFlags flags,
-                           const GskStandardOperation *ops,
-                           gsize n_ops,
-                           const graphene_point_t *points,
-                           gsize n_points)
+gsk_standard_contour_init (GskContour   *contour,
+                           GskPathFlags  flags,
+                           const         GskStandardOperation *ops,
+                           gsize         n_ops,
+                           const         graphene_point_t *points,
+                           gsize         n_points)
 {
   GskStandardContour *self = (GskStandardContour *) contour;
 
@@ -1446,6 +1427,22 @@ gsk_standard_contour_init (GskContour *contour,
   memcpy (self->points, points, sizeof (graphene_point_t) * n_points);
 }
 
+GskContour *
+gsk_standard_contour_new (GskPathFlags flags,
+                          const        GskStandardOperation *ops,
+                          gsize        n_ops,
+                          const        graphene_point_t *points,
+                          gsize        n_points)
+{
+  GskContour *contour;
+
+  contour = g_malloc0 (gsk_standard_contour_compute_size (n_ops, n_points));
+
+  gsk_standard_contour_init (contour, flags, ops, n_ops, points, n_points);
+
+  return contour;
+}
+
 /* CONTOUR */
 
 static gsize
@@ -1454,24 +1451,6 @@ gsk_contour_get_size (const GskContour *contour)
   return contour->klass->get_size (contour);
 }
 
-static void
-gsk_contour_copy (GskContour       *dest,
-                  const GskContour *src)
-{
-  src->klass->copy (src, dest);
-}
-
-static GskContour *
-gsk_contour_dup (const GskContour *src)
-{
-  GskContour *copy;
-
-  copy = g_malloc0 (gsk_contour_get_size (src));
-  gsk_contour_copy (copy, src);
-
-  return copy;
-}
-
 static gboolean
 gsk_contour_foreach (const GskContour   *contour,
                      float               tolerance,
@@ -1540,18 +1519,78 @@ gsk_contour_get_closest_point (GskPath                *path,
                                          out_tangent);
 }
 
+void
+gsk_contour_add_segment (const GskContour *self,
+                         GskPathBuilder   *builder,
+                         gpointer          measure_data,
+                         float             start,
+                         float             end)
+{
+  self->klass->add_segment (self, builder, measure_data, start, end);
+}
+
+static inline void
+gsk_contour_copy (GskContour       *dest,
+                  const GskContour *src)
+{
+  src->klass->copy (src, dest);
+}
+
+GskContour *
+gsk_contour_dup (const GskContour *src)
+{
+  GskContour *copy;
+
+  copy = g_malloc0 (gsk_contour_get_size (src));
+  gsk_contour_copy (copy, src);
+
+  return copy;
+}
+
 /* PATH */
 
-static GskPath *
-gsk_path_alloc (gsize extra_size)
+GskPath *
+gsk_path_new_from_contours (const GSList *contours)
 {
-  GskPath *self;
+  GskPath *path;
+  const GSList *l;
+  gsize size;
+  gsize n_contours;
+  guint8 *contour_data;
+  GskPathFlags flags;
 
-  self = g_malloc0 (sizeof (GskPath) + extra_size);
-  self->ref_count = 1;
-  self->n_contours = 0;
+  flags = GSK_PATH_CLOSED | GSK_PATH_FLAT;
+  size = 0;
+  n_contours = 0;
+  for (l = contours; l; l = l->next)
+    {
+      GskContour *contour = l->data;
 
-  return self;
+      n_contours++;
+      size += sizeof (GskContour *);
+      size += gsk_contour_get_size (contour);
+      flags &= contour->klass->get_flags (contour);
+    }
+
+  path = g_malloc0 (sizeof (GskPath) + size);
+  path->ref_count = 1;
+  path->flags = flags;
+  path->n_contours = n_contours;
+  contour_data = (guint8 *) &path->contours[n_contours];
+  n_contours = 0;
+
+  for (l = contours; l; l = l->next)
+    {
+      GskContour *contour = l->data;
+
+      path->contours[n_contours] = (GskContour *) contour_data;
+      gsk_contour_copy ((GskContour *) contour_data, contour);
+      size = gsk_contour_get_size (contour);
+      contour_data += size;
+      n_contours++;
+    }
+
+  return path;
 }
 
 /**
@@ -1647,6 +1686,13 @@ gsk_path_unref (GskPath *self)
   g_free (self);
 }
 
+const GskContour *
+gsk_path_get_contour (GskPath *path,
+                      gsize    i)
+{
+  return path->contours[i];
+}
+
 /**
  * gsk_path_print:
  * @self: a `GskPath`
@@ -1890,425 +1936,3 @@ gsk_path_foreach_with_tolerance (GskPath            *self,
 
   return TRUE;
 }
-
-/* BUILDER */
-
-/**
- * GskPathBuilder:
- *
- * A `GskPathBuilder` struct is an opaque struct. It is meant to
- * not be kept around and only be used to create new `GskPath`
- * objects.
- */
-
-struct _GskPathBuilder
-{
-  int ref_count;
-
-  GSList *contours; /* (reverse) list of already recorded contours */
-
-  GskPathFlags flags; /* flags for the current path */
-  GArray *ops; /* operations for current contour - size == 0 means no current contour */
-  GArray *points; /* points for the operations */
-};
-
-G_DEFINE_BOXED_TYPE (GskPathBuilder,
-                     gsk_path_builder,
-                     gsk_path_builder_ref,
-                     gsk_path_builder_unref)
-
-
-void
-gsk_path_builder_add_contour (GskPathBuilder *builder,
-                              GskPath        *path,
-                              gsize           i)
-{
-  GskContour *copy;
-
-  copy = gsk_contour_dup (path->contours[i]);
-  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:
- *
- * Create a new `GskPathBuilder` object. The resulting builder
- * would create an empty `GskPath`. Use addition functions to add
- * types to it.
- *
- * Returns: a new `GskPathBuilder`
- **/
-GskPathBuilder *
-gsk_path_builder_new (void)
-{
-  GskPathBuilder *builder;
-
-  builder = g_slice_new0 (GskPathBuilder);
-  builder->ref_count = 1;
-
-  builder->ops = g_array_new (FALSE, FALSE, sizeof (GskStandardOperation));
-  builder->points = g_array_new (FALSE, FALSE, sizeof (graphene_point_t));
-  return builder;
-}
-
-/**
- * gsk_path_builder_ref:
- * @builder: a `GskPathBuilder`
- *
- * Acquires a reference on the given @builder.
- *
- * This function is intended primarily for bindings. `GskPathBuilder` objects
- * should not be kept around.
- *
- * Returns: (transfer none): the given `GskPathBuilder` with
- *   its reference count increased
- */
-GskPathBuilder *
-gsk_path_builder_ref (GskPathBuilder *builder)
-{
-  g_return_val_if_fail (builder != NULL, NULL);
-  g_return_val_if_fail (builder->ref_count > 0, NULL);
-
-  builder->ref_count += 1;
-
-  return builder;
-}
-
-static void
-gsk_path_builder_append_current (GskPathBuilder         *builder,
-                                 GskPathOperation        op,
-                                 gsize                   n_points,
-                                 const graphene_point_t *points)
-{
-  g_assert (builder->ops->len > 0);
-  g_assert (builder->points->len > 0);
-  g_assert (n_points > 0);
-
-  g_array_append_vals (builder->ops, &(GskStandardOperation) { op, builder->points->len - 1 }, 1);
-  g_array_append_vals (builder->points, points, n_points);
-}
-
-static void
-gsk_path_builder_end_current (GskPathBuilder *builder)
-{
-  GskContour *contour;
-
-  if (builder->ops->len == 0)
-   return;
-
-  contour = g_malloc0 (gsk_standard_contour_compute_size (builder->ops->len, builder->points->len));
-  gsk_standard_contour_init (contour,
-                             0,
-                             (GskStandardOperation *) builder->ops->data,
-                             builder->ops->len,
-                             (graphene_point_t *) builder->points->data,
-                             builder->points->len);
-  builder->contours = g_slist_prepend (builder->contours, contour);
-
-  g_array_set_size (builder->ops, 0);
-  g_array_set_size (builder->points, 0);
-}
-
-static void
-gsk_path_builder_clear (GskPathBuilder *builder)
-{
-  gsk_path_builder_end_current (builder);
-
-  g_slist_free_full (builder->contours, g_free);
-  builder->contours = NULL;
-}
-
-/**
- * gsk_path_builder_unref:
- * @builder: a `GskPathBuilder`
- *
- * Releases a reference on the given @builder.
- */
-void
-gsk_path_builder_unref (GskPathBuilder *builder)
-{
-  g_return_if_fail (builder != NULL);
-  g_return_if_fail (builder->ref_count > 0);
-
-  builder->ref_count -= 1;
-
-  if (builder->ref_count > 0)
-    return;
-
-  gsk_path_builder_clear (builder);
-  g_array_unref (builder->ops);
-  g_array_unref (builder->points);
-  g_slice_free (GskPathBuilder, builder);
-}
-
-/**
- * gsk_path_builder_free_to_path: (skip)
- * @builder: a `GskPathBuilder`
- *
- * Creates a new `GskPath` from the current state of the
- * given @builder, and frees the @builder instance.
- *
- * Returns: (transfer full): the newly created `GskPath`
- *   with all the contours added to @builder
- */
-GskPath *
-gsk_path_builder_free_to_path (GskPathBuilder *builder)
-{
-  GskPath *res;
-
-  g_return_val_if_fail (builder != NULL, NULL);
-
-  res = gsk_path_builder_to_path (builder);
-
-  gsk_path_builder_unref (builder);
-
-  return res;
-}
-
-/**
- * gsk_path_builder_to_path:
- * @builder: a `GskPathBuilder`
- *
- * Creates a new `GskPath` from the given @builder.
- *
- * The given `GskPathBuilder` is reset once this function returns;
- * you cannot call this function multiple times on the same @builder instance.
- *
- * This function is intended primarily for bindings. C code should use
- * gsk_path_builder_free_to_path().
- *
- * Returns: (transfer full): the newly created `GskPath`
- *   with all the contours added to @builder
- */
-GskPath *
-gsk_path_builder_to_path (GskPathBuilder *builder)
-{
-  GskPath *path;
-  GSList *l;
-  gsize size;
-  gsize n_contours;
-  guint8 *contour_data;
-  GskPathFlags flags;
-
-  g_return_val_if_fail (builder != NULL, NULL);
-
-  gsk_path_builder_end_current (builder);
-
-  builder->contours = g_slist_reverse (builder->contours);
-  flags = GSK_PATH_CLOSED | GSK_PATH_FLAT;
-  size = 0;
-  n_contours = 0;
-  for (l = builder->contours; l; l = l->next)
-    {
-      GskContour *contour = l->data;
-
-      n_contours++;
-      size += sizeof (GskContour *);
-      size += gsk_contour_get_size (contour);
-      flags &= contour->klass->get_flags (contour);
-    }
-
-  path = gsk_path_alloc (size);
-  path->flags = flags;
-  path->n_contours = n_contours;
-  contour_data = (guint8 *) &path->contours[n_contours];
-  n_contours = 0;
-
-  for (l = builder->contours; l; l = l->next)
-    {
-      GskContour *contour = l->data;
-
-      path->contours[n_contours] = (GskContour *) contour_data;
-      gsk_contour_copy ((GskContour *) contour_data, contour);
-      size = gsk_contour_get_size (contour);
-      contour_data += size;
-      n_contours++;
-    }
-
-  gsk_path_builder_clear (builder);
-
-  return path;
-}
-
-/**
- * gsk_path_builder_add_path:
- * @builder: a #GskPathBuilder
- * @path: (transfer none): the path to append
- *
- * Appends all of @path to @builder.
- **/
-void
-gsk_path_builder_add_path (GskPathBuilder *builder,
-                           GskPath        *path)
-{
-  gsize i;
-
-  g_return_if_fail (builder != NULL);
-  g_return_if_fail (path != NULL);
-
-  for (i = 0; i < path->n_contours; i++)
-    {
-      gsk_path_builder_add_contour (builder, path, i);
-    }
-}
-
-static GskContour *
-gsk_path_builder_add_contour_by_klass (GskPathBuilder        *builder,
-                                       const GskContourClass *klass)
-{
-  GskContour *contour;
-
-  gsk_path_builder_end_current (builder);
-
-  contour = g_malloc0 (klass->struct_size);
-  builder->contours = g_slist_prepend (builder->contours, contour);
-
-  return contour;
-}
-
-/**
- * gsk_path_builder_add_rect:
- * @builder: A `GskPathBuilder`
- * @rect: The rectangle to create a path for
- *
- * Creates a path representing the given rectangle.
- *
- * If the width or height of the rectangle is negative, the start
- * point will be on the right or bottom, respectively.
- *
- * If the the width or height are 0, the path will be a closed
- * horizontal or vertical line. If both are 0, it'll be a closed dot.
- *
- * Returns: a new `GskPath` representing a rectangle
- **/
-void
-gsk_path_builder_add_rect (GskPathBuilder        *builder,
-                           const graphene_rect_t *rect)
-{
-  GskContour *contour;
-
-  g_return_if_fail (builder != NULL);
-
-  contour = gsk_path_builder_add_contour_by_klass (builder, &GSK_RECT_CONTOUR_CLASS);
-  gsk_rect_contour_init (contour,
-                         rect->origin.x, rect->origin.y,
-                         rect->size.width, rect->size.height);
-}
-
-/**
- * gsk_path_builder_add_circle:
- * @builder: a #GskPathBuilder
- * @center: the center of the circle
- * @radius: the radius of the circle
- *
- * Adds a circle with the @center and @radius.
- **/
-void
-gsk_path_builder_add_circle (GskPathBuilder         *builder,
-                             const graphene_point_t *center,
-                             float                   radius)
-{
-  GskContour *contour;
-
-  g_return_if_fail (builder != NULL);
-  g_return_if_fail (center != NULL);
-  g_return_if_fail (radius > 0);
-
-  contour = gsk_path_builder_add_contour_by_klass (builder, &GSK_CIRCLE_CONTOUR_CLASS);
-  gsk_circle_contour_init (contour, center, radius, 0, 360);
-}
-
-void
-gsk_path_builder_move_to (GskPathBuilder *builder,
-                          float           x,
-                          float           y)
-{
-  g_return_if_fail (builder != NULL);
-
-  gsk_path_builder_end_current (builder);
-
-  builder->flags = GSK_PATH_FLAT;
-  g_array_append_vals (builder->ops, &(GskStandardOperation) { GSK_PATH_MOVE, 0 }, 1);
-  g_array_append_val (builder->points, GRAPHENE_POINT_INIT(x, y));
-}
-
-void
-gsk_path_builder_line_to (GskPathBuilder *builder,
-                          float           x,
-                          float           y)
-{
-  g_return_if_fail (builder != NULL);
-
-  if (builder->ops->len == 0)
-    {
-      gsk_path_builder_move_to (builder, x, y);
-      return;
-    }
-
-  /* skip the line if it goes to the same point */
-  if (graphene_point_equal (&g_array_index (builder->points, graphene_point_t, builder->points->len - 1),
-                            &GRAPHENE_POINT_INIT (x, y)))
-    return;
-
-  gsk_path_builder_append_current (builder,
-                                   GSK_PATH_LINE,
-                                   1, (graphene_point_t[1]) {
-                                     GRAPHENE_POINT_INIT (x, y)
-                                   });
-}
-
-void
-gsk_path_builder_curve_to (GskPathBuilder *builder,
-                           float           x1,
-                           float           y1,
-                           float           x2,
-                           float           y2,
-                           float           x3,
-                           float           y3)
-{
-  g_return_if_fail (builder != NULL);
-
-  if (builder->ops->len == 0)
-    gsk_path_builder_move_to (builder, x1, y1);
-
-  builder->flags &= ~GSK_PATH_FLAT;
-  gsk_path_builder_append_current (builder,
-                                   GSK_PATH_CURVE,
-                                   3, (graphene_point_t[3]) {
-                                     GRAPHENE_POINT_INIT (x1, y1),
-                                     GRAPHENE_POINT_INIT (x2, y2),
-                                     GRAPHENE_POINT_INIT (x3, y3)
-                                   });
-}
-
-void
-gsk_path_builder_close (GskPathBuilder *builder)
-{
-  g_return_if_fail (builder != NULL);
-
-  if (builder->ops->len == 0)
-    return;
-
-  builder->flags |= GSK_PATH_CLOSED;
-  gsk_path_builder_append_current (builder,
-                                   GSK_PATH_CLOSE,
-                                   1, (graphene_point_t[1]) {
-                                     g_array_index (builder->points, graphene_point_t, 0)
-                                   });
-
-  gsk_path_builder_end_current (builder);
-}
-
diff --git a/gsk/gskpath.h b/gsk/gskpath.h
index c8b62568e2..9fb24f14d7 100644
--- a/gsk/gskpath.h
+++ b/gsk/gskpath.h
@@ -79,54 +79,6 @@ gboolean                gsk_path_foreach                        (GskPath
                                                                  GskPathForeachFunc      func,
                                                                  gpointer                user_data);
 
-#define GSK_TYPE_PATH_BUILDER (gsk_path_builder_get_type ())
-
-typedef struct _GskPathBuilder GskPathBuilder;
-
-GDK_AVAILABLE_IN_ALL
-GType                   gsk_path_builder_get_type               (void) G_GNUC_CONST;
-
-GDK_AVAILABLE_IN_ALL
-GskPathBuilder *        gsk_path_builder_new                    (void);
-GDK_AVAILABLE_IN_ALL
-GskPathBuilder *        gsk_path_builder_ref                    (GskPathBuilder         *builder);
-GDK_AVAILABLE_IN_ALL
-void                    gsk_path_builder_unref                  (GskPathBuilder         *builder);
-GDK_AVAILABLE_IN_ALL
-GskPath *               gsk_path_builder_free_to_path           (GskPathBuilder         *builder) 
G_GNUC_WARN_UNUSED_RESULT;
-GDK_AVAILABLE_IN_ALL
-GskPath *               gsk_path_builder_to_path                (GskPathBuilder         *builder) 
G_GNUC_WARN_UNUSED_RESULT;
-
-GDK_AVAILABLE_IN_ALL
-void                    gsk_path_builder_add_path               (GskPathBuilder         *builder,
-                                                                 GskPath                *path);
-GDK_AVAILABLE_IN_ALL
-void                    gsk_path_builder_add_rect               (GskPathBuilder         *builder,
-                                                                 const graphene_rect_t  *rect);
-GDK_AVAILABLE_IN_ALL
-void                    gsk_path_builder_add_circle             (GskPathBuilder         *builder,
-                                                                 const graphene_point_t *center,
-                                                                 float                   radius);
-
-GDK_AVAILABLE_IN_ALL
-void                    gsk_path_builder_move_to                (GskPathBuilder         *builder,
-                                                                 float                   x,
-                                                                 float                   y);
-GDK_AVAILABLE_IN_ALL
-void                    gsk_path_builder_line_to                (GskPathBuilder         *builder,
-                                                                 float                   x,
-                                                                 float                   y);
-GDK_AVAILABLE_IN_ALL
-void                    gsk_path_builder_curve_to               (GskPathBuilder         *builder,
-                                                                 float                   x1,
-                                                                 float                   y1,
-                                                                 float                   x2,
-                                                                 float                   y2,
-                                                                 float                   x3,
-                                                                 float                   y3);
-GDK_AVAILABLE_IN_ALL
-void                    gsk_path_builder_close                  (GskPathBuilder         *builder);
-
 G_END_DECLS
 
 #endif /* __GSK_PATH_H__ */
diff --git a/gsk/gskpathbuilder.c b/gsk/gskpathbuilder.c
new file mode 100644
index 0000000000..f296959dde
--- /dev/null
+++ b/gsk/gskpathbuilder.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright © 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gskpathbuilder.h"
+
+#include "gskpathprivate.h"
+
+/**
+ * GskPathBuilder:
+ *
+ * A `GskPathBuilder` is an auxiliary object that is used to
+ * create new `GskPath` objects.
+ *
+ * A path is constructed like this:
+ *
+ * ```
+ * GskPath *
+ * construct_path (void)
+ * {
+ *   GskPathBuilder *builder;
+ *
+ *   builder = gsk_path_builder_new ();
+ *
+ *   // add contours to the path here
+ *
+ *   return gsk_path_builder_free_to_path (builder);
+ * }
+ * ```
+ *
+ * Adding contours to the path can be done in two ways.
+ * The easiest option is to use the `gsk_path_builder_add_*` group
+ * of functions that add predefined contours to the current path,
+ * either common shapes like [method@Gsk.PathBuilder.add_circle]
+ * or by adding from other paths like [method@Gsk.PathBuilder.add_path].
+ *
+ * The other option is to define each line and curve manually with
+ * the `gsk_path_builder_*_to` group of functions. You start with
+ * a call to [method@Gsk.PathBuilder.move_to] to set the starting point
+ * and then use multiple calls to any of the drawing functions to
+ * move the pen along the plane. Once you are done, you can call
+ * [method@Gsk.PathBuilder.close] to close the path by connecting it
+ * back with a line to the starting point.
+ * This is similar for how paths are drawn in Cairo.
+ */
+
+struct _GskPathBuilder
+{
+  int ref_count;
+
+  GSList *contours; /* (reverse) list of already recorded contours */
+
+  GskPathFlags flags; /* flags for the current path */
+  GArray *ops; /* operations for current contour - size == 0 means no current contour */
+  GArray *points; /* points for the operations */
+};
+
+G_DEFINE_BOXED_TYPE (GskPathBuilder,
+                     gsk_path_builder,
+                     gsk_path_builder_ref,
+                     gsk_path_builder_unref)
+
+
+/**
+ * gsk_path_builder_new:
+ *
+ * Create a new `GskPathBuilder` object. The resulting builder
+ * would create an empty `GskPath`. Use addition functions to add
+ * types to it.
+ *
+ * Returns: a new `GskPathBuilder`
+ **/
+GskPathBuilder *
+gsk_path_builder_new (void)
+{
+  GskPathBuilder *builder;
+
+  builder = g_slice_new0 (GskPathBuilder);
+  builder->ref_count = 1;
+
+  builder->ops = g_array_new (FALSE, FALSE, sizeof (GskStandardOperation));
+  builder->points = g_array_new (FALSE, FALSE, sizeof (graphene_point_t));
+  return builder;
+}
+
+/**
+ * gsk_path_builder_ref:
+ * @builder: a `GskPathBuilder`
+ *
+ * Acquires a reference on the given @builder.
+ *
+ * This function is intended primarily for bindings. `GskPathBuilder` objects
+ * should not be kept around.
+ *
+ * Returns: (transfer none): the given `GskPathBuilder` with
+ *   its reference count increased
+ */
+GskPathBuilder *
+gsk_path_builder_ref (GskPathBuilder *builder)
+{
+  g_return_val_if_fail (builder != NULL, NULL);
+  g_return_val_if_fail (builder->ref_count > 0, NULL);
+
+  builder->ref_count += 1;
+
+  return builder;
+}
+
+static void
+gsk_path_builder_append_current (GskPathBuilder         *builder,
+                                 GskPathOperation        op,
+                                 gsize                   n_points,
+                                 const graphene_point_t *points)
+{
+  g_assert (builder->ops->len > 0);
+  g_assert (builder->points->len > 0);
+  g_assert (n_points > 0);
+
+  g_array_append_vals (builder->ops, &(GskStandardOperation) { op, builder->points->len - 1 }, 1);
+  g_array_append_vals (builder->points, points, n_points);
+}
+
+static void
+gsk_path_builder_end_current (GskPathBuilder *builder)
+{
+  GskContour *contour;
+
+  if (builder->ops->len == 0)
+   return;
+
+  contour = gsk_standard_contour_new (builder->flags,
+                                      (GskStandardOperation *) builder->ops->data,
+                                      builder->ops->len,
+                                      (graphene_point_t *) builder->points->data,
+                                      builder->points->len);
+
+  g_array_set_size (builder->ops, 0);
+  g_array_set_size (builder->points, 0);
+
+  /* do this at the end to avoid inflooping when add_contour calls back here */
+  gsk_path_builder_add_contour (builder, contour);
+}
+
+static void
+gsk_path_builder_clear (GskPathBuilder *builder)
+{
+  gsk_path_builder_end_current (builder);
+
+  g_slist_free_full (builder->contours, g_free);
+  builder->contours = NULL;
+}
+
+/**
+ * gsk_path_builder_unref:
+ * @builder: a `GskPathBuilder`
+ *
+ * Releases a reference on the given @builder.
+ */
+void
+gsk_path_builder_unref (GskPathBuilder *builder)
+{
+  g_return_if_fail (builder != NULL);
+  g_return_if_fail (builder->ref_count > 0);
+
+  builder->ref_count -= 1;
+
+  if (builder->ref_count > 0)
+    return;
+
+  gsk_path_builder_clear (builder);
+  g_array_unref (builder->ops);
+  g_array_unref (builder->points);
+  g_slice_free (GskPathBuilder, builder);
+}
+
+/**
+ * gsk_path_builder_free_to_path: (skip)
+ * @builder: a `GskPathBuilder`
+ *
+ * Creates a new `GskPath` from the current state of the
+ * given @builder, and frees the @builder instance.
+ *
+ * Returns: (transfer full): the newly created `GskPath`
+ *   with all the contours added to @builder
+ */
+GskPath *
+gsk_path_builder_free_to_path (GskPathBuilder *builder)
+{
+  GskPath *res;
+
+  g_return_val_if_fail (builder != NULL, NULL);
+
+  res = gsk_path_builder_to_path (builder);
+
+  gsk_path_builder_unref (builder);
+
+  return res;
+}
+
+/**
+ * gsk_path_builder_to_path:
+ * @builder: a `GskPathBuilder`
+ *
+ * Creates a new `GskPath` from the given @builder.
+ *
+ * The given `GskPathBuilder` is reset once this function returns;
+ * you cannot call this function multiple times on the same @builder instance.
+ *
+ * This function is intended primarily for bindings. C code should use
+ * gsk_path_builder_free_to_path().
+ *
+ * Returns: (transfer full): the newly created `GskPath`
+ *   with all the contours added to @builder
+ */
+GskPath *
+gsk_path_builder_to_path (GskPathBuilder *builder)
+{
+  GskPath *path;
+
+  g_return_val_if_fail (builder != NULL, NULL);
+
+  gsk_path_builder_end_current (builder);
+
+  builder->contours = g_slist_reverse (builder->contours);
+
+  path = gsk_path_new_from_contours (builder->contours);
+
+  gsk_path_builder_clear (builder);
+
+  return path;
+}
+
+void
+gsk_path_builder_add_contour (GskPathBuilder *builder,
+                              GskContour     *contour)
+{
+  gsk_path_builder_end_current (builder);
+
+  builder->contours = g_slist_prepend (builder->contours, contour);
+}
+
+/**
+ * gsk_path_builder_add_path:
+ * @builder: a `GskPathBuilder`
+ * @path: (transfer none): the path to append
+ *
+ * Appends all of @path to @builder.
+ **/
+void
+gsk_path_builder_add_path (GskPathBuilder *builder,
+                           GskPath        *path)
+{
+  gsize i;
+
+  g_return_if_fail (builder != NULL);
+  g_return_if_fail (path != NULL);
+
+  for (i = 0; i < gsk_path_get_n_contours (path); i++)
+    {
+      const GskContour *contour = gsk_path_get_contour (path, i);
+
+      gsk_path_builder_add_contour (builder, gsk_contour_dup (contour));
+    }
+}
+
+/**
+ * gsk_path_builder_add_rect:
+ * @builder: A `GskPathBuilder`
+ * @rect: The rectangle to add to @builder
+ *
+ * Adds a path representing the given rectangle.
+ *
+ * If the width or height of the rectangle is negative, the start
+ * point will be on the right or bottom, respectively.
+ *
+ * If the the width or height are 0, the path will be a closed
+ * horizontal or vertical line. If both are 0, it'll be a closed dot.
+ **/
+void
+gsk_path_builder_add_rect (GskPathBuilder        *builder,
+                           const graphene_rect_t *rect)
+{
+  GskContour *contour;
+
+  g_return_if_fail (builder != NULL);
+
+  contour = gsk_rect_contour_new (rect);
+  gsk_path_builder_add_contour (builder, contour);
+}
+
+/**
+ * gsk_path_builder_add_circle:
+ * @builder: a `GskPathBuilder`
+ * @center: the center of the circle
+ * @radius: the radius of the circle
+ *
+ * Adds a circle with the @center and @radius.
+ **/
+void
+gsk_path_builder_add_circle (GskPathBuilder         *builder,
+                             const graphene_point_t *center,
+                             float                   radius)
+{
+  GskContour *contour;
+
+  g_return_if_fail (builder != NULL);
+  g_return_if_fail (center != NULL);
+  g_return_if_fail (radius > 0);
+
+  contour = gsk_circle_contour_new (center, radius, 0, 360);
+  gsk_path_builder_add_contour (builder, contour);
+}
+
+/**
+ * gsk_path_builder_move_to:
+ * @builder: a `GskPathBuilder`
+ * @x: x coordinate
+ * @y: y coordinate
+ *
+ * Starts a new contour by placing the pen at @x, @y.
+ *
+ * If `gsk_path_builder_move_to()` is called twice in succession,
+ * the first call will result in a contour made up of a single point.
+ * The second call will start a new contour.
+ **/
+void
+gsk_path_builder_move_to (GskPathBuilder *builder,
+                          float           x,
+                          float           y)
+{
+  g_return_if_fail (builder != NULL);
+
+  gsk_path_builder_end_current (builder);
+
+  builder->flags = GSK_PATH_FLAT;
+  g_array_append_vals (builder->ops, &(GskStandardOperation) { GSK_PATH_MOVE, 0 }, 1);
+  g_array_append_val (builder->points, GRAPHENE_POINT_INIT(x, y));
+}
+
+/**
+ * gsk_path_builder_line_to:
+ * @builder: a `GskPathBuilder`
+ * @x: x coordinate
+ * @y: y coordinate
+ *
+ * Draws a line from the current point to @x, @y and makes it the new current
+ * point.
+ **/
+void
+gsk_path_builder_line_to (GskPathBuilder *builder,
+                          float           x,
+                          float           y)
+{
+  g_return_if_fail (builder != NULL);
+
+  if (builder->ops->len == 0)
+    {
+      gsk_path_builder_move_to (builder, x, y);
+      return;
+    }
+
+  /* skip the line if it goes to the same point */
+  if (graphene_point_equal (&g_array_index (builder->points, graphene_point_t, builder->points->len - 1),
+                            &GRAPHENE_POINT_INIT (x, y)))
+    return;
+
+  gsk_path_builder_append_current (builder,
+                                   GSK_PATH_LINE,
+                                   1, (graphene_point_t[1]) {
+                                     GRAPHENE_POINT_INIT (x, y)
+                                   });
+}
+
+/**
+ * gsk_path_builder_curve_to:
+ * @builder: a `GskPathBuilder`
+ * @x1: x coordinate of first control point
+ * @y1: y coordinate of first control point
+ * @x2: x coordinate of second control point
+ * @y2: y coordinate of second control point
+ * @x3: x coordinate of the end of the curve
+ * @y3: y coordinate of the end of the curve
+ *
+ * Adds a [cubic Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
+ * from the current point to @x3, @y3 with @x1, @y1 and @x2, @y2 as the control
+ * points.
+ **/
+void
+gsk_path_builder_curve_to (GskPathBuilder *builder,
+                           float           x1,
+                           float           y1,
+                           float           x2,
+                           float           y2,
+                           float           x3,
+                           float           y3)
+{
+  g_return_if_fail (builder != NULL);
+
+  if (builder->ops->len == 0)
+    gsk_path_builder_move_to (builder, x1, y1);
+
+  builder->flags &= ~GSK_PATH_FLAT;
+  gsk_path_builder_append_current (builder,
+                                   GSK_PATH_CURVE,
+                                   3, (graphene_point_t[3]) {
+                                     GRAPHENE_POINT_INIT (x1, y1),
+                                     GRAPHENE_POINT_INIT (x2, y2),
+                                     GRAPHENE_POINT_INIT (x3, y3)
+                                   });
+}
+
+/**
+ * gsk_path_builder_close:
+ * @builder: a `GskPathBuilder`
+ *
+ * Ends the current contour with a line back to the start point.
+ *
+ * Note that this is different from calling [method@Gsk.PathBuilder.line_to]
+ * with the start point in that the contour will be closed. A closed
+ * contour behaves different from an open one when stroking its start
+ * and end point are considered connected, so they will be joined
+ * via the line join, and not ended with line caps.
+ **/
+void
+gsk_path_builder_close (GskPathBuilder *builder)
+{
+  g_return_if_fail (builder != NULL);
+
+  if (builder->ops->len == 0)
+    return;
+
+  builder->flags |= GSK_PATH_CLOSED;
+  gsk_path_builder_append_current (builder,
+                                   GSK_PATH_CLOSE,
+                                   1, (graphene_point_t[1]) {
+                                     g_array_index (builder->points, graphene_point_t, 0)
+                                   });
+
+  gsk_path_builder_end_current (builder);
+}
+
diff --git a/gsk/gskpathbuilder.h b/gsk/gskpathbuilder.h
new file mode 100644
index 0000000000..2bc7a3933d
--- /dev/null
+++ b/gsk/gskpathbuilder.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GSK_PATH_BUILDER_H__
+#define __GSK_PATH_BUILDER_H__
+
+#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gsk/gsk.h> can be included directly."
+#endif
+
+
+#include <gsk/gsktypes.h>
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_PATH_BUILDER (gsk_path_builder_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+GType                   gsk_path_builder_get_type               (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_ALL
+GskPathBuilder *        gsk_path_builder_new                    (void);
+GDK_AVAILABLE_IN_ALL
+GskPathBuilder *        gsk_path_builder_ref                    (GskPathBuilder         *builder);
+GDK_AVAILABLE_IN_ALL
+void                    gsk_path_builder_unref                  (GskPathBuilder         *builder);
+GDK_AVAILABLE_IN_ALL
+GskPath *               gsk_path_builder_free_to_path           (GskPathBuilder         *builder) 
G_GNUC_WARN_UNUSED_RESULT;
+GDK_AVAILABLE_IN_ALL
+GskPath *               gsk_path_builder_to_path                (GskPathBuilder         *builder) 
G_GNUC_WARN_UNUSED_RESULT;
+
+GDK_AVAILABLE_IN_ALL
+void                    gsk_path_builder_add_path               (GskPathBuilder         *builder,
+                                                                 GskPath                *path);
+GDK_AVAILABLE_IN_ALL
+void                    gsk_path_builder_add_rect               (GskPathBuilder         *builder,
+                                                                 const graphene_rect_t  *rect);
+GDK_AVAILABLE_IN_ALL
+void                    gsk_path_builder_add_circle             (GskPathBuilder         *builder,
+                                                                 const graphene_point_t *center,
+                                                                 float                   radius);
+
+GDK_AVAILABLE_IN_ALL
+void                    gsk_path_builder_move_to                (GskPathBuilder         *builder,
+                                                                 float                   x,
+                                                                 float                   y);
+GDK_AVAILABLE_IN_ALL
+void                    gsk_path_builder_line_to                (GskPathBuilder         *builder,
+                                                                 float                   x,
+                                                                 float                   y);
+GDK_AVAILABLE_IN_ALL
+void                    gsk_path_builder_curve_to               (GskPathBuilder         *builder,
+                                                                 float                   x1,
+                                                                 float                   y1,
+                                                                 float                   x2,
+                                                                 float                   y2,
+                                                                 float                   x3,
+                                                                 float                   y3);
+GDK_AVAILABLE_IN_ALL
+void                    gsk_path_builder_close                  (GskPathBuilder         *builder);
+
+G_END_DECLS
+
+#endif /* __GSK_PATH_BUILDER_H__ */
diff --git a/gsk/gskpathmeasure.c b/gsk/gskpathmeasure.c
index a86838a78e..539c4220c3 100644
--- a/gsk/gskpathmeasure.c
+++ b/gsk/gskpathmeasure.c
@@ -410,12 +410,11 @@ gsk_path_measure_add_segment (GskPathMeasure *self,
       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);
+          gsk_contour_add_segment (gsk_path_get_contour (self->path, i),
+                                   builder,
+                                   self->measures[i].contour_data,
+                                   start,
+                                   len);
           end -= len;
           start = 0;
           if (end <= 0)
@@ -424,7 +423,7 @@ gsk_path_measure_add_segment (GskPathMeasure *self,
       else
         {
           end -= self->measures[i].length;
-          gsk_path_builder_add_contour (builder, self->path, i);
+          gsk_path_builder_add_contour (builder, gsk_contour_dup (gsk_path_get_contour (self->path, i)));
         }
     }
 }
diff --git a/gsk/gskpathprivate.h b/gsk/gskpathprivate.h
index ed8db4a49d..d987c90fc1 100644
--- a/gsk/gskpathprivate.h
+++ b/gsk/gskpathprivate.h
@@ -28,12 +28,44 @@ G_BEGIN_DECLS
 /* Same as Skia, so looks like a good value. ¯\_(ツ)_/¯ */
 #define GSK_PATH_TOLERANCE_DEFAULT (0.5)
 
+typedef enum 
+{
+  GSK_PATH_FLAT,
+  GSK_PATH_CLOSED
+} GskPathFlags;
+
+typedef struct _GskContour GskContour;
+typedef struct _GskContourClass GskContourClass;
+
+typedef struct _GskStandardOperation GskStandardOperation;
+
+struct _GskStandardOperation {
+  GskPathOperation op;
+  gsize point; /* index into points array of the start point (last point of previous op) */
+};
+
+GskContour *            gsk_rect_contour_new                    (const graphene_rect_t  *rect);
+GskContour *            gsk_circle_contour_new                  (const graphene_point_t *center,
+                                                                 float                   radius,
+                                                                 float                   start_angle,
+                                                                 float                   end_angle);
+GskContour *            gsk_standard_contour_new                (GskPathFlags            flags,
+                                                                 const                   
GskStandardOperation *ops,
+                                                                 gsize                   n_ops,
+                                                                 const                   graphene_point_t 
*points,
+                                                                 gsize                   n_points);
+
+GskPath *               gsk_path_new_from_contours              (const GSList           *contours);
+
 gsize                   gsk_path_get_n_contours                 (GskPath              *path);
+const GskContour *      gsk_path_get_contour                    (GskPath              *path,
+                                                                 gsize                 i);
 gboolean                gsk_path_foreach_with_tolerance         (GskPath              *self,
                                                                  double                tolerance,
                                                                  GskPathForeachFunc    func,
                                                                  gpointer              user_data);
 
+GskContour *            gsk_contour_dup                         (const GskContour     *src);
 gpointer                gsk_contour_init_measure                (GskPath              *path,
                                                                  gsize                 i,
                                                                  float                 tolerance,
@@ -57,16 +89,14 @@ gboolean                gsk_contour_get_closest_point           (GskPath
                                                                  graphene_point_t       *out_pos,
                                                                  float                  *out_offset,
                                                                  graphene_vec2_t        *out_tangent);
+void                    gsk_contour_add_segment                 (const GskContour       *self,
+                                                                 GskPathBuilder         *builder,
+                                                                 gpointer                measure_data,
+                                                                 float                   start,
+                                                                 float                   end);
 
-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);
+void                    gsk_path_builder_add_contour            (GskPathBuilder         *builder,
+                                                                 GskContour             *contour);
 
 G_END_DECLS
 
diff --git a/gsk/gsktypes.h b/gsk/gsktypes.h
index d31e5d9be4..345847a6ed 100644
--- a/gsk/gsktypes.h
+++ b/gsk/gsktypes.h
@@ -27,6 +27,7 @@
 #include <gsk/gskenums.h>
 
 typedef struct _GskPath                 GskPath;
+typedef struct _GskPathBuilder          GskPathBuilder;
 typedef struct _GskPathMeasure          GskPathMeasure;
 typedef struct _GskRenderer             GskRenderer;
 typedef struct _GskStroke               GskStroke;
diff --git a/gsk/meson.build b/gsk/meson.build
index 72f70b2b9f..de11a64c23 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -26,6 +26,7 @@ gsk_public_sources = files([
   'gskcairorenderer.c',
   'gskglshader.c',
   'gskpath.c',
+  'gskpathbuilder.c',
   'gskpathmeasure.c',
   'gskrenderer.c',
   'gskrendernode.c',
@@ -71,6 +72,7 @@ gsk_public_headers = files([
   'gskenums.h',
   'gskglshader.h',
   'gskpath.h',
+  'gskpathbuilder.h',
   'gskpathmeasure.h',
   'gskrenderer.h',
   'gskrendernode.h',


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