Add gsk_path_get_stroke_bounds
A relatively cheap way to get bounds for the area that would be affected by stroking a path.
This commit is contained in:
committed by
Benjamin Otte
parent
ee6879fba8
commit
776dc54c8a
@@ -330,6 +330,7 @@ gsk_path_to_cairo
|
||||
<SUBSECTION>
|
||||
gsk_path_is_empty
|
||||
gsk_path_get_bounds
|
||||
gsk_path_get_stroke_bounds
|
||||
<SUBSECTION>
|
||||
GskPathOperation
|
||||
GskPathForeachFlags
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "gskpathbuilder.h"
|
||||
#include "gskpathprivate.h"
|
||||
#include "gsksplineprivate.h"
|
||||
#include "gskstrokeprivate.h"
|
||||
|
||||
typedef struct _GskContourClass GskContourClass;
|
||||
|
||||
@@ -81,6 +82,9 @@ struct _GskContourClass
|
||||
gpointer measure_data,
|
||||
const graphene_point_t *point,
|
||||
gboolean *on_edge);
|
||||
gboolean (* get_stroke_bounds) (const GskContour *contour,
|
||||
const GskStroke *stroke,
|
||||
graphene_rect_t *bounds);
|
||||
};
|
||||
|
||||
static gsize
|
||||
@@ -469,6 +473,17 @@ gsk_rect_contour_get_winding (const GskContour *contour,
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 const GskContourClass GSK_RECT_CONTOUR_CLASS =
|
||||
{
|
||||
sizeof (GskRectContour),
|
||||
@@ -485,7 +500,8 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
|
||||
gsk_rect_contour_get_closest_point,
|
||||
gsk_rect_contour_copy,
|
||||
gsk_rect_contour_add_segment,
|
||||
gsk_rect_contour_get_winding
|
||||
gsk_rect_contour_get_winding,
|
||||
gsk_rect_contour_get_stroke_bounds
|
||||
};
|
||||
|
||||
GskContour *
|
||||
@@ -818,6 +834,23 @@ gsk_circle_contour_get_winding (const GskContour *contour,
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
|
||||
{
|
||||
sizeof (GskCircleContour),
|
||||
@@ -834,7 +867,8 @@ static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
|
||||
gsk_circle_contour_get_closest_point,
|
||||
gsk_circle_contour_copy,
|
||||
gsk_circle_contour_add_segment,
|
||||
gsk_circle_contour_get_winding
|
||||
gsk_circle_contour_get_winding,
|
||||
gsk_circle_contour_get_stroke_bounds
|
||||
};
|
||||
|
||||
GskContour *
|
||||
@@ -1470,6 +1504,55 @@ gsk_standard_contour_get_winding (const GskContour *contour,
|
||||
return winding;
|
||||
}
|
||||
|
||||
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 const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
|
||||
{
|
||||
sizeof (GskStandardContour),
|
||||
@@ -1486,7 +1569,8 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
|
||||
gsk_standard_contour_get_closest_point,
|
||||
gsk_standard_contour_copy,
|
||||
gsk_standard_contour_add_segment,
|
||||
gsk_standard_contour_get_winding
|
||||
gsk_standard_contour_get_winding,
|
||||
gsk_standard_contour_get_stroke_bounds
|
||||
};
|
||||
|
||||
/* You must ensure the contour has enough size allocated,
|
||||
@@ -1649,6 +1733,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,
|
||||
const GskStroke *stroke,
|
||||
graphene_rect_t *bounds)
|
||||
{
|
||||
return self->klass->get_stroke_bounds (self, stroke, bounds);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_contour_copy (GskContour *dest,
|
||||
const GskContour *src)
|
||||
|
||||
@@ -92,6 +92,9 @@ void gsk_contour_add_segment (const GskContou
|
||||
gpointer measure_data,
|
||||
float start,
|
||||
float end);
|
||||
gboolean gsk_contour_get_stroke_bounds (const GskContour *self,
|
||||
const GskStroke *stroke,
|
||||
graphene_rect_t *bounds);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -1168,3 +1168,53 @@ error:
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -99,6 +99,10 @@ gboolean gsk_path_is_empty (GskPath
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_get_bounds (GskPath *path,
|
||||
graphene_rect_t *bounds);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_get_stroke_bounds (GskPath *path,
|
||||
const GskStroke *stroke,
|
||||
graphene_rect_t *bounds);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gsk_path_foreach (GskPath *path,
|
||||
|
||||
Reference in New Issue
Block a user