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

Andrea Canciani ranma42 at kemper.freedesktop.org
Tue Nov 10 04:04:17 PST 2009


 src/cairo-quartz-surface.c |  328 +++++++++++++++++++++++++++------------------
 1 file changed, 200 insertions(+), 128 deletions(-)

New commits:
commit 7d8788b4ba5ae335a7bb77bd09e7ebd20376f632
Author: Robert O'Callahan <robert at ocallahan.org>
Date:   Mon Nov 9 18:58:59 2009 +0100

    [quartz] Cleanup fallback source
    
    Remove the transformation code as it's useless and confusing.
    The clipbox was transformed in a wrong way if the CTM
    was not the base one, otherwise the transformation did nothing.
    As long as _cairo_quartz_setup_fallback_source is only called
    with the base CTM, no transformation needs to be performed on the
    clipbox.
    Patch by Robert O'Callahan, see Mozilla bug #507939.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 6a0d0e7..44b25a3 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1148,7 +1148,6 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
 				     const cairo_pattern_t *source)
 {
     CGRect clipBox = CGContextGetClipBoundingBox (surface->cgContext);
-    CGAffineTransform ctm;
     double x0, y0, w, h;
 
     cairo_surface_t *fallback;
@@ -1160,14 +1159,6 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
 	clipBox.size.height == 0.0f)
 	return DO_NOTHING;
 
-    // the clipBox is in userspace, so:
-    ctm = CGContextGetCTM (surface->cgContext);
-    ctm = CGAffineTransformInvert (ctm);
-    clipBox = CGRectApplyAffineTransform (clipBox, ctm);
-
-    // get the Y flip right -- the CTM will always have a Y flip in place
-    clipBox.origin.y = surface->extents.height - (clipBox.origin.y + clipBox.size.height);
-
     x0 = floor(clipBox.origin.x);
     y0 = floor(clipBox.origin.y);
     w = ceil(clipBox.origin.x + clipBox.size.width) - x0;
commit 248090e52b02f2b2dc424c6073489df32632b9d1
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Mon Nov 9 21:38:00 2009 +0100

    [quartz] Fix compositing operators
    
    Fallback on SATURATE (since quartz doesn't support it) and on
    blending operators (to be implemented using CGContextSetBlendMode,
    after its availability has been assessed).
    Workaround the different behaviour of quartz operators on alpha
    masks.
    Fixes text in clip-operator and clip-text, blend modes in
    extended-blend, extended-blend-alpha, saturate in operator,
    operator-alpha and surface-pattern-operator.
    Changes the output of operator-alpha-alpha, but to really fix it
    pure-alpha surfaces needs to be treated as alpha masks and not as
    greyscale images.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index b607278..6a0d0e7 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -385,7 +385,7 @@ _cairo_quartz_cairo_path_to_quartz_context (cairo_path_fixed_t *path,
  */
 
 static PrivateCGCompositeMode
-_cairo_quartz_cairo_operator_to_quartz (cairo_operator_t op)
+_cairo_quartz_cairo_operator_to_quartz_composite (cairo_operator_t op)
 {
     switch (op) {
 	case CAIRO_OPERATOR_CLEAR:
@@ -395,39 +395,150 @@ _cairo_quartz_cairo_operator_to_quartz (cairo_operator_t op)
 	case CAIRO_OPERATOR_OVER:
 	    return kPrivateCGCompositeSourceOver;
 	case CAIRO_OPERATOR_IN:
-	    /* XXX This doesn't match image output */
 	    return kPrivateCGCompositeSourceIn;
 	case CAIRO_OPERATOR_OUT:
-	    /* XXX This doesn't match image output */
 	    return kPrivateCGCompositeSourceOut;
 	case CAIRO_OPERATOR_ATOP:
 	    return kPrivateCGCompositeSourceAtop;
-
-	case CAIRO_OPERATOR_DEST:
-	    /* XXX this is handled specially (noop)! */
-	    return kPrivateCGCompositeCopy;
 	case CAIRO_OPERATOR_DEST_OVER:
 	    return kPrivateCGCompositeDestinationOver;
 	case CAIRO_OPERATOR_DEST_IN:
-	    /* XXX This doesn't match image output */
 	    return kPrivateCGCompositeDestinationIn;
 	case CAIRO_OPERATOR_DEST_OUT:
 	    return kPrivateCGCompositeDestinationOut;
 	case CAIRO_OPERATOR_DEST_ATOP:
-	    /* XXX This doesn't match image output */
 	    return kPrivateCGCompositeDestinationAtop;
-
 	case CAIRO_OPERATOR_XOR:
-	    return kPrivateCGCompositeXOR; /* This will generate strange results */
+	    return kPrivateCGCompositeXOR;
 	case CAIRO_OPERATOR_ADD:
 	    return kPrivateCGCompositePlusLighter;
+
+	case CAIRO_OPERATOR_DEST:
 	case CAIRO_OPERATOR_SATURATE:
-	    /* XXX This doesn't match image output for SATURATE; there's no equivalent */
-	    return kPrivateCGCompositePlusDarker;  /* ??? */
+	case CAIRO_OPERATOR_MULTIPLY:
+	case CAIRO_OPERATOR_SCREEN:
+	case CAIRO_OPERATOR_OVERLAY:
+	case CAIRO_OPERATOR_DARKEN:
+	case CAIRO_OPERATOR_LIGHTEN:
+	case CAIRO_OPERATOR_COLOR_DODGE:
+	case CAIRO_OPERATOR_COLOR_BURN:
+	case CAIRO_OPERATOR_HARD_LIGHT:
+	case CAIRO_OPERATOR_SOFT_LIGHT:
+	case CAIRO_OPERATOR_DIFFERENCE:
+	case CAIRO_OPERATOR_EXCLUSION:
+	case CAIRO_OPERATOR_HSL_HUE:
+	case CAIRO_OPERATOR_HSL_SATURATION:
+	case CAIRO_OPERATOR_HSL_COLOR:
+	case CAIRO_OPERATOR_HSL_LUMINOSITY:
+        default:
+	    assert (0);
     }
+}
+
+static cairo_int_status_t
+_cairo_quartz_surface_set_cairo_operator (cairo_quartz_surface_t *surface, cairo_operator_t op)
+{
+    ND((stderr, "%p _cairo_quartz_surface_set_cairo_operator %d\n", surface, op));
+
+    if (surface->base.content == CAIRO_CONTENT_ALPHA) {
+	/* For some weird reason, some compositing operators are
+	   swapped when operating on masks */
+	switch (op) {
+	    case CAIRO_OPERATOR_CLEAR:
+	    case CAIRO_OPERATOR_SOURCE:
+	    case CAIRO_OPERATOR_OVER:
+	    case CAIRO_OPERATOR_DEST_IN:
+	    case CAIRO_OPERATOR_DEST_OUT:
+	    case CAIRO_OPERATOR_ADD:
+		CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz_composite (op));
+		return CAIRO_STATUS_SUCCESS;
 
+	    case CAIRO_OPERATOR_IN:
+		CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositeDestinationAtop);
+		return CAIRO_STATUS_SUCCESS;
+
+	    case CAIRO_OPERATOR_DEST_OVER:
+	    case CAIRO_OPERATOR_MULTIPLY:
+	    case CAIRO_OPERATOR_SCREEN:
+	    case CAIRO_OPERATOR_OVERLAY:
+	    case CAIRO_OPERATOR_DARKEN:
+	    case CAIRO_OPERATOR_LIGHTEN:
+	    case CAIRO_OPERATOR_COLOR_DODGE:
+	    case CAIRO_OPERATOR_COLOR_BURN:
+	    case CAIRO_OPERATOR_HARD_LIGHT:
+	    case CAIRO_OPERATOR_SOFT_LIGHT:
+	    case CAIRO_OPERATOR_DIFFERENCE:
+	    case CAIRO_OPERATOR_EXCLUSION:
+	    case CAIRO_OPERATOR_HSL_HUE:
+	    case CAIRO_OPERATOR_HSL_SATURATION:
+	    case CAIRO_OPERATOR_HSL_COLOR:
+	    case CAIRO_OPERATOR_HSL_LUMINOSITY:
+		CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositeSourceOver);
+		return CAIRO_STATUS_SUCCESS;
+
+	    case CAIRO_OPERATOR_DEST_ATOP:
+		CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositeSourceIn);
+		return CAIRO_STATUS_SUCCESS;
+
+	    case CAIRO_OPERATOR_SATURATE:
+		CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositePlusLighter);
+		return CAIRO_STATUS_SUCCESS;
+
+
+	    case CAIRO_OPERATOR_ATOP:
+		/*
+		CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositeDestinationOver);
+		return CAIRO_STATUS_SUCCESS;
+		*/
+	    case CAIRO_OPERATOR_DEST:
+		return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+	    case CAIRO_OPERATOR_OUT:
+	    case CAIRO_OPERATOR_XOR:
+	    default:
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+	}
+    } else {
+	switch (op) {
+	    case CAIRO_OPERATOR_CLEAR:
+	    case CAIRO_OPERATOR_SOURCE:
+	    case CAIRO_OPERATOR_OVER:
+	    case CAIRO_OPERATOR_IN:
+	    case CAIRO_OPERATOR_OUT:
+	    case CAIRO_OPERATOR_ATOP:
+	    case CAIRO_OPERATOR_DEST_OVER:
+	    case CAIRO_OPERATOR_DEST_IN:
+	    case CAIRO_OPERATOR_DEST_OUT:
+	    case CAIRO_OPERATOR_DEST_ATOP:
+	    case CAIRO_OPERATOR_XOR:
+	    case CAIRO_OPERATOR_ADD:
+		CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz_composite (op));
+		return CAIRO_STATUS_SUCCESS;
 
-    return kPrivateCGCompositeCopy;
+	    case CAIRO_OPERATOR_DEST:
+		return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+	    case CAIRO_OPERATOR_SATURATE:
+	    /* TODO: the following are mostly supported by CGContextSetBlendMode*/
+	    case CAIRO_OPERATOR_MULTIPLY:
+	    case CAIRO_OPERATOR_SCREEN:
+	    case CAIRO_OPERATOR_OVERLAY:
+	    case CAIRO_OPERATOR_DARKEN:
+	    case CAIRO_OPERATOR_LIGHTEN:
+	    case CAIRO_OPERATOR_COLOR_DODGE:
+	    case CAIRO_OPERATOR_COLOR_BURN:
+	    case CAIRO_OPERATOR_HARD_LIGHT:
+	    case CAIRO_OPERATOR_SOFT_LIGHT:
+	    case CAIRO_OPERATOR_DIFFERENCE:
+	    case CAIRO_OPERATOR_EXCLUSION:
+	    case CAIRO_OPERATOR_HSL_HUE:
+	    case CAIRO_OPERATOR_HSL_SATURATION:
+	    case CAIRO_OPERATOR_HSL_COLOR:
+	    case CAIRO_OPERATOR_HSL_LUMINOSITY:
+	    default:
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+	}
+    }
 }
 
 static inline CGLineCap
