d216261eaa9e4810318daa8067846c719bd8278e
[framework/graphics/cairo.git] / src / cairo-quartz-surface.c
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright � 2006, 2007 Mozilla Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is Mozilla Foundation.
32  *
33  * Contributor(s):
34  *      Vladimir Vukicevic <vladimir@mozilla.com>
35  */
36
37 #define _GNU_SOURCE /* required for RTLD_DEFAULT */
38 #include "cairoint.h"
39
40 #include "cairo-quartz-private.h"
41
42 #include "cairo-composite-rectangles-private.h"
43 #include "cairo-compositor-private.h"
44 #include "cairo-default-context-private.h"
45 #include "cairo-error-private.h"
46 #include "cairo-image-surface-private.h"
47 #include "cairo-pattern-private.h"
48 #include "cairo-surface-backend-private.h"
49 #include "cairo-surface-clipper-private.h"
50
51 #include <dlfcn.h>
52
53 #ifndef RTLD_DEFAULT
54 #define RTLD_DEFAULT ((void *) 0)
55 #endif
56
57 #include <limits.h>
58
59 #undef QUARTZ_DEBUG
60
61 #ifdef QUARTZ_DEBUG
62 #define ND(_x)  fprintf _x
63 #else
64 #define ND(_x)  do {} while(0)
65 #endif
66
67 #define IS_EMPTY(s) ((s)->extents.width == 0 || (s)->extents.height == 0)
68
69 /**
70  * SECTION:cairo-quartz
71  * @Title: Quartz Surfaces
72  * @Short_Description: Rendering to Quartz surfaces
73  * @See_Also: #cairo_surface_t
74  *
75  * The Quartz surface is used to render cairo graphics targeting the
76  * Apple OS X Quartz rendering system.
77  **/
78
79 /**
80  * CAIRO_HAS_QUARTZ_SURFACE:
81  *
82  * Defined if the Quartz surface backend is available.
83  * This macro can be used to conditionally compile backend-specific code.
84  *
85  * Since: 1.6
86  **/
87
88 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
89 /* This method is private, but it exists.  Its params are are exposed
90  * as args to the NS* method, but not as CG.
91  */
92 enum PrivateCGCompositeMode {
93     kPrivateCGCompositeClear            = 0,
94     kPrivateCGCompositeCopy             = 1,
95     kPrivateCGCompositeSourceOver       = 2,
96     kPrivateCGCompositeSourceIn         = 3,
97     kPrivateCGCompositeSourceOut        = 4,
98     kPrivateCGCompositeSourceAtop       = 5,
99     kPrivateCGCompositeDestinationOver  = 6,
100     kPrivateCGCompositeDestinationIn    = 7,
101     kPrivateCGCompositeDestinationOut   = 8,
102     kPrivateCGCompositeDestinationAtop  = 9,
103     kPrivateCGCompositeXOR              = 10,
104     kPrivateCGCompositePlusDarker       = 11, // (max (0, (1-d) + (1-s)))
105     kPrivateCGCompositePlusLighter      = 12, // (min (1, s + d))
106 };
107 typedef enum PrivateCGCompositeMode PrivateCGCompositeMode;
108 CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
109 #endif
110
111 /* Some of these are present in earlier versions of the OS than where
112  * they are public; other are not public at all
113  */
114 /* public since 10.5 */
115 static void (*CGContextDrawTiledImagePtr) (CGContextRef, CGRect, CGImageRef) = NULL;
116
117 /* public since 10.6 */
118 static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL;
119 static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
120
121 /* not yet public */
122 static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
123 static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
124
125 static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
126
127 /*
128  * Utility functions
129  */
130
131 #ifdef QUARTZ_DEBUG
132 static void quartz_surface_to_png (cairo_quartz_surface_t *nq, char *dest);
133 static void quartz_image_to_png (CGImageRef, char *dest);
134 #endif
135
136 static cairo_quartz_surface_t *
137 _cairo_quartz_surface_create_internal (CGContextRef cgContext,
138                                        cairo_content_t content,
139                                        unsigned int width,
140                                        unsigned int height);
141
142 static cairo_bool_t
143 _cairo_surface_is_quartz (const cairo_surface_t *surface);
144
145 /* Load all extra symbols */
146 static void quartz_ensure_symbols (void)
147 {
148     if (likely (_cairo_quartz_symbol_lookup_done))
149         return;
150
151     CGContextDrawTiledImagePtr = dlsym (RTLD_DEFAULT, "CGContextDrawTiledImage");
152     CGContextGetTypePtr = dlsym (RTLD_DEFAULT, "CGContextGetType");
153     CGContextCopyPathPtr = dlsym (RTLD_DEFAULT, "CGContextCopyPath");
154     CGContextGetAllowsFontSmoothingPtr = dlsym (RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
155     CGContextSetAllowsFontSmoothingPtr = dlsym (RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
156
157     _cairo_quartz_symbol_lookup_done = TRUE;
158 }
159
160 CGImageRef
161 CairoQuartzCreateCGImage (cairo_format_t format,
162                           unsigned int width,
163                           unsigned int height,
164                           unsigned int stride,
165                           void *data,
166                           cairo_bool_t interpolate,
167                           CGColorSpaceRef colorSpaceOverride,
168                           CGDataProviderReleaseDataCallback releaseCallback,
169                           void *releaseInfo)
170 {
171     CGImageRef image = NULL;
172     CGDataProviderRef dataProvider = NULL;
173     CGColorSpaceRef colorSpace = colorSpaceOverride;
174     CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host;
175     int bitsPerComponent, bitsPerPixel;
176
177     switch (format) {
178         case CAIRO_FORMAT_ARGB32:
179             if (colorSpace == NULL)
180                 colorSpace = CGColorSpaceCreateDeviceRGB ();
181             bitinfo |= kCGImageAlphaPremultipliedFirst;
182             bitsPerComponent = 8;
183             bitsPerPixel = 32;
184             break;
185
186         case CAIRO_FORMAT_RGB24:
187             if (colorSpace == NULL)
188                 colorSpace = CGColorSpaceCreateDeviceRGB ();
189             bitinfo |= kCGImageAlphaNoneSkipFirst;
190             bitsPerComponent = 8;
191             bitsPerPixel = 32;
192             break;
193
194         case CAIRO_FORMAT_A8:
195             bitsPerComponent = 8;
196             bitsPerPixel = 8;
197             break;
198
199         case CAIRO_FORMAT_A1:
200 #ifdef WORDS_BIGENDIAN
201             bitsPerComponent = 1;
202             bitsPerPixel = 1;
203             break;
204 #endif
205
206         case CAIRO_FORMAT_RGB16_565:
207         case CAIRO_FORMAT_INVALID:
208         default:
209             return NULL;
210     }
211
212     dataProvider = CGDataProviderCreateWithData (releaseInfo,
213                                                  data,
214                                                  height * stride,
215                                                  releaseCallback);
216
217     if (unlikely (!dataProvider)) {
218         // manually release
219         if (releaseCallback)
220             releaseCallback (releaseInfo, data, height * stride);
221         goto FINISH;
222     }
223
224     if (format == CAIRO_FORMAT_A8 || format == CAIRO_FORMAT_A1) {
225         cairo_quartz_float_t decode[] = {1.0, 0.0};
226         image = CGImageMaskCreate (width, height,
227                                    bitsPerComponent,
228                                    bitsPerPixel,
229                                    stride,
230                                    dataProvider,
231                                    decode,
232                                    interpolate);
233     } else
234         image = CGImageCreate (width, height,
235                                bitsPerComponent,
236                                bitsPerPixel,
237                                stride,
238                                colorSpace,
239                                bitinfo,
240                                dataProvider,
241                                NULL,
242                                interpolate,
243                                kCGRenderingIntentDefault);
244
245 FINISH:
246
247     CGDataProviderRelease (dataProvider);
248
249     if (colorSpace != colorSpaceOverride)
250         CGColorSpaceRelease (colorSpace);
251
252     return image;
253 }
254
255 static inline cairo_bool_t
256 _cairo_quartz_is_cgcontext_bitmap_context (CGContextRef cgc)
257 {
258     if (unlikely (cgc == NULL))
259         return FALSE;
260
261     if (likely (CGContextGetTypePtr)) {
262         /* 4 is the type value of a bitmap context */
263         return CGContextGetTypePtr (cgc) == 4;
264     }
265
266     /* This will cause a (harmless) warning to be printed if called on a non-bitmap context */
267     return CGBitmapContextGetBitsPerPixel (cgc) != 0;
268 }
269
270 /* CoreGraphics limitation with flipped CTM surfaces: height must be less than signed 16-bit max */
271
272 #define CG_MAX_HEIGHT   SHRT_MAX
273 #define CG_MAX_WIDTH    USHRT_MAX
274
275 /* is the desired size of the surface within bounds? */
276 cairo_bool_t
277 _cairo_quartz_verify_surface_size (int width, int height)
278 {
279     /* hmmm, allow width, height == 0 ? */
280     if (width < 0 || height < 0)
281         return FALSE;
282
283     if (width > CG_MAX_WIDTH || height > CG_MAX_HEIGHT)
284         return FALSE;
285
286     return TRUE;
287 }
288
289 /*
290  * Cairo path -> Quartz path conversion helpers
291  */
292
293 /* cairo path -> execute in context */
294 static cairo_status_t
295 _cairo_path_to_quartz_context_move_to (void *closure,
296                                        const cairo_point_t *point)
297 {
298     //ND ((stderr, "moveto: %f %f\n", _cairo_fixed_to_double (point->x), _cairo_fixed_to_double (point->y)));
299     double x = _cairo_fixed_to_double (point->x);
300     double y = _cairo_fixed_to_double (point->y);
301
302     CGContextMoveToPoint (closure, x, y);
303     return CAIRO_STATUS_SUCCESS;
304 }
305
306 static cairo_status_t
307 _cairo_path_to_quartz_context_line_to (void *closure,
308                                        const cairo_point_t *point)
309 {
310     //ND ((stderr, "lineto: %f %f\n",  _cairo_fixed_to_double (point->x), _cairo_fixed_to_double (point->y)));
311     double x = _cairo_fixed_to_double (point->x);
312     double y = _cairo_fixed_to_double (point->y);
313
314     CGContextAddLineToPoint (closure, x, y);
315     return CAIRO_STATUS_SUCCESS;
316 }
317
318 static cairo_status_t
319 _cairo_path_to_quartz_context_curve_to (void *closure,
320                                         const cairo_point_t *p0,
321                                         const cairo_point_t *p1,
322                                         const cairo_point_t *p2)
323 {
324     //ND ((stderr, "curveto: %f,%f %f,%f %f,%f\n",
325     //             _cairo_fixed_to_double (p0->x), _cairo_fixed_to_double (p0->y),
326     //             _cairo_fixed_to_double (p1->x), _cairo_fixed_to_double (p1->y),
327     //             _cairo_fixed_to_double (p2->x), _cairo_fixed_to_double (p2->y)));
328     double x0 = _cairo_fixed_to_double (p0->x);
329     double y0 = _cairo_fixed_to_double (p0->y);
330     double x1 = _cairo_fixed_to_double (p1->x);
331     double y1 = _cairo_fixed_to_double (p1->y);
332     double x2 = _cairo_fixed_to_double (p2->x);
333     double y2 = _cairo_fixed_to_double (p2->y);
334
335     CGContextAddCurveToPoint (closure, x0, y0, x1, y1, x2, y2);
336     return CAIRO_STATUS_SUCCESS;
337 }
338
339 static cairo_status_t
340 _cairo_path_to_quartz_context_close_path (void *closure)
341 {
342     //ND ((stderr, "closepath\n"));
343     CGContextClosePath (closure);
344     return CAIRO_STATUS_SUCCESS;
345 }
346
347 static void
348 _cairo_quartz_cairo_path_to_quartz_context (const cairo_path_fixed_t *path,
349                                             CGContextRef closure)
350 {
351     cairo_status_t status;
352
353     CGContextBeginPath (closure);
354     status = _cairo_path_fixed_interpret (path,
355                                           _cairo_path_to_quartz_context_move_to,
356                                           _cairo_path_to_quartz_context_line_to,
357                                           _cairo_path_to_quartz_context_curve_to,
358                                           _cairo_path_to_quartz_context_close_path,
359                                           closure);
360
361     assert (status == CAIRO_STATUS_SUCCESS);
362 }
363
364 /*
365  * Misc helpers/callbacks
366  */
367
368 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
369 static PrivateCGCompositeMode
370 _cairo_quartz_cairo_operator_to_quartz_composite (cairo_operator_t op)
371 {
372     switch (op) {
373         case CAIRO_OPERATOR_CLEAR:
374             return kPrivateCGCompositeClear;
375         case CAIRO_OPERATOR_SOURCE:
376             return kPrivateCGCompositeCopy;
377         case CAIRO_OPERATOR_OVER:
378             return kPrivateCGCompositeSourceOver;
379         case CAIRO_OPERATOR_IN:
380             return kPrivateCGCompositeSourceIn;
381         case CAIRO_OPERATOR_OUT:
382             return kPrivateCGCompositeSourceOut;
383         case CAIRO_OPERATOR_ATOP:
384             return kPrivateCGCompositeSourceAtop;
385         case CAIRO_OPERATOR_DEST_OVER:
386             return kPrivateCGCompositeDestinationOver;
387         case CAIRO_OPERATOR_DEST_IN:
388             return kPrivateCGCompositeDestinationIn;
389         case CAIRO_OPERATOR_DEST_OUT:
390             return kPrivateCGCompositeDestinationOut;
391         case CAIRO_OPERATOR_DEST_ATOP:
392             return kPrivateCGCompositeDestinationAtop;
393         case CAIRO_OPERATOR_XOR:
394             return kPrivateCGCompositeXOR;
395         case CAIRO_OPERATOR_ADD:
396             return kPrivateCGCompositePlusLighter;
397
398         case CAIRO_OPERATOR_DEST:
399         case CAIRO_OPERATOR_SATURATE:
400         case CAIRO_OPERATOR_MULTIPLY:
401         case CAIRO_OPERATOR_SCREEN:
402         case CAIRO_OPERATOR_OVERLAY:
403         case CAIRO_OPERATOR_DARKEN:
404         case CAIRO_OPERATOR_LIGHTEN:
405         case CAIRO_OPERATOR_COLOR_DODGE:
406         case CAIRO_OPERATOR_COLOR_BURN:
407         case CAIRO_OPERATOR_HARD_LIGHT:
408         case CAIRO_OPERATOR_SOFT_LIGHT:
409         case CAIRO_OPERATOR_DIFFERENCE:
410         case CAIRO_OPERATOR_EXCLUSION:
411         case CAIRO_OPERATOR_HSL_HUE:
412         case CAIRO_OPERATOR_HSL_SATURATION:
413         case CAIRO_OPERATOR_HSL_COLOR:
414         case CAIRO_OPERATOR_HSL_LUMINOSITY:
415         default:
416             ASSERT_NOT_REACHED;
417     }
418 }
419 #endif
420
421 static CGBlendMode
422 _cairo_quartz_cairo_operator_to_quartz_blend (cairo_operator_t op)
423 {
424     switch (op) {
425         case CAIRO_OPERATOR_MULTIPLY:
426             return kCGBlendModeMultiply;
427         case CAIRO_OPERATOR_SCREEN:
428             return kCGBlendModeScreen;
429         case CAIRO_OPERATOR_OVERLAY:
430             return kCGBlendModeOverlay;
431         case CAIRO_OPERATOR_DARKEN:
432             return kCGBlendModeDarken;
433         case CAIRO_OPERATOR_LIGHTEN:
434             return kCGBlendModeLighten;
435         case CAIRO_OPERATOR_COLOR_DODGE:
436             return kCGBlendModeColorDodge;
437         case CAIRO_OPERATOR_COLOR_BURN:
438             return kCGBlendModeColorBurn;
439         case CAIRO_OPERATOR_HARD_LIGHT:
440             return kCGBlendModeHardLight;
441         case CAIRO_OPERATOR_SOFT_LIGHT:
442             return kCGBlendModeSoftLight;
443         case CAIRO_OPERATOR_DIFFERENCE:
444             return kCGBlendModeDifference;
445         case CAIRO_OPERATOR_EXCLUSION:
446             return kCGBlendModeExclusion;
447         case CAIRO_OPERATOR_HSL_HUE:
448             return kCGBlendModeHue;
449         case CAIRO_OPERATOR_HSL_SATURATION:
450             return kCGBlendModeSaturation;
451         case CAIRO_OPERATOR_HSL_COLOR:
452             return kCGBlendModeColor;
453         case CAIRO_OPERATOR_HSL_LUMINOSITY:
454             return kCGBlendModeLuminosity;
455
456 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
457         case CAIRO_OPERATOR_CLEAR:
458             return kCGBlendModeClear;
459         case CAIRO_OPERATOR_SOURCE:
460             return kCGBlendModeCopy;
461         case CAIRO_OPERATOR_OVER:
462             return kCGBlendModeNormal;
463         case CAIRO_OPERATOR_IN:
464             return kCGBlendModeSourceIn;
465         case CAIRO_OPERATOR_OUT:
466             return kCGBlendModeSourceOut;
467         case CAIRO_OPERATOR_ATOP:
468             return kCGBlendModeSourceAtop;
469         case CAIRO_OPERATOR_DEST_OVER:
470             return kCGBlendModeDestinationOver;
471         case CAIRO_OPERATOR_DEST_IN:
472             return kCGBlendModeDestinationIn;
473         case CAIRO_OPERATOR_DEST_OUT:
474             return kCGBlendModeDestinationOut;
475         case CAIRO_OPERATOR_DEST_ATOP:
476             return kCGBlendModeDestinationAtop;
477         case CAIRO_OPERATOR_XOR:
478             return kCGBlendModeXOR;
479         case CAIRO_OPERATOR_ADD:
480             return kCGBlendModePlusLighter;
481 #else
482         case CAIRO_OPERATOR_CLEAR:
483         case CAIRO_OPERATOR_SOURCE:
484         case CAIRO_OPERATOR_OVER:
485         case CAIRO_OPERATOR_IN:
486         case CAIRO_OPERATOR_OUT:
487         case CAIRO_OPERATOR_ATOP:
488         case CAIRO_OPERATOR_DEST_OVER:
489         case CAIRO_OPERATOR_DEST_IN:
490         case CAIRO_OPERATOR_DEST_OUT:
491         case CAIRO_OPERATOR_DEST_ATOP:
492         case CAIRO_OPERATOR_XOR:
493         case CAIRO_OPERATOR_ADD:
494 #endif
495
496         case CAIRO_OPERATOR_DEST:
497         case CAIRO_OPERATOR_SATURATE:
498         default:
499             ASSERT_NOT_REACHED;
500     }
501 }
502
503 static cairo_int_status_t
504 _cairo_cgcontext_set_cairo_operator (CGContextRef context, cairo_operator_t op)
505 {
506     CGBlendMode blendmode;
507
508     assert (op != CAIRO_OPERATOR_DEST);
509
510     /* Quartz doesn't support SATURATE at all. COLOR_DODGE and
511      * COLOR_BURN in Quartz follow the ISO32000 definition, but cairo
512      * uses the definition from the Adobe Supplement.
513      */
514     if (op == CAIRO_OPERATOR_SATURATE ||
515         op == CAIRO_OPERATOR_COLOR_DODGE ||
516         op == CAIRO_OPERATOR_COLOR_BURN)
517     {
518         return CAIRO_INT_STATUS_UNSUPPORTED;
519     }
520
521 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1050
522     if (op <= CAIRO_OPERATOR_ADD) {
523         PrivateCGCompositeMode compmode;
524
525         compmode = _cairo_quartz_cairo_operator_to_quartz_composite (op);
526         CGContextSetCompositeOperation (context, compmode);
527         return CAIRO_STATUS_SUCCESS;
528     }
529 #endif
530
531     blendmode = _cairo_quartz_cairo_operator_to_quartz_blend (op);
532     CGContextSetBlendMode (context, blendmode);
533     return CAIRO_STATUS_SUCCESS;
534 }
535
536 static cairo_int_status_t
537 _cairo_quartz_surface_set_cairo_operator (cairo_quartz_surface_t *surface, cairo_operator_t op)
538 {
539     ND((stderr, "%p _cairo_quartz_surface_set_cairo_operator %d\n", surface, op));
540
541     /* When the destination has no color components, we can avoid some
542      * fallbacks, but we have to workaround operators which behave
543      * differently in Quartz. */
544     if (surface->base.content == CAIRO_CONTENT_ALPHA) {
545         assert (op != CAIRO_OPERATOR_ATOP); /* filtered by surface layer */
546
547         if (op == CAIRO_OPERATOR_SOURCE ||
548             op == CAIRO_OPERATOR_IN ||
549             op == CAIRO_OPERATOR_OUT ||
550             op == CAIRO_OPERATOR_DEST_IN ||
551             op == CAIRO_OPERATOR_DEST_ATOP ||
552             op == CAIRO_OPERATOR_XOR)
553         {
554             return CAIRO_INT_STATUS_UNSUPPORTED;
555         }
556
557         if (op == CAIRO_OPERATOR_DEST_OVER)
558             op = CAIRO_OPERATOR_OVER;
559         else if (op == CAIRO_OPERATOR_SATURATE)
560             op = CAIRO_OPERATOR_ADD;
561         else if (op == CAIRO_OPERATOR_COLOR_DODGE)
562             op = CAIRO_OPERATOR_OVER;
563         else if (op == CAIRO_OPERATOR_COLOR_BURN)
564             op = CAIRO_OPERATOR_OVER;
565     }
566
567     return _cairo_cgcontext_set_cairo_operator (surface->cgContext, op);
568 }
569
570 static inline CGLineCap
571 _cairo_quartz_cairo_line_cap_to_quartz (cairo_line_cap_t ccap)
572 {
573     switch (ccap) {
574     default:
575         ASSERT_NOT_REACHED;
576
577     case CAIRO_LINE_CAP_BUTT:
578         return kCGLineCapButt;
579
580     case CAIRO_LINE_CAP_ROUND:
581         return kCGLineCapRound;
582
583     case CAIRO_LINE_CAP_SQUARE:
584         return kCGLineCapSquare;
585     }
586 }
587
588 static inline CGLineJoin
589 _cairo_quartz_cairo_line_join_to_quartz (cairo_line_join_t cjoin)
590 {
591     switch (cjoin) {
592     default:
593         ASSERT_NOT_REACHED;
594
595     case CAIRO_LINE_JOIN_MITER:
596         return kCGLineJoinMiter;
597
598     case CAIRO_LINE_JOIN_ROUND:
599         return kCGLineJoinRound;
600
601     case CAIRO_LINE_JOIN_BEVEL:
602         return kCGLineJoinBevel;
603     }
604 }
605
606 static inline CGInterpolationQuality
607 _cairo_quartz_filter_to_quartz (cairo_filter_t filter)
608 {
609     switch (filter) {
610     case CAIRO_FILTER_NEAREST:
611     case CAIRO_FILTER_FAST:
612         return kCGInterpolationNone;
613
614     case CAIRO_FILTER_BEST:
615     case CAIRO_FILTER_GOOD:
616     case CAIRO_FILTER_BILINEAR:
617     case CAIRO_FILTER_GAUSSIAN:
618         return kCGInterpolationDefault;
619
620     default:
621         ASSERT_NOT_REACHED;
622         return kCGInterpolationDefault;
623     }
624 }
625
626 static inline void
627 _cairo_quartz_cairo_matrix_to_quartz (const cairo_matrix_t *src,
628                                       CGAffineTransform *dst)
629 {
630     dst->a = src->xx;
631     dst->b = src->yx;
632     dst->c = src->xy;
633     dst->d = src->yy;
634     dst->tx = src->x0;
635     dst->ty = src->y0;
636 }
637
638
639 /*
640  * Source -> Quartz setup and finish functions
641  */
642
643 static void
644 ComputeGradientValue (void *info,
645                       const cairo_quartz_float_t *in,
646                       cairo_quartz_float_t *out)
647 {
648     double fdist = *in;
649     const cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info;
650     unsigned int i;
651
652     /* Put fdist back in the 0.0..1.0 range if we're doing
653      * REPEAT/REFLECT
654      */
655     if (grad->base.extend == CAIRO_EXTEND_REPEAT) {
656         fdist = fdist - floor (fdist);
657     } else if (grad->base.extend == CAIRO_EXTEND_REFLECT) {
658         fdist = fmod (fabs (fdist), 2.0);
659         if (fdist > 1.0)
660             fdist = 2.0 - fdist;
661     }
662
663     for (i = 0; i < grad->n_stops; i++)
664         if (grad->stops[i].offset > fdist)
665             break;
666
667     if (i == 0 || i == grad->n_stops) {
668         if (i == grad->n_stops)
669             --i;
670         out[0] = grad->stops[i].color.red;
671         out[1] = grad->stops[i].color.green;
672         out[2] = grad->stops[i].color.blue;
673         out[3] = grad->stops[i].color.alpha;
674     } else {
675         cairo_quartz_float_t ax = grad->stops[i-1].offset;
676         cairo_quartz_float_t bx = grad->stops[i].offset - ax;
677         cairo_quartz_float_t bp = (fdist - ax)/bx;
678         cairo_quartz_float_t ap = 1.0 - bp;
679
680         out[0] =
681             grad->stops[i-1].color.red * ap +
682             grad->stops[i].color.red * bp;
683         out[1] =
684             grad->stops[i-1].color.green * ap +
685             grad->stops[i].color.green * bp;
686         out[2] =
687             grad->stops[i-1].color.blue * ap +
688             grad->stops[i].color.blue * bp;
689         out[3] =
690             grad->stops[i-1].color.alpha * ap +
691             grad->stops[i].color.alpha * bp;
692     }
693 }
694
695 static const cairo_quartz_float_t gradient_output_value_ranges[8] = {
696     0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f
697 };
698 static const CGFunctionCallbacks gradient_callbacks = {
699     0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy
700 };
701
702 /* Quartz computes a small number of samples of the gradient color
703  * function. On MacOS X 10.5 it apparently computes only 1024
704  * samples. */
705 #define MAX_GRADIENT_RANGE 1024
706
707 static CGFunctionRef
708 CairoQuartzCreateGradientFunction (const cairo_gradient_pattern_t *gradient,
709                                    const cairo_rectangle_int_t    *extents,
710                                    cairo_circle_double_t          *start,
711                                    cairo_circle_double_t          *end)
712 {
713     cairo_pattern_t *pat;
714     cairo_quartz_float_t input_value_range[2];
715
716     if (gradient->base.extend != CAIRO_EXTEND_NONE) {
717         double bounds_x1, bounds_x2, bounds_y1, bounds_y2;
718         double t[2], tolerance;
719
720         tolerance = fabs (_cairo_matrix_compute_determinant (&gradient->base.matrix));
721         tolerance /= _cairo_matrix_transformed_circle_major_axis (&gradient->base.matrix, 1);
722
723         bounds_x1 = extents->x;
724         bounds_y1 = extents->y;
725         bounds_x2 = extents->x + extents->width;
726         bounds_y2 = extents->y + extents->height;
727         _cairo_matrix_transform_bounding_box (&gradient->base.matrix,
728                                               &bounds_x1, &bounds_y1,
729                                               &bounds_x2, &bounds_y2,
730                                               NULL);
731
732         _cairo_gradient_pattern_box_to_parameter (gradient,
733                                                   bounds_x1, bounds_y1,
734                                                   bounds_x2, bounds_y2,
735                                                   tolerance,
736                                                   t);
737
738         if (gradient->base.extend == CAIRO_EXTEND_PAD) {
739             t[0] = MAX (t[0], -0.5);
740             t[1] = MIN (t[1],  1.5);
741         } else if (t[1] - t[0] > MAX_GRADIENT_RANGE)
742             return NULL;
743
744         /* set the input range for the function -- the function knows how
745            to map values outside of 0.0 .. 1.0 to the correct color */
746         input_value_range[0] = t[0];
747         input_value_range[1] = t[1];
748     } else {
749         input_value_range[0] = 0;
750         input_value_range[1] = 1;
751     }
752
753     _cairo_gradient_pattern_interpolate (gradient, input_value_range[0], start);
754     _cairo_gradient_pattern_interpolate (gradient, input_value_range[1], end);
755
756     if (_cairo_pattern_create_copy (&pat, &gradient->base))
757         return NULL;
758
759     return CGFunctionCreate (pat,
760                              1,
761                              input_value_range,
762                              4,
763                              gradient_output_value_ranges,
764                              &gradient_callbacks);
765 }
766
767 /* Obtain a CGImageRef from a #cairo_surface_t * */
768
769 typedef struct {
770     cairo_surface_t *surface;
771     cairo_image_surface_t *image_out;
772     void *image_extra;
773 } quartz_source_image_t;
774
775 static void
776 DataProviderReleaseCallback (void *info, const void *data, size_t size)
777 {
778     quartz_source_image_t *source_img = info;
779     _cairo_surface_release_source_image (source_img->surface, source_img->image_out, source_img->image_extra);
780     free (source_img);
781 }
782
783 static cairo_status_t
784 _cairo_surface_to_cgimage (cairo_surface_t *source,
785                            CGImageRef *image_out)
786 {
787     cairo_status_t status;
788     quartz_source_image_t *source_img;
789
790     if (source->backend && source->backend->type == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) {
791         cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source;
792         *image_out = CGImageRetain (surface->image);
793         return CAIRO_STATUS_SUCCESS;
794     }
795
796     if (_cairo_surface_is_quartz (source)) {
797         cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source;
798         if (IS_EMPTY (surface)) {
799             *image_out = NULL;
800             return CAIRO_INT_STATUS_NOTHING_TO_DO;
801         }
802
803         if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
804             *image_out = CGBitmapContextCreateImage (surface->cgContext);
805             if (*image_out)
806                 return CAIRO_STATUS_SUCCESS;
807         }
808     }
809
810     source_img = malloc (sizeof (quartz_source_image_t));
811     if (unlikely (source_img == NULL))
812         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
813
814     source_img->surface = source;
815
816     status = _cairo_surface_acquire_source_image (source_img->surface, &source_img->image_out, &source_img->image_extra);
817     if (unlikely (status)) {
818         free (source_img);
819         return status;
820     }
821
822     if (source_img->image_out->width == 0 || source_img->image_out->height == 0) {
823         *image_out = NULL;
824         DataProviderReleaseCallback (source_img,
825                                      source_img->image_out->data,
826                                      source_img->image_out->height * source_img->image_out->stride);
827     } else {
828         *image_out = CairoQuartzCreateCGImage (source_img->image_out->format,
829                                                source_img->image_out->width,
830                                                source_img->image_out->height,
831                                                source_img->image_out->stride,
832                                                source_img->image_out->data,
833                                                TRUE,
834                                                NULL,
835                                                DataProviderReleaseCallback,
836                                                source_img);
837
838         /* TODO: differentiate memory error and unsupported surface type */
839         if (unlikely (*image_out == NULL))
840             status = CAIRO_INT_STATUS_UNSUPPORTED;
841     }
842
843     return status;
844 }
845
846 /* Generic #cairo_pattern_t -> CGPattern function */
847
848 typedef struct {
849     CGImageRef image;
850     CGRect imageBounds;
851     cairo_bool_t do_reflect;
852 } SurfacePatternDrawInfo;
853
854 static void
855 SurfacePatternDrawFunc (void *ainfo, CGContextRef context)
856 {
857     SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo;
858
859     CGContextTranslateCTM (context, 0, info->imageBounds.size.height);
860     CGContextScaleCTM (context, 1, -1);
861
862     CGContextDrawImage (context, info->imageBounds, info->image);
863     if (info->do_reflect) {
864         /* draw 3 more copies of the image, flipped.
865          * DrawImage draws the image according to the current Y-direction into the rectangle given
866          * (imageBounds); at the time of the first DrawImage above, the origin is at the bottom left
867          * of the base image position, and the Y axis is extending upwards.
868          */
869
870         /* Make the y axis extend downwards, and draw a flipped image below */
871         CGContextScaleCTM (context, 1, -1);
872         CGContextDrawImage (context, info->imageBounds, info->image);
873
874         /* Shift over to the right, and flip vertically (translation is 2x,
875          * since we'll be flipping and thus rendering the rectangle "backwards"
876          */
877         CGContextTranslateCTM (context, 2 * info->imageBounds.size.width, 0);
878         CGContextScaleCTM (context, -1, 1);
879         CGContextDrawImage (context, info->imageBounds, info->image);
880
881         /* Then unflip the Y-axis again, and draw the image above the point. */
882         CGContextScaleCTM (context, 1, -1);
883         CGContextDrawImage (context, info->imageBounds, info->image);
884     }
885 }
886
887 static void
888 SurfacePatternReleaseInfoFunc (void *ainfo)
889 {
890     SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo;
891
892     CGImageRelease (info->image);
893     free (info);
894 }
895
896 static cairo_int_status_t
897 _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest,
898                                                          const cairo_pattern_t *apattern,
899                                                          CGPatternRef *cgpat)
900 {
901     cairo_surface_pattern_t *spattern;
902     cairo_surface_t *pat_surf;
903     cairo_rectangle_int_t extents;
904
905     CGImageRef image;
906     CGRect pbounds;
907     CGAffineTransform ptransform, stransform;
908     CGPatternCallbacks cb = { 0,
909                               SurfacePatternDrawFunc,
910                               SurfacePatternReleaseInfoFunc };
911     SurfacePatternDrawInfo *info;
912     cairo_quartz_float_t rw, rh;
913     cairo_status_t status;
914     cairo_bool_t is_bounded;
915
916     cairo_matrix_t m;
917
918     /* SURFACE is the only type we'll handle here */
919     assert (apattern->type == CAIRO_PATTERN_TYPE_SURFACE);
920
921     spattern = (cairo_surface_pattern_t *) apattern;
922     pat_surf = spattern->surface;
923
924     is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
925     assert (is_bounded);
926
927     status = _cairo_surface_to_cgimage (pat_surf, &image);
928     if (unlikely (status))
929         return status;
930
931     info = malloc (sizeof (SurfacePatternDrawInfo));
932     if (unlikely (!info))
933         return CAIRO_STATUS_NO_MEMORY;
934
935     /* XXX -- if we're printing, we may need to call CGImageCreateCopy to make sure
936      * that the data will stick around for this image when the printer gets to it.
937      * Otherwise, the underlying data store may disappear from under us!
938      *
939      * _cairo_surface_to_cgimage will copy when it converts non-Quartz surfaces,
940      * since the Quartz surfaces have a higher chance of sticking around.  If the
941      * source is a quartz image surface, then it's set up to retain a ref to the
942      * image surface that it's backed by.
943      */
944     info->image = image;
945     info->imageBounds = CGRectMake (0, 0, extents.width, extents.height);
946     info->do_reflect = FALSE;
947
948     pbounds.origin.x = 0;
949     pbounds.origin.y = 0;
950
951     if (spattern->base.extend == CAIRO_EXTEND_REFLECT) {
952         pbounds.size.width = 2.0 * extents.width;
953         pbounds.size.height = 2.0 * extents.height;
954         info->do_reflect = TRUE;
955     } else {
956         pbounds.size.width = extents.width;
957         pbounds.size.height = extents.height;
958     }
959     rw = pbounds.size.width;
960     rh = pbounds.size.height;
961
962     m = spattern->base.matrix;
963     cairo_matrix_invert (&m);
964     _cairo_quartz_cairo_matrix_to_quartz (&m, &stransform);
965
966     /* The pattern matrix is relative to the bottom left, again; the
967      * incoming cairo pattern matrix is relative to the upper left.
968      * So we take the pattern matrix and the original context matrix,
969      * which gives us the correct base translation/y flip.
970      */
971     ptransform = CGAffineTransformConcat (stransform, dest->cgContextBaseCTM);
972
973 #ifdef QUARTZ_DEBUG
974     ND ((stderr, "  pbounds: %f %f %f %f\n", pbounds.origin.x, pbounds.origin.y, pbounds.size.width, pbounds.size.height));
975     ND ((stderr, "  pattern xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", ptransform.tx, ptransform.ty, ptransform.a, ptransform.b, ptransform.c, ptransform.d));
976     CGAffineTransform xform = CGContextGetCTM (dest->cgContext);
977     ND ((stderr, "  context xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", xform.tx, xform.ty, xform.a, xform.b, xform.c, xform.d));
978 #endif
979
980     *cgpat = CGPatternCreate (info,
981                               pbounds,
982                               ptransform,
983                               rw, rh,
984                               kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */
985                               TRUE,
986                               &cb);
987
988     return CAIRO_STATUS_SUCCESS;
989 }
990
991 /* State used during a drawing operation. */
992 typedef struct {
993     /* The destination of the mask */
994     CGContextRef cgMaskContext;
995
996     /* The destination of the drawing of the source */
997     CGContextRef cgDrawContext;
998
999     /* The filter to be used when drawing the source */
1000     CGInterpolationQuality filter;
1001
1002     /* Action type */
1003     cairo_quartz_action_t action;
1004
1005     /* Destination rect */
1006     CGRect rect;
1007
1008     /* Used with DO_SHADING, DO_IMAGE and DO_TILED_IMAGE */
1009     CGAffineTransform transform;
1010
1011     /* Used with DO_IMAGE and DO_TILED_IMAGE */
1012     CGImageRef image;
1013
1014     /* Used with DO_SHADING */
1015     CGShadingRef shading;
1016
1017     /* Temporary destination for unbounded operations */
1018     CGLayerRef layer;
1019     CGRect clipRect;
1020 } cairo_quartz_drawing_state_t;
1021
1022 /*
1023 Quartz does not support repeating radients. We handle repeating gradients
1024 by manually extending the gradient and repeating color stops. We need to
1025 minimize the number of repetitions since Quartz seems to sample our color
1026 function across the entire range, even if part of that range is not needed
1027 for the visible area of the gradient, and it samples with some fixed resolution,
1028 so if the gradient range is too large it samples with very low resolution and
1029 the gradient is very coarse. _cairo_quartz_create_gradient_function computes
1030 the number of repetitions needed based on the extents.
1031 */
1032 static cairo_int_status_t
1033 _cairo_quartz_setup_gradient_source (cairo_quartz_drawing_state_t *state,
1034                                      const cairo_gradient_pattern_t *gradient,
1035                                      const cairo_rectangle_int_t *extents)
1036 {
1037     cairo_matrix_t mat;
1038     cairo_circle_double_t start, end;
1039     CGFunctionRef gradFunc;
1040     CGColorSpaceRef rgb;
1041     bool extend = gradient->base.extend != CAIRO_EXTEND_NONE;
1042
1043     assert (gradient->n_stops > 0);
1044
1045     mat = gradient->base.matrix;
1046     cairo_matrix_invert (&mat);
1047     _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform);
1048
1049     gradFunc = CairoQuartzCreateGradientFunction (gradient, extents,
1050                                                   &start, &end);
1051
1052     if (unlikely (gradFunc == NULL))
1053         return CAIRO_INT_STATUS_UNSUPPORTED;
1054
1055     rgb = CGColorSpaceCreateDeviceRGB ();
1056
1057     if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1058         state->shading = CGShadingCreateAxial (rgb,
1059                                                CGPointMake (start.center.x,
1060                                                             start.center.y),
1061                                                CGPointMake (end.center.x,
1062                                                             end.center.y),
1063                                                gradFunc,
1064                                                extend, extend);
1065     } else {
1066         state->shading = CGShadingCreateRadial (rgb,
1067                                                 CGPointMake (start.center.x,
1068                                                              start.center.y),
1069                                                 MAX (start.radius, 0),
1070                                                 CGPointMake (end.center.x,
1071                                                              end.center.y),
1072                                                 MAX (end.radius, 0),
1073                                                 gradFunc,
1074                                                 extend, extend);
1075     }
1076
1077     CGColorSpaceRelease (rgb);
1078     CGFunctionRelease (gradFunc);
1079
1080     state->action = DO_SHADING;
1081     return CAIRO_STATUS_SUCCESS;
1082 }
1083
1084 static cairo_int_status_t
1085 _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
1086                            cairo_composite_rectangles_t *extents)
1087 {
1088     cairo_quartz_surface_t       *surface = (cairo_quartz_surface_t *) extents->surface;
1089     cairo_operator_t              op = extents->op;
1090     const cairo_pattern_t        *source = &extents->source_pattern.base;
1091     const cairo_clip_t           *clip = extents->clip;
1092     cairo_bool_t needs_temp;
1093     cairo_status_t status;
1094
1095     state->layer = NULL;
1096     state->image = NULL;
1097     state->shading = NULL;
1098     state->cgDrawContext = NULL;
1099     state->cgMaskContext = NULL;
1100
1101     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
1102     if (unlikely (status))
1103         return status;
1104
1105     status = _cairo_quartz_surface_set_cairo_operator (surface, op);
1106     if (unlikely (status))
1107         return status;
1108
1109     /* Save before we change the pattern, colorspace, etc. so that
1110      * we can restore and make sure that quartz releases our
1111      * pattern (which may be stack allocated)
1112      */
1113
1114     CGContextSaveGState (surface->cgContext);
1115     state->clipRect = CGContextGetClipBoundingBox (surface->cgContext);
1116     state->clipRect = CGRectIntegral (state->clipRect);
1117     state->rect = state->clipRect;
1118
1119     state->cgMaskContext = surface->cgContext;
1120     state->cgDrawContext = state->cgMaskContext;
1121
1122     state->filter = _cairo_quartz_filter_to_quartz (source->filter);
1123
1124     if (op == CAIRO_OPERATOR_CLEAR) {
1125         CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
1126
1127         state->action = DO_DIRECT;
1128         return CAIRO_STATUS_SUCCESS;
1129     }
1130
1131     /*
1132      * To implement mask unbounded operations Quartz needs a temporary
1133      * surface which will be composited entirely (ignoring the mask).
1134      * To implement source unbounded operations Quartz needs a
1135      * temporary surface which allows extending the source to a size
1136      * covering the whole mask, but there are some optimization
1137      * opportunities:
1138      *
1139      * - CLEAR completely ignores the source, thus we can just use a
1140      *   solid color fill.
1141      *
1142      * - SOURCE can be implemented by drawing the source and clearing
1143      *   outside of the source as long as the two regions have no
1144      *   intersection. This happens when the source is a pixel-aligned
1145      *   rectangle. If the source is at least as big as the
1146      *   intersection between the clip rectangle and the mask
1147      *   rectangle, no clear operation is needed.
1148      */
1149     needs_temp = ! _cairo_operator_bounded_by_mask (op);
1150
1151     if (needs_temp) {
1152         state->layer = CGLayerCreateWithContext (surface->cgContext,
1153                                                  state->clipRect.size,
1154                                                  NULL);
1155         state->cgDrawContext = CGLayerGetContext (state->layer);
1156         state->cgMaskContext = state->cgDrawContext;
1157         CGContextTranslateCTM (state->cgDrawContext,
1158                                -state->clipRect.origin.x,
1159                                -state->clipRect.origin.y);
1160     }
1161
1162     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
1163         cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
1164
1165         CGContextSetRGBStrokeColor (state->cgDrawContext,
1166                                     solid->color.red,
1167                                     solid->color.green,
1168                                     solid->color.blue,
1169                                     solid->color.alpha);
1170         CGContextSetRGBFillColor (state->cgDrawContext,
1171                                   solid->color.red,
1172                                   solid->color.green,
1173                                   solid->color.blue,
1174                                   solid->color.alpha);
1175
1176         state->action = DO_DIRECT;
1177         return CAIRO_STATUS_SUCCESS;
1178     }
1179
1180     if (source->type == CAIRO_PATTERN_TYPE_LINEAR ||
1181         source->type == CAIRO_PATTERN_TYPE_RADIAL)
1182     {
1183         const cairo_gradient_pattern_t *gpat = (const cairo_gradient_pattern_t *)source;
1184         cairo_rectangle_int_t extents;
1185
1186         extents = surface->virtual_extents;
1187         extents.x -= surface->base.device_transform.x0;
1188         extents.y -= surface->base.device_transform.y0;
1189         _cairo_rectangle_union (&extents, &surface->extents);
1190
1191         return _cairo_quartz_setup_gradient_source (state, gpat, &extents);
1192     }
1193
1194     if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
1195         (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
1196     {
1197         const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source;
1198         cairo_surface_t *pat_surf = spat->surface;
1199         CGImageRef img;
1200         cairo_matrix_t m = spat->base.matrix;
1201         cairo_rectangle_int_t extents;
1202         CGAffineTransform xform;
1203         CGRect srcRect;
1204         cairo_fixed_t fw, fh;
1205         cairo_bool_t is_bounded;
1206
1207         status = _cairo_surface_to_cgimage (pat_surf, &img);
1208         if (unlikely (status))
1209             return status;
1210
1211         state->image = img;
1212
1213         if (state->filter == kCGInterpolationNone && _cairo_matrix_is_translation (&m)) {
1214             m.x0 = -ceil (m.x0 - 0.5);
1215             m.y0 = -ceil (m.y0 - 0.5);
1216         } else {
1217             cairo_matrix_invert (&m);
1218         }
1219
1220         _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform);
1221
1222         is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
1223         assert (is_bounded);
1224
1225         srcRect = CGRectMake (0, 0, extents.width, extents.height);
1226
1227         if (source->extend == CAIRO_EXTEND_NONE) {
1228             int x, y;
1229             if (op == CAIRO_OPERATOR_SOURCE &&
1230                 (pat_surf->content == CAIRO_CONTENT_ALPHA ||
1231                  ! _cairo_matrix_is_integer_translation (&m, &x, &y)))
1232             {
1233                 state->layer = CGLayerCreateWithContext (surface->cgContext,
1234                                                          state->clipRect.size,
1235                                                          NULL);
1236                 state->cgDrawContext = CGLayerGetContext (state->layer);
1237                 CGContextTranslateCTM (state->cgDrawContext,
1238                                        -state->clipRect.origin.x,
1239                                        -state->clipRect.origin.y);
1240             }
1241
1242             CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
1243
1244             state->rect = srcRect;
1245             state->action = DO_IMAGE;
1246             return CAIRO_STATUS_SUCCESS;
1247         }
1248
1249         CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
1250
1251         /* Quartz seems to tile images at pixel-aligned regions only -- this
1252          * leads to seams if the image doesn't end up scaling to fill the
1253          * space exactly.  The CGPattern tiling approach doesn't have this
1254          * problem.  Check if we're going to fill up the space (within some
1255          * epsilon), and if not, fall back to the CGPattern type.
1256          */
1257
1258         xform = CGAffineTransformConcat (CGContextGetCTM (state->cgDrawContext),
1259                                          state->transform);
1260
1261         srcRect = CGRectApplyAffineTransform (srcRect, xform);
1262
1263         fw = _cairo_fixed_from_double (srcRect.size.width);
1264         fh = _cairo_fixed_from_double (srcRect.size.height);
1265
1266         if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON &&
1267             (fh & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON)
1268         {
1269             /* We're good to use DrawTiledImage, but ensure that
1270              * the math works out */
1271
1272             srcRect.size.width = round (srcRect.size.width);
1273             srcRect.size.height = round (srcRect.size.height);
1274
1275             xform = CGAffineTransformInvert (xform);
1276
1277             srcRect = CGRectApplyAffineTransform (srcRect, xform);
1278
1279             state->rect = srcRect;
1280             state->action = DO_TILED_IMAGE;
1281             return CAIRO_STATUS_SUCCESS;
1282         }
1283
1284         /* Fall through to generic SURFACE case */
1285     }
1286
1287     if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
1288         cairo_quartz_float_t patternAlpha = 1.0f;
1289         CGColorSpaceRef patternSpace;
1290         CGPatternRef pattern = NULL;
1291         cairo_int_status_t status;
1292
1293         status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern);
1294         if (unlikely (status))
1295             return status;
1296
1297         patternSpace = CGColorSpaceCreatePattern (NULL);
1298         CGContextSetFillColorSpace (state->cgDrawContext, patternSpace);
1299         CGContextSetFillPattern (state->cgDrawContext, pattern, &patternAlpha);
1300         CGContextSetStrokeColorSpace (state->cgDrawContext, patternSpace);
1301         CGContextSetStrokePattern (state->cgDrawContext, pattern, &patternAlpha);
1302         CGColorSpaceRelease (patternSpace);
1303
1304         /* Quartz likes to munge the pattern phase (as yet unexplained
1305          * why); force it to 0,0 as we've already baked in the correct
1306          * pattern translation into the pattern matrix
1307          */
1308         CGContextSetPatternPhase (state->cgDrawContext, CGSizeMake (0, 0));
1309
1310         CGPatternRelease (pattern);
1311
1312         state->action = DO_DIRECT;
1313         return CAIRO_STATUS_SUCCESS;
1314     }
1315
1316     return CAIRO_INT_STATUS_UNSUPPORTED;
1317 }
1318
1319 static void
1320 _cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state,
1321                               cairo_composite_rectangles_t *extents)
1322 {
1323     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) extents->surface;
1324
1325     if (state->layer) {
1326         CGContextDrawLayerInRect (surface->cgContext,
1327                                   state->clipRect,
1328                                   state->layer);
1329         CGContextRelease (state->cgDrawContext);
1330         CGLayerRelease (state->layer);
1331     }
1332
1333     if (state->cgMaskContext)
1334         CGContextRestoreGState (surface->cgContext);
1335
1336     if (state->image)
1337         CGImageRelease (state->image);
1338
1339     if (state->shading)
1340         CGShadingRelease (state->shading);
1341 }
1342
1343 static void
1344 _cairo_quartz_draw_source (cairo_quartz_drawing_state_t *state,
1345                            cairo_operator_t              op)
1346 {
1347     CGContextSetShouldAntialias (state->cgDrawContext, state->filter != kCGInterpolationNone);
1348     CGContextSetInterpolationQuality(state->cgDrawContext, state->filter);
1349
1350     if (state->action == DO_DIRECT) {
1351         CGContextFillRect (state->cgDrawContext, state->rect);
1352         return;
1353     }
1354
1355     CGContextConcatCTM (state->cgDrawContext, state->transform);
1356
1357     if (state->action == DO_SHADING) {
1358         CGContextDrawShading (state->cgDrawContext, state->shading);
1359         return;
1360     }
1361
1362     CGContextTranslateCTM (state->cgDrawContext, 0, state->rect.size.height);
1363     CGContextScaleCTM (state->cgDrawContext, 1, -1);
1364
1365     if (state->action == DO_IMAGE) {
1366         CGContextDrawImage (state->cgDrawContext, state->rect, state->image);
1367         if (op == CAIRO_OPERATOR_SOURCE &&
1368             state->cgDrawContext == state->cgMaskContext)
1369         {
1370             CGContextBeginPath (state->cgDrawContext);
1371             CGContextAddRect (state->cgDrawContext, state->rect);
1372
1373             CGContextTranslateCTM (state->cgDrawContext, 0, state->rect.size.height);
1374             CGContextScaleCTM (state->cgDrawContext, 1, -1);
1375             CGContextConcatCTM (state->cgDrawContext,
1376                                 CGAffineTransformInvert (state->transform));
1377
1378             CGContextAddRect (state->cgDrawContext, state->clipRect);
1379
1380             CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 0);
1381             CGContextEOFillPath (state->cgDrawContext);
1382         }
1383     } else {
1384         CGContextDrawTiledImagePtr (state->cgDrawContext, state->rect, state->image);
1385     }
1386 }
1387
1388 /*
1389  * get source/dest image implementation
1390  */
1391
1392 /* Read the image from the surface's front buffer */
1393 static cairo_int_status_t
1394 _cairo_quartz_get_image (cairo_quartz_surface_t *surface,
1395                          cairo_image_surface_t **image_out)
1396 {
1397     unsigned char *imageData;
1398     cairo_image_surface_t *isurf;
1399
1400     if (IS_EMPTY (surface)) {
1401         *image_out = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
1402         return CAIRO_STATUS_SUCCESS;
1403     }
1404
1405     if (surface->imageSurfaceEquiv) {
1406         *image_out = (cairo_image_surface_t*) cairo_surface_reference (surface->imageSurfaceEquiv);
1407         return CAIRO_STATUS_SUCCESS;
1408     }
1409
1410     if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
1411         unsigned int stride;
1412         unsigned int bitinfo;
1413         unsigned int bpc, bpp;
1414         CGColorSpaceRef colorspace;
1415         unsigned int color_comps;
1416
1417         imageData = (unsigned char *) CGBitmapContextGetData (surface->cgContext);
1418
1419         bitinfo = CGBitmapContextGetBitmapInfo (surface->cgContext);
1420         stride = CGBitmapContextGetBytesPerRow (surface->cgContext);
1421         bpp = CGBitmapContextGetBitsPerPixel (surface->cgContext);
1422         bpc = CGBitmapContextGetBitsPerComponent (surface->cgContext);
1423
1424         // let's hope they don't add YUV under us
1425         colorspace = CGBitmapContextGetColorSpace (surface->cgContext);
1426         color_comps = CGColorSpaceGetNumberOfComponents (colorspace);
1427
1428         // XXX TODO: We can handle all of these by converting to
1429         // pixman masks, including non-native-endian masks
1430         if (bpc != 8)
1431             return CAIRO_INT_STATUS_UNSUPPORTED;
1432
1433         if (bpp != 32 && bpp != 8)
1434             return CAIRO_INT_STATUS_UNSUPPORTED;
1435
1436         if (color_comps != 3 && color_comps != 1)
1437             return CAIRO_INT_STATUS_UNSUPPORTED;
1438
1439         if (bpp == 32 && color_comps == 3 &&
1440             (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaPremultipliedFirst &&
1441             (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host)
1442         {
1443             isurf = (cairo_image_surface_t *)
1444                 cairo_image_surface_create_for_data (imageData,
1445                                                      CAIRO_FORMAT_ARGB32,
1446                                                      surface->extents.width,
1447                                                      surface->extents.height,
1448                                                      stride);
1449         } else if (bpp == 32 && color_comps == 3 &&
1450                    (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaNoneSkipFirst &&
1451                    (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host)
1452         {
1453             isurf = (cairo_image_surface_t *)
1454                 cairo_image_surface_create_for_data (imageData,
1455                                                      CAIRO_FORMAT_RGB24,
1456                                                      surface->extents.width,
1457                                                      surface->extents.height,
1458                                                      stride);
1459         } else if (bpp == 8 && color_comps == 1)
1460         {
1461             isurf = (cairo_image_surface_t *)
1462                 cairo_image_surface_create_for_data (imageData,
1463                                                      CAIRO_FORMAT_A8,
1464                                                      surface->extents.width,
1465                                                      surface->extents.height,
1466                                                      stride);
1467         } else {
1468             return CAIRO_INT_STATUS_UNSUPPORTED;
1469         }
1470     } else {
1471         return CAIRO_INT_STATUS_UNSUPPORTED;
1472     }
1473
1474     *image_out = isurf;
1475     return CAIRO_STATUS_SUCCESS;
1476 }
1477
1478 /*
1479  * Cairo surface backend implementations
1480  */
1481
1482 static cairo_status_t
1483 _cairo_quartz_surface_finish (void *abstract_surface)
1484 {
1485     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1486
1487     ND ((stderr, "_cairo_quartz_surface_finish[%p] cgc: %p\n", surface, surface->cgContext));
1488
1489     if (IS_EMPTY (surface))
1490         return CAIRO_STATUS_SUCCESS;
1491
1492     /* Restore our saved gstate that we use to reset clipping */
1493     CGContextRestoreGState (surface->cgContext);
1494     _cairo_surface_clipper_reset (&surface->clipper);
1495
1496     CGContextRelease (surface->cgContext);
1497
1498     surface->cgContext = NULL;
1499
1500     if (surface->imageSurfaceEquiv) {
1501         cairo_surface_destroy (surface->imageSurfaceEquiv);
1502         surface->imageSurfaceEquiv = NULL;
1503     }
1504
1505     free (surface->imageData);
1506     surface->imageData = NULL;
1507
1508     return CAIRO_STATUS_SUCCESS;
1509 }
1510
1511 static cairo_status_t
1512 _cairo_quartz_surface_acquire_source_image (void *abstract_surface,
1513                                              cairo_image_surface_t **image_out,
1514                                              void **image_extra)
1515 {
1516     cairo_int_status_t status;
1517     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1518
1519     //ND ((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface));
1520
1521     status = _cairo_quartz_get_image (surface, image_out);
1522     if (unlikely (status))
1523         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1524
1525     *image_extra = NULL;
1526
1527     return CAIRO_STATUS_SUCCESS;
1528 }
1529
1530 static cairo_surface_t *
1531 _cairo_quartz_surface_snapshot (void *abstract_surface)
1532 {
1533     cairo_int_status_t status;
1534     cairo_quartz_surface_t *surface = abstract_surface;
1535     cairo_image_surface_t *image;
1536
1537     if (surface->imageSurfaceEquiv)
1538         return NULL;
1539
1540     status = _cairo_quartz_get_image (surface, &image);
1541     if (unlikely (status))
1542         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
1543
1544     return &image->base;
1545 }
1546
1547 static void
1548 _cairo_quartz_surface_release_source_image (void *abstract_surface,
1549                                             cairo_image_surface_t *image,
1550                                             void *image_extra)
1551 {
1552     cairo_surface_destroy (&image->base);
1553 }
1554
1555
1556 static cairo_surface_t *
1557 _cairo_quartz_surface_map_to_image (void *abstract_surface,
1558                                     const cairo_rectangle_int_t *extents)
1559 {
1560     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1561     cairo_image_surface_t *image;
1562     cairo_surface_t *subsurface;
1563     cairo_status_t status;
1564
1565     status = _cairo_quartz_get_image (surface, &image);
1566     if (unlikely (status))
1567         return _cairo_surface_create_in_error (status);
1568
1569     /* Is this legitimate? shouldn't it return an image surface? */
1570
1571     subsurface = _cairo_surface_create_for_rectangle_int (&image->base, extents);
1572     cairo_surface_destroy (&image->base);
1573
1574     return subsurface;
1575 }
1576
1577 static cairo_int_status_t
1578 _cairo_quartz_surface_unmap_image (void *abstract_surface,
1579                                    cairo_image_surface_t *image)
1580 {
1581     cairo_surface_destroy (&image->base);
1582
1583     return CAIRO_STATUS_SUCCESS;
1584 }
1585
1586 static cairo_surface_t *
1587 _cairo_quartz_surface_create_similar (void *abstract_surface,
1588                                       cairo_content_t content,
1589                                       int width,
1590                                       int height)
1591 {
1592     cairo_quartz_surface_t *surface, *similar_quartz;
1593     cairo_surface_t *similar;
1594     cairo_format_t format;
1595
1596     if (content == CAIRO_CONTENT_COLOR_ALPHA)
1597         format = CAIRO_FORMAT_ARGB32;
1598     else if (content == CAIRO_CONTENT_COLOR)
1599         format = CAIRO_FORMAT_RGB24;
1600     else if (content == CAIRO_CONTENT_ALPHA)
1601         format = CAIRO_FORMAT_A8;
1602     else
1603         return NULL;
1604
1605     // verify width and height of surface
1606     if (!_cairo_quartz_verify_surface_size (width, height)) {
1607         return _cairo_surface_create_in_error (_cairo_error
1608                                                (CAIRO_STATUS_INVALID_SIZE));
1609     }
1610
1611     similar = cairo_quartz_surface_create (format, width, height);
1612     if (unlikely (similar->status))
1613         return similar;
1614
1615     surface = (cairo_quartz_surface_t *) abstract_surface;
1616     similar_quartz = (cairo_quartz_surface_t *) similar;
1617     similar_quartz->virtual_extents = surface->virtual_extents;
1618
1619     return similar;
1620 }
1621
1622 static cairo_bool_t
1623 _cairo_quartz_surface_get_extents (void *abstract_surface,
1624                                    cairo_rectangle_int_t *extents)
1625 {
1626     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
1627
1628     *extents = surface->extents;
1629     return TRUE;
1630 }
1631
1632 static cairo_int_status_t
1633 _cairo_quartz_cg_paint (const cairo_compositor_t *compositor,
1634                         cairo_composite_rectangles_t *extents)
1635 {
1636     cairo_quartz_drawing_state_t state;
1637     cairo_int_status_t rv;
1638
1639     ND ((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n",
1640          extents->surface, extents->op, extents->source_pattern.base.type));
1641
1642     rv = _cairo_quartz_setup_state (&state, extents);
1643     if (unlikely (rv))
1644         goto BAIL;
1645
1646     _cairo_quartz_draw_source (&state, extents->op);
1647
1648 BAIL:
1649     _cairo_quartz_teardown_state (&state, extents);
1650
1651     ND ((stderr, "-- paint\n"));
1652     return rv;
1653 }
1654
1655 static cairo_int_status_t
1656 _cairo_quartz_cg_mask_with_surface (cairo_composite_rectangles_t *extents,
1657                                     cairo_surface_t              *mask_surf,
1658                                     const cairo_matrix_t         *mask_mat,
1659                                     CGInterpolationQuality        filter)
1660 {
1661     CGRect rect;
1662     CGImageRef img;
1663     cairo_status_t status;
1664     CGAffineTransform mask_matrix;
1665     cairo_quartz_drawing_state_t state;
1666
1667     status = _cairo_surface_to_cgimage (mask_surf, &img);
1668     if (unlikely (status))
1669         return status;
1670
1671     status = _cairo_quartz_setup_state (&state, extents);
1672     if (unlikely (status))
1673         goto BAIL;
1674
1675     rect = CGRectMake (0.0, 0.0, CGImageGetWidth (img), CGImageGetHeight (img));
1676     _cairo_quartz_cairo_matrix_to_quartz (mask_mat, &mask_matrix);
1677
1678     /* ClipToMask is essentially drawing an image, so we need to flip the CTM
1679      * to get the image to appear oriented the right way */
1680     CGContextConcatCTM (state.cgMaskContext, CGAffineTransformInvert (mask_matrix));
1681     CGContextTranslateCTM (state.cgMaskContext, 0.0, rect.size.height);
1682     CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
1683
1684     state.filter = filter;
1685
1686     CGContextSetInterpolationQuality (state.cgMaskContext, filter);
1687     CGContextSetShouldAntialias (state.cgMaskContext, filter != kCGInterpolationNone);
1688
1689     CGContextClipToMask (state.cgMaskContext, rect, img);
1690
1691     CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
1692     CGContextTranslateCTM (state.cgMaskContext, 0.0, -rect.size.height);
1693     CGContextConcatCTM (state.cgMaskContext, mask_matrix);
1694
1695     _cairo_quartz_draw_source (&state, extents->op);
1696
1697 BAIL:
1698     _cairo_quartz_teardown_state (&state, extents);
1699
1700     CGImageRelease (img);
1701
1702     return status;
1703 }
1704
1705 static cairo_int_status_t
1706 _cairo_quartz_cg_mask_with_solid (cairo_quartz_surface_t *surface,
1707                                   cairo_composite_rectangles_t *extents)
1708 {
1709     cairo_quartz_drawing_state_t state;
1710     double alpha = extents->mask_pattern.solid.color.alpha;
1711     cairo_status_t status;
1712
1713     status = _cairo_quartz_setup_state (&state, extents);
1714     if (unlikely (status))
1715         return status;
1716
1717     CGContextSetAlpha (surface->cgContext, alpha);
1718     _cairo_quartz_draw_source (&state, extents->op);
1719
1720     _cairo_quartz_teardown_state (&state, extents);
1721
1722     return CAIRO_STATUS_SUCCESS;
1723 }
1724
1725 static cairo_int_status_t
1726 _cairo_quartz_cg_mask (const cairo_compositor_t *compositor,
1727                        cairo_composite_rectangles_t *extents)
1728 {
1729     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)extents->surface;
1730     const cairo_pattern_t *source = &extents->source_pattern.base;
1731     const cairo_pattern_t *mask = &extents->mask_pattern.base;
1732     cairo_surface_t *mask_surf;
1733     cairo_matrix_t matrix;
1734     cairo_status_t status;
1735     cairo_bool_t need_temp;
1736     CGInterpolationQuality filter;
1737
1738     ND ((stderr, "%p _cairo_quartz_surface_mask op %d source->type %d mask->type %d\n",
1739          extents->surface, extents->op, extents->source_pattern.base.type,
1740          extents->mask_pattern.base.type));
1741
1742     if (mask->type == CAIRO_PATTERN_TYPE_SOLID)
1743         return _cairo_quartz_cg_mask_with_solid (surface, extents);
1744
1745     need_temp = (mask->type   != CAIRO_PATTERN_TYPE_SURFACE ||
1746                  mask->extend != CAIRO_EXTEND_NONE);
1747
1748     filter = _cairo_quartz_filter_to_quartz (source->filter);
1749
1750     if (! need_temp) {
1751         mask_surf = extents->mask_pattern.surface.surface;
1752
1753         /* When an opaque surface used as a mask in Quartz, its
1754          * luminosity is used as the alpha value, so we con only use
1755          * surfaces with alpha without creating a temporary mask. */
1756         need_temp = ! (mask_surf->content & CAIRO_CONTENT_ALPHA);
1757     }
1758
1759     if (! need_temp) {
1760         CGInterpolationQuality mask_filter;
1761         cairo_bool_t simple_transform;
1762
1763         matrix = mask->matrix;
1764
1765         mask_filter = _cairo_quartz_filter_to_quartz (mask->filter);
1766         if (mask_filter == kCGInterpolationNone) {
1767             simple_transform = _cairo_matrix_is_translation (&matrix);
1768             if (simple_transform) {
1769                 matrix.x0 = ceil (matrix.x0 - 0.5);
1770                 matrix.y0 = ceil (matrix.y0 - 0.5);
1771             }
1772         } else {
1773             simple_transform = _cairo_matrix_is_integer_translation (&matrix,
1774                                                                      NULL,
1775                                                                      NULL);
1776         }
1777
1778         /* Quartz only allows one interpolation to be set for mask and
1779          * source, so we can skip the temp surface only if the source
1780          * filtering makes the mask look correct. */
1781         if (source->type == CAIRO_PATTERN_TYPE_SURFACE)
1782             need_temp = ! (simple_transform || filter == mask_filter);
1783         else
1784             filter = mask_filter;
1785     }
1786
1787     if (need_temp) {
1788         /* Render the mask to a surface */
1789         mask_surf = _cairo_quartz_surface_create_similar (surface,
1790                                                           CAIRO_CONTENT_ALPHA,
1791                                                           surface->extents.width,
1792                                                           surface->extents.height);
1793         status = mask_surf->status;
1794         if (unlikely (status))
1795             goto BAIL;
1796
1797         /* mask_surf is clear, so use OVER instead of SOURCE to avoid a
1798          * temporary layer or fallback to cairo-image. */
1799         status = _cairo_surface_paint (mask_surf, CAIRO_OPERATOR_OVER, mask, NULL);
1800         if (unlikely (status))
1801             goto BAIL;
1802
1803         cairo_matrix_init_identity (&matrix);
1804     }
1805
1806     status = _cairo_quartz_cg_mask_with_surface (extents,
1807                                                  mask_surf, &matrix, filter);
1808
1809 BAIL:
1810
1811     if (need_temp)
1812         cairo_surface_destroy (mask_surf);
1813
1814     return status;
1815 }
1816
1817 static cairo_int_status_t
1818 _cairo_quartz_cg_fill (const cairo_compositor_t *compositor,
1819                        cairo_composite_rectangles_t *extents,
1820                        const cairo_path_fixed_t *path,
1821                        cairo_fill_rule_t fill_rule,
1822                        double tolerance,
1823                        cairo_antialias_t antialias)
1824 {
1825     cairo_quartz_drawing_state_t state;
1826     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
1827
1828     ND ((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n",
1829          extents->surface, extents->op, extents->source_pattern.base.type));
1830
1831     rv = _cairo_quartz_setup_state (&state, extents);
1832     if (unlikely (rv))
1833         goto BAIL;
1834
1835     CGContextSetShouldAntialias (state.cgMaskContext, (antialias != CAIRO_ANTIALIAS_NONE));
1836
1837     _cairo_quartz_cairo_path_to_quartz_context (path, state.cgMaskContext);
1838
1839     if (state.action == DO_DIRECT) {
1840         assert (state.cgDrawContext == state.cgMaskContext);
1841         if (fill_rule == CAIRO_FILL_RULE_WINDING)
1842             CGContextFillPath (state.cgMaskContext);
1843         else
1844             CGContextEOFillPath (state.cgMaskContext);
1845     } else {
1846         if (fill_rule == CAIRO_FILL_RULE_WINDING)
1847             CGContextClip (state.cgMaskContext);
1848         else
1849             CGContextEOClip (state.cgMaskContext);
1850
1851         _cairo_quartz_draw_source (&state, extents->op);
1852     }
1853
1854 BAIL:
1855     _cairo_quartz_teardown_state (&state, extents);
1856
1857     ND ((stderr, "-- fill\n"));
1858     return rv;
1859 }
1860
1861 static cairo_int_status_t
1862 _cairo_quartz_cg_stroke (const cairo_compositor_t *compositor,
1863                          cairo_composite_rectangles_t *extents,
1864                          const cairo_path_fixed_t *path,
1865                          const cairo_stroke_style_t *style,
1866                          const cairo_matrix_t *ctm,
1867                          const cairo_matrix_t *ctm_inverse,
1868                          double tolerance,
1869                          cairo_antialias_t antialias)
1870 {
1871     cairo_quartz_drawing_state_t state;
1872     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
1873     CGAffineTransform strokeTransform, invStrokeTransform;
1874
1875     ND ((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n",
1876          extents->surface, extents->op, extents->source_pattern.base.type));
1877
1878     rv = _cairo_quartz_setup_state (&state, extents);
1879     if (unlikely (rv))
1880         goto BAIL;
1881
1882     // Turning antialiasing off used to cause misrendering with
1883     // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels).
1884     // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases.
1885     CGContextSetShouldAntialias (state.cgMaskContext, (antialias != CAIRO_ANTIALIAS_NONE));
1886     CGContextSetLineWidth (state.cgMaskContext, style->line_width);
1887     CGContextSetLineCap (state.cgMaskContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
1888     CGContextSetLineJoin (state.cgMaskContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
1889     CGContextSetMiterLimit (state.cgMaskContext, style->miter_limit);
1890
1891     if (style->dash && style->num_dashes) {
1892         cairo_quartz_float_t sdash[CAIRO_STACK_ARRAY_LENGTH (cairo_quartz_float_t)];
1893         cairo_quartz_float_t *fdash = sdash;
1894         unsigned int max_dashes = style->num_dashes;
1895         unsigned int k;
1896
1897         if (style->num_dashes%2)
1898             max_dashes *= 2;
1899         if (max_dashes > ARRAY_LENGTH (sdash))
1900             fdash = _cairo_malloc_ab (max_dashes, sizeof (cairo_quartz_float_t));
1901         if (unlikely (fdash == NULL)) {
1902             rv = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1903             goto BAIL;
1904         }
1905
1906         for (k = 0; k < max_dashes; k++)
1907             fdash[k] = (cairo_quartz_float_t) style->dash[k % style->num_dashes];
1908
1909         CGContextSetLineDash (state.cgMaskContext, style->dash_offset, fdash, max_dashes);
1910         if (fdash != sdash)
1911             free (fdash);
1912     } else
1913         CGContextSetLineDash (state.cgMaskContext, 0, NULL, 0);
1914
1915     _cairo_quartz_cairo_path_to_quartz_context (path, state.cgMaskContext);
1916
1917     _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform);
1918     CGContextConcatCTM (state.cgMaskContext, strokeTransform);
1919
1920     if (state.action == DO_DIRECT) {
1921         assert (state.cgDrawContext == state.cgMaskContext);
1922         CGContextStrokePath (state.cgMaskContext);
1923     } else {
1924         CGContextReplacePathWithStrokedPath (state.cgMaskContext);
1925         CGContextClip (state.cgMaskContext);
1926
1927         _cairo_quartz_cairo_matrix_to_quartz (ctm_inverse, &invStrokeTransform);
1928         CGContextConcatCTM (state.cgMaskContext, invStrokeTransform);
1929
1930         _cairo_quartz_draw_source (&state, extents->op);
1931     }
1932
1933 BAIL:
1934     _cairo_quartz_teardown_state (&state, extents);
1935
1936     ND ((stderr, "-- stroke\n"));
1937     return rv;
1938 }
1939
1940 #if CAIRO_HAS_QUARTZ_FONT
1941 static cairo_int_status_t
1942 _cairo_quartz_cg_glyphs (const cairo_compositor_t *compositor,
1943                          cairo_composite_rectangles_t *extents,
1944                          cairo_scaled_font_t *scaled_font,
1945                          cairo_glyph_t *glyphs,
1946                          int num_glyphs,
1947                          cairo_bool_t overlap)
1948 {
1949     CGAffineTransform textTransform, invTextTransform;
1950     CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
1951     CGSize cg_advances_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
1952     CGGlyph *cg_glyphs = &glyphs_static[0];
1953     CGSize *cg_advances = &cg_advances_static[0];
1954     COMPILE_TIME_ASSERT (sizeof (CGGlyph) <= sizeof (CGSize));
1955
1956     cairo_quartz_drawing_state_t state;
1957     cairo_int_status_t rv = CAIRO_INT_STATUS_UNSUPPORTED;
1958     cairo_quartz_float_t xprev, yprev;
1959     int i;
1960     CGFontRef cgfref = NULL;
1961
1962     cairo_bool_t didForceFontSmoothing = FALSE;
1963
1964     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ)
1965         return CAIRO_INT_STATUS_UNSUPPORTED;
1966
1967     rv = _cairo_quartz_setup_state (&state, extents);
1968     if (unlikely (rv))
1969         goto BAIL;
1970
1971     if (state.action == DO_DIRECT) {
1972         assert (state.cgDrawContext == state.cgMaskContext);
1973         CGContextSetTextDrawingMode (state.cgMaskContext, kCGTextFill);
1974     } else {
1975         CGContextSetTextDrawingMode (state.cgMaskContext, kCGTextClip);
1976     }
1977
1978     /* this doesn't addref */
1979     cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font);
1980     CGContextSetFont (state.cgMaskContext, cgfref);
1981     CGContextSetFontSize (state.cgMaskContext, 1.0);
1982
1983     switch (scaled_font->options.antialias) {
1984         case CAIRO_ANTIALIAS_SUBPIXEL:
1985         case CAIRO_ANTIALIAS_BEST:
1986             CGContextSetShouldAntialias (state.cgMaskContext, TRUE);
1987             CGContextSetShouldSmoothFonts (state.cgMaskContext, TRUE);
1988             if (CGContextSetAllowsFontSmoothingPtr &&
1989                 !CGContextGetAllowsFontSmoothingPtr (state.cgMaskContext))
1990             {
1991                 didForceFontSmoothing = TRUE;
1992                 CGContextSetAllowsFontSmoothingPtr (state.cgMaskContext, TRUE);
1993             }
1994             break;
1995         case CAIRO_ANTIALIAS_NONE:
1996             CGContextSetShouldAntialias (state.cgMaskContext, FALSE);
1997             break;
1998         case CAIRO_ANTIALIAS_GRAY:
1999         case CAIRO_ANTIALIAS_GOOD:
2000         case CAIRO_ANTIALIAS_FAST:
2001             CGContextSetShouldAntialias (state.cgMaskContext, TRUE);
2002             CGContextSetShouldSmoothFonts (state.cgMaskContext, FALSE);
2003             break;
2004         case CAIRO_ANTIALIAS_DEFAULT:
2005             /* Don't do anything */
2006             break;
2007     }
2008
2009     if (num_glyphs > ARRAY_LENGTH (glyphs_static)) {
2010         cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof (CGGlyph) + sizeof (CGSize));
2011         if (unlikely (cg_glyphs == NULL)) {
2012             rv = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2013             goto BAIL;
2014         }
2015
2016         cg_advances = (CGSize*) (cg_glyphs + num_glyphs);
2017     }
2018
2019     /* scale(1,-1) * scaled_font->scale */
2020     textTransform = CGAffineTransformMake (scaled_font->scale.xx,
2021                                            scaled_font->scale.yx,
2022                                            -scaled_font->scale.xy,
2023                                            -scaled_font->scale.yy,
2024                                            0.0, 0.0);
2025
2026     /* scaled_font->scale_inverse * scale(1,-1) */
2027     invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx,
2028                                               -scaled_font->scale_inverse.yx,
2029                                               scaled_font->scale_inverse.xy,
2030                                               -scaled_font->scale_inverse.yy,
2031                                               0.0, 0.0);
2032
2033     CGContextSetTextPosition (state.cgMaskContext, 0.0, 0.0);
2034     CGContextSetTextMatrix (state.cgMaskContext, CGAffineTransformIdentity);
2035
2036     /* Convert our glyph positions to glyph advances.  We need n-1 advances,
2037      * since the advance at index 0 is applied after glyph 0. */
2038     xprev = glyphs[0].x;
2039     yprev = glyphs[0].y;
2040
2041     cg_glyphs[0] = glyphs[0].index;
2042
2043     for (i = 1; i < num_glyphs; i++) {
2044         cairo_quartz_float_t xf = glyphs[i].x;
2045         cairo_quartz_float_t yf = glyphs[i].y;
2046         cg_glyphs[i] = glyphs[i].index;
2047         cg_advances[i - 1] = CGSizeApplyAffineTransform (CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
2048         xprev = xf;
2049         yprev = yf;
2050     }
2051
2052     /* Translate to the first glyph's position before drawing */
2053     CGContextTranslateCTM (state.cgMaskContext, glyphs[0].x, glyphs[0].y);
2054     CGContextConcatCTM (state.cgMaskContext, textTransform);
2055
2056     CGContextShowGlyphsWithAdvances (state.cgMaskContext,
2057                                      cg_glyphs,
2058                                      cg_advances,
2059                                      num_glyphs);
2060
2061     CGContextConcatCTM (state.cgMaskContext, invTextTransform);
2062     CGContextTranslateCTM (state.cgMaskContext, -glyphs[0].x, -glyphs[0].y);
2063
2064     if (state.action != DO_DIRECT)
2065         _cairo_quartz_draw_source (&state, extents->op);
2066
2067 BAIL:
2068     if (didForceFontSmoothing)
2069         CGContextSetAllowsFontSmoothingPtr (state.cgMaskContext, FALSE);
2070
2071     _cairo_quartz_teardown_state (&state, extents);
2072
2073     if (cg_glyphs != glyphs_static)
2074         free (cg_glyphs);
2075
2076     return rv;
2077 }
2078 #endif /* CAIRO_HAS_QUARTZ_FONT */
2079
2080 static const cairo_compositor_t _cairo_quartz_cg_compositor = {
2081     &_cairo_fallback_compositor,
2082
2083     _cairo_quartz_cg_paint,
2084     _cairo_quartz_cg_mask,
2085     _cairo_quartz_cg_stroke,
2086     _cairo_quartz_cg_fill,
2087 #if CAIRO_HAS_QUARTZ_FONT
2088     _cairo_quartz_cg_glyphs,
2089 #else
2090     NULL,
2091 #endif
2092 };
2093
2094 static cairo_int_status_t
2095 _cairo_quartz_surface_paint (void *surface,
2096                              cairo_operator_t op,
2097                              const cairo_pattern_t *source,
2098                              const cairo_clip_t *clip)
2099 {
2100     return _cairo_compositor_paint (&_cairo_quartz_cg_compositor,
2101                                     surface, op, source, clip);
2102 }
2103
2104 static cairo_int_status_t
2105 _cairo_quartz_surface_mask (void *surface,
2106                             cairo_operator_t op,
2107                             const cairo_pattern_t *source,
2108                             const cairo_pattern_t *mask,
2109                             const cairo_clip_t *clip)
2110 {
2111     return _cairo_compositor_mask (&_cairo_quartz_cg_compositor,
2112                                    surface, op, source, mask,
2113                                    clip);
2114 }
2115
2116 static cairo_int_status_t
2117 _cairo_quartz_surface_fill (void *surface,
2118                             cairo_operator_t op,
2119                             const cairo_pattern_t *source,
2120                             const cairo_path_fixed_t *path,
2121                             cairo_fill_rule_t fill_rule,
2122                             double tolerance,
2123                             cairo_antialias_t antialias,
2124                             const cairo_clip_t *clip)
2125 {
2126     return _cairo_compositor_fill (&_cairo_quartz_cg_compositor,
2127                                    surface, op, source, path,
2128                                    fill_rule, tolerance, antialias,
2129                                    clip);
2130 }
2131
2132 static cairo_int_status_t
2133 _cairo_quartz_surface_stroke (void *surface,
2134                               cairo_operator_t op,
2135                               const cairo_pattern_t *source,
2136                               const cairo_path_fixed_t *path,
2137                               const cairo_stroke_style_t *style,
2138                               const cairo_matrix_t *ctm,
2139                               const cairo_matrix_t *ctm_inverse,
2140                               double tolerance,
2141                               cairo_antialias_t antialias,
2142                               const cairo_clip_t *clip)
2143 {
2144     return _cairo_compositor_stroke (&_cairo_quartz_cg_compositor,
2145                                      surface, op, source, path,
2146                                      style, ctm,ctm_inverse,
2147                                      tolerance, antialias, clip);
2148 }
2149
2150 static cairo_int_status_t
2151 _cairo_quartz_surface_glyphs (void *surface,
2152                               cairo_operator_t op,
2153                               const cairo_pattern_t *source,
2154                               cairo_glyph_t *glyphs,
2155                               int num_glyphs,
2156                               cairo_scaled_font_t *scaled_font,
2157                               const cairo_clip_t *clip)
2158 {
2159     return _cairo_compositor_glyphs (&_cairo_quartz_cg_compositor,
2160                                      surface, op, source,
2161                                      glyphs, num_glyphs, scaled_font,
2162                                      clip);
2163 }
2164
2165 static cairo_status_t
2166 _cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
2167                                                    cairo_path_fixed_t *path,
2168                                                    cairo_fill_rule_t fill_rule,
2169                                                    double tolerance,
2170                                                    cairo_antialias_t antialias)
2171 {
2172     cairo_quartz_surface_t *surface =
2173         cairo_container_of (clipper, cairo_quartz_surface_t, clipper);
2174
2175     ND ((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path));
2176
2177     if (IS_EMPTY (surface))
2178         return CAIRO_STATUS_SUCCESS;
2179
2180     if (path == NULL) {
2181         /* If we're being asked to reset the clip, we can only do it
2182          * by restoring the gstate to our previous saved one, and
2183          * saving it again.
2184          *
2185          * Note that this assumes that ALL quartz surface creation
2186          * functions will do a SaveGState first; we do this in create_internal.
2187          */
2188         CGContextRestoreGState (surface->cgContext);
2189         CGContextSaveGState (surface->cgContext);
2190     } else {
2191         CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
2192
2193         _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext);
2194
2195         if (fill_rule == CAIRO_FILL_RULE_WINDING)
2196             CGContextClip (surface->cgContext);
2197         else
2198             CGContextEOClip (surface->cgContext);
2199     }
2200
2201     ND ((stderr, "-- intersect_clip_path\n"));
2202
2203     return CAIRO_STATUS_SUCCESS;
2204 }
2205
2206 // XXXtodo implement show_page; need to figure out how to handle begin/end
2207
2208 static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
2209     CAIRO_SURFACE_TYPE_QUARTZ,
2210     _cairo_quartz_surface_finish,
2211
2212     _cairo_default_context_create,
2213
2214     _cairo_quartz_surface_create_similar,
2215     NULL, /* similar image */
2216     _cairo_quartz_surface_map_to_image,
2217     _cairo_quartz_surface_unmap_image,
2218
2219     _cairo_surface_default_source,
2220     _cairo_quartz_surface_acquire_source_image,
2221     _cairo_quartz_surface_release_source_image,
2222     _cairo_quartz_surface_snapshot,
2223
2224     NULL, /* copy_page */
2225     NULL, /* show_page */
2226
2227     _cairo_quartz_surface_get_extents,
2228     NULL, /* get_font_options */
2229
2230     NULL, /* flush */
2231     NULL, /* mark_dirty_rectangle */
2232
2233     _cairo_quartz_surface_paint,
2234     _cairo_quartz_surface_mask,
2235     _cairo_quartz_surface_stroke,
2236     _cairo_quartz_surface_fill,
2237     NULL,  /* fill-stroke */
2238     _cairo_quartz_surface_glyphs,
2239 };
2240
2241 cairo_quartz_surface_t *
2242 _cairo_quartz_surface_create_internal (CGContextRef cgContext,
2243                                        cairo_content_t content,
2244                                        unsigned int width,
2245                                        unsigned int height)
2246 {
2247     cairo_quartz_surface_t *surface;
2248
2249     quartz_ensure_symbols ();
2250
2251     /* Init the base surface */
2252     surface = malloc (sizeof (cairo_quartz_surface_t));
2253     if (unlikely (surface == NULL))
2254         return (cairo_quartz_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2255
2256     memset (surface, 0, sizeof (cairo_quartz_surface_t));
2257
2258     _cairo_surface_init (&surface->base,
2259                          &cairo_quartz_surface_backend,
2260                          NULL, /* device */
2261                          content);
2262
2263     _cairo_surface_clipper_init (&surface->clipper,
2264                                  _cairo_quartz_surface_clipper_intersect_clip_path);
2265
2266     /* Save our extents */
2267     surface->extents.x = surface->extents.y = 0;
2268     surface->extents.width = width;
2269     surface->extents.height = height;
2270     surface->virtual_extents = surface->extents;
2271
2272     if (IS_EMPTY (surface)) {
2273         surface->cgContext = NULL;
2274         surface->cgContextBaseCTM = CGAffineTransformIdentity;
2275         surface->imageData = NULL;
2276         return surface;
2277     }
2278
2279     /* Save so we can always get back to a known-good CGContext -- this is
2280      * required for proper behaviour of intersect_clip_path(NULL)
2281      */
2282     CGContextSaveGState (cgContext);
2283
2284     surface->cgContext = cgContext;
2285     surface->cgContextBaseCTM = CGContextGetCTM (cgContext);
2286
2287     surface->imageData = NULL;
2288     surface->imageSurfaceEquiv = NULL;
2289
2290     return surface;
2291 }
2292
2293 /**
2294  * cairo_quartz_surface_create_for_cg_context:
2295  * @cgContext: the existing CGContext for which to create the surface
2296  * @width: width of the surface, in pixels
2297  * @height: height of the surface, in pixels
2298  *
2299  * Creates a Quartz surface that wraps the given CGContext.  The
2300  * CGContext is assumed to be in the standard Cairo coordinate space
2301  * (that is, with the origin at the upper left and the Y axis
2302  * increasing downward).  If the CGContext is in the Quartz coordinate
2303  * space (with the origin at the bottom left), then it should be
2304  * flipped before this function is called.  The flip can be accomplished
2305  * using a translate and a scale; for example:
2306  *
2307  * <informalexample><programlisting>
2308  * CGContextTranslateCTM (cgContext, 0.0, height);
2309  * CGContextScaleCTM (cgContext, 1.0, -1.0);
2310  * </programlisting></informalexample>
2311  *
2312  * All Cairo operations are implemented in terms of Quartz operations,
2313  * as long as Quartz-compatible elements are used (such as Quartz fonts).
2314  *
2315  * Return value: the newly created Cairo surface.
2316  *
2317  * Since: 1.6
2318  **/
2319
2320 cairo_surface_t *
2321 cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
2322                                             unsigned int width,
2323                                             unsigned int height)
2324 {
2325     cairo_quartz_surface_t *surf;
2326
2327     surf = _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA,
2328                                                   width, height);
2329     if (likely (!surf->base.status))
2330         CGContextRetain (cgContext);
2331
2332     return &surf->base;
2333 }
2334
2335 /**
2336  * cairo_quartz_surface_create:
2337  * @format: format of pixels in the surface to create
2338  * @width: width of the surface, in pixels
2339  * @height: height of the surface, in pixels
2340  *
2341  * Creates a Quartz surface backed by a CGBitmap.  The surface is
2342  * created using the Device RGB (or Device Gray, for A8) color space.
2343  * All Cairo operations, including those that require software
2344  * rendering, will succeed on this surface.
2345  *
2346  * Return value: the newly created surface.
2347  *
2348  * Since: 1.6
2349  **/
2350 cairo_surface_t *
2351 cairo_quartz_surface_create (cairo_format_t format,
2352                              unsigned int width,
2353                              unsigned int height)
2354 {
2355     cairo_quartz_surface_t *surf;
2356     CGContextRef cgc;
2357     CGColorSpaceRef cgColorspace;
2358     CGBitmapInfo bitinfo;
2359     void *imageData;
2360     int stride;
2361     int bitsPerComponent;
2362
2363     if (!_cairo_quartz_verify_surface_size (width, height))
2364         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
2365
2366     if (width == 0 || height == 0) {
2367         return &_cairo_quartz_surface_create_internal (NULL, _cairo_content_from_format (format),
2368                                                        width, height)->base;
2369     }
2370
2371     if (format == CAIRO_FORMAT_ARGB32 ||
2372         format == CAIRO_FORMAT_RGB24)
2373     {
2374         cgColorspace = CGColorSpaceCreateDeviceRGB ();
2375         bitinfo = kCGBitmapByteOrder32Host;
2376         if (format == CAIRO_FORMAT_ARGB32)
2377             bitinfo |= kCGImageAlphaPremultipliedFirst;
2378         else
2379             bitinfo |= kCGImageAlphaNoneSkipFirst;
2380         bitsPerComponent = 8;
2381         stride = width * 4;
2382     } else if (format == CAIRO_FORMAT_A8) {
2383         cgColorspace = NULL;
2384         stride = width;
2385         bitinfo = kCGImageAlphaOnly;
2386         bitsPerComponent = 8;
2387     } else if (format == CAIRO_FORMAT_A1) {
2388         /* I don't think we can usefully support this, as defined by
2389          * cairo_format_t -- these are 1-bit pixels stored in 32-bit
2390          * quantities.
2391          */
2392         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
2393     } else {
2394         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
2395     }
2396
2397     /* The Apple docs say that for best performance, the stride and the data
2398      * pointer should be 16-byte aligned.  malloc already aligns to 16-bytes,
2399      * so we don't have to anything special on allocation.
2400      */
2401     stride = (stride + 15) & ~15;
2402
2403     imageData = _cairo_malloc_ab (height, stride);
2404     if (unlikely (!imageData)) {
2405         CGColorSpaceRelease (cgColorspace);
2406         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2407     }
2408
2409     /* zero the memory to match the image surface behaviour */
2410     memset (imageData, 0, height * stride);
2411
2412     cgc = CGBitmapContextCreate (imageData,
2413                                  width,
2414                                  height,
2415                                  bitsPerComponent,
2416                                  stride,
2417                                  cgColorspace,
2418                                  bitinfo);
2419     CGColorSpaceRelease (cgColorspace);
2420
2421     if (!cgc) {
2422         free (imageData);
2423         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2424     }
2425
2426     /* flip the Y axis */
2427     CGContextTranslateCTM (cgc, 0.0, height);
2428     CGContextScaleCTM (cgc, 1.0, -1.0);
2429
2430     surf = _cairo_quartz_surface_create_internal (cgc, _cairo_content_from_format (format),
2431                                                   width, height);
2432     if (surf->base.status) {
2433         CGContextRelease (cgc);
2434         free (imageData);
2435         // create_internal will have set an error
2436         return &surf->base;
2437     }
2438
2439     surf->imageData = imageData;
2440     surf->imageSurfaceEquiv = cairo_image_surface_create_for_data (imageData, format, width, height, stride);
2441
2442     return &surf->base;
2443 }
2444
2445 /**
2446  * cairo_quartz_surface_get_cg_context:
2447  * @surface: the Cairo Quartz surface
2448  *
2449  * Returns the CGContextRef that the given Quartz surface is backed
2450  * by.
2451  *
2452  * A call to cairo_surface_flush() is required before using the
2453  * CGContextRef to ensure that all pending drawing operations are
2454  * finished and to restore any temporary modification cairo has made
2455  * to its state. A call to cairo_surface_mark_dirty() is required
2456  * after the state or the content of the CGContextRef has been
2457  * modified.
2458  *
2459  * Return value: the CGContextRef for the given surface.
2460  *
2461  * Since: 1.6
2462  **/
2463 CGContextRef
2464 cairo_quartz_surface_get_cg_context (cairo_surface_t *surface)
2465 {
2466     if (surface && _cairo_surface_is_quartz (surface)) {
2467         cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface;
2468         return quartz->cgContext;
2469     } else
2470         return NULL;
2471 }
2472
2473 static cairo_bool_t
2474 _cairo_surface_is_quartz (const cairo_surface_t *surface)
2475 {
2476     return surface->backend == &cairo_quartz_surface_backend;
2477 }
2478
2479 /* Debug stuff */
2480
2481 #ifdef QUARTZ_DEBUG
2482
2483 #include <Movies.h>
2484
2485 void ExportCGImageToPNGFile (CGImageRef inImageRef, char* dest)
2486 {
2487     Handle  dataRef = NULL;
2488     OSType  dataRefType;
2489     CFStringRef inPath = CFStringCreateWithCString (NULL, dest, kCFStringEncodingASCII);
2490
2491     GraphicsExportComponent grex = 0;
2492     unsigned long sizeWritten;
2493
2494     ComponentResult result;
2495
2496     // create the data reference
2497     result = QTNewDataReferenceFromFullPathCFString (inPath, kQTNativeDefaultPathStyle,
2498                                                      0, &dataRef, &dataRefType);
2499
2500     if (NULL != dataRef && noErr == result) {
2501         // get the PNG exporter
2502         result = OpenADefaultComponent (GraphicsExporterComponentType, kQTFileTypePNG,
2503                                         &grex);
2504
2505         if (grex) {
2506             // tell the exporter where to find its source image
2507             result = GraphicsExportSetInputCGImage (grex, inImageRef);
2508
2509             if (noErr == result) {
2510                 // tell the exporter where to save the exporter image
2511                 result = GraphicsExportSetOutputDataReference (grex, dataRef,
2512                                                                dataRefType);
2513
2514                 if (noErr == result) {
2515                     // write the PNG file
2516                     result = GraphicsExportDoExport (grex, &sizeWritten);
2517                 }
2518             }
2519
2520             // remember to close the component
2521             CloseComponent (grex);
2522         }
2523
2524         // remember to dispose of the data reference handle
2525         DisposeHandle (dataRef);
2526     }
2527 }
2528
2529 void
2530 quartz_image_to_png (CGImageRef imgref, char *dest)
2531 {
2532     static int sctr = 0;
2533     char sptr[] = "/Users/vladimir/Desktop/barXXXXX.png";
2534
2535     if (dest == NULL) {
2536         fprintf (stderr, "** Writing %p to bar%d\n", imgref, sctr);
2537         sprintf (sptr, "/Users/vladimir/Desktop/bar%d.png", sctr);
2538         sctr++;
2539         dest = sptr;
2540     }
2541
2542     ExportCGImageToPNGFile (imgref, dest);
2543 }
2544
2545 void
2546 quartz_surface_to_png (cairo_quartz_surface_t *nq, char *dest)
2547 {
2548     static int sctr = 0;
2549     char sptr[] = "/Users/vladimir/Desktop/fooXXXXX.png";
2550
2551     if (nq->base.type != CAIRO_SURFACE_TYPE_QUARTZ) {
2552         fprintf (stderr, "** quartz_surface_to_png: surface %p isn't quartz!\n", nq);
2553         return;
2554     }
2555
2556     if (dest == NULL) {
2557         fprintf (stderr, "** Writing %p to foo%d\n", nq, sctr);
2558         sprintf (sptr, "/Users/vladimir/Desktop/foo%d.png", sctr);
2559         sctr++;
2560         dest = sptr;
2561     }
2562
2563     CGImageRef imgref = CGBitmapContextCreateImage (nq->cgContext);
2564     if (imgref == NULL) {
2565         fprintf (stderr, "quartz surface at %p is not a bitmap context!\n", nq);
2566         return;
2567     }
2568
2569     ExportCGImageToPNGFile (imgref, dest);
2570
2571     CGImageRelease (imgref);
2572 }
2573
2574 #endif /* QUARTZ_DEBUG */