[cairo-commit] 4 commits - .gitlab-ci/ignore-quartz-argb32.txt .gitlab-ci/ignore-quartz-rgb24.txt src/cairo-quartz-image-surface.c src/cairo-quartz-private.h src/cairo-quartz-surface.c test/reference

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Feb 17 16:56:57 UTC 2023


 .gitlab-ci/ignore-quartz-argb32.txt             |    1 
 .gitlab-ci/ignore-quartz-rgb24.txt              |    1 
 src/cairo-quartz-image-surface.c                |  141 +++++-------
 src/cairo-quartz-private.h                      |   20 -
 src/cairo-quartz-surface.c                      |  267 +++++++-----------------
 test/reference/surface-pattern.quartz.xfail.png |binary
 6 files changed, 150 insertions(+), 280 deletions(-)

New commits:
commit d7b9695ee431dfe43a2ae48ebfd907623c6cb6e0
Merge: b7d8da7d1 e5ed09a1a
Author: Uli Schlachter <psychon at znc.in>
Date:   Fri Feb 17 16:56:55 2023 +0000

    Merge branch 'quartz-image-surface' into 'master'
    
    [quartz] Cleanup and make better use of cairo_quartz_image_surface_t.
    
    See merge request cairo/cairo!317

commit e5ed09a1ab0a8452c2f5753c3391ba66a74a3461
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun May 1 14:10:28 2022 -0700

    [quartz] Replace surface-pattern xfail with latest CI fail image.

diff --git a/test/reference/surface-pattern.quartz.xfail.png b/test/reference/surface-pattern.quartz.xfail.png
index 4ac47de5e..42938f026 100644
Binary files a/test/reference/surface-pattern.quartz.xfail.png and b/test/reference/surface-pattern.quartz.xfail.png differ
commit 6b1b14a23662b6050291a431731a096bfec1df82
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun May 1 13:30:21 2022 -0700

    [quartz] Pretty up the surface-type and zero-size tests.

diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index eb810f0d9..5d7f96018 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -359,7 +359,7 @@ _cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface)
 	return NULL;
 }
 
-/**
+/*
  * _cairo_surface_is_quartz_image:
  * @surface: a #cairo_surface_t
  *
@@ -368,8 +368,11 @@ _cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface)
  * Return value: True if the surface is an quartz surface
  **/
 cairo_bool_t
-_cairo_surface_is_quartz_image (const cairo_surface_t *surface)
-{
+_cairo_surface_is_quartz_image (const cairo_surface_t *surface) {
     return surface->backend == &cairo_quartz_image_surface_backend;
 }
 
+cairo_bool_t
+_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface) {
+    return surface->width == 0 || surface->height == 0;
+}
diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h
index 5b19601c1..4b6d2a99a 100644
--- a/src/cairo-quartz-private.h
+++ b/src/cairo-quartz-private.h
@@ -93,6 +93,8 @@ _cairo_surface_is_quartz (const cairo_surface_t *surface);
 
 cairo_private cairo_bool_t
 _cairo_surface_is_quartz_image (const cairo_surface_t *surface);
+cairo_private cairo_bool_t
+_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface);
 
 cairo_private CGContextRef
 _cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface);
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 6993bb3bd..789b110fd 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -56,6 +56,7 @@
 #endif
 
 #include <limits.h>
+#include <assert.h>
 
 #undef QUARTZ_DEBUG
 
@@ -72,16 +73,22 @@
 #endif
 
 static inline cairo_bool_t
