Cherry-pick https://gitlab.freedesktop.org/cairo/cairo/-/commit/1ddfccca31e23820a30e8f618e216fe2931b49b2 draft
authorJonathan Kew <jkew@mozilla.com>
Mon, 19 Apr 2021 12:52:34 +0100
changeset 3667287 2b8f9cafa3b59879e16ed74b415f855299c7ead0
parent 3667286 33f164a8c31c77b1490cb62dde144206e6e5711d
child 3667288 6f37a133d6ab64092dafb86c30532143de36c98f
push id683063
push userjkew@mozilla.com
push dateMon, 19 Apr 2021 13:15:26 +0000
treeherdertry@919daaf50d14 [default view] [failures only]
milestone89.0a1
Cherry-pick https://gitlab.freedesktop.org/cairo/cairo/-/commit/1ddfccca31e23820a30e8f618e216fe2931b49b2 Quartz image drawing: Remove containers for cairo_surface_t. Since we now copy the data that CGImage needs we don't need to keep the surface around anymore, nor release it or the image in the DataProviderReleaseCallback.
gfx/cairo/cairo/src/cairo-quartz-image-surface.c
gfx/cairo/cairo/src/cairo-quartz-surface.c
--- a/gfx/cairo/cairo/src/cairo-quartz-image-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-image-surface.c
@@ -44,27 +44,19 @@
 #include "cairo-error-private.h"
 #include "cairo-default-context-private.h"
 
 #define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)))
 #define SURFACE_ERROR_TYPE_MISMATCH (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_SURFACE_TYPE_MISMATCH)))
 #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)
+DataProviderReleaseCallback (void *image_info, const void *data, size_t size)
 {
-    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 *
 _cairo_quartz_image_surface_create_similar (void *asurface,
 					    cairo_content_t content,
 					    int width,
 					    int height)
@@ -90,19 +82,18 @@ static cairo_surface_t *
     return result;
 }
 
 static cairo_status_t
 _cairo_quartz_image_surface_finish (void *asurface)
 {
     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
 
-    /* the imageSurface will be destroyed by the data provider's release callback */
     CGImageRelease (surface->image);
-
+    cairo_surface_destroy (surface->imageSurface);
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
 _cairo_quartz_image_surface_acquire_source_image (void *asurface,
 						  cairo_image_surface_t **image_out,
 						  void **image_extra)
 {
@@ -149,45 +140,39 @@ static cairo_bool_t
 
 static cairo_status_t
 _cairo_quartz_image_surface_flush (void *asurface,
 				   unsigned flags)
 {
     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;
-
+    void *image_data;
+    const unsigned int size = surface->imageSurface->height * surface->imageSurface->stride;
     if (flags)
 	return CAIRO_STATUS_SUCCESS;
 
     /* XXX only flush if the image has been modified. */
 
-    image_info = _cairo_malloc (sizeof (quartz_image_info_t));
-    if (unlikely (!image_info))
+    image_data = _cairo_malloc_ab ( surface->imageSurface->height,
+				    surface->imageSurface->stride);
+    if (unlikely (!image_data))
 	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,
+    memcpy (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,
-					 image_info->image_data,
+					 image_data,
 					 TRUE,
 					 NULL,
 					 DataProviderReleaseCallback,
-					 image_info);
+					 image_data);
 
     surface->image = newImage;
     CGImageRelease (oldImage);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
@@ -321,65 +306,58 @@ cairo_quartz_image_surface_create (cairo
 {
     cairo_quartz_image_surface_t *qisurf;
 
     CGImageRef image;
 
     cairo_image_surface_t *image_surface;
     int width, height, stride;
     cairo_format_t format;
-    unsigned char *data;
-    quartz_image_info_t *image_info;
+    void *image_data;
 
     if (surface->status)
 	return surface;
 
     if (! _cairo_surface_is_image (surface))
 	return SURFACE_ERROR_TYPE_MISMATCH;
 
     image_surface = (cairo_image_surface_t*) surface;
     width = image_surface->width;
     height = image_surface->height;
     stride = image_surface->stride;
     format = image_surface->format;
-    data = image_surface->data;
 
     if (!_cairo_quartz_verify_surface_size(width, height))
 	return SURFACE_ERROR_INVALID_SIZE;
 
     if (width == 0 || height == 0)
 	return SURFACE_ERROR_INVALID_SIZE;
 
     if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24)
 	return SURFACE_ERROR_INVALID_FORMAT;
 
     qisurf = _cairo_malloc (sizeof(cairo_quartz_image_surface_t));
     if (qisurf == NULL)
 	return SURFACE_ERROR_NO_MEMORY;
 
     memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));
 
-    image_info = _cairo_malloc (sizeof (quartz_image_info_t));
-    if (unlikely (!image_info))
+    image_data = _cairo_malloc_ab (height, stride);
+    if (unlikely (!image_data))
 	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);