@@ -1766,14 +1877,13 @@ _cairo_quartz_surface_paint (void *abstract_surface,
     if (IS_EMPTY(surface))
 	return CAIRO_STATUS_SUCCESS;
 
-    if (op == CAIRO_OPERATOR_DEST)
-	return CAIRO_STATUS_SUCCESS;
-
     rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
     if (unlikely (rv))
 	return rv;
 
-    CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
+    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
+    if (unlikely (rv))
+	return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
 
     action = _cairo_quartz_setup_source (surface, source);
 
@@ -1815,7 +1925,6 @@ _cairo_quartz_surface_fill (void *abstract_surface,
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
     cairo_quartz_action_t action;
     quartz_stroke_t stroke;
-    cairo_box_t box;
     CGPathRef path_for_unbounded = NULL;
 
     ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
@@ -1823,27 +1932,17 @@ _cairo_quartz_surface_fill (void *abstract_surface,
     if (IS_EMPTY(surface))
 	return CAIRO_STATUS_SUCCESS;
 
-    if (op == CAIRO_OPERATOR_DEST)
-	return CAIRO_STATUS_SUCCESS;
-
-    /* Check whether the path would be a no-op */
-    /* XXX handle unbounded ops */
-    if (_cairo_path_fixed_fill_is_empty(path) ||
-	(_cairo_path_fixed_is_box(path, &box) &&
-	 box.p1.x == box.p2.x &&
-	 box.p1.y == box.p2.y))
-    {
-	return CAIRO_STATUS_SUCCESS;
-    }
-
     rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
     if (unlikely (rv))
 	return rv;
 
+    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
+    if (unlikely (rv))
+	return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
+
     CGContextSaveGState (surface->cgContext);
 
     CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
-    CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
 
     action = _cairo_quartz_setup_source (surface, source);
 
@@ -1928,13 +2027,14 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
     if (IS_EMPTY(surface))
 	return CAIRO_STATUS_SUCCESS;
 
-    if (op == CAIRO_OPERATOR_DEST)
-	return CAIRO_STATUS_SUCCESS;
-
     rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
     if (unlikely (rv))
 	return rv;
 
+    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
+    if (unlikely (rv))
+	return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
+
     // Turning antialiasing off used to cause misrendering with
     // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels).
     // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases.
@@ -1971,7 +2071,6 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
 
     CGContextSaveGState (surface->cgContext);
 
-    CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
 
     action = _cairo_quartz_setup_source (surface, source);
 
@@ -2070,9 +2169,6 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
     if (num_glyphs <= 0)
 	return CAIRO_STATUS_SUCCESS;
 
-    if (op == CAIRO_OPERATOR_DEST)
-	return CAIRO_STATUS_SUCCESS;
-
     if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
@@ -2080,6 +2176,10 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
     if (unlikely (rv))
 	return rv;
 
+    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
+    if (unlikely (rv))
+	return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
+
     CGContextSaveGState (surface->cgContext);
 
     action = _cairo_quartz_setup_source (surface, source);
@@ -2094,8 +2194,6 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
 	goto BAIL;
     }
 
-    CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
-
     /* this doesn't addref */
     cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font);
     CGContextSetFont (surface->cgContext, cgfref);
commit d44414191a685a23fd48bb32826366dfd113e1e5
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Mon Nov 9 14:21:40 2009 +0100

    [quartz] Fix source-unbounded compositing of surface sources
    
    Surface sources were not respecting EXTEND_NONE when composited
    because the part outside of the surface rectangle was not changed.
    To correctly extend the source, it's sufficient to composite a
    transparent rectangle with a hole in the region covered by the surface.
    Fixes clip-unbounded and operator-source. Changes the output of
    surface-pattern-operator.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index e375c61..b607278 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1392,6 +1392,30 @@ _cairo_quartz_teardown_source (cairo_quartz_surface_t *surface,
     }
 }
 
