b=414685, optimize mac image decoding and rendering ; r=stuart
authorvladimir@pobox.com
Tue, 05 Feb 2008 22:48:47 -0800
changeset 11244 dc8e83b07445de3eedf611820be8637af8e9f739
parent 11243 a4d921a6d1ff85ce3e4d7387f687807dbc7b6a5f
child 11245 ff046a01d0c5ed9a77a786821436b9fe16724774
push idunknown
push userunknown
push dateunknown
reviewersstuart
bugs414685
milestone1.9b4pre
b=414685, optimize mac image decoding and rendering ; r=stuart
gfx/cairo/cairo/src/Makefile.in
gfx/cairo/cairo/src/cairo-quartz-image-surface.c
gfx/cairo/cairo/src/cairo-quartz-private.h
gfx/cairo/cairo/src/cairo-quartz-surface.c
gfx/cairo/cairo/src/cairo-quartz.h
gfx/cairo/cairo/src/cairo-rename.h
gfx/cairo/cairo/src/cairo.h
gfx/src/thebes/nsThebesImage.cpp
gfx/src/thebes/nsThebesImage.h
gfx/thebes/public/Makefile.in
gfx/thebes/public/gfxASurface.h
gfx/thebes/public/gfxImageSurface.h
gfx/thebes/public/gfxPlatformMac.h
gfx/thebes/public/gfxQuartzImageSurface.h
gfx/thebes/public/gfxQuartzSurface.h
gfx/thebes/src/Makefile.in
gfx/thebes/src/gfxASurface.cpp
gfx/thebes/src/gfxImageSurface.cpp
gfx/thebes/src/gfxPlatformMac.cpp
gfx/thebes/src/gfxQuartzImageSurface.cpp
gfx/thebes/src/gfxQuartzSurface.cpp
--- a/gfx/cairo/cairo/src/Makefile.in
+++ b/gfx/cairo/cairo/src/Makefile.in
@@ -158,17 +158,17 @@ DEFINES += -DOS2_HIGH_MEMORY
 endif
 CSRCS   += cairo-os2-surface.c
 EXPORTS += cairo-os2.h cairo-os2-private.h
 CSRCS   += $(PSPDF_BASE_CSRCS) $(PDF_CSRCS)
 EXPORTS += $(PDF_EXPORTS)
 endif
 
 ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
-CSRCS   += cairo-quartz-surface.c cairo-atsui-font.c
+CSRCS   += cairo-quartz-surface.c cairo-quartz-image-surface.c cairo-atsui-font.c
 EXPORTS += cairo-quartz.h cairo-atsui.h
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),beos)
 CPPSRCS += cairo-beos-surface.cpp
 EXPORTS += cairo-beos.h
 endif
 
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/cairo/src/cairo-quartz-image-surface.c
@@ -0,0 +1,340 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright � 2008 Mozilla Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ *
+ * Contributor(s):
+ *	Vladimir Vukicevic <vladimir@mozilla.com>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-quartz-private.h"
+
+#define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)))
+#define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT)))
+
+CGImageRef
+_cairo_quartz_create_cgimage (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;
+    int bitsPerComponent, bitsPerPixel;
+
+    switch (format) {
+	case CAIRO_FORMAT_ARGB32:
+	    if (colorSpace == NULL)
+		colorSpace = CGColorSpaceCreateDeviceRGB();
+	    bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+	    bitsPerComponent = 8;
+	    bitsPerPixel = 32;
+	    break;
+
+	case CAIRO_FORMAT_RGB24:
+	    if (colorSpace == NULL)
+		colorSpace = CGColorSpaceCreateDeviceRGB();
+	    bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+	    bitsPerComponent = 8;
+	    bitsPerPixel = 32;
+	    break;
+
+	case CAIRO_FORMAT_A8:
+	    if (colorSpace == NULL)
+		colorSpace = CGColorSpaceCreateDeviceGray();
+	    bitinfo = kCGImageAlphaNone;
+	    bitsPerComponent = 8;
+	    bitsPerPixel = 8;
+	    break;
+
+	default:
+	    return NULL;
+    }
+
+    dataProvider = CGDataProviderCreateWithData (releaseInfo,
+						 data,
+						 height * stride,
+						 releaseCallback);
+
+    if (!dataProvider) {
+	// manually release
+	if (releaseCallback)
+	    releaseCallback (releaseInfo, data, height * stride);
+	goto FINISH;
+    }
+
+    image = CGImageCreate (width, height,
+			   bitsPerComponent,
+			   bitsPerPixel,
+			   stride,
+			   colorSpace,
+			   bitinfo,
+			   dataProvider,
+			   NULL,
+			   interpolate,
+			   kCGRenderingIntentDefault);
+
+FINISH:
+
+    CGDataProviderRelease (dataProvider);
+
+    if (colorSpace != colorSpaceOverride)
+	CGColorSpaceRelease (colorSpace);
+
+    return image;
+}
+
+
+static cairo_surface_t *
+_cairo_quartz_image_surface_create_similar (void *asurface,
+					    cairo_content_t content,
+					    int width,
+					    int height)
+{
+    cairo_surface_t *result;
+    cairo_surface_t *isurf = cairo_image_surface_create (_cairo_format_from_content (content),
+							 width,
+							 height);
+    if (cairo_surface_status(isurf))
+	return isurf;
+
+    result = cairo_quartz_image_surface_create (isurf);
+    cairo_surface_destroy (isurf);
+
+    return result;
+}
+
+static cairo_status_t
+_cairo_quartz_image_surface_finish (void *asurface)
+{
+    cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+
+    /* the imageSurface will be destroyed by the data provider's release callback */
+    CGImageRelease (surface->image);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_quartz_image_surface_acquire_source_image (void *asurface,
+						  cairo_image_surface_t **image_out,
+						  void **image_extra)
+{
+    cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+
+    *image_out = surface->imageSurface;
+    *image_extra = NULL;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_quartz_image_surface_acquire_dest_image (void *asurface,
+						cairo_rectangle_int_t *interest_rect,
+						cairo_image_surface_t **image_out,
+						cairo_rectangle_int_t *image_rect,
+						void **image_extra)
+{
+    cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+
+    *image_out = surface->imageSurface;
+    *image_rect = surface->extents;
+    *image_extra = NULL;
+
+    return CAIRO_STATUS_SUCCESS;
+   
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_get_extents (void *asurface,
+					 cairo_rectangle_int_t *extents)
+{
+    cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+
+    *extents = surface->extents;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
+    CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
+    _cairo_quartz_image_surface_create_similar,
+    _cairo_quartz_image_surface_finish,
+    _cairo_quartz_image_surface_acquire_source_image,
+    NULL, /* release_source_image */
+    _cairo_quartz_image_surface_acquire_dest_image,
+    NULL, /* release_dest_image */
+    NULL, /* clone_similar */
+    NULL, /* composite */
+    NULL, /* fill_rectangles */
+    NULL, /* composite_trapezoids */
+    NULL, /* copy_page */
+    NULL, /* show_page */
+    NULL, /* set_clip_region */
+    NULL, /* intersect_clip_path */
+    _cairo_quartz_image_surface_get_extents,
+    NULL, /* old_show_glyphs */
+    NULL, /* get_font_options */
+    NULL, /* flush */
+    NULL, /* mark_dirty_rectangle */
+    NULL, /* scaled_font_fini */
+    NULL, /* scaled_glyph_fini */
+
+    NULL, /* paint */
+    NULL, /* mask */
+    NULL, /* stroke */
+    NULL, /* fill */
+    NULL, /* surface_show_glyphs */
+    NULL, /* snapshot */
+    NULL, /* is_similar */
+    NULL, /* reset */
+    NULL  /* fill_stroke */
+
+};
+
+static void
+DataProviderReleaseCallback (void *info, const void *data, size_t size)
+{
+    cairo_surface_t *surface = (cairo_surface_t *) info;
+    cairo_surface_destroy (surface);
+}
+
+/**
+ * cairo_quartz_image_surface_create
+ * @surface: a cairo image surface to wrap with a quartz image surface
+ *
+ * Creates a Quartz surface backed by a CGImageRef that references
+ * the given image surface.
+ *
+ * Data is to be loaded into this surface by calling
+ * cairo_quartz_image_surface_get_image, and performing operations on the
+ * resulting image surface.
+ *
+ * The resulting surface can be rendered quickly when used as a source
+ * when rendering to a cairo_quartz_surface.
+ *
+ * Return value: the newly created surface.
+ *
+ * Since: 1.6
+ */
+cairo_surface_t *
+cairo_quartz_image_surface_create (cairo_surface_t *surface)
+{
+    cairo_quartz_image_surface_t *qisurf;
+
+    CGImageRef image;
+
+    CGContextRef cgContext;
+    CGColorSpaceRef cgColorspace;
+    CGBitmapInfo bitinfo;
+
+    cairo_image_surface_t *image_surface;
+    int width, height, stride;
+    cairo_format_t format;
+    unsigned char *data;
+
+    if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE)
+	return SURFACE_ERROR_NO_MEMORY;
+
+    image_surface = (cairo_image_surface_t*) surface;
+    width = image_surface->width;
+    height = image_surface->height;
+    stride = image_surface->stride;
+    format = image_surface->format;
+    data = image_surface->data;
+
+    if (!_cairo_quartz_verify_surface_size(width, height))
+	return SURFACE_ERROR_NO_MEMORY;
+
+    if (width == 0 || height == 0)
+	return SURFACE_ERROR_NO_MEMORY;
+
+    if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24)
+	return SURFACE_ERROR_INVALID_FORMAT;
+
+    qisurf = malloc(sizeof(cairo_quartz_image_surface_t));
+    if (qisurf == NULL)
+	return SURFACE_ERROR_NO_MEMORY;
+
+    memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));
+
+    // ref this here; in case the create_cgimage fails, it will
+    // be released by the callback.
+    cairo_surface_reference (surface);
+
+    image = _cairo_quartz_create_cgimage (format,
+					  width, height,
+					  stride,
+					  data,
+					  FALSE,
+					  NULL,
+					  DataProviderReleaseCallback,
+					  surface);
+
+    if (!image) {
+	free (qisurf);
+	return SURFACE_ERROR_NO_MEMORY;
+    }
+
+    _cairo_surface_init (&qisurf->base,
+			 &cairo_quartz_image_surface_backend,
+			 _cairo_content_from_format (format));
+
+    qisurf->extents.x = qisurf->extents.y = 0;
+    qisurf->extents.width = width;
+    qisurf->extents.height = height;
+
+    qisurf->image = image;
+    qisurf->imageSurface = image_surface;
+
+    return &qisurf->base;
+}
+
+
+cairo_surface_t *
+cairo_quartz_image_surface_get_image (cairo_surface_t *asurface)
+{
+    cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface;
+
+    if (cairo_surface_get_type(asurface) != CAIRO_SURFACE_TYPE_QUARTZ_IMAGE)
+	return NULL;
+
+    return (cairo_surface_t*) surface->imageSurface;
+}
+
--- a/gfx/cairo/cairo/src/cairo-quartz-private.h
+++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
@@ -41,36 +41,59 @@
 #include "cairoint.h"
 
 #ifdef CAIRO_HAS_QUARTZ_SURFACE
 #include <cairo-quartz.h>
 
 typedef struct cairo_quartz_surface {
     cairo_surface_t base;
 
-    void *imageData;
-
-    cairo_surface_t *imageSurfaceEquiv;
-
     CGContextRef cgContext;
     CGAffineTransform cgContextBaseCTM;
 
+    void *imageData;
+    cairo_surface_t *imageSurfaceEquiv;
+
     cairo_rectangle_int_t extents;
 
     /* These are stored while drawing operations are in place, set up
      * by quartz_setup_source() and quartz_finish_source()
      */
     CGImageRef sourceImage;
     cairo_surface_t *sourceImageSurface;
     CGAffineTransform sourceImageTransform;
     CGRect sourceImageRect;
 
     CGShadingRef sourceShading;
     CGPatternRef sourcePattern;
 } cairo_quartz_surface_t;
