gstate: Set an error status when restoring a push_group

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

Fixes group-state.
This commit is contained in:
Andrea Canciani 2011-01-20 01:44:29 +01:00
parent e0b741de90
commit 5d95ae924e
3 changed files with 30 additions and 15 deletions

View file

@ -87,6 +87,9 @@ _cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
cairo_private cairo_status_t cairo_private cairo_status_t
_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist); _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_private cairo_bool_t
_cairo_gstate_is_redirected (cairo_gstate_t *gstate); _cairo_gstate_is_redirected (cairo_gstate_t *gstate);

View file

@ -341,6 +341,22 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
&matrix); &matrix);
} }
/**
* _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 * _cairo_gstate_is_redirected
* @gstate: a #cairo_gstate_t * @gstate: a #cairo_gstate_t

View file

@ -585,6 +585,11 @@ cairo_restore (cairo_t *cr)
if (unlikely (cr->status)) if (unlikely (cr->status))
return; 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); status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
if (unlikely (status)) if (unlikely (status))
_cairo_set_error (cr, status); _cairo_set_error (cr, status);
@ -754,7 +759,7 @@ slim_hidden_def(cairo_push_group_with_content);
cairo_pattern_t * cairo_pattern_t *
cairo_pop_group (cairo_t *cr) cairo_pop_group (cairo_t *cr)
{ {
cairo_surface_t *group_surface, *parent_target; cairo_surface_t *group_surface;
cairo_pattern_t *group_pattern; cairo_pattern_t *group_pattern;
cairo_matrix_t group_matrix, device_transform_matrix; cairo_matrix_t group_matrix, device_transform_matrix;
cairo_status_t status; cairo_status_t status;
@ -762,27 +767,18 @@ cairo_pop_group (cairo_t *cr)
if (unlikely (cr->status)) if (unlikely (cr->status))
return _cairo_pattern_create_in_error (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 */ /* 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); _cairo_set_error (cr, CAIRO_STATUS_INVALID_POP_GROUP);
return _cairo_pattern_create_in_error (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 /* Get a reference to the active surface before restoring */
* to reference parent_target and original_target, since the group_surface = _cairo_gstate_get_target (cr->gstate);
* gstate will still hold refs to them once we restore. */
group_surface = cairo_surface_reference (group_surface); group_surface = cairo_surface_reference (group_surface);
cairo_restore (cr); status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
assert (status == CAIRO_STATUS_SUCCESS);
if (unlikely (cr->status)) {
group_pattern = _cairo_pattern_create_in_error (cr->status);
goto done;
}
group_pattern = cairo_pattern_create_for_surface (group_surface); group_pattern = cairo_pattern_create_for_surface (group_surface);
status = group_pattern->status; status = group_pattern->status;