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