commit 7992fd55771ea9e7905dd41421b9a91ef582c76a Author: Brian Ewins Date: Sun Mar 25 19:14:42 2007 +0100 [quartz] ensure that line widths are scaled. cairo-gstate applies the ctm to the coordinates used in paths, but not to the line width. In quartz this ends up drawing unscaled lines. This is a minimal fix - it undoes the scaling applied to the points and then draws the path scaled correctly. diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 53412e8..aa0bd4d 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -101,6 +101,11 @@ static void quartz_image_to_png (CGImageRef, char *dest); * Cairo path -> Quartz path conversion helpers */ +typedef struct _quartz_stroke { + CGContextRef cgContext; + cairo_matrix_t *ctm_inverse; +} quartz_stroke_t; + /* cairo path -> mutable path */ static cairo_status_t _cairo_path_to_quartz_path_move_to (void *closure, cairo_point_t *point) @@ -140,8 +145,14 @@ static cairo_status_t _cairo_path_to_quartz_context_move_to (void *closure, cairo_point_t *point) { //ND((stderr, "moveto: %f %f\n", _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y))); - CGContextMoveToPoint ((CGContextRef) closure, - _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y)); + 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); + + CGContextMoveToPoint (stroke->cgContext, x, y); return CAIRO_STATUS_SUCCESS; } @@ -149,12 +160,17 @@ static cairo_status_t _cairo_path_to_quartz_context_line_to (void *closure, cairo_point_t *point) { //ND((stderr, "lineto: %f %f\n", _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y))); - if (CGContextIsPathEmpty ((CGContextRef) closure)) - CGContextMoveToPoint ((CGContextRef) closure, - _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y)); + 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); + + if (CGContextIsPathEmpty (stroke->cgContext)) + CGContextMoveToPoint (stroke->cgContext, x, y); else - CGContextAddLineToPoint ((CGContextRef) closure, - _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y)); + CGContextAddLineToPoint (stroke->cgContext, x, y); return CAIRO_STATUS_SUCCESS; } @@ -165,11 +181,22 @@ _cairo_path_to_quartz_context_curve_to (void *closure, cairo_point_t *p0, cairo_ // _cairo_fixed_to_double(p0->x), _cairo_fixed_to_double(p0->y), // _cairo_fixed_to_double(p1->x), _cairo_fixed_to_double(p1->y), // _cairo_fixed_to_double(p2->x), _cairo_fixed_to_double(p2->y))); + quartz_stroke_t *stroke = (quartz_stroke_t *)closure; + double x0 = _cairo_fixed_to_double (p0->x); + double y0 = _cairo_fixed_to_double (p0->y); + double x1 = _cairo_fixed_to_double (p1->x); + double y1 = _cairo_fixed_to_double (p1->y); + double x2 = _cairo_fixed_to_double (p2->x); + double y2 = _cairo_fixed_to_double (p2->y); + + if (stroke->ctm_inverse) { + cairo_matrix_transform_point (stroke->ctm_inverse, &x0, &y0); + cairo_matrix_transform_point (stroke->ctm_inverse, &x1, &y1); + cairo_matrix_transform_point (stroke->ctm_inverse, &x2, &y2); + } - CGContextAddCurveToPoint ((CGContextRef) closure, - _cairo_fixed_to_double(p0->x), _cairo_fixed_to_double(p0->y), - _cairo_fixed_to_double(p1->x), _cairo_fixed_to_double(p1->y), - _cairo_fixed_to_double(p2->x), _cairo_fixed_to_double(p2->y)); + CGContextAddCurveToPoint (stroke->cgContext, + x0, y0, x1, y1, x2, y2); return CAIRO_STATUS_SUCCESS; } @@ -177,7 +204,8 @@ static cairo_status_t _cairo_path_to_quartz_context_close_path (void *closure) { //ND((stderr, "closepath\n")); - CGContextClosePath ((CGContextRef) closure); + quartz_stroke_t *stroke = (quartz_stroke_t *)closure; + CGContextClosePath (stroke->cgContext); return CAIRO_STATUS_SUCCESS; } @@ -293,6 +321,18 @@ _cairo_quartz_cairo_matrix_to_quartz (const cairo_matrix_t *src, dst->ty = src->y0; } +static void +_cairo_quartz_cairo_matrix_to_quartz_no_offset (const cairo_matrix_t *src, + CGAffineTransform *dst) +{ + dst->a = src->xx; + dst->b = src->xy; + dst->c = src->yx; + dst->d = src->yy; + dst->tx = 0; + dst->ty = 0; +} + /* * Source -> Quartz setup and finish functions */ @@ -1108,6 +1148,7 @@ _cairo_quartz_surface_fill (void *abstract_surface, cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; cairo_quartz_action_t action; + quartz_stroke_t stroke; ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type)); @@ -1126,7 +1167,10 @@ _cairo_quartz_surface_fill (void *abstract_surface, } CGContextBeginPath (surface->cgContext); - _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext); + + stroke.cgContext = surface->cgContext; + stroke.ctm_inverse = NULL; + _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); if (action == DO_SOLID || action == DO_PATTERN) { if (fill_rule == CAIRO_FILL_RULE_WINDING) @@ -1169,6 +1213,9 @@ _cairo_quartz_surface_stroke (void *abstract_surface, cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; cairo_quartz_action_t action; + quartz_stroke_t stroke; + CGAffineTransform strokeTransform; + cairo_matrix_t ctm_inverse_flipped; ND((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type)); @@ -1184,6 +1231,8 @@ _cairo_quartz_surface_stroke (void *abstract_surface, 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); + _cairo_quartz_cairo_matrix_to_quartz_no_offset (ctm, &strokeTransform); + CGContextConcatCTM (surface->cgContext, strokeTransform); if (style->dash && style->num_dashes) { #define STATIC_DASH 32 @@ -1211,7 +1260,17 @@ _cairo_quartz_surface_stroke (void *abstract_surface, } CGContextBeginPath (surface->cgContext); - _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext); + + ctm_inverse_flipped.xx = ctm_inverse->xx; + ctm_inverse_flipped.xy = -ctm_inverse->xy; + ctm_inverse_flipped.yx = -ctm_inverse->yx; + ctm_inverse_flipped.yy = ctm_inverse->yy; + ctm_inverse_flipped.x0 = 0; + ctm_inverse_flipped.y0 = 0; + + stroke.cgContext = surface->cgContext; + stroke.ctm_inverse = &ctm_inverse_flipped; + _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); if (action == DO_SOLID || action == DO_PATTERN) { CGContextStrokePath (surface->cgContext); @@ -1409,6 +1468,7 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface, cairo_antialias_t antialias) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + quartz_stroke_t stroke; ND((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path)); @@ -1424,7 +1484,9 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface, CGContextSaveGState (surface->cgContext); } else { CGContextBeginPath (surface->cgContext); - _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext); + stroke.cgContext = surface->cgContext; + stroke.ctm_inverse = NULL; + _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); if (fill_rule == CAIRO_FILL_RULE_WINDING) CGContextClip (surface->cgContext); else