[cairo] [PATCH 2/3] gstate: Set an error status when restoring a push_group

Andrea Canciani ranma42 at gmail.com
Thu Jan 20 02:16:51 PST 2011


cairo_push_group (cr) followed by cairo_restore (cr) should put cr in
an error status of CAIRO_STATUS_INVALID_RESTORE.

Fixes group-state.
---
 src/cairo-gstate-private.h |    3 +++
 src/cairo-gstate.c         |   16 ++++++++++++++++
 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 b41c7a2..34355be 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 efb8267..52d568c 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 b87274a..73dbaee 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;
-- 
1.7.1



More information about the cairo mailing list