|
1 changeset: 42959:e1964291f8ff |
|
2 user: Robert O'Callahan <robert@ocallahan.org> |
|
3 date: Tue Jun 01 11:33:23 2010 +1200 |
|
4 summary: Bug 568189. Implement CGLayer-backed cairo-quartz surfaces. r=jrmuizel |
|
5 |
|
6 diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h |
|
7 --- a/gfx/cairo/cairo/src/cairo-quartz-private.h |
|
8 +++ b/gfx/cairo/cairo/src/cairo-quartz-private.h |
|
9 @@ -57,16 +57,21 @@ typedef struct cairo_quartz_surface { |
|
10 |
|
11 /** |
|
12 * If non-null, this is a CGImage representing the contents of the surface. |
|
13 * We clear this out before any painting into the surface, so that we |
|
14 * don't force a copy to be created. |
|
15 */ |
|
16 CGImageRef bitmapContextImage; |
|
17 |
|
18 + /** |
|
19 + * If non-null, this is the CGLayer for the surface. |
|
20 + */ |
|
21 + CGLayerRef cgLayer; |
|
22 + |
|
23 cairo_rectangle_int_t extents; |
|
24 } cairo_quartz_surface_t; |
|
25 |
|
26 typedef struct cairo_quartz_image_surface { |
|
27 cairo_surface_t base; |
|
28 |
|
29 cairo_rectangle_int_t extents; |
|
30 |
|
31 diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c |
|
32 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c |
|
33 +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c |
|
34 @@ -1110,18 +1110,17 @@ CreateRepeatingRadialGradientFunction (c |
|
35 static void |
|
36 DataProviderReleaseCallback (void *info, const void *data, size_t size) |
|
37 { |
|
38 cairo_surface_t *surface = (cairo_surface_t *) info; |
|
39 cairo_surface_destroy (surface); |
|
40 } |
|
41 |
|
42 static cairo_status_t |
|
43 -_cairo_surface_to_cgimage (cairo_surface_t *target, |
|
44 - cairo_surface_t *source, |
|
45 +_cairo_surface_to_cgimage (cairo_surface_t *source, |
|
46 CGImageRef *image_out) |
|
47 { |
|
48 cairo_status_t status = CAIRO_STATUS_SUCCESS; |
|
49 cairo_surface_type_t stype = cairo_surface_get_type (source); |
|
50 cairo_image_surface_t *isurf; |
|
51 CGImageRef image; |
|
52 void *image_extra; |
|
53 |
|
54 @@ -1267,17 +1266,17 @@ _cairo_quartz_cairo_repeating_surface_pa |
|
55 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
56 |
|
57 spattern = (cairo_surface_pattern_t *) apattern; |
|
58 pat_surf = spattern->surface; |
|
59 |
|
60 is_bounded = _cairo_surface_get_extents (pat_surf, &extents); |
|
61 assert (is_bounded); |
|
62 |
|
63 - status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image); |
|
64 + status = _cairo_surface_to_cgimage (pat_surf, &image); |
|
65 if (status) |
|
66 return status; |
|
67 if (image == NULL) |
|
68 return CAIRO_INT_STATUS_NOTHING_TO_DO; |
|
69 |
|
70 info = malloc(sizeof(SurfacePatternDrawInfo)); |
|
71 if (!info) |
|
72 return CAIRO_STATUS_NO_MEMORY; |
|
73 @@ -1339,33 +1338,39 @@ _cairo_quartz_cairo_repeating_surface_pa |
|
74 } |
|
75 |
|
76 typedef enum { |
|
77 DO_SOLID, |
|
78 DO_SHADING, |
|
79 DO_PATTERN, |
|
80 DO_IMAGE, |
|
81 DO_TILED_IMAGE, |
|
82 + DO_LAYER, |
|
83 DO_UNSUPPORTED, |
|
84 DO_NOTHING |
|
85 } cairo_quartz_action_t; |
|
86 |
|
87 /* State used during a drawing operation. */ |
|
88 typedef struct { |
|
89 CGContextRef context; |
|
90 cairo_quartz_action_t action; |
|
91 |
|
92 - // Used with DO_SHADING, DO_IMAGE and DO_TILED_IMAGE |
|
93 + // Used with DO_SHADING, DO_IMAGE, DO_TILED_IMAGE and DO_LAYER |
|
94 CGAffineTransform transform; |
|
95 |
|
96 // Used with DO_IMAGE and DO_TILED_IMAGE |
|
97 CGImageRef image; |
|
98 cairo_surface_t *imageSurface; |
|
99 + |
|
100 + // Used with DO_IMAGE, DO_TILED_IMAGE and DO_LAYER |
|
101 CGRect imageRect; |
|
102 |
|
103 + // Used with DO_LAYER |
|
104 + CGLayerRef layer; |
|
105 + |
|
106 // Used with DO_SHADING |
|
107 CGShadingRef shading; |
|
108 |
|
109 // Used with DO_PATTERN |
|
110 CGPatternRef pattern; |
|
111 } cairo_quartz_drawing_state_t; |
|
112 |
|
113 static void |
|
114 @@ -1423,17 +1428,17 @@ _cairo_quartz_setup_fallback_source (cai |
|
115 _cairo_pattern_transform (&pattern.base, |
|
116 &fallback->device_transform_inverse); |
|
117 status = _cairo_surface_paint (fallback, |
|
118 CAIRO_OPERATOR_SOURCE, |
|
119 &pattern.base, NULL); |
|
120 } |
|
121 #endif |
|
122 |
|
123 - status = _cairo_surface_to_cgimage (&surface->base, fallback, &img); |
|
124 + status = _cairo_surface_to_cgimage (fallback, &img); |
|
125 if (status) { |
|
126 state->action = DO_UNSUPPORTED; |
|
127 return; |
|
128 } |
|
129 if (img == NULL) { |
|
130 state->action = DO_NOTHING; |
|
131 return; |
|
132 } |
|
133 @@ -1624,16 +1629,17 @@ _cairo_quartz_setup_state (cairo_quartz_ |
|
134 { |
|
135 CGContextRef context = surface->cgContext; |
|
136 cairo_quartz_drawing_state_t state; |
|
137 cairo_status_t status; |
|
138 |
|
139 state.context = context; |
|
140 state.image = NULL; |
|
141 state.imageSurface = NULL; |
|
142 + state.layer = NULL; |
|
143 state.shading = NULL; |
|
144 state.pattern = NULL; |
|
145 |
|
146 _cairo_quartz_surface_will_change (surface); |
|
147 |
|
148 // Save before we change the pattern, colorspace, etc. so that |
|
149 // we can restore and make sure that quartz releases our |
|
150 // pattern (which may be stack allocated) |
|
151 @@ -1689,33 +1695,43 @@ _cairo_quartz_setup_state (cairo_quartz_ |
|
152 CGImageRef img; |
|
153 cairo_matrix_t m = spat->base.matrix; |
|
154 cairo_rectangle_int_t extents; |
|
155 CGAffineTransform xform; |
|
156 CGRect srcRect; |
|
157 cairo_fixed_t fw, fh; |
|
158 cairo_bool_t is_bounded; |
|
159 |
|
160 - status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img); |
|
161 + cairo_matrix_invert(&m); |
|
162 + _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); |
|
163 + |
|
164 + if (cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { |
|
165 + cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; |
|
166 + if (quartz_surf->cgLayer && source->extend == CAIRO_EXTEND_NONE) { |
|
167 + state.imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); |
|
168 + state.layer = quartz_surf->cgLayer; |
|
169 + state.action = DO_LAYER; |
|
170 + return state; |
|
171 + } |
|
172 + } |
|
173 + |
|
174 + status = _cairo_surface_to_cgimage (pat_surf, &img); |
|
175 if (status) { |
|
176 state.action = DO_UNSUPPORTED; |
|
177 return state; |
|
178 } |
|
179 if (img == NULL) { |
|
180 state.action = DO_NOTHING; |
|
181 return state; |
|
182 } |
|
183 |
|
184 CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); |
|
185 |
|
186 state.image = img; |
|
187 |
|
188 - cairo_matrix_invert(&m); |
|
189 - _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); |
|
190 - |
|
191 is_bounded = _cairo_surface_get_extents (pat_surf, &extents); |
|
192 assert (is_bounded); |
|
193 |
|
194 if (source->extend == CAIRO_EXTEND_NONE) { |
|
195 state.imageRect = CGRectMake (0, 0, extents.width, extents.height); |
|
196 state.action = DO_IMAGE; |
|
197 return state; |
|
198 } |
|
199 @@ -1820,33 +1836,48 @@ _cairo_quartz_teardown_state (cairo_quar |
|
200 |
|
201 CGContextRestoreGState(state->context); |
|
202 } |
|
203 |
|
204 |
|
205 static void |
|
206 _cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state, cairo_operator_t op) |
|
207 { |
|
208 - assert (state && state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)); |
|
209 + assert (state && |
|
210 + ((state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)) || |
|
211 + (state->layer && state->action == DO_LAYER))); |
|
212 |
|
213 CGContextConcatCTM (state->context, state->transform); |
|
214 CGContextTranslateCTM (state->context, 0, state->imageRect.size.height); |
|
215 CGContextScaleCTM (state->context, 1, -1); |
|
216 |
|
217 - if (state->action == DO_IMAGE) { |
|
218 - CGContextDrawImage (state->context, state->imageRect, state->image); |
|
219 + if (state->action == DO_TILED_IMAGE) { |
|
220 + CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image); |
|
221 + /* no need to worry about unbounded operators, since tiled images |
|
222 + fill the entire clip region */ |
|
223 + } else { |
|
224 + if (state->action == DO_LAYER) { |
|
225 + /* Note that according to Apple docs it's completely legal |
|
226 + * to draw a CGLayer to any CGContext, even one it wasn't |
|
227 + * created for. |
|
228 + */ |
|
229 + CGContextDrawLayerAtPoint (state->context, state->imageRect.origin, |
|
230 + state->layer); |
|
231 + } else { |
|
232 + CGContextDrawImage (state->context, state->imageRect, state->image); |
|
233 + } |
|
234 + |
|
235 if (!_cairo_operator_bounded_by_source (op)) { |
|
236 CGContextBeginPath (state->context); |
|
237 CGContextAddRect (state->context, state->imageRect); |
|
238 CGContextAddRect (state->context, CGContextGetClipBoundingBox (state->context)); |
|
239 CGContextSetRGBFillColor (state->context, 0, 0, 0, 0); |
|
240 CGContextEOFillPath (state->context); |
|
241 } |
|
242 - } else |
|
243 - CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image); |
|
244 + } |
|
245 } |
|
246 |
|
247 |
|
248 /* |
|
249 * get source/dest image implementation |
|
250 */ |
|
251 |
|
252 /* Read the image from the surface's front buffer */ |
|
253 @@ -1971,95 +2002,153 @@ _cairo_quartz_surface_finish (void *abst |
|
254 surface->imageSurfaceEquiv = NULL; |
|
255 } |
|
256 |
|
257 if (surface->imageData) { |
|
258 free (surface->imageData); |
|
259 surface->imageData = NULL; |
|
260 } |
|
261 |
|
262 + if (surface->cgLayer) { |
|
263 + CGLayerRelease (surface->cgLayer); |
|
264 + } |
|
265 + |
|
266 return CAIRO_STATUS_SUCCESS; |
|
267 } |
|
268 |
|
269 static cairo_status_t |
|
270 -_cairo_quartz_surface_acquire_source_image (void *abstract_surface, |
|
271 - cairo_image_surface_t **image_out, |
|
272 - void **image_extra) |
|
273 +_cairo_quartz_surface_acquire_image (void *abstract_surface, |
|
274 + cairo_image_surface_t **image_out, |
|
275 + void **image_extra) |
|
276 { |
|
277 cairo_int_status_t status; |
|
278 cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; |
|
279 |
|
280 - //ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface)); |
|
281 + *image_extra = NULL; |
|
282 + |
|
283 + /* ND((stderr, "%p _cairo_quartz_surface_acquire_image\n", surface)); */ |
|
284 |
|
285 status = _cairo_quartz_get_image (surface, image_out); |
|
286 + |
|
287 + if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->cgLayer) { |
|
288 + /* copy the layer into a Quartz bitmap context so we can get the data */ |
|
289 + cairo_surface_t *tmp = |
|
290 + cairo_quartz_surface_create (CAIRO_CONTENT_COLOR_ALPHA, |
|
291 + surface->extents.width, |
|
292 + surface->extents.height); |
|
293 + cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) tmp; |
|
294 + |
|
295 + /* if surface creation failed, we won't have a Quartz surface here */ |
|
296 + if (cairo_surface_get_type (tmp) == CAIRO_SURFACE_TYPE_QUARTZ && |
|
297 + tmp_surface->imageSurfaceEquiv) { |
|
298 + CGContextSaveGState (tmp_surface->cgContext); |
|
299 + CGContextTranslateCTM (tmp_surface->cgContext, 0, surface->extents.height); |
|
300 + CGContextScaleCTM (tmp_surface->cgContext, 1, -1); |
|
301 + /* Note that according to Apple docs it's completely legal |
|
302 + * to draw a CGLayer to any CGContext, even one it wasn't |
|
303 + * created for. |
|
304 + */ |
|
305 + CGContextDrawLayerAtPoint (tmp_surface->cgContext, |
|
306 + CGPointMake (0.0, 0.0), |
|
307 + surface->cgLayer); |
|
308 + CGContextRestoreGState (tmp_surface->cgContext); |
|
309 + |
|
310 + *image_out = (cairo_image_surface_t*) |
|
311 + cairo_surface_reference(tmp_surface->imageSurfaceEquiv); |
|
312 + *image_extra = tmp; |
|
313 + } else { |
|
314 + cairo_surface_destroy (tmp); |
|
315 + } |
|
316 + } |
|
317 + |
|
318 if (status) |
|
319 return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
320 |
|
321 - *image_extra = NULL; |
|
322 - |
|
323 return CAIRO_STATUS_SUCCESS; |
|
324 } |
|
325 |
|
326 static void |
|
327 _cairo_quartz_surface_release_source_image (void *abstract_surface, |
|
328 cairo_image_surface_t *image, |
|
329 void *image_extra) |
|
330 { |
|
331 cairo_surface_destroy ((cairo_surface_t *) image); |
|
332 + |
|
333 + if (image_extra) { |
|
334 + cairo_surface_destroy ((cairo_surface_t *) image_extra); |
|
335 + } |
|
336 } |
|
337 |
|
338 |
|
339 static cairo_status_t |
|
340 _cairo_quartz_surface_acquire_dest_image (void *abstract_surface, |
|
341 cairo_rectangle_int_t *interest_rect, |
|
342 cairo_image_surface_t **image_out, |
|
343 cairo_rectangle_int_t *image_rect, |
|
344 void **image_extra) |
|
345 { |
|
346 cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; |
|
347 - cairo_int_status_t status; |
|
348 |
|
349 ND((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface)); |
|
350 |
|
351 - _cairo_quartz_surface_will_change (surface); |
|
352 - |
|
353 - status = _cairo_quartz_get_image (surface, image_out); |
|
354 - if (status) |
|
355 - return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
356 - |
|
357 *image_rect = surface->extents; |
|
358 *image_extra = NULL; |
|
359 |
|
360 - return CAIRO_STATUS_SUCCESS; |
|
361 + _cairo_quartz_surface_will_change (surface); |
|
362 + |
|
363 + return _cairo_quartz_surface_acquire_image (abstract_surface, |
|
364 + image_out, image_extra); |
|
365 } |
|
366 |
|
367 static void |
|
368 _cairo_quartz_surface_release_dest_image (void *abstract_surface, |
|
369 cairo_rectangle_int_t *interest_rect, |
|
370 cairo_image_surface_t *image, |
|
371 cairo_rectangle_int_t *image_rect, |
|
372 void *image_extra) |
|
373 { |
|
374 - //cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; |
|
375 - |
|
376 - //ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface)); |
|
377 + /* ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface)); */ |
|
378 |
|
379 cairo_surface_destroy ((cairo_surface_t *) image); |
|
380 + |
|
381 + if (image_extra) { |
|
382 + /* we need to write the data from the temp surface back to the layer */ |
|
383 + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; |
|
384 + cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) image_extra; |
|
385 + CGImageRef img; |
|
386 + cairo_status_t status = _cairo_surface_to_cgimage (&tmp_surface->base, &img); |
|
387 + if (status) { |
|
388 + cairo_surface_destroy (&tmp_surface->base); |
|
389 + return; |
|
390 + } |
|
391 + |
|
392 + CGContextSaveGState (surface->cgContext); |
|
393 + CGContextTranslateCTM (surface->cgContext, 0, surface->extents.height); |
|
394 + CGContextScaleCTM (surface->cgContext, 1, -1); |
|
395 + CGContextDrawImage (surface->cgContext, |
|
396 + CGRectMake (0.0, 0.0, surface->extents.width, surface->extents.height), |
|
397 + img); |
|
398 + CGContextRestoreGState (surface->cgContext); |
|
399 + |
|
400 + cairo_surface_destroy (&tmp_surface->base); |
|
401 + } |
|
402 } |
|
403 |
|
404 static cairo_surface_t * |
|
405 _cairo_quartz_surface_create_similar (void *abstract_surface, |
|
406 cairo_content_t content, |
|
407 int width, |
|
408 int height) |
|
409 { |
|
410 - /*cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;*/ |
|
411 - |
|
412 + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; |
|
413 cairo_format_t format; |
|
414 |
|
415 + if (surface->cgLayer) |
|
416 + return cairo_quartz_surface_create_cg_layer (abstract_surface, width, height); |
|
417 + |
|
418 if (content == CAIRO_CONTENT_COLOR_ALPHA) |
|
419 format = CAIRO_FORMAT_ARGB32; |
|
420 else if (content == CAIRO_CONTENT_COLOR) |
|
421 format = CAIRO_FORMAT_RGB24; |
|
422 else if (content == CAIRO_CONTENT_ALPHA) |
|
423 format = CAIRO_FORMAT_A8; |
|
424 else |
|
425 return NULL; |
|
426 @@ -2113,17 +2202,17 @@ _cairo_quartz_surface_clone_similar (voi |
|
427 _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, |
|
428 qsurf->extents.width, qsurf->extents.height); |
|
429 *clone_offset_x = 0; |
|
430 *clone_offset_y = 0; |
|
431 return CAIRO_STATUS_SUCCESS; |
|
432 } |
|
433 } |
|
434 |
|
435 - status = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src, &quartz_image); |
|
436 + status = _cairo_surface_to_cgimage (src, &quartz_image); |
|
437 if (status) |
|
438 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
439 |
|
440 new_format = CAIRO_FORMAT_ARGB32; /* assumed */ |
|
441 if (_cairo_surface_is_image (src)) { |
|
442 new_format = ((cairo_image_surface_t *) src)->format; |
|
443 } |
|
444 |
|
445 @@ -2194,17 +2283,18 @@ _cairo_quartz_surface_paint (void *abstr |
|
446 if (state.action == DO_SOLID || state.action == DO_PATTERN) { |
|
447 CGContextFillRect (state.context, CGRectMake(surface->extents.x, |
|
448 surface->extents.y, |
|
449 surface->extents.width, |
|
450 surface->extents.height)); |
|
451 } else if (state.action == DO_SHADING) { |
|
452 CGContextConcatCTM (state.context, state.transform); |
|
453 CGContextDrawShading (state.context, state.shading); |
|
454 - } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { |
|
455 + } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || |
|
456 + state.action == DO_LAYER) { |
|
457 _cairo_quartz_draw_image (&state, op); |
|
458 } else if (state.action != DO_NOTHING) { |
|
459 rv = CAIRO_INT_STATUS_UNSUPPORTED; |
|
460 } |
|
461 |
|
462 _cairo_quartz_teardown_state (&state); |
|
463 |
|
464 ND((stderr, "-- paint\n")); |
|
465 @@ -2291,17 +2381,18 @@ _cairo_quartz_surface_fill (void *abstra |
|
466 // with the shading |
|
467 if (fill_rule == CAIRO_FILL_RULE_WINDING) |
|
468 CGContextClip (state.context); |
|
469 else |
|
470 CGContextEOClip (state.context); |
|
471 |
|
472 CGContextConcatCTM (state.context, state.transform); |
|
473 CGContextDrawShading (state.context, state.shading); |
|
474 - } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { |
|
475 + } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || |
|
476 + state.action == DO_LAYER) { |
|
477 if (fill_rule == CAIRO_FILL_RULE_WINDING) |
|
478 CGContextClip (state.context); |
|
479 else |
|
480 CGContextEOClip (state.context); |
|
481 |
|
482 _cairo_quartz_draw_image (&state, op); |
|
483 } else if (state.action != DO_NOTHING) { |
|
484 rv = CAIRO_INT_STATUS_UNSUPPORTED; |
|
485 @@ -2416,17 +2507,18 @@ _cairo_quartz_surface_stroke (void *abst |
|
486 if (rv) |
|
487 goto BAIL; |
|
488 |
|
489 if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr) |
|
490 path_for_unbounded = CGContextCopyPathPtr (state.context); |
|
491 |
|
492 if (state.action == DO_SOLID || state.action == DO_PATTERN) { |
|
493 CGContextStrokePath (state.context); |
|
494 - } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { |
|
495 + } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || |
|
496 + state.action == DO_LAYER) { |
|
497 CGContextReplacePathWithStrokedPath (state.context); |
|
498 CGContextClip (state.context); |
|
499 |
|
500 CGContextSetCTM (state.context, origCTM); |
|
501 _cairo_quartz_draw_image (&state, op); |
|
502 } else if (state.action == DO_SHADING) { |
|
503 CGContextReplacePathWithStrokedPath (state.context); |
|
504 CGContextClip (state.context); |
|
505 @@ -2511,17 +2603,18 @@ _cairo_quartz_surface_show_glyphs (void |
|
506 &glyph_extents, NULL); |
|
507 state = _cairo_quartz_setup_state (surface, source, op, &glyph_extents); |
|
508 } else { |
|
509 state = _cairo_quartz_setup_state (surface, source, op, NULL); |
|
510 } |
|
511 |
|
512 if (state.action == DO_SOLID || state.action == DO_PATTERN) { |
|
513 CGContextSetTextDrawingMode (state.context, kCGTextFill); |
|
514 - } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || state.action == DO_SHADING) { |
|
515 + } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || |
|
516 + state.action == DO_SHADING || state.action == DO_LAYER) { |
|
517 CGContextSetTextDrawingMode (state.context, kCGTextClip); |
|
518 isClipping = TRUE; |
|
519 } else { |
|
520 if (state.action != DO_NOTHING) |
|
521 rv = CAIRO_INT_STATUS_UNSUPPORTED; |
|
522 goto BAIL; |
|
523 } |
|
524 |
|
525 @@ -2622,17 +2715,18 @@ _cairo_quartz_surface_show_glyphs (void |
|
526 |
|
527 CGContextShowGlyphsWithAdvances (state.context, |
|
528 cg_glyphs, |
|
529 cg_advances, |
|
530 num_glyphs); |
|
531 |
|
532 CGContextSetCTM (state.context, ctm); |
|
533 |
|
534 - if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { |
|
535 + if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || |
|
536 + state.action == DO_LAYER) { |
|
537 _cairo_quartz_draw_image (&state, op); |
|
538 } else if (state.action == DO_SHADING) { |
|
539 CGContextConcatCTM (state.context, state.transform); |
|
540 CGContextDrawShading (state.context, state.shading); |
|
541 } |
|
542 |
|
543 BAIL: |
|
544 if (didForceFontSmoothing) |
|
545 @@ -2679,17 +2773,17 @@ _cairo_quartz_surface_mask_with_surface |
|
546 cairo_clip_t *clip) |
|
547 { |
|
548 CGRect rect; |
|
549 CGImageRef img; |
|
550 cairo_surface_t *pat_surf = mask->surface; |
|
551 cairo_status_t status = CAIRO_STATUS_SUCCESS; |
|
552 CGAffineTransform ctm, mask_matrix; |
|
553 |
|
554 - status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img); |
|
555 + status = _cairo_surface_to_cgimage (pat_surf, &img); |
|
556 if (status) |
|
557 return status; |
|
558 if (img == NULL) { |
|
559 if (!_cairo_operator_bounded_by_mask (op)) |
|
560 CGContextClearRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext)); |
|
561 return CAIRO_STATUS_SUCCESS; |
|
562 } |
|
563 |
|
564 @@ -2869,17 +2963,17 @@ _cairo_quartz_surface_clipper_intersect_ |
|
565 } |
|
566 |
|
567 // XXXtodo implement show_page; need to figure out how to handle begin/end |
|
568 |
|
569 static const struct _cairo_surface_backend cairo_quartz_surface_backend = { |
|
570 CAIRO_SURFACE_TYPE_QUARTZ, |
|
571 _cairo_quartz_surface_create_similar, |
|
572 _cairo_quartz_surface_finish, |
|
573 - _cairo_quartz_surface_acquire_source_image, |
|
574 + _cairo_quartz_surface_acquire_image, |
|
575 _cairo_quartz_surface_release_source_image, |
|
576 _cairo_quartz_surface_acquire_dest_image, |
|
577 _cairo_quartz_surface_release_dest_image, |
|
578 _cairo_quartz_surface_clone_similar, |
|
579 NULL, /* composite */ |
|
580 NULL, /* fill_rectangles */ |
|
581 NULL, /* composite_trapezoids */ |
|
582 NULL, /* create_span_renderer */ |
|
583 @@ -2950,16 +3044,17 @@ _cairo_quartz_surface_create_internal (C |
|
584 CGContextSaveGState (cgContext); |
|
585 |
|
586 surface->cgContext = cgContext; |
|
587 surface->cgContextBaseCTM = CGContextGetCTM (cgContext); |
|
588 |
|
589 surface->imageData = NULL; |
|
590 surface->imageSurfaceEquiv = NULL; |
|
591 surface->bitmapContextImage = NULL; |
|
592 + surface->cgLayer = NULL; |
|
593 |
|
594 return surface; |
|
595 } |
|
596 |
|
597 /** |
|
598 * cairo_quartz_surface_create_for_cg_context |
|
599 * @cgContext: the existing CGContext for which to create the surface |
|
600 * @width: width of the surface, in pixels |
|
601 @@ -3002,16 +3097,88 @@ cairo_quartz_surface_create_for_cg_conte |
|
602 // create_internal will have set an error |
|
603 return (cairo_surface_t*) surf; |
|
604 } |
|
605 |
|
606 return (cairo_surface_t *) surf; |
|
607 } |
|
608 |
|
609 /** |
|
610 + * cairo_quartz_cglayer_surface_create_similar |
|
611 + * @surface: The returned surface can be efficiently drawn into this |
|
612 + * destination surface (if tiling is not used)." |
|
613 + * @width: width of the surface, in pixels |
|
614 + * @height: height of the surface, in pixels |
|
615 + * |
|
616 + * Creates a Quartz surface backed by a CGLayer, if the given surface |
|
617 + * is a Quartz surface; the CGLayer is created to match the surface's |
|
618 + * Quartz context. Otherwise just calls cairo_surface_create_similar |
|
619 + * with CAIRO_CONTENT_COLOR_ALPHA. |
|
620 + * The returned surface can be efficiently blitted to the given surface, |
|
621 + * but tiling and 'extend' modes other than NONE are not so efficient. |
|
622 + * |
|
623 + * Return value: the newly created surface. |
|
624 + * |
|
625 + * Since: 1.10 |
|
626 + **/ |
|
627 +cairo_surface_t * |
|
628 +cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface, |
|
629 + unsigned int width, |
|
630 + unsigned int height) |
|
631 +{ |
|
632 + cairo_quartz_surface_t *surf; |
|
633 + CGLayerRef layer; |
|
634 + CGContextRef ctx; |
|
635 + CGContextRef cgContext; |
|
636 + |
|
637 + cgContext = cairo_quartz_surface_get_cg_context (surface); |
|
638 + if (!cgContext) |
|
639 + return cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA, |
|
640 + width, height); |
|
641 + |
|
642 + if (!_cairo_quartz_verify_surface_size(width, height)) |
|
643 + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
|
644 + |
|
645 + /* If we pass zero width or height into CGLayerCreateWithContext below, |
|
646 + * it will fail. |
|
647 + */ |
|
648 + if (width == 0 || height == 0) { |
|
649 + return (cairo_surface_t*) |
|
650 + _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, |
|
651 + width, height); |
|
652 + } |
|
653 + |
|
654 + layer = CGLayerCreateWithContext (cgContext, |
|
655 + CGSizeMake (width, height), |
|
656 + NULL); |
|
657 + if (!layer) |
|
658 + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
|
659 + |
|
660 + ctx = CGLayerGetContext (layer); |
|
661 + /* Flip it when we draw into it, so that when we finally composite it |
|
662 + * to a flipped target, the directions match and Quartz will optimize |
|
663 + * the composition properly |
|
664 + */ |
|
665 + CGContextTranslateCTM (ctx, 0, height); |
|
666 + CGContextScaleCTM (ctx, 1, -1); |
|
667 + |
|
668 + CGContextRetain (ctx); |
|
669 + surf = _cairo_quartz_surface_create_internal (ctx, CAIRO_CONTENT_COLOR_ALPHA, |
|
670 + width, height); |
|
671 + if (surf->base.status) { |
|
672 + CGLayerRelease (layer); |
|
673 + // create_internal will have set an error |
|
674 + return (cairo_surface_t*) surf; |
|
675 + } |
|
676 + surf->cgLayer = layer; |
|
677 + |
|
678 + return (cairo_surface_t *) surf; |
|
679 +} |
|
680 + |
|
681 +/** |
|
682 * cairo_quartz_surface_create |
|
683 * @format: format of pixels in the surface to create |
|
684 * @width: width of the surface, in pixels |
|
685 * @height: height of the surface, in pixels |
|
686 * |
|
687 * Creates a Quartz surface backed by a CGBitmap. The surface is |
|
688 * created using the Device RGB (or Device Gray, for A8) color space. |
|
689 * All Cairo operations, including those that require software |
|
690 diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h |
|
691 --- a/gfx/cairo/cairo/src/cairo-quartz.h |
|
692 +++ b/gfx/cairo/cairo/src/cairo-quartz.h |
|
693 @@ -45,16 +45,21 @@ |
|
694 CAIRO_BEGIN_DECLS |
|
695 |
|
696 cairo_public cairo_surface_t * |
|
697 cairo_quartz_surface_create (cairo_format_t format, |
|
698 unsigned int width, |
|
699 unsigned int height); |
|
700 |
|
701 cairo_public cairo_surface_t * |
|
702 +cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface, |
|
703 + unsigned int width, |
|
704 + unsigned int height); |
|
705 + |
|
706 +cairo_public cairo_surface_t * |
|
707 cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, |
|
708 unsigned int width, |
|
709 unsigned int height); |
|
710 |
|
711 cairo_public CGContextRef |
|
712 cairo_quartz_surface_get_cg_context (cairo_surface_t *surface); |
|
713 |
|
714 cairo_public CGContextRef |
|
715 |