gecko-dev/gfx/cairo/09-quartz-surface-additions...

315 строки
9.9 KiB
Diff

diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h
--- a/gfx/cairo/cairo/src/cairo-quartz-private.h
+++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
@@ -71,8 +71,11 @@ typedef struct cairo_quartz_surface {
cairo_surface_t *imageSurfaceEquiv;
cairo_surface_clipper_t clipper;
+
cairo_rectangle_int_t extents;
cairo_rectangle_int_t virtual_extents;
+
+ cairo_bool_t ownsData;
} cairo_quartz_surface_t;
typedef struct cairo_quartz_image_surface {
diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
@@ -1520,6 +1520,103 @@ static cairo_int_status_t
/*
+ * get source/dest image implementation
+ */
+
+/* Read the image from the surface's front buffer */
+static cairo_int_status_t
+_cairo_quartz_get_image (cairo_quartz_surface_t *surface,
+ cairo_image_surface_t **image_out)
+{
+ unsigned char *imageData;
+ cairo_image_surface_t *isurf;
+
+ if (IS_EMPTY(surface)) {
+ *image_out = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (surface->imageSurfaceEquiv) {
+ CGContextFlush(surface->cgContext);
+ *image_out = (cairo_image_surface_t*) cairo_surface_reference(surface->imageSurfaceEquiv);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (_cairo_quartz_is_cgcontext_bitmap_context(surface->cgContext)) {
+ unsigned int stride;
+ unsigned int bitinfo;
+ unsigned int bpc, bpp;
+ CGColorSpaceRef colorspace;
+ unsigned int color_comps;
+
+ CGContextFlush(surface->cgContext);
+ imageData = (unsigned char *) CGBitmapContextGetData(surface->cgContext);
+
+#ifdef USE_10_3_WORKAROUNDS
+ bitinfo = CGBitmapContextGetAlphaInfo (surface->cgContext);
+#else
+ bitinfo = CGBitmapContextGetBitmapInfo (surface->cgContext);
+#endif
+ stride = CGBitmapContextGetBytesPerRow (surface->cgContext);
+ bpp = CGBitmapContextGetBitsPerPixel (surface->cgContext);
+ bpc = CGBitmapContextGetBitsPerComponent (surface->cgContext);
+
+ // let's hope they don't add YUV under us
+ colorspace = CGBitmapContextGetColorSpace (surface->cgContext);
+ color_comps = CGColorSpaceGetNumberOfComponents(colorspace);
+
+ // XXX TODO: We can handle all of these by converting to
+ // pixman masks, including non-native-endian masks
+ if (bpc != 8)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (bpp != 32 && bpp != 8)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (color_comps != 3 && color_comps != 1)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (bpp == 32 && color_comps == 3 &&
+ (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaPremultipliedFirst &&
+ (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host)
+ {
+ isurf = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (imageData,
+ CAIRO_FORMAT_ARGB32,
+ surface->extents.width,
+ surface->extents.height,
+ stride);
+ } else if (bpp == 32 && color_comps == 3 &&
+ (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaNoneSkipFirst &&
+ (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host)
+ {
+ isurf = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (imageData,
+ CAIRO_FORMAT_RGB24,
+ surface->extents.width,
+ surface->extents.height,
+ stride);
+ } else if (bpp == 8 && color_comps == 1)
+ {
+ isurf = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (imageData,
+ CAIRO_FORMAT_A8,
+ surface->extents.width,
+ surface->extents.height,
+ stride);
+ } else {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ } else {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ *image_out = isurf;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+/*
* Cairo surface backend implementations
*/
@@ -1542,11 +1639,14 @@ static cairo_status_t
surface->cgContext = NULL;
if (surface->imageSurfaceEquiv) {
+ if (surface->ownsData)
+ _cairo_image_surface_assume_ownership_of_data (surface->imageSurfaceEquiv);
cairo_surface_destroy (surface->imageSurfaceEquiv);
surface->imageSurfaceEquiv = NULL;
+ } else if (surface->imageData && surface->ownsData) {
+ free (surface->imageData);
}
- free (surface->imageData);
surface->imageData = NULL;
return CAIRO_STATUS_SUCCESS;
@@ -2298,6 +2398,8 @@ cairo_quartz_surface_t *
surface->cgContext = cgContext;
surface->cgContextBaseCTM = CGContextGetCTM (cgContext);
+ surface->ownsData = TRUE;
+
return surface;
}
@@ -2452,10 +2554,124 @@ cairo_quartz_surface_create (cairo_forma
surf->imageData = imageData;
surf->imageSurfaceEquiv = cairo_image_surface_create_for_data (imageData, format, width, height, stride);
+ // We created this data, so we can delete it.
+ surf->ownsData = TRUE;
+
return &surf->base;
}
/**
+ * cairo_quartz_surface_create_for_data
+ * @data: a pointer to a buffer supplied by the application in which
+ * to write contents. This pointer must be suitably aligned for any
+ * kind of variable, (for example, a pointer returned by malloc).
+ * @format: format of pixels in the surface to create
+ * @width: width of the surface, in pixels
+ * @height: height of the surface, in pixels
+ *
+ * Creates a Quartz surface backed by a CGBitmap. The surface is
+ * created using the Device RGB (or Device Gray, for A8) color space.
+ * All Cairo operations, including those that require software
+ * rendering, will succeed on this surface.
+ *
+ * Return value: the newly created surface.
+ *
+ * Since: 1.12 [Mozilla addition]
+ **/
+cairo_surface_t *
+cairo_quartz_surface_create_for_data (unsigned char *data,
+ cairo_format_t format,
+ unsigned int width,
+ unsigned int height,
+ unsigned int stride)
+{
+ cairo_quartz_surface_t *surf;
+ CGContextRef cgc;
+ CGColorSpaceRef cgColorspace;
+ CGBitmapInfo bitinfo;
+ void *imageData = data;
+ int bitsPerComponent;
+ unsigned int i;
+
+ // verify width and height of surface
+ if (!_cairo_quartz_verify_surface_size(width, height))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+
+ if (width == 0 || height == 0) {
+ return (cairo_surface_t*) _cairo_quartz_surface_create_internal (NULL, _cairo_content_from_format (format),
+ width, height);
+ }
+
+ if (format == CAIRO_FORMAT_ARGB32 ||
+ format == CAIRO_FORMAT_RGB24)
+ {
+ cgColorspace = CGColorSpaceCreateDeviceRGB();
+ bitinfo = kCGBitmapByteOrder32Host;
+ if (format == CAIRO_FORMAT_ARGB32)
+ bitinfo |= kCGImageAlphaPremultipliedFirst;
+ else
+ bitinfo |= kCGImageAlphaNoneSkipFirst;
+ bitsPerComponent = 8;
+ } else if (format == CAIRO_FORMAT_A8) {
+ cgColorspace = NULL;
+ bitinfo = kCGImageAlphaOnly;
+ bitsPerComponent = 8;
+ } else if (format == CAIRO_FORMAT_A1) {
+ /* I don't think we can usefully support this, as defined by
+ * cairo_format_t -- these are 1-bit pixels stored in 32-bit
+ * quantities.
+ */
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+ } else {
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+ }
+
+ cgc = CGBitmapContextCreate (imageData,
+ width,
+ height,
+ bitsPerComponent,
+ stride,
+ cgColorspace,
+ bitinfo);
+ CGColorSpaceRelease (cgColorspace);
+
+ if (!cgc) {
+ free (imageData);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ /* flip the Y axis */
+ CGContextTranslateCTM (cgc, 0.0, height);
+ CGContextScaleCTM (cgc, 1.0, -1.0);
+
+ surf = _cairo_quartz_surface_create_internal (cgc, _cairo_content_from_format (format),
+ width, height);
+ if (surf->base.status) {
+ CGContextRelease (cgc);
+ free (imageData);
+ // create_internal will have set an error
+ return (cairo_surface_t*) surf;
+ }
+
+ surf->imageData = imageData;
+
+ cairo_surface_t* tmpImageSurfaceEquiv =
+ cairo_image_surface_create_for_data (imageData, format,
+ width, height, stride);
+
+ if (cairo_surface_status (tmpImageSurfaceEquiv)) {
+ // Tried & failed to create an imageSurfaceEquiv!
+ cairo_surface_destroy (tmpImageSurfaceEquiv);
+ surf->imageSurfaceEquiv = NULL;
+ } else {
+ surf->imageSurfaceEquiv = tmpImageSurfaceEquiv;
+ surf->ownsData = FALSE;
+ }
+
+ return (cairo_surface_t *) surf;
+}
+
+/**
* cairo_quartz_surface_get_cg_context:
* @surface: the Cairo Quartz surface
*
@@ -2497,6 +2713,18 @@ cairo_bool_t
return surface->backend == &cairo_quartz_surface_backend;
}
+cairo_surface_t *
+cairo_quartz_surface_get_image (cairo_surface_t *surface)
+{
+ cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *)surface;
+ cairo_image_surface_t *image;
+
+ if (_cairo_quartz_get_image(quartz, &image))
+ return NULL;
+
+ return (cairo_surface_t *)image;
+}
+
/* Debug stuff */
#ifdef QUARTZ_DEBUG
diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h
--- a/gfx/cairo/cairo/src/cairo-quartz.h
+++ b/gfx/cairo/cairo/src/cairo-quartz.h
@@ -54,9 +54,19 @@ cairo_quartz_surface_create_for_cg_conte
unsigned int width,
unsigned int height);
+cairo_surface_t *
+cairo_quartz_surface_create_for_data (unsigned char *data,
+ cairo_format_t format,
+ unsigned int width,
+ unsigned int height,
+ unsigned int stride);
+
cairo_public CGContextRef
cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);
+cairo_public cairo_surface_t *
+cairo_quartz_surface_get_image (cairo_surface_t *surface);
+
#if CAIRO_HAS_QUARTZ_FONT
/*