1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
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);
|