diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-04-22 20:33:06 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-04-23 14:47:59 +0100 |
commit | c63e3490a5fc2836837e7adcb5ecad62bdfd18ab (patch) | |
tree | 3e124ffa459d2f6be833f6afe8ca4098141083ac | |
parent | 567e485f28716d7b72cbf864a0c573148be91cd8 (diff) |
cairo: Handle the all-clipped state in cairo_push_group()
Yet another bug reported by Jeff Muizelaar, thanks!
Fixes: test/clip-empty-group
-rw-r--r-- | src/cairo.c | 81 |
1 files changed, 46 insertions, 35 deletions
diff --git a/src/cairo.c b/src/cairo.c index 07194688..32c04375 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -491,46 +491,57 @@ cairo_push_group (cairo_t *cr) void cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) { + cairo_surface_t *group_surface; + cairo_clip_t *clip; cairo_status_t status; - cairo_rectangle_int_t extents; - const cairo_rectangle_int_t *clip_extents; - cairo_surface_t *parent_surface, *group_surface = NULL; - cairo_bool_t is_empty; if (unlikely (cr->status)) return; - parent_surface = _cairo_gstate_get_target (cr->gstate); - - /* Get the extents that we'll use in creating our new group surface */ - is_empty = _cairo_surface_get_extents (parent_surface, &extents); - clip_extents = _cairo_clip_get_extents (_cairo_gstate_get_clip (cr->gstate)); - if (clip_extents != NULL) - is_empty = _cairo_rectangle_intersect (&extents, clip_extents); - - group_surface = _cairo_surface_create_similar_solid (parent_surface, - content, - extents.width, - extents.height, - CAIRO_COLOR_TRANSPARENT, - TRUE); - status = group_surface->status; - if (unlikely (status)) - goto bail; - - /* Set device offsets on the new surface so that logically it appears at - * the same location on the parent surface -- when we pop_group this, - * the source pattern will get fixed up for the appropriate target surface - * device offsets, so we want to set our own surface offsets from /that/, - * and not from the device origin. */ - cairo_surface_set_device_offset (group_surface, - parent_surface->device_transform.x0 - extents.x, - parent_surface->device_transform.y0 - extents.y); - - /* If we have a current path, we need to adjust it to compensate for - * the device offset just applied. */ - _cairo_path_fixed_transform (cr->path, - &group_surface->device_transform); + clip = _cairo_gstate_get_clip (cr->gstate); + if (clip->all_clipped) { + group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); + status = group_surface->status; + if (unlikely (status)) + goto bail; + } else { + cairo_surface_t *parent_surface; + const cairo_rectangle_int_t *clip_extents; + cairo_rectangle_int_t extents; + cairo_bool_t is_empty; + + parent_surface = _cairo_gstate_get_target (cr->gstate); + + /* Get the extents that we'll use in creating our new group surface */ + is_empty = _cairo_surface_get_extents (parent_surface, &extents); + clip_extents = _cairo_clip_get_extents (_cairo_gstate_get_clip (cr->gstate)); + if (clip_extents != NULL) + is_empty = _cairo_rectangle_intersect (&extents, clip_extents); + + group_surface = _cairo_surface_create_similar_solid (parent_surface, + content, + extents.width, + extents.height, + CAIRO_COLOR_TRANSPARENT, + TRUE); + status = group_surface->status; + if (unlikely (status)) + goto bail; + + /* Set device offsets on the new surface so that logically it appears at + * the same location on the parent surface -- when we pop_group this, + * the source pattern will get fixed up for the appropriate target surface + * device offsets, so we want to set our own surface offsets from /that/, + * and not from the device origin. */ + cairo_surface_set_device_offset (group_surface, + parent_surface->device_transform.x0 - extents.x, + parent_surface->device_transform.y0 - extents.y); + + /* If we have a current path, we need to adjust it to compensate for + * the device offset just applied. */ + _cairo_path_fixed_transform (cr->path, + &group_surface->device_transform); + } /* create a new gstate for the redirect */ cairo_save (cr); |