b=423524, CGContextGetType warnings showing up in console, r=stuart
authorvladimir@pobox.com
Tue, 18 Mar 2008 13:36:40 -0700
changeset 13264 268a3047da58a0e6db8b777eb39238b876c4ae67
parent 13263 601ea65a1056a0594fb2514e6c8387d2794c99f1
child 13265 7ae1806d484e32756537f18d847266dfa9bb0742
push idunknown
push userunknown
push dateunknown
reviewersstuart
bugs423524
milestone1.9b5pre
b=423524, CGContextGetType warnings showing up in console, r=stuart
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
@@ -151,16 +151,19 @@ static void quartz_ensure_symbols(void)
     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
 
     _cairo_quartz_symbol_lookup_done = TRUE;
 }
 
 static inline cairo_bool_t
 _cairo_quartz_is_cgcontext_bitmap_context (CGContextRef cgc) {
+    if (cgc == NULL)
+	return FALSE;
+
     if (CGContextGetTypePtr) {
 	/* 4 is the type value of a bitmap context */
 	if (CGContextGetTypePtr(cgc) == 4)
 	    return TRUE;
 	return FALSE;
     }
 
     /* This will cause a (harmless) warning to be printed if called on a non-bitmap context */
@@ -680,63 +683,75 @@ CreateRepeatingGradientFunction (cairo_q
 			     input_value_range,
 			     4,
 			     output_value_ranges,
 			     &callbacks);
 }
 
 /* Obtain a CGImageRef from a #cairo_surface_t * */
 
-static CGImageRef
+static cairo_status_t
 _cairo_surface_to_cgimage (cairo_surface_t *target,
-			   cairo_surface_t *source)
+			   cairo_surface_t *source,
+			   CGImageRef *image_out)
 {
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
     cairo_surface_type_t stype = cairo_surface_get_type (source);
     cairo_image_surface_t *isurf;
-    CGImageRef image, image2;
+    CGImageRef image;
     void *image_extra;
 
     if (stype == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) {
 	cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source;
-	return CGImageRetain (surface->image);
+	*image_out = CGImageRetain (surface->image);
+	return CAIRO_STATUS_SUCCESS;
     }
 
     if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
 	cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source;
+	if (IS_EMPTY(surface)) {
+	    *image_out = NULL;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+
 	if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
-	    image = CGBitmapContextCreateImage (surface->cgContext);
-	    if (image)
-		return image;
+	    *image_out = CGBitmapContextCreateImage (surface->cgContext);
+	    if (*image_out)
+		return CAIRO_STATUS_SUCCESS;
 	}
     }
 
     if (stype != CAIRO_SURFACE_TYPE_IMAGE) {
-	cairo_status_t status =
-	    _cairo_surface_acquire_source_image (source, &isurf, &image_extra);
+	status = _cairo_surface_acquire_source_image (source, &isurf, &image_extra);
 	if (status)
-	    return NULL;
+	    return status;
     } else {
 	isurf = (cairo_image_surface_t *) source;
     }
 
-    image2 = _cairo_quartz_create_cgimage (isurf->format,
-					   isurf->width,
-					   isurf->height,
-					   isurf->stride,
-					   isurf->data,
-					   TRUE,
-					   NULL, NULL, NULL);
-
-    image = CGImageCreateCopy (image2);
-    CGImageRelease (image2);
+    if (isurf->width == 0 || isurf->height == 0) {
+	*image_out = NULL;
+    } else {
+	image = _cairo_quartz_create_cgimage (isurf->format,
+					      isurf->width,
+					      isurf->height,
+					      isurf->stride,
+					      isurf->data,
+					      TRUE,
+					      NULL, NULL, NULL);
+
+	/* Create a copy to ensure that the CGImageRef doesn't depend on the image surface's backing store */
+	*image_out = CGImageCreateCopy (image);
+	CGImageRelease (image);
+    }
 
     if ((cairo_surface_t*) isurf != source)
 	_cairo_surface_release_source_image (source, isurf, image_extra);
 