+    memcpy (image_data, image_surface->data, height * stride);
     image = CairoQuartzCreateCGImage (format,
 				      width, height,
 				      stride,
-				      image_info->image_data,
+				      image_data,
 				      TRUE,
 				      NULL,
 				      DataProviderReleaseCallback,
-				      image_info);
+				      image_data);
 
     if (!image) {
 	free (qisurf);
 	return SURFACE_ERROR_NO_MEMORY;
     }
 
     _cairo_surface_init (&qisurf->base,
 			 &cairo_quartz_image_surface_backend,
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
@@ -773,46 +773,33 @@ CairoQuartzCreateGradientFunction (const
     return CGFunctionCreate (pat,
 			     1,
 			     input_value_range,
 			     4,
 			     gradient_output_value_ranges,
 			     &gradient_callbacks);
 }
 
-/* Obtain a CGImageRef from a #cairo_surface_t * */
-
-typedef struct {
-    cairo_surface_t *surface;
-    cairo_image_surface_t *image_out;
-    void *image_extra;
-    void *image_data;
-} quartz_source_image_t;
-
 static void
 DataProviderReleaseCallback (void *info, const void *data, size_t size)
 {
-    quartz_source_image_t *source_img = info;
-    _cairo_surface_release_source_image (source_img->surface, source_img->image_out, source_img->image_extra);
-    cairo_surface_destroy (source_img->surface);
-    free (source_img->image_data);
-    free (source_img);
+    free (info);
 }
 
 static cairo_status_t
 _cairo_surface_to_cgimage (cairo_surface_t       *source,
 			   cairo_rectangle_int_t *extents,
 			   cairo_format_t         format,
 			   cairo_matrix_t        *matrix,
 			   const cairo_clip_t    *clip,
 			   CGImageRef            *image_out)
 {
     cairo_status_t status;
-    quartz_source_image_t *source_img;
     cairo_image_surface_t *image_surface;
+    void *image_data, *image_extra;
 
     if (source->backend && source->backend->type == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) {
 	cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source;
 	*image_out = CGImageRetain (surface->image);
 	return CAIRO_STATUS_SUCCESS;
     }
 
     if (_cairo_surface_is_quartz (source)) {
@@ -824,83 +811,68 @@ static cairo_status_t
 
 	if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
 	    *image_out = CGBitmapContextCreateImage (surface->cgContext);
 	    if (*image_out)
 		return CAIRO_STATUS_SUCCESS;
 	}
     }
 
-    source_img = _cairo_malloc (sizeof (quartz_source_image_t));
-    if (unlikely (source_img == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    source_img->surface = _cairo_surface_snapshot (source);
-
     if (source->type == CAIRO_SURFACE_TYPE_RECORDING) {
 	image_surface = (cairo_image_surface_t *)
 	    cairo_image_surface_create (format, extents->width, extents->height);
 	if (unlikely (image_surface->base.status)) {
 	    status = image_surface->base.status;
 	    cairo_surface_destroy (&image_surface->base);
-	    free (source_img);
 	    return status;
 	}
 
 	status = _cairo_recording_surface_replay_with_clip (source,
 							    matrix,
 							    &image_surface->base,
 							    NULL);
 	if (unlikely (status)) {
 	    cairo_surface_destroy (&image_surface->base);
-	    free (source_img);
 	    return status;
 	}
 
-	source_img->image_out = image_surface;
-	source_img->image_data = NULL;
-
 	cairo_matrix_init_identity (matrix);
     }
     else {
-	status = _cairo_surface_acquire_source_image (source_img->surface,
-						      &source_img->image_out,
-						      &source_img->image_extra);
-	if (unlikely (status)) {
-	    free (source_img);
+	status = _cairo_surface_acquire_source_image (source, &image_surface,
+						      &image_extra);
+	if (unlikely (status))
 	    return status;
-	}
     }
 
-    source_img->image_data = malloc (source_img->image_out->height * source_img->image_out->stride);
-    if (unlikely (!source_img->image_data))
+    image_data = _cairo_malloc_ab (image_surface->height, image_surface->stride);
+    if (unlikely (!image_data))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    memcpy (source_img->image_data, source_img->image_out->data,
-	    source_img->image_out->height * source_img->image_out->stride);
-    if (source_img->image_out->width == 0 || source_img->image_out->height == 0) {
+    memcpy (image_data, image_surface->data,
+	    image_surface->height * image_surface->stride);
+    if (image_surface->width == 0 || image_surface->height == 0) {
 	*image_out = NULL;
-	DataProviderReleaseCallback (source_img,
-				     source_img->image_out->data,
-				     source_img->image_out->height * source_img->image_out->stride);
+	DataProviderReleaseCallback (image_data, image_data, 0);
     } else {
-	*image_out = CairoQuartzCreateCGImage (source_img->image_out->format,
-					       source_img->image_out->width,
-					       source_img->image_out->height,
-					       source_img->image_out->stride,
-					       source_img->image_data,
+	*image_out = CairoQuartzCreateCGImage (image_surface->format,
+					       image_surface->width,
+					       image_surface->height,
+					       image_surface->stride,
+					       image_data,
 					       TRUE,
 					       NULL,
 					       DataProviderReleaseCallback,
-					       source_img);
+					       image_data);
 
 	/* TODO: differentiate memory error and unsupported surface type */
 	if (unlikely (*image_out == NULL))
 	    status = CAIRO_INT_STATUS_UNSUPPORTED;
     }
+    _cairo_surface_release_source_image (source, image_surface, image_extra);
 
     return status;
 }
 
 /* Generic #cairo_pattern_t -> CGPattern function */
 
 typedef struct {
     CGImageRef image;