[cairo-commit] 4 commits - src/cairo-quartz-surface.c test/clip-zero.c test/.gitignore test/Makefile.am
Vladimir Vukicevic
vladimir at kemper.freedesktop.org
Tue Dec 4 14:05:58 PST 2007
src/cairo-quartz-surface.c | 227 +++++++++++++++++++++++++++++++--------------
test/.gitignore | 1
test/Makefile.am | 1
test/clip-zero.c | 80 +++++++++++++++
4 files changed, 243 insertions(+), 66 deletions(-)
New commits:
commit 150564c7f8792fa2217fc2574e9e1925c9cd500f
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Tue Dec 4 14:05:47 2007 -0800
[quartz] use rectangle_int_t, not rectangle_int16_t
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 6b37dfa..b51a85a 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1669,7 +1669,7 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
cairo_pattern_t *source,
cairo_surface_pattern_t *mask)
{
- cairo_rectangle_int16_t extents;
+ cairo_rectangle_int_t extents;
cairo_quartz_surface_t *quartz_surf;
CGRect rect;
CGImageRef img;
commit e8574022f949559c069da30f11dee8680fc59586
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Tue Dec 4 13:54:32 2007 -0800
[quartz] cleanup: remove trailing whitespace
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index d1339db..6b37dfa 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -86,7 +86,7 @@ CG_EXTERN CGSize CGContextGetPatternPhase (CGContextRef);
/* We need to work with the 10.3 SDK as well (and 10.3 machines; luckily, 10.3.9
* has all the stuff we care about, just some of it isn't exported in the SDK.
- */
+ */
#ifndef kCGBitmapByteOrder32Host
#define USE_10_3_WORKAROUNDS
#define kCGBitmapAlphaInfoMask 0x1F
@@ -171,7 +171,7 @@ _cairo_path_to_quartz_context_line_to (void *closure, cairo_point_t *point)
quartz_stroke_t *stroke = (quartz_stroke_t *)closure;
double x = _cairo_fixed_to_double (point->x);
double y = _cairo_fixed_to_double (point->y);
-
+
if (stroke->ctm_inverse)
cairo_matrix_transform_point (stroke->ctm_inverse, &x, &y);
@@ -390,12 +390,12 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat,
return CAIRO_INT_STATUS_UNSUPPORTED;
/* bandaid for mozilla bug 379321, also visible in the
- * linear-gradient-reflect test.
+ * linear-gradient-reflect test.
*/
if (abspat->extend == CAIRO_EXTEND_REFLECT ||
abspat->extend == CAIRO_EXTEND_REPEAT)
return CAIRO_INT_STATUS_UNSUPPORTED;
-
+
/* We can only do this if we have an identity pattern matrix;
* otherwise fall back through to the generic pattern case.
* XXXperf we could optimize this by creating a pattern with the shading;
@@ -1093,7 +1093,7 @@ _cairo_quartz_surface_create_similar (void *abstract_surface,
format = CAIRO_FORMAT_A8;
else
return NULL;
-
+
// verify width and height of surface
if (!verify_surface_size(width, height)) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -1115,7 +1115,7 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
cairo_quartz_surface_t *new_surface = NULL;
cairo_format_t new_format;
CGImageRef quartz_image = NULL;
-
+
*clone_out = NULL;
// verify width and height of surface
@@ -1435,7 +1435,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
for (k = 0; k < max_dashes; k++)
fdash[k] = (float) style->dash[k % style->num_dashes];
-
+
CGContextSetLineDash (surface->cgContext, style->dash_offset, fdash, max_dashes);
if (fdash != sdash)
free (fdash);
@@ -1561,9 +1561,9 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
* text matrix?
*/
//ND((stderr, "show_glyphs: glyph 0 at: %f, %f\n", glyphs[0].x, glyphs[0].y));
- cairoTextTransform = CGAffineTransformMake (scaled_font->font_matrix.xx,
+ cairoTextTransform = CGAffineTransformMake (scaled_font->font_matrix.xx,
scaled_font->font_matrix.yx,
- scaled_font->font_matrix.xy,
+ scaled_font->font_matrix.xy,
scaled_font->font_matrix.yy,
0., 0.);
@@ -1656,7 +1656,7 @@ BAIL:
}
_cairo_quartz_teardown_source (surface, source);
-
+
CGContextRestoreGState (surface->cgContext);
return rv;
@@ -1885,7 +1885,7 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
return surface;
}
-
+
/**
* cairo_quartz_surface_create_for_cg_context
* @cgContext: the existing CGContext for which to create the surface
commit ee01a94726b3c0782fa182c9e874b2ed57e71aca
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Tue Dec 4 13:53:03 2007 -0800
[quartz] Use CGContextDrawTiledImage if available
Use this 10.5-only method if available, as it greatly speeds up
tiled image rendering (EXTEND_REPEAT).
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 977c71f..d1339db 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -103,6 +103,9 @@ CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef);
/* missing in 10.3.9 */
extern void CGContextClipToMask (CGContextRef, CGRect, CGImageRef) __attribute__((weak_import));
+/* 10.5-only optimization */
+extern void CGContextDrawTiledImage (CGContextRef, CGRect, CGImageRef) __attribute__((weak_import));
+
/*
* Utility functions
*/
@@ -699,7 +702,8 @@ typedef enum {
DO_PATTERN,
DO_IMAGE,
DO_UNSUPPORTED,
- DO_NOTHING
+ DO_NOTHING,
+ DO_TILED_IMAGE
} cairo_quartz_action_t;
static cairo_quartz_action_t
@@ -737,7 +741,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
return DO_SHADING;
} else if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
- source->extend == CAIRO_EXTEND_NONE)
+ (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImage && source->extend == CAIRO_EXTEND_REPEAT)))
{
cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source;
cairo_surface_t *pat_surf = spat->surface;
@@ -771,7 +775,10 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
- return DO_IMAGE;
+ if (source->extend == CAIRO_EXTEND_NONE)
+ return DO_IMAGE;
+ else
+ return DO_TILED_IMAGE;
} else if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
float patternAlpha = 1.0f;
CGColorSpaceRef patternSpace;
@@ -1247,24 +1254,31 @@ _cairo_quartz_surface_paint (void *abstract_surface,
surface->extents.height));
} else if (action == DO_SHADING) {
CGContextDrawShading (surface->cgContext, surface->sourceShading);
- } else if (action == DO_IMAGE) {
+ } 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);
- CGContextSetRGBFillColor (surface->cgContext, 0.0, 0.0, 0.0, 0.0);
- CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
- surface->extents.y,
- surface->extents.width,
- surface->extents.height));
+
+ if (action == DO_IMAGE && op != CAIRO_OPERATOR_OVER) {
+ CGContextSetRGBFillColor (surface->cgContext, 0.0, 0.0, 0.0, 0.0);
+ CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
+ surface->extents.y,
+ surface->extents.width,
+ surface->extents.height));
+ }
+
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);
}
- CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+ if (action == DO_IMAGE)
+ CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+ else
+ CGContextDrawTiledImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
CGContextRestoreGState (surface->cgContext);
} else if (action != DO_NOTHING) {
rv = CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1328,7 +1342,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
CGContextEOClip (surface->cgContext);
CGContextDrawShading (surface->cgContext, surface->sourceShading);
- } else if (action == DO_IMAGE) {
+ } 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;
@@ -1337,18 +1351,24 @@ _cairo_quartz_surface_fill (void *abstract_surface,
else
CGContextEOClip (surface->cgContext);
- CGContextSetRGBFillColor (surface->cgContext, 0.0, 0.0, 0.0, 0.0);
- CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
- surface->extents.y,
- surface->extents.width,
- surface->extents.height));
+ if (action == DO_IMAGE && op != CAIRO_OPERATOR_OVER) {
+ CGContextSetRGBFillColor (surface->cgContext, 0.0, 0.0, 0.0, 0.0);
+ CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
+ surface->extents.y,
+ surface->extents.width,
+ surface->extents.height));
+ }
+
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);
}
- CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+ if (action == DO_IMAGE)
+ CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+ else
+ CGContextDrawTiledImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
} else if (action != DO_NOTHING) {
rv = CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -1435,22 +1455,28 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
if (action == DO_SOLID || action == DO_PATTERN) {
CGContextStrokePath (surface->cgContext);
- } else if (action == DO_IMAGE) {
+ } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
CGContextReplacePathWithStrokedPath (surface->cgContext);
CGContextClip (surface->cgContext);
- CGContextSetRGBFillColor (surface->cgContext, 0.0, 0.0, 0.0, 0.0);
- CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
- surface->extents.y,
- surface->extents.width,
- surface->extents.height));
+ if (action == DO_IMAGE && op != CAIRO_OPERATOR_OVER) {
+ CGContextSetRGBFillColor (surface->cgContext, 0.0, 0.0, 0.0, 0.0);
+ CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
+ surface->extents.y,
+ surface->extents.width,
+ surface->extents.height));
+ }
+
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);
}
- CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+ if (action == DO_IMAGE)
+ CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+ else
+ CGContextDrawTiledImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
} else if (action == DO_SHADING) {
CGContextReplacePathWithStrokedPath (surface->cgContext);
CGContextClip (surface->cgContext);
@@ -1512,7 +1538,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
action = _cairo_quartz_setup_source (surface, source);
if (action == DO_SOLID || action == DO_PATTERN) {
CGContextSetTextDrawingMode (surface->cgContext, kCGTextFill);
- } else if (action == DO_IMAGE || action == DO_SHADING) {
+ } else if (action == DO_IMAGE || action == DO_TILED_IMAGE || action == DO_SHADING) {
CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip);
} else {
if (action != DO_NOTHING)
@@ -1597,19 +1623,25 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
cg_advances,
num_glyphs);
- if (action == DO_IMAGE) {
- CGContextSetRGBFillColor (surface->cgContext, 0.0, 0.0, 0.0, 0.0);
- CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
- surface->extents.y,
- surface->extents.width,
- surface->extents.height));
+ if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
+ if (action == DO_IMAGE && op != CAIRO_OPERATOR_OVER) {
+ CGContextSetRGBFillColor (surface->cgContext, 0.0, 0.0, 0.0, 0.0);
+ CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
+ surface->extents.y,
+ surface->extents.width,
+ surface->extents.height));
+ }
+
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);
}
- CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+ if (action == DO_IMAGE)
+ CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+ else
+ CGContextDrawTiledImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
} else if (action == DO_SHADING) {
CGContextDrawShading (surface->cgContext, surface->sourceShading);
}
commit 2c25033e14d7d9f705c27683dfb093318d67910b
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Tue Dec 4 13:49:59 2007 -0800
[quartz] Handle creating 0x0 surfaces
Make all 0x0 surfaces be no-ops when used in a rendering operation.
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index b3d0634..977c71f 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -57,6 +57,8 @@
#define ND(_x) do {} while(0)
#endif
+#define IS_EMPTY(s) ((s)->extents.width == 0 || (s)->extents.height == 0)
+
/* This method is private, but it exists. Its params are are exposed
* as args to the NS* method, but not as CG.
*/
@@ -108,6 +110,12 @@ extern void CGContextClipToMask (CGContextRef, CGRect, CGImageRef) __attribute__
static void quartz_surface_to_png (cairo_quartz_surface_t *nq, char *dest);
static void quartz_image_to_png (CGImageRef, char *dest);
+static cairo_quartz_surface_t *
+_cairo_quartz_surface_create_internal (CGContextRef cgContext,
+ cairo_content_t content,
+ unsigned int width,
+ unsigned int height);
+
/* CoreGraphics limitation with flipped CTM surfaces: height must be less than signed 16-bit max */
#define CG_MAX_HEIGHT SHRT_MAX
@@ -690,7 +698,8 @@ typedef enum {
DO_SHADING,
DO_PATTERN,
DO_IMAGE,
- DO_UNSUPPORTED
+ DO_UNSUPPORTED,
+ DO_NOTHING
} cairo_quartz_action_t;
static cairo_quartz_action_t
@@ -742,6 +751,11 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
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);
if (!img)
return DO_UNSUPPORTED;
@@ -757,8 +771,6 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
- surface->sourceImageSurface = (cairo_surface_t *)quartz_surf;
-
return DO_IMAGE;
} else if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
float patternAlpha = 1.0f;
@@ -845,6 +857,13 @@ _cairo_quartz_get_image (cairo_quartz_surface_t *surface,
unsigned char *imageData;
cairo_image_surface_t *isurf;
+ if (IS_EMPTY(surface)) {
+ *image_out = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
+ if (data_out)
+ *data_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
if (CGBitmapContextGetBitsPerPixel(surface->cgContext) != 0) {
unsigned int stride;
unsigned int bitinfo;
@@ -927,6 +946,9 @@ _cairo_quartz_surface_finish (void *abstract_surface)
ND((stderr, "_cairo_quartz_surface_finish[%p] cgc: %p\n", surface, surface->cgContext));
+ if (IS_EMPTY(surface))
+ return CAIRO_STATUS_SUCCESS;
+
/* Restore our saved gstate that we use to reset clipping */
CGContextRestoreGState (surface->cgContext);
@@ -1006,6 +1028,11 @@ _cairo_quartz_surface_release_dest_image (void *abstract_surface,
//ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface));
+ if (IS_EMPTY(surface)) {
+ cairo_surface_destroy ((cairo_surface_t*) image);
+ return;
+ }
+
if (!CGBitmapContextGetData (surface->cgContext)) {
CGDataProviderRef dataProvider;
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
@@ -1080,6 +1107,7 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
{
cairo_quartz_surface_t *new_surface = NULL;
cairo_format_t new_format;
+ CGImageRef quartz_image = NULL;
*clone_out = NULL;
@@ -1088,10 +1116,14 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- CGImageRef quartz_image = NULL;
-
if (cairo_surface_get_type(src) == 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);
+ 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)) {
@@ -1101,6 +1133,11 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
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;
@@ -1193,6 +1230,9 @@ _cairo_quartz_surface_paint (void *abstract_surface,
ND((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
+ if (IS_EMPTY(surface))
+ return CAIRO_STATUS_SUCCESS;
+
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
@@ -1226,7 +1266,7 @@ _cairo_quartz_surface_paint (void *abstract_surface,
CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
CGContextRestoreGState (surface->cgContext);
- } else {
+ } else if (action != DO_NOTHING) {
rv = CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -1252,6 +1292,9 @@ _cairo_quartz_surface_fill (void *abstract_surface,
ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
+ if (IS_EMPTY(surface))
+ return CAIRO_STATUS_SUCCESS;
+
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
@@ -1261,10 +1304,6 @@ _cairo_quartz_surface_fill (void *abstract_surface,
CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
action = _cairo_quartz_setup_source (surface, source);
- if (action == DO_UNSUPPORTED) {
- CGContextRestoreGState (surface->cgContext);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
CGContextBeginPath (surface->cgContext);
@@ -1310,7 +1349,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
}
CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
- } else {
+ } else if (action != DO_NOTHING) {
rv = CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -1342,6 +1381,9 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
ND((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type));
+ if (IS_EMPTY(surface))
+ return CAIRO_STATUS_SUCCESS;
+
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
@@ -1382,10 +1424,6 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
action = _cairo_quartz_setup_source (surface, source);
- if (action == DO_UNSUPPORTED) {
- CGContextRestoreGState (surface->cgContext);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
CGContextBeginPath (surface->cgContext);
@@ -1418,7 +1456,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
CGContextClip (surface->cgContext);
CGContextDrawShading (surface->cgContext, surface->sourceShading);
- } else {
+ } else if (action != DO_NOTHING) {
rv = CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -1457,6 +1495,9 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
float xprev, yprev;
int i;
+ if (IS_EMPTY(surface))
+ return CAIRO_STATUS_SUCCESS;
+
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
@@ -1474,8 +1515,8 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
} else if (action == DO_IMAGE || action == DO_SHADING) {
CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip);
} else {
- /* Unsupported */
- rv = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (action != DO_NOTHING)
+ rv = CAIRO_INT_STATUS_UNSUPPORTED;
goto BAIL;
}
@@ -1611,6 +1652,10 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
if (status)
return status;
+ // everything would be masked out, so do nothing
+ if (IS_EMPTY(quartz_surf))
+ goto BAIL;
+
img = CGBitmapContextCreateImage (quartz_surf->cgContext);
if (!img) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -1640,6 +1685,9 @@ _cairo_quartz_surface_mask (void *abstract_surface,
ND((stderr, "%p _cairo_quartz_surface_mask op %d source->type %d mask->type %d\n", surface, op, source->type, mask->type));
+ if (IS_EMPTY(surface))
+ return CAIRO_STATUS_SUCCESS;
+
if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
/* This is easy; we just need to paint with the alpha. */
cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
@@ -1684,6 +1732,9 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface,
ND((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path));
+ if (IS_EMPTY(surface))
+ return CAIRO_STATUS_SUCCESS;
+
if (path == NULL) {
/* If we're being asked to reset the clip, we can only do it
* by restoring the gstate to our previous saved one, and
@@ -1700,7 +1751,7 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface,
stroke.ctm_inverse = NULL;
/* path must not be empty. */
- CGContextMoveToPoint (surface->cgContext, 0, 0);
+ CGContextMoveToPoint (surface->cgContext, 0, 0);
status = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
if (status)
return status;
@@ -1748,7 +1799,7 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
_cairo_quartz_surface_fill,
#if CAIRO_HAS_ATSUI_FONT
_cairo_quartz_surface_show_glyphs,
-#else
+#else
NULL, /* surface_show_glyphs */
#endif /* CAIRO_HAS_ATSUI_FONT */
@@ -1758,7 +1809,7 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
NULL /* fill_stroke */
};
-static cairo_quartz_surface_t *
+cairo_quartz_surface_t *
_cairo_quartz_surface_create_internal (CGContextRef cgContext,
cairo_content_t content,
unsigned int width,
@@ -1783,6 +1834,13 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
surface->extents.width = width;
surface->extents.height = height;
+ if (IS_EMPTY(surface)) {
+ surface->cgContext = NULL;
+ surface->cgContextBaseCTM = CGAffineTransformIdentity;
+ surface->imageData = NULL;
+ return surface;
+ }
+
/* Save so we can always get back to a known-good CGContext -- this is
* required for proper behaviour of intersect_clip_path(NULL)
*/
@@ -1835,7 +1893,7 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
CGContextRetain (cgContext);
surf = _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA,
- width, height);
+ width, height);
if (!surf) {
CGContextRelease (cgContext);
// create_internal will have set an error
@@ -1879,6 +1937,11 @@ cairo_quartz_surface_create (cairo_format_t format,
return (cairo_surface_t*) &_cairo_surface_nil;
}
+ if (width == 0 || height == 0) {
+ return (cairo_surface_t*) _cairo_quartz_surface_create_internal (NULL, _cairo_content_from_format (format),
+ width, height);
+ }
+
if (format == CAIRO_FORMAT_ARGB32) {
cgColorspace = CGColorSpaceCreateDeviceRGB();
stride = width * 4;
@@ -1938,7 +2001,7 @@ cairo_quartz_surface_create (cairo_format_t format,
CGContextScaleCTM (cgc, 1.0, -1.0);
surf = _cairo_quartz_surface_create_internal (cgc, _cairo_content_from_format (format),
- width, height);
+ width, height);
if (!surf) {
CGContextRelease (cgc);
free (imageData);
diff --git a/test/.gitignore b/test/.gitignore
index b75c7f2..91d5096 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -17,6 +17,7 @@ clip-nesting
clip-operator
clip-push-group
clip-twice
+clip-zero
close-path
composite-integer-translate-source
composite-integer-translate-over
diff --git a/test/Makefile.am b/test/Makefile.am
index 3cb0708..ec2d028 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -15,6 +15,7 @@ clip-nesting \
clip-operator \
clip-push-group \
clip-twice \
+clip-zero \
close-path \
composite-integer-translate-source \
composite-integer-translate-over \
diff --git a/test/clip-zero.c b/test/clip-zero.c
new file mode 100644
index 0000000..ec2dcc8
--- /dev/null
+++ b/test/clip-zero.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2007 Mozilla Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Vladimir Vukicevic <vladimir at pobox.com>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_draw_function_t draw;
+
+cairo_test_t test = {
+ "clip-zero",
+ "Verifies that 0x0 surfaces or clips don't cause problems.",
+ 0, 0,
+ draw
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_pattern_t *pat;
+ cairo_surface_t *surf;
+
+ cairo_new_path (cr);
+ cairo_rectangle (cr, 0, 0, 0, 0);
+ cairo_clip (cr);
+
+ cairo_push_group (cr);
+
+ cairo_set_source_rgb (cr, 1, 0, 0);
+
+ cairo_new_path (cr);
+ cairo_rectangle (cr, -10, 10, 20, 20);
+ cairo_fill_preserve (cr);
+ cairo_stroke_preserve (cr);
+ cairo_paint (cr);
+
+ cairo_select_font_face (cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_show_text (cr, "ABC");
+
+ cairo_mask (cr, cairo_get_source (cr));
+
+ surf = cairo_surface_create_similar (cairo_get_target (cr), CAIRO_CONTENT_COLOR_ALPHA, 0, 0);
+ pat = cairo_pattern_create_for_surface (surf);
+ cairo_surface_destroy (surf);
+
+ cairo_mask (cr, pat);
+ cairo_pattern_destroy (pat);
+
+ cairo_pop_group_to_source (cr);
+ cairo_paint (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test);
+}
More information about the cairo-commit
mailing list