diff options
-rw-r--r-- | src/cairo-gstate-private.h | 3 | ||||
-rw-r--r-- | src/cairo-gstate.c | 16 | ||||
-rw-r--r-- | src/cairo.c | 26 |
3 files changed, 30 insertions, 15 deletions
diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h index b41c7a29..34355beb 100644 --- a/src/cairo-gstate-private.h +++ b/src/cairo-gstate-private.h @@ -88,6 +88,9 @@ cairo_private cairo_status_t _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist); cairo_private cairo_bool_t +_cairo_gstate_is_group (cairo_gstate_t *gstate); + +cairo_private cairo_bool_t _cairo_gstate_is_redirected (cairo_gstate_t *gstate); cairo_private cairo_status_t diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index efb82670..52d568c1 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -342,6 +342,22 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) } /** + * _cairo_gstate_is_group + * @gstate: a #cairo_gstate_t + * + * Check if _cairo_gstate_redirect_target has been called on the head + * of the stack. + * + * Return value: %TRUE if @gstate is redirected to a target different + * than the previous state in the stack, %FALSE otherwise. + **/ +cairo_bool_t +_cairo_gstate_is_group (cairo_gstate_t *gstate) +{ + return gstate->parent_target != NULL; +} + +/** * _cairo_gstate_is_redirected * @gstate: a #cairo_gstate_t * diff --git a/src/cairo.c b/src/cairo.c index b87274a2..73dbaeef 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -585,6 +585,11 @@ cairo_restore (cairo_t *cr) if (unlikely (cr->status)) return; + if (unlikely (_cairo_gstate_is_group (cr->gstate))) { + _cairo_set_error (cr, _cairo_error (CAIRO_STATUS_INVALID_RESTORE)); + return; + } + status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist); if (unlikely (status)) _cairo_set_error (cr, status); @@ -754,7 +759,7 @@ slim_hidden_def(cairo_push_group_with_content); cairo_pattern_t * cairo_pop_group (cairo_t *cr) { - cairo_surface_t *group_surface, *parent_target; + cairo_surface_t *group_surface; cairo_pattern_t *group_pattern; cairo_matrix_t group_matrix, device_transform_matrix; cairo_status_t status; @@ -762,27 +767,18 @@ cairo_pop_group (cairo_t *cr) if (unlikely (cr->status)) return _cairo_pattern_create_in_error (cr->status); - /* Grab the active surfaces */ - group_surface = _cairo_gstate_get_target (cr->gstate); - parent_target = _cairo_gstate_get_parent_target (cr->gstate); - /* Verify that we are at the right nesting level */ - if (parent_target == NULL) { + if (unlikely (! _cairo_gstate_is_group (cr->gstate))) { _cairo_set_error (cr, CAIRO_STATUS_INVALID_POP_GROUP); return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_POP_GROUP); } - /* We need to save group_surface before we restore; we don't need - * to reference parent_target and original_target, since the - * gstate will still hold refs to them once we restore. */ + /* Get a reference to the active surface before restoring */ + group_surface = _cairo_gstate_get_target (cr->gstate); group_surface = cairo_surface_reference (group_surface); - cairo_restore (cr); - - if (unlikely (cr->status)) { - group_pattern = _cairo_pattern_create_in_error (cr->status); - goto done; - } + status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist); + assert (status == CAIRO_STATUS_SUCCESS); group_pattern = cairo_pattern_create_for_surface (group_surface); status = group_pattern->status; |