diff options
Diffstat (limited to 'gfx/cairo/quartz-cglayers.patch')
-rw-r--r-- | gfx/cairo/quartz-cglayers.patch | 715 |
1 files changed, 715 insertions, 0 deletions
diff --git a/gfx/cairo/quartz-cglayers.patch b/gfx/cairo/quartz-cglayers.patch new file mode 100644 index 000000000..bb3d44d9e --- /dev/null +++ b/gfx/cairo/quartz-cglayers.patch @@ -0,0 +1,715 @@ +changeset: 42959:e1964291f8ff +user: Robert O'Callahan <robert@ocallahan.org> +date: Tue Jun 01 11:33:23 2010 +1200 +summary: Bug 568189. Implement CGLayer-backed cairo-quartz surfaces. r=jrmuizel + +diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h +--- a/gfx/cairo/cairo/src/cairo-quartz-private.h ++++ b/gfx/cairo/cairo/src/cairo-quartz-private.h +@@ -57,16 +57,21 @@ typedef struct cairo_quartz_surface { + + /** + * If non-null, this is a CGImage representing the contents of the surface. + * We clear this out before any painting into the surface, so that we + * don't force a copy to be created. + */ + CGImageRef bitmapContextImage; + ++ /** ++ * If non-null, this is the CGLayer for the surface. ++ */ ++ CGLayerRef cgLayer; ++ + cairo_rectangle_int_t extents; + } cairo_quartz_surface_t; + + typedef struct cairo_quartz_image_surface { + cairo_surface_t base; + + cairo_rectangle_int_t extents; + +diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c +--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c ++++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c +@@ -1110,18 +1110,17 @@ CreateRepeatingRadialGradientFunction (c + static void + DataProviderReleaseCallback (void *info, const void *data, size_t size) + { + cairo_surface_t *surface = (cairo_surface_t *) info; + cairo_surface_destroy (surface); + } + + static cairo_status_t +-_cairo_surface_to_cgimage (cairo_surface_t *target, +- cairo_surface_t *source, ++_cairo_surface_to_cgimage (cairo_surface_t *source, + CGImageRef *image_out) + { + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_surface_type_t stype = cairo_surface_get_type (source); + cairo_image_surface_t *isurf; + CGImageRef image; + void *image_extra; + +@@ -1267,17 +1266,17 @@ _cairo_quartz_cairo_repeating_surface_pa + return CAIRO_INT_STATUS_UNSUPPORTED; + + spattern = (cairo_surface_pattern_t *) apattern; + pat_surf = spattern->surface; + + is_bounded = _cairo_surface_get_extents (pat_surf, &extents); + assert (is_bounded); + +- status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image); ++ status = _cairo_surface_to_cgimage (pat_surf, &image); + if (status) + return status; + if (image == NULL) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + info = malloc(sizeof(SurfacePatternDrawInfo)); + if (!info) + return CAIRO_STATUS_NO_MEMORY; +@@ -1339,33 +1338,39 @@ _cairo_quartz_cairo_repeating_surface_pa + } + + typedef enum { + DO_SOLID, + DO_SHADING, + DO_PATTERN, + DO_IMAGE, + DO_TILED_IMAGE, ++ DO_LAYER, + DO_UNSUPPORTED, + DO_NOTHING + } cairo_quartz_action_t; + + /* State used during a drawing operation. */ + typedef struct { + CGContextRef context; + cairo_quartz_action_t action; + +- // Used with DO_SHADING, DO_IMAGE and DO_TILED_IMAGE ++ // Used with DO_SHADING, DO_IMAGE, DO_TILED_IMAGE and DO_LAYER + CGAffineTransform transform; + + // Used with DO_IMAGE and DO_TILED_IMAGE + CGImageRef image; + cairo_surface_t *imageSurface; ++ ++ // Used with DO_IMAGE, DO_TILED_IMAGE and DO_LAYER + CGRect imageRect; + ++ // Used with DO_LAYER ++ CGLayerRef layer; ++ + // Used with DO_SHADING + CGShadingRef shading; + + // Used with DO_PATTERN + CGPatternRef pattern; + } cairo_quartz_drawing_state_t; + + static void +@@ -1423,17 +1428,17 @@ _cairo_quartz_setup_fallback_source (cai + _cairo_pattern_transform (&pattern.base, + &fallback->device_transform_inverse); + status = _cairo_surface_paint (fallback, + CAIRO_OPERATOR_SOURCE, + &pattern.base, NULL); + } + #endif + +- status = _cairo_surface_to_cgimage (&surface->base, fallback, &img); ++ status = _cairo_surface_to_cgimage (fallback, &img); + if (status) { + state->action = DO_UNSUPPORTED; + return; + } + if (img == NULL) { + state->action = DO_NOTHING; + return; + } +@@ -1624,16 +1629,17 @@ _cairo_quartz_setup_state (cairo_quartz_ + { + CGContextRef context = surface->cgContext; + cairo_quartz_drawing_state_t state; + cairo_status_t status; + + state.context = context; + state.image = NULL; + state.imageSurface = NULL; ++ state.layer = NULL; + state.shading = NULL; + state.pattern = NULL; + + _cairo_quartz_surface_will_change (surface); + + // Save before we change the pattern, colorspace, etc. so that + // we can restore and make sure that quartz releases our + // pattern (which may be stack allocated) +@@ -1689,33 +1695,43 @@ _cairo_quartz_setup_state (cairo_quartz_ + CGImageRef img; + cairo_matrix_t m = spat->base.matrix; + cairo_rectangle_int_t extents; + CGAffineTransform xform; + CGRect srcRect; + cairo_fixed_t fw, fh; + cairo_bool_t is_bounded; + +- status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img); ++ cairo_matrix_invert(&m); ++ _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); ++ ++ if (cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { ++ cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; ++ if (quartz_surf->cgLayer && source->extend == CAIRO_EXTEND_NONE) { ++ state.imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); ++ state.layer = quartz_surf->cgLayer; ++ state.action = DO_LAYER; ++ return state; ++ } ++ } ++ ++ status = _cairo_surface_to_cgimage (pat_surf, &img); + if (status) { + state.action = DO_UNSUPPORTED; + return state; + } + if (img == NULL) { + state.action = DO_NOTHING; + return state; + } + + CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); + + state.image = img; + +- cairo_matrix_invert(&m); +- _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); +- + is_bounded = _cairo_surface_get_extents (pat_surf, &extents); + assert (is_bounded); + + if (source->extend == CAIRO_EXTEND_NONE) { + state.imageRect = CGRectMake (0, 0, extents.width, extents.height); + state.action = DO_IMAGE; + return state; + } +@@ -1820,33 +1836,48 @@ _cairo_quartz_teardown_state (cairo_quar + + CGContextRestoreGState(state->context); + } + + + static void + _cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state, cairo_operator_t op) + { +- assert (state && state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)); ++ assert (state && ++ ((state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)) || ++ (state->layer && state->action == DO_LAYER))); + + CGContextConcatCTM (state->context, state->transform); + CGContextTranslateCTM (state->context, 0, state->imageRect.size.height); + CGContextScaleCTM (state->context, 1, -1); + +- if (state->action == DO_IMAGE) { +- CGContextDrawImage (state->context, state->imageRect, state->image); ++ if (state->action == DO_TILED_IMAGE) { ++ CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image); ++ /* no need to worry about unbounded operators, since tiled images ++ fill the entire clip region */ ++ } else { ++ if (state->action == DO_LAYER) { ++ /* Note that according to Apple docs it's completely legal ++ * to draw a CGLayer to any CGContext, even one it wasn't ++ * created for. ++ */ ++ CGContextDrawLayerAtPoint (state->context, state->imageRect.origin, ++ state->layer); ++ } else { ++ CGContextDrawImage (state->context, state->imageRect, state->image); ++ } ++ + if (!_cairo_operator_bounded_by_source (op)) { + CGContextBeginPath (state->context); + CGContextAddRect (state->context, state->imageRect); + CGContextAddRect (state->context, CGContextGetClipBoundingBox (state->context)); + CGContextSetRGBFillColor (state->context, 0, 0, 0, 0); + CGContextEOFillPath (state->context); + } +- } else +- CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image); ++ } + } + + + /* + * get source/dest image implementation + */ + + /* Read the image from the surface's front buffer */ +@@ -1971,95 +2002,153 @@ _cairo_quartz_surface_finish (void *abst + surface->imageSurfaceEquiv = NULL; + } + + if (surface->imageData) { + free (surface->imageData); + surface->imageData = NULL; + } + ++ if (surface->cgLayer) { ++ CGLayerRelease (surface->cgLayer); ++ } ++ + return CAIRO_STATUS_SUCCESS; + } + + static cairo_status_t +-_cairo_quartz_surface_acquire_source_image (void *abstract_surface, +- cairo_image_surface_t **image_out, +- void **image_extra) ++_cairo_quartz_surface_acquire_image (void *abstract_surface, ++ cairo_image_surface_t **image_out, ++ void **image_extra) + { + cairo_int_status_t status; + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + +- //ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface)); ++ *image_extra = NULL; ++ ++ /* ND((stderr, "%p _cairo_quartz_surface_acquire_image\n", surface)); */ + + status = _cairo_quartz_get_image (surface, image_out); ++ ++ if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->cgLayer) { ++ /* copy the layer into a Quartz bitmap context so we can get the data */ ++ cairo_surface_t *tmp = ++ cairo_quartz_surface_create (CAIRO_CONTENT_COLOR_ALPHA, ++ surface->extents.width, ++ surface->extents.height); ++ cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) tmp; ++ ++ /* if surface creation failed, we won't have a Quartz surface here */ ++ if (cairo_surface_get_type (tmp) == CAIRO_SURFACE_TYPE_QUARTZ && ++ tmp_surface->imageSurfaceEquiv) { ++ CGContextSaveGState (tmp_surface->cgContext); ++ CGContextTranslateCTM (tmp_surface->cgContext, 0, surface->extents.height); ++ CGContextScaleCTM (tmp_surface->cgContext, 1, -1); ++ /* Note that according to Apple docs it's completely legal ++ * to draw a CGLayer to any CGContext, even one it wasn't ++ * created for. ++ */ ++ CGContextDrawLayerAtPoint (tmp_surface->cgContext, ++ CGPointMake (0.0, 0.0), ++ surface->cgLayer); ++ CGContextRestoreGState (tmp_surface->cgContext); ++ ++ *image_out = (cairo_image_surface_t*) ++ cairo_surface_reference(tmp_surface->imageSurfaceEquiv); ++ *image_extra = tmp; ++ } else { ++ cairo_surface_destroy (tmp); ++ } ++ } ++ + if (status) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + +- *image_extra = NULL; +- + return CAIRO_STATUS_SUCCESS; + } + + static void + _cairo_quartz_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) + { + cairo_surface_destroy ((cairo_surface_t *) image); ++ ++ if (image_extra) { ++ cairo_surface_destroy ((cairo_surface_t *) image_extra); ++ } + } + + + static cairo_status_t + _cairo_quartz_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_int_t *image_rect, + void **image_extra) + { + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; +- cairo_int_status_t status; + + ND((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface)); + +- _cairo_quartz_surface_will_change (surface); +- +- status = _cairo_quartz_get_image (surface, image_out); +- if (status) +- return _cairo_error (CAIRO_STATUS_NO_MEMORY); +- + *image_rect = surface->extents; + *image_extra = NULL; + +- return CAIRO_STATUS_SUCCESS; ++ _cairo_quartz_surface_will_change (surface); ++ ++ return _cairo_quartz_surface_acquire_image (abstract_surface, ++ image_out, image_extra); + } + + static void + _cairo_quartz_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_int_t *image_rect, + void *image_extra) + { +- //cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; +- +- //ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface)); ++ /* ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface)); */ + + cairo_surface_destroy ((cairo_surface_t *) image); ++ ++ if (image_extra) { ++ /* we need to write the data from the temp surface back to the layer */ ++ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; ++ cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) image_extra; ++ CGImageRef img; ++ cairo_status_t status = _cairo_surface_to_cgimage (&tmp_surface->base, &img); ++ if (status) { ++ cairo_surface_destroy (&tmp_surface->base); ++ return; ++ } ++ ++ CGContextSaveGState (surface->cgContext); ++ CGContextTranslateCTM (surface->cgContext, 0, surface->extents.height); ++ CGContextScaleCTM (surface->cgContext, 1, -1); ++ CGContextDrawImage (surface->cgContext, ++ CGRectMake (0.0, 0.0, surface->extents.width, surface->extents.height), ++ img); ++ CGContextRestoreGState (surface->cgContext); ++ ++ cairo_surface_destroy (&tmp_surface->base); ++ } + } + + static cairo_surface_t * + _cairo_quartz_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) + { +- /*cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;*/ +- ++ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_format_t format; + ++ if (surface->cgLayer) ++ return cairo_quartz_surface_create_cg_layer (abstract_surface, width, height); ++ + if (content == CAIRO_CONTENT_COLOR_ALPHA) + format = CAIRO_FORMAT_ARGB32; + else if (content == CAIRO_CONTENT_COLOR) + format = CAIRO_FORMAT_RGB24; + else if (content == CAIRO_CONTENT_ALPHA) + format = CAIRO_FORMAT_A8; + else + return NULL; +@@ -2113,17 +2202,17 @@ _cairo_quartz_surface_clone_similar (voi + _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, + qsurf->extents.width, qsurf->extents.height); + *clone_offset_x = 0; + *clone_offset_y = 0; + return CAIRO_STATUS_SUCCESS; + } + } + +- status = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src, &quartz_image); ++ status = _cairo_surface_to_cgimage (src, &quartz_image); + if (status) + return CAIRO_INT_STATUS_UNSUPPORTED; + + new_format = CAIRO_FORMAT_ARGB32; /* assumed */ + if (_cairo_surface_is_image (src)) { + new_format = ((cairo_image_surface_t *) src)->format; + } + +@@ -2194,17 +2283,18 @@ _cairo_quartz_surface_paint (void *abstr + if (state.action == DO_SOLID || state.action == DO_PATTERN) { + CGContextFillRect (state.context, CGRectMake(surface->extents.x, + surface->extents.y, + surface->extents.width, + surface->extents.height)); + } else if (state.action == DO_SHADING) { + CGContextConcatCTM (state.context, state.transform); + CGContextDrawShading (state.context, state.shading); +- } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { ++ } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || ++ state.action == DO_LAYER) { + _cairo_quartz_draw_image (&state, op); + } else if (state.action != DO_NOTHING) { + rv = CAIRO_INT_STATUS_UNSUPPORTED; + } + + _cairo_quartz_teardown_state (&state); + + ND((stderr, "-- paint\n")); +@@ -2291,17 +2381,18 @@ _cairo_quartz_surface_fill (void *abstra + // with the shading + if (fill_rule == CAIRO_FILL_RULE_WINDING) + CGContextClip (state.context); + else + CGContextEOClip (state.context); + + CGContextConcatCTM (state.context, state.transform); + CGContextDrawShading (state.context, state.shading); +- } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { ++ } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || ++ state.action == DO_LAYER) { + if (fill_rule == CAIRO_FILL_RULE_WINDING) + CGContextClip (state.context); + else + CGContextEOClip (state.context); + + _cairo_quartz_draw_image (&state, op); + } else if (state.action != DO_NOTHING) { + rv = CAIRO_INT_STATUS_UNSUPPORTED; +@@ -2416,17 +2507,18 @@ _cairo_quartz_surface_stroke (void *abst + if (rv) + goto BAIL; + + if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr) + path_for_unbounded = CGContextCopyPathPtr (state.context); + + if (state.action == DO_SOLID || state.action == DO_PATTERN) { + CGContextStrokePath (state.context); +- } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { ++ } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || ++ state.action == DO_LAYER) { + CGContextReplacePathWithStrokedPath (state.context); + CGContextClip (state.context); + + CGContextSetCTM (state.context, origCTM); + _cairo_quartz_draw_image (&state, op); + } else if (state.action == DO_SHADING) { + CGContextReplacePathWithStrokedPath (state.context); + CGContextClip (state.context); +@@ -2511,17 +2603,18 @@ _cairo_quartz_surface_show_glyphs (void + &glyph_extents, NULL); + state = _cairo_quartz_setup_state (surface, source, op, &glyph_extents); + } else { + state = _cairo_quartz_setup_state (surface, source, op, NULL); + } + + if (state.action == DO_SOLID || state.action == DO_PATTERN) { + CGContextSetTextDrawingMode (state.context, kCGTextFill); +- } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || state.action == DO_SHADING) { ++ } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || ++ state.action == DO_SHADING || state.action == DO_LAYER) { + CGContextSetTextDrawingMode (state.context, kCGTextClip); + isClipping = TRUE; + } else { + if (state.action != DO_NOTHING) + rv = CAIRO_INT_STATUS_UNSUPPORTED; + goto BAIL; + } + +@@ -2622,17 +2715,18 @@ _cairo_quartz_surface_show_glyphs (void + + CGContextShowGlyphsWithAdvances (state.context, + cg_glyphs, + cg_advances, + num_glyphs); + + CGContextSetCTM (state.context, ctm); + +- if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { ++ if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || ++ state.action == DO_LAYER) { + _cairo_quartz_draw_image (&state, op); + } else if (state.action == DO_SHADING) { + CGContextConcatCTM (state.context, state.transform); + CGContextDrawShading (state.context, state.shading); + } + + BAIL: + if (didForceFontSmoothing) +@@ -2679,17 +2773,17 @@ _cairo_quartz_surface_mask_with_surface + cairo_clip_t *clip) + { + CGRect rect; + CGImageRef img; + cairo_surface_t *pat_surf = mask->surface; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + CGAffineTransform ctm, mask_matrix; + +- status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img); ++ status = _cairo_surface_to_cgimage (pat_surf, &img); + if (status) + return status; + if (img == NULL) { + if (!_cairo_operator_bounded_by_mask (op)) + CGContextClearRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext)); + return CAIRO_STATUS_SUCCESS; + } + +@@ -2869,17 +2963,17 @@ _cairo_quartz_surface_clipper_intersect_ + } + + // XXXtodo implement show_page; need to figure out how to handle begin/end + + static const struct _cairo_surface_backend cairo_quartz_surface_backend = { + CAIRO_SURFACE_TYPE_QUARTZ, + _cairo_quartz_surface_create_similar, + _cairo_quartz_surface_finish, +- _cairo_quartz_surface_acquire_source_image, ++ _cairo_quartz_surface_acquire_image, + _cairo_quartz_surface_release_source_image, + _cairo_quartz_surface_acquire_dest_image, + _cairo_quartz_surface_release_dest_image, + _cairo_quartz_surface_clone_similar, + NULL, /* composite */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ +@@ -2950,16 +3044,17 @@ _cairo_quartz_surface_create_internal (C + CGContextSaveGState (cgContext); + + surface->cgContext = cgContext; + surface->cgContextBaseCTM = CGContextGetCTM (cgContext); + + surface->imageData = NULL; + surface->imageSurfaceEquiv = NULL; + surface->bitmapContextImage = NULL; ++ surface->cgLayer = NULL; + + return surface; + } + + /** + * cairo_quartz_surface_create_for_cg_context + * @cgContext: the existing CGContext for which to create the surface + * @width: width of the surface, in pixels +@@ -3002,16 +3097,88 @@ cairo_quartz_surface_create_for_cg_conte + // create_internal will have set an error + return (cairo_surface_t*) surf; + } + + return (cairo_surface_t *) surf; + } + + /** ++ * cairo_quartz_cglayer_surface_create_similar ++ * @surface: The returned surface can be efficiently drawn into this ++ * destination surface (if tiling is not used)." ++ * @width: width of the surface, in pixels ++ * @height: height of the surface, in pixels ++ * ++ * Creates a Quartz surface backed by a CGLayer, if the given surface ++ * is a Quartz surface; the CGLayer is created to match the surface's ++ * Quartz context. Otherwise just calls cairo_surface_create_similar ++ * with CAIRO_CONTENT_COLOR_ALPHA. ++ * The returned surface can be efficiently blitted to the given surface, ++ * but tiling and 'extend' modes other than NONE are not so efficient. ++ * ++ * Return value: the newly created surface. ++ * ++ * Since: 1.10 ++ **/ ++cairo_surface_t * ++cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface, ++ unsigned int width, ++ unsigned int height) ++{ ++ cairo_quartz_surface_t *surf; ++ CGLayerRef layer; ++ CGContextRef ctx; ++ CGContextRef cgContext; ++ ++ cgContext = cairo_quartz_surface_get_cg_context (surface); ++ if (!cgContext) ++ return cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA, ++ width, height); ++ ++ if (!_cairo_quartz_verify_surface_size(width, height)) ++ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); ++ ++ /* If we pass zero width or height into CGLayerCreateWithContext below, ++ * it will fail. ++ */ ++ if (width == 0 || height == 0) { ++ return (cairo_surface_t*) ++ _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, ++ width, height); ++ } ++ ++ layer = CGLayerCreateWithContext (cgContext, ++ CGSizeMake (width, height), ++ NULL); ++ if (!layer) ++ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); ++ ++ ctx = CGLayerGetContext (layer); ++ /* Flip it when we draw into it, so that when we finally composite it ++ * to a flipped target, the directions match and Quartz will optimize ++ * the composition properly ++ */ ++ CGContextTranslateCTM (ctx, 0, height); ++ CGContextScaleCTM (ctx, 1, -1); ++ ++ CGContextRetain (ctx); ++ surf = _cairo_quartz_surface_create_internal (ctx, CAIRO_CONTENT_COLOR_ALPHA, ++ width, height); ++ if (surf->base.status) { ++ CGLayerRelease (layer); ++ // create_internal will have set an error ++ return (cairo_surface_t*) surf; ++ } ++ surf->cgLayer = layer; ++ ++ return (cairo_surface_t *) surf; ++} ++ ++/** + * cairo_quartz_surface_create + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a Quartz surface backed by a CGBitmap. The surface is + * created using the Device RGB (or Device Gray, for A8) color space. + * All Cairo operations, including those that require software +diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h +--- a/gfx/cairo/cairo/src/cairo-quartz.h ++++ b/gfx/cairo/cairo/src/cairo-quartz.h +@@ -45,16 +45,21 @@ + CAIRO_BEGIN_DECLS + + cairo_public cairo_surface_t * + cairo_quartz_surface_create (cairo_format_t format, + unsigned int width, + unsigned int height); + + cairo_public cairo_surface_t * ++cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface, ++ unsigned int width, ++ unsigned int height); ++ ++cairo_public cairo_surface_t * + cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, + unsigned int width, + unsigned int height); + + cairo_public CGContextRef + cairo_quartz_surface_get_cg_context (cairo_surface_t *surface); + + cairo_public CGContextRef + |