summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2020-11-12 05:35:14 +0100
committerBenjamin Otte <otte@redhat.com>2020-12-27 00:31:17 +0100
commit483a4773cd0345fd7eae320f9baeef569808141f (patch)
tree1152d5746e597fe3dc77b5e3542e7aa6bd1d6172
parentc82ad0214ef6dda42c5dba9c560b99d1d02d27ee (diff)
downloadgtk+-483a4773cd0345fd7eae320f9baeef569808141f.tar.gz
pathmeasure: Add gsk_path_measure_add_segment()
This allows chunking paths, weeee.
-rw-r--r--docs/reference/gsk/gsk4-sections.txt1
-rw-r--r--gsk/gskpath.c185
-rw-r--r--gsk/gskpathmeasure.c59
-rw-r--r--gsk/gskpathmeasure.h7
-rw-r--r--gsk/gskpathprivate.h6
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