+
+static void
+_cairo_quartz_draw_image (cairo_quartz_surface_t *surface, cairo_operator_t op,  cairo_quartz_action_t action)
+{
+    assert (surface && surface->sourceImage && (action == DO_IMAGE || action == DO_TILED_IMAGE));
+
+    CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
+    CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+    CGContextScaleCTM (surface->cgContext, 1, -1);
+
+    if (action == DO_IMAGE) {
+	CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+	if (!_cairo_operator_bounded_by_source(op)) {
+	    CGContextBeginPath (surface->cgContext);
+	    CGContextAddRect (surface->cgContext, surface->sourceImageRect);
+	    CGContextAddRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext));
+	    CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 0);
+	    CGContextEOFillPath (surface->cgContext);
+	}
+    } else
+	CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+}
+
+
 /*
  * get source/dest image implementation
  */
@@ -1765,15 +1789,7 @@ _cairo_quartz_surface_paint (void *abstract_surface,
 	CGContextRestoreGState (surface->cgContext);
     } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
 	CGContextSaveGState (surface->cgContext);
-
-	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
-	CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
-	CGContextScaleCTM (surface->cgContext, 1, -1);
-
-	if (action == DO_IMAGE)
-	    CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
-	else
-	    CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+	_cairo_quartz_draw_image (surface, op, action);
 	CGContextRestoreGState (surface->cgContext);
     } else if (action != DO_NOTHING) {
 	rv = CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1864,14 +1880,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
 	else
 	    CGContextEOClip (surface->cgContext);
 
-	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
-	CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
-	CGContextScaleCTM (surface->cgContext, 1, -1);
-
-	if (action == DO_IMAGE)
-	    CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
-	else
-	    CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+	_cairo_quartz_draw_image (surface, op, action);
     } else if (action != DO_NOTHING) {
 	rv = CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -1987,15 +1996,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
 	CGContextClip (surface->cgContext);
 
 	CGContextSetCTM (surface->cgContext, origCTM);
-
-	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
-	CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
-	CGContextScaleCTM (surface->cgContext, 1, -1);
-
-	if (action == DO_IMAGE)
-	    CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
-	else
-	    CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+	_cairo_quartz_draw_image (surface, op, action);
     } else if (action == DO_SHADING) {
 	CGContextReplacePathWithStrokedPath (surface->cgContext);
 	CGContextClip (surface->cgContext);
@@ -2198,14 +2199,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
     CGContextSetCTM (surface->cgContext, ctm);
 
     if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
-	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
-	CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
-	CGContextScaleCTM (surface->cgContext, 1, -1);
-
-	if (action == DO_IMAGE)
-	    CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
-	else
-	    CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+	_cairo_quartz_draw_image (surface, op, action);
     } else if (action == DO_SHADING) {
 	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
 	CGContextDrawShading (surface->cgContext, surface->sourceShading);
commit 7ef611a67a2a68d0a50e2191804a8ef137c78b33
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Mon Nov 9 20:17:35 2009 +0100

    [quartz] Fix stroking with unbounded operator
    
    Stroking was not fixed up correctly when the stroke trasform
    was not the identity and when the stroked path was dashed.
    Instead of building a mask image and clearing through it
    (forgetting to use the CTM and the dash setting), the code now
    simply fills the outside of the stroke with tranparent black.
    Additionally this commit moves the CTM composition so that the invocation
    of _cairo_quartz_setup_source is always done with the base CTM.
    This commit changes the result of clip-stroke-unbounded (the clip
    mask is now correctly aligned to the stroked path).

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index d783422..e375c61 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1926,8 +1926,6 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
     if (unlikely (rv))
 	return rv;
 
-    CGContextSaveGState (surface->cgContext);
-
     // Turning antialiasing off used to cause misrendering with
     // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels).
     // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases.
@@ -1939,9 +1937,6 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
 
     origCTM = CGContextGetCTM (surface->cgContext);
 
-    _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform);
-    CGContextConcatCTM (surface->cgContext, strokeTransform);
-
     if (style->dash && style->num_dashes) {
 #define STATIC_DASH 32
 	float sdash[STATIC_DASH];
@@ -1962,12 +1957,18 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
 	CGContextSetLineDash (surface->cgContext, style->dash_offset, fdash, max_dashes);
 	if (fdash != sdash)
 	    free (fdash);
-    }
+    } else
+	CGContextSetLineDash (surface->cgContext, 0, NULL, 0);
+
+    CGContextSaveGState (surface->cgContext);
 
     CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
 
     action = _cairo_quartz_setup_source (surface, source);
 
