Author: Jeff Muizelaar diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 8278694..12f6242 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -1530,6 +1530,70 @@ _cairo_recording_surface_clone_similar (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +struct acquire_source_image_data +{ + cairo_surface_t *src; + cairo_image_surface_t *image; + void *image_extra; +}; + +static void +_wrap_release_source_image (void *data) +{ + struct acquire_source_image_data *acquire_data = data; + _cairo_surface_release_source_image (acquire_data->src, + acquire_data->image, + acquire_data->image_extra); + free(data); +} + +static cairo_status_t +_wrap_image (cairo_surface_t *src, + cairo_image_surface_t *image, + void *image_extra, + cairo_image_surface_t **out) +{ + static cairo_user_data_key_t wrap_image_key; + cairo_image_surface_t *surface; + cairo_status_t status; + + struct acquire_source_image_data *data = malloc (sizeof (*data)); + if (unlikely (data == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + data->src = src; + data->image = image; + data->image_extra = image_extra; + + surface = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (image->data, + image->pixman_format, + image->width, + image->height, + image->stride); + status = surface->base.status; + if (status) { + free (data); + return status; + } + + status = _cairo_user_data_array_set_data (&surface->base.user_data, + &wrap_image_key, + data, + _wrap_release_source_image); + if (status) { + cairo_surface_destroy (&surface->base); + free (data); + return status; + } + + pixman_image_set_component_alpha ( + surface->pixman_image, + pixman_image_get_component_alpha (surface->pixman_image)); + + *out = surface; + return CAIRO_STATUS_SUCCESS; +} + /** * _cairo_surface_clone_similar: * @surface: a #cairo_surface_t @@ -1606,15 +1670,19 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, /* If we failed, try again with an image surface */ status = _cairo_surface_acquire_source_image (src, &image, &image_extra); if (status == CAIRO_STATUS_SUCCESS) { - status = - surface->backend->clone_similar (surface, &image->base, - src_x, src_y, - width, height, - clone_offset_x, - clone_offset_y, - clone_out); - - _cairo_surface_release_source_image (src, image, image_extra); + status = _wrap_image(src, image, image_extra, &image); + if (status != CAIRO_STATUS_SUCCESS) { + _cairo_surface_release_source_image (src, image, image_extra); + } else { + status = + surface->backend->clone_similar (surface, &image->base, + src_x, src_y, + width, height, + clone_offset_x, + clone_offset_y, + clone_out); + cairo_surface_destroy(&image->base); + } } } }