[cairo-commit] 9 commits - src/cairo-quartz-surface.c test/a1-bug.quartz.xfail.png test/a1-image-sample.quartz.xfail.png test/a1-mask-sample.quartz.xfail.png test/a1-rasterisation-rectangles.quartz.xfail.png test/a1-rasterisation-triangles.quartz.xfail.png test/a8-clear.quartz.ref.png test/aliasing.quartz.ref.png test/clip-fill-eo-unbounded.quartz.argb32.ref.png test/clip-fill-eo-unbounded.quartz.rgb24.ref.png test/clip-fill-nz-unbounded.quartz.argb32.ref.png test/clip-fill-nz-unbounded.quartz.rgb24.ref.png test/clip-operator.quartz.argb32.ref.png test/clip-operator.quartz.rgb24.ref.png test/clip-stroke-unbounded.quartz.argb32.ref.png test/clip-stroke-unbounded.quartz.rgb24.ref.png test/filter-nearest-offset.quartz.xfail.png test/filter-nearest-transformed.quartz.xfail.png test/linear-gradient.quartz.ref.png test/linear-gradient-subset.quartz.ref.png test/Makefile.am test/mask.quartz.argb32.ref.png test/operator-alpha-alpha.c test/operator-source.quartz.argb32.ref.png test/operator -source.quartz.rgb24.ref.png test/overlapping-glyphs.quartz.argb32.ref.png test/overlapping-glyphs.quartz.rgb24.ref.png test/partial-clip-text.quartz.ref.png test/pthread-same-source.quartz.xfail.png test/pthread-show-text.quartz.ref.png test/radial-gradient-mask.quartz.ref.png test/radial-gradient-mask-source.quartz.argb32.ref.png test/radial-gradient-mask-source.quartz.rgb24.ref.png test/radial-gradient-one-stop.quartz.ref.png test/radial-gradient.quartz.ref.png test/radial-gradient-source.quartz.argb32.ref.png test/radial-gradient-source.quartz.rgb24.ref.png test/rotate-image-surface-paint.quartz.ref.png test/scale-offset-image.quartz.ref.png test/scale-offset-similar.quartz.ref.png test/surface-pattern-operator.quartz.argb32.ref.png test/surface-pattern-operator.quartz.argb32.xfail.png test/surface-pattern-operator.quartz.rgb24.ref.png test/surface-pattern-operator.quartz.rgb24.xfail.png test/trap-clip.quartz.argb32.ref.png test/trap-clip.quartz.rgb24.ref.png test/unboun ded-operator.quartz.argb32.ref.png test/unbounded-operator.quartz.rgb24.ref.png test/xcomposite-projection.quartz.ref.png

Andrea Canciani ranma42 at kemper.freedesktop.org
Wed Jan 19 04:37:20 PST 2011


 dev/null                                               |binary
 src/cairo-quartz-surface.c                             |  890 +++++++----------
 test/Makefile.am                                       |   24 
 test/a1-bug.quartz.xfail.png                           |binary
 test/a1-rasterisation-rectangles.quartz.xfail.png      |binary
 test/a1-rasterisation-triangles.quartz.xfail.png       |binary
 test/a8-clear.quartz.ref.png                           |binary
 test/aliasing.quartz.ref.png                           |binary
 test/clip-fill-eo-unbounded.quartz.argb32.ref.png      |binary
 test/clip-fill-eo-unbounded.quartz.rgb24.ref.png       |binary
 test/clip-fill-nz-unbounded.quartz.argb32.ref.png      |binary
 test/clip-fill-nz-unbounded.quartz.rgb24.ref.png       |binary
 test/clip-operator.quartz.argb32.ref.png               |binary
 test/clip-operator.quartz.rgb24.ref.png                |binary
 test/clip-stroke-unbounded.quartz.argb32.ref.png       |binary
 test/clip-stroke-unbounded.quartz.rgb24.ref.png        |binary
 test/filter-nearest-transformed.quartz.xfail.png       |binary
 test/linear-gradient-subset.quartz.ref.png             |binary
 test/linear-gradient.quartz.ref.png                    |binary
 test/mask.quartz.argb32.ref.png                        |binary
 test/operator-alpha-alpha.c                            |    4 
 test/operator-source.quartz.argb32.ref.png             |binary
 test/operator-source.quartz.rgb24.ref.png              |binary
 test/overlapping-glyphs.quartz.argb32.ref.png          |binary
 test/overlapping-glyphs.quartz.rgb24.ref.png           |binary
 test/partial-clip-text.quartz.ref.png                  |binary
 test/pthread-same-source.quartz.xfail.png              |binary
 test/pthread-show-text.quartz.ref.png                  |binary
 test/radial-gradient-mask-source.quartz.argb32.ref.png |binary
 test/radial-gradient-mask-source.quartz.rgb24.ref.png  |binary
 test/radial-gradient-mask.quartz.ref.png               |binary
 test/radial-gradient-one-stop.quartz.ref.png           |binary
 test/radial-gradient-source.quartz.argb32.ref.png      |binary
 test/radial-gradient-source.quartz.rgb24.ref.png       |binary
 test/radial-gradient.quartz.ref.png                    |binary
 test/rotate-image-surface-paint.quartz.ref.png         |binary
 test/scale-offset-image.quartz.ref.png                 |binary
 test/scale-offset-similar.quartz.ref.png               |binary
 test/surface-pattern-operator.quartz.argb32.ref.png    |binary
 test/surface-pattern-operator.quartz.rgb24.ref.png     |binary
 test/trap-clip.quartz.argb32.ref.png                   |binary
 test/trap-clip.quartz.rgb24.ref.png                    |binary
 test/unbounded-operator.quartz.argb32.ref.png          |binary
 test/unbounded-operator.quartz.rgb24.ref.png           |binary
 test/xcomposite-projection.quartz.ref.png              |binary
 45 files changed, 437 insertions(+), 481 deletions(-)

New commits:
commit b8e7bfdff0478f0515ea470b32fc15ca081d637e
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Thu Jan 6 17:40:05 2011 +0100

    quartz: Respect pattern filter settings
    
    CAIRO_FILTER_FAST and CAIRO_FILTER_NEAREST both map to nearest
    neighbor filtering, whereas all other filter modes are names for
    bilinear filtering.
    
    Additionally, translations matrices are transformed into integer
    translations when possible (i.e. when they are used on an nearest
    neighbor filtered surface pattern), which makes Quartz behave as
    cairo-image for these simple transformations.
    
    Fixes a1-image-sample, a1-mask-sample, filter-nearest-offset.
    
    Improves the output of filter-nearest-transformed and
    rotate-image-surface-paint. They are not blurry anymore, but they are
    different from the reference images because of different in/out rules
    between Quartz and cairo-image.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index c7a84ab..bb7be48 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -602,10 +602,8 @@ _cairo_quartz_filter_to_quartz (cairo_filter_t filter)
 {
     switch (filter) {
     case CAIRO_FILTER_NEAREST:
-	return kCGInterpolationNone;
-
     case CAIRO_FILTER_FAST:
-	return kCGInterpolationLow;
+	return kCGInterpolationNone;
 
     case CAIRO_FILTER_BEST:
     case CAIRO_FILTER_GOOD:
@@ -994,6 +992,9 @@ typedef struct {
     /* The destination of the drawing of the source */
     CGContextRef cgDrawContext;
 
+    /* The filter to be used when drawing the source */
+    CGInterpolationQuality filter;
+
     /* Action type */
     cairo_quartz_action_t action;
 
@@ -1115,6 +1116,8 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
     state->cgMaskContext = surface->cgContext;
     state->cgDrawContext = state->cgMaskContext;
 
+    state->filter = _cairo_quartz_filter_to_quartz (source->filter);
+
     if (op == CAIRO_OPERATOR_CLEAR) {
 	CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
 
@@ -1153,8 +1156,6 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
 			       -state->clipRect.origin.y);
     }
 
-    CGContextSetInterpolationQuality (state->cgDrawContext, _cairo_quartz_filter_to_quartz (source->filter));
-
     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
 	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
 
@@ -1208,7 +1209,13 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
 
 	state->image = img;
 
-	cairo_matrix_invert (&m);
+	if (state->filter == kCGInterpolationNone && _cairo_matrix_is_translation (&m)) {
+	    m.x0 = -ceil (m.x0 - 0.5);
+	    m.y0 = -ceil (m.y0 - 0.5);
+	} else {
+	    cairo_matrix_invert (&m);
+	}
+
 	_cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform);
 
 	is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
@@ -1334,6 +1341,9 @@ static void
 _cairo_quartz_draw_source (cairo_quartz_drawing_state_t *state,
 			   cairo_operator_t              op)
 {
+    CGContextSetShouldAntialias (state->cgDrawContext, state->filter != kCGInterpolationNone);
+    CGContextSetInterpolationQuality(state->cgDrawContext, state->filter);
+
     if (state->action == DO_DIRECT) {
 	CGContextFillRect (state->cgDrawContext, state->rect);
 	return;
@@ -2151,14 +2161,15 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
 
 static cairo_int_status_t
 _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
-                                         cairo_operator_t op,
-                                         const cairo_pattern_t *source,
-                                         const cairo_surface_pattern_t *mask,
-					 cairo_clip_t *clip)
+					 cairo_operator_t        op,
+					 const cairo_pattern_t  *source,
+					 cairo_surface_t        *mask_surf,
+					 const cairo_matrix_t   *mask_mat,
+					 CGInterpolationQuality filter,
+					 cairo_clip_t           *clip)
 {
     CGRect rect;
     CGImageRef img;
-    cairo_surface_t *pat_surf = mask->surface;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     CGAffineTransform mask_matrix;
     cairo_quartz_drawing_state_t state;
@@ -2166,7 +2177,7 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
     if (IS_EMPTY (surface))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
-    status = _cairo_surface_to_cgimage (pat_surf, &img);
+    status = _cairo_surface_to_cgimage (mask_surf, &img);
     if (unlikely (status))
 	return status;
 
@@ -2178,7 +2189,7 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
 	goto BAIL;
 
     rect = CGRectMake (0.0, 0.0, CGImageGetWidth (img), CGImageGetHeight (img));
-    _cairo_quartz_cairo_matrix_to_quartz (&mask->base.matrix, &mask_matrix);
+    _cairo_quartz_cairo_matrix_to_quartz (mask_mat, &mask_matrix);
 
     /* ClipToMask is essentially drawing an image, so we need to flip the CTM
      * to get the image to appear oriented the right way */
@@ -2186,6 +2197,11 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
     CGContextTranslateCTM (state.cgMaskContext, 0.0, rect.size.height);
     CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
 
+    state.filter = filter;
+
+    CGContextSetInterpolationQuality (state.cgMaskContext, filter);
+    CGContextSetShouldAntialias (state.cgMaskContext, filter != kCGInterpolationNone);
+
     CGContextClipToMask (state.cgMaskContext, rect, img);
 
     CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
@@ -2202,48 +2218,6 @@ 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
-_cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
-					 cairo_operator_t op,
-					 const cairo_pattern_t *source,
-					 const cairo_pattern_t *mask,
-					 cairo_clip_t *clip)
-{
-    cairo_surface_t *gradient_surf;
-    cairo_surface_pattern_t surface_pattern;
-    cairo_int_status_t status;
-
-    /* Render the gradient to a surface */
-    gradient_surf = _cairo_quartz_surface_create_similar (surface,
-							  CAIRO_CONTENT_ALPHA,
-							  surface->extents.width,
-							  surface->extents.height);
-    status = gradient_surf->status;
-    if (unlikely (status))
-	goto BAIL;
-
-    /* gradient_surf is clear, thus we can use OVER instead of SOURCE
-     * to make sure we won't have to create a temporary layer or
-     * fallback.
-     */
-    status = _cairo_quartz_surface_paint (gradient_surf, CAIRO_OPERATOR_OVER, mask, NULL);
-    if (unlikely (status))
-	goto BAIL;
-
-    _cairo_pattern_init_for_surface (&surface_pattern, gradient_surf);
-    status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern, clip);
-    _cairo_pattern_fini (&surface_pattern.base);
-
- BAIL:
-    cairo_surface_destroy (gradient_surf);
-
-    return status;
-}
-
 static cairo_int_status_t
 _cairo_quartz_surface_mask_with_solid (cairo_quartz_surface_t *surface,
 				       cairo_operator_t        op,
@@ -2274,6 +2248,12 @@ _cairo_quartz_surface_mask_cg (cairo_quartz_surface_t *surface,
 			       const cairo_pattern_t *mask,
 			       cairo_clip_t *clip)
 {
+    cairo_surface_t *mask_surf;
+    cairo_matrix_t matrix;
+    cairo_status_t status;
+    cairo_bool_t need_temp;
+    CGInterpolationQuality filter;
+
     ND ((stderr, "%p _cairo_quartz_surface_mask op %d source->type %d mask->type %d\n", surface, op, source->type, mask->type));
 
     if (IS_EMPTY (surface))
@@ -2288,15 +2268,79 @@ _cairo_quartz_surface_mask_cg (cairo_quartz_surface_t *surface,
 						      clip);
     }
 
-    /* For these, we can skip creating a temporary surface, since we already have one */
-    if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && mask->extend == CAIRO_EXTEND_NONE) {
-	const cairo_surface_pattern_t *mask_spat =  (const cairo_surface_pattern_t *) mask;
+    need_temp = (mask->type   != CAIRO_PATTERN_TYPE_SURFACE ||
+		 mask->extend != CAIRO_EXTEND_NONE);
+
+    filter = _cairo_quartz_filter_to_quartz (source->filter);
+
+    if (! need_temp) {
+	mask_surf = ((const cairo_surface_pattern_t *) mask)->surface;
+
+	/* When an opaque surface used as a mask in Quartz, its
+	 * luminosity is used as the alpha value, so we con only use
+	 * surfaces with alpha without creating a temporary mask. */
+	need_temp = ! (mask_surf->content & CAIRO_CONTENT_ALPHA);
+    }
+
+    if (! need_temp) {
+	CGInterpolationQuality mask_filter;
+	cairo_bool_t simple_transform;
 
-	if (mask_spat->surface->content & CAIRO_CONTENT_ALPHA)
-	    return _cairo_quartz_surface_mask_with_surface (surface, op, source, mask_spat, clip);
+	matrix = mask->matrix;
+
+	mask_filter = _cairo_quartz_filter_to_quartz (mask->filter);
+	if (mask_filter == kCGInterpolationNone) {
+	    simple_transform = _cairo_matrix_is_translation (&matrix);
+	    if (simple_transform) {
+		matrix.x0 = ceil (matrix.x0 - 0.5);
+		matrix.y0 = ceil (matrix.y0 - 0.5);
+	    }
+	} else {
+	    simple_transform = _cairo_matrix_is_integer_translation (&matrix,
+								     NULL,
+								     NULL);
+	}
+
+	/* Quartz only allows one interpolation to be set for mask and
+	 * source, so we can skip the temp surface only if the source
+	 * filtering makes the mask look correct. */
+	if (source->type == CAIRO_PATTERN_TYPE_SURFACE)
+	    need_temp = ! (simple_transform || filter == mask_filter);
+	else
+	    filter = mask_filter;
     }
 
-    return _cairo_quartz_surface_mask_with_generic (surface, op, source, mask, clip);
+    if (need_temp) {
+	/* Render the mask to a surface */
+	mask_surf = _cairo_quartz_surface_create_similar (surface,
+							  CAIRO_CONTENT_ALPHA,
+							  surface->extents.width,
+							  surface->extents.height);
+	status = mask_surf->status;
+	if (unlikely (status))
+	    goto BAIL;
+
+	/* mask_surf is clear, so use OVER instead of SOURCE to avoid a
+	 * temporary layer or fallback to cairo-image. */
+	status = _cairo_surface_paint (mask_surf, CAIRO_OPERATOR_OVER, mask, NULL);
+	if (unlikely (status))
+	    goto BAIL;
+
+	cairo_matrix_init_identity (&matrix);
+    }
+
+    status = _cairo_quartz_surface_mask_with_surface (surface, op, source,
+						      mask_surf,
+						      &matrix,
+						      filter,
+						      clip);
+
+BAIL:
+
+    if (need_temp)
+	cairo_surface_destroy (mask_surf);
+
+    return status;
 }
 
 static cairo_int_status_t
commit 45da39dda729be4c61c92d30e9373282941000fa
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Fri Jan 7 18:00:37 2011 +0100

    quartz: Avoid using private APIs
    
    CGContextSetCTM() is not part of the public API and can easily be
    replaced by CGContextConcatCTM()-ing an appropriate matrix.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 99095b1..c7a84ab 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -99,7 +99,6 @@ enum PrivateCGCompositeMode {
 typedef enum PrivateCGCompositeMode PrivateCGCompositeMode;
 CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
 #endif
-CG_EXTERN void CGContextSetCTM (CGContextRef, CGAffineTransform);
 
 /* Some of these are present in earlier versions of the OS than where
  * they are public; other are not public at all
@@ -1863,7 +1862,7 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
 {
     cairo_quartz_drawing_state_t state;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
-    CGAffineTransform origCTM, strokeTransform;
+    CGAffineTransform strokeTransform, invStrokeTransform;
 
     ND ((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type));
 
@@ -1883,8 +1882,6 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
     CGContextSetLineJoin (state.cgMaskContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
     CGContextSetMiterLimit (state.cgMaskContext, style->miter_limit);
 
-    origCTM = CGContextGetCTM (state.cgMaskContext);
-
     if (style->dash && style->num_dashes) {
 	cairo_quartz_float_t sdash[CAIRO_STACK_ARRAY_LENGTH (cairo_quartz_float_t)];
 	cairo_quartz_float_t *fdash = sdash;
@@ -1921,7 +1918,9 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
 	CGContextReplacePathWithStrokedPath (state.cgMaskContext);
 	CGContextClip (state.cgMaskContext);
 
-	CGContextSetCTM (state.cgMaskContext, origCTM);
+	_cairo_quartz_cairo_matrix_to_quartz (ctm_inverse, &invStrokeTransform);
+	CGContextConcatCTM (state.cgMaskContext, invStrokeTransform);
+
 	_cairo_quartz_draw_source (&state, op);
     }
 
@@ -1979,7 +1978,7 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
 				      cairo_clip_t *clip,
 				      int *remaining_glyphs)
 {
-    CGAffineTransform textTransform, ctm, invTextTransform;
+    CGAffineTransform textTransform, invTextTransform;
     CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
     CGSize cg_advances_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
     CGGlyph *cg_glyphs = &glyphs_static[0];
@@ -2054,11 +2053,17 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
 
     textTransform = CGAffineTransformMake (scaled_font->scale.xx,
 					   scaled_font->scale.yx,
-					   -scaled_font->scale.xy,
-					   -scaled_font->scale.yy,
-					   0, 0);
-    _cairo_quartz_cairo_matrix_to_quartz (&scaled_font->scale_inverse, &invTextTransform);
+					   scaled_font->scale.xy,
+					   scaled_font->scale.yy,
+					   0.0, 0.0);
 
+    invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx,
+					      scaled_font->scale_inverse.yx,
+					      scaled_font->scale_inverse.xy,
+					      scaled_font->scale_inverse.yy,
+					      0.0, 0.0);
+
+    CGContextSetTextPosition (state.cgMaskContext, 0.0, 0.0);
     CGContextSetTextMatrix (state.cgMaskContext, CGAffineTransformIdentity);
 
     /* Convert our glyph positions to glyph advances.  We need n-1 advances,
@@ -2078,16 +2083,18 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
     }
 
     /* Translate to the first glyph's position before drawing */
-    ctm = CGContextGetCTM (state.cgMaskContext);
     CGContextTranslateCTM (state.cgMaskContext, glyphs[0].x, glyphs[0].y);
     CGContextConcatCTM (state.cgMaskContext, textTransform);
+    CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
 
     CGContextShowGlyphsWithAdvances (state.cgMaskContext,
 				     cg_glyphs,
 				     cg_advances,
 				     num_glyphs);
 
-    CGContextSetCTM (state.cgMaskContext, ctm);
+    CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
+    CGContextConcatCTM (state.cgMaskContext, invTextTransform);
+    CGContextTranslateCTM (state.cgMaskContext, -glyphs[0].x, -glyphs[0].y);
 
     if (state.action != DO_DIRECT)
 	_cairo_quartz_draw_source (&state, op);
@@ -2153,7 +2160,7 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
     CGImageRef img;
     cairo_surface_t *pat_surf = mask->surface;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    CGAffineTransform ctm, mask_matrix;
+    CGAffineTransform mask_matrix;
     cairo_quartz_drawing_state_t state;
 
     if (IS_EMPTY (surface))
@@ -2170,21 +2177,20 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
     if (unlikely (img == NULL))
 	goto BAIL;
 
-    rect = CGRectMake (0.0f, 0.0f, CGImageGetWidth (img) , CGImageGetHeight (img));
+    rect = CGRectMake (0.0, 0.0, CGImageGetWidth (img), CGImageGetHeight (img));
+    _cairo_quartz_cairo_matrix_to_quartz (&mask->base.matrix, &mask_matrix);
 
     /* 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 (state.cgMaskContext);
+    CGContextConcatCTM (state.cgMaskContext, CGAffineTransformInvert (mask_matrix));
+    CGContextTranslateCTM (state.cgMaskContext, 0.0, rect.size.height);
+    CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
 
-    _cairo_quartz_cairo_matrix_to_quartz (&mask->base.matrix, &mask_matrix);
-    mask_matrix = CGAffineTransformInvert (mask_matrix);
-    mask_matrix = CGAffineTransformTranslate (mask_matrix, 0.0, CGImageGetHeight (img));
-    mask_matrix = CGAffineTransformScale (mask_matrix, 1.0, -1.0);
-
-    CGContextConcatCTM (state.cgMaskContext, mask_matrix);
     CGContextClipToMask (state.cgMaskContext, rect, img);
 
-    CGContextSetCTM (state.cgMaskContext, ctm);
+    CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
+    CGContextTranslateCTM (state.cgMaskContext, 0.0, -rect.size.height);
+    CGContextConcatCTM (state.cgMaskContext, mask_matrix);
 
     _cairo_quartz_draw_source (&state, op);
 
commit ca9068839bf28f914a5066d7846f4d4b95fee4a2
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Wed Jan 5 16:12:34 2011 +0100

    quartz: Use CGLayer to implement unbounded operators
    
    Quartz operators are not unbounded, but it is possible to implement
    unbounded operators by using a temporary destination.
    
    Fixes clip-stroke-unbounded, clip-fill-nz-unbounded,
    clip-fill-eo-unbounded, clip-operator, operator-alpha-alpha,
    overlapping-glyphs, surface-pattern-operator, unbounded-operator.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index f2fdb63..99095b1 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -532,20 +532,31 @@ _cairo_quartz_surface_set_cairo_operator (cairo_quartz_surface_t *surface, cairo
 {
     ND((stderr, "%p _cairo_quartz_surface_set_cairo_operator %d\n", surface, op));
 
+    /* When the destination has no color components, we can avoid some
+     * fallbacks, but we have to workaround operators which behave
+     * differently in Quartz. */
     if (surface->base.content == CAIRO_CONTENT_ALPHA) {
-	if (op == CAIRO_OPERATOR_OUT ||
+	if (op == CAIRO_OPERATOR_ATOP)
+	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+	if (op == CAIRO_OPERATOR_SOURCE ||
+	    op == CAIRO_OPERATOR_IN ||
+	    op == CAIRO_OPERATOR_OUT ||
+	    op == CAIRO_OPERATOR_DEST_IN ||
+	    op == CAIRO_OPERATOR_DEST_ATOP ||
 	    op == CAIRO_OPERATOR_XOR)
+	{
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	}
+
+	if (op == CAIRO_OPERATOR_DEST_OVER)
+	    op = CAIRO_OPERATOR_OVER;
 	else if (op == CAIRO_OPERATOR_SATURATE)
 	    op = CAIRO_OPERATOR_ADD;
-	else if (op == CAIRO_OPERATOR_IN)
-	    op = CAIRO_OPERATOR_DEST_ATOP;
-	else if (op == CAIRO_OPERATOR_DEST_ATOP)
-	    op = CAIRO_OPERATOR_IN;
-	else if (op == CAIRO_OPERATOR_ATOP)
-	    return CAIRO_INT_STATUS_NOTHING_TO_DO; /* op = CAIRO_OPERATOR_DEST_OVER */
-	else if (op == CAIRO_OPERATOR_DEST_OVER)
-	    op = CAIRO_OPERATOR_ATOP;
+	else if (op == CAIRO_OPERATOR_COLOR_DODGE)
+	    op = CAIRO_OPERATOR_OVER;
+	else if (op == CAIRO_OPERATOR_COLOR_BURN)
+	    op = CAIRO_OPERATOR_OVER;
     }
 
     return _cairo_cgcontext_set_cairo_operator (surface->cgContext, op);
@@ -621,152 +632,6 @@ _cairo_quartz_cairo_matrix_to_quartz (const cairo_matrix_t *src,
     dst->ty = src->y0;
 }
 
-typedef struct {
-    bool isClipping;
-    CGGlyph *cg_glyphs;
-    CGSize *cg_advances;
-    size_t nglyphs;
-    CGAffineTransform textTransform;
-    CGFontRef font;
-    CGPoint origin;
-} unbounded_show_glyphs_t;
-
-typedef struct {
-    CGPathRef cgPath;
-    cairo_fill_rule_t fill_rule;
-} unbounded_stroke_fill_t;
-
-typedef struct {
-    CGImageRef mask;
-    CGAffineTransform maskTransform;
-} unbounded_mask_t;
-
-typedef enum {
-    UNBOUNDED_STROKE_FILL,
-    UNBOUNDED_SHOW_GLYPHS,
-    UNBOUNDED_MASK
-} unbounded_op_t;
-
-typedef struct {
-    unbounded_op_t op;
-    union {
-	unbounded_stroke_fill_t stroke_fill;
-	unbounded_show_glyphs_t show_glyphs;
-	unbounded_mask_t mask;
-    } u;
-} unbounded_op_data_t;
-
-static void
-_cairo_quartz_fixup_unbounded_operation (cairo_quartz_surface_t *surface,
-					 unbounded_op_data_t *op,
-					 cairo_antialias_t antialias)
-{
-    CGRect clipBox, clipBoxRound;
-    CGContextRef cgc;
-    CGImageRef maskImage;
-
-    clipBox = CGContextGetClipBoundingBox (surface->cgContext);
-    clipBoxRound = CGRectIntegral (clipBox);
-
-    cgc = CGBitmapContextCreate (NULL,
-				 clipBoxRound.size.width,
-				 clipBoxRound.size.height,
-				 8,
-				 (((size_t) clipBoxRound.size.width) + 15) & (~15),
-				 NULL,
-				 kCGImageAlphaOnly);
-
-    if (!cgc)
-	return;
-
-    _cairo_cgcontext_set_cairo_operator (cgc, CAIRO_OPERATOR_SOURCE);
-
-    /* We want to mask out whatever we just rendered, so we fill the
-     * surface opaque, and then we'll render transparent.
-     */
-    CGContextSetAlpha (cgc, 1.0f);
-    CGContextFillRect (cgc, CGRectMake (0, 0, clipBoxRound.size.width, clipBoxRound.size.height));
-
-    _cairo_cgcontext_set_cairo_operator (cgc, CAIRO_OPERATOR_CLEAR);
-    CGContextSetShouldAntialias (cgc, (antialias != CAIRO_ANTIALIAS_NONE));
-
-    CGContextTranslateCTM (cgc, -clipBoxRound.origin.x, -clipBoxRound.origin.y);
-
-    /* We need to either render the path that was given to us, or the glyph op */
-    if (op->op == UNBOUNDED_STROKE_FILL) {
-	CGContextBeginPath (cgc);
-	CGContextAddPath (cgc, op->u.stroke_fill.cgPath);
-
-	if (op->u.stroke_fill.fill_rule == CAIRO_FILL_RULE_WINDING)
-	    CGContextFillPath (cgc);
-	else
-	    CGContextEOFillPath (cgc);
-    } else if (op->op == UNBOUNDED_SHOW_GLYPHS) {
-	CGContextSetFont (cgc, op->u.show_glyphs.font);
-	CGContextSetFontSize (cgc, 1.0);
-	CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
-	CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
-	CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
-
-	if (op->u.show_glyphs.isClipping) {
-	    /* Note that the comment in show_glyphs about kCGTextClip
-	     * and the text transform still applies here; however, the
-	     * cg_advances we have were already transformed, so we
-	     * don't have to do anything. */
-	    CGContextSetTextDrawingMode (cgc, kCGTextClip);
-	    CGContextSaveGState (cgc);
-	}
-
-	CGContextShowGlyphsWithAdvances (cgc,
-					 op->u.show_glyphs.cg_glyphs,
-					 op->u.show_glyphs.cg_advances,
-					 op->u.show_glyphs.nglyphs);
-
-	if (op->u.show_glyphs.isClipping) {
-	    CGContextClearRect (cgc, clipBoxRound);
-	    CGContextRestoreGState (cgc);
-	}
-    } else if (op->op == UNBOUNDED_MASK) {
-	CGAffineTransform ctm = CGContextGetCTM (cgc);
-	CGContextSaveGState (cgc);
-	CGContextConcatCTM (cgc, op->u.mask.maskTransform);
-	CGContextClipToMask (cgc,
-			     CGRectMake (0.0,
-					 0.0,
-					 CGImageGetWidth (op->u.mask.mask),
-					 CGImageGetHeight (op->u.mask.mask)),
-			     op->u.mask.mask);
-	CGContextSetCTM (cgc, ctm);
-	CGContextClearRect (cgc, clipBoxRound);
-	CGContextRestoreGState (cgc);
-    }
-
-    /* Also mask out the portion of the clipbox that we rounded out, if any */
-    if (!CGRectEqualToRect (clipBox, clipBoxRound)) {
-	CGContextBeginPath (cgc);
-	CGContextAddRect (cgc, clipBoxRound);
-	CGContextAddRect (cgc, clipBox);
-	CGContextEOFillPath (cgc);
-    }
-
-    maskImage = CGBitmapContextCreateImage (cgc);
-    CGContextRelease (cgc);
-
-    if (!maskImage)
-	return;
-
-    /* Then render with the mask */
-    CGContextSaveGState (surface->cgContext);
-
-    _cairo_quartz_surface_set_cairo_operator (surface, CAIRO_OPERATOR_SOURCE);
-    CGContextClipToMask (surface->cgContext, clipBoxRound, maskImage);
-    CGImageRelease (maskImage);
-
-    /* Finally, clear out the entire clipping region through our mask */
-    CGContextClearRect (surface->cgContext, clipBoxRound);
-
-    CGContextRestoreGState (surface->cgContext);
-}
 
 /*
  * Source -> Quartz setup and finish functions
@@ -1124,18 +989,30 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
 
 /* State used during a drawing operation. */
 typedef struct {
+    /* The destination of the mask */
+    CGContextRef cgMaskContext;
+
+    /* The destination of the drawing of the source */
+    CGContextRef cgDrawContext;
+
+    /* Action type */
     cairo_quartz_action_t action;
 
+    /* Destination rect */
+    CGRect rect;
+
     /* Used with DO_SHADING, DO_IMAGE and DO_TILED_IMAGE */
     CGAffineTransform transform;
 
     /* Used with DO_IMAGE and DO_TILED_IMAGE */
     CGImageRef image;
-    CGRect imageRect;
 
     /* Used with DO_SHADING */
     CGShadingRef shading;
 
+    /* Temporary destination for unbounded operations */
+    CGLayerRef layer;
+    CGRect clipRect;
 } cairo_quartz_drawing_state_t;
 
 /*
@@ -1203,15 +1080,28 @@ _cairo_quartz_setup_gradient_source (cairo_quartz_drawing_state_t *state,
 }
 
 static cairo_int_status_t
-_cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
-			    cairo_quartz_surface_t *surface,
-			    cairo_operator_t op,
-			    const cairo_pattern_t *source)
+_cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
+			   cairo_quartz_surface_t       *surface,
+			   cairo_operator_t              op,
+			   const cairo_pattern_t        *source,
+			   cairo_clip_t                 *clip)
 {
+    cairo_bool_t needs_temp;
     cairo_status_t status;
 
+    state->layer = NULL;
     state->image = NULL;
     state->shading = NULL;
+    state->cgDrawContext = NULL;
+    state->cgMaskContext = NULL;
+
+    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_quartz_surface_set_cairo_operator (surface, op);
+    if (unlikely (status))
+	return status;
 
     /* Save before we change the pattern, colorspace, etc. so that
      * we can restore and make sure that quartz releases our
@@ -1219,22 +1109,62 @@ _cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
      */
 
     CGContextSaveGState (surface->cgContext);
+    state->clipRect = CGContextGetClipBoundingBox (surface->cgContext);
+    state->clipRect = CGRectIntegral (state->clipRect);
+    state->rect = state->clipRect;
 
-    status = _cairo_quartz_surface_set_cairo_operator (surface, op);
-    if (unlikely (status))
-	return status;
+    state->cgMaskContext = surface->cgContext;
+    state->cgDrawContext = state->cgMaskContext;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
+
+	state->action = DO_DIRECT;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    /*
+     * To implement mask unbounded operations Quartz needs a temporary
+     * surface which will be composited entirely (ignoring the mask).
+     * To implement source unbounded operations Quartz needs a
+     * temporary surface which allows extending the source to a size
+     * covering the whole mask, but there are some optimization
+     * opportunities:
+     *
+     * - CLEAR completely ignores the source, thus we can just use a
+     *   solid color fill.
+     *
+     * - SOURCE can be implemented by drawing the source and clearing
+     *   outside of the source as long as the two regions have no
+     *   intersection. This happens when the source is a pixel-aligned
+     *   rectangle. If the source is at least as big as the
+     *   intersection between the clip rectangle and the mask
+     *   rectangle, no clear operation is needed.
+     */
+    needs_temp = ! _cairo_operator_bounded_by_mask (op);
 
-    CGContextSetInterpolationQuality (surface->cgContext, _cairo_quartz_filter_to_quartz (source->filter));
+    if (needs_temp) {
+	state->layer = CGLayerCreateWithContext (surface->cgContext,
+						 state->clipRect.size,
+						 NULL);
+	state->cgDrawContext = CGLayerGetContext (state->layer);
+	state->cgMaskContext = state->cgDrawContext;
+	CGContextTranslateCTM (state->cgDrawContext,
+			       -state->clipRect.origin.x,
+			       -state->clipRect.origin.y);
+    }
+
+    CGContextSetInterpolationQuality (state->cgDrawContext, _cairo_quartz_filter_to_quartz (source->filter));
 
     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
 	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
 
-	CGContextSetRGBStrokeColor (surface->cgContext,
+	CGContextSetRGBStrokeColor (state->cgDrawContext,
 				    solid->color.red,
 				    solid->color.green,
 				    solid->color.blue,
 				    solid->color.alpha);
-	CGContextSetRGBFillColor (surface->cgContext,
+	CGContextSetRGBFillColor (state->cgDrawContext,
 				  solid->color.red,
 				  solid->color.green,
 				  solid->color.blue,
@@ -1277,8 +1207,6 @@ _cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
 	if (unlikely (img == NULL))
 	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
-	CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1);
-
 	state->image = img;
 
 	cairo_matrix_invert (&m);
@@ -1287,12 +1215,32 @@ _cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
 	is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
 	assert (is_bounded);
 
+	srcRect = CGRectMake (0, 0, extents.width, extents.height);
+
 	if (source->extend == CAIRO_EXTEND_NONE) {
-	    state->imageRect = CGRectMake (0, 0, extents.width, extents.height);
+	    int x, y;
+	    if (op == CAIRO_OPERATOR_SOURCE &&
+		(pat_surf->content == CAIRO_CONTENT_ALPHA ||
+		 ! _cairo_matrix_is_integer_translation (&m, &x, &y)))
+	    {
+		state->layer = CGLayerCreateWithContext (surface->cgContext,
+							 state->clipRect.size,
+							 NULL);
+		state->cgDrawContext = CGLayerGetContext (state->layer);
+		CGContextTranslateCTM (state->cgDrawContext,
+				       -state->clipRect.origin.x,
+				       -state->clipRect.origin.y);
+	    }
+
+	    CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
+
+	    state->rect = srcRect;
 	    state->action = DO_IMAGE;
 	    return CAIRO_STATUS_SUCCESS;
 	}
 
+	CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
+
 	/* Quartz seems to tile images at pixel-aligned regions only -- this
 	 * leads to seams if the image doesn't end up scaling to fill the
 	 * space exactly.  The CGPattern tiling approach doesn't have this
@@ -1300,10 +1248,9 @@ _cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
 	 * epsilon), and if not, fall back to the CGPattern type.
 	 */
 
-	xform = CGAffineTransformConcat (CGContextGetCTM (surface->cgContext),
+	xform = CGAffineTransformConcat (CGContextGetCTM (state->cgDrawContext),
 					 state->transform);
 
-	srcRect = CGRectMake (0, 0, extents.width, extents.height);
 	srcRect = CGRectApplyAffineTransform (srcRect, xform);
 
 	fw = _cairo_fixed_from_double (srcRect.size.width);
@@ -1322,7 +1269,7 @@ _cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
 
 	    srcRect = CGRectApplyAffineTransform (srcRect, xform);
 
-	    state->imageRect = srcRect;
+	    state->rect = srcRect;
 	    state->action = DO_TILED_IMAGE;
 	    return CAIRO_STATUS_SUCCESS;
 	}
@@ -1341,17 +1288,17 @@ _cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
 	    return status;
 
 	patternSpace = CGColorSpaceCreatePattern (NULL);
-	CGContextSetFillColorSpace (surface->cgContext, patternSpace);
-	CGContextSetFillPattern (surface->cgContext, pattern, &patternAlpha);
-	CGContextSetStrokeColorSpace (surface->cgContext, patternSpace);
-	CGContextSetStrokePattern (surface->cgContext, pattern, &patternAlpha);
+	CGContextSetFillColorSpace (state->cgDrawContext, patternSpace);
+	CGContextSetFillPattern (state->cgDrawContext, pattern, &patternAlpha);
+	CGContextSetStrokeColorSpace (state->cgDrawContext, patternSpace);
+	CGContextSetStrokePattern (state->cgDrawContext, pattern, &patternAlpha);
 	CGColorSpaceRelease (patternSpace);
 
 	/* Quartz likes to munge the pattern phase (as yet unexplained
 	 * why); force it to 0,0 as we've already baked in the correct
 	 * pattern translation into the pattern matrix
 	 */
-	CGContextSetPatternPhase (surface->cgContext, CGSizeMake (0, 0));
+	CGContextSetPatternPhase (state->cgDrawContext, CGSizeMake (0, 0));
 
 	CGPatternRelease (pattern);
 
@@ -1363,11 +1310,19 @@ _cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
 }
 
 static void
-_cairo_quartz_teardown_source (cairo_quartz_drawing_state_t *state,
-			       cairo_quartz_surface_t *surface)
-			       
+_cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state,
+			      cairo_quartz_surface_t       *surface)
 {
-    CGContextRestoreGState (surface->cgContext);
+    if (state->layer) {
+	CGContextDrawLayerInRect (surface->cgContext,
+				  state->clipRect,
+				  state->layer);
+	CGContextRelease (state->cgDrawContext);
+	CGLayerRelease (state->layer);
+    }
+
+    if (state->cgMaskContext)
+	CGContextRestoreGState (surface->cgContext);
 
     if (state->image)
 	CGImageRelease (state->image);
@@ -1376,45 +1331,46 @@ _cairo_quartz_teardown_source (cairo_quartz_drawing_state_t *state,
 	CGShadingRelease (state->shading);
 }
 
-static cairo_int_status_t
-_cairo_quartz_setup_source_safe (cairo_quartz_drawing_state_t *state,
-				 cairo_quartz_surface_t *surface,
-				 cairo_operator_t op,
-				 const cairo_pattern_t *source)
-{
-    cairo_int_status_t status;
-
-    status = _cairo_quartz_setup_source (state, surface, op, source);
-    if (unlikely (status))
-	_cairo_quartz_teardown_source (state, surface);
-
-    return status;
-}
-
 static void
-_cairo_quartz_draw_source (cairo_quartz_surface_t *surface, cairo_operator_t op, cairo_quartz_drawing_state_t *state)
+_cairo_quartz_draw_source (cairo_quartz_drawing_state_t *state,
+			   cairo_operator_t              op)
 {
-    CGContextConcatCTM (surface->cgContext, state->transform);
+    if (state->action == DO_DIRECT) {
+	CGContextFillRect (state->cgDrawContext, state->rect);
+	return;
+    }
+
+    CGContextConcatCTM (state->cgDrawContext, state->transform);
 
     if (state->action == DO_SHADING) {
-	CGContextDrawShading (surface->cgContext, state->shading);
+	CGContextDrawShading (state->cgDrawContext, state->shading);
 	return;
     }
 
-    CGContextTranslateCTM (surface->cgContext, 0, state->imageRect.size.height);
-    CGContextScaleCTM (surface->cgContext, 1, -1);
+    CGContextTranslateCTM (state->cgDrawContext, 0, state->rect.size.height);
+    CGContextScaleCTM (state->cgDrawContext, 1, -1);
 
     if (state->action == DO_IMAGE) {
-	CGContextDrawImage (surface->cgContext, state->imageRect, state->image);
-	if (!_cairo_operator_bounded_by_source (op)) {
-	    CGContextBeginPath (surface->cgContext);
-	    CGContextAddRect (surface->cgContext, state->imageRect);
-	    CGContextAddRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext));
-	    CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 0);
-	    CGContextEOFillPath (surface->cgContext);
+	CGContextDrawImage (state->cgDrawContext, state->rect, state->image);
+	if (op == CAIRO_OPERATOR_SOURCE &&
+	    state->cgDrawContext == state->cgMaskContext)
+	{
+	    CGContextBeginPath (state->cgDrawContext);
+	    CGContextAddRect (state->cgDrawContext, state->rect);
+
+	    CGContextTranslateCTM (state->cgDrawContext, 0, state->rect.size.height);
+	    CGContextScaleCTM (state->cgDrawContext, 1, -1);
+	    CGContextConcatCTM (state->cgDrawContext,
+				CGAffineTransformInvert (state->transform));
+
+	    CGContextAddRect (state->cgDrawContext, state->clipRect);
+
+	    CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 0);
+	    CGContextEOFillPath (state->cgDrawContext);
 	}
-    } else
-	CGContextDrawTiledImagePtr (surface->cgContext, state->imageRect, state->image);
+    } else {
+	CGContextDrawTiledImagePtr (state->cgDrawContext, state->rect, state->image);
+    }
 }
 
 
@@ -1768,24 +1724,14 @@ _cairo_quartz_surface_paint_cg (cairo_quartz_surface_t *surface,
     if (IS_EMPTY (surface))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
-    rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
     if (unlikely (rv))
-	return rv;
-
-    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source);
-    if (unlikely (rv))
-	return rv;
+	goto BAIL;
 
-    if (state.action == DO_DIRECT) {
-	CGContextFillRect (surface->cgContext, CGRectMake (surface->extents.x,
-							   surface->extents.y,
-							   surface->extents.width,
-							   surface->extents.height));
-    } else {
-	_cairo_quartz_draw_source (surface, op, &state);
-    }
+    _cairo_quartz_draw_source (&state, op);
 
-    _cairo_quartz_teardown_source (&state, surface);
+BAIL:
+    _cairo_quartz_teardown_state (&state, surface);
 
     ND ((stderr, "-- paint\n"));
     return rv;
@@ -1830,53 +1776,37 @@ _cairo_quartz_surface_fill_cg (cairo_quartz_surface_t *surface,
 {
     cairo_quartz_drawing_state_t state;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
-    CGPathRef path_for_unbounded = NULL;
 
     ND ((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
 
     if (IS_EMPTY (surface))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
-    rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (unlikely (rv))
-	return rv;
-
-    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source);
+    rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
     if (unlikely (rv))
-	return rv;
-
-    CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
+	goto BAIL;
 
-    _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext);
+    CGContextSetShouldAntialias (state.cgMaskContext, (antialias != CAIRO_ANTIALIAS_NONE));
 
-    if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr)
-	path_for_unbounded = CGContextCopyPathPtr (surface->cgContext);
+    _cairo_quartz_cairo_path_to_quartz_context (path, state.cgMaskContext);
 
     if (state.action == DO_DIRECT) {
+	assert (state.cgDrawContext == state.cgMaskContext);
 	if (fill_rule == CAIRO_FILL_RULE_WINDING)
-	    CGContextFillPath (surface->cgContext);
+	    CGContextFillPath (state.cgMaskContext);
 	else
-	    CGContextEOFillPath (surface->cgContext);
+	    CGContextEOFillPath (state.cgMaskContext);
     } else {
 	if (fill_rule == CAIRO_FILL_RULE_WINDING)
-	    CGContextClip (surface->cgContext);
+	    CGContextClip (state.cgMaskContext);
 	else
-	    CGContextEOClip (surface->cgContext);
+	    CGContextEOClip (state.cgMaskContext);
 
-	_cairo_quartz_draw_source (surface, op, &state);
+	_cairo_quartz_draw_source (&state, op);
     }
 
-    _cairo_quartz_teardown_source (&state, surface);
-
-    if (path_for_unbounded) {
-	unbounded_op_data_t ub;
-	ub.op = UNBOUNDED_STROKE_FILL;
-	ub.u.stroke_fill.cgPath = path_for_unbounded;
-	ub.u.stroke_fill.fill_rule = fill_rule;
-
-	_cairo_quartz_fixup_unbounded_operation (surface, &ub, antialias);
-	CGPathRelease (path_for_unbounded);
-    }
+BAIL:
+    _cairo_quartz_teardown_state (&state, surface);
 
     ND ((stderr, "-- fill\n"));
     return rv;
@@ -1934,27 +1864,26 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
     cairo_quartz_drawing_state_t state;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
     CGAffineTransform origCTM, strokeTransform;
-    CGPathRef path_for_unbounded = NULL;
 
     ND ((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type));
 
     if (IS_EMPTY (surface))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
-    rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
     if (unlikely (rv))
-	return rv;
+	goto BAIL;
 
     // Turning antialiasing off used to cause misrendering with
     // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels).
     // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases.
-    CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
-    CGContextSetLineWidth (surface->cgContext, style->line_width);
-    CGContextSetLineCap (surface->cgContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
-    CGContextSetLineJoin (surface->cgContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
-    CGContextSetMiterLimit (surface->cgContext, style->miter_limit);
+    CGContextSetShouldAntialias (state.cgMaskContext, (antialias != CAIRO_ANTIALIAS_NONE));
+    CGContextSetLineWidth (state.cgMaskContext, style->line_width);
+    CGContextSetLineCap (state.cgMaskContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
+    CGContextSetLineJoin (state.cgMaskContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
+    CGContextSetMiterLimit (state.cgMaskContext, style->miter_limit);
 
-    origCTM = CGContextGetCTM (surface->cgContext);
+    origCTM = CGContextGetCTM (state.cgMaskContext);
 
     if (style->dash && style->num_dashes) {
 	cairo_quartz_float_t sdash[CAIRO_STACK_ARRAY_LENGTH (cairo_quartz_float_t)];
@@ -1966,61 +1895,38 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
 	    max_dashes *= 2;
 	if (max_dashes > ARRAY_LENGTH (sdash))
 	    fdash = _cairo_malloc_ab (max_dashes, sizeof (cairo_quartz_float_t));
-	if (unlikely (fdash == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	if (unlikely (fdash == NULL)) {
+	    rv = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto BAIL;
+	}
 
 	for (k = 0; k < max_dashes; k++)
 	    fdash[k] = (cairo_quartz_float_t) style->dash[k % style->num_dashes];
 
-	CGContextSetLineDash (surface->cgContext, style->dash_offset, fdash, max_dashes);
+	CGContextSetLineDash (state.cgMaskContext, style->dash_offset, fdash, max_dashes);
 	if (fdash != sdash)
 	    free (fdash);
     } else
-	CGContextSetLineDash (surface->cgContext, 0, NULL, 0);
-
-    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source);
-    if (unlikely (rv))
-	return rv;
-
-    _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext);
+	CGContextSetLineDash (state.cgMaskContext, 0, NULL, 0);
 
-    if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr)
-	path_for_unbounded = CGContextCopyPathPtr (surface->cgContext);
+    _cairo_quartz_cairo_path_to_quartz_context (path, state.cgMaskContext);
 
     _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform);
-    CGContextConcatCTM (surface->cgContext, strokeTransform);
+    CGContextConcatCTM (state.cgMaskContext, strokeTransform);
 
     if (state.action == DO_DIRECT) {
-	CGContextStrokePath (surface->cgContext);
+	assert (state.cgDrawContext == state.cgMaskContext);
+	CGContextStrokePath (state.cgMaskContext);
     } else {
-	CGContextReplacePathWithStrokedPath (surface->cgContext);
-	CGContextClip (surface->cgContext);
+	CGContextReplacePathWithStrokedPath (state.cgMaskContext);
+	CGContextClip (state.cgMaskContext);
 
-	CGContextSetCTM (surface->cgContext, origCTM);
-	_cairo_quartz_draw_source (surface, op, &state);
+	CGContextSetCTM (state.cgMaskContext, origCTM);
+	_cairo_quartz_draw_source (&state, op);
     }
 
-    _cairo_quartz_teardown_source (&state, surface);
-
-    if (path_for_unbounded) {
-	unbounded_op_data_t ub;
-	ub.op = UNBOUNDED_STROKE_FILL;
-	ub.u.stroke_fill.fill_rule = CAIRO_FILL_RULE_WINDING;
-
-	CGContextBeginPath (surface->cgContext);
-	CGContextAddPath (surface->cgContext, path_for_unbounded);
-	CGPathRelease (path_for_unbounded);
-
-	CGContextSaveGState (surface->cgContext);
-	CGContextConcatCTM (surface->cgContext, strokeTransform);
-	CGContextReplacePathWithStrokedPath (surface->cgContext);
-	CGContextRestoreGState (surface->cgContext);
-
-	ub.u.stroke_fill.cgPath = CGContextCopyPathPtr (surface->cgContext);
-
-	_cairo_quartz_fixup_unbounded_operation (surface, &ub, antialias);
-	CGPathRelease (ub.u.stroke_fill.cgPath);
-    }
+BAIL:
+    _cairo_quartz_teardown_state (&state, surface);
 
     ND ((stderr, "-- stroke\n"));
     return rv;
@@ -2086,7 +1992,6 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
     int i;
     CGFontRef cgfref = NULL;
 
-    cairo_bool_t isClipping = FALSE;
     cairo_bool_t didForceFontSmoothing = FALSE;
 
     if (IS_EMPTY (surface))
@@ -2098,43 +2003,39 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (unlikely (rv))
-	return rv;
-
-    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source);
+    rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
     if (unlikely (rv))
-	return rv;
+	goto BAIL;
 
     if (state.action == DO_DIRECT) {
-	CGContextSetTextDrawingMode (surface->cgContext, kCGTextFill);
+	assert (state.cgDrawContext == state.cgMaskContext);
+	CGContextSetTextDrawingMode (state.cgMaskContext, kCGTextFill);
     } else {
-	CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip);
-	isClipping = TRUE;
+	CGContextSetTextDrawingMode (state.cgMaskContext, kCGTextClip);
     }
 
     /* this doesn't addref */
     cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font);
-    CGContextSetFont (surface->cgContext, cgfref);
-    CGContextSetFontSize (surface->cgContext, 1.0);
+    CGContextSetFont (state.cgMaskContext, cgfref);
+    CGContextSetFontSize (state.cgMaskContext, 1.0);
 
     switch (scaled_font->options.antialias) {
 	case CAIRO_ANTIALIAS_SUBPIXEL:
-	    CGContextSetShouldAntialias (surface->cgContext, TRUE);
-	    CGContextSetShouldSmoothFonts (surface->cgContext, TRUE);
+	    CGContextSetShouldAntialias (state.cgMaskContext, TRUE);
+	    CGContextSetShouldSmoothFonts (state.cgMaskContext, TRUE);
 	    if (CGContextSetAllowsFontSmoothingPtr &&
-		!CGContextGetAllowsFontSmoothingPtr (surface->cgContext))
+		!CGContextGetAllowsFontSmoothingPtr (state.cgMaskContext))
 	    {
 		didForceFontSmoothing = TRUE;
-		CGContextSetAllowsFontSmoothingPtr (surface->cgContext, TRUE);
+		CGContextSetAllowsFontSmoothingPtr (state.cgMaskContext, TRUE);
 	    }
 	    break;
 	case CAIRO_ANTIALIAS_NONE:
-	    CGContextSetShouldAntialias (surface->cgContext, FALSE);
+	    CGContextSetShouldAntialias (state.cgMaskContext, FALSE);
 	    break;
 	case CAIRO_ANTIALIAS_GRAY:
-	    CGContextSetShouldAntialias (surface->cgContext, TRUE);
-	    CGContextSetShouldSmoothFonts (surface->cgContext, FALSE);
+	    CGContextSetShouldAntialias (state.cgMaskContext, TRUE);
+	    CGContextSetShouldSmoothFonts (state.cgMaskContext, FALSE);
 	    break;
 	case CAIRO_ANTIALIAS_DEFAULT:
 	    /* Don't do anything */
@@ -2158,7 +2059,7 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
 					   0, 0);
     _cairo_quartz_cairo_matrix_to_quartz (&scaled_font->scale_inverse, &invTextTransform);
 
-    CGContextSetTextMatrix (surface->cgContext, CGAffineTransformIdentity);
+    CGContextSetTextMatrix (state.cgMaskContext, CGAffineTransformIdentity);
 
     /* Convert our glyph positions to glyph advances.  We need n-1 advances,
      * since the advance at index 0 is applied after glyph 0. */
@@ -2177,43 +2078,25 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
     }
 
     /* Translate to the first glyph's position before drawing */
-    ctm = CGContextGetCTM (surface->cgContext);
-    CGContextTranslateCTM (surface->cgContext, glyphs[0].x, glyphs[0].y);
-    CGContextConcatCTM (surface->cgContext, textTransform);
+    ctm = CGContextGetCTM (state.cgMaskContext);
+    CGContextTranslateCTM (state.cgMaskContext, glyphs[0].x, glyphs[0].y);
+    CGContextConcatCTM (state.cgMaskContext, textTransform);
 
-    CGContextShowGlyphsWithAdvances (surface->cgContext,
+    CGContextShowGlyphsWithAdvances (state.cgMaskContext,
 				     cg_glyphs,
 				     cg_advances,
 				     num_glyphs);
 
-    CGContextSetCTM (surface->cgContext, ctm);
+    CGContextSetCTM (state.cgMaskContext, ctm);
 
     if (state.action != DO_DIRECT)
-	_cairo_quartz_draw_source (surface, op, &state);
+	_cairo_quartz_draw_source (&state, op);
 
 BAIL:
-    _cairo_quartz_teardown_source (&state, surface);
-
     if (didForceFontSmoothing)
-	CGContextSetAllowsFontSmoothingPtr (surface->cgContext, FALSE);
-
-    if (rv == CAIRO_STATUS_SUCCESS &&
-	cgfref &&
-	!_cairo_operator_bounded_by_mask (op))
-    {
-	unbounded_op_data_t ub;
-	ub.op = UNBOUNDED_SHOW_GLYPHS;
+	CGContextSetAllowsFontSmoothingPtr (state.cgMaskContext, FALSE);
 
-	ub.u.show_glyphs.isClipping = isClipping;
-	ub.u.show_glyphs.cg_glyphs = cg_glyphs;
-	ub.u.show_glyphs.cg_advances = cg_advances;
-	ub.u.show_glyphs.nglyphs = num_glyphs;
-	ub.u.show_glyphs.textTransform = textTransform;
-	ub.u.show_glyphs.font = cgfref;
-	ub.u.show_glyphs.origin = CGPointMake (glyphs[0].x, glyphs[0].y);
-
-	_cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias);
-    }
+    _cairo_quartz_teardown_state (&state, surface);
 
     if (cg_glyphs != glyphs_static)
 	free (cg_glyphs);
@@ -2271,45 +2154,42 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
     cairo_surface_t *pat_surf = mask->surface;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     CGAffineTransform ctm, mask_matrix;
+    cairo_quartz_drawing_state_t state;
+
+    if (IS_EMPTY (surface))
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
     status = _cairo_surface_to_cgimage (pat_surf, &img);
     if (unlikely (status))
 	return status;
-    if (unlikely (img == NULL)) {
-	if (!_cairo_operator_bounded_by_mask (op))
-	    CGContextClearRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext));
-	return CAIRO_STATUS_SUCCESS;
-    }
 
-    rect = CGRectMake (0.0f, 0.0f, CGImageGetWidth (img) , CGImageGetHeight (img));
+    status = _cairo_quartz_setup_state (&state, surface, op, source, clip);
+    if (unlikely (status))
+	goto BAIL;
 
-    CGContextSaveGState (surface->cgContext);
+    if (unlikely (img == NULL))
+	goto BAIL;
+
+    rect = CGRectMake (0.0f, 0.0f, CGImageGetWidth (img) , CGImageGetHeight (img));
 
     /* 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);
+    ctm = CGContextGetCTM (state.cgMaskContext);
 
     _cairo_quartz_cairo_matrix_to_quartz (&mask->base.matrix, &mask_matrix);
     mask_matrix = CGAffineTransformInvert (mask_matrix);
     mask_matrix = CGAffineTransformTranslate (mask_matrix, 0.0, CGImageGetHeight (img));
     mask_matrix = CGAffineTransformScale (mask_matrix, 1.0, -1.0);
 
-    CGContextConcatCTM (surface->cgContext, mask_matrix);
-    CGContextClipToMask (surface->cgContext, rect, img);
+    CGContextConcatCTM (state.cgMaskContext, mask_matrix);
+    CGContextClipToMask (state.cgMaskContext, rect, img);
 
-    CGContextSetCTM (surface->cgContext, ctm);
+    CGContextSetCTM (state.cgMaskContext, ctm);
 
-    status = _cairo_quartz_surface_paint_cg (surface, op, source, clip);
+    _cairo_quartz_draw_source (&state, op);
 
-    CGContextRestoreGState (surface->cgContext);
-
-    if (!_cairo_operator_bounded_by_mask (op)) {
-	unbounded_op_data_t ub;
-	ub.op = UNBOUNDED_MASK;
-	ub.u.mask.mask = img;
-	ub.u.mask.maskTransform = mask_matrix;
-	_cairo_quartz_fixup_unbounded_operation (surface, &ub, CAIRO_ANTIALIAS_NONE);
-    }
+BAIL:
+    _cairo_quartz_teardown_state (&state, surface);
 
     CGImageRelease (img);
 
@@ -2340,7 +2220,11 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
     if (unlikely (status))
 	goto BAIL;
 
-    status = _cairo_quartz_surface_paint (gradient_surf, CAIRO_OPERATOR_SOURCE, mask, NULL);
+    /* gradient_surf is clear, thus we can use OVER instead of SOURCE
+     * to make sure we won't have to create a temporary layer or
+     * fallback.
+     */
+    status = _cairo_quartz_surface_paint (gradient_surf, CAIRO_OPERATOR_OVER, mask, NULL);
     if (unlikely (status))
 	goto BAIL;
 
@@ -2355,32 +2239,47 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
 }
 
 static cairo_int_status_t
+_cairo_quartz_surface_mask_with_solid (cairo_quartz_surface_t *surface,
+				       cairo_operator_t        op,
+				       const cairo_pattern_t  *source,
+				       double                  alpha,
+				       cairo_clip_t *clip)
+{
+    cairo_quartz_drawing_state_t state;
+    cairo_status_t status;
+
+    status = _cairo_quartz_setup_state (&state, surface, op, source, clip);
+    if (unlikely (status))
+	goto BAIL;
+
+    CGContextSetAlpha (surface->cgContext, alpha);
+    _cairo_quartz_draw_source (&state, op);
+
+BAIL:
+    _cairo_quartz_teardown_state (&state, surface);
+
+    return status;
+}
+
+static cairo_int_status_t
 _cairo_quartz_surface_mask_cg (cairo_quartz_surface_t *surface,
 			       cairo_operator_t op,
 			       const cairo_pattern_t *source,
 			       const cairo_pattern_t *mask,
 			       cairo_clip_t *clip)
 {
-    cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
-
     ND ((stderr, "%p _cairo_quartz_surface_mask op %d source->type %d mask->type %d\n", surface, op, source->type, mask->type));
 
     if (IS_EMPTY (surface))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
-    rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (unlikely (rv))
-	return rv;
-
     if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
-	/* This is easy; we just need to paint with the alpha. */
-	cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
+	const cairo_solid_pattern_t *mask_solid;
 
-	CGContextSetAlpha (surface->cgContext, solid_mask->color.alpha);
-	rv = _cairo_quartz_surface_paint_cg (surface, op, source, clip);
-	CGContextSetAlpha (surface->cgContext, 1.0);
-
-	return rv;
+	mask_solid = (const cairo_solid_pattern_t *) mask;
+	return _cairo_quartz_surface_mask_with_solid (surface, op, source,
+						      mask_solid->color.alpha,
+						      clip);
     }
 
     /* For these, we can skip creating a temporary surface, since we already have one */
commit d7e3637af2ce31c35281c87c4ca064322de0d948
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Sat Jan 1 23:16:11 2011 +0100

    quartz: Cleanup extents computation
    
    All the draw operations use the same code to compute the gradient
    parameter range. It can be moved to the function which sets up the
    source.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 5f84c65..f2fdb63 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1206,8 +1206,7 @@ static cairo_int_status_t
 _cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
 			    cairo_quartz_surface_t *surface,
 			    cairo_operator_t op,
-			    const cairo_pattern_t *source,
-			    const cairo_rectangle_int_t *extents)
+			    const cairo_pattern_t *source)
 {
     cairo_status_t status;
 
@@ -1249,7 +1248,14 @@ _cairo_quartz_setup_source (cairo_quartz_drawing_state_t *state,
 	source->type == CAIRO_PATTERN_TYPE_RADIAL)
     {
 	const cairo_gradient_pattern_t *gpat = (const cairo_gradient_pattern_t *)source;
-	return _cairo_quartz_setup_gradient_source (state, gpat, extents);
+	cairo_rectangle_int_t extents;
+
+	extents = surface->virtual_extents;
+	extents.x -= surface->base.device_transform.x0;
+	extents.y -= surface->base.device_transform.y0;
+	_cairo_rectangle_union (&extents, &surface->extents);
+
+	return _cairo_quartz_setup_gradient_source (state, gpat, &extents);
     }
 
     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
@@ -1374,12 +1380,11 @@ static cairo_int_status_t
 _cairo_quartz_setup_source_safe (cairo_quartz_drawing_state_t *state,
 				 cairo_quartz_surface_t *surface,
 				 cairo_operator_t op,
-				 const cairo_pattern_t *source,
-				 const cairo_rectangle_int_t *extents)
+				 const cairo_pattern_t *source)
 {
     cairo_int_status_t status;
 
-    status = _cairo_quartz_setup_source (state, surface, op, source, extents);
+    status = _cairo_quartz_setup_source (state, surface, op, source);
     if (unlikely (status))
 	_cairo_quartz_teardown_source (state, surface);
 
@@ -1757,7 +1762,6 @@ _cairo_quartz_surface_paint_cg (cairo_quartz_surface_t *surface,
 {
     cairo_quartz_drawing_state_t state;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
-    cairo_rectangle_int_t extents;
 
     ND ((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
 
@@ -1768,11 +1772,7 @@ _cairo_quartz_surface_paint_cg (cairo_quartz_surface_t *surface,
     if (unlikely (rv))
 	return rv;
 
-    extents = surface->virtual_extents;
-    extents.x -= surface->base.device_transform.x0;
-    extents.y -= surface->base.device_transform.y0;
-    _cairo_rectangle_union (&extents, &surface->extents);
-    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source, &extents);
+    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source);
     if (unlikely (rv))
 	return rv;
 
@@ -1831,7 +1831,6 @@ _cairo_quartz_surface_fill_cg (cairo_quartz_surface_t *surface,
     cairo_quartz_drawing_state_t state;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
     CGPathRef path_for_unbounded = NULL;
-    cairo_rectangle_int_t extents;
 
     ND ((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
 
@@ -1842,11 +1841,7 @@ _cairo_quartz_surface_fill_cg (cairo_quartz_surface_t *surface,
     if (unlikely (rv))
 	return rv;
 
-    extents = surface->virtual_extents;
-    extents.x -= surface->base.device_transform.x0;
-    extents.y -= surface->base.device_transform.y0;
-    _cairo_rectangle_union (&extents, &surface->extents);
-    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source, &extents);
+    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source);
     if (unlikely (rv))
 	return rv;
 
@@ -1940,7 +1935,6 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
     CGAffineTransform origCTM, strokeTransform;
     CGPathRef path_for_unbounded = NULL;
-    cairo_rectangle_int_t extents;
 
     ND ((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type));
 
@@ -1984,11 +1978,7 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
     } else
 	CGContextSetLineDash (surface->cgContext, 0, NULL, 0);
 
-    extents = surface->virtual_extents;
-    extents.x -= surface->base.device_transform.x0;
-    extents.y -= surface->base.device_transform.y0;
-    _cairo_rectangle_union (&extents, &surface->extents);
-    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source, &extents);
+    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source);
     if (unlikely (rv))
 	return rv;
 
@@ -2091,7 +2081,6 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
     COMPILE_TIME_ASSERT (sizeof (CGGlyph) <= sizeof (CGSize));
 
     cairo_quartz_drawing_state_t state;
-    cairo_rectangle_int_t extents;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
     cairo_quartz_float_t xprev, yprev;
     int i;
@@ -2113,11 +2102,7 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
     if (unlikely (rv))
 	return rv;
 
-    extents = surface->virtual_extents;
-    extents.x -= surface->base.device_transform.x0;
-    extents.y -= surface->base.device_transform.y0;
-    _cairo_rectangle_union (&extents, &surface->extents);
-    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source, &extents);
+    rv = _cairo_quartz_setup_source_safe (&state, surface, op, source);
     if (unlikely (rv))
 	return rv;
 
commit aa2fb0c05fefeea97a2d72f882a6b2c40d98af39
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Sat Jan 1 22:36:45 2011 +0100

    quartz: Do not use opaque patterns as masks
    
    When an opaque surface is used as a mask, Quartz converts it to
    greyscale and uses the result as an alpha value. Cairo expects the
    mask operation to ignore the color components and only use the alpha
    of the pattern.
    
    The expected behavior can be achieved by drawing the mask on a
    temporary surface with an alpha channel.
    
    Fixes clear-source.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index e8ac7f6..5f84c65 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -2399,8 +2399,12 @@ _cairo_quartz_surface_mask_cg (cairo_quartz_surface_t *surface,
     }
 
     /* For these, we can skip creating a temporary surface, since we already have one */
-    if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && mask->extend == CAIRO_EXTEND_NONE)
-	return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask, clip);
+    if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && mask->extend == CAIRO_EXTEND_NONE) {
+	const cairo_surface_pattern_t *mask_spat =  (const cairo_surface_pattern_t *) mask;
+
+	if (mask_spat->surface->content & CAIRO_CONTENT_ALPHA)
+	    return _cairo_quartz_surface_mask_with_surface (surface, op, source, mask_spat, clip);
+    }
 
     return _cairo_quartz_surface_mask_with_generic (surface, op, source, mask, clip);
 }
commit 7d89d69c494bb438ca1caddf1a2226a48297e4b6
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Wed Jan 5 12:15:06 2011 +0100

    quartz: Make huge domain handling more stable
    
    Quartz cannot correctly handle arbitrary domains. Falling back is
    needed to get correct results on very large (in parameter space)
    gradients.
    
    For PAD extended gradients, limiting the domain to (at most) [-0.5,
    1.5] is sufficient to guarantee that it will correctly sample the
    extreme stops and improves the accuracy (over having a much bigger
    domain).
    
    Fixes radial-gradient, radial-gradient-mask, radial-gradient-source,
    radial-gradient-mask-source, radial-gradient-one-stop.
    
    Improves the quality of the linear gradients in linear-gradient,
    linear-gradient-subset, mask, operator-source, trap-clip.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index cacfeef..e8ac7f6 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -831,6 +831,11 @@ static const CGFunctionCallbacks gradient_callbacks = {
     0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy
 };
 