+
+typedef struct cairo_quartz_image_surface {
+    cairo_surface_t base;
+
+    cairo_rectangle_int_t extents;
+
+    CGImageRef image;
+    cairo_image_surface_t *imageSurface;
+} cairo_quartz_image_surface_t;
+
+cairo_bool_t
+_cairo_quartz_verify_surface_size(int width, int height);
+
+CGImageRef
+_cairo_quartz_create_cgimage (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);
+
 #endif /* CAIRO_HAS_QUARTZ_SURFACE */
 
 #if CAIRO_HAS_ATSUI_FONT
 ATSUStyle
 _cairo_atsui_scaled_font_get_atsu_style (cairo_scaled_font_t *sfont);
 
 ATSUFontID
 _cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont);
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
@@ -135,17 +135,18 @@ static void quartz_ensure_symbols(void)
 }
 
 /* CoreGraphics limitation with flipped CTM surfaces: height must be less than signed 16-bit max */
 
 #define CG_MAX_HEIGHT   SHRT_MAX
 #define CG_MAX_WIDTH    USHRT_MAX
 
 /* is the desired size of the surface within bounds? */
-static cairo_bool_t verify_surface_size(int width, int height)
+cairo_bool_t
+_cairo_quartz_verify_surface_size(int width, int height)
 {
     /* hmmm, allow width, height == 0 ? */
     if (width < 0 || height < 0) {
 	return FALSE;
     }
 
     if (width > CG_MAX_WIDTH || height > CG_MAX_HEIGHT) {
 	return FALSE;
@@ -388,124 +389,103 @@ CreateGradientFunction (cairo_gradient_p
     return CGFunctionCreate (gpat,
 			     1,
 			     input_value_range,
 			     4,
 			     output_value_ranges,
 			     &callbacks);
 }
 
-/* generic cairo surface -> cairo_quartz_surface_t function */
-static cairo_int_status_t
-_cairo_quartz_surface_to_quartz (cairo_surface_t *target,
-				 cairo_surface_t *pat_surf,
-				 cairo_quartz_surface_t **quartz_surf)
-{
-
-    if (cairo_surface_get_type(pat_surf) != CAIRO_SURFACE_TYPE_QUARTZ) {
-	/* XXXtodo/perf don't use clone if the source surface is an image surface!  Instead,
-	 * just create the CGImage directly!
-	 */
+/* Obtain a CGImageRef from a cairo_surface_t * */
 
-	cairo_surface_t *ref_type = target;
-	cairo_surface_t *new_surf = NULL;
-	cairo_rectangle_int_t rect;
-	cairo_status_t status;
-
-	if (ref_type == NULL)
-	    ref_type = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
-
-	status = _cairo_surface_get_extents (pat_surf, &rect);
-	if (status)
-	    return status;
+static CGImageRef
+_cairo_surface_to_cgimage (cairo_surface_t *target,
+			   cairo_surface_t *source)
+{
+    cairo_surface_type_t stype = cairo_surface_get_type (source);
+    cairo_image_surface_t *isurf;
+    CGImageRef image, image2;
+    void *image_extra;
 
-	status = _cairo_surface_clone_similar (ref_type, pat_surf, rect.x, rect.y,
-				      rect.width, rect.height, &new_surf);
-	if (target == NULL)
-	    cairo_surface_destroy(ref_type);
-
-        if (status)
-	    return status;
+    if (stype == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) {
+	cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source;
+	return CGImageRetain (surface->image);
+    }
 
- 	if (new_surf &&
-	    cairo_surface_get_type (new_surf) != CAIRO_SURFACE_TYPE_QUARTZ)
-	{
-	    ND((stderr, "got a non-quartz surface, format=%d width=%u height=%u type=%d\n", cairo_surface_get_type (pat_surf), rect.width, rect.height, cairo_surface_get_type (new_surf)));
-	    cairo_surface_destroy (new_surf);
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-	}
-
-	*quartz_surf = (cairo_quartz_surface_t *) new_surf;
-    } else {
-	/* If it's a quartz surface, we can try to see if it's a CGBitmapContext;
-	 * we do this when we call CGBitmapContextCreateImage below.
-	 */
-	cairo_surface_reference (pat_surf);
-	*quartz_surf = (cairo_quartz_surface_t*) pat_surf;
+    if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
+	cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source;
+	image = CGBitmapContextCreateImage (surface->cgContext);
+	if (image)
+	    return image;
     }
 
-    return CAIRO_STATUS_SUCCESS;
+    if (stype != CAIRO_SURFACE_TYPE_IMAGE) {
+	cairo_status_t status =
+	    _cairo_surface_acquire_source_image (source, &isurf, &image_extra);
+	if (status)
+	    return NULL;
+    } else {
+	isurf = (cairo_image_surface_t *) source;
+    }
+
+    image2 = _cairo_quartz_create_cgimage (isurf->format,
+					   isurf->width,
+					   isurf->height,
+					   isurf->stride,
+					   isurf->data,
+					   FALSE,
+					   NULL, NULL, NULL);
+
+    image = CGImageCreateCopy (image2);
+    CGImageRelease (image2);
+
+    if ((cairo_surface_t*) isurf != source)
+	_cairo_surface_release_source_image (source, isurf, image_extra);
+
+    return image;
 }
 
 /* Generic cairo_pattern -> CGPattern function */
-static void
-SurfacePatternDrawFunc (void *info, CGContextRef context)
-{
-    cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info;
-    cairo_surface_t *pat_surf = spat->surface;
-    cairo_int_status_t status;
 
-    cairo_quartz_surface_t *quartz_surf;
-    CGImageRef img;
+typedef struct {
+    CGImageRef image;
     CGRect imageBounds;
+    cairo_bool_t do_reflect;
+} SurfacePatternDrawInfo;
 
-    status = _cairo_quartz_surface_to_quartz (NULL, pat_surf, &quartz_surf);
-    if (status)
-	return;
+static void
+SurfacePatternDrawFunc (void *ainfo, CGContextRef context)
+{
+    SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo;
 
-    img = CGBitmapContextCreateImage (quartz_surf->cgContext);
-    if (!img) {
-	// ... give up.
-	ND((stderr, "CGBitmapContextCreateImage failed\n"));
-	_cairo_error (CAIRO_STATUS_NO_MEMORY);
-	cairo_surface_destroy ((cairo_surface_t*)quartz_surf);
-	return;
-    }
+    CGContextTranslateCTM (context, 0, info->imageBounds.size.height);
+    CGContextScaleCTM (context, 1, -1);
 
-    /* XXXtodo WHY does this need to be flipped?  Writing this stuff
-     * to disk shows that in both this path and the path above the source image
-     * has an identical orientation, and the destination context at all times has a Y
-     * flip.  So why do we need to flip in this case?
-     */
-    if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) {
-	CGContextTranslateCTM (context, 0, CGImageGetHeight(img));
+    CGContextDrawImage (context, info->imageBounds, info->image);
+    if (info->do_reflect) {
+	/* draw 3 more copies of the image, flipped. */
+	CGContextTranslateCTM (context, 0, 2 * info->imageBounds.size.height);
 	CGContextScaleCTM (context, 1, -1);
+	CGContextDrawImage (context, info->imageBounds, info->image);
+	CGContextTranslateCTM (context, 2 * info->imageBounds.size.width, 0);
+	CGContextScaleCTM (context, -1, 1);
+	CGContextDrawImage (context, info->imageBounds, info->image);
+	CGContextTranslateCTM (context, 0, 2 * info->imageBounds.size.height);
+	CGContextScaleCTM (context, 1, -1);
+	CGContextDrawImage (context, info->imageBounds, info->image);
     }
-
-    imageBounds.size = CGSizeMake (CGImageGetWidth(img), CGImageGetHeight(img));
-    imageBounds.origin.x = 0;
-    imageBounds.origin.y = 0;
+}
 
-    CGContextDrawImage (context, imageBounds, img);
-    if (spat->base.extend == CAIRO_EXTEND_REFLECT) {
-	/* draw 3 more copies of the image, flipped. */
-	CGContextTranslateCTM (context, 0, 2 * imageBounds.size.height);
-	CGContextScaleCTM (context, 1, -1);
-	CGContextDrawImage (context, imageBounds, img);
-	CGContextTranslateCTM (context, 2 * imageBounds.size.width, 0);
-	CGContextScaleCTM (context, -1, 1);
-	CGContextDrawImage (context, imageBounds, img);
-	CGContextTranslateCTM (context, 0, 2 * imageBounds.size.height);
-	CGContextScaleCTM (context, 1, -1);
-	CGContextDrawImage (context, imageBounds, img);
-    }
+static void
+SurfacePatternReleaseInfoFunc (void *ainfo)
+{
+    SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo;
 
-    CGImageRelease (img);
-
-    cairo_surface_destroy ((cairo_surface_t*) quartz_surf);
+    CGImageRelease (info->image);
+    free (info);
 }
 
 /* Borrowed from cairo-meta-surface */
 static cairo_status_t
 _init_pattern_with_snapshot (cairo_pattern_t *pattern,
 			     const cairo_pattern_t *other)
 {
     cairo_status_t status;
@@ -527,68 +507,82 @@ static cairo_status_t
 	    return surface_pattern->surface->status;
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
 _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest,
-							 cairo_pattern_t *abspat,
+							 cairo_pattern_t *apattern,
 							 CGPatternRef *cgpat)
 {
-    cairo_surface_pattern_t *spat;
+    cairo_surface_pattern_t *spattern;
     cairo_surface_t *pat_surf;
     cairo_rectangle_int_t extents;
 
+    CGImageRef image;
     CGRect pbounds;
     CGAffineTransform ptransform, stransform;
     CGPatternCallbacks cb = { 0,
 			      SurfacePatternDrawFunc,
-			      (CGFunctionReleaseInfoCallback) cairo_pattern_destroy };
+			      SurfacePatternReleaseInfoFunc };
+    SurfacePatternDrawInfo *info;
     float rw, rh;
     cairo_status_t status;
 
-    cairo_pattern_union_t *snap_pattern = NULL;
-    cairo_pattern_t *target_pattern = abspat;
+    cairo_matrix_t m;
 
-    cairo_matrix_t m;
     /* SURFACE is the only type we'll handle here */
-    if (abspat->type != CAIRO_PATTERN_TYPE_SURFACE)
+    if (apattern->type != CAIRO_PATTERN_TYPE_SURFACE)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    spat = (cairo_surface_pattern_t *) abspat;
-    pat_surf = spat->surface;
+    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);
+    if (image == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    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!
+     *
+     * _cairo_surface_to_cgimage will copy when it converts non-Quartz surfaces,
+     * since the Quartz surfaces have a higher chance of sticking around.  If the
+     * source is a quartz image surface, then it's set up to retain a ref to the
+     * image surface that it's backed by.
+     */
+    info->image = image;
+
+    info->imageBounds = CGRectMake (0, 0, extents.width, extents.height);
+    info->do_reflect = (spattern->base.extend == CAIRO_EXTEND_REFLECT);
+
     pbounds.origin.x = 0;
     pbounds.origin.y = 0;
 
-    // kjs seems to indicate this should work (setting to 0,0 to avoid
-    // tiling); however, the pattern CTM scaling ends up being NaN in
-    // the pattern draw function if either rw or rh are 0.
-    // XXXtodo get pattern drawing working with extend options
-    // XXXtodo/perf optimize CAIRO_EXTEND_NONE to a single DrawImage instead of a pattern
-    if (spat->base.extend == CAIRO_EXTEND_REFLECT) {
-	/* XXX broken; need to emulate by reflecting the image into 4 quadrants
-	 * and then tiling that
-	 */
+    if (spattern->base.extend == CAIRO_EXTEND_REFLECT) {
 	pbounds.size.width = 2 * extents.width;
 	pbounds.size.height = 2 * extents.height;
     } else {
 	pbounds.size.width = extents.width;
 	pbounds.size.height = extents.height;
     }
     rw = pbounds.size.width;
     rh = pbounds.size.height;
 
-    m = spat->base.matrix;
+    m = spattern->base.matrix;
     cairo_matrix_invert(&m);
     _cairo_quartz_cairo_matrix_to_quartz (&m, &stransform);
 
     /* The pattern matrix is relative to the bottom left, again; the
      * incoming cairo pattern matrix is relative to the upper left.
      * So we take the pattern matrix and the original context matrix,
      * which gives us the correct base translation/y flip.
      */
@@ -596,35 +590,24 @@ static cairo_int_status_t
 
 #ifdef QUARTZ_DEBUG
     ND((stderr, "  pbounds: %f %f %f %f\n", pbounds.origin.x, pbounds.origin.y, pbounds.size.width, pbounds.size.height));
     ND((stderr, "  pattern xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", ptransform.tx, ptransform.ty, ptransform.a, ptransform.b, ptransform.c, ptransform.d));
     CGAffineTransform xform = CGContextGetCTM(dest->cgContext);
     ND((stderr, "  context xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", xform.tx, xform.ty, xform.a, xform.b, xform.c, xform.d));
 #endif
 
+    *cgpat = CGPatternCreate (info,
+			      pbounds,
+			      ptransform,
+			      rw, rh,
+			      kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */
+			      TRUE,
+			      &cb);
 
-    /* XXX fixme: only do snapshots if the context is for printing, or get rid of the
-       other block if it doesn't fafect performance */
-    if (1 /* context is for printing */) {
-	snap_pattern = (cairo_pattern_union_t*) malloc(sizeof(cairo_pattern_union_t));
-	target_pattern = (cairo_pattern_t*) snap_pattern;
-	_init_pattern_with_snapshot (target_pattern, abspat);
-    } else {
-	cairo_pattern_reference (abspat);
-	target_pattern = abspat;
-    }
-
-    *cgpat = CGPatternCreate (target_pattern,
-			     pbounds,
-			     ptransform,
-			     rw, rh,
-			     kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */
-			     TRUE,
-			     &cb);
     return CAIRO_STATUS_SUCCESS;
 }
 
 typedef enum {
     DO_SOLID,
     DO_SHADING,
     DO_PATTERN,
     DO_IMAGE,
@@ -780,35 +763,25 @@ static cairo_quartz_action_t
 
     }
 
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
 	(source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
     {
 	cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source;
 	cairo_surface_t *pat_surf = spat->surface;
-	cairo_quartz_surface_t *quartz_surf;
 	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;
 
-	status = _cairo_quartz_surface_to_quartz ((cairo_surface_t *) surface, pat_surf, &quartz_surf);
-	if (status)
-	    return DO_UNSUPPORTED;
-
-	surface->sourceImageSurface = (cairo_surface_t *)quartz_surf;
-
-	if (IS_EMPTY(quartz_surf))
-	    return DO_NOTHING;
-
-	img = CGBitmapContextCreateImage (quartz_surf->cgContext);
+	img = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf);
 	if (!img)
 	    return DO_UNSUPPORTED;
 
 	surface->sourceImage = img;
 
 	cairo_matrix_invert(&m);
 	_cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceImageTransform);
 
@@ -1127,131 +1100,92 @@ static cairo_surface_t *
     else if (content == CAIRO_CONTENT_COLOR)
 	format = CAIRO_FORMAT_RGB24;
     else if (content == CAIRO_CONTENT_ALPHA)
 	format = CAIRO_FORMAT_A8;
     else
 	return NULL;
 
     // verify width and height of surface
-    if (!verify_surface_size(width, height)) {
+    if (!_cairo_quartz_verify_surface_size(width, height)) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return NULL;
     }
 
     return cairo_quartz_surface_create (format, width, height);
 }
 
 static cairo_status_t
 _cairo_quartz_surface_clone_similar (void *abstract_surface,
-				      cairo_surface_t *src,
-				      int              src_x,
-				      int              src_y,
-				      int              width,
-				      int              height,
-				      cairo_surface_t **clone_out)
+				     cairo_surface_t *src,
+				     int              src_x,
+				     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;
 
     *clone_out = NULL;
 
     // verify width and height of surface
-    if (!verify_surface_size(width, height)) {
+    if (!_cairo_quartz_verify_surface_size(width, height)) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    if (cairo_surface_get_type(src) == CAIRO_SURFACE_TYPE_QUARTZ) {
+    if (width == 0 || height == 0) {
+	*clone_out = (cairo_surface_t*)
+	    _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
+						   width, height);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    if (src->backend->type == CAIRO_SURFACE_TYPE_QUARTZ) {
 	cairo_quartz_surface_t *qsurf = (cairo_quartz_surface_t *) src;
 
 	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 = CGBitmapContextCreateImage (qsurf->cgContext);
-	new_format = CAIRO_FORMAT_ARGB32;  /* XXX bogus; recover a real format from the image */
-    } else if (_cairo_surface_is_image (src)) {
-	cairo_image_surface_t *isurf = (cairo_image_surface_t *) src;
-	CGDataProviderRef dataProvider;
-	CGColorSpaceRef cgColorspace;
-	CGBitmapInfo bitinfo;
-	int bitsPerComponent, bitsPerPixel;
-
-	if (isurf->width == 0 || isurf->height == 0) {
-	    *clone_out = (cairo_surface_t*) _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, isurf->width, isurf->height);
+	    *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;
 	}
-
-	if (isurf->format == CAIRO_FORMAT_ARGB32) {
-	    cgColorspace = CGColorSpaceCreateDeviceRGB();
-	    bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
-	    bitsPerComponent = 8;
-	    bitsPerPixel = 32;
-	} else if (isurf->format == CAIRO_FORMAT_RGB24) {
-	    cgColorspace = CGColorSpaceCreateDeviceRGB();
-	    bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
-	    bitsPerComponent = 8;
-	    bitsPerPixel = 32;
-	} else if (isurf->format == CAIRO_FORMAT_A8) {
-	    cgColorspace = CGColorSpaceCreateDeviceGray();
-	    bitinfo = kCGImageAlphaNone;
-	    bitsPerComponent = 8;
-	    bitsPerPixel = 8;
-	} else {
-	    /* SUPPORT A1, maybe */
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-	}
-
-	new_format = isurf->format;
-
-	dataProvider = CGDataProviderCreateWithData (NULL,
-						     isurf->data,
-						     isurf->height * isurf->stride,
-						     NULL);
-
-	quartz_image = CGImageCreate (isurf->width, isurf->height,
-				      bitsPerComponent,
-				      bitsPerPixel,
-				      isurf->stride,
-				      cgColorspace,
-				      bitinfo,
-				      dataProvider,
-				      NULL,
-				      false,
-				      kCGRenderingIntentDefault);
-	CGDataProviderRelease (dataProvider);
-	CGColorSpaceRelease (cgColorspace);
-    } else {
-	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
+    quartz_image = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src);
     if (!quartz_image)
 	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,
-				     CGImageGetWidth (quartz_image),
-				     CGImageGetHeight (quartz_image));
+	cairo_quartz_surface_create (new_format, width, height);
     if (!new_surface || new_surface->base.status) {
 	CGImageRelease (quartz_image);
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
+    CGContextSaveGState (new_surface->cgContext);
+
     CGContextSetCompositeOperation (new_surface->cgContext,
 				    kPrivateCGCompositeCopy);
 
-    quartz_image_to_png (quartz_image, NULL);
-
+    CGContextTranslateCTM (new_surface->cgContext, -src_x, -src_y);
     CGContextDrawImage (new_surface->cgContext,
-			CGRectMake (src_x, src_y, width, height),
+			CGRectMake (0, 0, CGImageGetWidth(quartz_image), CGImageGetHeight(quartz_image)),
 			quartz_image);
+
+    CGContextRestoreGState (new_surface->cgContext);
+
     CGImageRelease (quartz_image);
-
+    
     *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)
@@ -1260,18 +1194,18 @@ static cairo_int_status_t
 
     *extents = surface->extents;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
 _cairo_quartz_surface_paint (void *abstract_surface,
-			      cairo_operator_t op,
-			      cairo_pattern_t *source)
+			     cairo_operator_t op,
+			     cairo_pattern_t *source)
 {
     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
     cairo_quartz_action_t action;
 
     ND((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
 
     if (IS_EMPTY(surface))
@@ -1287,27 +1221,21 @@ static cairo_int_status_t
     if (action == DO_SOLID || action == DO_PATTERN) {
 	CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
 							  surface->extents.y,
 							  surface->extents.width,
 							  surface->extents.height));
     } else if (action == DO_SHADING) {
 	CGContextDrawShading (surface->cgContext, surface->sourceShading);
     } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
-	cairo_surface_pattern_t *surface_pattern =
-	    (cairo_surface_pattern_t *) source;
-	cairo_surface_t *pat_surf = surface_pattern->surface;
-
 	CGContextSaveGState (surface->cgContext);
 
 	CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform);
-	if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) {
-	    CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage));
-	    CGContextScaleCTM (surface->cgContext, 1, -1);
-	}
+	CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+	CGContextScaleCTM (surface->cgContext, 1, -1);
 
 	if (action == DO_IMAGE)
 	    CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
 	else
 	    CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
 	CGContextRestoreGState (surface->cgContext);
     } else if (action != DO_NOTHING) {
 	rv = CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1367,29 +1295,24 @@ static cairo_int_status_t
 	// with the shading
 	if (fill_rule == CAIRO_FILL_RULE_WINDING)
 	    CGContextClip (surface->cgContext);
 	else
 	    CGContextEOClip (surface->cgContext);
 
 	CGContextDrawShading (surface->cgContext, surface->sourceShading);
     } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
-	cairo_surface_pattern_t *surface_pattern =
-	    (cairo_surface_pattern_t *) source;
-	cairo_surface_t *pat_surf = surface_pattern->surface;
 	if (fill_rule == CAIRO_FILL_RULE_WINDING)
 	    CGContextClip (surface->cgContext);
 	else
 	    CGContextEOClip (surface->cgContext);
 
 	CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform);
-	if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) {
-	    CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage));
-	    CGContextScaleCTM (surface->cgContext, 1, -1);
-	}
+	CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+	CGContextScaleCTM (surface->cgContext, 1, -1);
 
 	if (action == DO_IMAGE)
 	    CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
 	else
 	    CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
     } else if (action != DO_NOTHING) {
 	rv = CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -1476,20 +1399,18 @@ static cairo_int_status_t
 
     if (action == DO_SOLID || action == DO_PATTERN) {
 	CGContextStrokePath (surface->cgContext);
     } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
 	CGContextReplacePathWithStrokedPath (surface->cgContext);
 	CGContextClip (surface->cgContext);
 
 	CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform);
-	if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) {
-	    CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage));
-	    CGContextScaleCTM (surface->cgContext, 1, -1);
-	}
+	CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+	CGContextScaleCTM (surface->cgContext, 1, -1);
 
 	if (action == DO_IMAGE)
 	    CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
 	else
 	    CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
     } else if (action == DO_SHADING) {
 	CGContextReplacePathWithStrokedPath (surface->cgContext);
 	CGContextClip (surface->cgContext);
@@ -1628,20 +1549,18 @@ static cairo_int_status_t
 
     CGContextShowGlyphsWithAdvances (surface->cgContext,
 				     cg_glyphs,
 				     cg_advances,
 				     num_glyphs);
 
     if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
 	CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform);
