mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-06 03:28:09 +02:00
[path] Separate the approx. bounds into 3 distinct functions
Based on feedback from Jeff Muizelaar, there is a case for a very quick and dirty extents approximation based solely on the curve control points (for example when computing the clip intersect rectangle of a path) and by moving the stroke extension into a core function we can clean up the interface for all users, and centralise the logic of approximating the stroke extents.
This commit is contained in:
parent
dea40e61ba
commit
813cbf13dd
6 changed files with 134 additions and 52 deletions
|
|
@ -290,12 +290,12 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
|
|||
surface->current_clip.width = surface->width;
|
||||
surface->current_clip.height = surface->height;
|
||||
} else {
|
||||
cairo_box_t extents;
|
||||
cairo_rectangle_int_t extents;
|
||||
cairo_bool_t is_empty;
|
||||
|
||||
_cairo_path_fixed_approximate_extents (path, tolerance, &extents);
|
||||
is_empty = _cairo_rectangle_intersect_box (&surface->current_clip,
|
||||
&extents);
|
||||
_cairo_path_fixed_approximate_extents (path, &extents);
|
||||
is_empty = _cairo_rectangle_intersect (&surface->current_clip,
|
||||
&extents);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
@ -478,19 +478,13 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
|
|||
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
|
||||
|
||||
if (_cairo_operator_bounded_by_mask (op)) {
|
||||
cairo_box_t mask_extents;
|
||||
double dx, dy;
|
||||
cairo_rectangle_int_t mask_extents;
|
||||
|
||||
_cairo_path_fixed_approximate_extents (path, tolerance, &mask_extents);
|
||||
_cairo_path_fixed_approximate_stroke_extents (path,
|
||||
style, ctm, tolerance,
|
||||
&mask_extents);
|
||||
|
||||
_cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);
|
||||
|
||||
mask_extents.p1.x -= _cairo_fixed_from_double (dx);
|
||||
mask_extents.p2.x += _cairo_fixed_from_double (dx);
|
||||
mask_extents.p1.y -= _cairo_fixed_from_double (dy);
|
||||
mask_extents.p2.y += _cairo_fixed_from_double (dy);
|
||||
|
||||
is_empty = _cairo_rectangle_intersect_box (&extents, &mask_extents);
|
||||
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
|
||||
}
|
||||
if (stroke_extents)
|
||||
*stroke_extents = extents;
|
||||
|
|
@ -542,11 +536,13 @@ _cairo_analysis_surface_fill (void *abstract_surface,
|
|||
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
|
||||
|
||||
if (_cairo_operator_bounded_by_mask (op)) {
|
||||
cairo_box_t mask_extents;
|
||||
cairo_rectangle_int_t mask_extents;
|
||||
|
||||
_cairo_path_fixed_approximate_extents (path, tolerance, &mask_extents);
|
||||
_cairo_path_fixed_approximate_fill_extents (path,
|
||||
tolerance,
|
||||
&mask_extents);
|
||||
|
||||
is_empty = _cairo_rectangle_intersect_box (&extents, &mask_extents);
|
||||
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
|
||||
}
|
||||
if (fill_extents)
|
||||
*fill_extents = extents;
|
||||
|
|
|
|||
|
|
@ -143,13 +143,11 @@ _cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path,
|
|||
cairo_rectangle_int_t *rectangle)
|
||||
{
|
||||
while (clip_path) {
|
||||
cairo_box_t extents;
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
_cairo_path_fixed_approximate_extents (&clip_path->path,
|
||||
clip_path->tolerance,
|
||||
&extents);
|
||||
_cairo_path_fixed_approximate_extents (&clip_path->path, &extents);
|
||||
|
||||
if (! _cairo_rectangle_intersect_box (rectangle, &extents))
|
||||
if (! _cairo_rectangle_intersect (rectangle, &extents))
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
clip_path = clip_path->prev;
|
||||
|
|
@ -577,10 +575,10 @@ _cairo_clip_intersect_mask_using_spans (cairo_clip_t *clip,
|
|||
/* We'll create a new surface the size of the intersection of the
|
||||
* old mask surface and the extents of the new clip path. */
|
||||
{
|
||||
cairo_box_t extents;
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
_cairo_path_fixed_approximate_extents (path, tolerance, &extents);
|
||||
if (! _cairo_rectangle_intersect_box (&surface_rect, &extents))
|
||||
_cairo_path_fixed_approximate_extents (path, &extents);
|
||||
if (! _cairo_rectangle_intersect (&surface_rect, &extents))
|
||||
goto SUCCESS;
|
||||
|
||||
if (clip->surface != NULL &&
|
||||
|
|
|
|||
|
|
@ -140,6 +140,27 @@ _cairo_path_bounder_curve_to (void *closure,
|
|||
return _cairo_spline_decompose (&spline, bounder->tolerance);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_curve_to_cp (void *closure,
|
||||
const cairo_point_t *b,
|
||||
const cairo_point_t *c,
|
||||
const cairo_point_t *d)
|
||||
{
|
||||
cairo_path_bounder_t *bounder = closure;
|
||||
|
||||
if (bounder->has_move_to_point) {
|
||||
_cairo_path_bounder_add_point (bounder,
|
||||
&bounder->move_to_point);
|
||||
bounder->has_move_to_point = FALSE;
|
||||
}
|
||||
|
||||
_cairo_path_bounder_add_point (bounder, b);
|
||||
_cairo_path_bounder_add_point (bounder, c);
|
||||
_cairo_path_bounder_add_point (bounder, d);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_path_bounder_close_path (void *closure)
|
||||
{
|
||||
|
|
@ -152,8 +173,38 @@ _cairo_path_bounder_close_path (void *closure)
|
|||
*/
|
||||
void
|
||||
_cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path,
|
||||
double tolerance,
|
||||
cairo_box_t *extents)
|
||||
cairo_rectangle_int_t *extents)
|
||||
{
|
||||
cairo_path_bounder_t bounder;
|
||||
cairo_status_t status;
|
||||
|
||||
_cairo_path_bounder_init (&bounder, 0.);
|
||||
|
||||
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
|
||||
_cairo_path_bounder_move_to,
|
||||
_cairo_path_bounder_line_to,
|
||||
_cairo_path_bounder_curve_to_cp,
|
||||
_cairo_path_bounder_close_path,
|
||||
&bounder);
|
||||
assert (status == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
if (bounder.has_point) {
|
||||
_cairo_box_round_to_rectangle (&bounder.extents, extents);
|
||||
} else {
|
||||
extents->x = extents->y = 0;
|
||||
extents->width = extents->width = 0;
|
||||
}
|
||||
|
||||
_cairo_path_bounder_fini (&bounder);
|
||||
}
|
||||
|
||||
/* A slightly better approximation than above - we actually decompose the
|
||||
* Bezier, but we continue to ignore winding.
|
||||
*/
|
||||
void
|
||||
_cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
|
||||
double tolerance,
|
||||
cairo_rectangle_int_t *extents)
|
||||
{
|
||||
cairo_path_bounder_t bounder;
|
||||
cairo_status_t status;
|
||||
|
|
@ -169,10 +220,50 @@ _cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path,
|
|||
assert (status == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
if (bounder.has_point) {
|
||||
*extents = bounder.extents;
|
||||
_cairo_box_round_to_rectangle (&bounder.extents, extents);
|
||||
} else {
|
||||
extents->p1.x = extents->p1.y = 0;
|
||||
extents->p2.x = extents->p2.y = 0;
|
||||
extents->x = extents->y = 0;
|
||||
extents->width = extents->width = 0;
|
||||
}
|
||||
|
||||
_cairo_path_bounder_fini (&bounder);
|
||||
}
|
||||
|
||||
/* Adjusts the fill extents (above) by the device-space pen. */
|
||||
void
|
||||
_cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
|
||||
cairo_stroke_style_t *style,
|
||||
const cairo_matrix_t *ctm,
|
||||
double tolerance,
|
||||
cairo_rectangle_int_t *extents)
|
||||
{
|
||||
cairo_path_bounder_t bounder;
|
||||
cairo_status_t status;
|
||||
|
||||
_cairo_path_bounder_init (&bounder, tolerance);
|
||||
|
||||
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
|
||||
_cairo_path_bounder_move_to,
|
||||
_cairo_path_bounder_line_to,
|
||||
_cairo_path_bounder_curve_to,
|
||||
_cairo_path_bounder_close_path,
|
||||
&bounder);
|
||||
assert (status == CAIRO_STATUS_SUCCESS);
|
||||
|
||||
if (bounder.has_point) {
|
||||
double dx, dy;
|
||||
|
||||
_cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);
|
||||
|
||||
bounder.extents.p1.x -= _cairo_fixed_from_double (dx);
|
||||
bounder.extents.p2.x += _cairo_fixed_from_double (dx);
|
||||
bounder.extents.p1.y -= _cairo_fixed_from_double (dy);
|
||||
bounder.extents.p2.y += _cairo_fixed_from_double (dy);
|
||||
|
||||
_cairo_box_round_to_rectangle (&bounder.extents, extents);
|
||||
} else {
|
||||
extents->x = extents->y = 0;
|
||||
extents->width = extents->width = 0;
|
||||
}
|
||||
|
||||
_cairo_path_bounder_fini (&bounder);
|
||||
|
|
|
|||
|
|
@ -126,16 +126,6 @@ _cairo_rectangle_intersect (cairo_rectangle_int_t *dst,
|
|||
}
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_rectangle_intersect_box (cairo_rectangle_int_t *dst,
|
||||
const cairo_box_t *src)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
_cairo_box_round_to_rectangle (src, &rect);
|
||||
return _cairo_rectangle_intersect (dst, &rect);
|
||||
}
|
||||
|
||||
#define P1x (line->p1.x)
|
||||
#define P1y (line->p1.y)
|
||||
#define P2x (line->p2.x)
|
||||
|
|
|
|||
|
|
@ -955,12 +955,12 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
|
|||
info.antialias = antialias;
|
||||
|
||||
if (_cairo_operator_bounded_by_mask (op)) {
|
||||
cairo_box_t path_extents;
|
||||
cairo_rectangle_int_t path_extents;
|
||||
|
||||
_cairo_path_fixed_approximate_extents (path,
|
||||
tolerance,
|
||||
&path_extents);
|
||||
if (! _cairo_rectangle_intersect_box (&extents, &path_extents))
|
||||
_cairo_path_fixed_approximate_fill_extents (path,
|
||||
tolerance,
|
||||
&path_extents);
|
||||
if (! _cairo_rectangle_intersect (&extents, &path_extents))
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -258,10 +258,6 @@ cairo_private cairo_bool_t
|
|||
_cairo_rectangle_intersect (cairo_rectangle_int_t *dst,
|
||||
const cairo_rectangle_int_t *src);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_rectangle_intersect_box (cairo_rectangle_int_t *dst,
|
||||
const cairo_box_t *src);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line);
|
||||
|
||||
|
|
@ -1545,8 +1541,19 @@ _cairo_path_fixed_append (cairo_path_fixed_t *path,
|
|||
|
||||
cairo_private void
|
||||
_cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path,
|
||||
double tolerance,
|
||||
cairo_box_t *extents);
|
||||
cairo_rectangle_int_t *extents);
|
||||
|
||||
cairo_private void
|
||||
_cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
|
||||
double tolerance,
|
||||
cairo_rectangle_int_t *extents);
|
||||
|
||||
cairo_private void
|
||||
_cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
|
||||
cairo_stroke_style_t *style,
|
||||
const cairo_matrix_t *ctm,
|
||||
double tolerance,
|
||||
cairo_rectangle_int_t *extents);
|
||||
|
||||
cairo_private void
|
||||
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue