summaryrefslogtreecommitdiff
path: root/src/cairo-surface-snapshot.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-05-01 14:57:18 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-05-01 16:55:22 +0100
commitf62f8f907d14a7267f136f299208029c7b904eaa (patch)
treec7781f4a2316ff22d13e39529a18e8bfb96fe4b5 /src/cairo-surface-snapshot.c
parentaf3c8abbce529b0928742cc219e5e8e21191eee7 (diff)
downloadcairo-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.c51
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 = {