-	if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) {
-	    CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage));
-	    CGContextScaleCTM (surface->cgContext, 1, -1);
-	}
+	CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+	CGContextScaleCTM (surface->cgContext, 1, -1);
 
 	if (action == DO_IMAGE)
 	    CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
 	else
 	    CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
     } else if (action == DO_SHADING) {
 	CGContextDrawShading (surface->cgContext, surface->sourceShading);
     }
@@ -1665,49 +1584,43 @@ BAIL:
 
 static cairo_int_status_t
 _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
                                          cairo_operator_t op,
                                          cairo_pattern_t *source,
                                          cairo_surface_pattern_t *mask)
 {
     cairo_rectangle_int_t extents;
-    cairo_quartz_surface_t *quartz_surf;
     CGRect rect;
     CGImageRef img;
     cairo_surface_t *pat_surf = mask->surface;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
     status = _cairo_surface_get_extents (pat_surf, &extents);
     if (status)
 	return status;
 
-    status = _cairo_quartz_surface_to_quartz (NULL, pat_surf, &quartz_surf);
-    if (status)
-	return status;
-
     // everything would be masked out, so do nothing
-    if (IS_EMPTY(quartz_surf))
+    if (extents.width == 0 || extents.height == 0)
 	goto BAIL;
 
-    img = CGBitmapContextCreateImage (quartz_surf->cgContext);
+    img = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf);
     if (!img) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto BAIL;
     }
 
     rect = CGRectMake (-mask->base.matrix.x0, -mask->base.matrix.y0, extents.width, extents.height);
     CGContextSaveGState (surface->cgContext);
     CGContextClipToMaskPtr (surface->cgContext, rect, img);
     status = _cairo_quartz_surface_paint (surface, op, source);
 
     CGContextRestoreGState (surface->cgContext);
     CGImageRelease (img);
   BAIL:
-    cairo_surface_destroy ((cairo_surface_t*) quartz_surf);
     return status;
 }
 
 static cairo_int_status_t
 _cairo_quartz_surface_mask (void *abstract_surface,
 			     cairo_operator_t op,
 			     cairo_pattern_t *source,
 			     cairo_pattern_t *mask)
@@ -1960,17 +1873,17 @@ cairo_quartz_surface_create (cairo_forma
     CGContextRef cgc;
     CGColorSpaceRef cgColorspace;
     CGBitmapInfo bitinfo;
     void *imageData;
     int stride;
     int bitsPerComponent;
 
     // verify width and height of surface
-    if (!verify_surface_size(width, height))
+    if (!_cairo_quartz_verify_surface_size(width, height))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
     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) {
@@ -2001,16 +1914,17 @@ cairo_quartz_surface_create (cairo_forma
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
     }
 
     imageData = _cairo_malloc_ab (height, stride);
     if (!imageData) {
 	CGColorSpaceRelease (cgColorspace);
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     }
+
     /* zero the memory to match the image surface behaviour */
     memset (imageData, 0, height * stride);
 
     cgc = CGBitmapContextCreate (imageData,
 				 width,
 				 height,
 				 bitsPerComponent,
 				 stride,
@@ -2159,20 +2073,8 @@ quartz_surface_to_png (cairo_quartz_surf
 	return;
     }
 
     ExportCGImageToPNGFile(imgref, dest);
 
     CGImageRelease(imgref);
 #endif
 }
-
-cairo_surface_t *
-cairo_quartz_surface_get_image (cairo_surface_t *surface)
-{
-    cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface;
-
-    if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ)
-	return NULL;
-
-    return quartz->imageSurfaceEquiv;
-}
-
--- a/gfx/cairo/cairo/src/cairo-quartz.h
+++ b/gfx/cairo/cairo/src/cairo-quartz.h
@@ -53,17 +53,20 @@ cairo_public cairo_surface_t *
 cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
                                             unsigned int width,
                                             unsigned int height);
 
 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);
