1diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h
2--- a/gfx/cairo/cairo/src/cairo-quartz-private.h
3+++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
4@@ -50,30 +50,16 @@ typedef struct cairo_quartz_surface {
5     CGContextRef cgContext;
6     CGAffineTransform cgContextBaseCTM;
7
8     void *imageData;
9     cairo_surface_t *imageSurfaceEquiv;
10
11     cairo_surface_clipper_t clipper;
12     cairo_rectangle_int_t extents;
13-
14-    /* These are stored while drawing operations are in place, set up
15-     * by quartz_setup_source() and quartz_finish_source()
16-     */
17-    CGAffineTransform sourceTransform;
18-
19-    CGImageRef sourceImage;
20-    cairo_surface_t *sourceImageSurface;
21-    CGRect sourceImageRect;
22-
23-    CGShadingRef sourceShading;
24-    CGPatternRef sourcePattern;
25-
26-    CGInterpolationQuality oldInterpolationQuality;
27 } cairo_quartz_surface_t;
28
29 typedef struct cairo_quartz_image_surface {
30     cairo_surface_t base;
31
32     cairo_rectangle_int_t extents;
33
34     CGImageRef image;
35diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c
36--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
37+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
38@@ -1333,36 +1333,59 @@ _cairo_quartz_cairo_repeating_surface_pa
39     return CAIRO_STATUS_SUCCESS;
40 }
41
42 typedef enum {
43     DO_SOLID,
44     DO_SHADING,
45     DO_PATTERN,
46     DO_IMAGE,
47+    DO_TILED_IMAGE,
48     DO_UNSUPPORTED,
49-    DO_NOTHING,
50-    DO_TILED_IMAGE
51+    DO_NOTHING
52 } cairo_quartz_action_t;
53
54-static cairo_quartz_action_t
55+/* State used during a drawing operation. */
56+typedef struct {
57+    CGContextRef context;
58+    cairo_quartz_action_t action;
59+
60+    // Used with DO_SHADING, DO_IMAGE and DO_TILED_IMAGE
61+    CGAffineTransform transform;
62+
63+    // Used with DO_IMAGE and DO_TILED_IMAGE
64+    CGImageRef image;
65+    cairo_surface_t *imageSurface;
66+    CGRect imageRect;
67+
68+    // Used with DO_SHADING
69+    CGShadingRef shading;
70+
71+    // Used with DO_PATTERN
72+    CGPatternRef pattern;
73+} cairo_quartz_drawing_state_t;
74+
75+static void
76 _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
77-				     const cairo_pattern_t *source)
78+				     const cairo_pattern_t *source,
79+				     cairo_quartz_drawing_state_t *state)
80 {
81-    CGRect clipBox = CGContextGetClipBoundingBox (surface->cgContext);
82+    CGRect clipBox = CGContextGetClipBoundingBox (state->context);
83     double x0, y0, w, h;
84
85     cairo_surface_t *fallback;
86     CGImageRef img;
87
88     cairo_status_t status;
89
90     if (clipBox.size.width == 0.0f ||
91-	clipBox.size.height == 0.0f)
92-	return DO_NOTHING;
93+	clipBox.size.height == 0.0f) {
94+	state->action = DO_NOTHING;
95+	return;
96+    }
97
98     x0 = floor(clipBox.origin.x);
99     y0 = floor(clipBox.origin.y);
100     w = ceil(clipBox.origin.x + clipBox.size.width) - x0;
101     h = ceil(clipBox.origin.y + clipBox.size.height) - y0;
102
103     /* Create a temporary the size of the clip surface, and position
104      * it so that the device origin coincides with the original surface */
105@@ -1396,73 +1419,79 @@ _cairo_quartz_setup_fallback_source (cai
106 				  &fallback->device_transform_inverse);
107 	status = _cairo_surface_paint (fallback,
108 				       CAIRO_OPERATOR_SOURCE,
109 				       &pattern.base, NULL);
110     }
111 #endif
112
113     status = _cairo_surface_to_cgimage (&surface->base, fallback, &img);
114-    if (status)
115-	return DO_UNSUPPORTED;
116-    if (img == NULL)
117-	return DO_NOTHING;
118-
119-    surface->sourceImageRect = CGRectMake (0.0, 0.0, w, h);
120-    surface->sourceImage = img;
121-    surface->sourceImageSurface = fallback;
122-    surface->sourceTransform = CGAffineTransformMakeTranslation (x0, y0);
123-
124-    return DO_IMAGE;
125+    if (status) {
126+        state->action = DO_UNSUPPORTED;
127+	return;
128+    }
129+    if (img == NULL) {
130+        state->action = DO_NOTHING;
131+	return;
132+    }
133+
134+    state->imageRect = CGRectMake (0.0, 0.0, w, h);
135+    state->image = img;
136+    state->imageSurface = fallback;
137+    state->transform = CGAffineTransformMakeTranslation (x0, y0);
138+    state->action = DO_IMAGE;
139 }
140
141 /*
142 Quartz does not support repeating radients. We handle repeating gradients
143 by manually extending the gradient and repeating color stops. We need to
144 minimize the number of repetitions since Quartz seems to sample our color
145 function across the entire range, even if part of that range is not needed
146 for the visible area of the gradient, and it samples with some fixed resolution,
147 so if the gradient range is too large it samples with very low resolution and
148 the gradient is very coarse. CreateRepeatingLinearGradientFunction and
149 CreateRepeatingRadialGradientFunction compute the number of repetitions needed
150 based on the extents of the object (the clip region cannot be used here since
151 we don't want the rasterization of the entire gradient to depend on the
152 clip region).
153 */
154-static cairo_quartz_action_t
155+static void
156 _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
157 				   const cairo_linear_pattern_t *lpat,
158-				   cairo_rectangle_int_t *extents)
159+				   cairo_rectangle_int_t *extents,
160+				   cairo_quartz_drawing_state_t *state)
161 {
162     const cairo_pattern_t *abspat = &lpat->base.base;
163     cairo_matrix_t mat;
164     CGPoint start, end;
165     CGFunctionRef gradFunc;
166     CGColorSpaceRef rgb;
167     bool extend = abspat->extend == CAIRO_EXTEND_PAD;
168
169     if (lpat->base.n_stops == 0) {
170-	CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.);
171-	CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
172-	return DO_SOLID;
173+	CGContextSetRGBStrokeColor (state->context, 0., 0., 0., 0.);
174+	CGContextSetRGBFillColor (state->context, 0., 0., 0., 0.);
175+	state->action = DO_SOLID;
176+	return;
177     }
178
179     if (lpat->p1.x == lpat->p2.x &&
180         lpat->p1.y == lpat->p2.y) {
181 	/* Quartz handles cases where the vector has no length very
182 	 * differently from pixman.
183 	 * Whatever the correct behaviour is, let's at least have only pixman's
184 	 * implementation to worry about.
185 	 */
186-	return _cairo_quartz_setup_fallback_source (surface, abspat);
187+	_cairo_quartz_setup_fallback_source (surface, abspat, state);
188+	return;
189     }
190
191     mat = abspat->matrix;
192     cairo_matrix_invert (&mat);
193-    _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform);
194+    _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform);
195
196     rgb = CGColorSpaceCreateDeviceRGB();
197
198     start = CGPointMake (_cairo_fixed_to_double (lpat->p1.x),
199 			 _cairo_fixed_to_double (lpat->p1.y));
200     end = CGPointMake (_cairo_fixed_to_double (lpat->p2.x),
201 		       _cairo_fixed_to_double (lpat->p2.y));
202
203@@ -1472,31 +1501,32 @@ _cairo_quartz_setup_linear_source (cairo
204 	gradFunc = CreateGradientFunction (&lpat->base);
205     } else {
206 	gradFunc = CreateRepeatingLinearGradientFunction (surface,
207 						          &lpat->base,
208 						          &start, &end,
209 						          extents);
210     }
211
212-    surface->sourceShading = CGShadingCreateAxial (rgb,
213-						   start, end,
214-						   gradFunc,
215-						   extend, extend);
216+    state->shading = CGShadingCreateAxial (rgb,
217+					   start, end,
218+					   gradFunc,
219+					   extend, extend);
220
221     CGColorSpaceRelease(rgb);
222     CGFunctionRelease(gradFunc);
223
224-    return DO_SHADING;
225+    state->action = DO_SHADING;
226 }
227
228-static cairo_quartz_action_t
229+static void
230 _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
231 				   const cairo_radial_pattern_t *rpat,
232-				   cairo_rectangle_int_t *extents)
233+				   cairo_rectangle_int_t *extents,
234+				   cairo_quartz_drawing_state_t *state)
235 {
236     const cairo_pattern_t *abspat = &rpat->base.base;
237     cairo_matrix_t mat;
238     CGPoint start, end;
239     CGFunctionRef gradFunc;
240     CGColorSpaceRef rgb;
241     bool extend = abspat->extend == CAIRO_EXTEND_PAD;
242     double c1x = _cairo_fixed_to_double (rpat->c1.x);
243@@ -1505,35 +1535,37 @@ _cairo_quartz_setup_radial_source (cairo
244     double c2y = _cairo_fixed_to_double (rpat->c2.y);
245     double r1 = _cairo_fixed_to_double (rpat->r1);
246     double r2 = _cairo_fixed_to_double (rpat->r2);
247     double dx = c1x - c2x;
248     double dy = c1y - c2y;
249     double centerDistance = sqrt (dx*dx + dy*dy);
250
251     if (rpat->base.n_stops == 0) {
252-	CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.);
253-	CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
254-	return DO_SOLID;
255+	CGContextSetRGBStrokeColor (state->context, 0., 0., 0., 0.);
256+	CGContextSetRGBFillColor (state->context, 0., 0., 0., 0.);
257+	state->action = DO_SOLID;
258+	return;
259     }
260
261     if (r2 <= centerDistance + r1 + 1e-6 && /* circle 2 doesn't contain circle 1 */
262         r1 <= centerDistance + r2 + 1e-6) { /* circle 1 doesn't contain circle 2 */
263 	/* Quartz handles cases where neither circle contains the other very
264 	 * differently from pixman.
265 	 * Whatever the correct behaviour is, let's at least have only pixman's
266 	 * implementation to worry about.
267 	 * Note that this also catches the cases where r1 == r2.
268 	 */
269-	return _cairo_quartz_setup_fallback_source (surface, abspat);
270+	_cairo_quartz_setup_fallback_source (surface, abspat, state);
271+	return;
272     }
273
274     mat = abspat->matrix;
275     cairo_matrix_invert (&mat);
276-    _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform);
277+    _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform);
278
279     rgb = CGColorSpaceCreateDeviceRGB();
280
281     start = CGPointMake (c1x, c1y);
282     end = CGPointMake (c2x, c2y);
283
284     if (abspat->extend == CAIRO_EXTEND_NONE ||
285         abspat->extend == CAIRO_EXTEND_PAD)
286@@ -1542,111 +1574,146 @@ _cairo_quartz_setup_radial_source (cairo
287     } else {
288 	gradFunc = CreateRepeatingRadialGradientFunction (surface,
289 						          &rpat->base,
290 						          &start, &r1,
291 						          &end, &r2,
292 						          extents);
293     }
294
295-    surface->sourceShading = CGShadingCreateRadial (rgb,
296-						    start,
297-						    r1,
298-						    end,
299-						    r2,
300-						    gradFunc,
301-						    extend, extend);
302+    state->shading = CGShadingCreateRadial (rgb,
303+					    start,
304+					    r1,
305+					    end,
306+					    r2,
307+					    gradFunc,
308+					    extend, extend);
309
310     CGColorSpaceRelease(rgb);
311     CGFunctionRelease(gradFunc);
312
313-    return DO_SHADING;
314+    state->action = DO_SHADING;
315 }
316
317-static cairo_quartz_action_t
318-_cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
319-			    const cairo_pattern_t *source,
320-			    cairo_rectangle_int_t *extents)
321+/**
322+ * Sets up internal state to be used to draw the source mask, stored in
323+ * cairo_quartz_state_t. Guarantees to call CGContextSaveGState on
324+ * surface->cgContext.
325+ */
326+static cairo_quartz_drawing_state_t
327+_cairo_quartz_setup_state (cairo_quartz_surface_t *surface,
328+			   const cairo_pattern_t *source,
329+			   cairo_operator_t op,
330+			   cairo_rectangle_int_t *extents)
331 {
332-    assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern));
333-
334-    surface->oldInterpolationQuality = CGContextGetInterpolationQuality (surface->cgContext);
335-    CGContextSetInterpolationQuality (surface->cgContext, _cairo_quartz_filter_to_quartz (source->filter));
336+    CGContextRef context = surface->cgContext;
337+    cairo_quartz_drawing_state_t state;
338+    cairo_status_t status;
339+
340+    state.context = context;
341+    state.image = NULL;
342+    state.imageSurface = NULL;
343+    state.shading = NULL;
344+    state.pattern = NULL;
345+
346+    // Save before we change the pattern, colorspace, etc. so that
347+    // we can restore and make sure that quartz releases our
348+    // pattern (which may be stack allocated)
349+    CGContextSaveGState(context);
350+
351+    CGContextSetInterpolationQuality (context, _cairo_quartz_filter_to_quartz (source->filter));
352+
353+    status = _cairo_quartz_surface_set_cairo_operator (surface, op);
354+    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
355+        state.action = DO_NOTHING;
356+        return state;
357+    }
358+    if (status) {
359+        state.action = DO_UNSUPPORTED;
360+        return state;
361+    }
362
363     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
364 	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
365
366-	CGContextSetRGBStrokeColor (surface->cgContext,
367+	CGContextSetRGBStrokeColor (context,
368 				    solid->color.red,
369 				    solid->color.green,
370 				    solid->color.blue,
371 				    solid->color.alpha);
372-	CGContextSetRGBFillColor (surface->cgContext,
373+	CGContextSetRGBFillColor (context,
374 				  solid->color.red,
375 				  solid->color.green,
376 				  solid->color.blue,
377 				  solid->color.alpha);
378
379-	return DO_SOLID;
380+        state.action = DO_SOLID;
381+        return state;
382     }
383
384     if (source->type == CAIRO_PATTERN_TYPE_LINEAR) {
385 	const cairo_linear_pattern_t *lpat = (const cairo_linear_pattern_t *)source;
386-	return _cairo_quartz_setup_linear_source (surface, lpat, extents);
387+	_cairo_quartz_setup_linear_source (surface, lpat, extents, &state);
388+	return state;
389     }
390
391     if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
392 	const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source;
393-	return _cairo_quartz_setup_radial_source (surface, rpat, extents);
394+	_cairo_quartz_setup_radial_source (surface, rpat, extents, &state);
395+	return state;
396     }
397
398     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
399 	(source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
400     {
401 	const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source;
402 	cairo_surface_t *pat_surf = spat->surface;
403 	CGImageRef img;
404 	cairo_matrix_t m = spat->base.matrix;
405 	cairo_rectangle_int_t extents;
406-	cairo_status_t status;
407 	CGAffineTransform xform;
408 	CGRect srcRect;
409 	cairo_fixed_t fw, fh;
410 	cairo_bool_t is_bounded;
411
412 	status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
413-	if (status)
414-	    return DO_UNSUPPORTED;
415-	if (img == NULL)
416-	    return DO_NOTHING;
417+        if (status) {
418+            state.action = DO_UNSUPPORTED;
419+	    return state;
420+        }
421+        if (img == NULL) {
422+            state.action = DO_NOTHING;
423+	    return state;
424+        }
425
426 	CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1);
427
428-	surface->sourceImage = img;
429+	state.image = img;
430
431 	cairo_matrix_invert(&m);
432-	_cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceTransform);
433+	_cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform);
434
435 	is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
436 	assert (is_bounded);
437
438 	if (source->extend == CAIRO_EXTEND_NONE) {
439-	    surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
440-	    return DO_IMAGE;
441+	    state.imageRect = CGRectMake (0, 0, extents.width, extents.height);
442+	    state.action = DO_IMAGE;
443+	    return state;
444 	}
445
446 	/* Quartz seems to tile images at pixel-aligned regions only -- this
447 	 * leads to seams if the image doesn't end up scaling to fill the
448 	 * space exactly.  The CGPattern tiling approach doesn't have this
449 	 * problem.  Check if we're going to fill up the space (within some
450 	 * epsilon), and if not, fall back to the CGPattern type.
451 	 */
452
453-	xform = CGAffineTransformConcat (CGContextGetCTM (surface->cgContext),
454-					 surface->sourceTransform);
455+	xform = CGAffineTransformConcat (CGContextGetCTM (context),
456+					 state.transform);
457
458 	srcRect = CGRectMake (0, 0, extents.width, extents.height);
459 	srcRect = CGRectApplyAffineTransform (srcRect, xform);
460
461 	fw = _cairo_fixed_from_double (srcRect.size.width);
462 	fh = _cairo_fixed_from_double (srcRect.size.height);
463
464 	if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON &&
465@@ -1657,111 +1724,109 @@ _cairo_quartz_setup_source (cairo_quartz
466
467 	    srcRect.size.width = round(srcRect.size.width);
468 	    srcRect.size.height = round(srcRect.size.height);
469
470 	    xform = CGAffineTransformInvert (xform);
471
472 	    srcRect = CGRectApplyAffineTransform (srcRect, xform);
473
474-	    surface->sourceImageRect = srcRect;
475-
476-	    return DO_TILED_IMAGE;
477+	    state.imageRect = srcRect;
478+            state.action = DO_TILED_IMAGE;
479+            return state;
480 	}
481
482 	/* Fall through to generic SURFACE case */
483     }
484
485     if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
486 	CGFloat patternAlpha = 1.0f;
487 	CGColorSpaceRef patternSpace;
488 	CGPatternRef pattern;
489 	cairo_int_status_t status;
490
491 	status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern);
492-	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
493-	    return DO_NOTHING;
494-	if (status)
495-	    return DO_UNSUPPORTED;
496-
497-	// Save before we change the pattern, colorspace, etc. so that
498-	// we can restore and make sure that quartz releases our
499-	// pattern (which may be stack allocated)
500-	CGContextSaveGState(surface->cgContext);
501-
502-	patternSpace = CGColorSpaceCreatePattern(NULL);
503-	CGContextSetFillColorSpace (surface->cgContext, patternSpace);
504-	CGContextSetFillPattern (surface->cgContext, pattern, &patternAlpha);
505-	CGContextSetStrokeColorSpace (surface->cgContext, patternSpace);
506-	CGContextSetStrokePattern (surface->cgContext, pattern, &patternAlpha);
507+	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
508+	    state.action = DO_NOTHING;
509+	    return state;
510+	}
511+	if (status) {
512+	    state.action = DO_UNSUPPORTED;
513+	    return state;
514+	}
515+
516+	patternSpace = CGColorSpaceCreatePattern (NULL);
517+	CGContextSetFillColorSpace (context, patternSpace);
518+	CGContextSetFillPattern (context, pattern, &patternAlpha);
519+	CGContextSetStrokeColorSpace (context, patternSpace);
520+	CGContextSetStrokePattern (context, pattern, &patternAlpha);
521 	CGColorSpaceRelease (patternSpace);
522
523 	/* Quartz likes to munge the pattern phase (as yet unexplained
524 	 * why); force it to 0,0 as we've already baked in the correct
525 	 * pattern translation into the pattern matrix
526 	 */
527-	CGContextSetPatternPhase (surface->cgContext, CGSizeMake(0,0));
528-
529-	surface->sourcePattern = pattern;
530-
531-	return DO_PATTERN;
532+	CGContextSetPatternPhase (context, CGSizeMake(0,0));
533+
534+	state.pattern = pattern;
535+        state.action = DO_PATTERN;
536+        return state;
537     }
538
539-    return DO_UNSUPPORTED;
540+    state.action = DO_UNSUPPORTED;
541+    return state;
542 }
543
544+/**
545+ * 1) Tears down internal state used to draw the source
546+ * 2) Does CGContextRestoreGState(state->context)
547+ */
548 static void
549-_cairo_quartz_teardown_source (cairo_quartz_surface_t *surface,
550-			       const cairo_pattern_t *source)
551+_cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state)
552 {
553-    CGContextSetInterpolationQuality (surface->cgContext, surface->oldInterpolationQuality);
554-
555-    if (surface->sourceImage) {
556-	CGImageRelease(surface->sourceImage);
557-	surface->sourceImage = NULL;
558-
559-	cairo_surface_destroy(surface->sourceImageSurface);
560-	surface->sourceImageSurface = NULL;
561+    if (state->image) {
562+	CGImageRelease(state->image);
563     }
564
565-    if (surface->sourceShading) {
566-	CGShadingRelease(surface->sourceShading);
567-	surface->sourceShading = NULL;
568+    if (state->imageSurface) {
569+	cairo_surface_destroy(state->imageSurface);
570     }
571
572-    if (surface->sourcePattern) {
573-	CGPatternRelease(surface->sourcePattern);
574-	// To tear down the pattern and colorspace
575-	CGContextRestoreGState(surface->cgContext);
576-
577-	surface->sourcePattern = NULL;
578+    if (state->shading) {
579+	CGShadingRelease(state->shading);
580     }
581+
582+    if (state->pattern) {
583+	CGPatternRelease(state->pattern);
584+    }
585+
586+    CGContextRestoreGState(state->context);
587 }
588
589
590 static void
591-_cairo_quartz_draw_image (cairo_quartz_surface_t *surface, cairo_operator_t op,  cairo_quartz_action_t action)
592+_cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state, cairo_operator_t op)
593 {
594-    assert (surface && surface->sourceImage && (action == DO_IMAGE || action == DO_TILED_IMAGE));
595-
596-    CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
597-    CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
598-    CGContextScaleCTM (surface->cgContext, 1, -1);
599-
600-    if (action == DO_IMAGE) {
601-	CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
602-	if (!_cairo_operator_bounded_by_source(op)) {
603-	    CGContextBeginPath (surface->cgContext);
604-	    CGContextAddRect (surface->cgContext, surface->sourceImageRect);
605-	    CGContextAddRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext));
606-	    CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 0);
607-	    CGContextEOFillPath (surface->cgContext);
608+    assert (state && state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE));
609+
610+    CGContextConcatCTM (state->context, state->transform);
611+    CGContextTranslateCTM (state->context, 0, state->imageRect.size.height);
612+    CGContextScaleCTM (state->context, 1, -1);
613+
614+    if (state->action == DO_IMAGE) {
615+	CGContextDrawImage (state->context, state->imageRect, state->image);
616+	if (!_cairo_operator_bounded_by_source (op)) {
617+	    CGContextBeginPath (state->context);
618+	    CGContextAddRect (state->context, state->imageRect);
619+	    CGContextAddRect (state->context, CGContextGetClipBoundingBox (state->context));
620+	    CGContextSetRGBFillColor (state->context, 0, 0, 0, 0);
621+	    CGContextEOFillPath (state->context);
622 	}
623     } else
624-	CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
625+	CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image);
626 }
627
628
629 /*
630  * get source/dest image implementation
631  */
632
633 /* Read the image from the surface's front buffer */
634@@ -2098,52 +2163,44 @@ _cairo_quartz_surface_get_extents (void
635 static cairo_int_status_t
636 _cairo_quartz_surface_paint (void *abstract_surface,
637 			     cairo_operator_t op,
638 			     const cairo_pattern_t *source,
639 			     cairo_clip_t *clip)
640 {
641     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
642     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
643-    cairo_quartz_action_t action;
644+    cairo_quartz_drawing_state_t state;
645
646     ND((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
647
648     if (IS_EMPTY(surface))
649 	return CAIRO_STATUS_SUCCESS;
650
651     rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
652     if (unlikely (rv))
653 	return rv;
654
655-    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
656-    if (unlikely (rv))
657-	return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
658-
659-    action = _cairo_quartz_setup_source (surface, source, NULL);
660-
661-    if (action == DO_SOLID || action == DO_PATTERN) {
662-	CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
663-							  surface->extents.y,
664-							  surface->extents.width,
665-							  surface->extents.height));
666-    } else if (action == DO_SHADING) {
667-	CGContextSaveGState (surface->cgContext);
668-	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
669-	CGContextDrawShading (surface->cgContext, surface->sourceShading);
670-	CGContextRestoreGState (surface->cgContext);
671-    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
672-	CGContextSaveGState (surface->cgContext);
673-	_cairo_quartz_draw_image (surface, op, action);
674-	CGContextRestoreGState (surface->cgContext);
675-    } else if (action != DO_NOTHING) {
676+    state = _cairo_quartz_setup_state (surface, source, op, NULL);
677+
678+    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
679+	CGContextFillRect (state.context, CGRectMake(surface->extents.x,
680+						     surface->extents.y,
681+						     surface->extents.width,
682+						     surface->extents.height));
683+    } else if (state.action == DO_SHADING) {
684+	CGContextConcatCTM (state.context, state.transform);
685+	CGContextDrawShading (state.context, state.shading);
686+    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) {
687+	_cairo_quartz_draw_image (&state, op);
688+    } else if (state.action != DO_NOTHING) {
689 	rv = CAIRO_INT_STATUS_UNSUPPORTED;
690     }
691
692-    _cairo_quartz_teardown_source (surface, source);
693+    _cairo_quartz_teardown_state (&state);
694
695     ND((stderr, "-- paint\n"));
696     return rv;
697 }
698
699 static cairo_bool_t
700 _cairo_quartz_source_needs_extents (const cairo_pattern_t *source)
701 {
702@@ -2170,91 +2227,83 @@ _cairo_quartz_surface_fill (void *abstra
703 			     cairo_path_fixed_t *path,
704 			     cairo_fill_rule_t fill_rule,
705 			     double tolerance,
706 			     cairo_antialias_t antialias,
707 			     cairo_clip_t *clip)
708 {
709     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
710     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
711-    cairo_quartz_action_t action;
712+    cairo_quartz_drawing_state_t state;
713     quartz_stroke_t stroke;
714     CGPathRef path_for_unbounded = NULL;
715
716     ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
717
718     if (IS_EMPTY(surface))
719 	return CAIRO_STATUS_SUCCESS;
720
721     rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
722     if (unlikely (rv))
723 	return rv;
724
725-    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
726-    if (unlikely (rv))
727-	return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
728-
729-    CGContextSaveGState (surface->cgContext);
730-
731-    CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
732-
733     if (_cairo_quartz_source_needs_extents (source))
734     {
735         /* We don't need precise extents since these are only used to
736            compute the number of gradient reptitions needed to cover the
737            object. */
738         cairo_rectangle_int_t path_extents;
739         _cairo_path_fixed_approximate_fill_extents (path, &path_extents);
740-        action = _cairo_quartz_setup_source (surface, source, &path_extents);
741+        state = _cairo_quartz_setup_state (surface, source, op, &path_extents);
742     } else {
743-        action = _cairo_quartz_setup_source (surface, source, NULL);
744+        state = _cairo_quartz_setup_state (surface, source, op, NULL);
745     }
746
747-    CGContextBeginPath (surface->cgContext);
748-
749-    stroke.cgContext = surface->cgContext;
750+    CGContextSetShouldAntialias (state.context, (antialias != CAIRO_ANTIALIAS_NONE));
751+
752+    CGContextBeginPath (state.context);
753+
754+    stroke.cgContext = state.context;
755     stroke.ctm_inverse = NULL;
756     rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
757     if (rv)
758         goto BAIL;
759
760     if (!_cairo_operator_bounded_by_mask(op) && CGContextCopyPathPtr)
761-	path_for_unbounded = CGContextCopyPathPtr (surface->cgContext);
762-
763-    if (action == DO_SOLID || action == DO_PATTERN) {
764+	path_for_unbounded = CGContextCopyPathPtr (state.context);
765+
766+    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
767 	if (fill_rule == CAIRO_FILL_RULE_WINDING)
768-	    CGContextFillPath (surface->cgContext);
769+	    CGContextFillPath (state.context);
770 	else
771-	    CGContextEOFillPath (surface->cgContext);
772-    } else if (action == DO_SHADING) {
773+	    CGContextEOFillPath (state.context);
774+    } else if (state.action == DO_SHADING) {
775
776 	// we have to clip and then paint the shading; we can't fill
777 	// with the shading
778 	if (fill_rule == CAIRO_FILL_RULE_WINDING)
779-	    CGContextClip (surface->cgContext);
780+	    CGContextClip (state.context);
781 	else
782-	    CGContextEOClip (surface->cgContext);
783-
784-	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
785-	CGContextDrawShading (surface->cgContext, surface->sourceShading);
786-    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
787+            CGContextEOClip (state.context);
788+
789+	CGContextConcatCTM (state.context, state.transform);
790+	CGContextDrawShading (state.context, state.shading);
791+    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) {
792 	if (fill_rule == CAIRO_FILL_RULE_WINDING)
793-	    CGContextClip (surface->cgContext);
794+	    CGContextClip (state.context);
795 	else
796-	    CGContextEOClip (surface->cgContext);
797-
798-	_cairo_quartz_draw_image (surface, op, action);
799-    } else if (action != DO_NOTHING) {
800+	    CGContextEOClip (state.context);
801+
802+	_cairo_quartz_draw_image (&state, op);
803+    } else if (state.action != DO_NOTHING) {
804 	rv = CAIRO_INT_STATUS_UNSUPPORTED;
805     }
806
807   BAIL:
808-    _cairo_quartz_teardown_source (surface, source);
809-
810-    CGContextRestoreGState (surface->cgContext);
811+    _cairo_quartz_teardown_state (&state);
812
813     if (path_for_unbounded) {
814 	unbounded_op_data_t ub;
815 	ub.op = UNBOUNDED_STROKE_FILL;
816 	ub.u.stroke_fill.cgPath = path_for_unbounded;
817 	ub.u.stroke_fill.fill_rule = fill_rule;
818
819 	_cairo_quartz_fixup_unbounded_operation (surface, &ub, antialias);
820@@ -2274,44 +2323,49 @@ _cairo_quartz_surface_stroke (void *abst
821 			      cairo_matrix_t *ctm,
822 			      cairo_matrix_t *ctm_inverse,
823 			      double tolerance,
824 			      cairo_antialias_t antialias,
825 			      cairo_clip_t *clip)
826 {
827     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
828     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
829-    cairo_quartz_action_t action;
830+    cairo_quartz_drawing_state_t state;
831     quartz_stroke_t stroke;
832     CGAffineTransform origCTM, strokeTransform;
833     CGPathRef path_for_unbounded = NULL;
834
835     ND((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type));
836
837     if (IS_EMPTY(surface))
838 	return CAIRO_STATUS_SUCCESS;
839
840     rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
841     if (unlikely (rv))
842 	return rv;
843
844-    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
845-    if (unlikely (rv))
846-	return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
847+    if (_cairo_quartz_source_needs_extents (source))
848+    {
849+        cairo_rectangle_int_t path_extents;
850+        _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents);
851+        state = _cairo_quartz_setup_state (surface, source, op, &path_extents);
852+    } else {
853+        state = _cairo_quartz_setup_state (surface, source, op, NULL);
854+    }
855
856     // Turning antialiasing off used to cause misrendering with
857     // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels).
858     // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases.
859-    CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
860-    CGContextSetLineWidth (surface->cgContext, style->line_width);
861-    CGContextSetLineCap (surface->cgContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
862-    CGContextSetLineJoin (surface->cgContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
863-    CGContextSetMiterLimit (surface->cgContext, style->miter_limit);
864-
865-    origCTM = CGContextGetCTM (surface->cgContext);
866+    CGContextSetShouldAntialias (state.context, (antialias != CAIRO_ANTIALIAS_NONE));
867+    CGContextSetLineWidth (state.context, style->line_width);
868+    CGContextSetLineCap (state.context, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
869+    CGContextSetLineJoin (state.context, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
870+    CGContextSetMiterLimit (state.context, style->miter_limit);
871+
872+    origCTM = CGContextGetCTM (state.context);
873
874     if (style->dash && style->num_dashes) {
875 #define STATIC_DASH 32
876 	CGFloat sdash[STATIC_DASH];
877 	CGFloat *fdash = sdash;
878 	double offset = style->dash_offset;
879 	unsigned int max_dashes = style->num_dashes;
880 	unsigned int k;
881@@ -2330,90 +2384,75 @@ _cairo_quartz_surface_stroke (void *abst
882 	    if (max_dashes > STATIC_DASH)
883 		fdash = _cairo_malloc_ab (max_dashes, sizeof (CGFloat));
884 	    if (fdash == NULL)
885 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
886
887 	    for (k = 0; k < max_dashes; k++)
888 		fdash[k] = (CGFloat) style->dash[k % style->num_dashes];
889 	}
890-	CGContextSetLineDash (surface->cgContext, offset, fdash, max_dashes);
891+	CGContextSetLineDash (state.context, offset, fdash, max_dashes);
892 	if (fdash != sdash)
893 	    free (fdash);
894     } else
895-	CGContextSetLineDash (surface->cgContext, 0, NULL, 0);
896-
897-    CGContextSaveGState (surface->cgContext);
898-
899-
900-    if (_cairo_quartz_source_needs_extents (source))
901-    {
902-        cairo_rectangle_int_t path_extents;
903-        _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents);
904-        action = _cairo_quartz_setup_source (surface, source, &path_extents);
905-    } else {
906-        action = _cairo_quartz_setup_source (surface, source, NULL);
907-    }
908+	CGContextSetLineDash (state.context, 0, NULL, 0);
909
910     _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform);
911-    CGContextConcatCTM (surface->cgContext, strokeTransform);
912-
913-    CGContextBeginPath (surface->cgContext);
914-
915-    stroke.cgContext = surface->cgContext;
916+    CGContextConcatCTM (state.context, strokeTransform);
917+
918+    CGContextBeginPath (state.context);
919+
920+    stroke.cgContext = state.context;
921     stroke.ctm_inverse = ctm_inverse;
922     rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
923     if (rv)
924 	goto BAIL;
925
926     if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr)
927-	path_for_unbounded = CGContextCopyPathPtr (surface->cgContext);
928-
929-    if (action == DO_SOLID || action == DO_PATTERN) {
930-	CGContextStrokePath (surface->cgContext);
931-    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
932-	CGContextReplacePathWithStrokedPath (surface->cgContext);
933-	CGContextClip (surface->cgContext);
934-
935-	CGContextSetCTM (surface->cgContext, origCTM);
936-	_cairo_quartz_draw_image (surface, op, action);
937-    } else if (action == DO_SHADING) {
938-	CGContextReplacePathWithStrokedPath (surface->cgContext);
939-	CGContextClip (surface->cgContext);
940-
941-	CGContextSetCTM (surface->cgContext, origCTM);
942-
943-	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
944-	CGContextDrawShading (surface->cgContext, surface->sourceShading);
945-    } else if (action != DO_NOTHING) {
946+	path_for_unbounded = CGContextCopyPathPtr (state.context);
947+
948+    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
949+	CGContextStrokePath (state.context);
950+    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) {
951+	CGContextReplacePathWithStrokedPath (state.context);
952+	CGContextClip (state.context);
953+
954+	CGContextSetCTM (state.context, origCTM);
955+	_cairo_quartz_draw_image (&state, op);
956+    } else if (state.action == DO_SHADING) {
957+	CGContextReplacePathWithStrokedPath (state.context);
958+	CGContextClip (state.context);
959+
960+	CGContextSetCTM (state.context, origCTM);
961+
962+	CGContextConcatCTM (state.context, state.transform);
963+	CGContextDrawShading (state.context, state.shading);
964+    } else if (state.action != DO_NOTHING) {
965 	rv = CAIRO_INT_STATUS_UNSUPPORTED;
966+	goto BAIL;
967     }
968
969+    if (path_for_unbounded) {
970+	CGContextSetCTM (state.context, origCTM);
971+	CGContextConcatCTM (state.context, strokeTransform);
972+
973+	CGContextBeginPath (state.context);
974+	CGContextAddPath (state.context, path_for_unbounded);
975+	CGPathRelease (path_for_unbounded);
976+
977+	CGContextReplacePathWithStrokedPath (state.context);
978+
979+	CGContextAddRect (state.context, CGContextGetClipBoundingBox (state.context));
980+
981+	CGContextSetRGBFillColor (state.context, 0., 0., 0., 0.);
982+	CGContextEOFillPath (state.context);
983+    }
984+
985   BAIL:
986-    _cairo_quartz_teardown_source (surface, source);
987-
988-    CGContextRestoreGState (surface->cgContext);
989-
990-    if (path_for_unbounded) {
991-	CGContextSaveGState (surface->cgContext);
992-	CGContextConcatCTM (surface->cgContext, strokeTransform);
993-
994-	CGContextBeginPath (surface->cgContext);
995-	CGContextAddPath (surface->cgContext, path_for_unbounded);
996-	CGPathRelease (path_for_unbounded);
997-
998-	CGContextReplacePathWithStrokedPath (surface->cgContext);
999-
1000-	CGContextAddRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext));
1001-
1002-	CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
1003-	CGContextEOFillPath (surface->cgContext);
1004-
1005-	CGContextRestoreGState (surface->cgContext);
1006-    }
1007+    _cairo_quartz_teardown_state (&state);
1008
1009     ND((stderr, "-- stroke\n"));
1010     return rv;
1011 }
1012
1013 #if CAIRO_HAS_QUARTZ_FONT
1014 static cairo_int_status_t
1015 _cairo_quartz_surface_show_glyphs (void *abstract_surface,
1016@@ -2429,17 +2468,17 @@ _cairo_quartz_surface_show_glyphs (void
1017 #define STATIC_BUF_SIZE 64
1018     CGGlyph glyphs_static[STATIC_BUF_SIZE];
1019     CGSize cg_advances_static[STATIC_BUF_SIZE];
1020     CGGlyph *cg_glyphs = &glyphs_static[0];
1021     CGSize *cg_advances = &cg_advances_static[0];
1022
1023     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1024     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
1025-    cairo_quartz_action_t action;
1026+    cairo_quartz_drawing_state_t state;
1027     float xprev, yprev;
1028     int i;
1029     CGFontRef cgfref = NULL;
1030
1031     cairo_bool_t isClipping = FALSE;
1032     cairo_bool_t didForceFontSmoothing = FALSE;
1033
1034     if (IS_EMPTY(surface))
1035@@ -2450,65 +2489,59 @@ _cairo_quartz_surface_show_glyphs (void
1036
1037     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ)
1038 	return CAIRO_INT_STATUS_UNSUPPORTED;
1039
1040     rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
1041     if (unlikely (rv))
1042 	return rv;
1043
1044-    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
1045-    if (unlikely (rv))
1046-	return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
1047-
1048-    CGContextSaveGState (surface->cgContext);
1049-
1050     if (_cairo_quartz_source_needs_extents (source))
1051     {
1052         cairo_rectangle_int_t glyph_extents;
1053         _cairo_scaled_font_glyph_device_extents (scaled_font, glyphs, num_glyphs,
1054                                                  &glyph_extents, NULL);
1055-        action = _cairo_quartz_setup_source (surface, source, &glyph_extents);
1056+        state = _cairo_quartz_setup_state (surface, source, op, &glyph_extents);
1057     } else {
1058-        action = _cairo_quartz_setup_source (surface, source, NULL);
1059+        state = _cairo_quartz_setup_state (surface, source, op, NULL);
1060     }
1061
1062-    if (action == DO_SOLID || action == DO_PATTERN) {
1063-	CGContextSetTextDrawingMode (surface->cgContext, kCGTextFill);
1064-    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE || action == DO_SHADING) {
1065-	CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip);
1066+    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
1067+	CGContextSetTextDrawingMode (state.context, kCGTextFill);
1068+    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || state.action == DO_SHADING) {
1069+	CGContextSetTextDrawingMode (state.context, kCGTextClip);
1070 	isClipping = TRUE;
1071     } else {
1072-	if (action != DO_NOTHING)
1073+	if (state.action != DO_NOTHING)
1074 	    rv = CAIRO_INT_STATUS_UNSUPPORTED;
1075 	goto BAIL;
1076     }
1077
1078     /* this doesn't addref */
1079     cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font);
1080-    CGContextSetFont (surface->cgContext, cgfref);
1081-    CGContextSetFontSize (surface->cgContext, 1.0);
1082+    CGContextSetFont (state.context, cgfref);
1083+    CGContextSetFontSize (state.context, 1.0);
1084
1085     switch (scaled_font->options.antialias) {
1086 	case CAIRO_ANTIALIAS_SUBPIXEL:
1087-	    CGContextSetShouldAntialias (surface->cgContext, TRUE);
1088-	    CGContextSetShouldSmoothFonts (surface->cgContext, TRUE);
1089+	    CGContextSetShouldAntialias (state.context, TRUE);
1090+	    CGContextSetShouldSmoothFonts (state.context, TRUE);
1091 	    if (CGContextSetAllowsFontSmoothingPtr &&
1092-		!CGContextGetAllowsFontSmoothingPtr (surface->cgContext))
1093+		!CGContextGetAllowsFontSmoothingPtr (state.context))
1094 	    {
1095 		didForceFontSmoothing = TRUE;
1096-		CGContextSetAllowsFontSmoothingPtr (surface->cgContext, TRUE);
1097+		CGContextSetAllowsFontSmoothingPtr (state.context, TRUE);
1098 	    }
1099 	    break;
1100 	case CAIRO_ANTIALIAS_NONE:
1101-	    CGContextSetShouldAntialias (surface->cgContext, FALSE);
1102+	    CGContextSetShouldAntialias (state.context, FALSE);
1103 	    break;
1104 	case CAIRO_ANTIALIAS_GRAY:
1105-	    CGContextSetShouldAntialias (surface->cgContext, TRUE);
1106-	    CGContextSetShouldSmoothFonts (surface->cgContext, FALSE);
1107+	    CGContextSetShouldAntialias (state.context, TRUE);
1108+	    CGContextSetShouldSmoothFonts (state.context, FALSE);
1109 	    break;
1110 	case CAIRO_ANTIALIAS_DEFAULT:
1111 	    /* Don't do anything */
1112 	    break;
1113     }
1114
1115     if (num_glyphs > STATIC_BUF_SIZE) {
1116 	cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof(CGGlyph));
1117@@ -2532,17 +2565,17 @@ _cairo_quartz_surface_show_glyphs (void
1118     textTransform = CGAffineTransformScale (textTransform, 1.0, -1.0);
1119     textTransform = CGAffineTransformConcat (CGAffineTransformMake(scaled_font->ctm.xx,
1120 								   -scaled_font->ctm.yx,
1121 								   -scaled_font->ctm.xy,
1122 								   scaled_font->ctm.yy,
1123 								   0., 0.),
1124 					     textTransform);
1125
1126-    CGContextSetTextMatrix (surface->cgContext, textTransform);
1127+    CGContextSetTextMatrix (state.context, textTransform);
1128
1129     /* Convert our glyph positions to glyph advances.  We need n-1 advances,
1130      * since the advance at index 0 is applied after glyph 0. */
1131     xprev = glyphs[0].x;
1132     yprev = glyphs[0].y;
1133
1134     cg_glyphs[0] = glyphs[0].index;
1135
1136@@ -2569,40 +2602,38 @@ _cairo_quartz_surface_show_glyphs (void
1137
1138 #if 0
1139     for (i = 0; i < num_glyphs; i++) {
1140 	ND((stderr, "[%d: %d %f,%f]\n", i, cg_glyphs[i], cg_advances[i].width, cg_advances[i].height));
1141     }
1142 #endif
1143
1144     /* Translate to the first glyph's position before drawing */
1145-    ctm = CGContextGetCTM (surface->cgContext);
1146-    CGContextTranslateCTM (surface->cgContext, glyphs[0].x, glyphs[0].y);
1147-
1148-    CGContextShowGlyphsWithAdvances (surface->cgContext,
1149+    ctm = CGContextGetCTM (state.context);
1150+    CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y);
1151+
1152+    CGContextShowGlyphsWithAdvances (state.context,
1153 				     cg_glyphs,
1154 				     cg_advances,
1155 				     num_glyphs);
1156
1157-    CGContextSetCTM (surface->cgContext, ctm);
1158-
1159-    if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
1160-	_cairo_quartz_draw_image (surface, op, action);
1161-    } else if (action == DO_SHADING) {
1162-	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
1163-	CGContextDrawShading (surface->cgContext, surface->sourceShading);
1164+    CGContextSetCTM (state.context, ctm);
1165+
1166+    if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) {
1167+	_cairo_quartz_draw_image (&state, op);
1168+    } else if (state.action == DO_SHADING) {
1169+	CGContextConcatCTM (state.context, state.transform);
1170+	CGContextDrawShading (state.context, state.shading);
1171     }
1172
1173 BAIL:
1174-    _cairo_quartz_teardown_source (surface, source);
1175-
1176     if (didForceFontSmoothing)
1177-	CGContextSetAllowsFontSmoothingPtr (surface->cgContext, FALSE);
1178-
1179-    CGContextRestoreGState (surface->cgContext);
1180+        CGContextSetAllowsFontSmoothingPtr (state.context, FALSE);
1181+
1182+    _cairo_quartz_teardown_state (&state);
1183
1184     if (rv == CAIRO_STATUS_SUCCESS &&
1185 	cgfref &&
1186 	!_cairo_operator_bounded_by_mask (op))
1187     {
1188 	unbounded_op_data_t ub;
1189 	ub.op = UNBOUNDED_SHOW_GLYPHS;
1190
1191