diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-05-01 14:57:18 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-05-01 16:55:22 +0100 |
commit | f62f8f907d14a7267f136f299208029c7b904eaa (patch) | |
tree | c7781f4a2316ff22d13e39529a18e8bfb96fe4b5 /src/cairo-surface-snapshot.c | |
parent | af3c8abbce529b0928742cc219e5e8e21191eee7 (diff) | |
download | cairo-f62f8f907d14a7267f136f299208029c7b904eaa.tar.gz |
snapshot: Hold a reference to target whilst querying
Due to race with cow and accessing target from multiple threads, we need
to be careful that we always acquire a reference for our access to
the snapshot target.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/cairo-surface-snapshot.c')
-rw-r--r-- | src/cairo-surface-snapshot.c | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c index 7b8a9a10c..9471e4747 100644 --- a/src/cairo-surface-snapshot.c +++ b/src/cairo-surface-snapshot.c @@ -58,6 +58,8 @@ _cairo_surface_snapshot_finish (void *abstract_surface) cairo_surface_destroy (surface->clone); } + CAIRO_MUTEX_FINI (surface->mutex); + return status; } @@ -65,9 +67,15 @@ static cairo_status_t _cairo_surface_snapshot_flush (void *abstract_surface) { cairo_surface_snapshot_t *surface = abstract_surface; + cairo_surface_t *target; + cairo_status_t status; - cairo_surface_flush (surface->target); - return surface->target->status; + target = _cairo_surface_snapshot_get_target (&surface->base); + cairo_surface_flush (target); + status = target->status; + cairo_surface_destroy (target); + + return status; } static cairo_surface_t * @@ -75,27 +83,48 @@ _cairo_surface_snapshot_source (void *abstract_surface, cairo_rectangle_int_t *extents) { cairo_surface_snapshot_t *surface = abstract_surface; - return _cairo_surface_get_source (surface->target, extents); + return _cairo_surface_get_source (surface->target, extents); /* XXX racy */ } +struct snapshot_extra { + cairo_surface_t *target; + void *extra; +}; + static cairo_status_t _cairo_surface_snapshot_acquire_source_image (void *abstract_surface, cairo_image_surface_t **image_out, void **extra_out) { cairo_surface_snapshot_t *surface = abstract_surface; + struct snapshot_extra *extra; + cairo_status_t status; - return _cairo_surface_acquire_source_image (surface->target, image_out, extra_out); + extra = malloc (sizeof (*extra)); + if (unlikely (extra == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + extra->target = _cairo_surface_snapshot_get_target (&surface->base); + status = _cairo_surface_acquire_source_image (extra->target, image_out, &extra->extra); + if (unlikely (status)) { + cairo_surface_destroy (extra->target); + free (extra); + } + + *extra_out = extra; + return status; } static void _cairo_surface_snapshot_release_source_image (void *abstract_surface, cairo_image_surface_t *image, - void *extra) + void *_extra) { - cairo_surface_snapshot_t *surface = abstract_surface; + struct snapshot_extra *extra = _extra; - _cairo_surface_release_source_image (surface->target, image, extra); + _cairo_surface_release_source_image (extra->target, image, extra->extra); + cairo_surface_destroy (extra->target); + free (extra); } static cairo_bool_t @@ -103,8 +132,14 @@ _cairo_surface_snapshot_get_extents (void *abstract_surface, cairo_rectangle_int_t *extents) { cairo_surface_snapshot_t *surface = abstract_surface; + cairo_surface_t *target; + cairo_bool_t bounded; + + target = _cairo_surface_snapshot_get_target (&surface->base); + bounded = _cairo_surface_get_extents (target, extents); + cairo_surface_destroy (target); - return _cairo_surface_get_extents (surface->target, extents); + return bounded; } static const cairo_surface_backend_t _cairo_surface_snapshot_backend = { |