+cairo_quartz_image_surface_create (cairo_surface_t *image_surface);
+
+cairo_public cairo_surface_t *
+cairo_quartz_image_surface_get_image (cairo_surface_t *surface);
 
 CAIRO_END_DECLS
 
 #else  /* CAIRO_HAS_QUARTZ_SURFACE */
 # error Cairo was not compiled with support for the quartz backend
 #endif /* CAIRO_HAS_QUARTZ_SURFACE */
 
 #endif /* CAIRO_QUARTZ_H */
--- a/gfx/cairo/cairo/src/cairo-rename.h
+++ b/gfx/cairo/cairo/src/cairo-rename.h
@@ -164,17 +164,18 @@
 #define cairo_ps_surface_restrict_to_level _moz_cairo_ps_surface_restrict_to_level
 #define cairo_ps_surface_set_eps _moz_cairo_ps_surface_set_eps
 #define cairo_ps_surface_set_size _moz_cairo_ps_surface_set_size
 #define cairo_push_group _moz_cairo_push_group
 #define cairo_push_group_with_content _moz_cairo_push_group_with_content
 #define cairo_quartz_surface_create _moz_cairo_quartz_surface_create
 #define cairo_quartz_surface_create_for_cg_context _moz_cairo_quartz_surface_create_for_cg_context
 #define cairo_quartz_surface_get_cg_context _moz_cairo_quartz_surface_get_cg_context
-#define cairo_quartz_surface_get_image _moz_cairo_quartz_surface_get_image
+#define cairo_quartz_image_surface_create _moz_cairo_quartz_image_surface_create
+#define cairo_quartz_image_surface_get_image _moz_cairo_quartz_image_surface_get_image
 #define cairo_rectangle _moz_cairo_rectangle
 #define cairo_rectangle_list_destroy _moz_cairo_rectangle_list_destroy
 #define cairo_reference _moz_cairo_reference
 #define cairo_rel_curve_to _moz_cairo_rel_curve_to
 #define cairo_rel_line_to _moz_cairo_rel_line_to
 #define cairo_rel_move_to _moz_cairo_rel_move_to
 #define cairo_reset_clip _moz_cairo_reset_clip
 #define cairo_restore _moz_cairo_restore
--- a/gfx/cairo/cairo/src/cairo.h
+++ b/gfx/cairo/cairo/src/cairo.h
@@ -1476,17 +1476,18 @@ typedef enum _cairo_surface_type {
     CAIRO_SURFACE_TYPE_XCB,
     CAIRO_SURFACE_TYPE_GLITZ,
     CAIRO_SURFACE_TYPE_QUARTZ,
     CAIRO_SURFACE_TYPE_WIN32,
     CAIRO_SURFACE_TYPE_BEOS,
     CAIRO_SURFACE_TYPE_DIRECTFB,
     CAIRO_SURFACE_TYPE_SVG,
     CAIRO_SURFACE_TYPE_OS2,
-    CAIRO_SURFACE_TYPE_WIN32_PRINTING
+    CAIRO_SURFACE_TYPE_WIN32_PRINTING,
+    CAIRO_SURFACE_TYPE_QUARTZ_IMAGE
 } cairo_surface_type_t;
 
 cairo_public cairo_surface_type_t
 cairo_surface_get_type (cairo_surface_t *surface);
 
 cairo_public cairo_content_t
 cairo_surface_get_content (cairo_surface_t *surface);
 
--- a/gfx/src/thebes/nsThebesImage.cpp
+++ b/gfx/src/thebes/nsThebesImage.cpp
@@ -106,48 +106,42 @@ nsThebesImage::Init(PRInt32 aWidth, PRIn
         default:
             format = gfxImageSurface::ImageFormatRGB24;
             mAlphaDepth = 0;
             break;
     }
 
     mFormat = format;
 
-#if defined(XP_WIN)
+#ifdef XP_WIN
     if (!ShouldUseImageSurfaces()) {
         mWinSurface = new gfxWindowsSurface(gfxIntSize(mWidth, mHeight), format);
         if (mWinSurface && mWinSurface->CairoStatus() == 0) {
             // no error
             mImageSurface = mWinSurface->GetImageSurface();
         }
     }
 
     if (!mImageSurface)
         mWinSurface = nsnull;
-#elif defined(XP_MACOSX)
-    if (!ShouldUseImageSurfaces()) {
-        mQuartzSurface = new gfxQuartzSurface(gfxSize(mWidth, mHeight), format);
-        if (mQuartzSurface && mQuartzSurface->CairoStatus() == 0) {
-            mImageSurface = mQuartzSurface->GetImageSurface();
-        }
-    }
-
-    if (!mImageSurface)
-        mQuartzSurface = nsnull;
 #endif
 
     if (!mImageSurface)
         mImageSurface = new gfxImageSurface(gfxIntSize(mWidth, mHeight), format);
 
     if (!mImageSurface || mImageSurface->CairoStatus()) {
         mImageSurface = nsnull;
         // guess
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
+#ifdef XP_MACOSX
+    mQuartzSurface = new gfxQuartzImageSurface(mImageSurface);
+#endif
+
     mStride = mImageSurface->Stride();
 
     return NS_OK;
 }
 
 nsThebesImage::~nsThebesImage()
 {
 #ifdef XP_WIN
--- a/gfx/src/thebes/nsThebesImage.h
+++ b/gfx/src/thebes/nsThebesImage.h
@@ -42,17 +42,17 @@
 #include "nsIImage.h"
 
 #include "gfxColor.h"
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #if defined(XP_WIN)
 #include "gfxWindowsSurface.h"
 #elif defined(XP_MACOSX)
-#include "gfxQuartzSurface.h"
+#include "gfxQuartzImageSurface.h"
 #endif
 
 class nsThebesImage : public nsIImage
 {
 public:
     nsThebesImage();
     ~nsThebesImage();
 
@@ -157,17 +157,17 @@ protected:
 
     gfxRGBA mSinglePixelColor;
 
     nsRefPtr<gfxImageSurface> mImageSurface;
     nsRefPtr<gfxASurface> mOptSurface;
 #if defined(XP_WIN)
     nsRefPtr<gfxWindowsSurface> mWinSurface;
 #elif defined(XP_MACOSX)
-    nsRefPtr<gfxQuartzSurface> mQuartzSurface;
+    nsRefPtr<gfxQuartzImageSurface> mQuartzSurface;
 #endif
 
     PRUint8 mAlphaDepth;
 
     // this function should return true if
     // we should (temporarily) not allocate any
     // platform native surfaces and instead use
     // image surfaces for everything.
--- a/gfx/thebes/public/Makefile.in
+++ b/gfx/thebes/public/Makefile.in
@@ -73,16 +73,17 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),beos)
 EXPORTS	+=	gfxBeOSSurface.h gfxBeOSPlatform.h
 EXPORTS +=	gfxPangoFonts.h
 EXPORTS +=	gfxPDFSurface.h
 endif
 
 ifneq (,$(filter $(MOZ_WIDGET_TOOLKIT),mac cocoa))
 EXPORTS +=	gfxPlatformMac.h \
 		gfxQuartzSurface.h \
