diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cairo-quartz-image-surface.c | 138 | ||||
-rw-r--r-- | src/cairo-quartz-private.h | 18 | ||||
-rw-r--r-- | src/cairo-quartz-surface.c | 253 |
3 files changed, 135 insertions, 274 deletions
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); |