+/* Quartz computes a small number of samples of the gradient color
+ * function. On MacOS X 10.5 it apparently computes only 1024
+ * samples. */
+#define MAX_GRADIENT_RANGE 1024
+
 static CGFunctionRef
 _cairo_quartz_create_gradient_function (const cairo_gradient_pattern_t *gradient,
 					const cairo_rectangle_int_t *extents,
@@ -862,6 +867,12 @@ _cairo_quartz_create_gradient_function (const cairo_gradient_pattern_t *gradient
 						  tolerance,
 						  t);
 
+	if (gradient->base.extend == CAIRO_EXTEND_PAD) {
+	    t[0] = MAX (t[0], -0.5);
+	    t[1] = MIN (t[1],  1.5);
+	} else if (t[1] - t[0] > MAX_GRADIENT_RANGE)
+	    return NULL;
+
 	/* set the input range for the function -- the function knows how
 	   to map values outside of 0.0 .. 1.0 to the correct color */
 	input_value_range[0] = t[0];
@@ -875,8 +886,6 @@ _cairo_quartz_create_gradient_function (const cairo_gradient_pattern_t *gradient
     _cairo_gradient_pattern_interpolate (gradient, input_value_range[1], end);
 
     if (_cairo_pattern_create_copy (&pat, &gradient->base))
-	/* quartz doesn't deal very well with malloc failing, so there's
-	 * not much point in us trying either */
 	return NULL;
 
     return CGFunctionCreate (pat,
@@ -1156,13 +1165,16 @@ _cairo_quartz_setup_gradient_source (cairo_quartz_drawing_state_t *state,
     cairo_matrix_invert (&mat);
     _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform);
 
-    rgb = CGColorSpaceCreateDeviceRGB ();
-
     gradFunc = _cairo_quartz_create_gradient_function (gradient,
 						       extents,
 						       &start,
 						       &end);
 
+    if (unlikely (gradFunc == NULL))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    rgb = CGColorSpaceCreateDeviceRGB ();
+
     if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
 	state->shading = CGShadingCreateAxial (rgb,
 					       CGPointMake (start.center.x,
commit 4874dab984fe73ae687b354aff45b879e1de9db2
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Sat Jan 1 22:57:27 2011 +0100

    quartz: Use standard stack allocation size
    
    Make cairo-quartz respect the convention that stack-allocated data
    structures use the size computed by CAIRO_STACK_ARRAY_LENGTH ().
    
    Additionally this increases the size of the dash and glyph arrays,
    making dynamic memory allocation less likely.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index d29eef0..cacfeef 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1951,15 +1951,14 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
     origCTM = CGContextGetCTM (surface->cgContext);
 
     if (style->dash && style->num_dashes) {
-#define STATIC_DASH 32
-	cairo_quartz_float_t sdash[STATIC_DASH];
+	cairo_quartz_float_t sdash[CAIRO_STACK_ARRAY_LENGTH (cairo_quartz_float_t)];
 	cairo_quartz_float_t *fdash = sdash;
 	unsigned int max_dashes = style->num_dashes;
 	unsigned int k;
 
 	if (style->num_dashes%2)
 	    max_dashes *= 2;
-	if (max_dashes > STATIC_DASH)
+	if (max_dashes > ARRAY_LENGTH (sdash))
 	    fdash = _cairo_malloc_ab (max_dashes, sizeof (cairo_quartz_float_t));
 	if (unlikely (fdash == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -2073,11 +2072,11 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
 				      int *remaining_glyphs)
 {
     CGAffineTransform textTransform, ctm, invTextTransform;
-#define STATIC_BUF_SIZE 64
-    CGGlyph glyphs_static[STATIC_BUF_SIZE];
-    CGSize cg_advances_static[STATIC_BUF_SIZE];
+    CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
+    CGSize cg_advances_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
     CGGlyph *cg_glyphs = &glyphs_static[0];
     CGSize *cg_advances = &cg_advances_static[0];
+    COMPILE_TIME_ASSERT (sizeof (CGGlyph) <= sizeof (CGSize));
 
     cairo_quartz_drawing_state_t state;
     cairo_rectangle_int_t extents;
@@ -2145,18 +2144,14 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
 	    break;
     }
 
-    if (num_glyphs > STATIC_BUF_SIZE) {
-	cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof (CGGlyph));
+    if (num_glyphs > ARRAY_LENGTH (glyphs_static)) {
+	cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof (CGGlyph) + sizeof (CGSize));
 	if (unlikely (cg_glyphs == NULL)) {
 	    rv = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    goto BAIL;
 	}
 
-	cg_advances = (CGSize*) _cairo_malloc_ab (num_glyphs, sizeof (CGSize));
-	if (unlikely (cg_advances == NULL)) {
-	    rv = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto BAIL;
-	}
+	cg_advances = (CGSize*) (cg_glyphs + num_glyphs);
     }
 
     textTransform = CGAffineTransformMake (scaled_font->scale.xx,
@@ -2223,9 +2218,6 @@ BAIL:
 	_cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias);
     }
 
-    if (cg_advances != cg_advances_static)
-	free (cg_advances);
-
     if (cg_glyphs != glyphs_static)
 	free (cg_glyphs);
 
commit 5a1e590b122d99ad91ba104b8fc68e8adaa2d6cd
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Sat Jan 8 00:56:38 2011 +0100

    test: Update quartz ref images
    
    The following commits fix and/or improve the output of some tests.
    Updating the ref images before fixing the code allows to check that
    the fix is correct and makes it easy to find out which tests are fixed
    by each commit.

diff --git a/test/Makefile.am b/test/Makefile.am
index e96d528..1648dd8 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -127,21 +127,24 @@ CLEANFILES += $(BUILT_SOURCES)
 REFERENCE_IMAGES = \
 	a1-bug.ref.png \
 	a1-bug.image16.ref.png \
+	a1-bug.quartz.xfail.png \
 	a1-bug.xlib.ref.png \
 	a1-image-sample.ref.png \
 	a1-image-sample.gl.xfail.png \
-	a1-image-sample.quartz.xfail.png \
 	a1-mask.ref.png \
 	a1-mask-sample.ref.png \
-	a1-mask-sample.quartz.xfail.png \
 	a1-rasterisation-rectangles.ref.png \
+	a1-rasterisation-rectangles.quartz.xfail.png \
 	a1-rasterisation-triangles.ref.png \
+	a1-rasterisation-triangles.quartz.xfail.png \
 	a1-traps-sample.ref.png \
 	a1-traps-sample.quartz.xfail.png \
 	a8-clear.ref.png \
+	a8-clear.quartz.ref.png \
 	a8-mask.ref.png \
 	aliasing.ref.png \
 	aliasing.image16.ref.png \
+	aliasing.quartz.ref.png \
 	aliasing.xlib.ref.png \
 	alpha-similar.gl.argb32.xfail.png \
 	alpha-similar.gl.rgb24.xfail.png \
@@ -614,7 +617,6 @@ REFERENCE_IMAGES = \
 	filter-nearest-offset.pdf.xfail.png \
 	filter-nearest-offset.ps2.ref.png \
 	filter-nearest-offset.ps3.ref.png \
-	filter-nearest-offset.quartz.xfail.png \
 	filter-nearest-offset.ref.png \
 	filter-nearest-offset.svg.xfail.png \
 	filter-nearest-transformed.image16.ref.png \
@@ -964,6 +966,8 @@ REFERENCE_IMAGES = \
 	overlapping-glyphs.rgb24.ref.png \
 	overlapping-glyphs.pdf.argb32.xfail.png \
 	overlapping-glyphs.pdf.rgb24.xfail.png \
+	overlapping-glyphs.quartz.argb32.ref.png \
+	overlapping-glyphs.quartz.rgb24.ref.png \
 	overlapping-glyphs.svg.rgb24.ref.png \
 	overlapping-glyphs.svg.argb32.ref.png \
 	paint-repeat.ref.png \
@@ -976,6 +980,7 @@ REFERENCE_IMAGES = \
 	paint.ref.png \
 	partial-clip-text.ref.png \
 	partial-clip-text.ps.ref.png \
+	partial-clip-text.quartz.ref.png \
 	partial-clip-text.svg.ref.png \
 	partial-coverage-half-reference.ref.png \
 	partial-coverage-half-triangles.ref.png \
@@ -1046,19 +1051,26 @@ REFERENCE_IMAGES = \
 	quartz-surface-source.ps3.ref.png \
 	radial-gradient.image16.ref.png \
 	radial-gradient.ref.png \
+	radial-gradient.quartz.ref.png \
 	radial-gradient-extend.ps3.ref.png \
 	radial-gradient-extend.ref.png \
 	radial-gradient-source.image16.ref.png \
 	radial-gradient-source.argb32.ref.png \
 	radial-gradient-source.rgb24.ref.png \
+	radial-gradient-source.quartz.argb32.ref.png \
+	radial-gradient-source.quartz.rgb24.ref.png \
 	radial-gradient-mask.ref.png \
 	radial-gradient-mask.image16.ref.png \
+	radial-gradient-mask.quartz.ref.png \
 	radial-gradient-mask-source.argb32.ref.png \
 	radial-gradient-mask-source.rgb24.ref.png \
 	radial-gradient-mask-source.image16.ref.png \
+	radial-gradient-mask-source.quartz.argb32.ref.png \
+	radial-gradient-mask-source.quartz.rgb24.ref.png \
 	radial-gradient-mask-source.xlib.argb32.ref.png \
 	radial-gradient-mask-source.xlib.rgb24.ref.png \
 	radial-gradient-one-stop.ref.png \
+	radial-gradient-one-stop.quartz.ref.png \
 	random-intersections-eo.image16.ref.png \
 	random-intersections-eo.ps.ref.png \
 	random-intersections-eo.quartz.ref.png \
@@ -1285,8 +1297,8 @@ REFERENCE_IMAGES = \
 	surface-pattern-operator.xlib.rgb24.ref.png \
 	surface-pattern-operator.pdf.argb32.xfail.png \
 	surface-pattern-operator.pdf.rgb24.xfail.png \
-	surface-pattern-operator.quartz.argb32.xfail.png \
-	surface-pattern-operator.quartz.rgb24.xfail.png \
+	surface-pattern-operator.quartz.argb32.ref.png \
+	surface-pattern-operator.quartz.rgb24.ref.png \
 	surface-pattern-scale-down.image16.ref.png \
 	surface-pattern-scale-down.pdf.ref.png \
 	surface-pattern-scale-down.ps2.ref.png \
@@ -1397,6 +1409,8 @@ REFERENCE_IMAGES = \
 	unbounded-operator.pdf.argb32.ref.png \
 	unbounded-operator.ps2.argb32.ref.png \
 	unbounded-operator.ps3.argb32.ref.png \
+	unbounded-operator.quartz.argb32.ref.png \
+	unbounded-operator.quartz.rgb24.ref.png \
 	unbounded-operator.ref.png \
 	unbounded-operator.rgb24.ref.png \
 	unbounded-operator.svg12.argb32.ref.png \
diff --git a/test/a1-bug.quartz.xfail.png b/test/a1-bug.quartz.xfail.png
new file mode 100644
index 0000000..4ed3793
Binary files /dev/null and b/test/a1-bug.quartz.xfail.png differ
diff --git a/test/a1-image-sample.quartz.xfail.png b/test/a1-image-sample.quartz.xfail.png
deleted file mode 100644
index ca24391..0000000
Binary files a/test/a1-image-sample.quartz.xfail.png and /dev/null differ
diff --git a/test/a1-mask-sample.quartz.xfail.png b/test/a1-mask-sample.quartz.xfail.png
deleted file mode 100644
index ca24391..0000000
Binary files a/test/a1-mask-sample.quartz.xfail.png and /dev/null differ
diff --git a/test/a1-rasterisation-rectangles.quartz.xfail.png b/test/a1-rasterisation-rectangles.quartz.xfail.png
new file mode 100644
index 0000000..f8f3bf8
Binary files /dev/null and b/test/a1-rasterisation-rectangles.quartz.xfail.png differ
diff --git a/test/a1-rasterisation-triangles.quartz.xfail.png b/test/a1-rasterisation-triangles.quartz.xfail.png
new file mode 100644
index 0000000..f8f3bf8
Binary files /dev/null and b/test/a1-rasterisation-triangles.quartz.xfail.png differ
diff --git a/test/a8-clear.quartz.ref.png b/test/a8-clear.quartz.ref.png
new file mode 100644
index 0000000..5b7c67f
Binary files /dev/null and b/test/a8-clear.quartz.ref.png differ
diff --git a/test/aliasing.quartz.ref.png b/test/aliasing.quartz.ref.png
new file mode 100644
index 0000000..f4b6e22
Binary files /dev/null and b/test/aliasing.quartz.ref.png differ
diff --git a/test/clip-fill-eo-unbounded.quartz.argb32.ref.png b/test/clip-fill-eo-unbounded.quartz.argb32.ref.png
index 2ea24a3..3423000 100644
Binary files a/test/clip-fill-eo-unbounded.quartz.argb32.ref.png and b/test/clip-fill-eo-unbounded.quartz.argb32.ref.png differ
diff --git a/test/clip-fill-eo-unbounded.quartz.rgb24.ref.png b/test/clip-fill-eo-unbounded.quartz.rgb24.ref.png
index 2705008..1612801 100644
Binary files a/test/clip-fill-eo-unbounded.quartz.rgb24.ref.png and b/test/clip-fill-eo-unbounded.quartz.rgb24.ref.png differ
diff --git a/test/clip-fill-nz-unbounded.quartz.argb32.ref.png b/test/clip-fill-nz-unbounded.quartz.argb32.ref.png
index 2ea24a3..3423000 100644
Binary files a/test/clip-fill-nz-unbounded.quartz.argb32.ref.png and b/test/clip-fill-nz-unbounded.quartz.argb32.ref.png differ
diff --git a/test/clip-fill-nz-unbounded.quartz.rgb24.ref.png b/test/clip-fill-nz-unbounded.quartz.rgb24.ref.png
index 2705008..1612801 100644
Binary files a/test/clip-fill-nz-unbounded.quartz.rgb24.ref.png and b/test/clip-fill-nz-unbounded.quartz.rgb24.ref.png differ
diff --git a/test/clip-operator.quartz.argb32.ref.png b/test/clip-operator.quartz.argb32.ref.png
index 53634bd..ecf6ee2 100644
Binary files a/test/clip-operator.quartz.argb32.ref.png and b/test/clip-operator.quartz.argb32.ref.png differ
diff --git a/test/clip-operator.quartz.rgb24.ref.png b/test/clip-operator.quartz.rgb24.ref.png
index 79562e7..67c628f 100644
Binary files a/test/clip-operator.quartz.rgb24.ref.png and b/test/clip-operator.quartz.rgb24.ref.png differ
diff --git a/test/clip-stroke-unbounded.quartz.argb32.ref.png b/test/clip-stroke-unbounded.quartz.argb32.ref.png
index c6124dd..8bd5b36 100644
Binary files a/test/clip-stroke-unbounded.quartz.argb32.ref.png and b/test/clip-stroke-unbounded.quartz.argb32.ref.png differ
diff --git a/test/clip-stroke-unbounded.quartz.rgb24.ref.png b/test/clip-stroke-unbounded.quartz.rgb24.ref.png
index c6e0eb9..5349f84 100644
Binary files a/test/clip-stroke-unbounded.quartz.rgb24.ref.png and b/test/clip-stroke-unbounded.quartz.rgb24.ref.png differ
diff --git a/test/filter-nearest-offset.quartz.xfail.png b/test/filter-nearest-offset.quartz.xfail.png
deleted file mode 100644
index ee69e36..0000000
Binary files a/test/filter-nearest-offset.quartz.xfail.png and /dev/null differ
diff --git a/test/filter-nearest-transformed.quartz.xfail.png b/test/filter-nearest-transformed.quartz.xfail.png
index c616d64..246cdf4 100644
Binary files a/test/filter-nearest-transformed.quartz.xfail.png and b/test/filter-nearest-transformed.quartz.xfail.png differ
diff --git a/test/linear-gradient-subset.quartz.ref.png b/test/linear-gradient-subset.quartz.ref.png
index 2bec9fe..85d80ad 100644
Binary files a/test/linear-gradient-subset.quartz.ref.png and b/test/linear-gradient-subset.quartz.ref.png differ
diff --git a/test/linear-gradient.quartz.ref.png b/test/linear-gradient.quartz.ref.png
index 7eeabe6..1c3e7c2 100644
Binary files a/test/linear-gradient.quartz.ref.png and b/test/linear-gradient.quartz.ref.png differ
diff --git a/test/mask.quartz.argb32.ref.png b/test/mask.quartz.argb32.ref.png
index d7feaf9..c7ab76e 100644
Binary files a/test/mask.quartz.argb32.ref.png and b/test/mask.quartz.argb32.ref.png differ
diff --git a/test/operator-source.quartz.argb32.ref.png b/test/operator-source.quartz.argb32.ref.png
index 6b79166..83d788c 100644
Binary files a/test/operator-source.quartz.argb32.ref.png and b/test/operator-source.quartz.argb32.ref.png differ
diff --git a/test/operator-source.quartz.rgb24.ref.png b/test/operator-source.quartz.rgb24.ref.png
index a88ecb5..038662f 100644
Binary files a/test/operator-source.quartz.rgb24.ref.png and b/test/operator-source.quartz.rgb24.ref.png differ
diff --git a/test/overlapping-glyphs.quartz.argb32.ref.png b/test/overlapping-glyphs.quartz.argb32.ref.png
new file mode 100644
index 0000000..eaa0cb9
Binary files /dev/null and b/test/overlapping-glyphs.quartz.argb32.ref.png differ
diff --git a/test/overlapping-glyphs.quartz.rgb24.ref.png b/test/overlapping-glyphs.quartz.rgb24.ref.png
new file mode 100644
index 0000000..c2b5fc0
Binary files /dev/null and b/test/overlapping-glyphs.quartz.rgb24.ref.png differ
diff --git a/test/partial-clip-text.quartz.ref.png b/test/partial-clip-text.quartz.ref.png
new file mode 100644
index 0000000..33ac283
Binary files /dev/null and b/test/partial-clip-text.quartz.ref.png differ
diff --git a/test/pthread-same-source.quartz.xfail.png b/test/pthread-same-source.quartz.xfail.png
index cc0998f..ffed619 100644
Binary files a/test/pthread-same-source.quartz.xfail.png and b/test/pthread-same-source.quartz.xfail.png differ
diff --git a/test/pthread-show-text.quartz.ref.png b/test/pthread-show-text.quartz.ref.png
index 9b6d774..cc9bb25 100644
Binary files a/test/pthread-show-text.quartz.ref.png and b/test/pthread-show-text.quartz.ref.png differ
diff --git a/test/radial-gradient-mask-source.quartz.argb32.ref.png b/test/radial-gradient-mask-source.quartz.argb32.ref.png
new file mode 100644
index 0000000..5f734f6
Binary files /dev/null and b/test/radial-gradient-mask-source.quartz.argb32.ref.png differ
diff --git a/test/radial-gradient-mask-source.quartz.rgb24.ref.png b/test/radial-gradient-mask-source.quartz.rgb24.ref.png
new file mode 100644
index 0000000..4ae71f7
Binary files /dev/null and b/test/radial-gradient-mask-source.quartz.rgb24.ref.png differ
diff --git a/test/radial-gradient-mask.quartz.ref.png b/test/radial-gradient-mask.quartz.ref.png
new file mode 100644
index 0000000..c1bd506
Binary files /dev/null and b/test/radial-gradient-mask.quartz.ref.png differ
diff --git a/test/radial-gradient-one-stop.quartz.ref.png b/test/radial-gradient-one-stop.quartz.ref.png
new file mode 100644
index 0000000..da991b1
Binary files /dev/null and b/test/radial-gradient-one-stop.quartz.ref.png differ
diff --git a/test/radial-gradient-source.quartz.argb32.ref.png b/test/radial-gradient-source.quartz.argb32.ref.png
new file mode 100644
index 0000000..421c0b9
Binary files /dev/null and b/test/radial-gradient-source.quartz.argb32.ref.png differ
diff --git a/test/radial-gradient-source.quartz.rgb24.ref.png b/test/radial-gradient-source.quartz.rgb24.ref.png
new file mode 100644
index 0000000..22f2b90
Binary files /dev/null and b/test/radial-gradient-source.quartz.rgb24.ref.png differ
diff --git a/test/radial-gradient.quartz.ref.png b/test/radial-gradient.quartz.ref.png
new file mode 100644
index 0000000..f01c6eb
Binary files /dev/null and b/test/radial-gradient.quartz.ref.png differ
diff --git a/test/rotate-image-surface-paint.quartz.ref.png b/test/rotate-image-surface-paint.quartz.ref.png
index 1b317f9..a716b63 100644
Binary files a/test/rotate-image-surface-paint.quartz.ref.png and b/test/rotate-image-surface-paint.quartz.ref.png differ
diff --git a/test/scale-offset-image.quartz.ref.png b/test/scale-offset-image.quartz.ref.png
index 3d8e71a..f7a5e72 100644
Binary files a/test/scale-offset-image.quartz.ref.png and b/test/scale-offset-image.quartz.ref.png differ
diff --git a/test/scale-offset-similar.quartz.ref.png b/test/scale-offset-similar.quartz.ref.png
index 3d8e71a..f7a5e72 100644
Binary files a/test/scale-offset-similar.quartz.ref.png and b/test/scale-offset-similar.quartz.ref.png differ
diff --git a/test/surface-pattern-operator.quartz.argb32.ref.png b/test/surface-pattern-operator.quartz.argb32.ref.png
new file mode 100644
index 0000000..5e934b2
Binary files /dev/null and b/test/surface-pattern-operator.quartz.argb32.ref.png differ
diff --git a/test/surface-pattern-operator.quartz.argb32.xfail.png b/test/surface-pattern-operator.quartz.argb32.xfail.png
deleted file mode 100644
index eb6e890..0000000
Binary files a/test/surface-pattern-operator.quartz.argb32.xfail.png and /dev/null differ
diff --git a/test/surface-pattern-operator.quartz.rgb24.ref.png b/test/surface-pattern-operator.quartz.rgb24.ref.png
new file mode 100644
index 0000000..30408c1
Binary files /dev/null and b/test/surface-pattern-operator.quartz.rgb24.ref.png differ
diff --git a/test/surface-pattern-operator.quartz.rgb24.xfail.png b/test/surface-pattern-operator.quartz.rgb24.xfail.png
deleted file mode 100644
index 6275a48..0000000
Binary files a/test/surface-pattern-operator.quartz.rgb24.xfail.png and /dev/null differ
diff --git a/test/trap-clip.quartz.argb32.ref.png b/test/trap-clip.quartz.argb32.ref.png
index c5096df..e045ea4 100644
Binary files a/test/trap-clip.quartz.argb32.ref.png and b/test/trap-clip.quartz.argb32.ref.png differ
diff --git a/test/trap-clip.quartz.rgb24.ref.png b/test/trap-clip.quartz.rgb24.ref.png
index 7c2a15e..1044d86 100644
Binary files a/test/trap-clip.quartz.rgb24.ref.png and b/test/trap-clip.quartz.rgb24.ref.png differ
diff --git a/test/unbounded-operator.quartz.argb32.ref.png b/test/unbounded-operator.quartz.argb32.ref.png
new file mode 100644
index 0000000..b2e9916
Binary files /dev/null and b/test/unbounded-operator.quartz.argb32.ref.png differ
diff --git a/test/unbounded-operator.quartz.rgb24.ref.png b/test/unbounded-operator.quartz.rgb24.ref.png
new file mode 100644
index 0000000..ea41dc8
Binary files /dev/null and b/test/unbounded-operator.quartz.rgb24.ref.png differ
diff --git a/test/xcomposite-projection.quartz.ref.png b/test/xcomposite-projection.quartz.ref.png
index c7b6f5c..0221607 100644
Binary files a/test/xcomposite-projection.quartz.ref.png and b/test/xcomposite-projection.quartz.ref.png differ
commit 2e75bf5a25cc5b7fd33702e2b1474f94caeab158
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Wed Jan 5 16:00:37 2011 +0100

    test: Fix operator-alpha-alpha
    
    The test is checking the compositing of color-alpha sources although
    it was meant to check the compositing of alpha-only sources on
    alpha-only destinations.
    
    This commit fixes the code to respect the test description.

diff --git a/test/operator-alpha-alpha.c b/test/operator-alpha-alpha.c
index b76faf5..2cef858 100644
--- a/test/operator-alpha-alpha.c
+++ b/test/operator-alpha-alpha.c
@@ -93,9 +93,9 @@ subdraw (cairo_t *cr, int width, int height)
     cairo_surface_t *bg, *fg;
 
     bg = cairo_surface_create_similar (cairo_get_target (cr),
-	    CAIRO_CONTENT_COLOR_ALPHA, SIZE * STEPS, SIZE * STEPS);
+	    CAIRO_CONTENT_ALPHA, SIZE * STEPS, SIZE * STEPS);
     fg = cairo_surface_create_similar (cairo_get_target (cr),
-	    CAIRO_CONTENT_COLOR_ALPHA, SIZE * STEPS, SIZE * STEPS);
+	    CAIRO_CONTENT_ALPHA, SIZE * STEPS, SIZE * STEPS);
     bgcr = cairo_create (bg);
     fgcr = cairo_create (fg);
     cairo_scale (bgcr, SIZE, SIZE);


More information about the cairo-commit mailing list