[gtk/mask-nodes: 5/8] Add gsk_path_get_stroke_bounds
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/mask-nodes: 5/8] Add gsk_path_get_stroke_bounds
- Date: Wed, 16 Dec 2020 05:04:13 +0000 (UTC)
commit be8fa5c77e413d843cc9bc1223c19a6fda5fb58d
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Dec 5 19:23:33 2020 -0500
Add gsk_path_get_stroke_bounds
A relatively cheap way to get bounds for the area
that would be affected by stroking a path.
gsk/gskcontour.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++--
gsk/gskcontourprivate.h | 3 ++
gsk/gskpath.c | 50 +++++++++++++++++++++++++
gsk/gskpath.h | 3 ++
4 files changed, 150 insertions(+), 3 deletions(-)
---
diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c
index fb7dc9456b..d413f96c39 100644
--- a/gsk/gskcontour.c
+++ b/gsk/gskcontour.c
@@ -85,6 +85,9 @@ struct _GskContourClass
void (* add_stroke) (const GskContour *contour,
GskPathBuilder *builder,
GskStroke *stroke);
+ gboolean (* get_stroke_bounds) (const GskContour *contour,
+ GskStroke *stroke,
+ graphene_rect_t *bounds);
};
static gsize
@@ -514,6 +517,17 @@ gsk_rect_contour_add_stroke (const GskContour *contour,
gsk_contour_default_add_stroke (contour, builder, stroke);
}
+static gboolean
+gsk_rect_contour_get_stroke_bounds (const GskContour *contour,
+ GskStroke *stroke,
+ graphene_rect_t *bounds)
+{
+ const GskRectContour *self = (const GskRectContour *) contour;
+ graphene_rect_init (bounds, self->x, self->y, self->width, self->height);
+ graphene_rect_inset (bounds, - stroke->line_width / 2, - stroke->line_width / 2);
+ return TRUE;
+}
+
static const GskContourClass GSK_RECT_CONTOUR_CLASS =
{
sizeof (GskRectContour),
@@ -531,7 +545,8 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
gsk_rect_contour_copy,
gsk_rect_contour_add_segment,
gsk_rect_contour_get_winding,
- gsk_rect_contour_add_stroke
+ gsk_rect_contour_add_stroke,
+ gsk_rect_contour_get_stroke_bounds
};
GskContour *
@@ -890,6 +905,23 @@ gsk_circle_contour_add_stroke (const GskContour *contour,
gsk_contour_default_add_stroke (contour, builder, stroke);
}
+static gboolean
+gsk_circle_contour_get_stroke_bounds (const GskContour *contour,
+ GskStroke *stroke,
+ graphene_rect_t *bounds)
+{
+ const GskCircleContour *self = (const GskCircleContour *) contour;
+
+ graphene_rect_init (bounds,
+ self->center.x - self->radius,
+ self->center.y - self->radius,
+ 2 * self->radius,
+ 2 * self->radius);
+ graphene_rect_inset (bounds, - stroke->line_width / 2, - stroke->line_width / 2);
+
+ return TRUE;
+}
+
static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
{
sizeof (GskCircleContour),
@@ -907,7 +939,8 @@ static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
gsk_circle_contour_copy,
gsk_circle_contour_add_segment,
gsk_circle_contour_get_winding,
- gsk_circle_contour_add_stroke
+ gsk_circle_contour_add_stroke,
+ gsk_circle_contour_get_stroke_bounds
};
GskContour *
@@ -1551,6 +1584,55 @@ gsk_standard_contour_add_stroke (const GskContour *contour,
gsk_contour_default_add_stroke (contour, builder, stroke);
}
+static gboolean
+add_stroke_bounds (GskPathOperation op,
+ const graphene_point_t *pts,
+ gsize n_pts,
+ float weight,
+ gpointer user_data)
+{
+ struct {
+ graphene_rect_t *bounds;
+ float lw;
+ float mw;
+ } *data = user_data;
+ graphene_rect_t bounds;
+
+ for (int i = 1; i < n_pts - 1; i++)
+ {
+ graphene_rect_init (&bounds, pts[i].x - data->lw/2, pts[i].y - data->lw/2, data->lw, data->lw);
+ graphene_rect_union (&bounds, data->bounds, data->bounds);
+ }
+
+ graphene_rect_init (&bounds, pts[n_pts - 1].x - data->mw/2, pts[n_pts - 1].y - data->mw/2, data->mw,
data->mw);
+ graphene_rect_union (&bounds, data->bounds, data->bounds);
+
+ return TRUE;
+}
+
+static gboolean
+gsk_standard_contour_get_stroke_bounds (const GskContour *contour,
+ GskStroke *stroke,
+ graphene_rect_t *bounds)
+{
+ GskStandardContour *self = (GskStandardContour *) contour;
+ struct {
+ graphene_rect_t *bounds;
+ float lw;
+ float mw;
+ } data;
+
+ data.bounds = bounds;
+ data.lw = stroke->line_width;
+ data.mw = MAX (stroke->miter_limit, 0.5) * stroke->line_width;
+
+ graphene_rect_init (bounds, self->points[0].x - data.mw/2, self->points[0].y - data.mw/2, data.mw,
data.mw);
+
+ gsk_standard_contour_foreach (contour, GSK_PATH_TOLERANCE_DEFAULT, add_stroke_bounds, &data);
+
+ return TRUE;
+}
+
static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
{
sizeof (GskStandardContour),
@@ -1568,7 +1650,8 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
gsk_standard_contour_copy,
gsk_standard_contour_add_segment,
gsk_standard_contour_get_winding,
- gsk_standard_contour_add_stroke
+ gsk_standard_contour_add_stroke,
+ gsk_standard_contour_get_stroke_bounds
};
/* You must ensure the contour has enough size allocated,
@@ -1731,6 +1814,14 @@ gsk_contour_get_winding (const GskContour *self,
return self->klass->get_winding (self, measure_data, point, on_edge);
}
+gboolean
+gsk_contour_get_stroke_bounds (const GskContour *self,
+ GskStroke *stroke,
+ graphene_rect_t *bounds)
+{
+ return self->klass->get_stroke_bounds (self, stroke, bounds);
+}
+
void
gsk_contour_add_stroke (const GskContour *self,
GskPathBuilder *builder,
diff --git a/gsk/gskcontourprivate.h b/gsk/gskcontourprivate.h
index a3f9bb48ee..30bd291774 100644
--- a/gsk/gskcontourprivate.h
+++ b/gsk/gskcontourprivate.h
@@ -98,6 +98,9 @@ void gsk_contour_add_stroke (const GskContou
void gsk_contour_default_add_stroke (const GskContour *contour,
GskPathBuilder *builder,
GskStroke *stroke);
+gboolean gsk_contour_get_stroke_bounds (const GskContour *self,
+ GskStroke *stroke,
+ graphene_rect_t *bounds);
G_END_DECLS
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index a9b063bc45..279e60ab0c 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -1211,3 +1211,53 @@ gsk_path_stroke (GskPath *self,
return gsk_path_builder_free_to_path (builder);
}
+
+/**
+ * gsk_path_get_stroke_bounds:
+ * @self: a #GtkPath
+ * @stroke: stroke parameters
+ * @bounds: (out) (caller-allocates): the bounds to fill in
+ *
+ * Computes the bounds for stroking the given path with the
+ * parameters in @stroke.
+ *
+ * The returned bounds may be larger than necessary, because this
+ * function aims to be fast, not accurate. The bounds are guaranteed
+ * to contain the area affected by the stroke, including protrusions
+ * like miters.
+ *
+ * Returns: %TRUE if the path has bounds, %FALSE if the path is known
+ * to be empty and have no bounds.
+ */
+gboolean
+gsk_path_get_stroke_bounds (GskPath *self,
+ GskStroke *stroke,
+ graphene_rect_t *bounds)
+{
+ gsize i;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (bounds != NULL, FALSE);
+
+ for (i = 0; i < self->n_contours; i++)
+ {
+ if (gsk_contour_get_stroke_bounds (self->contours[i], stroke, bounds))
+ break;
+ }
+
+ if (i >= self->n_contours)
+ {
+ graphene_rect_init_from_rect (bounds, graphene_rect_zero ());
+ return FALSE;
+ }
+
+ for (i++; i < self->n_contours; i++)
+ {
+ graphene_rect_t tmp;
+
+ if (gsk_contour_get_stroke_bounds (self->contours[i], stroke, &tmp))
+ graphene_rect_union (bounds, &tmp, bounds);
+ }
+
+ return TRUE;
+}
diff --git a/gsk/gskpath.h b/gsk/gskpath.h
index 48bf7e4476..e32f7184a2 100644
--- a/gsk/gskpath.h
+++ b/gsk/gskpath.h
@@ -110,6 +110,9 @@ GDK_AVAILABLE_IN_ALL
GskPath * gsk_path_stroke (GskPath *path,
GskStroke *stroke);
+gboolean gsk_path_get_stroke_bounds (GskPath *path,
+ GskStroke *stroke,
+ graphene_rect_t *bounds);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]