-    return image;
+    return status;
 }
 
 /* Generic #cairo_pattern_t -> CGPattern function */
 
 typedef struct {
     CGImageRef image;
     CGRect imageBounds;
     cairo_bool_t do_reflect;
@@ -812,19 +827,22 @@ static cairo_int_status_t
 
     spattern = (cairo_surface_pattern_t *) apattern;
     pat_surf = spattern->surface;
 
     status = _cairo_surface_get_extents (pat_surf, &extents);
     if (status)
 	return status;
 
-    image = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf);
+    status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image);
+    if (status != CAIRO_STATUS_SUCCESS)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
     if (image == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
     info = malloc(sizeof(SurfacePatternDrawInfo));
     if (!info)
 	return CAIRO_STATUS_NO_MEMORY;
 
     /* XXX -- if we're printing, we may need to call CGImageCreateCopy to make sure
      * that the data will stick around for this image when the printer gets to it.
      * Otherwise, the underlying data store may disappear from under us!
@@ -898,16 +916,18 @@ static cairo_quartz_action_t
     CGRect clipBox = CGContextGetClipBoundingBox (surface->cgContext);
     CGAffineTransform ctm;
     double x0, y0, w, h;
 
     cairo_surface_t *fallback;
     cairo_t *fallback_cr;
     CGImageRef img;
 
+    cairo_status_t status;
+
     if (clipBox.size.width == 0.0f ||
 	clipBox.size.height == 0.0f)
 	return DO_NOTHING;
 
     // the clipBox is in userspace, so:
     ctm = CGContextGetCTM (surface->cgContext);
     ctm = CGAffineTransformInvert (ctm);
     clipBox = CGRectApplyAffineTransform (clipBox, ctm);
@@ -927,17 +947,21 @@ static cairo_quartz_action_t
 
     /* Paint the source onto our temporary */
     fallback_cr = cairo_create (fallback);
     cairo_set_operator (fallback_cr, CAIRO_OPERATOR_SOURCE);
     cairo_set_source (fallback_cr, source);
     cairo_paint (fallback_cr);
     cairo_destroy (fallback_cr);
 
-    img = _cairo_surface_to_cgimage ((cairo_surface_t*) surface, fallback);
+    status = _cairo_surface_to_cgimage ((cairo_surface_t*) surface, fallback, &img);
+    if (status == CAIRO_STATUS_SUCCESS && img == NULL)
+	return DO_NOTHING;
+    if (status)
+	return DO_UNSUPPORTED;
 
     surface->sourceImageRect = CGRectMake (0.0, 0.0, w, h);
     surface->sourceImage = img;
     surface->sourceImageSurface = fallback;
     surface->sourceTransform = CGAffineTransformMakeTranslation (x0, y0);
 
     return DO_IMAGE;
 }
@@ -1098,18 +1122,20 @@ static cairo_quartz_action_t
 	CGImageRef img;
 	cairo_matrix_t m = spat->base.matrix;
 	cairo_rectangle_int_t extents;
 	cairo_status_t status;
 	CGAffineTransform xform;
 	CGRect srcRect;
 	cairo_fixed_t fw, fh;
 
-	img = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf);
-	if (!img)
+	status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
+	if (status == CAIRO_STATUS_SUCCESS && img == NULL)
+	    return DO_NOTHING;
+	if (status)
 	    return DO_UNSUPPORTED;
 
 	surface->sourceImage = img;
 
 	cairo_matrix_invert(&m);
 	_cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceTransform);
 
 	status = _cairo_surface_get_extents (pat_surf, &extents);
@@ -1160,16 +1186,18 @@ static cairo_quartz_action_t
 
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	float patternAlpha = 1.0f;
 	CGColorSpaceRef patternSpace;
 	CGPatternRef pattern;
 	cairo_int_status_t status;
 
 	status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern);
+	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	    return DO_NOTHING;
 	if (status)
 	    return DO_UNSUPPORTED;
 
 	// Save before we change the pattern, colorspace, etc. so that
 	// we can restore and make sure that quartz releases our
 	// pattern (which may be stack allocated)
 	CGContextSaveGState(surface->cgContext);
 
