mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
716 lines
25 KiB
Diff
716 lines
25 KiB
Diff
|
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
|
||
|
|