summaryrefslogtreecommitdiff
path: root/src/cairo-quartz-image-surface.c
diff options
context:
space:
mode:
authorJohn Ralls <jralls@ceridwen.us>2020-11-30 15:13:41 -0800
committerJohn Ralls <jralls@ceridwen.us>2020-12-03 10:59:04 -0800
commitb5e84a97833e8e1d082f4409383b09f9827ada09 (patch)
tree0724f46ef256a14e91b3defb92f0fda932810c71 /src/cairo-quartz-image-surface.c
parent32c12c617a2551e1238e52c570bd5c42a6c0cbef (diff)
downloadcairo-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.c49
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);