diff --git a/gfx/cairo/cairo/src/Makefile.in b/gfx/cairo/cairo/src/Makefile.in index 412ea7945de..fbb4a12b11e 100644 --- a/gfx/cairo/cairo/src/Makefile.in +++ b/gfx/cairo/cairo/src/Makefile.in @@ -163,7 +163,7 @@ EXPORTS += $(PDF_EXPORTS) endif ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) -CSRCS += cairo-quartz-surface.c cairo-atsui-font.c +CSRCS += cairo-quartz-surface.c cairo-quartz-image-surface.c cairo-atsui-font.c EXPORTS += cairo-quartz.h cairo-atsui.h endif diff --git a/gfx/cairo/cairo/src/cairo-quartz-image-surface.c b/gfx/cairo/cairo/src/cairo-quartz-image-surface.c new file mode 100644 index 00000000000..8f74642786e --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-quartz-image-surface.c @@ -0,0 +1,340 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright � 2008 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Corporation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include "cairo-quartz-private.h" + +#define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY))) +#define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT))) + +CGImageRef +_cairo_quartz_create_cgimage (cairo_format_t format, + unsigned int width, + unsigned int height, + unsigned int stride, + void *data, + cairo_bool_t interpolate, + CGColorSpaceRef colorSpaceOverride, + CGDataProviderReleaseDataCallback releaseCallback, + void *releaseInfo) +{ + CGImageRef image = NULL; + CGDataProviderRef dataProvider = NULL; + CGColorSpaceRef colorSpace = colorSpaceOverride; + CGBitmapInfo bitinfo; + int bitsPerComponent, bitsPerPixel; + + switch (format) { + case CAIRO_FORMAT_ARGB32: + if (colorSpace == NULL) + colorSpace = CGColorSpaceCreateDeviceRGB(); + bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; + bitsPerComponent = 8; + bitsPerPixel = 32; + break; + + case CAIRO_FORMAT_RGB24: + if (colorSpace == NULL) + colorSpace = CGColorSpaceCreateDeviceRGB(); + bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; + bitsPerComponent = 8; + bitsPerPixel = 32; + break; + + case CAIRO_FORMAT_A8: + if (colorSpace == NULL) + colorSpace = CGColorSpaceCreateDeviceGray(); + bitinfo = kCGImageAlphaNone; + bitsPerComponent = 8; + bitsPerPixel = 8; + break; + + default: + return NULL; + } + + dataProvider = CGDataProviderCreateWithData (releaseInfo, + data, + height * stride, + releaseCallback); + + if (!dataProvider) { + // manually release + if (releaseCallback) + releaseCallback (releaseInfo, data, height * stride); + goto FINISH; + } + + image = CGImageCreate (width, height, + bitsPerComponent, + bitsPerPixel, + stride, + colorSpace, + bitinfo, + dataProvider, + NULL, + interpolate, + kCGRenderingIntentDefault); + +FINISH: + + CGDataProviderRelease (dataProvider); + + if (colorSpace != colorSpaceOverride) + CGColorSpaceRelease (colorSpace); + + return image; +} + + +static cairo_surface_t * +_cairo_quartz_image_surface_create_similar (void *asurface, + cairo_content_t content, + int width, + int height) +{ + cairo_surface_t *result; + cairo_surface_t *isurf = cairo_image_surface_create (_cairo_format_from_content (content), + width, + height); + if (cairo_surface_status(isurf)) + return isurf; + + result = cairo_quartz_image_surface_create (isurf); + cairo_surface_destroy (isurf); + + return result; +} + +static cairo_status_t +_cairo_quartz_image_surface_finish (void *asurface) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; + + /* the imageSurface will be destroyed by the data provider's release callback */ + CGImageRelease (surface->image); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_quartz_image_surface_acquire_source_image (void *asurface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; + + *image_out = surface->imageSurface; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_quartz_image_surface_acquire_dest_image (void *asurface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_int_t *image_rect, + void **image_extra) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; + + *image_out = surface->imageSurface; + *image_rect = surface->extents; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; + +} + +static cairo_int_status_t +_cairo_quartz_image_surface_get_extents (void *asurface, + cairo_rectangle_int_t *extents) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; + + *extents = surface->extents; + + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t cairo_quartz_image_surface_backend = { + CAIRO_SURFACE_TYPE_QUARTZ_IMAGE, + _cairo_quartz_image_surface_create_similar, + _cairo_quartz_image_surface_finish, + _cairo_quartz_image_surface_acquire_source_image, + NULL, /* release_source_image */ + _cairo_quartz_image_surface_acquire_dest_image, + NULL, /* release_dest_image */ + NULL, /* clone_similar */ + NULL, /* composite */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* copy_page */ + NULL, /* show_page */ + NULL, /* set_clip_region */ + NULL, /* intersect_clip_path */ + _cairo_quartz_image_surface_get_extents, + NULL, /* old_show_glyphs */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, /* scaled_font_fini */ + NULL, /* scaled_glyph_fini */ + + NULL, /* paint */ + NULL, /* mask */ + NULL, /* stroke */ + NULL, /* fill */ + NULL, /* surface_show_glyphs */ + NULL, /* snapshot */ + NULL, /* is_similar */ + NULL, /* reset */ + NULL /* fill_stroke */ + +}; + +static void +DataProviderReleaseCallback (void *info, const void *data, size_t size) +{ + cairo_surface_t *surface = (cairo_surface_t *) info; + cairo_surface_destroy (surface); +} + +/** + * cairo_quartz_image_surface_create + * @surface: a cairo image surface to wrap with a quartz image surface + * + * Creates a Quartz surface backed by a CGImageRef that references + * the given image surface. + * + * Data is to be loaded into this surface by calling + * cairo_quartz_image_surface_get_image, and performing operations on the + * resulting image surface. + * + * The resulting surface can be rendered quickly when used as a source + * when rendering to a cairo_quartz_surface. + * + * Return value: the newly created surface. + * + * Since: 1.6 + */ +cairo_surface_t * +cairo_quartz_image_surface_create (cairo_surface_t *surface) +{ + cairo_quartz_image_surface_t *qisurf; + + CGImageRef image; + + CGContextRef cgContext; + CGColorSpaceRef cgColorspace; + CGBitmapInfo bitinfo; + + cairo_image_surface_t *image_surface; + int width, height, stride; + cairo_format_t format; + unsigned char *data; + + if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE) + return SURFACE_ERROR_NO_MEMORY; + + image_surface = (cairo_image_surface_t*) surface; + width = image_surface->width; + height = image_surface->height; + stride = image_surface->stride; + format = image_surface->format; + data = image_surface->data; + + if (!_cairo_quartz_verify_surface_size(width, height)) + return SURFACE_ERROR_NO_MEMORY; + + if (width == 0 || height == 0) + return SURFACE_ERROR_NO_MEMORY; + + if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24) + return SURFACE_ERROR_INVALID_FORMAT; + + qisurf = malloc(sizeof(cairo_quartz_image_surface_t)); + if (qisurf == NULL) + return SURFACE_ERROR_NO_MEMORY; + + memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t)); + + // ref this here; in case the create_cgimage fails, it will + // be released by the callback. + cairo_surface_reference (surface); + + image = _cairo_quartz_create_cgimage (format, + width, height, + stride, + data, + FALSE, + NULL, + DataProviderReleaseCallback, + surface); + + if (!image) { + free (qisurf); + return SURFACE_ERROR_NO_MEMORY; + } + + _cairo_surface_init (&qisurf->base, + &cairo_quartz_image_surface_backend, + _cairo_content_from_format (format)); + + qisurf->extents.x = qisurf->extents.y = 0; + qisurf->extents.width = width; + qisurf->extents.height = height; + + qisurf->image = image; + qisurf->imageSurface = image_surface; + + return &qisurf->base; +} + + +cairo_surface_t * +cairo_quartz_image_surface_get_image (cairo_surface_t *asurface) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface; + + if (cairo_surface_get_type(asurface) != CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) + return NULL; + + return (cairo_surface_t*) surface->imageSurface; +} + diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h index a62f62d9ced..3596192cde7 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-private.h +++ b/gfx/cairo/cairo/src/cairo-quartz-private.h @@ -46,13 +46,12 @@ typedef struct cairo_quartz_surface { cairo_surface_t base; - void *imageData; - - cairo_surface_t *imageSurfaceEquiv; - CGContextRef cgContext; CGAffineTransform cgContextBaseCTM; + void *imageData; + cairo_surface_t *imageSurfaceEquiv; + cairo_rectangle_int_t extents; /* These are stored while drawing operations are in place, set up @@ -66,6 +65,30 @@ typedef struct cairo_quartz_surface { CGShadingRef sourceShading; CGPatternRef sourcePattern; } cairo_quartz_surface_t; + +typedef struct cairo_quartz_image_surface { + cairo_surface_t base; + + cairo_rectangle_int_t extents; + + CGImageRef image; + cairo_image_surface_t *imageSurface; +} cairo_quartz_image_surface_t; + +cairo_bool_t +_cairo_quartz_verify_surface_size(int width, int height); + +CGImageRef +_cairo_quartz_create_cgimage (cairo_format_t format, + unsigned int width, + unsigned int height, + unsigned int stride, + void *data, + cairo_bool_t interpolate, + CGColorSpaceRef colorSpaceOverride, + CGDataProviderReleaseDataCallback releaseCallback, + void *releaseInfo); + #endif /* CAIRO_HAS_QUARTZ_SURFACE */ #if CAIRO_HAS_ATSUI_FONT diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c index b2ad56c88a7..fa784b6cd27 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c @@ -140,7 +140,8 @@ static void quartz_ensure_symbols(void) #define CG_MAX_WIDTH USHRT_MAX /* is the desired size of the surface within bounds? */ -static cairo_bool_t verify_surface_size(int width, int height) +cairo_bool_t +_cairo_quartz_verify_surface_size(int width, int height) { /* hmmm, allow width, height == 0 ? */ if (width < 0 || height < 0) { @@ -393,114 +394,93 @@ CreateGradientFunction (cairo_gradient_pattern_t *gpat) &callbacks); } -/* generic cairo surface -> cairo_quartz_surface_t function */ -static cairo_int_status_t -_cairo_quartz_surface_to_quartz (cairo_surface_t *target, - cairo_surface_t *pat_surf, - cairo_quartz_surface_t **quartz_surf) +/* Obtain a CGImageRef from a cairo_surface_t * */ + +static CGImageRef +_cairo_surface_to_cgimage (cairo_surface_t *target, + cairo_surface_t *source) { + cairo_surface_type_t stype = cairo_surface_get_type (source); + cairo_image_surface_t *isurf; + CGImageRef image, image2; + void *image_extra; - if (cairo_surface_get_type(pat_surf) != CAIRO_SURFACE_TYPE_QUARTZ) { - /* XXXtodo/perf don't use clone if the source surface is an image surface! Instead, - * just create the CGImage directly! - */ - - cairo_surface_t *ref_type = target; - cairo_surface_t *new_surf = NULL; - cairo_rectangle_int_t rect; - cairo_status_t status; - - if (ref_type == NULL) - ref_type = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); - - status = _cairo_surface_get_extents (pat_surf, &rect); - if (status) - return status; - - status = _cairo_surface_clone_similar (ref_type, pat_surf, rect.x, rect.y, - rect.width, rect.height, &new_surf); - if (target == NULL) - cairo_surface_destroy(ref_type); - - if (status) - return status; - - if (new_surf && - cairo_surface_get_type (new_surf) != CAIRO_SURFACE_TYPE_QUARTZ) - { - ND((stderr, "got a non-quartz surface, format=%d width=%u height=%u type=%d\n", cairo_surface_get_type (pat_surf), rect.width, rect.height, cairo_surface_get_type (new_surf))); - cairo_surface_destroy (new_surf); - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - *quartz_surf = (cairo_quartz_surface_t *) new_surf; - } else { - /* If it's a quartz surface, we can try to see if it's a CGBitmapContext; - * we do this when we call CGBitmapContextCreateImage below. - */ - cairo_surface_reference (pat_surf); - *quartz_surf = (cairo_quartz_surface_t*) pat_surf; + if (stype == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) { + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source; + return CGImageRetain (surface->image); } - return CAIRO_STATUS_SUCCESS; + if (stype == CAIRO_SURFACE_TYPE_QUARTZ) { + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source; + image = CGBitmapContextCreateImage (surface->cgContext); + if (image) + return image; + } + + if (stype != CAIRO_SURFACE_TYPE_IMAGE) { + cairo_status_t status = + _cairo_surface_acquire_source_image (source, &isurf, &image_extra); + if (status) + return NULL; + } else { + isurf = (cairo_image_surface_t *) source; + } + + image2 = _cairo_quartz_create_cgimage (isurf->format, + isurf->width, + isurf->height, + isurf->stride, + isurf->data, + FALSE, + NULL, NULL, NULL); + + image = CGImageCreateCopy (image2); + CGImageRelease (image2); + + if ((cairo_surface_t*) isurf != source) + _cairo_surface_release_source_image (source, isurf, image_extra); + + return image; } /* Generic cairo_pattern -> CGPattern function */ -static void -SurfacePatternDrawFunc (void *info, CGContextRef context) -{ - cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info; - cairo_surface_t *pat_surf = spat->surface; - cairo_int_status_t status; - cairo_quartz_surface_t *quartz_surf; - CGImageRef img; +typedef struct { + CGImageRef image; CGRect imageBounds; + cairo_bool_t do_reflect; +} SurfacePatternDrawInfo; - status = _cairo_quartz_surface_to_quartz (NULL, pat_surf, &quartz_surf); - if (status) - return; +static void +SurfacePatternDrawFunc (void *ainfo, CGContextRef context) +{ + SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo; - img = CGBitmapContextCreateImage (quartz_surf->cgContext); - if (!img) { - // ... give up. - ND((stderr, "CGBitmapContextCreateImage failed\n")); - _cairo_error (CAIRO_STATUS_NO_MEMORY); - cairo_surface_destroy ((cairo_surface_t*)quartz_surf); - return; - } + CGContextTranslateCTM (context, 0, info->imageBounds.size.height); + CGContextScaleCTM (context, 1, -1); - /* XXXtodo WHY does this need to be flipped? Writing this stuff - * to disk shows that in both this path and the path above the source image - * has an identical orientation, and the destination context at all times has a Y - * flip. So why do we need to flip in this case? - */ - if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { - CGContextTranslateCTM (context, 0, CGImageGetHeight(img)); - CGContextScaleCTM (context, 1, -1); - } - - imageBounds.size = CGSizeMake (CGImageGetWidth(img), CGImageGetHeight(img)); - imageBounds.origin.x = 0; - imageBounds.origin.y = 0; - - CGContextDrawImage (context, imageBounds, img); - if (spat->base.extend == CAIRO_EXTEND_REFLECT) { + CGContextDrawImage (context, info->imageBounds, info->image); + if (info->do_reflect) { /* draw 3 more copies of the image, flipped. */ - CGContextTranslateCTM (context, 0, 2 * imageBounds.size.height); + CGContextTranslateCTM (context, 0, 2 * info->imageBounds.size.height); CGContextScaleCTM (context, 1, -1); - CGContextDrawImage (context, imageBounds, img); - CGContextTranslateCTM (context, 2 * imageBounds.size.width, 0); + CGContextDrawImage (context, info->imageBounds, info->image); + CGContextTranslateCTM (context, 2 * info->imageBounds.size.width, 0); CGContextScaleCTM (context, -1, 1); - CGContextDrawImage (context, imageBounds, img); - CGContextTranslateCTM (context, 0, 2 * imageBounds.size.height); + CGContextDrawImage (context, info->imageBounds, info->image); + CGContextTranslateCTM (context, 0, 2 * info->imageBounds.size.height); CGContextScaleCTM (context, 1, -1); - CGContextDrawImage (context, imageBounds, img); + CGContextDrawImage (context, info->imageBounds, info->image); } +} - CGImageRelease (img); +static void +SurfacePatternReleaseInfoFunc (void *ainfo) +{ + SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo; - cairo_surface_destroy ((cairo_surface_t*) quartz_surf); + CGImageRelease (info->image); + free (info); } /* Borrowed from cairo-meta-surface */ @@ -532,48 +512,62 @@ _init_pattern_with_snapshot (cairo_pattern_t *pattern, static cairo_int_status_t _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest, - cairo_pattern_t *abspat, + cairo_pattern_t *apattern, CGPatternRef *cgpat) { - cairo_surface_pattern_t *spat; + cairo_surface_pattern_t *spattern; cairo_surface_t *pat_surf; cairo_rectangle_int_t extents; + CGImageRef image; CGRect pbounds; CGAffineTransform ptransform, stransform; CGPatternCallbacks cb = { 0, SurfacePatternDrawFunc, - (CGFunctionReleaseInfoCallback) cairo_pattern_destroy }; + SurfacePatternReleaseInfoFunc }; + SurfacePatternDrawInfo *info; float rw, rh; cairo_status_t status; - cairo_pattern_union_t *snap_pattern = NULL; - cairo_pattern_t *target_pattern = abspat; - cairo_matrix_t m; + /* SURFACE is the only type we'll handle here */ - if (abspat->type != CAIRO_PATTERN_TYPE_SURFACE) + if (apattern->type != CAIRO_PATTERN_TYPE_SURFACE) return CAIRO_INT_STATUS_UNSUPPORTED; - spat = (cairo_surface_pattern_t *) abspat; - pat_surf = spat->surface; + spattern = (cairo_surface_pattern_t *) apattern; + pat_surf = spattern->surface; status = _cairo_surface_get_extents (pat_surf, &extents); if (status) return status; + image = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf); + if (image == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + info = malloc(sizeof(SurfacePatternDrawInfo)); + if (!info) + return CAIRO_STATUS_NO_MEMORY; + + /* XXX -- if we're printing, we may need to call CGImageCreateCopy to make sure + * that the data will stick around for this image when the printer gets to it. + * Otherwise, the underlying data store may disappear from under us! + * + * _cairo_surface_to_cgimage will copy when it converts non-Quartz surfaces, + * since the Quartz surfaces have a higher chance of sticking around. If the + * source is a quartz image surface, then it's set up to retain a ref to the + * image surface that it's backed by. + */ + info->image = image; + + info->imageBounds = CGRectMake (0, 0, extents.width, extents.height); + info->do_reflect = (spattern->base.extend == CAIRO_EXTEND_REFLECT); + pbounds.origin.x = 0; pbounds.origin.y = 0; - // kjs seems to indicate this should work (setting to 0,0 to avoid - // tiling); however, the pattern CTM scaling ends up being NaN in - // the pattern draw function if either rw or rh are 0. - // XXXtodo get pattern drawing working with extend options - // XXXtodo/perf optimize CAIRO_EXTEND_NONE to a single DrawImage instead of a pattern - if (spat->base.extend == CAIRO_EXTEND_REFLECT) { - /* XXX broken; need to emulate by reflecting the image into 4 quadrants - * and then tiling that - */ + if (spattern->base.extend == CAIRO_EXTEND_REFLECT) { pbounds.size.width = 2 * extents.width; pbounds.size.height = 2 * extents.height; } else { @@ -583,7 +577,7 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t rw = pbounds.size.width; rh = pbounds.size.height; - m = spat->base.matrix; + m = spattern->base.matrix; cairo_matrix_invert(&m); _cairo_quartz_cairo_matrix_to_quartz (&m, &stransform); @@ -601,25 +595,14 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t ND((stderr, " context xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", xform.tx, xform.ty, xform.a, xform.b, xform.c, xform.d)); #endif + *cgpat = CGPatternCreate (info, + pbounds, + ptransform, + rw, rh, + kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */ + TRUE, + &cb); - /* XXX fixme: only do snapshots if the context is for printing, or get rid of the - other block if it doesn't fafect performance */ - if (1 /* context is for printing */) { - snap_pattern = (cairo_pattern_union_t*) malloc(sizeof(cairo_pattern_union_t)); - target_pattern = (cairo_pattern_t*) snap_pattern; - _init_pattern_with_snapshot (target_pattern, abspat); - } else { - cairo_pattern_reference (abspat); - target_pattern = abspat; - } - - *cgpat = CGPatternCreate (target_pattern, - pbounds, - ptransform, - rw, rh, - kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */ - TRUE, - &cb); return CAIRO_STATUS_SUCCESS; } @@ -785,7 +768,6 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, { cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source; cairo_surface_t *pat_surf = spat->surface; - cairo_quartz_surface_t *quartz_surf; CGImageRef img; cairo_matrix_t m = spat->base.matrix; cairo_rectangle_int_t extents; @@ -794,16 +776,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, CGRect srcRect; cairo_fixed_t fw, fh; - status = _cairo_quartz_surface_to_quartz ((cairo_surface_t *) surface, pat_surf, &quartz_surf); - if (status) - return DO_UNSUPPORTED; - - surface->sourceImageSurface = (cairo_surface_t *)quartz_surf; - - if (IS_EMPTY(quartz_surf)) - return DO_NOTHING; - - img = CGBitmapContextCreateImage (quartz_surf->cgContext); + img = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf); if (!img) return DO_UNSUPPORTED; @@ -1132,7 +1105,7 @@ _cairo_quartz_surface_create_similar (void *abstract_surface, return NULL; // verify width and height of surface - if (!verify_surface_size(width, height)) { + if (!_cairo_quartz_verify_surface_size(width, height)) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return NULL; } @@ -1142,12 +1115,12 @@ _cairo_quartz_surface_create_similar (void *abstract_surface, static cairo_status_t _cairo_quartz_surface_clone_similar (void *abstract_surface, - cairo_surface_t *src, - int src_x, - int src_y, - int width, - int height, - cairo_surface_t **clone_out) + cairo_surface_t *src, + int src_x, + int src_y, + int width, + int height, + cairo_surface_t **clone_out) { cairo_quartz_surface_t *new_surface = NULL; cairo_format_t new_format; @@ -1156,97 +1129,58 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface, *clone_out = NULL; // verify width and height of surface - if (!verify_surface_size(width, height)) { + if (!_cairo_quartz_verify_surface_size(width, height)) { return CAIRO_INT_STATUS_UNSUPPORTED; } - if (cairo_surface_get_type(src) == CAIRO_SURFACE_TYPE_QUARTZ) { + if (width == 0 || height == 0) { + *clone_out = (cairo_surface_t*) + _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, + width, height); + return CAIRO_STATUS_SUCCESS; + } + + if (src->backend->type == CAIRO_SURFACE_TYPE_QUARTZ) { cairo_quartz_surface_t *qsurf = (cairo_quartz_surface_t *) src; if (IS_EMPTY(qsurf)) { - *clone_out = (cairo_surface_t*) _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, qsurf->extents.width, qsurf->extents.height); + *clone_out = (cairo_surface_t*) + _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, + qsurf->extents.width, qsurf->extents.height); return CAIRO_STATUS_SUCCESS; } - - quartz_image = CGBitmapContextCreateImage (qsurf->cgContext); - new_format = CAIRO_FORMAT_ARGB32; /* XXX bogus; recover a real format from the image */ - } else if (_cairo_surface_is_image (src)) { - cairo_image_surface_t *isurf = (cairo_image_surface_t *) src; - CGDataProviderRef dataProvider; - CGColorSpaceRef cgColorspace; - CGBitmapInfo bitinfo; - int bitsPerComponent, bitsPerPixel; - - if (isurf->width == 0 || isurf->height == 0) { - *clone_out = (cairo_surface_t*) _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, isurf->width, isurf->height); - return CAIRO_STATUS_SUCCESS; - } - - if (isurf->format == CAIRO_FORMAT_ARGB32) { - cgColorspace = CGColorSpaceCreateDeviceRGB(); - bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; - bitsPerComponent = 8; - bitsPerPixel = 32; - } else if (isurf->format == CAIRO_FORMAT_RGB24) { - cgColorspace = CGColorSpaceCreateDeviceRGB(); - bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; - bitsPerComponent = 8; - bitsPerPixel = 32; - } else if (isurf->format == CAIRO_FORMAT_A8) { - cgColorspace = CGColorSpaceCreateDeviceGray(); - bitinfo = kCGImageAlphaNone; - bitsPerComponent = 8; - bitsPerPixel = 8; - } else { - /* SUPPORT A1, maybe */ - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - new_format = isurf->format; - - dataProvider = CGDataProviderCreateWithData (NULL, - isurf->data, - isurf->height * isurf->stride, - NULL); - - quartz_image = CGImageCreate (isurf->width, isurf->height, - bitsPerComponent, - bitsPerPixel, - isurf->stride, - cgColorspace, - bitinfo, - dataProvider, - NULL, - false, - kCGRenderingIntentDefault); - CGDataProviderRelease (dataProvider); - CGColorSpaceRelease (cgColorspace); - } else { - return CAIRO_INT_STATUS_UNSUPPORTED; } + quartz_image = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src); if (!quartz_image) return CAIRO_INT_STATUS_UNSUPPORTED; + new_format = CAIRO_FORMAT_ARGB32; /* assumed */ + if (_cairo_surface_is_image (src)) { + new_format = ((cairo_image_surface_t *) src)->format; + } + new_surface = (cairo_quartz_surface_t *) - cairo_quartz_surface_create (new_format, - CGImageGetWidth (quartz_image), - CGImageGetHeight (quartz_image)); + cairo_quartz_surface_create (new_format, width, height); if (!new_surface || new_surface->base.status) { CGImageRelease (quartz_image); return CAIRO_INT_STATUS_UNSUPPORTED; } + CGContextSaveGState (new_surface->cgContext); + CGContextSetCompositeOperation (new_surface->cgContext, kPrivateCGCompositeCopy); - quartz_image_to_png (quartz_image, NULL); - + CGContextTranslateCTM (new_surface->cgContext, -src_x, -src_y); CGContextDrawImage (new_surface->cgContext, - CGRectMake (src_x, src_y, width, height), + CGRectMake (0, 0, CGImageGetWidth(quartz_image), CGImageGetHeight(quartz_image)), quartz_image); - CGImageRelease (quartz_image); + CGContextRestoreGState (new_surface->cgContext); + + CGImageRelease (quartz_image); + *clone_out = (cairo_surface_t*) new_surface; return CAIRO_STATUS_SUCCESS; @@ -1265,8 +1199,8 @@ _cairo_quartz_surface_get_extents (void *abstract_surface, static cairo_int_status_t _cairo_quartz_surface_paint (void *abstract_surface, - cairo_operator_t op, - cairo_pattern_t *source) + cairo_operator_t op, + cairo_pattern_t *source) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1292,17 +1226,11 @@ _cairo_quartz_surface_paint (void *abstract_surface, } else if (action == DO_SHADING) { CGContextDrawShading (surface->cgContext, surface->sourceShading); } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) { - cairo_surface_pattern_t *surface_pattern = - (cairo_surface_pattern_t *) source; - cairo_surface_t *pat_surf = surface_pattern->surface; - CGContextSaveGState (surface->cgContext); CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform); - if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { - CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage)); - CGContextScaleCTM (surface->cgContext, 1, -1); - } + CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height); + CGContextScaleCTM (surface->cgContext, 1, -1); if (action == DO_IMAGE) CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage); @@ -1372,19 +1300,14 @@ _cairo_quartz_surface_fill (void *abstract_surface, CGContextDrawShading (surface->cgContext, surface->sourceShading); } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) { - cairo_surface_pattern_t *surface_pattern = - (cairo_surface_pattern_t *) source; - cairo_surface_t *pat_surf = surface_pattern->surface; if (fill_rule == CAIRO_FILL_RULE_WINDING) CGContextClip (surface->cgContext); else CGContextEOClip (surface->cgContext); CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform); - if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { - CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage)); - CGContextScaleCTM (surface->cgContext, 1, -1); - } + CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height); + CGContextScaleCTM (surface->cgContext, 1, -1); if (action == DO_IMAGE) CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage); @@ -1481,10 +1404,8 @@ _cairo_quartz_surface_stroke (void *abstract_surface, CGContextClip (surface->cgContext); CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform); - if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) { - CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage)); - CGContextScaleCTM (surface->cgContext, 1, -1); - } + CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height); + CGContextScaleCTM (surface->cgContext, 1, -1); if (action == DO_IMAGE) CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage); @@ -1633,10 +1554,8 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, if (action == DO_IMAGE || action == DO_TILED_IMAGE) { CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform); - if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) { - CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage)); - CGContextScaleCTM (surface->cgContext, 1, -1); - } + CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height); + CGContextScaleCTM (surface->cgContext, 1, -1); if (action == DO_IMAGE) CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage); @@ -1670,7 +1589,6 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, cairo_surface_pattern_t *mask) { cairo_rectangle_int_t extents; - cairo_quartz_surface_t *quartz_surf; CGRect rect; CGImageRef img; cairo_surface_t *pat_surf = mask->surface; @@ -1680,15 +1598,11 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, if (status) return status; - status = _cairo_quartz_surface_to_quartz (NULL, pat_surf, &quartz_surf); - if (status) - return status; - // everything would be masked out, so do nothing - if (IS_EMPTY(quartz_surf)) + if (extents.width == 0 || extents.height == 0) goto BAIL; - img = CGBitmapContextCreateImage (quartz_surf->cgContext); + img = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf); if (!img) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto BAIL; @@ -1702,7 +1616,6 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, CGContextRestoreGState (surface->cgContext); CGImageRelease (img); BAIL: - cairo_surface_destroy ((cairo_surface_t*) quartz_surf); return status; } @@ -1965,7 +1878,7 @@ cairo_quartz_surface_create (cairo_format_t format, int bitsPerComponent; // verify width and height of surface - if (!verify_surface_size(width, height)) + if (!_cairo_quartz_verify_surface_size(width, height)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); if (width == 0 || height == 0) { @@ -2006,6 +1919,7 @@ cairo_quartz_surface_create (cairo_format_t format, CGColorSpaceRelease (cgColorspace); return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } + /* zero the memory to match the image surface behaviour */ memset (imageData, 0, height * stride); @@ -2164,15 +2078,3 @@ quartz_surface_to_png (cairo_quartz_surface_t *nq, char *dest) CGImageRelease(imgref); #endif } - -cairo_surface_t * -cairo_quartz_surface_get_image (cairo_surface_t *surface) -{ - cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface; - - if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ) - return NULL; - - return quartz->imageSurfaceEquiv; -} - diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h index d02cf2e869f..c0edb0ccd75 100644 --- a/gfx/cairo/cairo/src/cairo-quartz.h +++ b/gfx/cairo/cairo/src/cairo-quartz.h @@ -58,7 +58,10 @@ cairo_public CGContextRef cairo_quartz_surface_get_cg_context (cairo_surface_t *surface); cairo_public cairo_surface_t * -cairo_quartz_surface_get_image (cairo_surface_t *surface); +cairo_quartz_image_surface_create (cairo_surface_t *image_surface); + +cairo_public cairo_surface_t * +cairo_quartz_image_surface_get_image (cairo_surface_t *surface); CAIRO_END_DECLS diff --git a/gfx/cairo/cairo/src/cairo-rename.h b/gfx/cairo/cairo/src/cairo-rename.h index cb5ba530da2..a8116d8841d 100644 --- a/gfx/cairo/cairo/src/cairo-rename.h +++ b/gfx/cairo/cairo/src/cairo-rename.h @@ -169,7 +169,8 @@ #define cairo_quartz_surface_create _moz_cairo_quartz_surface_create #define cairo_quartz_surface_create_for_cg_context _moz_cairo_quartz_surface_create_for_cg_context #define cairo_quartz_surface_get_cg_context _moz_cairo_quartz_surface_get_cg_context -#define cairo_quartz_surface_get_image _moz_cairo_quartz_surface_get_image +#define cairo_quartz_image_surface_create _moz_cairo_quartz_image_surface_create +#define cairo_quartz_image_surface_get_image _moz_cairo_quartz_image_surface_get_image #define cairo_rectangle _moz_cairo_rectangle #define cairo_rectangle_list_destroy _moz_cairo_rectangle_list_destroy #define cairo_reference _moz_cairo_reference diff --git a/gfx/cairo/cairo/src/cairo.h b/gfx/cairo/cairo/src/cairo.h index 157b6e1361a..3aef5f79e44 100644 --- a/gfx/cairo/cairo/src/cairo.h +++ b/gfx/cairo/cairo/src/cairo.h @@ -1481,7 +1481,8 @@ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_SURFACE_TYPE_SVG, CAIRO_SURFACE_TYPE_OS2, - CAIRO_SURFACE_TYPE_WIN32_PRINTING + CAIRO_SURFACE_TYPE_WIN32_PRINTING, + CAIRO_SURFACE_TYPE_QUARTZ_IMAGE } cairo_surface_type_t; cairo_public cairo_surface_type_t diff --git a/gfx/src/thebes/nsThebesImage.cpp b/gfx/src/thebes/nsThebesImage.cpp index eeec9f3584f..864a7d648ed 100644 --- a/gfx/src/thebes/nsThebesImage.cpp +++ b/gfx/src/thebes/nsThebesImage.cpp @@ -111,7 +111,7 @@ nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequi mFormat = format; -#if defined(XP_WIN) +#ifdef XP_WIN if (!ShouldUseImageSurfaces()) { mWinSurface = new gfxWindowsSurface(gfxIntSize(mWidth, mHeight), format); if (mWinSurface && mWinSurface->CairoStatus() == 0) { @@ -122,16 +122,6 @@ nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequi if (!mImageSurface) mWinSurface = nsnull; -#elif defined(XP_MACOSX) - if (!ShouldUseImageSurfaces()) { - mQuartzSurface = new gfxQuartzSurface(gfxSize(mWidth, mHeight), format); - if (mQuartzSurface && mQuartzSurface->CairoStatus() == 0) { - mImageSurface = mQuartzSurface->GetImageSurface(); - } - } - - if (!mImageSurface) - mQuartzSurface = nsnull; #endif if (!mImageSurface) @@ -143,6 +133,10 @@ nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequi return NS_ERROR_OUT_OF_MEMORY; } +#ifdef XP_MACOSX + mQuartzSurface = new gfxQuartzImageSurface(mImageSurface); +#endif + mStride = mImageSurface->Stride(); return NS_OK; diff --git a/gfx/src/thebes/nsThebesImage.h b/gfx/src/thebes/nsThebesImage.h index 4d2f428e6e9..c87995c6116 100644 --- a/gfx/src/thebes/nsThebesImage.h +++ b/gfx/src/thebes/nsThebesImage.h @@ -47,7 +47,7 @@ #if defined(XP_WIN) #include "gfxWindowsSurface.h" #elif defined(XP_MACOSX) -#include "gfxQuartzSurface.h" +#include "gfxQuartzImageSurface.h" #endif class nsThebesImage : public nsIImage @@ -162,7 +162,7 @@ protected: #if defined(XP_WIN) nsRefPtr mWinSurface; #elif defined(XP_MACOSX) - nsRefPtr mQuartzSurface; + nsRefPtr mQuartzSurface; #endif PRUint8 mAlphaDepth; diff --git a/gfx/thebes/public/Makefile.in b/gfx/thebes/public/Makefile.in index b03d53c7b25..2eecdfbf1aa 100644 --- a/gfx/thebes/public/Makefile.in +++ b/gfx/thebes/public/Makefile.in @@ -78,6 +78,7 @@ endif ifneq (,$(filter $(MOZ_WIDGET_TOOLKIT),mac cocoa)) EXPORTS += gfxPlatformMac.h \ gfxQuartzSurface.h \ + gfxQuartzImageSurface.h \ gfxQuartzPDFSurface.h \ gfxAtsuiFonts.h \ $(NULL) diff --git a/gfx/thebes/public/gfxASurface.h b/gfx/thebes/public/gfxASurface.h index f7bc101c8ed..b7940705d57 100644 --- a/gfx/thebes/public/gfxASurface.h +++ b/gfx/thebes/public/gfxASurface.h @@ -81,7 +81,8 @@ public: SurfaceTypeDirectFB, SurfaceTypeSVG, SurfaceTypeOS2, - SurfaceTypeWin32Printing + SurfaceTypeWin32Printing, + SurfaceTypeQuartzImage } gfxSurfaceType; typedef enum { diff --git a/gfx/thebes/public/gfxImageSurface.h b/gfx/thebes/public/gfxImageSurface.h index c3ded8b4b34..dc155ecd285 100644 --- a/gfx/thebes/public/gfxImageSurface.h +++ b/gfx/thebes/public/gfxImageSurface.h @@ -81,6 +81,9 @@ public: */ unsigned char* Data() { return mData; } // delete this data under us and die. + /* Fast copy from another image surface; returns TRUE if successful, FALSE otherwise */ + PRBool CopyFrom (gfxImageSurface *other); + private: long ComputeStride() const; diff --git a/gfx/thebes/public/gfxPlatformMac.h b/gfx/thebes/public/gfxPlatformMac.h index bd3e4803d56..1c652b39bd5 100644 --- a/gfx/thebes/public/gfxPlatformMac.h +++ b/gfx/thebes/public/gfxPlatformMac.h @@ -53,6 +53,9 @@ public: already_AddRefed CreateOffscreenSurface(const gfxIntSize& size, gfxASurface::gfxImageFormat imageFormat); + already_AddRefed gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface, + gfxASurface::gfxImageFormat format); + nsresult ResolveFontName(const nsAString& aFontName, FontResolverCallback aCallback, void *aClosure, PRBool& aAborted); diff --git a/gfx/thebes/public/gfxQuartzImageSurface.h b/gfx/thebes/public/gfxQuartzImageSurface.h new file mode 100644 index 00000000000..6cf03ebe4a5 --- /dev/null +++ b/gfx/thebes/public/gfxQuartzImageSurface.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GFX_QUARTZIMAGESURFACE_H +#define GFX_QUARTZIMAGESURFACE_H + +#include "gfxASurface.h" +#include "gfxImageSurface.h" + +class THEBES_API gfxQuartzImageSurface : public gfxASurface { +public: + gfxQuartzImageSurface(gfxImageSurface *imageSurface); + gfxQuartzImageSurface(cairo_surface_t *csurf); + + virtual ~gfxQuartzImageSurface(); + + already_AddRefed GetImageSurface(); +}; + +#endif /* GFX_QUARTZIMAGESURFACE_H */ diff --git a/gfx/thebes/public/gfxQuartzSurface.h b/gfx/thebes/public/gfxQuartzSurface.h index 772a63ec37f..b417284583d 100644 --- a/gfx/thebes/public/gfxQuartzSurface.h +++ b/gfx/thebes/public/gfxQuartzSurface.h @@ -58,8 +58,6 @@ public: virtual PRInt32 GetDefaultContextFlags() const; - already_AddRefed GetImageSurface(); - protected: CGContextRef mCGContext; gfxSize mSize; diff --git a/gfx/thebes/src/Makefile.in b/gfx/thebes/src/Makefile.in index 76a81c9df8d..cf1e3348f26 100644 --- a/gfx/thebes/src/Makefile.in +++ b/gfx/thebes/src/Makefile.in @@ -101,7 +101,13 @@ endif ifneq (,$(filter $(MOZ_WIDGET_TOOLKIT),mac cocoa)) -CPPSRCS += gfxQuartzSurface.cpp gfxQuartzPDFSurface.cpp gfxPlatformMac.cpp gfxAtsuiFonts.cpp +CPPSRCS += \ + gfxQuartzSurface.cpp \ + gfxQuartzImageSurface.cpp \ + gfxQuartzPDFSurface.cpp \ + gfxPlatformMac.cpp \ + gfxAtsuiFonts.cpp \ + $(NULL) #CPPSRCS += gfxPDFSurface.cpp CPPSRCS += nsUnicodeRange.cpp diff --git a/gfx/thebes/src/gfxASurface.cpp b/gfx/thebes/src/gfxASurface.cpp index d975535844b..0719298f461 100644 --- a/gfx/thebes/src/gfxASurface.cpp +++ b/gfx/thebes/src/gfxASurface.cpp @@ -52,6 +52,7 @@ #ifdef CAIRO_HAS_QUARTZ_SURFACE #include "gfxQuartzSurface.h" +#include "gfxQuartzImageSurface.h" #endif #include @@ -158,6 +159,9 @@ gfxASurface::Wrap (cairo_surface_t *csurf) else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) { result = new gfxQuartzSurface(csurf); } + else if (stype == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) { + result = new gfxQuartzImageSurface(csurf); + } #endif else { result = new gfxUnknownSurface(csurf); diff --git a/gfx/thebes/src/gfxImageSurface.cpp b/gfx/thebes/src/gfxImageSurface.cpp index e27fd5901d9..54f6909303b 100644 --- a/gfx/thebes/src/gfxImageSurface.cpp +++ b/gfx/thebes/src/gfxImageSurface.cpp @@ -114,3 +114,33 @@ gfxImageSurface::ComputeStride() const return stride; } + +PRBool +gfxImageSurface::CopyFrom(gfxImageSurface *other) +{ + if (other->mSize != mSize) + { + return PR_FALSE; + } + + if (other->mFormat != mFormat && + !(other->mFormat == ImageFormatARGB32 && mFormat == ImageFormatRGB24) && + !(other->mFormat == ImageFormatRGB24 && mFormat == ImageFormatARGB32)) + { + return PR_FALSE; + } + + if (other->mStride == mStride) { + memcpy (mData, other->mData, mStride * mSize.height); + } else { + int lineSize = PR_MIN(other->mStride, mStride); + for (int i = 0; i < mSize.height; i++) { + unsigned char *src = other->mData + other->mStride * i; + unsigned char *dst = mData + mStride * i; + + memcpy (dst, src, lineSize); + } + } + + return PR_TRUE; +} diff --git a/gfx/thebes/src/gfxPlatformMac.cpp b/gfx/thebes/src/gfxPlatformMac.cpp index 3f00032f327..1398ef7fa6a 100644 --- a/gfx/thebes/src/gfxPlatformMac.cpp +++ b/gfx/thebes/src/gfxPlatformMac.cpp @@ -40,6 +40,7 @@ #include "gfxImageSurface.h" #include "gfxQuartzSurface.h" +#include "gfxQuartzImageSurface.h" #include "gfxQuartzFontCache.h" #include "gfxAtsuiFonts.h" @@ -144,6 +145,26 @@ gfxPlatformMac::CreateOffscreenSurface(const gfxIntSize& size, return newSurface; } +already_AddRefed +gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface, + gfxASurface::gfxImageFormat format) +{ + const gfxIntSize& surfaceSize = aSurface->GetSize(); + nsRefPtr isurf = aSurface; + + if (format != aSurface->Format()) { + isurf = new gfxImageSurface (surfaceSize, format); + if (!isurf->CopyFrom (aSurface)) { + // don't even bother doing anything more + NS_ADDREF(aSurface); + return aSurface; + } + } + + nsRefPtr ret = new gfxQuartzImageSurface(isurf); + return ret.forget(); +} + nsresult gfxPlatformMac::ResolveFontName(const nsAString& aFontName, FontResolverCallback aCallback, diff --git a/gfx/thebes/src/gfxQuartzImageSurface.cpp b/gfx/thebes/src/gfxQuartzImageSurface.cpp new file mode 100644 index 00000000000..4044e77b3d8 --- /dev/null +++ b/gfx/thebes/src/gfxQuartzImageSurface.cpp @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "gfxQuartzImageSurface.h" + +#include "cairo-quartz.h" + +gfxQuartzImageSurface::gfxQuartzImageSurface(gfxImageSurface *imageSurface) +{ + if (imageSurface->CairoStatus() || imageSurface->CairoSurface() == NULL) + return; + + cairo_surface_t *surf = cairo_quartz_image_surface_create (imageSurface->CairoSurface()); + Init (surf); +} + +gfxQuartzImageSurface::gfxQuartzImageSurface(cairo_surface_t *csurf) +{ + Init (csurf, PR_TRUE); +} + +gfxQuartzImageSurface::~gfxQuartzImageSurface() +{ +} + +already_AddRefed +gfxQuartzImageSurface::GetImageSurface() +{ + if (!mSurfaceValid) + return nsnull; + + cairo_surface_t *isurf = cairo_quartz_image_surface_get_image (CairoSurface()); + if (!isurf) { + NS_WARNING ("Couldn't obtain an image surface from a QuartzImageSurface?!"); + return nsnull; + } + + nsRefPtr asurf = gfxASurface::Wrap(isurf); + gfxImageSurface *imgsurf = (gfxImageSurface*) asurf.get(); + NS_ADDREF(imgsurf); + return imgsurf; +} diff --git a/gfx/thebes/src/gfxQuartzSurface.cpp b/gfx/thebes/src/gfxQuartzSurface.cpp index d5ebc756f58..9375bcb75f4 100644 --- a/gfx/thebes/src/gfxQuartzSurface.cpp +++ b/gfx/thebes/src/gfxQuartzSurface.cpp @@ -44,11 +44,14 @@ gfxQuartzSurface::gfxQuartzSurface(const gfxSize& size, gfxImageFormat format, PRBool aForPrinting) : mSize(size), mForPrinting(aForPrinting) { - if (!CheckSurfaceSize(gfxIntSize((int)size.width, (int)size.height))) + unsigned int width = (unsigned int) floor(size.width); + unsigned int height = (unsigned int) floor(size.height); + + if (!CheckSurfaceSize(gfxIntSize(width, height))) return; cairo_surface_t *surf = cairo_quartz_surface_create - ((cairo_format_t) format, floor(size.width), floor(size.height)); + ((cairo_format_t) format, width, height); mCGContext = cairo_quartz_surface_get_cg_context (surf); @@ -62,10 +65,12 @@ gfxQuartzSurface::gfxQuartzSurface(CGContextRef context, PRBool aForPrinting) : mCGContext(context), mSize(size), mForPrinting(aForPrinting) { + unsigned int width = (unsigned int) floor(size.width); + unsigned int height = (unsigned int) floor(size.height); + cairo_surface_t *surf = cairo_quartz_surface_create_for_cg_context(context, - floor(size.width), - floor(size.height)); + width, height); CGContextRetain(mCGContext); @@ -94,23 +99,3 @@ gfxQuartzSurface::~gfxQuartzSurface() { CGContextRelease(mCGContext); } - -already_AddRefed -gfxQuartzSurface::GetImageSurface() -{ - if (!mSurfaceValid) { - NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?"); - return nsnull; - } - - NS_ASSERTION(CairoSurface() != nsnull, "CairoSurface() shouldn't be nsnull when mSurfaceValid is TRUE!"); - - cairo_surface_t *isurf = cairo_quartz_surface_get_image(CairoSurface()); - if (!isurf) - return nsnull; - - nsRefPtr asurf = gfxASurface::Wrap(isurf); - gfxImageSurface *imgsurf = (gfxImageSurface*) asurf.get(); - NS_ADDREF(imgsurf); - return imgsurf; -}