summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cairo-gstate-private.h3
-rw-r--r--src/cairo-gstate.c16
-rw-r--r--src/cairo.c26
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;