changeset: 42954:7881873b2b5d user: Robert O'Callahan date: Tue Jun 01 11:19:45 2010 +1200 summary: Bug 552537. Cache the CGImageRef that we create for a CGBitmapContext so that we can take advantage of Quartz caching optimizations. r=jrmuizel 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 @@ -49,16 +49,24 @@ typedef struct cairo_quartz_surface { CGContextRef cgContext; CGAffineTransform cgContextBaseCTM; void *imageData; cairo_surface_t *imageSurfaceEquiv; cairo_surface_clipper_t clipper; + + /** + * If non-null, this is a CGImage representing the contents of the surface. + * We clear this out before any painting into the surface, so that we + * don't force a copy to be created. + */ + CGImageRef bitmapContextImage; + cairo_rectangle_int_t extents; } cairo_quartz_surface_t; typedef struct cairo_quartz_image_surface { cairo_surface_t base; cairo_rectangle_int_t 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 @@ -1134,19 +1134,24 @@ _cairo_surface_to_cgimage (cairo_surface if (stype == CAIRO_SURFACE_TYPE_QUARTZ) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source; if (IS_EMPTY(surface)) { *image_out = NULL; return CAIRO_STATUS_SUCCESS; } if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) { - *image_out = CGBitmapContextCreateImage (surface->cgContext); - if (*image_out) - return CAIRO_STATUS_SUCCESS; + if (!surface->bitmapContextImage) { + surface->bitmapContextImage = + CGBitmapContextCreateImage (surface->cgContext); + } + if (surface->bitmapContextImage) { + *image_out = CGImageRetain (surface->bitmapContextImage); + return CAIRO_STATUS_SUCCESS; + } } } if (stype != CAIRO_SURFACE_TYPE_IMAGE) { status = _cairo_surface_acquire_source_image (source, &isurf, &image_extra); if (status) return status; @@ -1589,16 +1594,29 @@ _cairo_quartz_setup_radial_source (cairo CGColorSpaceRelease(rgb); CGFunctionRelease(gradFunc); state->action = DO_SHADING; } /** + * Call this before any operation that can modify the contents of a + * cairo_quartz_surface_t. + */ +static void +_cairo_quartz_surface_will_change (cairo_quartz_surface_t *surface) +{ + if (surface->bitmapContextImage) { + CGImageRelease (surface->bitmapContextImage); + surface->bitmapContextImage = NULL; + } +} + +/** * Sets up internal state to be used to draw the source mask, stored in * cairo_quartz_state_t. Guarantees to call CGContextSaveGState on * surface->cgContext. */ static cairo_quartz_drawing_state_t _cairo_quartz_setup_state (cairo_quartz_surface_t *surface, const cairo_pattern_t *source, cairo_operator_t op, @@ -1609,16 +1627,18 @@ _cairo_quartz_setup_state (cairo_quartz_ cairo_status_t status; state.context = context; state.image = NULL; state.imageSurface = NULL; state.shading = NULL; state.pattern = NULL; + _cairo_quartz_surface_will_change (surface); + // Save before we change the pattern, colorspace, etc. so that // we can restore and make sure that quartz releases our // pattern (which may be stack allocated) CGContextSaveGState(context); CGContextSetInterpolationQuality (context, _cairo_quartz_filter_to_quartz (source->filter)); status = _cairo_quartz_surface_set_cairo_operator (surface, op); @@ -1936,16 +1956,21 @@ _cairo_quartz_surface_finish (void *abst /* Restore our saved gstate that we use to reset clipping */ CGContextRestoreGState (surface->cgContext); _cairo_surface_clipper_reset (&surface->clipper); CGContextRelease (surface->cgContext); surface->cgContext = NULL; + if (surface->bitmapContextImage) { + CGImageRelease (surface->bitmapContextImage); + surface->bitmapContextImage = NULL; + } + if (surface->imageSurfaceEquiv) { cairo_surface_destroy (surface->imageSurfaceEquiv); surface->imageSurfaceEquiv = NULL; } if (surface->imageData) { free (surface->imageData); surface->imageData = NULL; @@ -2006,16 +2031,18 @@ _cairo_quartz_surface_acquire_dest_image cairo_rectangle_int_t *image_rect, void **image_extra) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t status; ND((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface)); + _cairo_quartz_surface_will_change (surface); + status = _cairo_quartz_get_image (surface, image_out); if (status) return _cairo_error (CAIRO_STATUS_NO_MEMORY); *image_rect = surface->extents; *image_extra = NULL; return CAIRO_STATUS_SUCCESS; @@ -2939,16 +2966,17 @@ _cairo_quartz_surface_create_internal (C */ CGContextSaveGState (cgContext); surface->cgContext = cgContext; surface->cgContextBaseCTM = CGContextGetCTM (cgContext); surface->imageData = NULL; surface->imageSurfaceEquiv = NULL; + surface->bitmapContextImage = NULL; return surface; } /** * cairo_quartz_surface_create_for_cg_context * @cgContext: the existing CGContext for which to create the surface * @width: width of the surface, in pixels