diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c index 72bd21cb9d..51b53f589d 100644 --- a/gsk/gskcontour.c +++ b/gsk/gskcontour.c @@ -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); +} diff --git a/gsk/gskcontourprivate.h b/gsk/gskcontourprivate.h index 6f8c950c61..6201cb03d4 100644 --- a/gsk/gskcontourprivate.h +++ b/gsk/gskcontourprivate.h @@ -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, diff --git a/gsk/gskpath.c b/gsk/gskpath.c index 9d577401bb..40a11ecba3 100644 --- a/gsk/gskpath.c +++ b/gsk/gskpath.c @@ -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` diff --git a/gsk/gskpath.h b/gsk/gskpath.h index 89335d3a8d..60e388bf66 100644 --- a/gsk/gskpath.h +++ b/gsk/gskpath.h @@ -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);