summaryrefslogtreecommitdiff
path: root/src/cairo-quartz-surface.c
diff options
context:
space:
mode:
authorJohn Ralls <jralls@ceridwen.us>2022-04-26 12:20:04 -0700
committerJohn Ralls <jralls@ceridwen.us>2023-02-14 11:52:57 -0800
commit198d1792cf1bdcc8379bcdcea798bd4249eb2c3c (patch)
tree78d0c8d78a223561a7be2032149539f73d4b2033 /src/cairo-quartz-surface.c
parent6b5519626c0f809a58f072e3b402963ec45f29ab (diff)
downloadcairo-198d1792cf1bdcc8379bcdcea798bd4249eb2c3c.tar.gz
[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.
Diffstat (limited to 'src/cairo-quartz-surface.c')
-rw-r--r--src/cairo-quartz-surface.c253
1 files changed, 74 insertions, 179 deletions
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);