diff -Naur cairo-old/src/cairo-quartz-surface.c cairo-new/src/cairo-quartz-surface.c --- cairo-old/src/cairo-quartz-surface.c 2006-06-29 20:05:59.000000000 -0400 +++ cairo-new/src/cairo-quartz-surface.c 2006-07-06 21:22:51.000000000 -0400 @@ -37,6 +37,8 @@ #include "cairo-private.h" #include "cairo-quartz-private.h" +#include + static cairo_status_t _cairo_quartz_surface_finish(void *abstract_surface) { @@ -48,18 +50,147 @@ return CAIRO_STATUS_SUCCESS; } +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + +/* Get the cairo format for a CGContext's data. Return true if successful, + * false if no matching format known. */ +static cairo_bool_t +_cairo_quartz_surface_format_for_bitmap_context( + CGContextRef context, + cairo_format_t *format_out) +{ + size_t bpp, bpc; + CGBitmapInfo info, order; + + bpp = CGBitmapContextGetBitsPerPixel(context); + if (bpp == 0) { + return FALSE; /* Not a bitmap! */ + } + bpc = CGBitmapContextGetBitsPerComponent(context); + info = CGBitmapContextGetBitmapInfo(context); + order = info & kCGBitmapByteOrderMask; + + if (info & kCGBitmapFloatComponents) { + return FALSE; + } + + if (bpp == 32 && order == kCGBitmapByteOrder32Host) { + CGBitmapInfo alpha = info & kCGBitmapAlphaInfoMask; + if (alpha == kCGImageAlphaPremultipliedFirst) { + *format_out = CAIRO_FORMAT_ARGB32; + return TRUE; + } else if (alpha == kCGImageAlphaNoneSkipFirst) { + *format_out = CAIRO_FORMAT_RGB24; + return TRUE; + } + } else if (bpp == 8 && bpc == 8) { + *format_out = CAIRO_FORMAT_A8; + return TRUE; + } + return FALSE; +} + +/* Given a CGBitmapContext, return a bitmap context with the same contents, + * whose data is appropriate for conversion to a cairo surface. + * The caller is responsible for freeing the new context. */ +static CGContextRef +_cairo_quartz_surface_convert_bitmap( + CGContextRef context) +{ + CGImageRef image; + CGColorSpaceRef color_space; + CGContextRef new_context; + CGRect rect; + size_t height, width; + void *data; + + /* Make a new context */ + color_space = CGColorSpaceCreateDeviceRGB(); + height = CGBitmapContextGetHeight(context); + width = CGBitmapContextGetWidth(context); + rect = CGRectMake(0.0, 0.0, width, height); + data = malloc(4 * height * width); + new_context = CGBitmapContextCreate(data, width, height, 8, width * 4, + color_space, + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); + CGContextClearRect(new_context, rect); + + /* Turn the old one into an image, and draw the image to the new context */ + image = CGBitmapContextCreateImage(context); + CGContextDrawImage(new_context, rect, image); + CGImageRelease(image); + return new_context; +} + +static cairo_status_t +_cairo_quartz_surface_acquire_source_image( + void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + CGContextRef context, source; + cairo_format_t format; + cairo_image_surface_t *image; + void *data; + + /* Support weak linking */ + if (CGBitmapContextGetBitmapInfo == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + context = ((cairo_quartz_surface_t *)abstract_surface)->context; + + /* We can only use bitmap contexts as sources */ + if (CGBitmapContextGetBitsPerPixel(context) == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; /* not a bitmap */ + + /* Find a format, and what bitmap to use as the data source */ + if (_cairo_quartz_surface_format_for_bitmap_context(context, &format)) { + source = context; + *image_extra = NULL; + } else { + source = _cairo_quartz_surface_convert_bitmap(context); + *image_extra = source; + _cairo_quartz_surface_format_for_bitmap_context(source, &format); + } + + /* Make a cairo surface from the data */ + data = CGBitmapContextGetData(source); + image = (cairo_image_surface_t*)cairo_image_surface_create_for_data( + data, format, + CGBitmapContextGetWidth(source), + CGBitmapContextGetHeight(source), + CGBitmapContextGetBytesPerRow(source)); + *image_out = image; + + return CAIRO_STATUS_SUCCESS; +} + +#else /* < MAC_OS_X_VERSION_10_4 */ + static cairo_status_t -_cairo_quartz_surface_acquire_source_image(void *abstract_surface, - cairo_image_surface_t **image_out, - void **image_extra) +_cairo_quartz_surface_acquire_source_image( + void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { - cairo_quartz_surface_t *surface = abstract_surface; + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +#endif - if (CGBitmapContextGetBitmapInfo (surface->context) != 0) { - /* XXX: We can create an image out of the bitmap here */ - } - return CAIRO_INT_STATUS_UNSUPPORTED; +static void +_cairo_quartz_surface_release_source_image ( + void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy((cairo_surface_t *)image); + if (image_extra != NULL) { + CGContextRef bitmap = (CGContextRef)image_extra; + free(CGBitmapContextGetData(bitmap)); + CGContextRelease(bitmap); + } } static cairo_status_t @@ -210,7 +341,7 @@ NULL, /* create_similar */ _cairo_quartz_surface_finish, _cairo_quartz_surface_acquire_source_image, - NULL, /* release_source_image */ + _cairo_quartz_surface_release_source_image, _cairo_quartz_surface_acquire_dest_image, _cairo_quartz_surface_release_dest_image, NULL, /* clone_similar */