1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/cairo/quartz-cglayers.patch Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,715 @@ 1.4 +changeset: 42959:e1964291f8ff 1.5 +user: Robert O'Callahan <robert@ocallahan.org> 1.6 +date: Tue Jun 01 11:33:23 2010 +1200 1.7 +summary: Bug 568189. Implement CGLayer-backed cairo-quartz surfaces. r=jrmuizel 1.8 + 1.9 +diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h 1.10 +--- a/gfx/cairo/cairo/src/cairo-quartz-private.h 1.11 ++++ b/gfx/cairo/cairo/src/cairo-quartz-private.h 1.12 +@@ -57,16 +57,21 @@ typedef struct cairo_quartz_surface { 1.13 + 1.14 + /** 1.15 + * If non-null, this is a CGImage representing the contents of the surface. 1.16 + * We clear this out before any painting into the surface, so that we 1.17 + * don't force a copy to be created. 1.18 + */ 1.19 + CGImageRef bitmapContextImage; 1.20 + 1.21 ++ /** 1.22 ++ * If non-null, this is the CGLayer for the surface. 1.23 ++ */ 1.24 ++ CGLayerRef cgLayer; 1.25 ++ 1.26 + cairo_rectangle_int_t extents; 1.27 + } cairo_quartz_surface_t; 1.28 + 1.29 + typedef struct cairo_quartz_image_surface { 1.30 + cairo_surface_t base; 1.31 + 1.32 + cairo_rectangle_int_t extents; 1.33 + 1.34 +diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c 1.35 +--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c 1.36 ++++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c 1.37 +@@ -1110,18 +1110,17 @@ CreateRepeatingRadialGradientFunction (c 1.38 + static void 1.39 + DataProviderReleaseCallback (void *info, const void *data, size_t size) 1.40 + { 1.41 + cairo_surface_t *surface = (cairo_surface_t *) info; 1.42 + cairo_surface_destroy (surface); 1.43 + } 1.44 + 1.45 + static cairo_status_t 1.46 +-_cairo_surface_to_cgimage (cairo_surface_t *target, 1.47 +- cairo_surface_t *source, 1.48 ++_cairo_surface_to_cgimage (cairo_surface_t *source, 1.49 + CGImageRef *image_out) 1.50 + { 1.51 + cairo_status_t status = CAIRO_STATUS_SUCCESS; 1.52 + cairo_surface_type_t stype = cairo_surface_get_type (source); 1.53 + cairo_image_surface_t *isurf; 1.54 + CGImageRef image; 1.55 + void *image_extra; 1.56 + 1.57 +@@ -1267,17 +1266,17 @@ _cairo_quartz_cairo_repeating_surface_pa 1.58 + return CAIRO_INT_STATUS_UNSUPPORTED; 1.59 + 1.60 + spattern = (cairo_surface_pattern_t *) apattern; 1.61 + pat_surf = spattern->surface; 1.62 + 1.63 + is_bounded = _cairo_surface_get_extents (pat_surf, &extents); 1.64 + assert (is_bounded); 1.65 + 1.66 +- status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image); 1.67 ++ status = _cairo_surface_to_cgimage (pat_surf, &image); 1.68 + if (status) 1.69 + return status; 1.70 + if (image == NULL) 1.71 + return CAIRO_INT_STATUS_NOTHING_TO_DO; 1.72 + 1.73 + info = malloc(sizeof(SurfacePatternDrawInfo)); 1.74 + if (!info) 1.75 + return CAIRO_STATUS_NO_MEMORY; 1.76 +@@ -1339,33 +1338,39 @@ _cairo_quartz_cairo_repeating_surface_pa 1.77 + } 1.78 + 1.79 + typedef enum { 1.80 + DO_SOLID, 1.81 + DO_SHADING, 1.82 + DO_PATTERN, 1.83 + DO_IMAGE, 1.84 + DO_TILED_IMAGE, 1.85 ++ DO_LAYER, 1.86 + DO_UNSUPPORTED, 1.87 + DO_NOTHING 1.88 + } cairo_quartz_action_t; 1.89 + 1.90 + /* State used during a drawing operation. */ 1.91 + typedef struct { 1.92 + CGContextRef context; 1.93 + cairo_quartz_action_t action; 1.94 + 1.95 +- // Used with DO_SHADING, DO_IMAGE and DO_TILED_IMAGE 1.96 ++ // Used with DO_SHADING, DO_IMAGE, DO_TILED_IMAGE and DO_LAYER 1.97 + CGAffineTransform transform; 1.98 + 1.99 + // Used with DO_IMAGE and DO_TILED_IMAGE 1.100 + CGImageRef image; 1.101 + cairo_surface_t *imageSurface; 1.102 ++ 1.103 ++ // Used with DO_IMAGE, DO_TILED_IMAGE and DO_LAYER 1.104 + CGRect imageRect; 1.105 + 1.106 ++ // Used with DO_LAYER 1.107 ++ CGLayerRef layer; 1.108 ++ 1.109 + // Used with DO_SHADING 1.110 + CGShadingRef shading; 1.111 + 1.112 + // Used with DO_PATTERN 1.113 + CGPatternRef pattern; 1.114 + } cairo_quartz_drawing_state_t; 1.115 + 1.116 + static void 1.117 +@@ -1423,17 +1428,17 @@ _cairo_quartz_setup_fallback_source (cai 1.118 + _cairo_pattern_transform (&pattern.base, 1.119 + &fallback->device_transform_inverse); 1.120 + status = _cairo_surface_paint (fallback, 1.121 + CAIRO_OPERATOR_SOURCE, 1.122 + &pattern.base, NULL); 1.123 + } 1.124 + #endif 1.125 + 1.126 +- status = _cairo_surface_to_cgimage (&surface->base, fallback, &img); 1.127 ++ status = _cairo_surface_to_cgimage (fallback, &img); 1.128 + if (status) { 1.129 + state->action = DO_UNSUPPORTED; 1.130 + return; 1.131 + } 1.132 + if (img == NULL) { 1.133 + state->action = DO_NOTHING; 1.134 + return; 1.135 + } 1.136 +@@ -1624,16 +1629,17 @@ _cairo_quartz_setup_state (cairo_quartz_ 1.137 + { 1.138 + CGContextRef context = surface->cgContext; 1.139 + cairo_quartz_drawing_state_t state; 1.140 + cairo_status_t status; 1.141 + 1.142 + state.context = context; 1.143 + state.image = NULL; 1.144 + state.imageSurface = NULL; 1.145 ++ state.layer = NULL; 1.146 + state.shading = NULL; 1.147 + state.pattern = NULL; 1.148 + 1.149 + _cairo_quartz_surface_will_change (surface); 1.150 + 1.151 + // Save before we change the pattern, colorspace, etc. so that 1.152 + // we can restore and make sure that quartz releases our 1.153 + // pattern (which may be stack allocated) 1.154 +@@ -1689,33 +1695,43 @@ _cairo_quartz_setup_state (cairo_quartz_ 1.155 + CGImageRef img; 1.156 + cairo_matrix_t m = spat->base.matrix; 1.157 + cairo_rectangle_int_t extents; 1.158 + CGAffineTransform xform; 1.159 + CGRect srcRect; 1.160 + cairo_fixed_t fw, fh; 1.161 + cairo_bool_t is_bounded; 1.162 + 1.163 +- status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img); 1.164 ++ cairo_matrix_invert(&m); 1.165 ++ _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); 1.166 ++ 1.167 ++ if (cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { 1.168 ++ cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; 1.169 ++ if (quartz_surf->cgLayer && source->extend == CAIRO_EXTEND_NONE) { 1.170 ++ state.imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); 1.171 ++ state.layer = quartz_surf->cgLayer; 1.172 ++ state.action = DO_LAYER; 1.173 ++ return state; 1.174 ++ } 1.175 ++ } 1.176 ++ 1.177 ++ status = _cairo_surface_to_cgimage (pat_surf, &img); 1.178 + if (status) { 1.179 + state.action = DO_UNSUPPORTED; 1.180 + return state; 1.181 + } 1.182 + if (img == NULL) { 1.183 + state.action = DO_NOTHING; 1.184 + return state; 1.185 + } 1.186 + 1.187 + CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); 1.188 + 1.189 + state.image = img; 1.190 + 1.191 +- cairo_matrix_invert(&m); 1.192 +- _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); 1.193 +- 1.194 + is_bounded = _cairo_surface_get_extents (pat_surf, &extents); 1.195 + assert (is_bounded); 1.196 + 1.197 + if (source->extend == CAIRO_EXTEND_NONE) { 1.198 + state.imageRect = CGRectMake (0, 0, extents.width, extents.height); 1.199 + state.action = DO_IMAGE; 1.200 + return state; 1.201 + } 1.202 +@@ -1820,33 +1836,48 @@ _cairo_quartz_teardown_state (cairo_quar 1.203 + 1.204 + CGContextRestoreGState(state->context); 1.205 + } 1.206 + 1.207 + 1.208 + static void 1.209 + _cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state, cairo_operator_t op) 1.210 + { 1.211 +- assert (state && state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)); 1.212 ++ assert (state && 1.213 ++ ((state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)) || 1.214 ++ (state->layer && state->action == DO_LAYER))); 1.215 + 1.216 + CGContextConcatCTM (state->context, state->transform); 1.217 + CGContextTranslateCTM (state->context, 0, state->imageRect.size.height); 1.218 + CGContextScaleCTM (state->context, 1, -1); 1.219 + 1.220 +- if (state->action == DO_IMAGE) { 1.221 +- CGContextDrawImage (state->context, state->imageRect, state->image); 1.222 ++ if (state->action == DO_TILED_IMAGE) { 1.223 ++ CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image); 1.224 ++ /* no need to worry about unbounded operators, since tiled images 1.225 ++ fill the entire clip region */ 1.226 ++ } else { 1.227 ++ if (state->action == DO_LAYER) { 1.228 ++ /* Note that according to Apple docs it's completely legal 1.229 ++ * to draw a CGLayer to any CGContext, even one it wasn't 1.230 ++ * created for. 1.231 ++ */ 1.232 ++ CGContextDrawLayerAtPoint (state->context, state->imageRect.origin, 1.233 ++ state->layer); 1.234 ++ } else { 1.235 ++ CGContextDrawImage (state->context, state->imageRect, state->image); 1.236 ++ } 1.237 ++ 1.238 + if (!_cairo_operator_bounded_by_source (op)) { 1.239 + CGContextBeginPath (state->context); 1.240 + CGContextAddRect (state->context, state->imageRect); 1.241 + CGContextAddRect (state->context, CGContextGetClipBoundingBox (state->context)); 1.242 + CGContextSetRGBFillColor (state->context, 0, 0, 0, 0); 1.243 + CGContextEOFillPath (state->context); 1.244 + } 1.245 +- } else 1.246 +- CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image); 1.247 ++ } 1.248 + } 1.249 + 1.250 + 1.251 + /* 1.252 + * get source/dest image implementation 1.253 + */ 1.254 + 1.255 + /* Read the image from the surface's front buffer */ 1.256 +@@ -1971,95 +2002,153 @@ _cairo_quartz_surface_finish (void *abst 1.257 + surface->imageSurfaceEquiv = NULL; 1.258 + } 1.259 + 1.260 + if (surface->imageData) { 1.261 + free (surface->imageData); 1.262 + surface->imageData = NULL; 1.263 + } 1.264 + 1.265 ++ if (surface->cgLayer) { 1.266 ++ CGLayerRelease (surface->cgLayer); 1.267 ++ } 1.268 ++ 1.269 + return CAIRO_STATUS_SUCCESS; 1.270 + } 1.271 + 1.272 + static cairo_status_t 1.273 +-_cairo_quartz_surface_acquire_source_image (void *abstract_surface, 1.274 +- cairo_image_surface_t **image_out, 1.275 +- void **image_extra) 1.276 ++_cairo_quartz_surface_acquire_image (void *abstract_surface, 1.277 ++ cairo_image_surface_t **image_out, 1.278 ++ void **image_extra) 1.279 + { 1.280 + cairo_int_status_t status; 1.281 + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; 1.282 + 1.283 +- //ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface)); 1.284 ++ *image_extra = NULL; 1.285 ++ 1.286 ++ /* ND((stderr, "%p _cairo_quartz_surface_acquire_image\n", surface)); */ 1.287 + 1.288 + status = _cairo_quartz_get_image (surface, image_out); 1.289 ++ 1.290 ++ if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->cgLayer) { 1.291 ++ /* copy the layer into a Quartz bitmap context so we can get the data */ 1.292 ++ cairo_surface_t *tmp = 1.293 ++ cairo_quartz_surface_create (CAIRO_CONTENT_COLOR_ALPHA, 1.294 ++ surface->extents.width, 1.295 ++ surface->extents.height); 1.296 ++ cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) tmp; 1.297 ++ 1.298 ++ /* if surface creation failed, we won't have a Quartz surface here */ 1.299 ++ if (cairo_surface_get_type (tmp) == CAIRO_SURFACE_TYPE_QUARTZ && 1.300 ++ tmp_surface->imageSurfaceEquiv) { 1.301 ++ CGContextSaveGState (tmp_surface->cgContext); 1.302 ++ CGContextTranslateCTM (tmp_surface->cgContext, 0, surface->extents.height); 1.303 ++ CGContextScaleCTM (tmp_surface->cgContext, 1, -1); 1.304 ++ /* Note that according to Apple docs it's completely legal 1.305 ++ * to draw a CGLayer to any CGContext, even one it wasn't 1.306 ++ * created for. 1.307 ++ */ 1.308 ++ CGContextDrawLayerAtPoint (tmp_surface->cgContext, 1.309 ++ CGPointMake (0.0, 0.0), 1.310 ++ surface->cgLayer); 1.311 ++ CGContextRestoreGState (tmp_surface->cgContext); 1.312 ++ 1.313 ++ *image_out = (cairo_image_surface_t*) 1.314 ++ cairo_surface_reference(tmp_surface->imageSurfaceEquiv); 1.315 ++ *image_extra = tmp; 1.316 ++ } else { 1.317 ++ cairo_surface_destroy (tmp); 1.318 ++ } 1.319 ++ } 1.320 ++ 1.321 + if (status) 1.322 + return _cairo_error (CAIRO_STATUS_NO_MEMORY); 1.323 + 1.324 +- *image_extra = NULL; 1.325 +- 1.326 + return CAIRO_STATUS_SUCCESS; 1.327 + } 1.328 + 1.329 + static void 1.330 + _cairo_quartz_surface_release_source_image (void *abstract_surface, 1.331 + cairo_image_surface_t *image, 1.332 + void *image_extra) 1.333 + { 1.334 + cairo_surface_destroy ((cairo_surface_t *) image); 1.335 ++ 1.336 ++ if (image_extra) { 1.337 ++ cairo_surface_destroy ((cairo_surface_t *) image_extra); 1.338 ++ } 1.339 + } 1.340 + 1.341 + 1.342 + static cairo_status_t 1.343 + _cairo_quartz_surface_acquire_dest_image (void *abstract_surface, 1.344 + cairo_rectangle_int_t *interest_rect, 1.345 + cairo_image_surface_t **image_out, 1.346 + cairo_rectangle_int_t *image_rect, 1.347 + void **image_extra) 1.348 + { 1.349 + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; 1.350 +- cairo_int_status_t status; 1.351 + 1.352 + ND((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface)); 1.353 + 1.354 +- _cairo_quartz_surface_will_change (surface); 1.355 +- 1.356 +- status = _cairo_quartz_get_image (surface, image_out); 1.357 +- if (status) 1.358 +- return _cairo_error (CAIRO_STATUS_NO_MEMORY); 1.359 +- 1.360 + *image_rect = surface->extents; 1.361 + *image_extra = NULL; 1.362 + 1.363 +- return CAIRO_STATUS_SUCCESS; 1.364 ++ _cairo_quartz_surface_will_change (surface); 1.365 ++ 1.366 ++ return _cairo_quartz_surface_acquire_image (abstract_surface, 1.367 ++ image_out, image_extra); 1.368 + } 1.369 + 1.370 + static void 1.371 + _cairo_quartz_surface_release_dest_image (void *abstract_surface, 1.372 + cairo_rectangle_int_t *interest_rect, 1.373 + cairo_image_surface_t *image, 1.374 + cairo_rectangle_int_t *image_rect, 1.375 + void *image_extra) 1.376 + { 1.377 +- //cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; 1.378 +- 1.379 +- //ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface)); 1.380 ++ /* ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface)); */ 1.381 + 1.382 + cairo_surface_destroy ((cairo_surface_t *) image); 1.383 ++ 1.384 ++ if (image_extra) { 1.385 ++ /* we need to write the data from the temp surface back to the layer */ 1.386 ++ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; 1.387 ++ cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) image_extra; 1.388 ++ CGImageRef img; 1.389 ++ cairo_status_t status = _cairo_surface_to_cgimage (&tmp_surface->base, &img); 1.390 ++ if (status) { 1.391 ++ cairo_surface_destroy (&tmp_surface->base); 1.392 ++ return; 1.393 ++ } 1.394 ++ 1.395 ++ CGContextSaveGState (surface->cgContext); 1.396 ++ CGContextTranslateCTM (surface->cgContext, 0, surface->extents.height); 1.397 ++ CGContextScaleCTM (surface->cgContext, 1, -1); 1.398 ++ CGContextDrawImage (surface->cgContext, 1.399 ++ CGRectMake (0.0, 0.0, surface->extents.width, surface->extents.height), 1.400 ++ img); 1.401 ++ CGContextRestoreGState (surface->cgContext); 1.402 ++ 1.403 ++ cairo_surface_destroy (&tmp_surface->base); 1.404 ++ } 1.405 + } 1.406 + 1.407 + static cairo_surface_t * 1.408 + _cairo_quartz_surface_create_similar (void *abstract_surface, 1.409 + cairo_content_t content, 1.410 + int width, 1.411 + int height) 1.412 + { 1.413 +- /*cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;*/ 1.414 +- 1.415 ++ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; 1.416 + cairo_format_t format; 1.417 + 1.418 ++ if (surface->cgLayer) 1.419 ++ return cairo_quartz_surface_create_cg_layer (abstract_surface, width, height); 1.420 ++ 1.421 + if (content == CAIRO_CONTENT_COLOR_ALPHA) 1.422 + format = CAIRO_FORMAT_ARGB32; 1.423 + else if (content == CAIRO_CONTENT_COLOR) 1.424 + format = CAIRO_FORMAT_RGB24; 1.425 + else if (content == CAIRO_CONTENT_ALPHA) 1.426 + format = CAIRO_FORMAT_A8; 1.427 + else 1.428 + return NULL; 1.429 +@@ -2113,17 +2202,17 @@ _cairo_quartz_surface_clone_similar (voi 1.430 + _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, 1.431 + qsurf->extents.width, qsurf->extents.height); 1.432 + *clone_offset_x = 0; 1.433 + *clone_offset_y = 0; 1.434 + return CAIRO_STATUS_SUCCESS; 1.435 + } 1.436 + } 1.437 + 1.438 +- status = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src, &quartz_image); 1.439 ++ status = _cairo_surface_to_cgimage (src, &quartz_image); 1.440 + if (status) 1.441 + return CAIRO_INT_STATUS_UNSUPPORTED; 1.442 + 1.443 + new_format = CAIRO_FORMAT_ARGB32; /* assumed */ 1.444 + if (_cairo_surface_is_image (src)) { 1.445 + new_format = ((cairo_image_surface_t *) src)->format; 1.446 + } 1.447 + 1.448 +@@ -2194,17 +2283,18 @@ _cairo_quartz_surface_paint (void *abstr 1.449 + if (state.action == DO_SOLID || state.action == DO_PATTERN) { 1.450 + CGContextFillRect (state.context, CGRectMake(surface->extents.x, 1.451 + surface->extents.y, 1.452 + surface->extents.width, 1.453 + surface->extents.height)); 1.454 + } else if (state.action == DO_SHADING) { 1.455 + CGContextConcatCTM (state.context, state.transform); 1.456 + CGContextDrawShading (state.context, state.shading); 1.457 +- } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { 1.458 ++ } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || 1.459 ++ state.action == DO_LAYER) { 1.460 + _cairo_quartz_draw_image (&state, op); 1.461 + } else if (state.action != DO_NOTHING) { 1.462 + rv = CAIRO_INT_STATUS_UNSUPPORTED; 1.463 + } 1.464 + 1.465 + _cairo_quartz_teardown_state (&state); 1.466 + 1.467 + ND((stderr, "-- paint\n")); 1.468 +@@ -2291,17 +2381,18 @@ _cairo_quartz_surface_fill (void *abstra 1.469 + // with the shading 1.470 + if (fill_rule == CAIRO_FILL_RULE_WINDING) 1.471 + CGContextClip (state.context); 1.472 + else 1.473 + CGContextEOClip (state.context); 1.474 + 1.475 + CGContextConcatCTM (state.context, state.transform); 1.476 + CGContextDrawShading (state.context, state.shading); 1.477 +- } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { 1.478 ++ } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || 1.479 ++ state.action == DO_LAYER) { 1.480 + if (fill_rule == CAIRO_FILL_RULE_WINDING) 1.481 + CGContextClip (state.context); 1.482 + else 1.483 + CGContextEOClip (state.context); 1.484 + 1.485 + _cairo_quartz_draw_image (&state, op); 1.486 + } else if (state.action != DO_NOTHING) { 1.487 + rv = CAIRO_INT_STATUS_UNSUPPORTED; 1.488 +@@ -2416,17 +2507,18 @@ _cairo_quartz_surface_stroke (void *abst 1.489 + if (rv) 1.490 + goto BAIL; 1.491 + 1.492 + if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr) 1.493 + path_for_unbounded = CGContextCopyPathPtr (state.context); 1.494 + 1.495 + if (state.action == DO_SOLID || state.action == DO_PATTERN) { 1.496 + CGContextStrokePath (state.context); 1.497 +- } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { 1.498 ++ } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || 1.499 ++ state.action == DO_LAYER) { 1.500 + CGContextReplacePathWithStrokedPath (state.context); 1.501 + CGContextClip (state.context); 1.502 + 1.503 + CGContextSetCTM (state.context, origCTM); 1.504 + _cairo_quartz_draw_image (&state, op); 1.505 + } else if (state.action == DO_SHADING) { 1.506 + CGContextReplacePathWithStrokedPath (state.context); 1.507 + CGContextClip (state.context); 1.508 +@@ -2511,17 +2603,18 @@ _cairo_quartz_surface_show_glyphs (void 1.509 + &glyph_extents, NULL); 1.510 + state = _cairo_quartz_setup_state (surface, source, op, &glyph_extents); 1.511 + } else { 1.512 + state = _cairo_quartz_setup_state (surface, source, op, NULL); 1.513 + } 1.514 + 1.515 + if (state.action == DO_SOLID || state.action == DO_PATTERN) { 1.516 + CGContextSetTextDrawingMode (state.context, kCGTextFill); 1.517 +- } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || state.action == DO_SHADING) { 1.518 ++ } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || 1.519 ++ state.action == DO_SHADING || state.action == DO_LAYER) { 1.520 + CGContextSetTextDrawingMode (state.context, kCGTextClip); 1.521 + isClipping = TRUE; 1.522 + } else { 1.523 + if (state.action != DO_NOTHING) 1.524 + rv = CAIRO_INT_STATUS_UNSUPPORTED; 1.525 + goto BAIL; 1.526 + } 1.527 + 1.528 +@@ -2622,17 +2715,18 @@ _cairo_quartz_surface_show_glyphs (void 1.529 + 1.530 + CGContextShowGlyphsWithAdvances (state.context, 1.531 + cg_glyphs, 1.532 + cg_advances, 1.533 + num_glyphs); 1.534 + 1.535 + CGContextSetCTM (state.context, ctm); 1.536 + 1.537 +- if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { 1.538 ++ if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || 1.539 ++ state.action == DO_LAYER) { 1.540 + _cairo_quartz_draw_image (&state, op); 1.541 + } else if (state.action == DO_SHADING) { 1.542 + CGContextConcatCTM (state.context, state.transform); 1.543 + CGContextDrawShading (state.context, state.shading); 1.544 + } 1.545 + 1.546 + BAIL: 1.547 + if (didForceFontSmoothing) 1.548 +@@ -2679,17 +2773,17 @@ _cairo_quartz_surface_mask_with_surface 1.549 + cairo_clip_t *clip) 1.550 + { 1.551 + CGRect rect; 1.552 + CGImageRef img; 1.553 + cairo_surface_t *pat_surf = mask->surface; 1.554 + cairo_status_t status = CAIRO_STATUS_SUCCESS; 1.555 + CGAffineTransform ctm, mask_matrix; 1.556 + 1.557 +- status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img); 1.558 ++ status = _cairo_surface_to_cgimage (pat_surf, &img); 1.559 + if (status) 1.560 + return status; 1.561 + if (img == NULL) { 1.562 + if (!_cairo_operator_bounded_by_mask (op)) 1.563 + CGContextClearRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext)); 1.564 + return CAIRO_STATUS_SUCCESS; 1.565 + } 1.566 + 1.567 +@@ -2869,17 +2963,17 @@ _cairo_quartz_surface_clipper_intersect_ 1.568 + } 1.569 + 1.570 + // XXXtodo implement show_page; need to figure out how to handle begin/end 1.571 + 1.572 + static const struct _cairo_surface_backend cairo_quartz_surface_backend = { 1.573 + CAIRO_SURFACE_TYPE_QUARTZ, 1.574 + _cairo_quartz_surface_create_similar, 1.575 + _cairo_quartz_surface_finish, 1.576 +- _cairo_quartz_surface_acquire_source_image, 1.577 ++ _cairo_quartz_surface_acquire_image, 1.578 + _cairo_quartz_surface_release_source_image, 1.579 + _cairo_quartz_surface_acquire_dest_image, 1.580 + _cairo_quartz_surface_release_dest_image, 1.581 + _cairo_quartz_surface_clone_similar, 1.582 + NULL, /* composite */ 1.583 + NULL, /* fill_rectangles */ 1.584 + NULL, /* composite_trapezoids */ 1.585 + NULL, /* create_span_renderer */ 1.586 +@@ -2950,16 +3044,17 @@ _cairo_quartz_surface_create_internal (C 1.587 + CGContextSaveGState (cgContext); 1.588 + 1.589 + surface->cgContext = cgContext; 1.590 + surface->cgContextBaseCTM = CGContextGetCTM (cgContext); 1.591 + 1.592 + surface->imageData = NULL; 1.593 + surface->imageSurfaceEquiv = NULL; 1.594 + surface->bitmapContextImage = NULL; 1.595 ++ surface->cgLayer = NULL; 1.596 + 1.597 + return surface; 1.598 + } 1.599 + 1.600 + /** 1.601 + * cairo_quartz_surface_create_for_cg_context 1.602 + * @cgContext: the existing CGContext for which to create the surface 1.603 + * @width: width of the surface, in pixels 1.604 +@@ -3002,16 +3097,88 @@ cairo_quartz_surface_create_for_cg_conte 1.605 + // create_internal will have set an error 1.606 + return (cairo_surface_t*) surf; 1.607 + } 1.608 + 1.609 + return (cairo_surface_t *) surf; 1.610 + } 1.611 + 1.612 + /** 1.613 ++ * cairo_quartz_cglayer_surface_create_similar 1.614 ++ * @surface: The returned surface can be efficiently drawn into this 1.615 ++ * destination surface (if tiling is not used)." 1.616 ++ * @width: width of the surface, in pixels 1.617 ++ * @height: height of the surface, in pixels 1.618 ++ * 1.619 ++ * Creates a Quartz surface backed by a CGLayer, if the given surface 1.620 ++ * is a Quartz surface; the CGLayer is created to match the surface's 1.621 ++ * Quartz context. Otherwise just calls cairo_surface_create_similar 1.622 ++ * with CAIRO_CONTENT_COLOR_ALPHA. 1.623 ++ * The returned surface can be efficiently blitted to the given surface, 1.624 ++ * but tiling and 'extend' modes other than NONE are not so efficient. 1.625 ++ * 1.626 ++ * Return value: the newly created surface. 1.627 ++ * 1.628 ++ * Since: 1.10 1.629 ++ **/ 1.630 ++cairo_surface_t * 1.631 ++cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface, 1.632 ++ unsigned int width, 1.633 ++ unsigned int height) 1.634 ++{ 1.635 ++ cairo_quartz_surface_t *surf; 1.636 ++ CGLayerRef layer; 1.637 ++ CGContextRef ctx; 1.638 ++ CGContextRef cgContext; 1.639 ++ 1.640 ++ cgContext = cairo_quartz_surface_get_cg_context (surface); 1.641 ++ if (!cgContext) 1.642 ++ return cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA, 1.643 ++ width, height); 1.644 ++ 1.645 ++ if (!_cairo_quartz_verify_surface_size(width, height)) 1.646 ++ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); 1.647 ++ 1.648 ++ /* If we pass zero width or height into CGLayerCreateWithContext below, 1.649 ++ * it will fail. 1.650 ++ */ 1.651 ++ if (width == 0 || height == 0) { 1.652 ++ return (cairo_surface_t*) 1.653 ++ _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, 1.654 ++ width, height); 1.655 ++ } 1.656 ++ 1.657 ++ layer = CGLayerCreateWithContext (cgContext, 1.658 ++ CGSizeMake (width, height), 1.659 ++ NULL); 1.660 ++ if (!layer) 1.661 ++ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); 1.662 ++ 1.663 ++ ctx = CGLayerGetContext (layer); 1.664 ++ /* Flip it when we draw into it, so that when we finally composite it 1.665 ++ * to a flipped target, the directions match and Quartz will optimize 1.666 ++ * the composition properly 1.667 ++ */ 1.668 ++ CGContextTranslateCTM (ctx, 0, height); 1.669 ++ CGContextScaleCTM (ctx, 1, -1); 1.670 ++ 1.671 ++ CGContextRetain (ctx); 1.672 ++ surf = _cairo_quartz_surface_create_internal (ctx, CAIRO_CONTENT_COLOR_ALPHA, 1.673 ++ width, height); 1.674 ++ if (surf->base.status) { 1.675 ++ CGLayerRelease (layer); 1.676 ++ // create_internal will have set an error 1.677 ++ return (cairo_surface_t*) surf; 1.678 ++ } 1.679 ++ surf->cgLayer = layer; 1.680 ++ 1.681 ++ return (cairo_surface_t *) surf; 1.682 ++} 1.683 ++ 1.684 ++/** 1.685 + * cairo_quartz_surface_create 1.686 + * @format: format of pixels in the surface to create 1.687 + * @width: width of the surface, in pixels 1.688 + * @height: height of the surface, in pixels 1.689 + * 1.690 + * Creates a Quartz surface backed by a CGBitmap. The surface is 1.691 + * created using the Device RGB (or Device Gray, for A8) color space. 1.692 + * All Cairo operations, including those that require software 1.693 +diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h 1.694 +--- a/gfx/cairo/cairo/src/cairo-quartz.h 1.695 ++++ b/gfx/cairo/cairo/src/cairo-quartz.h 1.696 +@@ -45,16 +45,21 @@ 1.697 + CAIRO_BEGIN_DECLS 1.698 + 1.699 + cairo_public cairo_surface_t * 1.700 + cairo_quartz_surface_create (cairo_format_t format, 1.701 + unsigned int width, 1.702 + unsigned int height); 1.703 + 1.704 + cairo_public cairo_surface_t * 1.705 ++cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface, 1.706 ++ unsigned int width, 1.707 ++ unsigned int height); 1.708 ++ 1.709 ++cairo_public cairo_surface_t * 1.710 + cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, 1.711 + unsigned int width, 1.712 + unsigned int height); 1.713 + 1.714 + cairo_public CGContextRef 1.715 + cairo_quartz_surface_get_cg_context (cairo_surface_t *surface); 1.716 + 1.717 + cairo_public CGContextRef 1.718 +