[gtk/wip/matthiasc/lottie-stroke: 31/60] path: Split GskPathBuilder into its own file




commit a431d53d2935da8da73f9589855972f93e191a9c
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        | 630 +++++++++++----------------------------------------
 gsk/gskpath.h        |  48 ----
 gsk/gskpathbuilder.c | 469 ++++++++++++++++++++++++++++++++++++++
 gsk/gskpathbuilder.h |  80 +++++++
 gsk/gskpathmeasure.c |  13 +-
 gsk/gskpathprivate.h |  48 +++-
 gsk/gsktypes.h       |   1 +
 gsk/meson.build      |   2 +
 9 files changed, 724 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 1f34eb7e20..9dd0b5be4b 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -21,13 +21,14 @@
 
 #include "gskpathprivate.h"
 
+#include "gskpathbuilder.h"
 #include "gsksplineprivate.h"
 
 /**
  * SECTION:gskpath
  * @Title: Path
  * @Short_description: Lines and Curves
- * @See_also: #GskRenderNode
+ * @See_also: #GskRenderNode, #GskPathBuilder
  *
  * This section describes the #GskPath structure that is used to
  * describe lines and curves that are more complex than simple rectangles.
@@ -37,15 +38,6 @@
  * The #GskPathBuilder structure is meant to help in this endeavor.
  */
 
-typedef enum 
-{
-  GSK_PATH_FLAT,
-  GSK_PATH_CLOSED
-} GskPathFlags;
-
-typedef struct _GskContour GskContour;
-typedef struct _GskContourClass GskContourClass;
-
 struct _GskContour
 {
   const GskContourClass *klass;
@@ -123,10 +115,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,
@@ -493,20 +481,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 */
@@ -743,13 +732,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,
@@ -762,12 +744,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 =
@@ -787,14 +767,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);
 
@@ -803,17 +786,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
 {
@@ -1433,12 +1411,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;
 
@@ -1452,6 +1430,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
@@ -1460,24 +1454,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,
@@ -1546,18 +1522,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;
 }
 
 /**
@@ -1652,6 +1688,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,424 +1933,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 7c34b3a165..57bdc5bba2 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..a84da117fb
--- /dev/null
+++ b/gsk/gskpathbuilder.c
@@ -0,0 +1,469 @@
+/*
+ * 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"
+
+/**
+ * SECTION:gskpathbuilder
+ * @Title: Building paths
+ * @Short_description: Building paths of lines and curves
+ * @See_also: #GskPath, #GskPathMeasure
+ *
+ * This section describes how to construct #GskPath structures.
+ *
+ * A path is constructed like this:
+ *
+ * |[<!-- language="C" -->
+ * 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 gsk_path_builder_add_circle()
+ * or by adding from other paths like gsk_path_builder_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 gsk_path_builder_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
+ * gsk_path_builder_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.
+ */
+
+/**
+ * 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)
+
+
+/**
+ * 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 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_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 gsk_path_builder_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 3b808cde2d..38cc793faf 100644
--- a/gsk/gskpathmeasure.c
+++ b/gsk/gskpathmeasure.c
@@ -416,12 +416,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)
@@ -430,7 +429,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 a40b7b6e70..f4edb9b49b 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -24,6 +24,7 @@ gsk_public_sources = files([
   'gskcairorenderer.c',
   'gskglshader.c',
   'gskpath.c',
+  'gskpathbuilder.c',
   'gskpathmeasure.c',
   'gskrenderer.c',
   'gskrendernode.c',
@@ -58,6 +59,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]