From 83ff8ea194763659be84e7cfa59ad2e1711fb3da Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 28 Oct 2005 20:49:59 +0000 Subject: [PATCH] Bound mask fallback operation by transformed mask and source. This should speed up any applications calling cairo_mask with a bounded source or mask operand. --- ChangeLog | 9 +++++ src/cairo-pattern.c | 85 ++++++++++++++++++++++++++++++++++++++++++++- src/cairo-surface.c | 23 ++++++++---- src/cairoint.h | 4 +++ 4 files changed, 113 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8ee1bfbfc..4f082af59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2005-10-28 Keith Packard + + * src/cairo-pattern.c: (_cairo_pattern_get_extents): + * src/cairo-surface.c: (_fallback_mask): + * src/cairoint.h: + Bound mask fallback operation by transformed mask and + source. This should speed up any applications calling + cairo_mask with a bounded source or mask operand. + 2005-10-28 Keith Packard * src/cairo-gstate.c: (_cairo_operator_bounded_by_mask), diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 4fe8227e5..46dc91d3c 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -22,7 +22,9 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * Author: David Reveman + * Authors: David Reveman + * Keith Packard + * Carl Worth */ #include "cairoint.h" @@ -1624,3 +1626,84 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, return status; } + +/** + * _cairo_pattern_get_extents: + * + * Return the "target-space" extents of @pattern in @extents. + * + * For unbounded patterns, the @extents will be initialized with + * "infinite" extents, (minimum and maximum fixed-point values). + * + * XXX: Currently, bounded gradient patterns will also return + * "infinite" extents, though it would be possible to optimize these + * with a little more work. + **/ +cairo_status_t +_cairo_pattern_get_extents (cairo_pattern_t *pattern, + cairo_rectangle_t *extents) +{ + if (pattern->extend == CAIRO_EXTEND_NONE && + pattern->type == CAIRO_PATTERN_SURFACE) + { + cairo_status_t status; + cairo_rectangle_t surface_extents; + cairo_surface_pattern_t *surface_pattern = + (cairo_surface_pattern_t *) pattern; + cairo_surface_t *surface = surface_pattern->surface; + cairo_matrix_t imatrix; + double x, y; + int left, right, top, bottom; + int lx, rx, ty, by; + int sx, sy; + cairo_bool_t set = FALSE; + + status = _cairo_surface_get_extents (surface, &surface_extents); + if (status) + return status; + + imatrix = pattern->matrix; + cairo_matrix_invert (&imatrix); + + for (sy = 0; sy <= 1; sy++) { + for (sx = 0; sx <= 1; sx++) { + x = surface_extents.x + sx * surface_extents.width; + y = surface_extents.y + sy * surface_extents.height; + cairo_matrix_transform_point (&imatrix, &x, &y); + if (x < 0) x = 0; + if (x > CAIRO_MAXSHORT) x = CAIRO_MAXSHORT; + if (y < 0) y = 0; + if (y > CAIRO_MAXSHORT) y = CAIRO_MAXSHORT; + lx = floor (x); rx = ceil (x); + ty = floor (y); by = ceil (y); + if (!set) { + left = lx; + right = rx; + top = ty; + bottom = by; + set = TRUE; + } else { + if (lx < left) left = lx; + if (rx > right) right = rx; + if (ty < top) top = ty; + if (by > bottom) bottom = by; + } + } + } + extents->x = left; extents->width = right - left; + extents->y = top; extents->height = bottom - top; + return CAIRO_STATUS_SUCCESS; + } + + /* XXX: We could optimize gradients with pattern->extend of NONE + * here in some cases, (eg. radial gradients and 1 axis of + * horizontal/vertical linear gradients). + */ + + extents->x = 0; + extents->y = 0; + extents->width = CAIRO_MAXSHORT; + extents->height = CAIRO_MAXSHORT; + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 2099d5223..dc172c4f2 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -1236,18 +1236,27 @@ _fallback_mask (cairo_operator_t operator, cairo_surface_t *dst) { cairo_status_t status; - cairo_rectangle_t extents; + cairo_rectangle_t extents, source_extents, mask_extents; status = _cairo_surface_get_extents (dst, &extents); if (status) return status; - /* - * XXX should take mask extents into account, but - * that involves checking the transform and - * _cairo_operator_bounded (operator)... For now, - * be lazy and just use the destination extents - */ + if (_cairo_operator_bounded_by_source (operator)) { + status = _cairo_pattern_get_extents (source_pattern, &source_extents); + if (status) + return status; + + _cairo_rectangle_intersect (&extents, &source_extents); + } + + if (_cairo_operator_bounded_by_mask (operator)) { + status = _cairo_pattern_get_extents (mask_pattern, &mask_extents); + if (status) + return status; + + _cairo_rectangle_intersect (&extents, &mask_extents); + } status = _cairo_clip_intersect_to_rectangle (dst->clip, &extents); if (status) diff --git a/src/cairoint.h b/src/cairoint.h index 91e7ce661..6dbef66de 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1972,6 +1972,10 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, cairo_surface_attributes_t *src_attributes, cairo_surface_attributes_t *mask_attributes); +cairo_status_t +_cairo_pattern_get_extents (cairo_pattern_t *pattern, + cairo_rectangle_t *extents); + cairo_private cairo_status_t _cairo_gstate_set_antialias (cairo_gstate_t *gstate, cairo_antialias_t antialias);