summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-04-22 20:33:06 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2010-04-23 14:47:59 +0100
commitc63e3490a5fc2836837e7adcb5ecad62bdfd18ab (patch)
tree3e124ffa459d2f6be833f6afe8ca4098141083ac
parent567e485f28716d7b72cbf864a0c573148be91cd8 (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.c81
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);