Add gsk_path_get_stroke_bounds

This is a help to compute the bounds for
stroke nodes. We keep it private for now.
This commit is contained in:
Matthias Clasen
2023-07-21 23:35:14 -04:00
parent 5a54b764bd
commit a715e69640
4 changed files with 162 additions and 0 deletions

View File

@@ -26,6 +26,7 @@
#include "gskpathprivate.h"
#include "gskpathpointprivate.h"
#include "gsksplineprivate.h"
#include "gskstrokeprivate.h"
typedef struct _GskContourClass GskContourClass;
@@ -47,6 +48,9 @@ struct _GskContourClass
GString *string);
gboolean (* get_bounds) (const GskContour *contour,
graphene_rect_t *bounds);
gboolean (* get_stroke_bounds) (const GskContour *contour,
const GskStroke *stroke,
graphene_rect_t *bounds);
void (* get_start_end) (const GskContour *self,
graphene_point_t *start,
graphene_point_t *end);
@@ -360,6 +364,55 @@ gsk_standard_contour_get_bounds (const GskContour *contour,
return bounds->size.width > 0 && bounds->size.height > 0;
}
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,
const 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, 1.f) * 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 void
gsk_standard_contour_get_start_end (const GskContour *contour,
graphene_point_t *start,
@@ -855,6 +908,7 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
gsk_standard_contour_get_flags,
gsk_standard_contour_print,
gsk_standard_contour_get_bounds,
gsk_standard_contour_get_stroke_bounds,
gsk_standard_contour_get_start_end,
gsk_standard_contour_foreach,
gsk_standard_contour_reverse,
@@ -977,6 +1031,17 @@ gsk_rect_contour_get_bounds (const GskContour *contour,
return TRUE;
}
static gboolean
gsk_rect_contour_get_stroke_bounds (const GskContour *contour,
const 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 void
gsk_rect_contour_get_start_end (const GskContour *contour,
graphene_point_t *start,
@@ -1396,6 +1461,7 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
gsk_rect_contour_get_flags,
gsk_rect_contour_print,
gsk_rect_contour_get_bounds,
gsk_rect_contour_get_stroke_bounds,
gsk_rect_contour_get_start_end,
gsk_rect_contour_foreach,
gsk_rect_contour_reverse,
@@ -1507,6 +1573,23 @@ gsk_circle_contour_get_bounds (const GskContour *contour,
return TRUE;
}
static gboolean
gsk_circle_contour_get_stroke_bounds (const GskContour *contour,
const 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 void
gsk_circle_contour_get_start_end (const GskContour *contour,
graphene_point_t *start,
@@ -1834,6 +1917,7 @@ static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
gsk_circle_contour_get_flags,
gsk_circle_contour_print,
gsk_circle_contour_get_bounds,
gsk_circle_contour_get_stroke_bounds,
gsk_circle_contour_get_start_end,
gsk_circle_contour_foreach,
gsk_circle_contour_reverse,
@@ -1993,6 +2077,19 @@ gsk_rounded_rect_contour_get_bounds (const GskContour *contour,
return TRUE;
}
static gboolean
gsk_rounded_rect_contour_get_stroke_bounds (const GskContour *contour,
const GskStroke *stroke,
graphene_rect_t *bounds)
{
const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
graphene_rect_init_from_rect (bounds, &self->rect.bounds);
graphene_rect_inset (bounds, - stroke->line_width / 2, - stroke->line_width / 2);
return TRUE;
}
static void
gsk_rounded_rect_contour_get_start_end (const GskContour *contour,
graphene_point_t *start,
@@ -2313,6 +2410,7 @@ static const GskContourClass GSK_ROUNDED_RECT_CONTOUR_CLASS =
gsk_rounded_rect_contour_get_flags,
gsk_rounded_rect_contour_print,
gsk_rounded_rect_contour_get_bounds,
gsk_rounded_rect_contour_get_stroke_bounds,
gsk_rounded_rect_contour_get_start_end,
gsk_rounded_rect_contour_foreach,
gsk_rounded_rect_contour_reverse,
@@ -2395,6 +2493,14 @@ gsk_contour_get_bounds (const GskContour *self,
return self->klass->get_bounds (self, bounds);
}
gboolean
gsk_contour_get_stroke_bounds (const GskContour *self,
const GskStroke *stroke,
graphene_rect_t *bounds)
{
return self->klass->get_stroke_bounds (self, stroke, bounds);
}
gboolean
gsk_contour_foreach (const GskContour *self,
float tolerance,

View File

@@ -58,6 +58,9 @@ void gsk_contour_print (const GskContou
GString *string);
gboolean gsk_contour_get_bounds (const GskContour *self,
graphene_rect_t *bounds);
gboolean gsk_contour_get_stroke_bounds (const GskContour *self,
const GskStroke *stroke,
graphene_rect_t *bounds);
gboolean gsk_contour_foreach (const GskContour *self,
float tolerance,
GskPathForeachFunc func,

View File

@@ -407,6 +407,56 @@ gsk_path_get_bounds (GskPath *self,
return TRUE;
}
/*< private >
* 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,
const 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;
}
/**
* gsk_path_in_fill:
* @self: a `GskPath`

View File

@@ -57,6 +57,9 @@ void gsk_path_builder_svg_arc_to (GskPathBuilder
float x,
float y);
gboolean gsk_path_get_stroke_bounds (GskPath *self,
const GskStroke *stroke,
graphene_rect_t *bounds);
G_END_DECLS