gfx/cairo/quartz-cglayers.patch

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:f838b0678b8c
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

mercurial