gecko-dev/gfx/cairo/13-quartz-cglayer-surface.patch
Jonathan Kew 64df3d06dc Bug 1803059 - Remove obsolete patch files from gfx/cairo, and create patch files to record locally-applied fixes. r=gfx-reviewers,lsalzman DONTBUILD
When we did the major cairo update in bug 739096, most of our old patch files were superseded
and no longer relevant, but I failed to clean them up at the time. So here, we remove all the
old patch files, and create new ones just for the fixes we've applied on top of the new code
from upstream.

I've omitted patch files for fixes that I am aware have already landed upstream, as those will
automatically be included in any future update we take. (It's possible more of the new patch
files will also be obsolete by the time we try pulling a new version, but at least they should
provide a starting point.)

Differential Revision: https://phabricator.services.mozilla.com/D164680
2022-12-14 16:18:01 +00:00

254 lines
9.4 KiB
Diff

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
@@ -55,7 +55,8 @@ typedef enum {
DO_DIRECT,
DO_SHADING,
DO_IMAGE,
- DO_TILED_IMAGE
+ DO_TILED_IMAGE,
+ DO_LAYER
} cairo_quartz_action_t;
/* define CTFontRef for pre-10.5 SDKs */
@@ -72,6 +73,11 @@ typedef struct cairo_quartz_surface {
cairo_surface_clipper_t clipper;
+ /**
+ * If non-null, this is the CGLayer for the surface.
+ */
+ CGLayerRef cgLayer;
+
cairo_rectangle_int_t extents;
cairo_rectangle_int_t virtual_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
@@ -503,6 +503,7 @@ static CGBlendMode
default:
ASSERT_NOT_REACHED;
}
+ return kCGBlendModeNormal; /* just to silence clang warning [-Wreturn-type] */
}
static cairo_int_status_t
@@ -1065,7 +1066,7 @@ typedef struct {
/* Destination rect */
CGRect rect;
- /* Used with DO_SHADING, DO_IMAGE and DO_TILED_IMAGE */
+ /* Used with DO_SHADING, DO_IMAGE, DO_TILED_IMAGE, DO_LAYER */
CGAffineTransform transform;
/* Used with DO_IMAGE and DO_TILED_IMAGE */
@@ -1077,6 +1078,11 @@ typedef struct {
/* Temporary destination for unbounded operations */
CGLayerRef layer;
CGRect clipRect;
+
+ /* Source layer to be rendered when using DO_LAYER.
+ Unlike 'layer' above, this is not owned by the drawing state
+ but by the source surface. */
+ CGLayerRef sourceLayer;
} cairo_quartz_drawing_state_t;
/*
@@ -1253,7 +1259,9 @@ static cairo_int_status_t
}
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
- (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
+ (source->extend == CAIRO_EXTEND_NONE ||
+ source->extend == CAIRO_EXTEND_PAD ||
+ (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
{
const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source;
cairo_surface_t *pat_surf = spat->surface;
@@ -1265,6 +1273,20 @@ static cairo_int_status_t
cairo_fixed_t fw, fh;
cairo_bool_t is_bounded;
+ /* Draw nonrepeating CGLayer surface using DO_LAYER */
+ if (source->extend != CAIRO_EXTEND_REPEAT &&
+ 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) {
+ cairo_matrix_invert(&m);
+ _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform);
+ state->rect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height);
+ state->sourceLayer = quartz_surf->cgLayer;
+ state->action = DO_LAYER;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
_cairo_surface_get_extents (composite->surface, &extents);
status = _cairo_surface_to_cgimage (pat_surf, &extents, format,
&m, clip, &img);
@@ -1426,7 +1448,14 @@ static void
CGContextTranslateCTM (state->cgDrawContext, 0, state->rect.size.height);
CGContextScaleCTM (state->cgDrawContext, 1, -1);
- if (state->action == DO_IMAGE) {
+ 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.
+ */
+ assert (state->sourceLayer);
+ CGContextDrawLayerAtPoint (state->cgDrawContext, state->rect.origin,
+ state->sourceLayer);
+ } else if (state->action == DO_IMAGE) {
CGContextDrawImage (state->cgDrawContext, state->rect, state->image);
if (op == CAIRO_OPERATOR_SOURCE &&
state->cgDrawContext == state->cgMaskContext)
@@ -1655,6 +1684,10 @@ static cairo_status_t
surface->imageData = NULL;
+ if (surface->cgLayer) {
+ CGLayerRelease (surface->cgLayer);
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1693,9 +1726,14 @@ static cairo_surface_t *
int width,
int height)
{
- cairo_quartz_surface_t *surface, *similar_quartz;
+ cairo_quartz_surface_t *similar_quartz;
cairo_surface_t *similar;
cairo_format_t format;
+ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+
+ if (surface->cgLayer)
+ return cairo_quartz_surface_create_cg_layer (abstract_surface, content,
+ width, height);
if (content == CAIRO_CONTENT_COLOR_ALPHA)
format = CAIRO_FORMAT_ARGB32;
@@ -2068,7 +2106,6 @@ static cairo_int_status_t
cairo_quartz_drawing_state_t state;
cairo_int_status_t rv = CAIRO_INT_STATUS_UNSUPPORTED;
int i;
- CGFontRef cgfref = NULL;
cairo_bool_t didForceFontSmoothing = FALSE;
cairo_antialias_t effective_antialiasing;
@@ -2087,10 +2124,12 @@ static cairo_int_status_t
CGContextSetTextDrawingMode (state.cgMaskContext, kCGTextClip);
}
- /* this doesn't addref */
- cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font);
- CGContextSetFont (state.cgMaskContext, cgfref);
- CGContextSetFontSize (state.cgMaskContext, 1.0);
+ if (!CTFontDrawGlyphsPtr) {
+ /* this doesn't addref */
+ CGFontRef cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font);
+ CGContextSetFont (state.cgMaskContext, cgfref);
+ CGContextSetFontSize (state.cgMaskContext, 1.0);
+ }
effective_antialiasing = scaled_font->options.antialias;
if (effective_antialiasing == CAIRO_ANTIALIAS_SUBPIXEL &&
@@ -2625,6 +2664,79 @@ cairo_quartz_surface_create_for_cg_conte
}
/**
+ * cairo_quartz_surface_create_cg_layer
+ * @surface: The returned surface can be efficiently drawn into this
+ * destination surface (if tiling is not used)."
+ * @content: the content type of the surface
+ * @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.
+ * 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,
+ cairo_content_t content,
+ 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, content,
+ 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, content,
+ 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, content,
+ 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
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
@@ -61,6 +61,12 @@ cairo_quartz_surface_create_for_data (un
unsigned int height,
unsigned int stride);
+cairo_public cairo_surface_t *
+cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface,
+ cairo_content_t content,
+ unsigned int width,
+ unsigned int height);
+
cairo_public CGContextRef
cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);