@@ -1449,16 +1477,17 @@ static cairo_status_t
 				     int              src_y,
 				     int              width,
 				     int              height,
 				     cairo_surface_t **clone_out)
 {
     cairo_quartz_surface_t *new_surface = NULL;
     cairo_format_t new_format;
     CGImageRef quartz_image = NULL;
+    cairo_status_t status;
 
     *clone_out = NULL;
 
     // verify width and height of surface
     if (!_cairo_quartz_verify_surface_size(width, height)) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
@@ -1475,27 +1504,31 @@ static cairo_status_t
 	if (IS_EMPTY(qsurf)) {
 	    *clone_out = (cairo_surface_t*)
 		_cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
 						       qsurf->extents.width, qsurf->extents.height);
 	    return CAIRO_STATUS_SUCCESS;
 	}
     }
 
-    quartz_image = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src);
-    if (!quartz_image)
+    status = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src, &quartz_image);
+    if (status)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     new_format = CAIRO_FORMAT_ARGB32;  /* assumed */
     if (_cairo_surface_is_image (src)) {
 	new_format = ((cairo_image_surface_t *) src)->format;
     }
 
     new_surface = (cairo_quartz_surface_t *)
 	cairo_quartz_surface_create (new_format, width, height);
+
+    if (quartz_image == NULL)
+	goto FINISH;
+
     if (!new_surface || new_surface->base.status) {
 	CGImageRelease (quartz_image);
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
     CGContextSaveGState (new_surface->cgContext);
 
     CGContextSetCompositeOperation (new_surface->cgContext,
@@ -1504,17 +1537,18 @@ static cairo_status_t
     CGContextTranslateCTM (new_surface->cgContext, -src_x, -src_y);
     CGContextDrawImage (new_surface->cgContext,
 			CGRectMake (0, 0, CGImageGetWidth(quartz_image), CGImageGetHeight(quartz_image)),
 			quartz_image);
 
     CGContextRestoreGState (new_surface->cgContext);
 
     CGImageRelease (quartz_image);
-    
+
+FINISH:    
     *clone_out = (cairo_surface_t*) new_surface;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
 _cairo_quartz_surface_get_extents (void *abstract_surface,
 				   cairo_rectangle_int_t *extents)
@@ -2042,23 +2076,23 @@ static cairo_int_status_t
     CGAffineTransform ctm, mask_matrix;
 
     status = _cairo_surface_get_extents (pat_surf, &extents);
     if (status)
 	return status;
 
     // everything would be masked out, so do nothing
     if (extents.width == 0 || extents.height == 0)
-	goto BAIL;
-
-    img = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf);
-    if (!img) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto BAIL;
-    }
+	return CAIRO_STATUS_SUCCESS;
+
+    status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
+    if (status == CAIRO_STATUS_SUCCESS && img == NULL)
+	return CAIRO_STATUS_SUCCESS;
+    if (status)
+	return status;
 
     rect = CGRectMake (0.0f, 0.0f, extents.width, extents.height);
 
     CGContextSaveGState (surface->cgContext);
 
     /* ClipToMask is essentially drawing an image, so we need to flip the CTM
      * to get the image to appear oriented the right way */
     ctm = CGContextGetCTM (surface->cgContext);
@@ -2080,17 +2114,17 @@ static cairo_int_status_t
 	unbounded_op_data_t ub;
 	ub.op = UNBOUNDED_MASK;
 	ub.u.mask.mask = img;
 	ub.u.mask.maskTransform = CGAffineTransformInvert(mask_matrix);
 	_cairo_quartz_fixup_unbounded_operation (surface, &ub, CAIRO_ANTIALIAS_NONE);
     }
 
     CGImageRelease (img);
-  BAIL:
+
     return status;
 }
 
 /* This is somewhat less than ideal, but it gets the job done;
  * it would be better to avoid calling back into cairo.  This
  * creates a temporary surface to use as the mask.
  */
 static cairo_int_status_t