diff options
author | Benjamin Otte <otte@redhat.com> | 2020-11-12 05:35:14 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2020-12-27 00:31:17 +0100 |
commit | 483a4773cd0345fd7eae320f9baeef569808141f (patch) | |
tree | 1152d5746e597fe3dc77b5e3542e7aa6bd1d6172 | |
parent | c82ad0214ef6dda42c5dba9c560b99d1d02d27ee (diff) | |
download | gtk+-483a4773cd0345fd7eae320f9baeef569808141f.tar.gz |
pathmeasure: Add gsk_path_measure_add_segment()
This allows chunking paths, weeee.
-rw-r--r-- | docs/reference/gsk/gsk4-sections.txt | 1 | ||||
-rw-r--r-- | gsk/gskpath.c | 185 | ||||
-rw-r--r-- | gsk/gskpathmeasure.c | 59 | ||||
-rw-r--r-- | gsk/gskpathmeasure.h | 7 | ||||
-rw-r--r-- | gsk/gskpathprivate.h | 6 |
5 files changed, 255 insertions, 3 deletions
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index 8f101ee401..183844b725 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -363,6 +363,7 @@ gsk_path_measure_ref gsk_path_measure_unref <SUBSECTION> gsk_path_measure_get_length +gsk_path_measure_add_segment <SUBSECTION Private> GSK_TYPE_PATH_MEASURE gsk_path_measure_get_type diff --git a/gsk/gskpath.c b/gsk/gskpath.c index a1c2d20ebf..0475f97925 100644 --- a/gsk/gskpath.c +++ b/gsk/gskpath.c @@ -61,6 +61,11 @@ struct _GskContourClass gpointer measure_data); void (* copy) (const GskContour *contour, GskContour *dest); + void (* add_segment) (const GskContour *contour, + GskPathBuilder *builder, + gpointer measure_data, + float start, + float end); }; struct _GskPath @@ -188,6 +193,71 @@ gsk_rect_contour_copy (const GskContour *contour, *target = *self; } +static void +gsk_rect_contour_add_segment (const GskContour *contour, + GskPathBuilder *builder, + gpointer measure_data, + float start, + float end) +{ + const GskRectContour *self = (const GskRectContour *) contour; + float w = ABS (self->width); + float h = ABS (self->height); + + if (start < w) + { + gsk_path_builder_move_to (builder, self->x + start * (w / self->width), self->y); + if (end <= w) + { + gsk_path_builder_line_to (builder, self->x + end * (w / self->width), self->y); + return; + } + gsk_path_builder_line_to (builder, self->x + self->width, self->y); + } + start -= w; + end -= w; + + if (start < h) + { + if (start >= 0) + gsk_path_builder_move_to (builder, self->x + self->width, self->y + start * (h / self->height)); + if (end <= h) + { + gsk_path_builder_line_to (builder, self->x + self->width, self->y + end * (h / self->height)); + return; + } + gsk_path_builder_line_to (builder, self->x + self->width, self->y + self->height); + } + start -= h; + end -= h; + + if (start < w) + { + if (start >= 0) + gsk_path_builder_move_to (builder, self->x + (w - start) * (w / self->width), self->y + self->height); + if (end <= w) + { + gsk_path_builder_line_to (builder, self->x + (w - end) * (w / self->width), self->y + self->height); + return; + } + gsk_path_builder_line_to (builder, self->x, self->y + self->height); + } + start -= w; + end -= w; + + if (start < h) + { + if (start >= 0) + gsk_path_builder_move_to (builder, self->x, self->y + (h - start) * (h / self->height)); + if (end <= h) + { + gsk_path_builder_line_to (builder, self->x, self->y + (h - end) * (h / self->height)); + return; + } + gsk_path_builder_line_to (builder, self->x, self->y); + } +} + static const GskContourClass GSK_RECT_CONTOUR_CLASS = { sizeof (GskRectContour), @@ -198,7 +268,8 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS = gsk_rect_contour_get_bounds, gsk_rect_contour_init_measure, gsk_rect_contour_free_measure, - gsk_rect_contour_copy + gsk_rect_contour_copy, + gsk_rect_contour_add_segment }; static void @@ -452,6 +523,102 @@ gsk_standard_contour_copy (const GskContour *contour, gsk_standard_contour_init (dest, self->ops, self->n_ops, self->points, self->n_points); } +static void +gsk_standard_contour_add_segment (const GskContour *contour, + GskPathBuilder *builder, + gpointer measure_data, + float start, + float end) +{ + GskStandardContour *self = (GskStandardContour *) contour; + gsize i; + float length; + + for (i = 0; end > 0 && i < self->n_ops; i ++) + { + graphene_point_t *pt = &self->points[self->ops[i].point]; + + switch (self->ops[i].op) + { + case GSK_PATH_MOVE: + if (start <= 0.0) + { + gsk_path_builder_move_to (builder, pt[0].x, pt[0].y); + start = -1; + } + break; + + case GSK_PATH_CLOSE: + case GSK_PATH_LINE: + length = graphene_point_distance (&pt[0], &pt[1], NULL, NULL); + if (length <= start) + { + start -= length; + end -= length; + } + else + { + if (start >= 0) + { + graphene_point_t start_pt; + graphene_point_interpolate (&pt[0], &pt[1], start / length, &start_pt); + gsk_path_builder_move_to (builder, start_pt.x, start_pt.y); + start = -1; + } + if (length <= end) + { + gsk_path_builder_line_to (builder, pt[1].x, pt[1].y); + end -= length; + } + else + { + graphene_point_t end_pt; + graphene_point_interpolate (&pt[0], &pt[1], end / length, &end_pt); + gsk_path_builder_line_to (builder, end_pt.x, end_pt.y); + return; + } + } + break; + + case GSK_PATH_CURVE: + g_warning ("i'm not fat!"); + length = graphene_point_distance (&pt[0], &pt[3], NULL, NULL); + if (length <= start) + { + start -= length; + end -= length; + } + else + { + if (start >= 0) + { + graphene_point_t start_pt; + graphene_point_interpolate (&pt[0], &pt[3], start / length, &start_pt); + gsk_path_builder_move_to (builder, start_pt.x, start_pt.y); + start = -1; + } + if (length <= end) + { + gsk_path_builder_line_to (builder, pt[3].x, pt[3].y); + end -= length; + } + else + { + graphene_point_t end_pt; + graphene_point_interpolate (&pt[0], &pt[3], end / length, &end_pt); + gsk_path_builder_line_to (builder, end_pt.x, end_pt.y); + return; + } + } + break; + + default: + g_assert_not_reached(); + return; + } + } +} + static const GskContourClass GSK_STANDARD_CONTOUR_CLASS = { sizeof (GskStandardContour), @@ -462,7 +629,8 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS = gsk_standard_contour_get_bounds, gsk_standard_contour_init_measure, gsk_standard_contour_free_measure, - gsk_standard_contour_copy + gsk_standard_contour_copy, + gsk_standard_contour_add_segment }; /* You must ensure the contour has enough size allocated, @@ -845,6 +1013,19 @@ gsk_path_builder_add_contour (GskPathBuilder *builder, 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: * diff --git a/gsk/gskpathmeasure.c b/gsk/gskpathmeasure.c index 60b8727564..7fd0eeb65d 100644 --- a/gsk/gskpathmeasure.c +++ b/gsk/gskpathmeasure.c @@ -161,3 +161,62 @@ gsk_path_measure_get_length (GskPathMeasure *self) return self->length; } +/** + * gsk_path_measure_add_segment: + * @self: a #GskPathMeasure + * @builder: the builder to add the segment to + * @start: start distance into the path + * @end: end distance into the path + * + * Adds to @builder the segment of @path inbetween @start and @end. + * + * The distances are given relative to the length of @self's path, + * from 0 for the begginning of the path to + * gsk_path_measure_get_length() for the end of the path. The values + * will be clamped to that range. + * + * If @start >= @end after clamping, no path will be added. + **/ +void +gsk_path_measure_add_segment (GskPathMeasure *self, + GskPathBuilder *builder, + float start, + float end) +{ + gsize i; + + g_return_if_fail (self != NULL); + g_return_if_fail (builder != NULL); + + start = CLAMP (start, 0, self->length); + end = CLAMP (end, 0, self->length); + if (start >= end) + return; + + for (i = 0; i < self->n_contours; i++) + { + if (self->measures[i].length < start) + { + start -= self->measures[i].length; + end -= self->measures[i].length; + } + 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); + start = 0; + end -= len; + } + else + { + end -= self->measures[i].length; + gsk_path_builder_add_contour (builder, self->path, i); + } + } +} + diff --git a/gsk/gskpathmeasure.h b/gsk/gskpathmeasure.h index 2941176e60..abf4202eb6 100644 --- a/gsk/gskpathmeasure.h +++ b/gsk/gskpathmeasure.h @@ -25,7 +25,7 @@ #endif -#include <gsk/gsktypes.h> +#include <gsk/gskpath.h> G_BEGIN_DECLS @@ -44,6 +44,11 @@ void gsk_path_measure_unref (GskPathMeasure GDK_AVAILABLE_IN_ALL float gsk_path_measure_get_length (GskPathMeasure *self); +GDK_AVAILABLE_IN_ALL +void gsk_path_measure_add_segment (GskPathMeasure *self, + GskPathBuilder *builder, + float start, + float end); G_END_DECLS #endif /* __GSK_PATH_MEASURE_H__ */ diff --git a/gsk/gskpathprivate.h b/gsk/gskpathprivate.h index aae06f1dd3..7238c44418 100644 --- a/gsk/gskpathprivate.h +++ b/gsk/gskpathprivate.h @@ -37,6 +37,12 @@ void gsk_contour_free_measure (GskPath 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); G_END_DECLS |