michael@0: From: Robert O'Callahan michael@0: Bug 593270. Part 1: Move surface setup code to a helper function. r=jrmuizel,a=joe michael@0: michael@0: diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c michael@0: --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c michael@0: +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c michael@0: @@ -1455,16 +1455,147 @@ _cairo_quartz_setup_radial_source (cairo michael@0: extend, extend); michael@0: michael@0: CGColorSpaceRelease(rgb); michael@0: CGFunctionRelease(gradFunc); michael@0: michael@0: state->action = DO_SHADING; michael@0: } michael@0: michael@0: +static void michael@0: +_cairo_quartz_setup_surface_source (cairo_quartz_surface_t *surface, michael@0: + const cairo_surface_pattern_t *spat, michael@0: + cairo_rectangle_int_t *extents, michael@0: + cairo_quartz_drawing_state_t *state) michael@0: +{ michael@0: + const cairo_pattern_t *source = &spat->base; michael@0: + CGContextRef context = state->context; michael@0: + michael@0: + if (source->extend == CAIRO_EXTEND_NONE || michael@0: + (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)) michael@0: + { michael@0: + cairo_surface_t *pat_surf = spat->surface; michael@0: + CGImageRef img; michael@0: + cairo_matrix_t m = spat->base.matrix; michael@0: + cairo_rectangle_int_t extents; michael@0: + CGAffineTransform xform; michael@0: + CGRect srcRect; michael@0: + cairo_fixed_t fw, fh; michael@0: + cairo_bool_t is_bounded; michael@0: + cairo_status_t status; michael@0: + michael@0: + cairo_matrix_invert(&m); michael@0: + _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); michael@0: + michael@0: + /* Draw nonrepeating CGLayer surface using DO_LAYER */ michael@0: + if (source->extend == CAIRO_EXTEND_NONE || michael@0: + (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)) michael@0: + cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; michael@0: + if (quartz_surf->cgLayer) { michael@0: + state->imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); michael@0: + state->layer = quartz_surf->cgLayer; michael@0: + state->action = DO_LAYER; michael@0: + return; michael@0: + } michael@0: + } michael@0: + michael@0: + status = _cairo_surface_to_cgimage (pat_surf, &img); michael@0: + if (status) { michael@0: + state->action = DO_UNSUPPORTED; michael@0: + return; michael@0: + } michael@0: + if (img == NULL) { michael@0: + state->action = DO_NOTHING; michael@0: + return; michael@0: + } michael@0: + michael@0: + /* XXXroc what is this for? */ michael@0: + CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); michael@0: + michael@0: + state->image = img; michael@0: + michael@0: + is_bounded = _cairo_surface_get_extents (pat_surf, &extents); michael@0: + assert (is_bounded); michael@0: + michael@0: + if (source->extend == CAIRO_EXTEND_NONE) { michael@0: + state->imageRect = CGRectMake (0, 0, extents.width, extents.height); michael@0: + state->action = DO_IMAGE; michael@0: + return; michael@0: + } michael@0: + michael@0: + /* Quartz seems to tile images at pixel-aligned regions only -- this michael@0: + * leads to seams if the image doesn't end up scaling to fill the michael@0: + * space exactly. The CGPattern tiling approach doesn't have this michael@0: + * problem. Check if we're going to fill up the space (within some michael@0: + * epsilon), and if not, fall back to the CGPattern type. michael@0: + */ michael@0: + michael@0: + xform = CGAffineTransformConcat (CGContextGetCTM (context), michael@0: + state->transform); michael@0: + michael@0: + srcRect = CGRectMake (0, 0, extents.width, extents.height); michael@0: + srcRect = CGRectApplyAffineTransform (srcRect, xform); michael@0: + michael@0: + fw = _cairo_fixed_from_double (srcRect.size.width); michael@0: + fh = _cairo_fixed_from_double (srcRect.size.height); michael@0: + michael@0: + if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON && michael@0: + (fh & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON) michael@0: + { michael@0: + /* We're good to use DrawTiledImage, but ensure that michael@0: + * the math works out */ michael@0: + michael@0: + srcRect.size.width = round(srcRect.size.width); michael@0: + srcRect.size.height = round(srcRect.size.height); michael@0: + michael@0: + xform = CGAffineTransformInvert (xform); michael@0: + michael@0: + srcRect = CGRectApplyAffineTransform (srcRect, xform); michael@0: + michael@0: + state->imageRect = srcRect; michael@0: + state->action = DO_TILED_IMAGE; michael@0: + return; michael@0: + } michael@0: + michael@0: + /* Fall through to generic SURFACE case */ michael@0: + } michael@0: + michael@0: + CGFloat patternAlpha = 1.0f; michael@0: + CGColorSpaceRef patternSpace; michael@0: + CGPatternRef pattern; michael@0: + cairo_int_status_t status; michael@0: + michael@0: + status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern); michael@0: + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { michael@0: + state->action = DO_NOTHING; michael@0: + return; michael@0: + } michael@0: + if (status) { michael@0: + state->action = DO_UNSUPPORTED; michael@0: + return; michael@0: + } michael@0: + michael@0: + patternSpace = CGColorSpaceCreatePattern (NULL); michael@0: + CGContextSetFillColorSpace (context, patternSpace); michael@0: + CGContextSetFillPattern (context, pattern, &patternAlpha); michael@0: + CGContextSetStrokeColorSpace (context, patternSpace); michael@0: + CGContextSetStrokePattern (context, pattern, &patternAlpha); michael@0: + CGColorSpaceRelease (patternSpace); michael@0: + michael@0: + /* Quartz likes to munge the pattern phase (as yet unexplained michael@0: + * why); force it to 0,0 as we've already baked in the correct michael@0: + * pattern translation into the pattern matrix michael@0: + */ michael@0: + CGContextSetPatternPhase (context, CGSizeMake(0,0)); michael@0: + michael@0: + state->pattern = pattern; michael@0: + state->action = DO_PATTERN; michael@0: + return; michael@0: +} michael@0: + michael@0: /** michael@0: * Call this before any operation that can modify the contents of a michael@0: * cairo_quartz_surface_t. michael@0: */ michael@0: static void michael@0: _cairo_quartz_surface_will_change (cairo_quartz_surface_t *surface) michael@0: { michael@0: if (surface->bitmapContextImage) { michael@0: @@ -1566,133 +1697,19 @@ _cairo_quartz_setup_state (cairo_quartz_ michael@0: } michael@0: michael@0: if (source->type == CAIRO_PATTERN_TYPE_RADIAL) { michael@0: const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source; michael@0: _cairo_quartz_setup_radial_source (surface, rpat, extents, &state); michael@0: return state; michael@0: } michael@0: michael@0: - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && michael@0: - (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT))) michael@0: - { michael@0: + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { michael@0: const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source; michael@0: - cairo_surface_t *pat_surf = spat->surface; michael@0: - CGImageRef img; michael@0: - cairo_matrix_t m = spat->base.matrix; michael@0: - cairo_rectangle_int_t extents; michael@0: - CGAffineTransform xform; michael@0: - CGRect srcRect; michael@0: - cairo_fixed_t fw, fh; michael@0: - cairo_bool_t is_bounded; michael@0: - michael@0: - cairo_matrix_invert(&m); michael@0: - _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); michael@0: - michael@0: - if (cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { michael@0: - cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; michael@0: - if (quartz_surf->cgLayer && source->extend == CAIRO_EXTEND_NONE) { michael@0: - state.imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); michael@0: - state.layer = quartz_surf->cgLayer; michael@0: - state.action = DO_LAYER; michael@0: - return state; michael@0: - } michael@0: - } michael@0: - michael@0: - status = _cairo_surface_to_cgimage (pat_surf, &img); michael@0: - if (status) { michael@0: - state.action = DO_UNSUPPORTED; michael@0: - return state; michael@0: - } michael@0: - if (img == NULL) { michael@0: - state.action = DO_NOTHING; michael@0: - return state; michael@0: - } michael@0: - michael@0: - CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); michael@0: - michael@0: - state.image = img; michael@0: - michael@0: - is_bounded = _cairo_surface_get_extents (pat_surf, &extents); michael@0: - assert (is_bounded); michael@0: - michael@0: - if (source->extend == CAIRO_EXTEND_NONE) { michael@0: - state.imageRect = CGRectMake (0, 0, extents.width, extents.height); michael@0: - state.action = DO_IMAGE; michael@0: - return state; michael@0: - } michael@0: - michael@0: - /* Quartz seems to tile images at pixel-aligned regions only -- this michael@0: - * leads to seams if the image doesn't end up scaling to fill the michael@0: - * space exactly. The CGPattern tiling approach doesn't have this michael@0: - * problem. Check if we're going to fill up the space (within some michael@0: - * epsilon), and if not, fall back to the CGPattern type. michael@0: - */ michael@0: - michael@0: - xform = CGAffineTransformConcat (CGContextGetCTM (context), michael@0: - state.transform); michael@0: - michael@0: - srcRect = CGRectMake (0, 0, extents.width, extents.height); michael@0: - srcRect = CGRectApplyAffineTransform (srcRect, xform); michael@0: - michael@0: - fw = _cairo_fixed_from_double (srcRect.size.width); michael@0: - fh = _cairo_fixed_from_double (srcRect.size.height); michael@0: - michael@0: - if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON && michael@0: - (fh & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON) michael@0: - { michael@0: - /* We're good to use DrawTiledImage, but ensure that michael@0: - * the math works out */ michael@0: - michael@0: - srcRect.size.width = round(srcRect.size.width); michael@0: - srcRect.size.height = round(srcRect.size.height); michael@0: - michael@0: - xform = CGAffineTransformInvert (xform); michael@0: - michael@0: - srcRect = CGRectApplyAffineTransform (srcRect, xform); michael@0: - michael@0: - state.imageRect = srcRect; michael@0: - state.action = DO_TILED_IMAGE; michael@0: - return state; michael@0: - } michael@0: - michael@0: - /* Fall through to generic SURFACE case */ michael@0: - } michael@0: - michael@0: - if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { michael@0: - CGFloat patternAlpha = 1.0f; michael@0: - CGColorSpaceRef patternSpace; michael@0: - CGPatternRef pattern; michael@0: - cairo_int_status_t status; michael@0: - michael@0: - status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern); michael@0: - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { michael@0: - state.action = DO_NOTHING; michael@0: - return state; michael@0: - } michael@0: - if (status) { michael@0: - state.action = DO_UNSUPPORTED; michael@0: - return state; michael@0: - } michael@0: - michael@0: - patternSpace = CGColorSpaceCreatePattern (NULL); michael@0: - CGContextSetFillColorSpace (context, patternSpace); michael@0: - CGContextSetFillPattern (context, pattern, &patternAlpha); michael@0: - CGContextSetStrokeColorSpace (context, patternSpace); michael@0: - CGContextSetStrokePattern (context, pattern, &patternAlpha); michael@0: - CGColorSpaceRelease (patternSpace); michael@0: - michael@0: - /* Quartz likes to munge the pattern phase (as yet unexplained michael@0: - * why); force it to 0,0 as we've already baked in the correct michael@0: - * pattern translation into the pattern matrix michael@0: - */ michael@0: - CGContextSetPatternPhase (context, CGSizeMake(0,0)); michael@0: - michael@0: - state.pattern = pattern; michael@0: - state.action = DO_PATTERN; michael@0: + _cairo_quartz_setup_surface_source (surface, spat, extents, &state); michael@0: return state; michael@0: } michael@0: michael@0: state.action = DO_UNSUPPORTED; michael@0: return state; michael@0: } michael@0: michael@0: /**