+    _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform);
+    CGContextConcatCTM (surface->cgContext, strokeTransform);
+
     CGContextBeginPath (surface->cgContext);
 
     stroke.cgContext = surface->cgContext;
@@ -2013,32 +2014,21 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
     CGContextRestoreGState (surface->cgContext);
 
     if (path_for_unbounded) {
-	unbounded_op_data_t ub;
+	CGContextSaveGState (surface->cgContext);
+	CGContextConcatCTM (surface->cgContext, strokeTransform);
 
 	CGContextBeginPath (surface->cgContext);
-
-	/* recreate the stroke state, but without the CTM, as it's been already baked
-	 * into the path.
-	 */
-	CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
-	CGContextSetLineWidth (surface->cgContext, style->line_width);
-	CGContextSetLineCap (surface->cgContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
-	CGContextSetLineJoin (surface->cgContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
-	CGContextSetMiterLimit (surface->cgContext, style->miter_limit);
-
 	CGContextAddPath (surface->cgContext, path_for_unbounded);
 	CGPathRelease (path_for_unbounded);
 
 	CGContextReplacePathWithStrokedPath (surface->cgContext);
-	path_for_unbounded = CGContextCopyPathPtr (surface->cgContext);
 
-	ub.op = UNBOUNDED_STROKE_FILL;
-	ub.u.stroke_fill.cgPath = path_for_unbounded;
-	ub.u.stroke_fill.fill_rule = CAIRO_FILL_RULE_WINDING;
+	CGContextAddRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext));
 
-	_cairo_quartz_fixup_unbounded_operation (surface, &ub, antialias);
+	CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
+	CGContextEOFillPath (surface->cgContext);
 
-	CGPathRelease (path_for_unbounded);
+	CGContextRestoreGState (surface->cgContext);
     }
 
     ND((stderr, "-- stroke\n"));
