[cairo-commit] 2 commits - src/cairo-quartz-surface.c src/cairo-win32-surface.c

Vladimir Vukicevic vladimir at kemper.freedesktop.org
Sun Jan 27 16:52:43 PST 2008


 src/cairo-quartz-surface.c |  144 ++++++++++++++++++++++++---------------------
 src/cairo-win32-surface.c  |    3 
 2 files changed, 78 insertions(+), 69 deletions(-)

New commits:
commit 936edecb35b94213997fdb172f0256c658f416aa
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Sun Jan 27 16:52:39 2008 -0800

    [quartz] only use DrawTiledImage if transformed image is integer aligned
    
    This Quartz API seems to only tile at integer coordinates; if the source image is
    scaled to anything less than integer-aligned, seams appear between tiles.  Detect
    this and fall back to slower but more general CGPattern path.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 0688284..166b443 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -766,55 +766,99 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
 				  solid->color.alpha);
 
 	return DO_SOLID;
-    } else if (source->type == CAIRO_PATTERN_TYPE_LINEAR)
-    {
+    }
+
+    if (source->type == CAIRO_PATTERN_TYPE_LINEAR) {
 	cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t *)source;
 	return _cairo_quartz_setup_linear_source (surface, lpat);
 
-    } else if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
+    }
+
+    if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
 	cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t *)source;
 	return _cairo_quartz_setup_radial_source (surface, rpat);
 
-    } else if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
-	       (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
+    }
+
+    if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+	(source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
     {
-	    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;
-	    cairo_status_t status;
+	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;
+	cairo_status_t status;
+	CGAffineTransform xform;
+	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;
+	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;
+	surface->sourceImageSurface = (cairo_surface_t *)quartz_surf;
 
-	    if (IS_EMPTY(quartz_surf))
-		return DO_NOTHING;
+	if (IS_EMPTY(quartz_surf))
+	    return DO_NOTHING;
 
-	    img = CGBitmapContextCreateImage (quartz_surf->cgContext);
-	    if (!img)
-		return DO_UNSUPPORTED;
+	img = CGBitmapContextCreateImage (quartz_surf->cgContext);
+	if (!img)
+	    return DO_UNSUPPORTED;
 
-	    surface->sourceImage = img;
+	surface->sourceImage = img;
 
-	    cairo_matrix_invert(&m);
-	    _cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceImageTransform);
+	cairo_matrix_invert(&m);
+	_cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceImageTransform);
 
-	    status = _cairo_surface_get_extents (pat_surf, &extents);
-	    if (status)
-		return DO_UNSUPPORTED;
+	status = _cairo_surface_get_extents (pat_surf, &extents);
+	if (status)
+	    return DO_UNSUPPORTED;
 
+	if (source->extend == CAIRO_EXTEND_NONE) {
 	    surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
+	    return DO_IMAGE;
+	}
+
+	/* Quartz seems to tile images at pixel-aligned regions only -- this
+	 * leads to seams if the image doesn't end up scaling to fill the
+	 * space exactly.  The CGPattern tiling approach doesn't have this
+	 * problem.  Check if we're going to fill up the space (within some
+	 * epsilon), and if not, fall back to the CGPattern type.
+	 */
+
+	xform = CGAffineTransformConcat (CGContextGetCTM (surface->cgContext),
+					 surface->sourceImageTransform);
+
+	srcRect = CGRectMake (0, 0, extents.width, extents.height);
+	srcRect = CGRectApplyAffineTransform (srcRect, xform);
 
-	    if (source->extend == CAIRO_EXTEND_NONE)
-		return DO_IMAGE;
-	    else
-		return DO_TILED_IMAGE;
-    } else if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	fw = _cairo_fixed_from_double (srcRect.size.width);
+	fh = _cairo_fixed_from_double (srcRect.size.height);
+
+	if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON &&
+	    (fh & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON)
+	{
+	    /* We're good to use DrawTiledImage, but ensure that
+	     * the math works out */
+
+	    srcRect.size.width = round(srcRect.size.width);
+	    srcRect.size.height = round(srcRect.size.height);
+
+	    xform = CGAffineTransformInvert (xform);
+
+	    srcRect = CGRectApplyAffineTransform (srcRect, xform);
+
+	    surface->sourceImageRect = srcRect;
+
+	    return DO_TILED_IMAGE;
+	}
+
+	/* Fall through to generic SURFACE case */
+    }
+
+    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	float patternAlpha = 1.0f;
 	CGColorSpaceRef patternSpace;
 	CGPatternRef pattern;
@@ -845,11 +889,9 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
 	surface->sourcePattern = pattern;
 
 	return DO_PATTERN;
-    } else {
-	return DO_UNSUPPORTED;
     }
 
-    ASSERT_NOT_REACHED;
+    return DO_UNSUPPORTED;
 }
 
 static void
@@ -1245,14 +1287,6 @@ _cairo_quartz_surface_paint (void *abstract_surface,
 
 	CGContextSaveGState (surface->cgContext);
 
-	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));
@@ -1335,14 +1369,6 @@ _cairo_quartz_surface_fill (void *abstract_surface,
 	else
 	    CGContextEOClip (surface->cgContext);
 
-	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));
@@ -1443,14 +1469,6 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
 	CGContextReplacePathWithStrokedPath (surface->cgContext);
 	CGContextClip (surface->cgContext);
 
-	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));
@@ -1603,14 +1621,6 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
 				     num_glyphs);
 
     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));
commit 182b02240192c03b1fae5367573962d527f8aad4
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Sat Jan 26 10:57:20 2008 -0800

    [win32] Fix initial clip region test
    
    I misread the docs; GetClipBox's return value doesn't necessarily correspond to
    GetClipRgn's region type.

diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 69c6406..4017e2f 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -2052,8 +2052,7 @@ _cairo_win32_save_initial_clip (HDC hdc, cairo_win32_surface_t *surface)
 
     if (clipBoxType == COMPLEXREGION) {
 	surface->initial_clip_rgn = CreateRectRgn (0, 0, 0, 0);
-	if (GetClipRgn (hdc, surface->initial_clip_rgn) == -1) {
-	    /* this should never happen */
+	if (GetClipRgn (hdc, surface->initial_clip_rgn) <= 0) {
 	    DeleteObject(surface->initial_clip_rgn);
 	    surface->initial_clip_rgn = NULL;
 	}


More information about the cairo-commit mailing list