Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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