diff options
author | John Ralls <jralls@ceridwen.us> | 2020-11-30 15:13:41 -0800 |
---|---|---|
committer | John Ralls <jralls@ceridwen.us> | 2020-12-03 10:59:04 -0800 |
commit | b5e84a97833e8e1d082f4409383b09f9827ada09 (patch) | |
tree | 0724f46ef256a14e91b3defb92f0fda932810c71 /src/cairo-quartz-image-surface.c | |
parent | 32c12c617a2551e1238e52c570bd5c42a6c0cbef (diff) | |
download | cairo-b5e84a97833e8e1d082f4409383b09f9827ada09.tar.gz |
Quartz: Ensure that image data and surface are available to draw.
Snapshot the cairo_surface_t and copy the image data to provide to
the CGDataProvider so that it is independent of the cairo_surface_t's
lifetime.
Closes https://gitlab.freedesktop.org/cairo/cairo/-/issues/420
Diffstat (limited to 'src/cairo-quartz-image-surface.c')
-rw-r--r-- | src/cairo-quartz-image-surface.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c index 84d56c9b4..7d8c71f1a 100644 --- a/src/cairo-quartz-image-surface.c +++ b/src/cairo-quartz-image-surface.c @@ -49,11 +49,18 @@ #define SURFACE_ERROR_INVALID_SIZE (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE))) #define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT))) +typedef struct { + cairo_surface_t *surface; + void *image_data; +} quartz_image_info_t; + static void DataProviderReleaseCallback (void *info, const void *data, size_t size) { - cairo_surface_t *surface = (cairo_surface_t *) info; - cairo_surface_destroy (surface); + quartz_image_info_t *image_info = (quartz_image_info_t *) info; + cairo_surface_destroy (image_info->surface); + free (image_info->image_data); + free (image_info); } static cairo_surface_t * @@ -147,24 +154,35 @@ _cairo_quartz_image_surface_flush (void *asurface, cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; CGImageRef oldImage = surface->image; CGImageRef newImage = NULL; + quartz_image_info_t *image_info; if (flags) return CAIRO_STATUS_SUCCESS; /* XXX only flush if the image has been modified. */ - /* To be released by the ReleaseCallback */ - cairo_surface_reference ((cairo_surface_t*) surface->imageSurface); + image_info = _cairo_malloc (sizeof (quartz_image_info_t)); + if (unlikely (!image_info)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + image_info->surface = _cairo_surface_snapshot ((cairo_surface_t*)surface->imageSurface); + image_info->image_data = _cairo_malloc_ab (surface->imageSurface->height, + surface->imageSurface->stride); + if (unlikely (!image_info->image_data)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (image_info->image_data, surface->imageSurface->data, + surface->imageSurface->height * surface->imageSurface->stride); newImage = CairoQuartzCreateCGImage (surface->imageSurface->format, surface->imageSurface->width, surface->imageSurface->height, surface->imageSurface->stride, - surface->imageSurface->data, + image_info->image_data, TRUE, NULL, DataProviderReleaseCallback, - surface->imageSurface); + image_info); surface->image = newImage; CGImageRelease (oldImage); @@ -309,6 +327,7 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface) int width, height, stride; cairo_format_t format; unsigned char *data; + quartz_image_info_t *image_info; if (surface->status) return surface; @@ -338,20 +357,24 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface) memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t)); - /* In case the create_cgimage fails, this ref will - * be released via the callback (which will be called in - * case of failure.) - */ - cairo_surface_reference (surface); + image_info = _cairo_malloc (sizeof (quartz_image_info_t)); + if (unlikely (!image_info)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + image_info->surface = _cairo_surface_snapshot (surface); + image_info->image_data = _cairo_malloc_ab (height, stride); + if (unlikely (!image_info->image_data)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + memcpy (image_info->image_data, data, height * stride); image = CairoQuartzCreateCGImage (format, width, height, stride, - data, + image_info->image_data, TRUE, NULL, DataProviderReleaseCallback, - image_surface); + image_info); if (!image) { free (qisurf); |