mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-28 11:00:11 +01:00
Rework the quartz backend to not always hold an image but instead to create it on demand.#
This commit is contained in:
parent
df3c02c9ca
commit
8ba59b0336
2 changed files with 111 additions and 117 deletions
|
|
@ -46,13 +46,9 @@ typedef struct cairo_quartz_surface {
|
|||
|
||||
cairo_bool_t flipped;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
cairo_rectangle_t extents;
|
||||
|
||||
cairo_image_surface_t *image;
|
||||
pixman_region16_t *clip_region;
|
||||
|
||||
CGImageRef cgImage;
|
||||
pixman_region16_t *clip_region;
|
||||
} cairo_quartz_surface_t;
|
||||
|
||||
cairo_bool_t
|
||||
|
|
|
|||
|
|
@ -50,14 +50,8 @@ _cairo_quartz_surface_finish(void *abstract_surface)
|
|||
{
|
||||
cairo_quartz_surface_t *surface = abstract_surface;
|
||||
|
||||
if (surface->image)
|
||||
cairo_surface_destroy(&surface->image->base);
|
||||
|
||||
if (surface->cgImage)
|
||||
CGImageRelease(surface->cgImage);
|
||||
|
||||
if (surface->clip_region)
|
||||
pixman_region_destroy (surface->clip_region);
|
||||
if (surface->clip_region)
|
||||
pixman_region_destroy (surface->clip_region);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -67,64 +61,13 @@ _cairo_quartz_surface_acquire_source_image(void *abstract_surface,
|
|||
cairo_image_surface_t **image_out,
|
||||
void **image_extra)
|
||||
{
|
||||
cairo_quartz_surface_t *surface = abstract_surface;
|
||||
CGColorSpaceRef colorSpace;
|
||||
void *imageData;
|
||||
UInt32 imageDataSize, rowBytes;
|
||||
CGDataProviderRef dataProvider;
|
||||
cairo_quartz_surface_t *surface = abstract_surface;
|
||||
|
||||
/* We keep a cached (cairo_image_surface_t *) in the cairo_quartz_surface_t
|
||||
* struct. If the window is ever drawn to without going through Cairo, then
|
||||
* we would need to refetch the pixel data from the window into the cached
|
||||
* image surface.
|
||||
*/
|
||||
if (surface->image) {
|
||||
cairo_surface_reference(&surface->image->base);
|
||||
if (CGBitmapContextGetBitmapInfo (surface->context) != 0) {
|
||||
/* XXX: We can create an image out of the bitmap here */
|
||||
}
|
||||
|
||||
*image_out = surface->image;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
|
||||
rowBytes = surface->width * 4;
|
||||
imageDataSize = rowBytes * surface->height;
|
||||
imageData = malloc(imageDataSize);
|
||||
|
||||
dataProvider =
|
||||
CGDataProviderCreateWithData(NULL, imageData, imageDataSize,
|
||||
ImageDataReleaseFunc);
|
||||
|
||||
surface->cgImage = CGImageCreate(surface->width,
|
||||
surface->height,
|
||||
8,
|
||||
32,
|
||||
rowBytes,
|
||||
colorSpace,
|
||||
kCGImageAlphaPremultipliedFirst,
|
||||
dataProvider,
|
||||
NULL,
|
||||
false, kCGRenderingIntentDefault);
|
||||
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
CGDataProviderRelease(dataProvider);
|
||||
|
||||
surface->image = (cairo_image_surface_t *)
|
||||
cairo_image_surface_create_for_data(imageData,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
surface->width,
|
||||
surface->height, rowBytes);
|
||||
if (surface->image->base.status) {
|
||||
if (surface->cgImage)
|
||||
CGImageRelease(surface->cgImage);
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
*image_out = surface->image;
|
||||
*image_extra = NULL;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
|
|
@ -136,19 +79,79 @@ _cairo_quartz_surface_acquire_dest_image(void *abstract_surface,
|
|||
void **image_extra)
|
||||
{
|
||||
cairo_quartz_surface_t *surface = abstract_surface;
|
||||
cairo_surface_t *image_surface;
|
||||
unsigned char *data;
|
||||
int x1, y1, x2, y2;
|
||||
|
||||
image_rect->x = 0;
|
||||
image_rect->y = 0;
|
||||
image_rect->width = surface->image->width;
|
||||
image_rect->height = surface->image->height;
|
||||
x1 = surface->extents.x;
|
||||
x2 = surface->extents.x + surface->extents.width;
|
||||
y1 = surface->extents.y;
|
||||
y2 = surface->extents.y + surface->extents.height;
|
||||
|
||||
*image_out = surface->image;
|
||||
if (image_extra)
|
||||
if (interest_rect->x > x1)
|
||||
x1 = interest_rect->x;
|
||||
if (interest_rect->y > y1)
|
||||
y1 = interest_rect->y;
|
||||
if (interest_rect->x + interest_rect->width < x2)
|
||||
x2 = interest_rect->x + interest_rect->width;
|
||||
if (interest_rect->y + interest_rect->height < y2)
|
||||
y2 = interest_rect->y + interest_rect->height;
|
||||
|
||||
if (x1 >= x2 || y1 >= y2) {
|
||||
*image_out = NULL;
|
||||
*image_extra = NULL;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
image_rect->x = x1;
|
||||
image_rect->y = y1;
|
||||
image_rect->width = x2 - x1;
|
||||
image_rect->height = y2 - y1;
|
||||
|
||||
data = calloc (image_rect->width * image_rect->height * 4, 1);
|
||||
image_surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
image_rect->width,
|
||||
image_rect->height,
|
||||
image_rect->width * 4);
|
||||
|
||||
*image_out = (cairo_image_surface_t *)image_surface;
|
||||
*image_extra = data;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static CGImageRef
|
||||
create_image_from_surface (cairo_image_surface_t *image_surface, void *data)
|
||||
{
|
||||
CGImageRef image;
|
||||
CGColorSpaceRef color_space;
|
||||
CGDataProviderRef data_provider;
|
||||
int width, height;
|
||||
|
||||
width = cairo_image_surface_get_width ((cairo_surface_t *)image_surface);
|
||||
height = cairo_image_surface_get_height ((cairo_surface_t *)image_surface);
|
||||
|
||||
color_space = CGColorSpaceCreateDeviceRGB();
|
||||
data_provider = CGDataProviderCreateWithData (NULL, data,
|
||||
width * height * 4, NULL);
|
||||
image = CGImageCreate (width, height,
|
||||
8, 32,
|
||||
width * 4,
|
||||
color_space,
|
||||
kCGImageAlphaPremultipliedFirst,
|
||||
data_provider,
|
||||
NULL,
|
||||
FALSE, kCGRenderingIntentDefault);
|
||||
|
||||
CGColorSpaceRelease (color_space);
|
||||
CGDataProviderRelease (data_provider);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_quartz_surface_release_dest_image(void *abstract_surface,
|
||||
|
|
@ -159,25 +162,28 @@ _cairo_quartz_surface_release_dest_image(void *abstract_surface,
|
|||
void *image_extra)
|
||||
{
|
||||
cairo_quartz_surface_t *surface = abstract_surface;
|
||||
CGImageRef image_ref;
|
||||
CGRect rect;
|
||||
|
||||
image_ref = create_image_from_surface (image, image_extra);
|
||||
|
||||
if (surface->image == image) {
|
||||
CGRect rect;
|
||||
rect = CGRectMake (image_rect->x, image_rect->y, image_rect->width, image_rect->height);
|
||||
|
||||
rect = CGRectMake(0, 0, surface->width, surface->height);
|
||||
|
||||
if (surface->flipped) {
|
||||
CGContextSaveGState (surface->context);
|
||||
CGContextTranslateCTM (surface->context, 0, surface->height);
|
||||
CGContextScaleCTM (surface->context, 1, -1);
|
||||
}
|
||||
|
||||
CGContextDrawImage(surface->context, rect, surface->cgImage);
|
||||
|
||||
if (surface->flipped)
|
||||
CGContextRestoreGState (surface->context);
|
||||
|
||||
memset(surface->image->data, 0, surface->width * surface->height * 4);
|
||||
if (surface->flipped) {
|
||||
CGContextSaveGState (surface->context);
|
||||
CGContextTranslateCTM (surface->context, 0, image_rect->height + 2 * image_rect->y);
|
||||
CGContextScaleCTM (surface->context, 1, -1);
|
||||
}
|
||||
|
||||
CGContextDrawImage(surface->context, rect, image_ref);
|
||||
CFRelease (image_ref);
|
||||
|
||||
if (surface->flipped) {
|
||||
CGContextRestoreGState (surface->context);
|
||||
}
|
||||
|
||||
cairo_surface_destroy ((cairo_surface_t *)image);
|
||||
free (image_extra);
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
|
|
@ -185,21 +191,17 @@ _cairo_quartz_surface_set_clip_region(void *abstract_surface,
|
|||
pixman_region16_t * region)
|
||||
{
|
||||
cairo_quartz_surface_t *surface = abstract_surface;
|
||||
unsigned int serial;
|
||||
|
||||
serial = _cairo_surface_allocate_clip_serial (&surface->image->base);
|
||||
if (surface->clip_region)
|
||||
pixman_region_destroy (surface->clip_region);
|
||||
|
||||
if (region) {
|
||||
surface->clip_region = pixman_region_create ();
|
||||
pixman_region_copy (surface->clip_region, region);
|
||||
} else
|
||||
surface->clip_region = NULL;
|
||||
|
||||
if (surface->clip_region)
|
||||
pixman_region_destroy (surface->clip_region);
|
||||
|
||||
if (region) {
|
||||
surface->clip_region = pixman_region_create ();
|
||||
pixman_region_copy (surface->clip_region, region);
|
||||
} else
|
||||
surface->clip_region = NULL;
|
||||
|
||||
return _cairo_surface_set_clip_region(&surface->image->base,
|
||||
region, serial);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
|
|
@ -208,10 +210,7 @@ _cairo_quartz_surface_get_extents (void *abstract_surface,
|
|||
{
|
||||
cairo_quartz_surface_t *surface = abstract_surface;
|
||||
|
||||
rectangle->x = 0;
|
||||
rectangle->y = 0;
|
||||
rectangle->width = surface->width;
|
||||
rectangle->height = surface->height;
|
||||
*rectangle = surface->extents;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -242,6 +241,7 @@ cairo_surface_t *cairo_quartz_surface_create(CGContextRef context,
|
|||
int width, int height)
|
||||
{
|
||||
cairo_quartz_surface_t *surface;
|
||||
CGRect clip_box;
|
||||
|
||||
surface = malloc(sizeof(cairo_quartz_surface_t));
|
||||
if (surface == NULL) {
|
||||
|
|
@ -252,16 +252,14 @@ cairo_surface_t *cairo_quartz_surface_create(CGContextRef context,
|
|||
_cairo_surface_init(&surface->base, &cairo_quartz_surface_backend);
|
||||
|
||||
surface->context = context;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->image = NULL;
|
||||
surface->cgImage = NULL;
|
||||
surface->clip_region = NULL;
|
||||
surface->clip_region = NULL;
|
||||
surface->flipped = flipped;
|
||||
|
||||
/* Set up the image surface which Cairo draws into and we blit to & from. */
|
||||
void *foo;
|
||||
_cairo_quartz_surface_acquire_source_image(surface, &surface->image, &foo);
|
||||
clip_box = CGContextGetClipBoundingBox (context);
|
||||
surface->extents.x = clip_box.origin.x;
|
||||
surface->extents.y = clip_box.origin.y;
|
||||
surface->extents.width = clip_box.size.width;
|
||||
surface->extents.height = clip_box.size.height;
|
||||
|
||||
return (cairo_surface_t *) surface;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue