From: Robert O'Callahan Bug 593270. Part 1: Move surface setup code to a helper function. r=jrmuizel,a=joe diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c @@ -1455,16 +1455,147 @@ _cairo_quartz_setup_radial_source (cairo extend, extend); CGColorSpaceRelease(rgb); CGFunctionRelease(gradFunc); state->action = DO_SHADING; } +static void +_cairo_quartz_setup_surface_source (cairo_quartz_surface_t *surface, + const cairo_surface_pattern_t *spat, + cairo_rectangle_int_t *extents, + cairo_quartz_drawing_state_t *state) +{ + const cairo_pattern_t *source = &spat->base; + CGContextRef context = state->context; + + if (source->extend == CAIRO_EXTEND_NONE || + (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)) + { + cairo_surface_t *pat_surf = spat->surface; + CGImageRef img; + cairo_matrix_t m = spat->base.matrix; + cairo_rectangle_int_t extents; + CGAffineTransform xform; + CGRect srcRect; + cairo_fixed_t fw, fh; + cairo_bool_t is_bounded; + cairo_status_t status; + + cairo_matrix_invert(&m); + _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); + + /* Draw nonrepeating CGLayer surface using DO_LAYER */ + if (source->extend == CAIRO_EXTEND_NONE || + (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)) + cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; + if (quartz_surf->cgLayer) { + state->imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); + state->layer = quartz_surf->cgLayer; + state->action = DO_LAYER; + return; + } + } + + status = _cairo_surface_to_cgimage (pat_surf, &img); + if (status) { + state->action = DO_UNSUPPORTED; + return; + } + if (img == NULL) { + state->action = DO_NOTHING; + return; + } + + /* XXXroc what is this for? */ + CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); + + state->image = img; + + is_bounded = _cairo_surface_get_extents (pat_surf, &extents); + assert (is_bounded); + + if (source->extend == CAIRO_EXTEND_NONE) { + state->imageRect = CGRectMake (0, 0, extents.width, extents.height); + state->action = DO_IMAGE; + return; + } + + /* 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 (context), + state->transform); + + srcRect = CGRectMake (0, 0, extents.width, extents.height); + srcRect = CGRectApplyAffineTransform (srcRect, xform); + + 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); + + state->imageRect = srcRect; + state->action = DO_TILED_IMAGE; + return; + } + + /* Fall through to generic SURFACE case */ + } + + CGFloat patternAlpha = 1.0f; + CGColorSpaceRef patternSpace; + CGPatternRef pattern; + cairo_int_status_t status; + + status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern); + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { + state->action = DO_NOTHING; + return; + } + if (status) { + state->action = DO_UNSUPPORTED; + return; + } + + patternSpace = CGColorSpaceCreatePattern (NULL); + CGContextSetFillColorSpace (context, patternSpace); + CGContextSetFillPattern (context, pattern, &patternAlpha); + CGContextSetStrokeColorSpace (context, patternSpace); + CGContextSetStrokePattern (context, pattern, &patternAlpha); + CGColorSpaceRelease (patternSpace); + + /* Quartz likes to munge the pattern phase (as yet unexplained + * why); force it to 0,0 as we've already baked in the correct + * pattern translation into the pattern matrix + */ + CGContextSetPatternPhase (context, CGSizeMake(0,0)); + + state->pattern = pattern; + state->action = DO_PATTERN; + return; +} + /** * Call this before any operation that can modify the contents of a * cairo_quartz_surface_t. */ static void _cairo_quartz_surface_will_change (cairo_quartz_surface_t *surface) { if (surface->bitmapContextImage) { @@ -1566,133 +1697,19 @@ _cairo_quartz_setup_state (cairo_quartz_ } if (source->type == CAIRO_PATTERN_TYPE_RADIAL) { const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source; _cairo_quartz_setup_radial_source (surface, rpat, extents, &state); return state; } - 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) { const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source; - cairo_surface_t *pat_surf = spat->surface; - CGImageRef img; - cairo_matrix_t m = spat->base.matrix; - cairo_rectangle_int_t extents; - CGAffineTransform xform; - CGRect srcRect; - cairo_fixed_t fw, fh; - cairo_bool_t is_bounded; - - cairo_matrix_invert(&m); - _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); - - if (cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { - cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; - if (quartz_surf->cgLayer && source->extend == CAIRO_EXTEND_NONE) { - state.imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); - state.layer = quartz_surf->cgLayer; - state.action = DO_LAYER; - return state; - } - } - - status = _cairo_surface_to_cgimage (pat_surf, &img); - if (status) { - state.action = DO_UNSUPPORTED; - return state; - } - if (img == NULL) { - state.action = DO_NOTHING; - return state; - } - - CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); - - state.image = img; - - is_bounded = _cairo_surface_get_extents (pat_surf, &extents); - assert (is_bounded); - - if (source->extend == CAIRO_EXTEND_NONE) { - state.imageRect = CGRectMake (0, 0, extents.width, extents.height); - state.action = DO_IMAGE; - return state; - } - - /* 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 (context), - state.transform); - - srcRect = CGRectMake (0, 0, extents.width, extents.height); - srcRect = CGRectApplyAffineTransform (srcRect, xform); - - 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); - - state.imageRect = srcRect; - state.action = DO_TILED_IMAGE; - return state; - } - - /* Fall through to generic SURFACE case */ - } - - if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { - CGFloat patternAlpha = 1.0f; - CGColorSpaceRef patternSpace; - CGPatternRef pattern; - cairo_int_status_t status; - - status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { - state.action = DO_NOTHING; - return state; - } - if (status) { - state.action = DO_UNSUPPORTED; - return state; - } - - patternSpace = CGColorSpaceCreatePattern (NULL); - CGContextSetFillColorSpace (context, patternSpace); - CGContextSetFillPattern (context, pattern, &patternAlpha); - CGContextSetStrokeColorSpace (context, patternSpace); - CGContextSetStrokePattern (context, pattern, &patternAlpha); - CGColorSpaceRelease (patternSpace); - - /* Quartz likes to munge the pattern phase (as yet unexplained - * why); force it to 0,0 as we've already baked in the correct - * pattern translation into the pattern matrix - */ - CGContextSetPatternPhase (context, CGSizeMake(0,0)); - - state.pattern = pattern; - state.action = DO_PATTERN; + _cairo_quartz_setup_surface_source (surface, spat, extents, &state); return state; } state.action = DO_UNSUPPORTED; return state; } /**