[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:
Chris Wilson 2008-12-18 14:52:03 +00:00
parent dea40e61ba
commit 813cbf13dd
6 changed files with 134 additions and 52 deletions

View file

@ -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;

View file

@ -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 &&

View file

@ -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);

View file

@ -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)

View file

@ -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;
}

View file

@ -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,