diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 54792312e..7b1207339 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -204,47 +204,6 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) gstate->source = NULL; } -static void -_cairo_gstate_destroy (cairo_gstate_t *gstate) -{ - _cairo_gstate_fini (gstate); - free (gstate); -} - -/** - * _cairo_gstate_clone: - * @other: a #cairo_gstate_t to be copied, not %NULL. - * - * Create a new #cairo_gstate_t setting all graphics state parameters - * to the same values as contained in @other. gstate->next will be set - * to %NULL and may be used by the caller to chain #cairo_gstate_t - * objects together. - * - * Return value: a new #cairo_gstate_t or %NULL if there is insufficient - * memory. - **/ -static cairo_status_t -_cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out) -{ - cairo_status_t status; - cairo_gstate_t *gstate; - - assert (other != NULL); - - gstate = malloc (sizeof (cairo_gstate_t)); - if (gstate == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - status = _cairo_gstate_init_copy (gstate, other); - if (status) { - free (gstate); - return status; - } - - *out = gstate; - return CAIRO_STATUS_SUCCESS; -} - /** * _cairo_gstate_save: * @gstate: input/output gstate pointer @@ -254,14 +213,25 @@ _cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out) * copy into @gstate. _cairo_gstate_restore() reverses this. **/ cairo_status_t -_cairo_gstate_save (cairo_gstate_t **gstate) +_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist) { - cairo_gstate_t *top = NULL; + cairo_gstate_t *top; cairo_status_t status; - status = _cairo_gstate_clone (*gstate, &top); - if (status) + top = *freelist; + if (top == NULL) { + top = malloc (sizeof (cairo_gstate_t)); + if (top == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + *freelist = top->next; + + status = _cairo_gstate_init_copy (top, *gstate); + if (status) { + top->next = *freelist; + *freelist = top; return status; + } top->next = *gstate; *gstate = top; @@ -276,7 +246,7 @@ _cairo_gstate_save (cairo_gstate_t **gstate) * Reverses the effects of one _cairo_gstate_save() call. **/ cairo_status_t -_cairo_gstate_restore (cairo_gstate_t **gstate) +_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist) { cairo_gstate_t *top; @@ -286,7 +256,9 @@ _cairo_gstate_restore (cairo_gstate_t **gstate) *gstate = top->next; - _cairo_gstate_destroy (top); + _cairo_gstate_fini (top); + top->next = *freelist; + *freelist = top; return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo-private.h b/src/cairo-private.h index a5faec832..43bd2232c 100644 --- a/src/cairo-private.h +++ b/src/cairo-private.h @@ -49,6 +49,7 @@ struct _cairo { cairo_gstate_t *gstate; cairo_gstate_t gstate_tail[1]; + cairo_gstate_t *gstate_freelist; cairo_path_fixed_t path[1]; }; diff --git a/src/cairo.c b/src/cairo.c index e001e70f6..ec2616a80 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -52,7 +52,8 @@ static const cairo_t _cairo_nil = { {{ /* gstate_tail */ 0 }}, - {{ /* path */ + NULL, /* gstate_freelist */ + {{ /* path */ { 0, 0 }, /* last_move_point */ { 0, 0 }, /* current point */ FALSE, /* has_current_point */ @@ -205,6 +206,7 @@ cairo_create (cairo_surface_t *target) _cairo_path_fixed_init (cr->path); cr->gstate = cr->gstate_tail; + cr->gstate_freelist = NULL; status = _cairo_gstate_init (cr->gstate, target); if (status) @@ -260,11 +262,16 @@ cairo_destroy (cairo_t *cr) return; while (cr->gstate != cr->gstate_tail) { - if (_cairo_gstate_restore (&cr->gstate)) + if (_cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist)) break; } _cairo_gstate_fini (cr->gstate); + while (cr->gstate_freelist != NULL) { + cairo_gstate_t *gstate = cr->gstate_freelist; + cr->gstate_freelist = gstate->next; + free (gstate); + } _cairo_path_fixed_fini (cr->path); @@ -371,10 +378,9 @@ cairo_save (cairo_t *cr) if (cr->status) return; - status = _cairo_gstate_save (&cr->gstate); - if (status) { + status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist); + if (status) _cairo_set_error (cr, status); - } } slim_hidden_def(cairo_save); @@ -394,10 +400,9 @@ cairo_restore (cairo_t *cr) if (cr->status) return; - status = _cairo_gstate_restore (&cr->gstate); - if (status) { + status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist); + if (status) _cairo_set_error (cr, status); - } } slim_hidden_def(cairo_restore); diff --git a/src/cairoint.h b/src/cairoint.h old mode 100755 new mode 100644 index b52b0401d..218afc005 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -952,10 +952,10 @@ cairo_private void _cairo_gstate_fini (cairo_gstate_t *gstate); cairo_private cairo_status_t -_cairo_gstate_save (cairo_gstate_t **gstate); +_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist); cairo_private cairo_status_t -_cairo_gstate_restore (cairo_gstate_t **gstate); +_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist); cairo_private cairo_bool_t _cairo_gstate_is_redirected (cairo_gstate_t *gstate);