-IS_EMPTY(void *abstract_surface) {
-    if (_cairo_surface_is_quartz ((cairo_surface_t*)abstract_surface)) {
-	cairo_quartz_surface_t *surface = (cairo_quartz_surface_t*)abstract_surface;
-	return surface->extents.width == 0 || surface->extents.height == 0;
-    }
-    if (_cairo_surface_is_quartz_image ((cairo_surface_t*)abstract_surface)) {
-	cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*)abstract_surface;
-	return surface->width == 0 || surface->height == 0;
-    }
-    return TRUE;
+_is_quartz_surface (cairo_surface_t *surface) {
+    return _cairo_surface_is_quartz (surface) || _cairo_surface_is_quartz_image (surface);
+}
+
+static inline cairo_bool_t
+_cairo_quartz_surface_is_zero (cairo_quartz_surface_t* surface) {
+    return surface->extents.width == 0 || surface->extents.height == 0;
+}
+
+static inline cairo_bool_t
+_cairo_quartz_is_zero_surface (cairo_surface_t* surface) {
+    assert (_is_quartz_surface (surface));
+    if (_cairo_surface_is_quartz (surface))
+	return (_cairo_quartz_surface_is_zero ((cairo_quartz_surface_t*) surface));
+    else
+	return (_cairo_quartz_image_surface_is_zero ((cairo_quartz_image_surface_t*) surface));
 }
 
 /**
@@ -609,9 +616,9 @@ _cairo_surface_to_cgimage (cairo_surface_t       *source,
     void *image_extra;
     cairo_bool_t acquired = FALSE;
 
-    if (_cairo_surface_is_quartz (source) || _cairo_surface_is_quartz_image (source)) {
+    if (_is_quartz_surface (source)) {
 	CGContextRef cgContext = cairo_quartz_surface_get_cg_context(source);
-	if (IS_EMPTY (source)) {
+	if (_cairo_quartz_is_zero_surface (source)) {
 	    *image_out = NULL;
 	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
 	}
@@ -1249,7 +1256,7 @@ _cairo_quartz_surface_map_to_image (void *abstract_surface,
     unsigned char *imageData;
     cairo_format_t format;
 
-    if (IS_EMPTY (surface))
+    if (_cairo_quartz_is_zero_surface (&surface->base))
 	return (cairo_image_surface_t *) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
 
     if (! _cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext))
@@ -1321,7 +1328,7 @@ _cairo_quartz_surface_finish (void *abstract_surface)
 
     ND ((stderr, "_cairo_quartz_surface_finish[%p] cgc: %p\n", surface, surface->cgContext));
 
-    if (IS_EMPTY (surface))
+    if (_cairo_quartz_is_zero_surface (&surface->base))
 	return CAIRO_STATUS_SUCCESS;
 
     /* Restore our saved gstate that we use to reset clipping */
@@ -1968,7 +1975,7 @@ _cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip
 
     ND ((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path));
 
