diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index d5b63e8ed..431f98ebf 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -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); } diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 83ba28c1f..ce2a24092 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -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; diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 33880d840..3acbc1009 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -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 diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 70867e31c..54df5bff4 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -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; } diff --git a/src/cairo-surface.c b/src/cairo-surface.c index eaff47a29..4c10f9589 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -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 diff --git a/src/cairo.c b/src/cairo.c index c80589d28..d1892fd22 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -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); } /** diff --git a/src/cairoint.h b/src/cairoint.h index d219061de..32cc7591f 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -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,