+		gfxQuartzImageSurface.h \
 		gfxQuartzPDFSurface.h \
 		gfxAtsuiFonts.h \
 		$(NULL)
 
 ifdef MOZ_ENABLE_GLITZ
 REQUIRES += glitzagl
 endif
 endif
--- a/gfx/thebes/public/gfxASurface.h
+++ b/gfx/thebes/public/gfxASurface.h
@@ -76,17 +76,18 @@ public:
         SurfaceTypeXcb,
         SurfaceTypeGlitz,
         SurfaceTypeQuartz,
         SurfaceTypeWin32,
         SurfaceTypeBeOS,
         SurfaceTypeDirectFB,
         SurfaceTypeSVG,
         SurfaceTypeOS2,
-        SurfaceTypeWin32Printing
+        SurfaceTypeWin32Printing,
+        SurfaceTypeQuartzImage
     } gfxSurfaceType;
 
     typedef enum {
         CONTENT_COLOR       = 0x1000,
         CONTENT_ALPHA       = 0x2000,
         CONTENT_COLOR_ALPHA = 0x3000
     } gfxContentType;
 
--- a/gfx/thebes/public/gfxImageSurface.h
+++ b/gfx/thebes/public/gfxImageSurface.h
@@ -76,16 +76,19 @@ public:
      */
     long Stride() const { return mStride; }
     /**
      * Returns a pointer for the image data. Users of this function can
      * write to it, but must not attempt to free the buffer.
      */
     unsigned char* Data() { return mData; } // delete this data under us and die.
 
+    /* Fast copy from another image surface; returns TRUE if successful, FALSE otherwise */
+    PRBool CopyFrom (gfxImageSurface *other);
+
 private:
     long ComputeStride() const;
 
     gfxIntSize mSize;
     PRBool mOwnsData;
     unsigned char *mData;
     gfxImageFormat mFormat;
     long mStride;
--- a/gfx/thebes/public/gfxPlatformMac.h
+++ b/gfx/thebes/public/gfxPlatformMac.h
@@ -48,16 +48,19 @@ public:
 
     static gfxPlatformMac *GetPlatform() {
         return (gfxPlatformMac*) gfxPlatform::GetPlatform();
     }
 
     already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
                                                          gfxASurface::gfxImageFormat imageFormat);
 
+    already_AddRefed<gfxASurface> gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface,
+                                                                gfxASurface::gfxImageFormat format);
+
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, PRBool& aAborted);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
                                   const gfxFontStyle *aStyle);
 
     nsresult GetFontList(const nsACString& aLangGroup,
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/public/gfxQuartzImageSurface.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef GFX_QUARTZIMAGESURFACE_H
+#define GFX_QUARTZIMAGESURFACE_H
+
+#include "gfxASurface.h"
+#include "gfxImageSurface.h"
+
+class THEBES_API gfxQuartzImageSurface : public gfxASurface {
+public:
+    gfxQuartzImageSurface(gfxImageSurface *imageSurface);
+    gfxQuartzImageSurface(cairo_surface_t *csurf);
+
+    virtual ~gfxQuartzImageSurface();
+
+    already_AddRefed<gfxImageSurface> GetImageSurface();
+};
+
+#endif /* GFX_QUARTZIMAGESURFACE_H */
--- a/gfx/thebes/public/gfxQuartzSurface.h
+++ b/gfx/thebes/public/gfxQuartzSurface.h
@@ -53,17 +53,15 @@ public:
     virtual ~gfxQuartzSurface();
 
     const gfxSize& GetSize() const { return mSize; }
 
     CGContextRef GetCGContext() { return mCGContext; }
 
     virtual PRInt32 GetDefaultContextFlags() const;
 
-    already_AddRefed<gfxImageSurface> GetImageSurface();
-
 protected:
     CGContextRef mCGContext;
     gfxSize      mSize;
     PRPackedBool mForPrinting;
 };
 
 #endif /* GFX_QUARTZSURFACE_H */
--- a/gfx/thebes/src/Makefile.in
+++ b/gfx/thebes/src/Makefile.in
@@ -96,17 +96,23 @@ CPPSRCS +=	gfxPangoFonts.cpp
 #CPPSRCS +=	gfxPDFSurface.cpp
 CPPSRCS +=	gfxFontconfigUtils.cpp
 CPPSRCS +=	nsUnicodeRange.cpp
 EXTRA_DSO_LDOPTS += $(MOZ_PANGO_LIBS) $(CAIRO_FT_LIBS) -lfontconfig -lpangocairo-1.0
 endif
 
 
 ifneq (,$(filter $(MOZ_WIDGET_TOOLKIT),mac cocoa))
-CPPSRCS	+= 	gfxQuartzSurface.cpp gfxQuartzPDFSurface.cpp gfxPlatformMac.cpp gfxAtsuiFonts.cpp
+CPPSRCS	+= \
+	gfxQuartzSurface.cpp \
+	gfxQuartzImageSurface.cpp \
+	gfxQuartzPDFSurface.cpp \
+	gfxPlatformMac.cpp \
+	gfxAtsuiFonts.cpp \
+	$(NULL)
 #CPPSRCS +=	gfxPDFSurface.cpp
 CPPSRCS +=      nsUnicodeRange.cpp
 
 CMMSRCS = gfxQuartzFontCache.mm
 
 # Always link with OpenGL/AGL
 EXTRA_DSO_LDOPTS += -framework OpenGL -framework AGL -framework Cocoa -framework QuickTime
 endif
--- a/gfx/thebes/src/gfxASurface.cpp
+++ b/gfx/thebes/src/gfxASurface.cpp
@@ -47,16 +47,17 @@
 #endif
 
 #ifdef CAIRO_HAS_XLIB_SURFACE
 #include "gfxXlibSurface.h"
 #endif
 
 #ifdef CAIRO_HAS_QUARTZ_SURFACE
 #include "gfxQuartzSurface.h"
+#include "gfxQuartzImageSurface.h"
 #endif
 
 #include <stdio.h>
 #include <limits.h>
 
 static cairo_user_data_key_t gfxasurface_pointer_key;
 
 // Surfaces use refcounting that's tied to the cairo surface refcnt, to avoid
@@ -153,16 +154,19 @@ gfxASurface::Wrap (cairo_surface_t *csur
     else if (stype == CAIRO_SURFACE_TYPE_XLIB) {
         result = new gfxXlibSurface(csurf);
     }
 #endif
 #ifdef CAIRO_HAS_QUARTZ_SURFACE
     else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
         result = new gfxQuartzSurface(csurf);
     }
+    else if (stype == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) {
+        result = new gfxQuartzImageSurface(csurf);
+    }
 #endif
     else {
         result = new gfxUnknownSurface(csurf);
     }
 
     // fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result);
 
     NS_ADDREF(result);
