From 28cb5ee985ae66cdf153e4b522e19bb2b46ac75b Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 6 Apr 2022 22:27:55 -0400 Subject: [PATCH] API: Add gsk_path_transform This is an obvious operation to want for paths. --- gsk/gskpath.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ gsk/gskpath.h | 4 +++ 2 files changed, 98 insertions(+) diff --git a/gsk/gskpath.c b/gsk/gskpath.c index c3ca905edc..0a7faf1d68 100644 --- a/gsk/gskpath.c +++ b/gsk/gskpath.c @@ -24,6 +24,7 @@ #include "gskcurveprivate.h" #include "gskpathbuilder.h" #include "gskstrokeprivate.h" +#include "gsktransform.h" #include "gdk/gdkprivate.h" @@ -1282,6 +1283,99 @@ gsk_path_is_convex (GskPath *self) return gsk_contour_is_convex (gsk_path_get_contour (self, 0)); } +typedef struct +{ + GskTransform *transform; + GskPathBuilder *builder; +} TransformData; + +static gboolean +transform_cb (GskPathOperation op, + const graphene_point_t *pts, + gsize n_pts, + float weight, + gpointer user_data) +{ + TransformData *data = user_data; + graphene_point_t tp[4]; + + switch (op) + { + case GSK_PATH_CLOSE: + gsk_path_builder_close (data->builder); + break; + + case GSK_PATH_MOVE: + gsk_transform_transform_point (data->transform, &pts[0], &tp[0]); + gsk_path_builder_move_to (data->builder, tp[0].x, tp[0].y); + break; + + case GSK_PATH_LINE: + gsk_transform_transform_point (data->transform, &pts[1], &tp[1]); + gsk_path_builder_line_to (data->builder, tp[1].x, tp[1].y); + break; + + case GSK_PATH_QUAD: + gsk_transform_transform_point (data->transform, &pts[1], &tp[1]); + gsk_transform_transform_point (data->transform, &pts[2], &tp[2]); + gsk_path_builder_quad_to (data->builder, + tp[1].x, tp[1].y, + tp[2].x, tp[2].y); + break; + + case GSK_PATH_CUBIC: + gsk_transform_transform_point (data->transform, &pts[1], &tp[1]); + gsk_transform_transform_point (data->transform, &pts[2], &tp[2]); + gsk_transform_transform_point (data->transform, &pts[3], &tp[3]); + gsk_path_builder_cubic_to (data->builder, + tp[1].x, tp[1].y, + tp[2].x, tp[2].y, + tp[3].x, tp[3].y); + break; + + case GSK_PATH_CONIC: + gsk_transform_transform_point (data->transform, &pts[1], &tp[1]); + gsk_transform_transform_point (data->transform, &pts[3], &tp[3]); + gsk_path_builder_conic_to (data->builder, + tp[1].x, tp[1].y, + tp[3].x, tp[3].y, + weight); + break; + + default: + g_assert_not_reached (); + } + + return TRUE; +} + +/** + * gsk_path_transform: + * @self: a `GskPath` + * @transform: the transform to apply + * + * Applies the transform to all points of @self + * and returns the resulting path. + * + * Returns: a new `GskPath` + */ +GskPath * +gsk_path_transform (GskPath *self, + GskTransform *transform) +{ + TransformData data; + + data.transform = transform; + data.builder = gsk_path_builder_new (); + + gsk_path_foreach (self, + GSK_PATH_FOREACH_ALLOW_CUBIC | GSK_PATH_FOREACH_ALLOW_CONIC, + transform_cb, + &data); + + return gsk_path_builder_free_to_path (data.builder); +} + /** * gsk_path_stroke: * @self: a `GskPath` diff --git a/gsk/gskpath.h b/gsk/gskpath.h index 0b899eedfb..0ac760f6af 100644 --- a/gsk/gskpath.h +++ b/gsk/gskpath.h @@ -116,6 +116,10 @@ gboolean gsk_path_foreach (GskPath GDK_AVAILABLE_IN_ALL GskPath * gsk_path_reverse (GskPath *self); +GDK_AVAILABLE_IN_ALL +GskPath * gsk_path_transform (GskPath *self, + GskTransform *transform); + GDK_AVAILABLE_IN_ALL GskPath * gsk_path_stroke (GskPath *self, GskStroke *stroke);