commit 577ac4fc6d810cae7ff6d460fdea1886cd97258c
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Mon Nov 9 14:24:13 2009 +0100

    [quartz] Fix implied colour of alpha-only surface sources
    
    If a fill colour was set, an alpha-only surface source would
    have used that colour instead of black.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 86cee86..d783422 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1274,6 +1274,8 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
 	if (status)
 	    return DO_UNSUPPORTED;
 
+	CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1);
+
 	surface->sourceImage = img;
 
 	cairo_matrix_invert(&m);
commit 8b25e4a7fd839ac399d14460d2596037134c9801
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Mon Oct 19 18:38:57 2009 +0200

    [quartz] Improve unbounded operators fixup
    
    Don't allocate a colorspace and use a 16-bytes aligned stride and
    an alpha-only image for the rendering of the fixup mask.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index e67ed0b..86cee86 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -526,7 +526,6 @@ _cairo_quartz_fixup_unbounded_operation (cairo_quartz_surface_t *surface,
 					 unbounded_op_data_t *op,
 					 cairo_antialias_t antialias)
 {
-    CGColorSpaceRef gray;
     CGRect clipBox, clipBoxRound;
     CGContextRef cgc;
     CGImageRef maskImage;
@@ -537,26 +536,25 @@ _cairo_quartz_fixup_unbounded_operation (cairo_quartz_surface_t *surface,
     clipBox = CGContextGetClipBoundingBox (surface->cgContext);
     clipBoxRound = CGRectIntegral (clipBox);
 
-    gray = CGColorSpaceCreateDeviceGray ();
     cgc = CGBitmapContextCreate (NULL,
 				 clipBoxRound.size.width,
 				 clipBoxRound.size.height,
 				 8,
-				 clipBoxRound.size.width,
-				 gray,
-				 kCGImageAlphaNone);
-    CGColorSpaceRelease (gray);
+				 (((size_t) clipBoxRound.size.width) + 15) & (~15),
+				 NULL,
+				 kCGImageAlphaOnly);
 
     if (!cgc)
 	return;
 
+    CGContextSetCompositeOperation (cgc, kPrivateCGCompositeCopy);
     /* We want to mask out whatever we just rendered, so we fill the
-     * surface with white, and then we'll render with black.
+     * surface opaque, and then we'll render transparent.
      */
-    CGContextSetRGBFillColor (cgc, 1.0f, 1.0f, 1.0f, 1.0f);
+    CGContextSetAlpha (cgc, 1.0f);
     CGContextFillRect (cgc, CGRectMake (0, 0, clipBoxRound.size.width, clipBoxRound.size.height));
 
-    CGContextSetRGBFillColor (cgc, 0.0f, 0.0f, 0.0f, 1.0f);
+    CGContextSetAlpha (cgc, 0.0f);
     CGContextSetShouldAntialias (cgc, (antialias != CAIRO_ANTIALIAS_NONE));
 
     CGContextTranslateCTM (cgc, -clipBoxRound.origin.x, -clipBoxRound.origin.y);
commit ed8bdcd59863964a3eb9c49ca1a9bfd5f544350c
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Mon Oct 19 17:33:10 2009 +0200

    [quartz] Improve A8 image handling
    
    A8 images were cosidered grayscale, whereas they should behave like
    transparency mask. They are now alpha-only images and the stride is
    16-bytes aligned, as suggested.
    Fixes alpha-similar and mask-transformed-similar. Makes the patterns
    behave (as expected) as masks in surface-pattern-operator.
    Affects the output of operator-alpha-alpha, but the result is not
    correct because of wrong compositing.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 0cc7e6b..e67ed0b 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -2660,20 +2660,11 @@ cairo_quartz_surface_create (cairo_format_t format,
 	else
 	    bitinfo |= kCGImageAlphaNoneSkipFirst;
 	bitsPerComponent = 8;
-
-	/* The Apple docs say that for best performance, the stride and the data
-	 * pointer should be 16-byte aligned.  malloc already aligns to 16-bytes,
-	 * so we don't have to anything special on allocation.
-	 */
 	stride = width * 4;
-	stride += (16 - (stride & 15)) & 15;
     } else if (format == CAIRO_FORMAT_A8) {
-	cgColorspace = CGColorSpaceCreateDeviceGray();
-	if (width % 4 == 0)
-	    stride = width;
-	else
-	    stride = (width & ~3) + 4;
-	bitinfo = kCGImageAlphaNone;
+	cgColorspace = NULL;
+	stride = width;
+	bitinfo = kCGImageAlphaOnly;
 	bitsPerComponent = 8;
     } else if (format == CAIRO_FORMAT_A1) {
 	/* I don't think we can usefully support this, as defined by
@@ -2685,6 +2676,12 @@ cairo_quartz_surface_create (cairo_format_t format,
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
     }
 
+    /* The Apple docs say that for best performance, the stride and the data
+     * pointer should be 16-byte aligned.  malloc already aligns to 16-bytes,
+     * so we don't have to anything special on allocation.
+     */
+    stride = (stride + 15) & ~15;
+
     imageData = _cairo_malloc_ab (height, stride);
     if (!imageData) {
 	CGColorSpaceRelease (cgColorspace);
commit b32695c248b08289ce431d5f2fdab5205219c203
Author: Robert O'Callahan <robert at ocallahan.org>
Date:   Tue Oct 20 16:07:52 2009 +0200

    [quartz] Fix gradient pattern painting
    
    CTM was changed and not restored when painting gradients.
    Fixes the alignment of surface patterns in surface-pattern-operator.
    Patch by Robert O'Callahan, see Mozilla bug #507939.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 17de3b1..0cc7e6b 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1759,8 +1759,10 @@ _cairo_quartz_surface_paint (void *abstract_surface,
 							  surface->extents.width,
 							  surface->extents.height));
     } else if (action == DO_SHADING) {
+	CGContextSaveGState (surface->cgContext);
 	CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
 	CGContextDrawShading (surface->cgContext, surface->sourceShading);
+	CGContextRestoreGState (surface->cgContext);
     } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
 	CGContextSaveGState (surface->cgContext);
 


More information about the cairo-commit mailing list