diff options
author | John Ralls <jralls@ceridwen.us> | 2022-04-26 12:20:04 -0700 |
---|---|---|
committer | John Ralls <jralls@ceridwen.us> | 2023-02-14 11:52:57 -0800 |
commit | 198d1792cf1bdcc8379bcdcea798bd4249eb2c3c (patch) | |
tree | 78d0c8d78a223561a7be2032149539f73d4b2033 /src/cairo-quartz-surface.c | |
parent | 6b5519626c0f809a58f072e3b402963ec45f29ab (diff) | |
download | cairo-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.c | 253 |
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); |