-    if (IS_EMPTY (surface))
+    if (_cairo_quartz_is_zero_surface (&surface->base))
 	return CAIRO_STATUS_SUCCESS;
 
     if (path == NULL) {
@@ -2066,7 +2073,7 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
     surface->extents.height = height;
     surface->virtual_extents = surface->extents;
 
-    if (IS_EMPTY (surface)) {
+    if (_cairo_quartz_is_zero_surface (&surface->base)) {
 	surface->cgContext = NULL;
 	surface->cgContextBaseCTM = CGAffineTransformIdentity;
 	surface->base.is_clear = TRUE;
@@ -2283,7 +2290,7 @@ _cairo_quartz_snapshot_create (cairo_surface_t *surface)
 {
     cairo_quartz_snapshot_t *snapshot = NULL;
     CGContextRef cgContext;
-    if (!surface || IS_EMPTY (surface)) //IS_EMPTY returns true if the surface type is wrong.
+    if (!surface || ! _is_quartz_surface (surface) || _cairo_quartz_is_zero_surface (surface))
 	return NULL;
 
     if (_cairo_surface_is_quartz (surface) &&
@@ -2320,8 +2327,7 @@ CGImageRef
 _cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface)
 {
     cairo_surface_t *snapshot;
-    assert (_cairo_surface_is_quartz (surface) ||
-	    _cairo_surface_is_quartz_image (surface));
+    assert (_is_quartz_surface (surface));
     snapshot =
 	_cairo_surface_has_snapshot (surface, &cairo_quartz_snapshot_backend);
 
commit 198d1792cf1bdcc8379bcdcea798bd4249eb2c3c
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 26 12:20:04 2022 -0700

    [quartz] Cleanup and make better use of cairo_quartz_image_surface_t.
    
    Use a CGBitmapContext mapping the underlying image surface's data instead
    of maintaining a CGImage. Generalize the quartz surface snapshot mechanism
    to work with both cairo_quartz_surface_t and cairo_quartz_image_surface_t
    and to use the latter to get a CGContext around non-quartz surfaces.
    Use this snapshot machanism to get a CGImageRef when needed from a
    cairo_quartz_image_surface_t.

diff --git a/.gitlab-ci/ignore-quartz-argb32.txt b/.gitlab-ci/ignore-quartz-argb32.txt
index e00077831..fb30f4bb0 100644
--- a/.gitlab-ci/ignore-quartz-argb32.txt
+++ b/.gitlab-ci/ignore-quartz-argb32.txt
@@ -12,7 +12,6 @@ fallback
 ft-show-glyphs-positioning
 ft-text-vertical-layout-type1
 ft-text-vertical-layout-type3
-negative-stride-image
 operator-www
 radial-gradient
 radial-gradient-mask
diff --git a/.gitlab-ci/ignore-quartz-rgb24.txt b/.gitlab-ci/ignore-quartz-rgb24.txt
index 0941d59cd..92416e16b 100644
--- a/.gitlab-ci/ignore-quartz-rgb24.txt
+++ b/.gitlab-ci/ignore-quartz-rgb24.txt
@@ -31,7 +31,6 @@ image-surface-source
 linear-gradient-one-stop
 mask-ctm
 mask-surface-ctm
-negative-stride-image
 nil-surface
 operator-www
 overlapping-boxes
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index e05523459..eb810f0d9 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -49,12 +49,6 @@
 #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)))
 
-static void
-DataProviderReleaseCallback (void *image_info, const void *data, size_t size)
-{
-    free (image_info);
-}
-
 static cairo_surface_t *
 _cairo_quartz_image_surface_create_similar (void *asurface,
 					    cairo_content_t content,
@@ -87,8 +81,9 @@ _cairo_quartz_image_surface_finish (void *asurface)
 {
     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
 
-    CGImageRelease (surface->image);
-    cairo_surface_destroy ( (cairo_surface_t*) surface->imageSurface);
+    CGContextRelease (surface->cgContext);
+    if (surface->imageSurface)
+	cairo_surface_destroy ( (cairo_surface_t*) surface->imageSurface);
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -134,47 +129,6 @@ _cairo_quartz_image_surface_get_extents (void *asurface,
     return TRUE;
 }
 
-/* we assume some drawing happened to the image buffer; make sure it's
- * represented in the CGImage on flush()
- */
-
-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;
-    void *image_data;
-
-    if (flags)
-	return CAIRO_STATUS_SUCCESS;
-
-    /* XXX only flush if the image has been modified. */
-
-    image_data = _cairo_malloc_ab ( surface->imageSurface->height,
-				    surface->imageSurface->stride);
-    if (unlikely (!image_data))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    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_data,
-					 TRUE,
-					 NULL,
-					 DataProviderReleaseCallback,
-					 image_data);
-
-    surface->image = newImage;
-    CGImageRelease (oldImage);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static cairo_int_status_t
 _cairo_quartz_image_surface_paint (void			*abstract_surface,
 				   cairo_operator_t		 op,
@@ -275,7 +229,7 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
     _cairo_quartz_image_surface_get_extents,
     NULL, /* get_font_options */
 
-    _cairo_quartz_image_surface_flush,
+    NULL, /*surface_flush */
     NULL, /* mark_dirty_rectangle */
 
     _cairo_quartz_image_surface_paint,
@@ -290,12 +244,9 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
  * cairo_quartz_image_surface_create:
  * @image_surface: a cairo image surface to wrap with a quartz image surface
  *
- * Creates a Quartz surface backed by a CGImageRef that references the
+ * Creates a Quartz surface backed by a CGBitmapContext that references the
  * given image surface. The resulting surface can be rendered quickly
- * when used as a source when rendering to a #cairo_quartz_surface.  If
- * the data in the image surface is ever updated, cairo_surface_flush()
- * must be called on the #cairo_quartz_image_surface to ensure that the
- * CGImageRef refers to the updated data.
+ * when used as a source when rendering to a #cairo_quartz_surface.
  *
  * Return value: the newly created surface.
  *
@@ -305,13 +256,11 @@ cairo_surface_t *
 cairo_quartz_image_surface_create (cairo_surface_t *surface)
 {
     cairo_quartz_image_surface_t *qisurf;
-
-    CGImageRef image;
-
     cairo_image_surface_t *image_surface;
     int width, height, stride;
     cairo_format_t format;
-    void *image_data;
+    CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host;
+    CGColorSpaceRef colorspace;
 
     if (surface->status)
 	return surface;
@@ -338,41 +287,22 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
     if (qisurf == NULL)
 	return SURFACE_ERROR_NO_MEMORY;
 
-    memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));
-
-    image_data = _cairo_malloc_ab (height, stride);
-    if (unlikely (!image_data)) {
-	free(qisurf);
-	return SURFACE_ERROR_NO_MEMORY;
-    }
-
-    memcpy (image_data, image_surface->data, height * stride);
-    image = CairoQuartzCreateCGImage (format,
-				      width, height,
-				      stride,
-				      image_data,
-				      TRUE,
-				      NULL,
-				      DataProviderReleaseCallback,
-				      image_data);
-
-    if (!image) {
-	free (qisurf);
-	return SURFACE_ERROR_NO_MEMORY;
-    }
-
     _cairo_surface_init (&qisurf->base,
 			 &cairo_quartz_image_surface_backend,
 			 NULL, /* device */
 			 _cairo_content_from_format (format),
 			 FALSE); /* is_vector */
+    colorspace = CGColorSpaceCreateDeviceRGB ();
+    bitinfo |= format == CAIRO_FORMAT_ARGB32 ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
 
     qisurf->width = width;
     qisurf->height = height;
 
-    qisurf->image = image;
+    qisurf->cgContext = CGBitmapContextCreate (image_surface->data, width, height, 8, image_surface->stride,
+					       colorspace, bitinfo);
     qisurf->imageSurface = (cairo_image_surface_t*) cairo_surface_reference(surface);
 
+    CGColorSpaceRelease (colorspace);
     return &qisurf->base;
 }
 
@@ -401,3 +331,45 @@ cairo_quartz_image_surface_get_image (cairo_surface_t *surface)
 
     return (cairo_surface_t*) qsurface->imageSurface;
 }
+
+/*
+ * _cairo_quartz_image_surface_get_cg_context:
+ * @surface: the Cairo Quartz surface
+ *
+ * Returns the CGContextRef that the given Quartz surface is backed
+ * by.
+ *
+ * A call to cairo_surface_flush() is required before using the
+ * CGContextRef to ensure that all pending drawing operations are
+ * finished and to restore any temporary modification cairo has made
+ * to its state. A call to cairo_surface_mark_dirty() is required
+ * after the state or the content of the CGContextRef has been
+ * modified.
+ *
+ * Return value: the CGContextRef for the given surface.
+ *
+ **/
+CGContextRef
+_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface)
+{
+    if (surface && _cairo_surface_is_quartz_image (surface)) {
+	cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface;
+	return quartz->cgContext;
+    } else
+	return NULL;
+}
+
+/**
+ * _cairo_surface_is_quartz_image:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is a #cairo_quartz_surface_t
+ *
+ * Return value: True if the surface is an quartz surface
+ **/
+cairo_bool_t
+_cairo_surface_is_quartz_image (const cairo_surface_t *surface)
+{
+    return surface->backend == &cairo_quartz_image_surface_backend;
+}
+
diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h
index f142f8471..5b19601c1 100644
--- a/src/cairo-quartz-private.h
+++ b/src/cairo-quartz-private.h
@@ -81,8 +81,7 @@ typedef struct cairo_quartz_image_surface {
     cairo_surface_t base;
 
     int width, height;
-
-    CGImageRef image;
+    CGContextRef cgContext;
     cairo_image_surface_t *imageSurface;
 } cairo_quartz_image_surface_t;
 
@@ -92,16 +91,11 @@ _cairo_quartz_verify_surface_size(int width, int height);
 cairo_private cairo_bool_t
 _cairo_surface_is_quartz (const cairo_surface_t *surface);
 
-cairo_private CGImageRef
-CairoQuartzCreateCGImage (cairo_format_t format,
-			      unsigned int width,
-			      unsigned int height,
-			      unsigned int stride,
-			      void *data,
-			      cairo_bool_t interpolate,
-			      CGColorSpaceRef colorSpaceOverride,
-			      CGDataProviderReleaseDataCallback releaseCallback,
-			      void *releaseInfo);
+cairo_private cairo_bool_t
+_cairo_surface_is_quartz_image (const cairo_surface_t *surface);
+
+cairo_private CGContextRef
+_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface);
 
 cairo_private CGFontRef
 _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index dbb6aa46f..6993bb3bd 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -37,6 +37,7 @@
 #include "cairoint.h"
 
 #include "cairo-quartz-private.h"
+#include "cairo-quartz-image.h"
 
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-compositor-private.h"
@@ -64,13 +65,24 @@
 #define ND(_x)	do {} while(0)
 #endif
 
-#define IS_EMPTY(s) ((s)->extents.width == 0 || (s)->extents.height == 0)
 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
 #define FONT_ORIENTATION_HORIZONTAL kCTFontHorizontalOrientation
 #else
 #define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal
 #endif
 
+static inline cairo_bool_t
+IS_EMPTY(void *abstract_surface) {
+    if (_cairo_surface_is_quartz ((cairo_surface_t*)abstract_surface)) {
+	cairo_quartz_surface_t *surface = (cairo_quartz_surface_t*)abstract_surface;
+	return surface->extents.width == 0 || surface->extents.height == 0;
+    }
+    if (_cairo_surface_is_quartz_image ((cairo_surface_t*)abstract_surface)) {
+	cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*)abstract_surface;
+	return surface->width == 0 || surface->height == 0;
+    }
+    return TRUE;
+}
 
 /**
  * SECTION:cairo-quartz
@@ -119,9 +131,9 @@ typedef struct
     CGImageRef image;
 } cairo_quartz_snapshot_t;
 
-static cairo_surface_t* _cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface);
-static cairo_status_t _cairo_quartz_snapshot_finish (void* surface);
-static CGImageRef _cairo_quartz_surface_snapshot_get_image (cairo_quartz_surface_t *surface);
+static cairo_surface_t* _cairo_quartz_snapshot_create (cairo_surface_t *surface);
+static cairo_status_t _cairo_quartz_snapshot_finish (void *surface);
+static CGImageRef _cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface);
 
 static const cairo_surface_backend_t cairo_quartz_snapshot_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_QUARTZ_SNAPSHOT,
@@ -134,104 +146,6 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
 				       unsigned int width,
 				       unsigned int height);
 
-CGImageRef
-CairoQuartzCreateCGImage (cairo_format_t format,
-			  unsigned int width,
-			  unsigned int height,
-			  unsigned int stride,
-			  void *data,
-			  cairo_bool_t interpolate,
-			  CGColorSpaceRef colorSpaceOverride,
-			  CGDataProviderReleaseDataCallback releaseCallback,
-			  void *releaseInfo)
-{
-    CGImageRef image = NULL;
-    CGDataProviderRef dataProvider = NULL;
-    CGColorSpaceRef colorSpace = colorSpaceOverride;
-    CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host;
-    int bitsPerComponent, bitsPerPixel;
-
-    switch (format) {
-	case CAIRO_FORMAT_ARGB32:
-	    if (colorSpace == NULL)
-		colorSpace = CGColorSpaceCreateDeviceRGB ();
-	    bitinfo |= kCGImageAlphaPremultipliedFirst;
-	    bitsPerComponent = 8;
-	    bitsPerPixel = 32;
-	    break;
-
-	case CAIRO_FORMAT_RGB24:
-	    if (colorSpace == NULL)
-		colorSpace = CGColorSpaceCreateDeviceRGB ();
-	    bitinfo |= kCGImageAlphaNoneSkipFirst;
-	    bitsPerComponent = 8;
-	    bitsPerPixel = 32;
-	    break;
-
-	case CAIRO_FORMAT_A8:
-	    bitsPerComponent = 8;
-	    bitsPerPixel = 8;
-	    break;
-
-	case CAIRO_FORMAT_A1:
-#ifdef WORDS_BIGENDIAN
-	    bitsPerComponent = 1;
-	    bitsPerPixel = 1;
-	    break;
-#endif
-
-	case CAIRO_FORMAT_RGB30:
-	case CAIRO_FORMAT_RGB16_565:
-        case CAIRO_FORMAT_RGB96F:
-        case CAIRO_FORMAT_RGBA128F:
-	case CAIRO_FORMAT_INVALID:
-	default:
-	    return NULL;
-    }
-
-    dataProvider = CGDataProviderCreateWithData (releaseInfo,
-						 data,
-						 height * stride,
-						 releaseCallback);
-
-    if (unlikely (!dataProvider)) {
-	// manually release
-	if (releaseCallback)
-	    releaseCallback (releaseInfo, data, height * stride);
-	goto FINISH;
-    }
-
-    if (format == CAIRO_FORMAT_A8 || format == CAIRO_FORMAT_A1) {
-	cairo_quartz_float_t decode[] = {1.0, 0.0};
-	image = CGImageMaskCreate (width, height,
-				   bitsPerComponent,
-				   bitsPerPixel,
-				   stride,
-				   dataProvider,
-				   decode,
-				   interpolate);
-    } else
-	image = CGImageCreate (width, height,
-			       bitsPerComponent,
-			       bitsPerPixel,
-			       stride,
-			       colorSpace,
-			       bitinfo,
-			       dataProvider,
-			       NULL,
-			       interpolate,
-			       kCGRenderingIntentDefault);
-
-FINISH:
-
-    CGDataProviderRelease (dataProvider);
-
-    if (colorSpace != colorSpaceOverride)
-	CGColorSpaceRelease (colorSpace);
-
-    return image;
-}
-
 static inline cairo_bool_t
 _cairo_quartz_is_cgcontext_bitmap_context (CGContextRef cgc)
 {
@@ -682,12 +596,6 @@ CairoQuartzCreateGradientFunction (const cairo_gradient_pattern_t *gradient,
 			     &gradient_callbacks);
 }
 
-static void
-DataProviderReleaseCallback (void *info, const void *data, size_t size)
-{
-    free (info);
-}
-
 static cairo_status_t
 _cairo_surface_to_cgimage (cairo_surface_t       *source,
 			   cairo_rectangle_int_t *extents,
@@ -697,25 +605,19 @@ _cairo_surface_to_cgimage (cairo_surface_t       *source,
 			   CGImageRef            *image_out)
 {
     cairo_status_t status;
-    cairo_image_surface_t *image_surface;
-    void *image_data, *image_extra;
+    cairo_quartz_image_surface_t *image_surface;
+    void *image_extra;
     cairo_bool_t acquired = FALSE;
 
-    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)) {
-	cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source;
-	if (IS_EMPTY (surface)) {
+    if (_cairo_surface_is_quartz (source) || _cairo_surface_is_quartz_image (source)) {
+	CGContextRef cgContext = cairo_quartz_surface_get_cg_context(source);
+	if (IS_EMPTY (source)) {
 	    *image_out = NULL;
 	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
 	}
 
-	if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
-	    *image_out = _cairo_quartz_surface_snapshot_get_image (surface);
+	if (_cairo_quartz_is_cgcontext_bitmap_context (cgContext)) {
+	    *image_out = _cairo_quartz_surface_snapshot_get_image (source);
 	    return CAIRO_STATUS_SUCCESS;
 	}
 
@@ -724,80 +626,60 @@ _cairo_surface_to_cgimage (cairo_surface_t       *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);
+	cairo_image_surface_t *surface =
+	    (cairo_image_surface_t*)cairo_image_surface_create (format, extents->width,
+								extents->height);
+	if (unlikely (surface->base.status)) {
+	    status = surface->base.status;
+	    cairo_surface_destroy (&surface->base);
 	    return status;
 	}
 
 	status = _cairo_recording_surface_replay_with_clip (source,
 							    matrix,
-							    &image_surface->base,
+							    &surface->base,
 							    NULL,
 							    FALSE);
 	if (unlikely (status)) {
-	    cairo_surface_destroy (&image_surface->base);
+	    cairo_surface_destroy (&surface->base);
 	    return status;
 	}
 
+	image_surface =
+	    (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
 	cairo_matrix_init_identity (matrix);
     }
     else {
-	status = _cairo_surface_acquire_source_image (source, &image_surface,
+	cairo_image_surface_t *surface;
+	status = _cairo_surface_acquire_source_image (source, &surface,
 						      &image_extra);
 	if (unlikely (status))
 	    return status;
-	acquired = TRUE;
-    }
-
-    if (image_surface->width == 0 || image_surface->height == 0) {
-	*image_out = NULL;
-	if (acquired)
-	    _cairo_surface_release_source_image (source, image_surface, image_extra);
+	image_surface =
+	    (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
+	status = image_surface->base.status;
+	if (status)
+	    _cairo_surface_release_source_image (source, surface, image_extra);
 	else
-	    cairo_surface_destroy (&image_surface->base);
-
-	return status;
+	    acquired = TRUE;
     }
 
-    image_data = _cairo_malloc_ab (image_surface->height, image_surface->stride);
-    if (unlikely (!image_data))
-    {
-	if (acquired)
-	    _cairo_surface_release_source_image (source, image_surface, image_extra);
-	else
-	    cairo_surface_destroy (&image_surface->base);
-
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    *image_out = NULL;
+    if (image_surface->width > 0 && image_surface->height > 0) {
+	*image_out = _cairo_quartz_surface_snapshot_get_image (&image_surface->base);
+	status = CAIRO_STATUS_SUCCESS;
     }
 
-    // The last row of data may have less than stride bytes so make sure we
-    // only copy the minimum amount required from that row.
-    memcpy (image_data, image_surface->data,
-	    (image_surface->height - 1) * image_surface->stride +
-	    cairo_format_stride_for_width (image_surface->format,
-					   image_surface->width));
-    *image_out = CairoQuartzCreateCGImage (image_surface->format,
-					   image_surface->width,
-					   image_surface->height,
-					   image_surface->stride,
-					   image_data,
-					   TRUE,
-					   NULL,
-					   DataProviderReleaseCallback,
-					   image_data);
+    if (acquired) {
+	_cairo_surface_release_source_image (source, image_surface->imageSurface, image_extra);
+	image_surface->imageSurface = NULL;
+    }
+    cairo_surface_destroy (&image_surface->base);
 
     /* TODO: differentiate memory error and unsupported surface type */
     if (unlikely (*image_out == NULL))
 	status = CAIRO_INT_STATUS_UNSUPPORTED;
 
-    if (acquired)
-	_cairo_surface_release_source_image (source, image_surface, image_extra);
-    else
-	cairo_surface_destroy (&image_surface->base);
-
     return status;
 }
 