--- a/gfx/thebes/src/gfxImageSurface.cpp
+++ b/gfx/thebes/src/gfxImageSurface.cpp
@@ -109,8 +109,38 @@ gfxImageSurface::ComputeStride() const
         NS_WARNING("Unknown format specified to gfxImageSurface!");
         stride = mSize.width * 4;
     }
 
     stride = ((stride + 3) / 4) * 4;
 
     return stride;
 }
+
+PRBool
+gfxImageSurface::CopyFrom(gfxImageSurface *other)
+{
+    if (other->mSize != mSize)
+    {
+        return PR_FALSE;
+    }
+
+    if (other->mFormat != mFormat &&
+        !(other->mFormat == ImageFormatARGB32 && mFormat == ImageFormatRGB24) &&
+        !(other->mFormat == ImageFormatRGB24 && mFormat == ImageFormatARGB32))
+    {
+        return PR_FALSE;
+    }
+
+    if (other->mStride == mStride) {
+        memcpy (mData, other->mData, mStride * mSize.height);
+    } else {
+        int lineSize = PR_MIN(other->mStride, mStride);
+        for (int i = 0; i < mSize.height; i++) {
+            unsigned char *src = other->mData + other->mStride * i;
+            unsigned char *dst = mData + mStride * i;
+
+            memcpy (dst, src, lineSize);
+        }
+    }
+
+    return PR_TRUE;
+}
--- a/gfx/thebes/src/gfxPlatformMac.cpp
+++ b/gfx/thebes/src/gfxPlatformMac.cpp
@@ -35,16 +35,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxPlatformMac.h"
 
 #include "gfxImageSurface.h"
 #include "gfxQuartzSurface.h"
+#include "gfxQuartzImageSurface.h"
 
 #include "gfxQuartzFontCache.h"
 #include "gfxAtsuiFonts.h"
 
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsIPrefLocalizedString.h"
 #include "nsServiceManagerUtils.h"
@@ -139,16 +140,36 @@ gfxPlatformMac::CreateOffscreenSurface(c
         newSurface = new gfxGlitzSurface(gdraw, gsurf, PR_TRUE);
 #endif
     }
 
     NS_IF_ADDREF(newSurface);
     return newSurface;
 }
 
+already_AddRefed<gfxASurface>
+gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface,
+                              gfxASurface::gfxImageFormat format)
+{
+    const gfxIntSize& surfaceSize = aSurface->GetSize();
+    nsRefPtr<gfxImageSurface> isurf = aSurface;
+
+    if (format != aSurface->Format()) {
+        isurf = new gfxImageSurface (surfaceSize, format);
+        if (!isurf->CopyFrom (aSurface)) {
+            // don't even bother doing anything more
+            NS_ADDREF(aSurface);
+            return aSurface;
+        }
+    }
+
+    nsRefPtr<gfxASurface> ret = new gfxQuartzImageSurface(isurf);
+    return ret.forget();
+}
+
 nsresult
 gfxPlatformMac::ResolveFontName(const nsAString& aFontName,
                                 FontResolverCallback aCallback,
                                 void *aClosure, PRBool& aAborted)
 {
     nsAutoString resolvedName;
     if (!gfxQuartzFontCache::SharedFontCache()->
              ResolveFontName(aFontName, resolvedName)) {
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxQuartzImageSurface.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "gfxQuartzImageSurface.h"
+
+#include "cairo-quartz.h"
+
+gfxQuartzImageSurface::gfxQuartzImageSurface(gfxImageSurface *imageSurface)
+{
+    if (imageSurface->CairoStatus() || imageSurface->CairoSurface() == NULL)
+        return;
+
+    cairo_surface_t *surf = cairo_quartz_image_surface_create (imageSurface->CairoSurface());
+    Init (surf);
+}
+
+gfxQuartzImageSurface::gfxQuartzImageSurface(cairo_surface_t *csurf)
+{
+    Init (csurf, PR_TRUE);
+}
+
+gfxQuartzImageSurface::~gfxQuartzImageSurface()
+{
+}
+
+already_AddRefed<gfxImageSurface>
+gfxQuartzImageSurface::GetImageSurface()
+{
+    if (!mSurfaceValid)
+        return nsnull;
+
+    cairo_surface_t *isurf = cairo_quartz_image_surface_get_image (CairoSurface());
+    if (!isurf) {
+        NS_WARNING ("Couldn't obtain an image surface from a QuartzImageSurface?!");
+        return nsnull;
+    }
+
+    nsRefPtr<gfxASurface> asurf = gfxASurface::Wrap(isurf);
+    gfxImageSurface *imgsurf = (gfxImageSurface*) asurf.get();
+    NS_ADDREF(imgsurf);
+    return imgsurf;
+}
--- a/gfx/thebes/src/gfxQuartzSurface.cpp
+++ b/gfx/thebes/src/gfxQuartzSurface.cpp
@@ -39,38 +39,43 @@
 #include "gfxContext.h"
 
 #include "cairo-quartz.h"
 
 gfxQuartzSurface::gfxQuartzSurface(const gfxSize& size, gfxImageFormat format,
                                    PRBool aForPrinting)
     : mSize(size), mForPrinting(aForPrinting)
 {
-    if (!CheckSurfaceSize(gfxIntSize((int)size.width, (int)size.height)))
+    unsigned int width = (unsigned int) floor(size.width);
+    unsigned int height = (unsigned int) floor(size.height);
+
+    if (!CheckSurfaceSize(gfxIntSize(width, height)))
         return;
 
     cairo_surface_t *surf = cairo_quartz_surface_create
-        ((cairo_format_t) format, floor(size.width), floor(size.height));
+        ((cairo_format_t) format, width, height);
 
     mCGContext = cairo_quartz_surface_get_cg_context (surf);
 
     CGContextRetain(mCGContext);
 
     Init(surf);
 }
 
 gfxQuartzSurface::gfxQuartzSurface(CGContextRef context,
                                    const gfxSize& size,
                                    PRBool aForPrinting)
     : mCGContext(context), mSize(size), mForPrinting(aForPrinting)
 {
+    unsigned int width = (unsigned int) floor(size.width);
+    unsigned int height = (unsigned int) floor(size.height);
+
     cairo_surface_t *surf = 
         cairo_quartz_surface_create_for_cg_context(context,
-                                                   floor(size.width),
-                                                   floor(size.height));
+                                                   width, height);
 
     CGContextRetain(mCGContext);
 
     Init(surf);
 }
 
 gfxQuartzSurface::gfxQuartzSurface(cairo_surface_t *csurf,
                                    PRBool aForPrinting) :
@@ -89,28 +94,8 @@ PRInt32 gfxQuartzSurface::GetDefaultCont
 
     return 0;
 }
 
 gfxQuartzSurface::~gfxQuartzSurface()
 {
     CGContextRelease(mCGContext);
 }
-
-already_AddRefed<gfxImageSurface>
-gfxQuartzSurface::GetImageSurface()
-{
-    if (!mSurfaceValid) {
-        NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?");
-        return nsnull;
-    }
-
-    NS_ASSERTION(CairoSurface() != nsnull, "CairoSurface() shouldn't be nsnull when mSurfaceValid is TRUE!");
-
-    cairo_surface_t *isurf = cairo_quartz_surface_get_image(CairoSurface());
-    if (!isurf)
-        return nsnull;
-
-    nsRefPtr<gfxASurface> asurf = gfxASurface::Wrap(isurf);
-    gfxImageSurface *imgsurf = (gfxImageSurface*) asurf.get();
-    NS_ADDREF(imgsurf);
-    return imgsurf;
-}