Added 'mac-sdk-package' Make target
[mono.git] / bockbuild / MacSDK / patches / cairo-cglayer.patch
1 --- a/src/cairo-quartz-font.c   2012-11-13 18:20:00.000000000 -0800
2 +++ b/src/cairo-quartz-font.c   2012-11-13 18:06:56.000000000 -0800
3 @@ -90,8 +90,9 @@ static int (*CGFontGetAscentPtr) (CGFont
4  static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
5  static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
6
7 -/* Not public anymore in 64-bits nor in 10.7 */
8 -static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;
9 +/* CTFontCreateWithGraphicsFont is not public until 10.5. */
10 +typedef const struct __CTFontDescriptor *CTFontDescriptorRef;
11 +static CTFontRef (*CTFontCreateWithGraphicsFontPtr) (CGFontRef, CGFloat, const CGAffineTransform *, CTFontDescriptorRef) = NULL;
12
13  static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
14  static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
15 @@ -130,7 +131,7 @@ quartz_font_ensure_symbols(void)
16      CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
17      CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
18
19 -    FMGetATSFontRefFromFontPtr = dlsym(RTLD_DEFAULT, "FMGetATSFontRefFromFont");
20 +    CTFontCreateWithGraphicsFontPtr = dlsym(RTLD_DEFAULT, "CTFontCreateWithGraphicsFont");
21
22      if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
23         CGFontGetGlyphBBoxesPtr &&
24 @@ -155,6 +156,7 @@ struct _cairo_quartz_font_face {
25      cairo_font_face_t base;
26
27      CGFontRef cgFont;
28 +    CTFontRef ctFont;
29  };
30
31  /*
32 @@ -239,6 +241,10 @@ _cairo_quartz_font_face_destroy (void *a
33  {
34      cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
35
36 +    if (font_face->ctFont) {
37 +        CFRelease (font_face->ctFont);
38 +    }
39 +
40      CGFontRelease (font_face->cgFont);
41  }
42
43 @@ -363,6 +369,12 @@ cairo_quartz_font_face_create_for_cgfont
44
45      font_face->cgFont = CGFontRetain (font);
46
47 +    if (CTFontCreateWithGraphicsFontPtr) {
48 +        font_face->ctFont = CTFontCreateWithGraphicsFontPtr (font, 1.0, NULL, NULL);
49 +    } else {
50 +        font_face->ctFont = NULL;
51 +    }
52 +
53      _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
54
55      return &font_face->base;
56 @@ -782,49 +794,10 @@ _cairo_quartz_scaled_font_get_cg_font_re
57      return ffont->cgFont;
58  }
59
60 -/*
61 - * compat with old ATSUI backend
62 - */
63 -
64 -/**
65 - * cairo_quartz_font_face_create_for_atsu_font_id
66 - * @font_id: an ATSUFontID for the font.
67 - *
68 - * Creates a new font for the Quartz font backend based on an
69 - * #ATSUFontID. This font can then be used with
70 - * cairo_set_font_face() or cairo_scaled_font_create().
71 - *
72 - * Return value: a newly created #cairo_font_face_t. Free with
73 - *  cairo_font_face_destroy() when you are done using it.
74 - *
75 - * Since: 1.6
76 - **/
77 -cairo_font_face_t *
78 -cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id)
79 +CTFontRef
80 +_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *abstract_font)
81  {
82 -    quartz_font_ensure_symbols();
83 -
84 -    if (FMGetATSFontRefFromFontPtr != NULL) {
85 -       ATSFontRef atsFont = FMGetATSFontRefFromFontPtr (font_id);
86 -       CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont);
87 -       cairo_font_face_t *ff;
88 -
89 -       ff = cairo_quartz_font_face_create_for_cgfont (cgFont);
90 -
91 -       CGFontRelease (cgFont);
92 -
93 -       return ff;
94 -    } else {
95 -       _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
96 -       return (cairo_font_face_t *)&_cairo_font_face_nil;
97 -    }
98 -}
99 -
100 -/* This is the old name for the above function, exported for compat purposes */
101 -cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id);
102 +    cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
103
104 -cairo_font_face_t *
105 -cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
106 -{
107 -    return cairo_quartz_font_face_create_for_atsu_font_id (font_id);
108 +    return ffont->ctFont;
109  }
110 --- a/src/cairo-quartz-image-surface.c  2010-06-18 04:47:13.000000000 -0700
111 +++ b/src/cairo-quartz-image-surface.c  2012-11-13 18:06:56.000000000 -0800
112 @@ -148,6 +148,8 @@ _cairo_quartz_image_surface_flush (void
113      surface->image = newImage;
114      CGImageRelease (oldImage);
115
116 +    surface->base.is_clear = surface->imageSurface->base.is_clear;
117 +
118      return CAIRO_STATUS_SUCCESS;
119  }
120
121 @@ -270,6 +272,8 @@ cairo_quartz_image_surface_create (cairo
122      qisurf->image = image;
123      qisurf->imageSurface = image_surface;
124
125 +    qisurf->base.is_clear = image_surface->base.is_clear;
126 +
127      return &qisurf->base;
128  }
129
130 --- a/src/cairo-quartz-private.h        2010-12-25 06:21:34.000000000 -0800
131 +++ b/src/cairo-quartz-private.h        2012-11-13 18:06:56.000000000 -0800
132 @@ -50,6 +50,9 @@ typedef CGFloat cairo_quartz_float_t;
133  typedef float cairo_quartz_float_t;
134  #endif
135
136 +/* define CTFontRef for pre-10.5 SDKs */
137 +typedef const struct __CTFont *CTFontRef;
138 +
139  typedef struct cairo_quartz_surface {
140      cairo_surface_t base;
141
142 @@ -60,21 +63,22 @@ typedef struct cairo_quartz_surface {
143      cairo_surface_t *imageSurfaceEquiv;
144
145      cairo_surface_clipper_t clipper;
146 -    cairo_rectangle_int_t extents;
147
148 -    /* These are stored while drawing operations are in place, set up
149 -     * by quartz_setup_source() and quartz_finish_source()
150 +    /**
151 +     * If non-null, this is a CGImage representing the contents of the surface.
152 +     * We clear this out before any painting into the surface, so that we
153 +     * don't force a copy to be created.
154       */
155 -    CGAffineTransform sourceTransform;
156 +    CGImageRef bitmapContextImage;
157
158 -    CGImageRef sourceImage;
159 -    cairo_surface_t *sourceImageSurface;
160 -    CGRect sourceImageRect;
161 +    /**
162 +     * If non-null, this is the CGLayer for the surface.
163 +     */
164 +    CGLayerRef cgLayer;
165
166 -    CGShadingRef sourceShading;
167 -    CGPatternRef sourcePattern;
168 +    cairo_rectangle_int_t extents;
169
170 -    CGInterpolationQuality oldInterpolationQuality;
171 +    cairo_bool_t ownsData;
172  } cairo_quartz_surface_t;
173
174  typedef struct cairo_quartz_image_surface {
175 @@ -103,6 +107,9 @@ _cairo_quartz_create_cgimage (cairo_form
176  CGFontRef
177  _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
178
179 +CTFontRef
180 +_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *sfont);
181 +
182  #else
183
184  # error Cairo was not compiled with support for the quartz backend
185 --- a/src/cairo-quartz-surface.c        2012-11-13 18:20:00.000000000 -0800
186 +++ b/src/cairo-quartz-surface.c        2012-11-13 18:06:56.000000000 -0800
187 @@ -41,6 +41,8 @@
188
189  #include "cairo-error-private.h"
190  #include "cairo-surface-clipper-private.h"
191 +#include "cairo-gstate-private.h"
192 +#include "cairo-private.h"
193
194  #include <dlfcn.h>
195
196 @@ -77,6 +79,11 @@
197   * This macro can be used to conditionally compile backend-specific code.
198   */
199
200 +/* Here are some of the differences between cairo and CoreGraphics
201 +   - cairo has only a single source active at once vs. CoreGraphics having
202 +     separate sources for stroke and fill
203 +*/
204 +
205  /* This method is private, but it exists.  Its params are are exposed
206   * as args to the NS* method, but not as CG.
207   */
208 @@ -126,6 +133,12 @@ static void (*CGContextSetShouldAntialia
209  static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
210  static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
211  static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL;
212 +static CGFloat (*CGContextGetAlphaPtr) (CGContextRef) = NULL;
213 +
214 +/* CTFontDrawGlyphs is not available until 10.7 */
215 +static void (*CTFontDrawGlyphsPtr) (CTFontRef, const CGGlyph[], const CGPoint[], size_t, CGContextRef) = NULL;
216 +
217 +static SInt32 _cairo_quartz_osx_version = 0x0;
218
219  static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
220
221 @@ -160,6 +173,14 @@ static void quartz_ensure_symbols(void)
222      CGContextCopyPathPtr = dlsym(RTLD_DEFAULT, "CGContextCopyPath");
223      CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
224      CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
225 +    CGContextGetAlphaPtr = dlsym(RTLD_DEFAULT, "CGContextGetAlpha");
226 +
227 +    CTFontDrawGlyphsPtr = dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
228 +
229 +    if (Gestalt(gestaltSystemVersion, &_cairo_quartz_osx_version) != noErr) {
230 +        // assume 10.5
231 +        _cairo_quartz_osx_version = 0x1050;
232 +    }
233
234      _cairo_quartz_symbol_lookup_done = TRUE;
235  }
236 @@ -430,6 +446,7 @@ _cairo_quartz_cairo_operator_to_quartz_c
237         case CAIRO_OPERATOR_HSL_LUMINOSITY:
238          default:
239             assert (0);
240 +           return kPrivateCGCompositeClear;
241      }
242  }
243
244 @@ -598,10 +615,13 @@ _cairo_quartz_cairo_matrix_to_quartz (co
245  typedef struct {
246      bool isClipping;
247      CGGlyph *cg_glyphs;
248 -    CGSize *cg_advances;
249 +    union {
250 +      CGSize *cg_advances;
251 +      CGPoint *cg_positions;
252 +    } u;
253      size_t nglyphs;
254      CGAffineTransform textTransform;
255 -    CGFontRef font;
256 +    cairo_scaled_font_t *scaled_font;
257      CGPoint origin;
258  } unbounded_show_glyphs_t;
259
260 @@ -679,12 +699,6 @@ _cairo_quartz_fixup_unbounded_operation
261         else
262             CGContextEOFillPath (cgc);
263      } else if (op->op == UNBOUNDED_SHOW_GLYPHS) {
264 -       CGContextSetFont (cgc, op->u.show_glyphs.font);
265 -       CGContextSetFontSize (cgc, 1.0);
266 -       CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
267 -       CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
268 -       CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
269 -
270         if (op->u.show_glyphs.isClipping) {
271             /* Note that the comment in show_glyphs about kCGTextClip
272              * and the text transform still applies here; however, the
273 @@ -693,12 +707,25 @@ _cairo_quartz_fixup_unbounded_operation
274             CGContextSetTextDrawingMode (cgc, kCGTextClip);
275             CGContextSaveGState (cgc);
276         }
277 +        CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
278 +        CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
279 +        if (CTFontDrawGlyphsPtr) {
280 +            CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (op->u.show_glyphs.scaled_font),
281 +                                 op->u.show_glyphs.cg_glyphs,
282 +                                 op->u.show_glyphs.u.cg_positions,
283 +                                 op->u.show_glyphs.nglyphs,
284 +                                 cgc);
285 +        } else {
286 +           CGContextSetFont (cgc, _cairo_quartz_scaled_font_get_cg_font_ref (op->u.show_glyphs.scaled_font));
287 +           CGContextSetFontSize (cgc, 1.0);
288 +           CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
289 +
290 +           CGContextShowGlyphsWithAdvances (cgc,
291 +                                            op->u.show_glyphs.cg_glyphs,
292 +                                            op->u.show_glyphs.u.cg_advances,
293 +                                            op->u.show_glyphs.nglyphs);
294
295 -       CGContextShowGlyphsWithAdvances (cgc,
296 -                                        op->u.show_glyphs.cg_glyphs,
297 -                                        op->u.show_glyphs.cg_advances,
298 -                                        op->u.show_glyphs.nglyphs);
299 -
300 +        }
301         if (op->u.show_glyphs.isClipping) {
302             CGContextClearRect (cgc, clipBoxRound);
303             CGContextRestoreGState (cgc);
304 @@ -1102,12 +1129,12 @@ DataProviderReleaseCallback (void *info,
305  {
306      quartz_source_image_t *source_img = info;
307      _cairo_surface_release_source_image (source_img->surface, source_img->image_out, source_img->image_extra);
308 +    cairo_surface_destroy (source_img->surface);
309      free (source_img);
310  }
311
312  static cairo_status_t
313 -_cairo_surface_to_cgimage (cairo_surface_t *target,
314 -                          cairo_surface_t *source,
315 +_cairo_surface_to_cgimage (cairo_surface_t *source,
316                            CGImageRef *image_out)
317  {
318      cairo_status_t status;
319 @@ -1127,9 +1154,14 @@ _cairo_surface_to_cgimage (cairo_surface
320         }
321
322         if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
323 -           *image_out = CGBitmapContextCreateImage (surface->cgContext);
324 -           if (*image_out)
325 -               return CAIRO_STATUS_SUCCESS;
326 +           if (!surface->bitmapContextImage) {
327 +               surface->bitmapContextImage =
328 +                   CGBitmapContextCreateImage (surface->cgContext);
329 +           }
330 +           if (surface->bitmapContextImage) {
331 +                *image_out = CGImageRetain (surface->bitmapContextImage);
332 +                return CAIRO_STATUS_SUCCESS;
333 +            }
334         }
335      }
336
337 @@ -1137,10 +1169,11 @@ _cairo_surface_to_cgimage (cairo_surface
338      if (source_img == NULL)
339         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
340
341 -    source_img->surface = source;
342 +    source_img->surface = cairo_surface_reference(source);
343
344      status = _cairo_surface_acquire_source_image (source_img->surface, &source_img->image_out, &source_img->image_extra);
345      if (status) {
346 +       cairo_surface_destroy (source_img->surface);
347         free (source_img);
348         return status;
349      }
350 @@ -1251,7 +1284,7 @@ _cairo_quartz_cairo_repeating_surface_pa
351      is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
352      assert (is_bounded);
353
354 -    status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image);
355 +    status = _cairo_surface_to_cgimage (pat_surf, &image);
356      if (status)
357         return status;
358      if (image == NULL)
359 @@ -1322,16 +1355,43 @@ typedef enum {
360      DO_SHADING,
361      DO_PATTERN,
362      DO_IMAGE,
363 +    DO_TILED_IMAGE,
364 +    DO_LAYER,
365      DO_UNSUPPORTED,
366 -    DO_NOTHING,
367 -    DO_TILED_IMAGE
368 +    DO_NOTHING
369  } cairo_quartz_action_t;
370
371 -static cairo_quartz_action_t
372 +/* State used during a drawing operation. */
373 +typedef struct {
374 +    CGContextRef context;
375 +    cairo_quartz_action_t action;
376 +
377 +    // Used with DO_SHADING, DO_IMAGE, DO_TILED_IMAGE and DO_LAYER
378 +    CGAffineTransform transform;
379 +
380 +    // Used with DO_IMAGE and DO_TILED_IMAGE
381 +    CGImageRef image;
382 +    cairo_surface_t *imageSurface;
383 +
384 +    // Used with DO_IMAGE, DO_TILED_IMAGE and DO_LAYER
385 +    CGRect imageRect;
386 +
387 +    // Used with DO_LAYER
388 +    CGLayerRef layer;
389 +
390 +    // Used with DO_SHADING
391 +    CGShadingRef shading;
392 +
393 +    // Used with DO_PATTERN
394 +    CGPatternRef pattern;
395 +} cairo_quartz_drawing_state_t;
396 +
397 +static void
398  _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
399 -                                    const cairo_pattern_t *source)
400 +                                    const cairo_pattern_t *source,
401 +                                    cairo_quartz_drawing_state_t *state)
402  {
403 -    CGRect clipBox = CGContextGetClipBoundingBox (surface->cgContext);
404 +    CGRect clipBox = CGContextGetClipBoundingBox (state->context);
405      double x0, y0, w, h;
406
407      cairo_surface_t *fallback;
408 @@ -1340,8 +1400,10 @@ _cairo_quartz_setup_fallback_source (cai
409      cairo_status_t status;
410
411      if (clipBox.size.width == 0.0f ||
412 -       clipBox.size.height == 0.0f)
413 -       return DO_NOTHING;
414 +       clipBox.size.height == 0.0f) {
415 +       state->action = DO_NOTHING;
416 +       return;
417 +    }
418
419      x0 = floor(clipBox.origin.x);
420      y0 = floor(clipBox.origin.y);
421 @@ -1384,18 +1446,21 @@ _cairo_quartz_setup_fallback_source (cai
422      }
423  #endif
424
425 -    status = _cairo_surface_to_cgimage (&surface->base, fallback, &img);
426 -    if (status)
427 -       return DO_UNSUPPORTED;
428 -    if (img == NULL)
429 -       return DO_NOTHING;
430 -
431 -    surface->sourceImageRect = CGRectMake (0.0, 0.0, w, h);
432 -    surface->sourceImage = img;
433 -    surface->sourceImageSurface = fallback;
434 -    surface->sourceTransform = CGAffineTransformMakeTranslation (x0, y0);
435 +    status = _cairo_surface_to_cgimage (fallback, &img);
436 +    if (status) {
437 +        state->action = DO_UNSUPPORTED;
438 +       return;
439 +    }
440 +    if (img == NULL) {
441 +        state->action = DO_NOTHING;
442 +       return;
443 +    }
444
445 -    return DO_IMAGE;
446 +    state->imageRect = CGRectMake (0.0, 0.0, w, h);
447 +    state->image = img;
448 +    state->imageSurface = fallback;
449 +    state->transform = CGAffineTransformMakeTranslation (x0, y0);
450 +    state->action = DO_IMAGE;
451  }
452
453  /*
454 @@ -1411,10 +1476,11 @@ based on the extents of the object (the
455  we don't want the rasterization of the entire gradient to depend on the
456  clip region).
457  */
458 -static cairo_quartz_action_t
459 +static void
460  _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
461                                    const cairo_linear_pattern_t *lpat,
462 -                                  cairo_rectangle_int_t *extents)
463 +                                  cairo_rectangle_int_t *extents,
464 +                                  cairo_quartz_drawing_state_t *state)
465  {
466      const cairo_pattern_t *abspat = &lpat->base.base;
467      cairo_matrix_t mat;
468 @@ -1424,9 +1490,10 @@ _cairo_quartz_setup_linear_source (cairo
469      bool extend = abspat->extend == CAIRO_EXTEND_PAD;
470
471      if (lpat->base.n_stops == 0) {
472 -       CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.);
473 -       CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
474 -       return DO_SOLID;
475 +       CGContextSetRGBStrokeColor (state->context, 0., 0., 0., 0.);
476 +       CGContextSetRGBFillColor (state->context, 0., 0., 0., 0.);
477 +       state->action = DO_SOLID;
478 +       return;
479      }
480
481      if (lpat->p1.x == lpat->p2.x &&
482 @@ -1436,12 +1503,13 @@ _cairo_quartz_setup_linear_source (cairo
483          * Whatever the correct behaviour is, let's at least have only pixman's
484          * implementation to worry about.
485          */
486 -       return _cairo_quartz_setup_fallback_source (surface, abspat);
487 +       _cairo_quartz_setup_fallback_source (surface, abspat, state);
488 +       return;
489      }
490
491      mat = abspat->matrix;
492      cairo_matrix_invert (&mat);
493 -    _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform);
494 +    _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform);
495
496      rgb = CGColorSpaceCreateDeviceRGB();
497
498 @@ -1461,21 +1529,22 @@ _cairo_quartz_setup_linear_source (cairo
499                                                           extents);
500      }
501
502 -    surface->sourceShading = CGShadingCreateAxial (rgb,
503 -                                                  start, end,
504 -                                                  gradFunc,
505 -                                                  extend, extend);
506 +    state->shading = CGShadingCreateAxial (rgb,
507 +                                          start, end,
508 +                                          gradFunc,
509 +                                          extend, extend);
510
511      CGColorSpaceRelease(rgb);
512      CGFunctionRelease(gradFunc);
513
514 -    return DO_SHADING;
515 +    state->action = DO_SHADING;
516  }
517
518 -static cairo_quartz_action_t
519 +static void
520  _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
521                                    const cairo_radial_pattern_t *rpat,
522 -                                  cairo_rectangle_int_t *extents)
523 +                                  cairo_rectangle_int_t *extents,
524 +                                  cairo_quartz_drawing_state_t *state)
525  {
526      const cairo_pattern_t *abspat = &rpat->base.base;
527      cairo_matrix_t mat;
528 @@ -1494,9 +1563,10 @@ _cairo_quartz_setup_radial_source (cairo
529      double centerDistance = sqrt (dx*dx + dy*dy);
530
531      if (rpat->base.n_stops == 0) {
532 -       CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.);
533 -       CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
534 -       return DO_SOLID;
535 +       CGContextSetRGBStrokeColor (state->context, 0., 0., 0., 0.);
536 +       CGContextSetRGBFillColor (state->context, 0., 0., 0., 0.);
537 +       state->action = DO_SOLID;
538 +       return;
539      }
540
541      if (r2 <= centerDistance + r1 + 1e-6 && /* circle 2 doesn't contain circle 1 */
542 @@ -1507,12 +1577,13 @@ _cairo_quartz_setup_radial_source (cairo
543          * implementation to worry about.
544          * Note that this also catches the cases where r1 == r2.
545          */
546 -       return _cairo_quartz_setup_fallback_source (surface, abspat);
547 +       _cairo_quartz_setup_fallback_source (surface, abspat, state);
548 +       return;
549      }
550
551      mat = abspat->matrix;
552      cairo_matrix_invert (&mat);
553 -    _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform);
554 +    _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform);
555
556      rgb = CGColorSpaceCreateDeviceRGB();
557
558 @@ -1531,90 +1602,79 @@ _cairo_quartz_setup_radial_source (cairo
559                                                           extents);
560      }
561
562 -    surface->sourceShading = CGShadingCreateRadial (rgb,
563 -                                                   start,
564 -                                                   r1,
565 -                                                   end,
566 -                                                   r2,
567 -                                                   gradFunc,
568 -                                                   extend, extend);
569 +    state->shading = CGShadingCreateRadial (rgb,
570 +                                           start,
571 +                                           r1,
572 +                                           end,
573 +                                           r2,
574 +                                           gradFunc,
575 +                                           extend, extend);
576
577      CGColorSpaceRelease(rgb);
578      CGFunctionRelease(gradFunc);
579
580 -    return DO_SHADING;
581 +    state->action = DO_SHADING;
582  }
583
584 -static cairo_quartz_action_t
585 -_cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
586 -                           const cairo_pattern_t *source,
587 -                           cairo_rectangle_int_t *extents)
588 +static void
589 +_cairo_quartz_setup_surface_source (cairo_quartz_surface_t *surface,
590 +                                   const cairo_surface_pattern_t *spat,
591 +                                   cairo_rectangle_int_t *extents,
592 +                                   cairo_quartz_drawing_state_t *state)
593  {
594 -    assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern));
595 -
596 -    surface->oldInterpolationQuality = CGContextGetInterpolationQuality (surface->cgContext);
597 -    CGContextSetInterpolationQuality (surface->cgContext, _cairo_quartz_filter_to_quartz (source->filter));
598 +    const cairo_pattern_t *source = &spat->base;
599 +    CGContextRef context = state->context;
600
601 -    if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
602 -       cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
603 -
604 -       CGContextSetRGBStrokeColor (surface->cgContext,
605 -                                   solid->color.red,
606 -                                   solid->color.green,
607 -                                   solid->color.blue,
608 -                                   solid->color.alpha);
609 -       CGContextSetRGBFillColor (surface->cgContext,
610 -                                 solid->color.red,
611 -                                 solid->color.green,
612 -                                 solid->color.blue,
613 -                                 solid->color.alpha);
614 -
615 -       return DO_SOLID;
616 -    }
617 -
618 -    if (source->type == CAIRO_PATTERN_TYPE_LINEAR) {
619 -       const cairo_linear_pattern_t *lpat = (const cairo_linear_pattern_t *)source;
620 -       return _cairo_quartz_setup_linear_source (surface, lpat, extents);
621 -    }
622 -
623 -    if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
624 -       const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source;
625 -       return _cairo_quartz_setup_radial_source (surface, rpat, extents);
626 -    }
627 -
628 -    if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
629 -       (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
630 +    if (source->extend == CAIRO_EXTEND_NONE || source->extend == CAIRO_EXTEND_PAD ||
631 +        (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT))
632      {
633 -       const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source;
634         cairo_surface_t *pat_surf = spat->surface;
635         CGImageRef img;
636         cairo_matrix_t m = spat->base.matrix;
637         cairo_rectangle_int_t extents;
638 -       cairo_status_t status;
639         CGAffineTransform xform;
640         CGRect srcRect;
641         cairo_fixed_t fw, fh;
642         cairo_bool_t is_bounded;
643 +       cairo_bool_t repeat = source->extend == CAIRO_EXTEND_REPEAT;
644 +        cairo_status_t status;
645
646 -       status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
647 -       if (status)
648 -           return DO_UNSUPPORTED;
649 -       if (img == NULL)
650 -           return DO_NOTHING;
651 +        cairo_matrix_invert(&m);
652 +        _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform);
653
654 -       CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1);
655 +        /* Draw nonrepeating CGLayer surface using DO_LAYER */
656 +        if (!repeat && cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) {
657 +            cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf;
658 +            if (quartz_surf->cgLayer) {
659 +               state->imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height);
660 +                state->layer = quartz_surf->cgLayer;
661 +                state->action = DO_LAYER;
662 +                return;
663 +            }
664 +        }
665 +
666 +       status = _cairo_surface_to_cgimage (pat_surf, &img);
667 +        if (status) {
668 +            state->action = DO_UNSUPPORTED;
669 +           return;
670 +        }
671 +        if (img == NULL) {
672 +            state->action = DO_NOTHING;
673 +           return;
674 +        }
675
676 -       surface->sourceImage = img;
677 +        /* XXXroc what is this for? */
678 +       CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1);
679
680 -       cairo_matrix_invert(&m);
681 -       _cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceTransform);
682 +       state->image = img;
683
684         is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
685         assert (is_bounded);
686
687 -       if (source->extend == CAIRO_EXTEND_NONE) {
688 -           surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
689 -           return DO_IMAGE;
690 +       if (!repeat) {
691 +           state->imageRect = CGRectMake (0, 0, extents.width, extents.height);
692 +           state->action = DO_IMAGE;
693 +           return;
694         }
695
696         /* Quartz seems to tile images at pixel-aligned regions only -- this
697 @@ -1624,8 +1684,8 @@ _cairo_quartz_setup_source (cairo_quartz
698          * epsilon), and if not, fall back to the CGPattern type.
699          */
700
701 -       xform = CGAffineTransformConcat (CGContextGetCTM (surface->cgContext),
702 -                                        surface->sourceTransform);
703 +       xform = CGAffineTransformConcat (CGContextGetCTM (context),
704 +                                        state->transform);
705
706         srcRect = CGRectMake (0, 0, extents.width, extents.height);
707         srcRect = CGRectApplyAffineTransform (srcRect, xform);
708 @@ -1646,101 +1706,218 @@ _cairo_quartz_setup_source (cairo_quartz
709
710             srcRect = CGRectApplyAffineTransform (srcRect, xform);
711
712 -           surface->sourceImageRect = srcRect;
713 -
714 -           return DO_TILED_IMAGE;
715 +           state->imageRect = srcRect;
716 +            state->action = DO_TILED_IMAGE;
717 +            return;
718         }
719
720         /* Fall through to generic SURFACE case */
721      }
722
723 -    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
724 -       cairo_quartz_float_t patternAlpha = 1.0f;
725 -       CGColorSpaceRef patternSpace;
726 -       CGPatternRef pattern;
727 -       cairo_int_status_t status;
728 -
729 -       status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern);
730 -       if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
731 -           return DO_NOTHING;
732 -       if (status)
733 -           return DO_UNSUPPORTED;
734 -
735 -       // Save before we change the pattern, colorspace, etc. so that
736 -       // we can restore and make sure that quartz releases our
737 -       // pattern (which may be stack allocated)
738 -       CGContextSaveGState(surface->cgContext);
739 -
740 -       patternSpace = CGColorSpaceCreatePattern(NULL);
741 -       CGContextSetFillColorSpace (surface->cgContext, patternSpace);
742 -       CGContextSetFillPattern (surface->cgContext, pattern, &patternAlpha);
743 -       CGContextSetStrokeColorSpace (surface->cgContext, patternSpace);
744 -       CGContextSetStrokePattern (surface->cgContext, pattern, &patternAlpha);
745 -       CGColorSpaceRelease (patternSpace);
746 -
747 -       /* Quartz likes to munge the pattern phase (as yet unexplained
748 -        * why); force it to 0,0 as we've already baked in the correct
749 -        * pattern translation into the pattern matrix
750 -        */
751 -       CGContextSetPatternPhase (surface->cgContext, CGSizeMake(0,0));
752 -
753 -       surface->sourcePattern = pattern;
754 +    CGFloat patternAlpha = 1.0f;
755 +    CGColorSpaceRef patternSpace;
756 +    CGPatternRef pattern;
757 +    cairo_int_status_t status;
758
759 -       return DO_PATTERN;
760 +    status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern);
761 +    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
762 +        state->action = DO_NOTHING;
763 +       return;
764 +    }
765 +    if (status) {
766 +       state->action = DO_UNSUPPORTED;
767 +       return;
768      }
769
770 -    return DO_UNSUPPORTED;
771 +    patternSpace = CGColorSpaceCreatePattern (NULL);
772 +    CGContextSetFillColorSpace (context, patternSpace);
773 +    CGContextSetFillPattern (context, pattern, &patternAlpha);
774 +    CGContextSetStrokeColorSpace (context, patternSpace);
775 +    CGContextSetStrokePattern (context, pattern, &patternAlpha);
776 +    CGColorSpaceRelease (patternSpace);
777 +
778 +    /* Quartz likes to munge the pattern phase (as yet unexplained
779 +     * why); force it to 0,0 as we've already baked in the correct
780 +     * pattern translation into the pattern matrix
781 +     */
782 +    CGContextSetPatternPhase (context, CGSizeMake(0,0));
783 +
784 +    state->pattern = pattern;
785 +    state->action = DO_PATTERN;
786 +    return;
787  }
788
789 +/**
790 + * Call this before any operation that can modify the contents of a
791 + * cairo_quartz_surface_t.
792 + */
793  static void
794 -_cairo_quartz_teardown_source (cairo_quartz_surface_t *surface,
795 -                              const cairo_pattern_t *source)
796 +_cairo_quartz_surface_will_change (cairo_quartz_surface_t *surface)
797  {
798 -    CGContextSetInterpolationQuality (surface->cgContext, surface->oldInterpolationQuality);
799 +    if (surface->bitmapContextImage) {
800 +        CGImageRelease (surface->bitmapContextImage);
801 +        surface->bitmapContextImage = NULL;
802 +    }
803 +}
804
805 -    if (surface->sourceImage) {
806 -       CGImageRelease(surface->sourceImage);
807 -       surface->sourceImage = NULL;
808 +/**
809 + * Sets up internal state to be used to draw the source mask, stored in
810 + * cairo_quartz_state_t. Guarantees to call CGContextSaveGState on
811 + * surface->cgContext.
812 + */
813 +static cairo_quartz_drawing_state_t
814 +_cairo_quartz_setup_state (cairo_quartz_surface_t *surface,
815 +                          const cairo_pattern_t *source,
816 +                          cairo_operator_t op,
817 +                          cairo_rectangle_int_t *extents)
818 +{
819 +    CGContextRef context = surface->cgContext;
820 +    cairo_quartz_drawing_state_t state;
821 +    cairo_status_t status;
822
823 -       cairo_surface_destroy(surface->sourceImageSurface);
824 -       surface->sourceImageSurface = NULL;
825 +    state.context = context;
826 +    state.image = NULL;
827 +    state.imageSurface = NULL;
828 +    state.layer = NULL;
829 +    state.shading = NULL;
830 +    state.pattern = NULL;
831 +
832 +    _cairo_quartz_surface_will_change (surface);
833 +
834 +    // Save before we change the pattern, colorspace, etc. so that
835 +    // we can restore and make sure that quartz releases our
836 +    // pattern (which may be stack allocated)
837 +    CGContextSaveGState(context);
838 +
839 +    CGContextSetInterpolationQuality (context, _cairo_quartz_filter_to_quartz (source->filter));
840 +
841 +    status = _cairo_quartz_surface_set_cairo_operator (surface, op);
842 +    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
843 +        state.action = DO_NOTHING;
844 +        return state;
845 +    }
846 +    if (status) {
847 +        state.action = DO_UNSUPPORTED;
848 +        return state;
849      }
850
851 -    if (surface->sourceShading) {
852 -       CGShadingRelease(surface->sourceShading);
853 -       surface->sourceShading = NULL;
854 +    if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
855 +       cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
856 +
857 +       CGContextSetRGBStrokeColor (context,
858 +                                   solid->color.red,
859 +                                   solid->color.green,
860 +                                   solid->color.blue,
861 +                                   solid->color.alpha);
862 +       CGContextSetRGBFillColor (context,
863 +                                 solid->color.red,
864 +                                 solid->color.green,
865 +                                 solid->color.blue,
866 +                                 solid->color.alpha);
867 +
868 +        state.action = DO_SOLID;
869 +        return state;
870 +    }
871 +
872 +    if (source->type == CAIRO_PATTERN_TYPE_LINEAR) {
873 +       const cairo_linear_pattern_t *lpat = (const cairo_linear_pattern_t *)source;
874 +       _cairo_quartz_setup_linear_source (surface, lpat, extents, &state);
875 +       return state;
876 +    }
877 +
878 +    if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
879 +       const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source;
880 +       _cairo_quartz_setup_radial_source (surface, rpat, extents, &state);
881 +       return state;
882      }
883
884 -    if (surface->sourcePattern) {
885 -       CGPatternRelease(surface->sourcePattern);
886 -       // To tear down the pattern and colorspace
887 -       CGContextRestoreGState(surface->cgContext);
888 +    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
889 +        if (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque (source, NULL) &&
890 +            CGContextGetAlphaPtr &&
891 +            CGContextGetAlphaPtr (surface->cgContext) == 1.0) {
892 +            // Quartz won't touch pixels outside the bounds of the
893 +            // source surface, so we can just go ahead and use Copy here
894 +            // to accelerate things.
895 +            // Quartz won't necessarily be able to do this optimization internally;
896 +            // for CGLayer surfaces, we can know all the pixels are opaque
897 +            // (because it's CONTENT_COLOR), but Quartz won't know.
898 +            CGContextSetCompositeOperation (context, kPrivateCGCompositeCopy);
899 +        }
900
901 -       surface->sourcePattern = NULL;
902 +       const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source;
903 +        _cairo_quartz_setup_surface_source (surface, spat, extents, &state);
904 +        return state;
905      }
906 -}
907
908 +    state.action = DO_UNSUPPORTED;
909 +    return state;
910 +}
911
912 +/**
913 + * 1) Tears down internal state used to draw the source
914 + * 2) Does CGContextRestoreGState(state->context)
915 + */
916  static void
917 -_cairo_quartz_draw_image (cairo_quartz_surface_t *surface, cairo_operator_t op,  cairo_quartz_action_t action)
918 +_cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state)
919  {
920 -    assert (surface && surface->sourceImage && (action == DO_IMAGE || action == DO_TILED_IMAGE));
921 +    if (state->image) {
922 +       CGImageRelease(state->image);
923 +    }
924
925 -    CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
926 -    CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
927 -    CGContextScaleCTM (surface->cgContext, 1, -1);
928 -
929 -    if (action == DO_IMAGE) {
930 -       CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
931 -       if (!_cairo_operator_bounded_by_source(op)) {
932 -           CGContextBeginPath (surface->cgContext);
933 -           CGContextAddRect (surface->cgContext, surface->sourceImageRect);
934 -           CGContextAddRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext));
935 -           CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 0);
936 -           CGContextEOFillPath (surface->cgContext);
937 +    if (state->imageSurface) {
938 +       cairo_surface_destroy(state->imageSurface);
939 +    }
940 +
941 +    if (state->shading) {
942 +       CGShadingRelease(state->shading);
943 +    }
944 +
945 +    if (state->pattern) {
946 +       CGPatternRelease(state->pattern);
947 +    }
948 +
949 +    CGContextRestoreGState(state->context);
950 +}
951 +
952 +
953 +static void
954 +_cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state, cairo_operator_t op)
955 +{
956 +    assert (state &&
957 +            ((state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)) ||
958 +             (state->layer && state->action == DO_LAYER)));
959 +
960 +    CGContextConcatCTM (state->context, state->transform);
961 +    CGContextTranslateCTM (state->context, 0, state->imageRect.size.height);
962 +    CGContextScaleCTM (state->context, 1, -1);
963 +
964 +    if (state->action == DO_TILED_IMAGE) {
965 +       CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image);
966 +       /* no need to worry about unbounded operators, since tiled images
967 +          fill the entire clip region */
968 +    } else {
969 +        if (state->action == DO_LAYER) {
970 +            /* Note that according to Apple docs it's completely legal
971 +             * to draw a CGLayer to any CGContext, even one it wasn't
972 +             * created for.
973 +             */
974 +            CGContextSetInterpolationQuality (state->context, kCGInterpolationNone);
975 +            CGContextDrawLayerAtPoint (state->context, state->imageRect.origin,
976 +                                       state->layer);
977 +        } else {
978 +            CGContextDrawImage (state->context, state->imageRect, state->image);
979 +        }
980 +
981 +       /* disable this EXTEND_NONE correctness code because we use this path
982 +        * for both EXTEND_NONE and EXTEND_PAD */
983 +       if (0 && !_cairo_operator_bounded_by_source (op)) {
984 +           CGContextBeginPath (state->context);
985 +           CGContextAddRect (state->context, state->imageRect);
986 +           CGContextAddRect (state->context, CGContextGetClipBoundingBox (state->context));
987 +           CGContextSetRGBFillColor (state->context, 0, 0, 0, 0);
988 +           CGContextEOFillPath (state->context);
989         }
990 -    } else
991 -       CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
992 +    }
993  }
994
995
996 @@ -1762,6 +1939,7 @@ _cairo_quartz_get_image (cairo_quartz_su
997      }
998
999      if (surface->imageSurfaceEquiv) {
1000 +       CGContextFlush(surface->cgContext);
1001         *image_out = (cairo_image_surface_t*) cairo_surface_reference(surface->imageSurfaceEquiv);
1002         return CAIRO_STATUS_SUCCESS;
1003      }
1004 @@ -1773,6 +1951,7 @@ _cairo_quartz_get_image (cairo_quartz_su
1005         CGColorSpaceRef colorspace;
1006         unsigned int color_comps;
1007
1008 +       CGContextFlush(surface->cgContext);
1009         imageData = (unsigned char *) CGBitmapContextGetData(surface->cgContext);
1010
1011  #ifdef USE_10_3_WORKAROUNDS
1012 @@ -1860,53 +2039,79 @@ _cairo_quartz_surface_finish (void *abst
1013
1014      surface->cgContext = NULL;
1015
1016 +    if (surface->bitmapContextImage) {
1017 +        CGImageRelease (surface->bitmapContextImage);
1018 +        surface->bitmapContextImage = NULL;
1019 +    }
1020 +
1021      if (surface->imageSurfaceEquiv) {
1022 +        if (surface->ownsData)
1023 +            _cairo_image_surface_assume_ownership_of_data (surface->imageSurfaceEquiv);
1024         cairo_surface_destroy (surface->imageSurfaceEquiv);
1025         surface->imageSurfaceEquiv = NULL;
1026 +    } else if (surface->imageData && surface->ownsData) {
1027 +        free (surface->imageData);
1028      }
1029
1030 -    if (surface->imageData) {
1031 -       free (surface->imageData);
1032 -       surface->imageData = NULL;
1033 +    surface->imageData = NULL;
1034 +
1035 +    if (surface->cgLayer) {
1036 +        CGLayerRelease (surface->cgLayer);
1037      }
1038
1039      return CAIRO_STATUS_SUCCESS;
1040  }
1041
1042  static cairo_status_t
1043 -_cairo_quartz_surface_acquire_source_image (void *abstract_surface,
1044 -                                            cairo_image_surface_t **image_out,
1045 -                                            void **image_extra)
1046 +_cairo_quartz_surface_acquire_image (void *abstract_surface,
1047 +                                     cairo_image_surface_t **image_out,
1048 +                                     void **image_extra)
1049  {
1050      cairo_int_status_t status;
1051      cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1052
1053 -    //ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface));
1054 -
1055 -    status = _cairo_quartz_get_image (surface, image_out);
1056 -    if (status)
1057 -       return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1058 -
1059      *image_extra = NULL;
1060
1061 -    return CAIRO_STATUS_SUCCESS;
1062 -}
1063 +    /* ND((stderr, "%p _cairo_quartz_surface_acquire_image\n", surface)); */
1064
1065 -static cairo_surface_t *
1066 -_cairo_quartz_surface_snapshot (void *abstract_surface)
1067 -{
1068 -    cairo_int_status_t status;
1069 -    cairo_quartz_surface_t *surface = abstract_surface;
1070 -    cairo_image_surface_t *image;
1071 +    status = _cairo_quartz_get_image (surface, image_out);
1072
1073 -    if (surface->imageSurfaceEquiv)
1074 -       return NULL;
1075 +    if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->cgLayer) {
1076 +        /* copy the layer into a Quartz bitmap context so we can get the data */
1077 +        cairo_surface_t *tmp =
1078 +            cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32,
1079 +                                         surface->extents.width,
1080 +                                         surface->extents.height);
1081 +        cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) tmp;
1082 +
1083 +        /* if surface creation failed, we won't have a Quartz surface here */
1084 +        if (cairo_surface_get_type (tmp) == CAIRO_SURFACE_TYPE_QUARTZ &&
1085 +            tmp_surface->imageSurfaceEquiv) {
1086 +            CGContextSaveGState (tmp_surface->cgContext);
1087 +            CGContextTranslateCTM (tmp_surface->cgContext, 0, surface->extents.height);
1088 +            CGContextScaleCTM (tmp_surface->cgContext, 1, -1);
1089 +            /* Note that according to Apple docs it's completely legal
1090 +             * to draw a CGLayer to any CGContext, even one it wasn't
1091 +             * created for.
1092 +             */
1093 +            CGContextDrawLayerAtPoint (tmp_surface->cgContext,
1094 +                                       CGPointMake (0.0, 0.0),
1095 +                                       surface->cgLayer);
1096 +            CGContextRestoreGState (tmp_surface->cgContext);
1097 +
1098 +            *image_out = (cairo_image_surface_t*)
1099 +                cairo_surface_reference(tmp_surface->imageSurfaceEquiv);
1100 +            *image_extra = tmp;
1101 +            status = CAIRO_STATUS_SUCCESS;
1102 +        } else {
1103 +            cairo_surface_destroy (tmp);
1104 +        }
1105 +    }
1106
1107 -    status = _cairo_quartz_get_image (surface, &image);
1108 -    if (unlikely (status))
1109 -        return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
1110 +    if (status)
1111 +       return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1112
1113 -    return &image->base;
1114 +    return CAIRO_STATUS_SUCCESS;
1115  }
1116
1117  static void
1118 @@ -1915,6 +2120,10 @@ _cairo_quartz_surface_release_source_ima
1119                                              void *image_extra)
1120  {
1121      cairo_surface_destroy ((cairo_surface_t *) image);
1122 +
1123 +    if (image_extra) {
1124 +        cairo_surface_destroy ((cairo_surface_t *) image_extra);
1125 +    }
1126  }
1127
1128
1129 @@ -1926,18 +2135,16 @@ _cairo_quartz_surface_acquire_dest_image
1130                                           void **image_extra)
1131  {
1132      cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1133 -    cairo_int_status_t status;
1134
1135      ND((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface));
1136
1137 -    status = _cairo_quartz_get_image (surface, image_out);
1138 -    if (status)
1139 -       return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1140 -
1141      *image_rect = surface->extents;
1142      *image_extra = NULL;
1143
1144 -    return CAIRO_STATUS_SUCCESS;
1145 +    _cairo_quartz_surface_will_change (surface);
1146 +
1147 +    return _cairo_quartz_surface_acquire_image (abstract_surface,
1148 +        image_out, image_extra);
1149  }
1150
1151  static void
1152 @@ -1947,11 +2154,31 @@ _cairo_quartz_surface_release_dest_image
1153                                           cairo_rectangle_int_t *image_rect,
1154                                           void *image_extra)
1155  {
1156 -    //cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1157 -
1158 -    //ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface));
1159 +    /* ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface)); */
1160
1161      cairo_surface_destroy ((cairo_surface_t *) image);
1162 +
1163 +    if (image_extra) {
1164 +        /* we need to write the data from the temp surface back to the layer */
1165 +        cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1166 +        cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) image_extra;
1167 +        CGImageRef img;
1168 +        cairo_status_t status = _cairo_surface_to_cgimage (&tmp_surface->base, &img);
1169 +        if (status) {
1170 +            cairo_surface_destroy (&tmp_surface->base);
1171 +            return;
1172 +        }
1173 +
1174 +        CGContextSaveGState (surface->cgContext);
1175 +        CGContextTranslateCTM (surface->cgContext, 0, surface->extents.height);
1176 +        CGContextScaleCTM (surface->cgContext, 1, -1);
1177 +        CGContextDrawImage (surface->cgContext,
1178 +                            CGRectMake (0.0, 0.0, surface->extents.width, surface->extents.height),
1179 +                            img);
1180 +        CGContextRestoreGState (surface->cgContext);
1181 +
1182 +        cairo_surface_destroy (&tmp_surface->base);
1183 +    }
1184  }
1185
1186  static cairo_surface_t *
1187 @@ -1960,10 +2187,13 @@ _cairo_quartz_surface_create_similar (vo
1188                                        int width,
1189                                        int height)
1190  {
1191 -    /*cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;*/
1192 -
1193 +    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1194      cairo_format_t format;
1195
1196 +    if (surface->cgLayer)
1197 +        return cairo_quartz_surface_create_cg_layer (abstract_surface, content,
1198 +                                                     width, height);
1199 +
1200      if (content == CAIRO_CONTENT_COLOR_ALPHA)
1201         format = CAIRO_FORMAT_ARGB32;
1202      else if (content == CAIRO_CONTENT_COLOR)
1203 @@ -2027,7 +2257,7 @@ _cairo_quartz_surface_clone_similar (voi
1204         }
1205      }
1206
1207 -    status = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src, &quartz_image);
1208 +    status = _cairo_surface_to_cgimage (src, &quartz_image);
1209      if (status)
1210         return CAIRO_INT_STATUS_UNSUPPORTED;
1211
1212 @@ -2087,7 +2317,7 @@ _cairo_quartz_surface_paint_cg (void *ab
1213  {
1214      cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1215      cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
1216 -    cairo_quartz_action_t action;
1217 +    cairo_quartz_drawing_state_t state;
1218
1219      ND((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
1220
1221 @@ -2098,31 +2328,24 @@ _cairo_quartz_surface_paint_cg (void *ab
1222      if (unlikely (rv))
1223         return rv;
1224
1225 -    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
1226 -    if (unlikely (rv))
1227 -       return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
1228 +    state = _cairo_quartz_setup_state (surface, source, op, NULL);
1229
1230 -    action = _cairo_quartz_setup_source (surface, source, NULL);
1231 -
1232 -    if (action == DO_SOLID || action == DO_PATTERN) {
1233 -       CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
1234 -                                                         surface->extents.y,
1235 -                                                         surface->extents.width,
1236 -                                                         surface->extents.height));
1237 -    } else if (action == DO_SHADING) {
1238 -       CGContextSaveGState (surface->cgContext);
1239 -       CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
1240 -       CGContextDrawShading (surface->cgContext, surface->sourceShading);
1241 -       CGContextRestoreGState (surface->cgContext);
1242 -    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
1243 -       CGContextSaveGState (surface->cgContext);
1244 -       _cairo_quartz_draw_image (surface, op, action);
1245 -       CGContextRestoreGState (surface->cgContext);
1246 -    } else if (action != DO_NOTHING) {
1247 +    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
1248 +       CGContextFillRect (state.context, CGRectMake(surface->extents.x,
1249 +                                                    surface->extents.y,
1250 +                                                    surface->extents.width,
1251 +                                                    surface->extents.height));
1252 +    } else if (state.action == DO_SHADING) {
1253 +       CGContextConcatCTM (state.context, state.transform);
1254 +       CGContextDrawShading (state.context, state.shading);
1255 +    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
1256 +               state.action == DO_LAYER) {
1257 +       _cairo_quartz_draw_image (&state, op);
1258 +    } else if (state.action != DO_NOTHING) {
1259         rv = CAIRO_INT_STATUS_UNSUPPORTED;
1260      }
1261
1262 -    _cairo_quartz_teardown_source (surface, source);
1263 +    _cairo_quartz_teardown_state (&state);
1264
1265      ND((stderr, "-- paint\n"));
1266      return rv;
1267 @@ -2186,7 +2409,7 @@ _cairo_quartz_surface_fill_cg (void *abs
1268  {
1269      cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1270      cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
1271 -    cairo_quartz_action_t action;
1272 +    cairo_quartz_drawing_state_t state;
1273      CGPathRef path_for_unbounded = NULL;
1274
1275      ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
1276 @@ -2198,14 +2421,6 @@ _cairo_quartz_surface_fill_cg (void *abs
1277      if (unlikely (rv))
1278         return rv;
1279
1280 -    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
1281 -    if (unlikely (rv))
1282 -       return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
1283 -
1284 -    CGContextSaveGState (surface->cgContext);
1285 -
1286 -    CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
1287 -
1288      if (_cairo_quartz_source_needs_extents (source))
1289      {
1290          /* We don't need precise extents since these are only used to
1291 @@ -2213,46 +2428,47 @@ _cairo_quartz_surface_fill_cg (void *abs
1292             object. */
1293          cairo_rectangle_int_t path_extents;
1294          _cairo_path_fixed_approximate_fill_extents (path, &path_extents);
1295 -        action = _cairo_quartz_setup_source (surface, source, &path_extents);
1296 +        state = _cairo_quartz_setup_state (surface, source, op, &path_extents);
1297      } else {
1298 -        action = _cairo_quartz_setup_source (surface, source, NULL);
1299 +        state = _cairo_quartz_setup_state (surface, source, op, NULL);
1300      }
1301
1302 -    _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext);
1303 +    CGContextSetShouldAntialias (state.context, (antialias != CAIRO_ANTIALIAS_NONE));
1304 +
1305 +    _cairo_quartz_cairo_path_to_quartz_context (path, state.context);
1306
1307      if (!_cairo_operator_bounded_by_mask(op) && CGContextCopyPathPtr)
1308 -       path_for_unbounded = CGContextCopyPathPtr (surface->cgContext);
1309 +       path_for_unbounded = CGContextCopyPathPtr (state.context);
1310
1311 -    if (action == DO_SOLID || action == DO_PATTERN) {
1312 +    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
1313         if (fill_rule == CAIRO_FILL_RULE_WINDING)
1314 -           CGContextFillPath (surface->cgContext);
1315 +           CGContextFillPath (state.context);
1316         else
1317 -           CGContextEOFillPath (surface->cgContext);
1318 -    } else if (action == DO_SHADING) {
1319 +           CGContextEOFillPath (state.context);
1320 +    } else if (state.action == DO_SHADING) {
1321
1322         // we have to clip and then paint the shading; we can't fill
1323         // with the shading
1324         if (fill_rule == CAIRO_FILL_RULE_WINDING)
1325 -           CGContextClip (surface->cgContext);
1326 +           CGContextClip (state.context);
1327         else
1328 -           CGContextEOClip (surface->cgContext);
1329 +            CGContextEOClip (state.context);
1330
1331 -       CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
1332 -       CGContextDrawShading (surface->cgContext, surface->sourceShading);
1333 -    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
1334 +       CGContextConcatCTM (state.context, state.transform);
1335 +       CGContextDrawShading (state.context, state.shading);
1336 +    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
1337 +               state.action == DO_LAYER) {
1338         if (fill_rule == CAIRO_FILL_RULE_WINDING)
1339 -           CGContextClip (surface->cgContext);
1340 +           CGContextClip (state.context);
1341         else
1342 -           CGContextEOClip (surface->cgContext);
1343 +           CGContextEOClip (state.context);
1344
1345 -       _cairo_quartz_draw_image (surface, op, action);
1346 -    } else if (action != DO_NOTHING) {
1347 +       _cairo_quartz_draw_image (&state, op);
1348 +    } else if (state.action != DO_NOTHING) {
1349         rv = CAIRO_INT_STATUS_UNSUPPORTED;
1350      }
1351
1352 -    _cairo_quartz_teardown_source (surface, source);
1353 -
1354 -    CGContextRestoreGState (surface->cgContext);
1355 +    _cairo_quartz_teardown_state (&state);
1356
1357      if (path_for_unbounded) {
1358         unbounded_op_data_t ub;
1359 @@ -2319,7 +2535,7 @@ _cairo_quartz_surface_stroke_cg (void *a
1360  {
1361      cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1362      cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
1363 -    cairo_quartz_action_t action;
1364 +    cairo_quartz_drawing_state_t state;
1365      CGAffineTransform origCTM, strokeTransform;
1366      CGPathRef path_for_unbounded = NULL;
1367
1368 @@ -2336,16 +2552,25 @@ _cairo_quartz_surface_stroke_cg (void *a
1369      if (unlikely (rv))
1370         return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
1371
1372 +    if (_cairo_quartz_source_needs_extents (source))
1373 +    {
1374 +       cairo_rectangle_int_t path_extents;
1375 +       _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents);
1376 +       state = _cairo_quartz_setup_state (surface, source, op, &path_extents);
1377 +    } else {
1378 +       state = _cairo_quartz_setup_state (surface, source, op, NULL);
1379 +    }
1380 +
1381      // Turning antialiasing off used to cause misrendering with
1382      // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels).
1383      // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases.
1384 -    CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
1385 -    CGContextSetLineWidth (surface->cgContext, style->line_width);
1386 -    CGContextSetLineCap (surface->cgContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
1387 -    CGContextSetLineJoin (surface->cgContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
1388 -    CGContextSetMiterLimit (surface->cgContext, style->miter_limit);
1389 +    CGContextSetShouldAntialias (state.context, (antialias != CAIRO_ANTIALIAS_NONE));
1390 +    CGContextSetLineWidth (state.context, style->line_width);
1391 +    CGContextSetLineCap (state.context, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
1392 +    CGContextSetLineJoin (state.context, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
1393 +    CGContextSetMiterLimit (state.context, style->miter_limit);
1394
1395 -    origCTM = CGContextGetCTM (surface->cgContext);
1396 +    origCTM = CGContextGetCTM (state.context);
1397
1398      if (style->dash && style->num_dashes) {
1399  #define STATIC_DASH 32
1400 @@ -2368,72 +2593,62 @@ _cairo_quartz_surface_stroke_cg (void *a
1401         if (fdash != sdash)
1402             free (fdash);
1403      } else
1404 -       CGContextSetLineDash (surface->cgContext, 0, NULL, 0);
1405 +       CGContextSetLineDash (state.context, 0, NULL, 0);
1406
1407 -    CGContextSaveGState (surface->cgContext);
1408
1409 +    _cairo_quartz_cairo_path_to_quartz_context (path, state.context);
1410
1411 -    if (_cairo_quartz_source_needs_extents (source))
1412 -    {
1413 -        cairo_rectangle_int_t path_extents;
1414 -        _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents);
1415 -        action = _cairo_quartz_setup_source (surface, source, &path_extents);
1416 -    } else {
1417 -        action = _cairo_quartz_setup_source (surface, source, NULL);
1418 -    }
1419 -
1420 -    _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext);
1421 +    _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform);
1422 +    CGContextConcatCTM (state.context, strokeTransform);
1423
1424      if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr)
1425 -       path_for_unbounded = CGContextCopyPathPtr (surface->cgContext);
1426 -
1427 -    _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform);
1428 -    CGContextConcatCTM (surface->cgContext, strokeTransform);
1429 +       path_for_unbounded = CGContextCopyPathPtr (state.context);
1430
1431 -    if (action == DO_SOLID || action == DO_PATTERN) {
1432 -       CGContextStrokePath (surface->cgContext);
1433 -    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
1434 -       CGContextReplacePathWithStrokedPath (surface->cgContext);
1435 -       CGContextClip (surface->cgContext);
1436 -
1437 -       CGContextSetCTM (surface->cgContext, origCTM);
1438 -       _cairo_quartz_draw_image (surface, op, action);
1439 -    } else if (action == DO_SHADING) {
1440 -       CGContextReplacePathWithStrokedPath (surface->cgContext);
1441 -       CGContextClip (surface->cgContext);
1442 -
1443 -       CGContextSetCTM (surface->cgContext, origCTM);
1444 -
1445 -       CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
1446 -       CGContextDrawShading (surface->cgContext, surface->sourceShading);
1447 -    } else if (action != DO_NOTHING) {
1448 +    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
1449 +       CGContextStrokePath (state.context);
1450 +    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
1451 +               state.action == DO_LAYER) {
1452 +       CGContextReplacePathWithStrokedPath (state.context);
1453 +       CGContextClip (state.context);
1454 +
1455 +       CGContextSetCTM (state.context, origCTM);
1456 +       _cairo_quartz_draw_image (&state, op);
1457 +    } else if (state.action == DO_SHADING) {
1458 +       CGContextReplacePathWithStrokedPath (state.context);
1459 +       CGContextClip (state.context);
1460 +
1461 +       CGContextSetCTM (state.context, origCTM);
1462 +
1463 +       CGContextConcatCTM (state.context, state.transform);
1464 +       CGContextDrawShading (state.context, state.shading);
1465 +    } else if (state.action != DO_NOTHING) {
1466         rv = CAIRO_INT_STATUS_UNSUPPORTED;
1467 +       goto BAIL;
1468      }
1469
1470 -    _cairo_quartz_teardown_source (surface, source);
1471 -
1472 -    CGContextRestoreGState (surface->cgContext);
1473 -
1474      if (path_for_unbounded) {
1475         unbounded_op_data_t ub;
1476         ub.op = UNBOUNDED_STROKE_FILL;
1477         ub.u.stroke_fill.fill_rule = CAIRO_FILL_RULE_WINDING;
1478
1479 -       CGContextBeginPath (surface->cgContext);
1480 -       CGContextAddPath (surface->cgContext, path_for_unbounded);
1481 +       CGContextBeginPath (state.context);
1482 +       CGContextAddPath (state.context, path_for_unbounded);
1483         CGPathRelease (path_for_unbounded);
1484
1485 -       CGContextSaveGState (surface->cgContext);
1486 -       CGContextConcatCTM (surface->cgContext, strokeTransform);
1487 -       CGContextReplacePathWithStrokedPath (surface->cgContext);
1488 -       CGContextRestoreGState (surface->cgContext);
1489 +       CGContextSaveGState (state.context);
1490 +       CGContextConcatCTM (state.context, strokeTransform);
1491 +       CGContextReplacePathWithStrokedPath (state.context);
1492 +       CGContextRestoreGState (state.context);
1493
1494 -       ub.u.stroke_fill.cgPath = CGContextCopyPathPtr (surface->cgContext);
1495 +       ub.u.stroke_fill.cgPath = CGContextCopyPathPtr (state.context);
1496
1497         _cairo_quartz_fixup_unbounded_operation (surface, &ub, antialias);
1498         CGPathRelease (ub.u.stroke_fill.cgPath);
1499      }
1500
1501 +  BAIL:
1502 +    _cairo_quartz_teardown_state (&state);
1503 +
1504      ND((stderr, "-- stroke\n"));
1505      return rv;
1506  }
1507 @@ -2490,18 +2705,22 @@ _cairo_quartz_surface_show_glyphs_cg (vo
1508      CGGlyph glyphs_static[STATIC_BUF_SIZE];
1509      CGSize cg_advances_static[STATIC_BUF_SIZE];
1510      CGGlyph *cg_glyphs = &glyphs_static[0];
1511 +    /* We'll use the cg_advances array for either advances or positions,
1512 +       depending which API we're using to actually draw. The types involved
1513 +       have the same size, so this is safe. */
1514      CGSize *cg_advances = &cg_advances_static[0];
1515
1516      cairo_rectangle_int_t glyph_extents;
1517      cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1518      cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
1519 -    cairo_quartz_action_t action;
1520 +    cairo_quartz_drawing_state_t state;
1521      cairo_quartz_float_t xprev, yprev;
1522      int i;
1523      CGFontRef cgfref = NULL;
1524
1525      cairo_bool_t isClipping = FALSE;
1526      cairo_bool_t didForceFontSmoothing = FALSE;
1527 +    cairo_antialias_t effective_antialiasing;
1528
1529      if (IS_EMPTY(surface))
1530         return CAIRO_STATUS_SUCCESS;
1531 @@ -2516,54 +2735,51 @@ _cairo_quartz_surface_show_glyphs_cg (vo
1532      if (unlikely (rv))
1533         return rv;
1534
1535 -    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
1536 -    if (unlikely (rv))
1537 -       return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
1538 -
1539 -    CGContextSaveGState (surface->cgContext);
1540 -
1541      if (_cairo_quartz_source_needs_extents (source) &&
1542         !_cairo_scaled_font_glyph_device_extents (scaled_font, glyphs, num_glyphs,
1543                                                   &glyph_extents, NULL))
1544      {
1545 -        action = _cairo_quartz_setup_source (surface, source, &glyph_extents);
1546 +        state = _cairo_quartz_setup_state (surface, source, op, &glyph_extents);
1547      } else {
1548 -        action = _cairo_quartz_setup_source (surface, source, NULL);
1549 +        state = _cairo_quartz_setup_state (surface, source, op, NULL);
1550      }
1551
1552 -    if (action == DO_SOLID || action == DO_PATTERN) {
1553 -       CGContextSetTextDrawingMode (surface->cgContext, kCGTextFill);
1554 -    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE || action == DO_SHADING) {
1555 -       CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip);
1556 +    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
1557 +       CGContextSetTextDrawingMode (state.context, kCGTextFill);
1558 +    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
1559 +               state.action == DO_SHADING || state.action == DO_LAYER) {
1560 +       CGContextSetTextDrawingMode (state.context, kCGTextClip);
1561         isClipping = TRUE;
1562      } else {
1563 -       if (action != DO_NOTHING)
1564 +       if (state.action != DO_NOTHING)
1565             rv = CAIRO_INT_STATUS_UNSUPPORTED;
1566         goto BAIL;
1567      }
1568
1569      /* this doesn't addref */
1570      cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font);
1571 -    CGContextSetFont (surface->cgContext, cgfref);
1572 -    CGContextSetFontSize (surface->cgContext, 1.0);
1573 +    CGContextSetFont (state.context, cgfref);
1574 +    CGContextSetFontSize (state.context, 1.0);
1575 +
1576 +    effective_antialiasing = scaled_font->options.antialias;
1577
1578      switch (scaled_font->options.antialias) {
1579         case CAIRO_ANTIALIAS_SUBPIXEL:
1580 -           CGContextSetShouldAntialias (surface->cgContext, TRUE);
1581 -           CGContextSetShouldSmoothFonts (surface->cgContext, TRUE);
1582 +           CGContextSetShouldAntialias (state.context, TRUE);
1583 +           CGContextSetShouldSmoothFonts (state.context, TRUE);
1584             if (CGContextSetAllowsFontSmoothingPtr &&
1585 -               !CGContextGetAllowsFontSmoothingPtr (surface->cgContext))
1586 +               !CGContextGetAllowsFontSmoothingPtr (state.context))
1587             {
1588                 didForceFontSmoothing = TRUE;
1589 -               CGContextSetAllowsFontSmoothingPtr (surface->cgContext, TRUE);
1590 +               CGContextSetAllowsFontSmoothingPtr (state.context, TRUE);
1591             }
1592             break;
1593         case CAIRO_ANTIALIAS_NONE:
1594 -           CGContextSetShouldAntialias (surface->cgContext, FALSE);
1595 +           CGContextSetShouldAntialias (state.context, FALSE);
1596             break;
1597         case CAIRO_ANTIALIAS_GRAY:
1598 -           CGContextSetShouldAntialias (surface->cgContext, TRUE);
1599 -           CGContextSetShouldSmoothFonts (surface->cgContext, FALSE);
1600 +           CGContextSetShouldAntialias (state.context, TRUE);
1601 +           CGContextSetShouldSmoothFonts (state.context, FALSE);
1602             break;
1603         case CAIRO_ANTIALIAS_DEFAULT:
1604             /* Don't do anything */
1605 @@ -2584,57 +2800,84 @@ _cairo_quartz_surface_show_glyphs_cg (vo
1606         }
1607      }
1608
1609 +    /* scale(1,-1) * scaled_font->scale */
1610      textTransform = CGAffineTransformMake (scaled_font->scale.xx,
1611                                            scaled_font->scale.yx,
1612                                            -scaled_font->scale.xy,
1613                                            -scaled_font->scale.yy,
1614                                            0, 0);
1615 -    _cairo_quartz_cairo_matrix_to_quartz (&scaled_font->scale_inverse, &invTextTransform);
1616
1617 -    CGContextSetTextMatrix (surface->cgContext, CGAffineTransformIdentity);
1618 +    /* scaled_font->scale_inverse * scale(1,-1) */
1619 +    invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx,
1620 +                                             -scaled_font->scale_inverse.yx,
1621 +                                             scaled_font->scale_inverse.xy,
1622 +                                             -scaled_font->scale_inverse.yy,
1623 +                                             0.0, 0.0);
1624
1625 -    /* Convert our glyph positions to glyph advances.  We need n-1 advances,
1626 -     * since the advance at index 0 is applied after glyph 0. */
1627 -    xprev = glyphs[0].x;
1628 -    yprev = glyphs[0].y;
1629 -
1630 -    cg_glyphs[0] = glyphs[0].index;
1631 -
1632 -    for (i = 1; i < num_glyphs; i++) {
1633 -       cairo_quartz_float_t xf = glyphs[i].x;
1634 -       cairo_quartz_float_t yf = glyphs[i].y;
1635 -       cg_glyphs[i] = glyphs[i].index;
1636 -       cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
1637 -       xprev = xf;
1638 -       yprev = yf;
1639 -    }
1640 +    CGContextSetTextMatrix (state.context, CGAffineTransformIdentity);
1641
1642      /* Translate to the first glyph's position before drawing */
1643 -    ctm = CGContextGetCTM (surface->cgContext);
1644 -    CGContextTranslateCTM (surface->cgContext, glyphs[0].x, glyphs[0].y);
1645 -    CGContextConcatCTM (surface->cgContext, textTransform);
1646 -
1647 -    CGContextShowGlyphsWithAdvances (surface->cgContext,
1648 -                                    cg_glyphs,
1649 -                                    cg_advances,
1650 -                                    num_glyphs);
1651 -
1652 -    CGContextSetCTM (surface->cgContext, ctm);
1653 +    ctm = CGContextGetCTM (state.context);
1654 +    CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y);
1655 +    CGContextConcatCTM (state.context, textTransform);
1656 +
1657 +    if (CTFontDrawGlyphsPtr) {
1658 +        /* If CTFontDrawGlyphs is available (i.e. OS X 10.7 or later), we want to use
1659 +         * that in preference to CGContextShowGlyphsWithAdvances so that colored-bitmap
1660 +         * fonts like Apple Color Emoji will render properly.
1661 +         * For this, we need to convert our glyph positions to Core Graphics's CGPoint.
1662 +         * We borrow the cg_advances array, as CGPoint and CGSize are the same size. */
1663 +
1664 +        CGPoint *cg_positions = (CGPoint*) cg_advances;
1665 +        cairo_quartz_float_t origin_x = glyphs[0].x;
1666 +        cairo_quartz_float_t origin_y = glyphs[0].y;
1667 +
1668 +        for (i = 0; i < num_glyphs; i++) {
1669 +            CGPoint pt = CGPointMake (glyphs[i].x - origin_x, glyphs[i].y - origin_y);
1670 +            cg_positions[i] = CGPointApplyAffineTransform (pt, invTextTransform);
1671 +            cg_glyphs[i] = glyphs[i].index;
1672 +        }
1673
1674 -    if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
1675 -       _cairo_quartz_draw_image (surface, op, action);
1676 -    } else if (action == DO_SHADING) {
1677 -       CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
1678 -       CGContextDrawShading (surface->cgContext, surface->sourceShading);
1679 +        CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (scaled_font),
1680 +                             cg_glyphs, cg_positions, num_glyphs, state.context);
1681 +    } else {
1682 +        /* Convert our glyph positions to glyph advances.  We need n-1 advances,
1683 +         * since the advance at index 0 is applied after glyph 0. */
1684 +        xprev = glyphs[0].x;
1685 +        yprev = glyphs[0].y;
1686 +
1687 +        cg_glyphs[0] = glyphs[0].index;
1688 +
1689 +        for (i = 1; i < num_glyphs; i++) {
1690 +           cairo_quartz_float_t xf = glyphs[i].x;
1691 +           cairo_quartz_float_t yf = glyphs[i].y;
1692 +           cg_glyphs[i] = glyphs[i].index;
1693 +           cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
1694 +           xprev = xf;
1695 +           yprev = yf;
1696 +        }
1697 +
1698 +        CGContextShowGlyphsWithAdvances (state.context,
1699 +                                        cg_glyphs,
1700 +                                        cg_advances,
1701 +                                        num_glyphs);
1702 +    }
1703 +
1704 +    CGContextSetCTM (state.context, ctm);
1705 +
1706 +    if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
1707 +        state.action == DO_LAYER) {
1708 +       _cairo_quartz_draw_image (&state, op);
1709 +    } else if (state.action == DO_SHADING) {
1710 +       CGContextConcatCTM (state.context, state.transform);
1711 +       CGContextDrawShading (state.context, state.shading);
1712      }
1713
1714  BAIL:
1715 -    _cairo_quartz_teardown_source (surface, source);
1716 -
1717      if (didForceFontSmoothing)
1718 -       CGContextSetAllowsFontSmoothingPtr (surface->cgContext, FALSE);
1719 +        CGContextSetAllowsFontSmoothingPtr (state.context, FALSE);
1720
1721 -    CGContextRestoreGState (surface->cgContext);
1722 +    _cairo_quartz_teardown_state (&state);
1723
1724      if (rv == CAIRO_STATUS_SUCCESS &&
1725         cgfref &&
1726 @@ -2645,10 +2888,17 @@ BAIL:
1727
1728         ub.u.show_glyphs.isClipping = isClipping;
1729         ub.u.show_glyphs.cg_glyphs = cg_glyphs;
1730 -       ub.u.show_glyphs.cg_advances = cg_advances;
1731 +       if (CTFontDrawGlyphsPtr) {
1732 +           /* we're using Core Text API: the cg_advances array was
1733 +              reused (above) for glyph positions */
1734 +            CGPoint *cg_positions = (CGPoint*) cg_advances;
1735 +           ub.u.show_glyphs.u.cg_positions = cg_positions;
1736 +       } else {
1737 +           ub.u.show_glyphs.u.cg_advances = cg_advances;
1738 +       }
1739         ub.u.show_glyphs.nglyphs = num_glyphs;
1740         ub.u.show_glyphs.textTransform = textTransform;
1741 -       ub.u.show_glyphs.font = cgfref;
1742 +       ub.u.show_glyphs.scaled_font = scaled_font;
1743         ub.u.show_glyphs.origin = CGPointMake (glyphs[0].x, glyphs[0].y);
1744
1745         _cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias);
1746 @@ -2717,7 +2967,7 @@ _cairo_quartz_surface_mask_with_surface
1747      cairo_status_t status = CAIRO_STATUS_SUCCESS;
1748      CGAffineTransform ctm, mask_matrix;
1749
1750 -    status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
1751 +    status = _cairo_surface_to_cgimage (pat_surf, &img);
1752      if (status)
1753         return status;
1754      if (img == NULL) {
1755 @@ -2820,7 +3070,9 @@ _cairo_quartz_surface_mask_cg (void *abs
1756      if (unlikely (rv))
1757         return rv;
1758
1759 -    if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
1760 +    /* Using CGContextSetAlpha to implement mask alpha doesn't work for all operators. */
1761 +    if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
1762 +        op == CAIRO_OPERATOR_OVER) {
1763         /* This is easy; we just need to paint with the alpha. */
1764         cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
1765
1766 @@ -2834,8 +3086,11 @@ _cairo_quartz_surface_mask_cg (void *abs
1767      /* If we have CGContextClipToMask, we can do more complex masks */
1768      if (CGContextClipToMaskPtr) {
1769         /* For these, we can skip creating a temporary surface, since we already have one */
1770 -       if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && mask->extend == CAIRO_EXTEND_NONE)
1771 +       /* For some reason this doesn't work reliably on OS X 10.5.  See bug 721663. */
1772 +       if (_cairo_quartz_osx_version >= 0x1060 && mask->type == CAIRO_PATTERN_TYPE_SURFACE &&
1773 +           mask->extend == CAIRO_EXTEND_NONE) {
1774             return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask, clip);
1775 +       }
1776
1777         return _cairo_quartz_surface_mask_with_generic (surface, op, source, mask, clip);
1778      }
1779 @@ -2920,13 +3175,24 @@ _cairo_quartz_surface_clipper_intersect_
1780      return CAIRO_STATUS_SUCCESS;
1781  }
1782
1783 +static cairo_status_t
1784 +_cairo_quartz_surface_mark_dirty_rectangle (void *abstract_surface,
1785 +                                           int x, int y,
1786 +                                           int width, int height)
1787 +{
1788 +    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1789 +    _cairo_quartz_surface_will_change (surface);
1790 +    return CAIRO_STATUS_SUCCESS;
1791 +}
1792 +
1793 +
1794  // XXXtodo implement show_page; need to figure out how to handle begin/end
1795
1796  static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
1797      CAIRO_SURFACE_TYPE_QUARTZ,
1798      _cairo_quartz_surface_create_similar,
1799      _cairo_quartz_surface_finish,
1800 -    _cairo_quartz_surface_acquire_source_image,
1801 +    _cairo_quartz_surface_acquire_image,
1802      _cairo_quartz_surface_release_source_image,
1803      _cairo_quartz_surface_acquire_dest_image,
1804      _cairo_quartz_surface_release_dest_image,
1805 @@ -2942,7 +3208,7 @@ static const struct _cairo_surface_backe
1806      NULL, /* old_show_glyphs */
1807      NULL, /* get_font_options */
1808      NULL, /* flush */
1809 -    NULL, /* mark_dirty_rectangle */
1810 +    _cairo_quartz_surface_mark_dirty_rectangle,
1811      NULL, /* scaled_font_fini */
1812      NULL, /* scaled_glyph_fini */
1813
1814 @@ -2952,7 +3218,7 @@ static const struct _cairo_surface_backe
1815      _cairo_quartz_surface_fill,
1816      _cairo_quartz_surface_show_glyphs,
1817
1818 -    _cairo_quartz_surface_snapshot,
1819 +    NULL, /* snapshot */
1820      NULL, /* is_similar */
1821      NULL  /* fill_stroke */
1822  };
1823 @@ -3004,6 +3270,9 @@ _cairo_quartz_surface_create_internal (C
1824
1825      surface->imageData = NULL;
1826      surface->imageSurfaceEquiv = NULL;
1827 +    surface->bitmapContextImage = NULL;
1828 +    surface->cgLayer = NULL;
1829 +    surface->ownsData = TRUE;
1830
1831      return surface;
1832  }
1833 @@ -3056,6 +3325,81 @@ cairo_quartz_surface_create_for_cg_conte
1834  }
1835
1836  /**
1837 + * cairo_quartz_cglayer_surface_create_similar
1838 + * @surface: The returned surface can be efficiently drawn into this
1839 + * destination surface (if tiling is not used)."
1840 + * @content: the content type of the surface
1841 + * @width: width of the surface, in pixels
1842 + * @height: height of the surface, in pixels
1843 + *
1844 + * Creates a Quartz surface backed by a CGLayer, if the given surface
1845 + * is a Quartz surface; the CGLayer is created to match the surface's
1846 + * Quartz context. Otherwise just calls cairo_surface_create_similar.
1847 + * The returned surface can be efficiently blitted to the given surface,
1848 + * but tiling and 'extend' modes other than NONE are not so efficient.
1849 + *
1850 + * Return value: the newly created surface.
1851 + *
1852 + * Since: 1.10
1853 + **/
1854 +cairo_surface_t *
1855 +cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface,
1856 +                                      cairo_content_t content,
1857 +                                      unsigned int width,
1858 +                                      unsigned int height)
1859 +{
1860 +    cairo_quartz_surface_t *surf;
1861 +    CGLayerRef layer;
1862 +    CGContextRef ctx;
1863 +    CGContextRef cgContext;
1864 +
1865 +    cgContext = cairo_quartz_surface_get_cg_context (surface);
1866 +    if (!cgContext)
1867 +       return cairo_surface_create_similar (surface, content,
1868 +                                             width, height);
1869 +
1870 +
1871 +    if (!_cairo_quartz_verify_surface_size(width, height))
1872 +        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1873 +
1874 +    /* If we pass zero width or height into CGLayerCreateWithContext below,
1875 +     * it will fail.
1876 +     */
1877 +    if (width == 0 || height == 0) {
1878 +        return (cairo_surface_t*)
1879 +            _cairo_quartz_surface_create_internal (NULL, content,
1880 +                                                   width, height);
1881 +    }
1882 +
1883 +    layer = CGLayerCreateWithContext (cgContext,
1884 +                                      CGSizeMake (width, height),
1885 +                                      NULL);
1886 +    if (!layer)
1887 +      return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1888 +
1889 +    ctx = CGLayerGetContext (layer);
1890 +    CGContextSetInterpolationQuality (ctx, kCGInterpolationNone);
1891 +    /* Flip it when we draw into it, so that when we finally composite it
1892 +     * to a flipped target, the directions match and Quartz will optimize
1893 +     * the composition properly
1894 +     */
1895 +    CGContextTranslateCTM (ctx, 0, height);
1896 +    CGContextScaleCTM (ctx, 1, -1);
1897 +
1898 +    CGContextRetain (ctx);
1899 +    surf = _cairo_quartz_surface_create_internal (ctx, content,
1900 +                                                  width, height);
1901 +    if (surf->base.status) {
1902 +        CGLayerRelease (layer);
1903 +        // create_internal will have set an error
1904 +        return (cairo_surface_t*) surf;
1905 +    }
1906 +    surf->cgLayer = layer;
1907 +
1908 +    return (cairo_surface_t *) surf;
1909 +}
1910 +
1911 +/**
1912   * cairo_quartz_surface_create
1913   * @format: format of pixels in the surface to create
1914   * @width: width of the surface, in pixels
1915 @@ -3075,13 +3419,93 @@ cairo_quartz_surface_create (cairo_forma
1916                              unsigned int width,
1917                              unsigned int height)
1918  {
1919 +    int stride;
1920 +    unsigned char *data;
1921 +
1922 +    if (!_cairo_quartz_verify_surface_size(width, height))
1923 +       return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1924 +
1925 +    if (width == 0 || height == 0) {
1926 +       return (cairo_surface_t*) _cairo_quartz_surface_create_internal (NULL, _cairo_content_from_format (format),
1927 +                                                                        width, height);
1928 +    }
1929 +
1930 +    if (format == CAIRO_FORMAT_ARGB32 ||
1931 +       format == CAIRO_FORMAT_RGB24)
1932 +    {
1933 +       stride = width * 4;
1934 +    } else if (format == CAIRO_FORMAT_A8) {
1935 +       stride = width;
1936 +    } else if (format == CAIRO_FORMAT_A1) {
1937 +       /* I don't think we can usefully support this, as defined by
1938 +        * cairo_format_t -- these are 1-bit pixels stored in 32-bit
1939 +        * quantities.
1940 +        */
1941 +       return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1942 +    } else {
1943 +       return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1944 +    }
1945 +
1946 +    /* The Apple docs say that for best performance, the stride and the data
1947 +     * pointer should be 16-byte aligned.  malloc already aligns to 16-bytes,
1948 +     * so we don't have to anything special on allocation.
1949 +     */
1950 +    stride = (stride + 15) & ~15;
1951 +
1952 +    data = _cairo_malloc_ab (height, stride);
1953 +    if (!data) {
1954 +       return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1955 +    }
1956 +
1957 +    /* zero the memory to match the image surface behaviour */
1958 +    memset (data, 0, height * stride);
1959 +
1960 +    cairo_quartz_surface_t *surf;
1961 +    surf = (cairo_quartz_surface_t *) cairo_quartz_surface_create_for_data
1962 +                                           (data, format, width, height, stride);
1963 +    if (surf->base.status) {
1964 +        free (data);
1965 +        return (cairo_surface_t *) surf;
1966 +    }
1967 +
1968 +    // We created this data, so we can delete it.
1969 +    surf->ownsData = TRUE;
1970 +
1971 +    return (cairo_surface_t *) surf;
1972 +}
1973 +
1974 +/**
1975 + * cairo_quartz_surface_create_for_data
1976 + * @data: a pointer to a buffer supplied by the application in which
1977 + *     to write contents. This pointer must be suitably aligned for any
1978 + *     kind of variable, (for example, a pointer returned by malloc).
1979 + * @format: format of pixels in the surface to create
1980 + * @width: width of the surface, in pixels
1981 + * @height: height of the surface, in pixels
1982 + *
1983 + * Creates a Quartz surface backed by a CGBitmap.  The surface is
1984 + * created using the Device RGB (or Device Gray, for A8) color space.
1985 + * All Cairo operations, including those that require software
1986 + * rendering, will succeed on this surface.
1987 + *
1988 + * Return value: the newly created surface.
1989 + *
1990 + * Since: 1.12
1991 + **/
1992 +cairo_surface_t *
1993 +cairo_quartz_surface_create_for_data (unsigned char *data,
1994 +                                     cairo_format_t format,
1995 +                                     unsigned int width,
1996 +                                     unsigned int height,
1997 +                                     unsigned int stride)
1998 +{
1999      cairo_quartz_surface_t *surf;
2000      CGContextRef cgc;
2001      CGColorSpaceRef cgColorspace;
2002      CGBitmapInfo bitinfo;
2003 -    void *imageData;
2004 -    int stride;
2005 +    void *imageData = data;
2006      int bitsPerComponent;
2007 +    unsigned int i;
2008
2009      // verify width and height of surface
2010      if (!_cairo_quartz_verify_surface_size(width, height))
2011 @@ -3102,10 +3526,8 @@ cairo_quartz_surface_create (cairo_forma
2012         else
2013             bitinfo |= kCGImageAlphaNoneSkipFirst;
2014         bitsPerComponent = 8;
2015 -       stride = width * 4;
2016      } else if (format == CAIRO_FORMAT_A8) {
2017         cgColorspace = NULL;
2018 -       stride = width;
2019         bitinfo = kCGImageAlphaOnly;
2020         bitsPerComponent = 8;
2021      } else if (format == CAIRO_FORMAT_A1) {
2022 @@ -3118,21 +3540,6 @@ cairo_quartz_surface_create (cairo_forma
2023         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
2024      }
2025
2026 -    /* The Apple docs say that for best performance, the stride and the data
2027 -     * pointer should be 16-byte aligned.  malloc already aligns to 16-bytes,
2028 -     * so we don't have to anything special on allocation.
2029 -     */
2030 -    stride = (stride + 15) & ~15;
2031 -
2032 -    imageData = _cairo_malloc_ab (height, stride);
2033 -    if (!imageData) {
2034 -       CGColorSpaceRelease (cgColorspace);
2035 -       return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2036 -    }
2037 -
2038 -    /* zero the memory to match the image surface behaviour */
2039 -    memset (imageData, 0, height * stride);
2040 -
2041      cgc = CGBitmapContextCreate (imageData,
2042                                  width,
2043                                  height,
2044 @@ -3161,7 +3568,19 @@ cairo_quartz_surface_create (cairo_forma
2045      }
2046
2047      surf->imageData = imageData;
2048 -    surf->imageSurfaceEquiv = cairo_image_surface_create_for_data (imageData, format, width, height, stride);
2049 +
2050 +    cairo_surface_t* tmpImageSurfaceEquiv =
2051 +      cairo_image_surface_create_for_data (imageData, format,
2052 +                                           width, height, stride);
2053 +
2054 +    if (cairo_surface_status (tmpImageSurfaceEquiv)) {
2055 +        // Tried & failed to create an imageSurfaceEquiv!
2056 +        cairo_surface_destroy (tmpImageSurfaceEquiv);
2057 +        surf->imageSurfaceEquiv = NULL;
2058 +    } else {
2059 +        surf->imageSurfaceEquiv = tmpImageSurfaceEquiv;
2060 +        surf->ownsData = FALSE;
2061 +    }
2062
2063      return (cairo_surface_t *) surf;
2064  }
2065 @@ -3193,6 +3612,74 @@ _cairo_surface_is_quartz (const cairo_su
2066      return surface->backend == &cairo_quartz_surface_backend;
2067  }
2068
2069 +CGContextRef
2070 +cairo_quartz_get_cg_context_with_clip (cairo_t *cr)
2071 +{
2072 +
2073 +    cairo_surface_t *surface = cr->gstate->target;
2074 +    cairo_clip_t *clip = &cr->gstate->clip;
2075 +    cairo_status_t status;
2076 +
2077 +    cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface;
2078 +
2079 +    if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ)
2080 +       return NULL;
2081 +
2082 +    if (!clip->path) {
2083 +       if (clip->all_clipped) {
2084 +           /* Save the state before we set an empty clip rect so that
2085 +            * our previous clip will be restored */
2086 +
2087 +           /* _cairo_surface_clipper_set_clip doesn't deal with
2088 +            * clip->all_clipped because drawing is normally discarded earlier */
2089 +           CGRect empty = {{0,0}, {0,0}};
2090 +           CGContextClipToRect (quartz->cgContext, empty);
2091 +           CGContextSaveGState (quartz->cgContext);
2092 +
2093 +           return quartz->cgContext;
2094 +       }
2095 +
2096 +       /* an empty clip is represented by NULL */
2097 +       clip = NULL;
2098 +    }
2099 +
2100 +    status = _cairo_surface_clipper_set_clip (&quartz->clipper, clip);
2101 +
2102 +    /* Save the state after we set the clip so that it persists
2103 +     * after we restore */
2104 +    CGContextSaveGState (quartz->cgContext);
2105 +
2106 +    if (unlikely (status))
2107 +       return NULL;
2108 +
2109 +    return quartz->cgContext;
2110 +}
2111 +
2112 +void
2113 +cairo_quartz_finish_cg_context_with_clip (cairo_t *cr)
2114 +{
2115 +    cairo_surface_t *surface = cr->gstate->target;
2116 +
2117 +    cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface;
2118 +
2119 +    if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ)
2120 +       return;
2121 +
2122 +    CGContextRestoreGState (quartz->cgContext);
2123 +}
2124 +
2125 +cairo_surface_t *
2126 +cairo_quartz_surface_get_image (cairo_surface_t *surface)
2127 +{
2128 +    cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *)surface;
2129 +    cairo_image_surface_t *image;
2130 +
2131 +    if (_cairo_quartz_get_image(quartz, &image))
2132 +        return NULL;
2133 +
2134 +    return (cairo_surface_t *)image;
2135 +}
2136 +
2137  /* Debug stuff */
2138
2139  #ifdef QUARTZ_DEBUG
2140 --- a/src/cairo-quartz.h        2012-11-13 18:20:00.000000000 -0800
2141 +++ b/src/cairo-quartz.h        2012-11-13 18:06:56.000000000 -0800
2142 @@ -50,6 +50,19 @@ cairo_quartz_surface_create (cairo_forma
2143                               unsigned int height);
2144
2145  cairo_public cairo_surface_t *
2146 +cairo_quartz_surface_create_for_data (unsigned char *data,
2147 +                                     cairo_format_t format,
2148 +                                     unsigned int width,
2149 +                                     unsigned int height,
2150 +                                     unsigned int stride);
2151 +
2152 +cairo_public cairo_surface_t *
2153 +cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface,
2154 +                                      cairo_content_t content,
2155 +                                      unsigned int width,
2156 +                                      unsigned int height);
2157 +
2158 +cairo_public cairo_surface_t *
2159  cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
2160                                              unsigned int width,
2161                                              unsigned int height);
2162 @@ -57,6 +70,15 @@ cairo_quartz_surface_create_for_cg_conte
2163  cairo_public CGContextRef
2164  cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);
2165
2166 +cairo_public CGContextRef
2167 +cairo_quartz_get_cg_context_with_clip (cairo_t *cr);
2168 +
2169 +cairo_public void
2170 +cairo_quartz_finish_cg_context_with_clip (cairo_t *cr);
2171 +
2172 +cairo_public cairo_surface_t *
2173 +cairo_quartz_surface_get_image (cairo_surface_t *surface);
2174 +
2175  #if CAIRO_HAS_QUARTZ_FONT
2176
2177  /*
2178 @@ -66,8 +88,10 @@ cairo_quartz_surface_get_cg_context (cai
2179  cairo_public cairo_font_face_t *
2180  cairo_quartz_font_face_create_for_cgfont (CGFontRef font);
2181
2182 +#ifndef __LP64__
2183  cairo_public cairo_font_face_t *
2184  cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id);
2185 +#endif
2186
2187  #endif /* CAIRO_HAS_QUARTZ_FONT */