@@ -2372,8 +2254,14 @@ cairo_quartz_surface_get_cg_context (cairo_surface_t *surface)
     if (surface && _cairo_surface_is_quartz (surface)) {
 	cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface;
 	return quartz->cgContext;
-    } else
-	return NULL;
+    }
+
+    if (surface && _cairo_surface_is_quartz_image (surface)) {
+	cairo_quartz_image_surface_t *quartz = (cairo_quartz_image_surface_t *) surface;
+	return quartz->cgContext;
+    }
+
+    return NULL;
 }
 
 /**
@@ -2391,12 +2279,15 @@ _cairo_surface_is_quartz (const cairo_surface_t *surface)
 }
 
 cairo_surface_t*
-_cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface)
+_cairo_quartz_snapshot_create (cairo_surface_t *surface)
 {
     cairo_quartz_snapshot_t *snapshot = NULL;
+    CGContextRef cgContext;
+    if (!surface || IS_EMPTY (surface)) //IS_EMPTY returns true if the surface type is wrong.
+	return NULL;
 
-    if (!surface || !_cairo_surface_is_quartz (&surface->base) || IS_EMPTY (surface) ||
-	! _cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext))
+    if (_cairo_surface_is_quartz (surface) &&
+	! _cairo_quartz_is_cgcontext_bitmap_context (((cairo_quartz_surface_t*)surface)->cgContext))
 	return NULL;
 
     snapshot = _cairo_malloc (sizeof (cairo_quartz_snapshot_t));
@@ -2405,10 +2296,13 @@ _cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface)
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
     memset (snapshot, 0, sizeof (cairo_quartz_snapshot_t));
+    cgContext = cairo_quartz_surface_get_cg_context (surface);
     _cairo_surface_init (&snapshot->base,
 			 &cairo_quartz_snapshot_backend,
 			 NULL, CAIRO_CONTENT_COLOR_ALPHA, FALSE);
-    snapshot->image = CGBitmapContextCreateImage (surface->cgContext);
+    snapshot->image = CGBitmapContextCreateImage (cgContext);
+    _cairo_surface_attach_snapshot (surface, &snapshot->base, NULL);
+    cairo_surface_destroy (&snapshot->base); // The surface has reffed the snapshot so we must unref it here.
 
     return &snapshot->base;
 }
@@ -2423,18 +2317,19 @@ _cairo_quartz_snapshot_finish (void *surface)
 }
 
 CGImageRef
-_cairo_quartz_surface_snapshot_get_image (cairo_quartz_surface_t *surface)
+_cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface)
 {
-    cairo_surface_t *snapshot =
-	_cairo_surface_has_snapshot (&surface->base, &cairo_quartz_snapshot_backend);
+    cairo_surface_t *snapshot;
+    assert (_cairo_surface_is_quartz (surface) ||
+	    _cairo_surface_is_quartz_image (surface));
+    snapshot =
+	_cairo_surface_has_snapshot (surface, &cairo_quartz_snapshot_backend);
 
     if (unlikely (!snapshot))
     {
 	snapshot = _cairo_quartz_snapshot_create (surface);
 	if (unlikely (!snapshot || cairo_surface_status (snapshot)))
 	    return NULL;
-	_cairo_surface_attach_snapshot (&surface->base, snapshot, NULL);
-	cairo_surface_destroy (snapshot);
     }
 
     return CGImageRetain (((cairo_quartz_snapshot_t*)snapshot)->image);


More information about the cairo-commit mailing list