[path] Compute approximate extents.

When computing the bounds of the clip path, we care more for a fast result
than absolute precision as the extents are only used as a guide to trim
the future operations. So computing the extents of the path suffices.
This commit is contained in:
Chris Wilson 2008-11-25 10:04:50 +00:00
parent b6bf047494
commit 59de6fb89e
7 changed files with 82 additions and 61 deletions

View file

@ -283,9 +283,6 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
cairo_antialias_t antialias)
{
cairo_analysis_surface_t *surface = abstract_surface;
double x1, y1, x2, y2;
cairo_rectangle_int_t extent;
cairo_bool_t is_empty;
if (path == NULL) {
surface->current_clip.x = 0;
@ -293,17 +290,10 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
surface->current_clip.width = surface->width;
surface->current_clip.height = surface->height;
} else {
cairo_status_t status;
status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2, tolerance);
if (status)
return status;
extent.x = floor (x1);
extent.y = floor (y1);
extent.width = ceil (x2) - extent.x;
extent.height = ceil (y2) - extent.y;
cairo_rectangle_int_t extent;
cairo_bool_t is_empty;
_cairo_path_fixed_approximate_extents (path, &extent);
is_empty = _cairo_rectangle_intersect (&surface->current_clip, &extent);
}

View file

@ -143,30 +143,11 @@ _cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path,
cairo_rectangle_int_t *rectangle)
{
while (clip_path) {
cairo_status_t status;
cairo_traps_t traps;
cairo_box_t extents;
cairo_rectangle_int_t extents_rect;
cairo_rectangle_int_t extents;
_cairo_box_from_rectangle (&extents, rectangle);
_cairo_path_fixed_approximate_extents (&clip_path->path, &extents);
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, &extents);
status = _cairo_path_fixed_fill_to_traps (&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
&traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
_cairo_traps_extents (&traps, &extents);
_cairo_traps_fini (&traps);
_cairo_box_round_to_rectangle (&extents, &extents_rect);
if (! _cairo_rectangle_intersect (rectangle, &extents_rect))
if (! _cairo_rectangle_intersect (rectangle, &extents))
return CAIRO_STATUS_SUCCESS;
clip_path = clip_path->prev;

View file

@ -783,20 +783,17 @@ _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
}
*/
cairo_status_t
void
_cairo_gstate_path_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
cairo_status_t status;
double px1, py1, px2, py2;
status = _cairo_path_fixed_bounds (path,
&px1, &py1, &px2, &py2,
gstate->tolerance);
if (status)
return status;
_cairo_path_fixed_bounds (path,
&px1, &py1, &px2, &py2,
gstate->tolerance);
_cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
@ -809,8 +806,6 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate,
*x2 = px2;
if (y2)
*y2 = py2;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t

View file

@ -131,14 +131,68 @@ _cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_curve_to (void *closure,
cairo_point_t *b,
cairo_point_t *c,
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)
{
return CAIRO_STATUS_SUCCESS;
}
/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
cairo_status_t
/* This computes the extents of all the points in the path, not those of
* the damage area (i.e it does not consider winding and it only inspects
* the control points of the curves, not the flattened path).
*/
void
_cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
_cairo_path_bounder_init (&bounder);
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) {
extents->x = bounder.min_x;
extents->y = bounder.min_y;
extents->width = bounder.max_x - extents->x;
extents->height = bounder.max_y - extents->y;
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
_cairo_path_bounder_fini (&bounder);
}
void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2,
@ -155,8 +209,9 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path,
_cairo_path_bounder_close_path,
&bounder,
tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
if (status == CAIRO_STATUS_SUCCESS && bounder.has_point) {
if (bounder.has_point) {
*x1 = _cairo_fixed_to_double (bounder.min_x);
*y1 = _cairo_fixed_to_double (bounder.min_y);
*x2 = _cairo_fixed_to_double (bounder.max_x);
@ -169,6 +224,4 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path,
}
_cairo_path_bounder_fini (&bounder);
return status;
}

View file

@ -2132,11 +2132,13 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface,
assert (surface->backend->set_clip_region != NULL);
status = surface->backend->set_clip_region (surface, region);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
surface->current_clip_serial = serial;
status = surface->backend->set_clip_region (surface, region);
return _cairo_surface_set_error (surface, status);
return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t

View file

@ -1907,8 +1907,6 @@ void
cairo_path_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
cairo_status_t status;
if (cr->status) {
if (x1)
*x1 = 0.0;
@ -1922,11 +1920,9 @@ cairo_path_extents (cairo_t *cr,
return;
}
status = _cairo_gstate_path_extents (cr->gstate,
cr->path,
x1, y1, x2, y2);
if (status)
_cairo_set_error (cr, status);
_cairo_gstate_path_extents (cr->gstate,
cr->path,
x1, y1, x2, y2);
}
/**

View file

@ -1139,7 +1139,7 @@ _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
double *x2, double *y2,
cairo_bool_t *is_tight);
cairo_private cairo_status_t
cairo_private void
_cairo_gstate_path_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
@ -1511,7 +1511,11 @@ _cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir);
cairo_private cairo_status_t
cairo_private void
_cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents);
cairo_private void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2,