[cairo] Cairo 1.6.4 Quartz crash: CGImageCreateCopy misuse
paulmessmer at hotmail.com
Sun May 4 22:54:14 PDT 2008
If I try to use Cairo 1.6.4 to print from a Cocoa application using the cairo_quartz_surface_create_for_cg_context() and I draw images, I'll crash inside of CoreGraphics decode_image routine when Apple's printing code is doing its thing, long after all the cairo surfaces are flushed and gone. I believe this is due to the following:
In cairo-quartz-surface.c, line ~749, there is:
/* Create a copy to ensure that the CGImageRef doesn't depend on the image surface's backing store */
*image_out = CGImageCreateCopy (image);
However, I don't believe the Cairo code does what the comment says it does. I believe that the copy has the same data provider as the original, and still depends on the backing store. While Apple's documentation doesn't say what kind of copy is done, the CGImage.h header claims:
/* Return a copy of `image'. Only the image structure itself is copied; the
* underlying data is not. */
CG_EXTERN CGImageRef CGImageCreateCopy(CGImageRef image);
What I'm pretty sure is happening is that the "copied" CGImage that Cairo believes it has is using the same data provider as the original image. This provider is still referencing the bits in memory I supplied originally with cairo_image_surface_create_for_data. When Cairo is making Core Graphics calls to draw images to a context which is a printer context, Apple is retaining the CGImages and actually using them much later in the printing process, i.e. after the cairo surfaces are flushed and gone, and the NSView drawing code used for printing is complete. By then the data for the images is long gone.
If I modify my drawing code to never free image data it passes to cairo_image_surface_create_for_data, the printing crash goes away, further cementing my belief about what's happening.
If fixing this, please consider that it should be possible to draw using a single source image surface multiple times without incurring multiple copies.
It also might be interesting to have some quartz-specific API allowing clients to say "use this CGImage as a Cairo surface", thus allowing clients to create a CGImage with a custom data provider. As it stands now, Apple's apparent behavior of retaining all of the CGImages used during printing means that they all have to fit in memory at once, which could be very demanding in some applications (but can probably be ameliorated with a custom data provider).
More information about the cairo