API: Add gsk_path_reverse

This is a natural operation, and useful for debugging things.
This commit is contained in:
Matthias Clasen
2022-03-25 16:48:09 -04:00
parent 08d76d9b18
commit c72c51e8f4
4 changed files with 112 additions and 1 deletions

View File

@@ -97,6 +97,7 @@ struct _GskContourClass
float distance,
GskLineJoin line_join,
float miter_limit);
GskContour * (* reverse) (const GskContour *contour);
};
static gsize
@@ -557,6 +558,17 @@ gsk_rect_contour_offset (const GskContour *contour,
gsk_contour_default_offset (contour, builder, distance, line_join, miter_limit);
}
static GskContour *
gsk_rect_contour_reverse (const GskContour *contour)
{
const GskRectContour *self = (const GskRectContour *) contour;
return gsk_rect_contour_new (&GRAPHENE_RECT_INIT (self->x + self->width,
self->y,
- self->width,
self->height));
}
static const GskContourClass GSK_RECT_CONTOUR_CLASS =
{
sizeof (GskRectContour),
@@ -578,6 +590,7 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
gsk_rect_contour_get_stroke_bounds,
gsk_rect_contour_add_stroke,
gsk_rect_contour_offset,
gsk_rect_contour_reverse,
};
GskContour *
@@ -979,6 +992,17 @@ gsk_circle_contour_offset (const GskContour *contour,
gsk_contour_default_offset (contour, builder, distance, line_join, miter_limit);
}
static GskContour *
gsk_circle_contour_reverse (const GskContour *contour)
{
const GskCircleContour *self = (const GskCircleContour *) contour;
return gsk_circle_contour_new (&self->center,
self->radius,
self->end_angle,
self->start_angle);
}
static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
{
sizeof (GskCircleContour),
@@ -1000,6 +1024,7 @@ static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
gsk_circle_contour_get_stroke_bounds,
gsk_circle_contour_add_stroke,
gsk_circle_contour_offset,
gsk_circle_contour_reverse,
};
GskContour *
@@ -1642,7 +1667,7 @@ gsk_standard_contour_add_segment (const GskContour *contour,
gsk_curve_builder_to (&cut, builder);
i = start_measure->op + 1;
}
else
else
i = emit_move_to ? 0 : 1;
for (; i < (end_measure ? end_measure->op : self->n_ops - 1); i++)
@@ -1802,6 +1827,59 @@ gsk_standard_contour_offset (const GskContour *contour,
gsk_contour_default_offset (contour, builder, distance, line_join, miter_limit);
}
static gboolean
add_reverse (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gpointer user_data)
{
GskPathBuilder *builder = user_data;
GskCurve c, r;
if (op == GSK_PATH_MOVE)
return TRUE;
if (op == GSK_PATH_CLOSE)
op = GSK_PATH_LINE;
gsk_curve_init_foreach (&c, op, pts, n_pts, weight);
gsk_curve_reverse (&c, &r);
gsk_curve_builder_to (&r, builder);
return TRUE;
}
static GskContour *
gsk_standard_contour_reverse (const GskContour *contour)
{
const GskStandardContour *self = (const GskStandardContour *) contour;
GskPathBuilder *builder;
GskPath *path;
GskContour *res;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, self->points[self->n_points - 1].x,
self->points[self->n_points - 1].y);
for (int i = self->n_ops - 1; i >= 0; i--)
gsk_pathop_foreach (self->ops[i], add_reverse, builder);
if (self->flags & GSK_PATH_CLOSED)
gsk_path_builder_close (builder);
path = gsk_path_builder_free_to_path (builder);
g_assert (gsk_path_get_n_contours (path) == 1);
res = gsk_contour_dup (gsk_path_get_contour (path, 0));
gsk_path_unref (path);
return res;
}
static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
{
sizeof (GskStandardContour),
@@ -1823,6 +1901,7 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
gsk_standard_contour_get_stroke_bounds,
gsk_standard_contour_add_stroke,
gsk_standard_contour_offset,
gsk_standard_contour_reverse,
};
/* You must ensure the contour has enough size allocated,
@@ -2038,3 +2117,8 @@ gsk_contour_dup (const GskContour *src)
return copy;
}
GskContour *
gsk_contour_reverse (const GskContour *src)
{
return src->klass->reverse (src);
}

View File

@@ -51,6 +51,8 @@ void gsk_contour_copy (GskContour *
const GskContour *src);
GskContour * gsk_contour_dup (const GskContour *src);
GskContour * gsk_contour_reverse (const GskContour *src);
gsize gsk_contour_get_size (const GskContour *self);
GskPathFlags gsk_contour_get_flags (const GskContour *self);
void gsk_contour_print (const GskContour *self,

View File

@@ -1238,6 +1238,28 @@ gsk_path_get_stroke_bounds (GskPath *self,
return TRUE;
}
/**
* gsk_path_reverse:
* @self: a `GskPath`
*
* Creates a path that traverses the same contours as
* @self, in the opposite direction.
*
* Returns: the reverse of @self
*/
GskPath *
gsk_path_reverse (GskPath *self)
{
GskPathBuilder *builder;
builder = gsk_path_builder_new ();
for (int i = self->n_contours - 1; i >= 0; i--)
gsk_path_builder_add_contour (builder, gsk_contour_reverse (gsk_path_get_contour (self, i)));
return gsk_path_builder_free_to_path (builder);
}
/**
* gsk_path_stroke:
* @self: a `GskPath`

View File

@@ -110,6 +110,9 @@ gboolean gsk_path_foreach (GskPath
GskPathForeachFunc func,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
GskPath * gsk_path_reverse (GskPath *self);
GDK_AVAILABLE_IN_ALL
GskPath * gsk_path_stroke (GskPath *self,
GskStroke *stroke);