summaryrefslogtreecommitdiff
path: root/src/cairo-image-source.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-04-27 12:39:40 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-04-27 14:10:50 +0100
commit7eb33099d34234dcccb8f96caba94b38fa385f16 (patch)
tree60dc97ad4280107987751a09ca7a85d5eb724ca2 /src/cairo-image-source.c
parent455b4de1fc6be05f985b43c2f8f83eeed2b2a191 (diff)
downloadcairo-7eb33099d34234dcccb8f96caba94b38fa385f16.tar.gz
snapshot: Perform the cow under a mutex
In order to prevent a race between concurrent destroy and use in another thread, we need to acquire a reference to the snapshot->target under a mutex. Whilst we hold that reference, it prevents the internal destroy mechanism from freeing the memory we are using (if we have a pointer to the original surface) and the client drops their final reference. Oh boy, talk about opening a can of worms... Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/cairo-image-source.c')
-rw-r--r--src/cairo-image-source.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
index ec557c53a..c5bd228c4 100644
--- a/src/cairo-image-source.c
+++ b/src/cairo-image-source.c
@@ -432,6 +432,13 @@ _acquire_source_cleanup (pixman_image_t *pixman_image,
free (data);
}
+static void
+_defer_free_cleanup (pixman_image_t *pixman_image,
+ void *closure)
+{
+ cairo_surface_destroy (closure);
+}
+
static uint16_t
expand_channel (uint16_t v, uint32_t bits)
{
@@ -816,11 +823,14 @@ _pixman_image_for_surface (cairo_image_surface_t *dst,
(! is_mask || ! pattern->base.has_component_alpha ||
(pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
{
+ cairo_surface_t *defer_free = NULL;
cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
cairo_surface_type_t type;
- if (_cairo_surface_is_snapshot (&source->base))
- source = (cairo_image_surface_t *) _cairo_surface_snapshot_get_target (&source->base);
+ if (_cairo_surface_is_snapshot (&source->base)) {
+ defer_free = _cairo_surface_snapshot_get_target (&source->base);
+ source = (cairo_image_surface_t *) defer_free;
+ }
type = source->base.backend->type;
if (type == CAIRO_SURFACE_TYPE_IMAGE) {
@@ -839,15 +849,19 @@ _pixman_image_for_surface (cairo_image_surface_t *dst,
sample->x >= source->width ||
sample->y >= source->height)
{
- if (extend == CAIRO_EXTEND_NONE)
+ if (extend == CAIRO_EXTEND_NONE) {
+ cairo_surface_destroy (defer_free);
return _pixman_transparent_image ();
+ }
}
else
{
pixman_image = _pixel_to_solid (source,
sample->x, sample->y);
- if (pixman_image)
+ if (pixman_image) {
+ cairo_surface_destroy (defer_free);
return pixman_image;
+ }
}
}
@@ -858,6 +872,7 @@ _pixman_image_for_surface (cairo_image_surface_t *dst,
pattern->base.filter,
ix, iy))
{
+ cairo_surface_destroy (defer_free);
return pixman_image_ref (source->pixman_image);
}
#endif
@@ -867,8 +882,16 @@ _pixman_image_for_surface (cairo_image_surface_t *dst,
source->height,
(uint32_t *) source->data,
source->stride);
- if (unlikely (pixman_image == NULL))
+ if (unlikely (pixman_image == NULL)) {
+ cairo_surface_destroy (defer_free);
return NULL;
+ }
+
+ if (defer_free) {
+ pixman_image_set_destroy_function (pixman_image,
+ _defer_free_cleanup,
+ defer_free);
+ }
} else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub;
cairo_bool_t is_contained = FALSE;