From 813cbf13ddbd3d4b708b3b362dd6c108966f44d5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 18 Dec 2008 14:52:03 +0000 Subject: [PATCH] [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. --- src/cairo-analysis-surface.c | 32 +++++------ src/cairo-clip.c | 14 +++-- src/cairo-path-bounds.c | 101 +++++++++++++++++++++++++++++++++-- src/cairo-rectangle.c | 10 ---- src/cairo-surface-fallback.c | 10 ++-- src/cairoint.h | 19 ++++--- 6 files changed, 134 insertions(+), 52 deletions(-) diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index b8f2ab4d8..b3eab41f4 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -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; diff --git a/src/cairo-clip.c b/src/cairo-clip.c index cd3692424..f0f68a3e6 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -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 && diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 25737e835..ec5bb2185 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -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); diff --git a/src/cairo-rectangle.c b/src/cairo-rectangle.c index 31a530e89..b13962487 100644 --- a/src/cairo-rectangle.c +++ b/src/cairo-rectangle.c @@ -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) diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index 0fd1dee22..9cd59d425 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -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; } diff --git a/src/cairoint.h b/src/cairoint.h index 88945a35b..e98bac09e 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -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,