diff options
author | John Ralls <jralls@ceridwen.us> | 2022-02-19 18:37:16 -0800 |
---|---|---|
committer | John Ralls <jralls@ceridwen.us> | 2022-02-24 17:00:07 -0800 |
commit | a502280fcd4ca28c1c5d350674edde645cb784c8 (patch) | |
tree | 4fa752fa1de8746d2118bb8c1fae3c0c9f9c9c6b /src/cairo-quartz-surface.c | |
parent | b6e0f36ee5de521fffcadffcece1ef27bb4dfd5b (diff) | |
download | cairo-a502280fcd4ca28c1c5d350674edde645cb784c8.tar.gz |
[quartz] extract function _cairo_quartz_setup_pattern_source
To simplify _cairo_quartz_setup_state.
Diffstat (limited to 'src/cairo-quartz-surface.c')
-rw-r--r-- | src/cairo-quartz-surface.c | 283 |
1 files changed, 146 insertions, 137 deletions
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index da3f39c0d..3f1d91dfc 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -1077,6 +1077,150 @@ typedef struct { CGRect clipRect; } cairo_quartz_drawing_state_t; +static cairo_int_status_t +_cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state, + const cairo_pattern_t *source, + cairo_quartz_surface_t *surface, + const cairo_clip_t *clip, + cairo_operator_t op) +{ + const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source; + cairo_surface_t *pat_surf = spat->surface; + cairo_matrix_t m = spat->base.matrix; + cairo_format_t format = _cairo_format_from_content (surface->base.content); + cairo_rectangle_int_t extents; + CGRect srcRect; + CGImageRef img; + + cairo_quartz_float_t patternAlpha = 1.0f; + CGColorSpaceRef patternSpace; + CGPatternRef pattern = NULL; + cairo_int_status_t status; + + _cairo_surface_get_extents (&surface->base, &extents); + + if (pat_surf->backend->type == 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) { + cairo_matrix_invert (&m); + _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); + state->rect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); + state->layer = quartz_surf->cgLayer; + state->action = DO_LAYER; + return CAIRO_STATUS_SUCCESS; + } + } + + status = _cairo_surface_to_cgimage (pat_surf, &extents, format, + &m, clip, &img); // Note that only pat_surf will get used! + if (unlikely (status)) + return status; + + state->image = img; + + if (state->filter == kCGInterpolationNone && _cairo_matrix_is_translation (&m)) { + m.x0 = -ceil (m.x0 - 0.5); + m.y0 = -ceil (m.y0 - 0.5); + } else { + cairo_matrix_invert (&m); + } + + _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); + + if (pat_surf->type != CAIRO_SURFACE_TYPE_RECORDING) { + cairo_bool_t is_bounded = _cairo_surface_get_extents (pat_surf, &extents); + assert (is_bounded); + } + + srcRect = CGRectMake (0, 0, extents.width, extents.height); + + if (source->extend == CAIRO_EXTEND_NONE) { + int x, y; + if (op == CAIRO_OPERATOR_SOURCE && + (pat_surf->content == CAIRO_CONTENT_ALPHA || + ! _cairo_matrix_is_integer_translation (&m, &x, &y))) + { + state->layer = CGLayerCreateWithContext (surface->cgContext, + state->clipRect.size, + NULL); + state->cgDrawContext = CGLayerGetContext (state->layer); + CGContextTranslateCTM (state->cgDrawContext, + -state->clipRect.origin.x, + -state->clipRect.origin.y); + } + + CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1); + + state->rect = srcRect; + state->action = DO_IMAGE; + return CAIRO_STATUS_SUCCESS; + } + + if (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT) { + int fh, fw; + CGAffineTransform xform; + + CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1); + + /* 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 (state->cgDrawContext), + state->transform); + + 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->rect = srcRect; + state->action = DO_TILED_IMAGE; + return CAIRO_STATUS_SUCCESS; + } + } + /* Fall through to generic SURFACE case */ + status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, clip, &pattern); + if (unlikely (status)) + return status; + + patternSpace = CGColorSpaceCreatePattern (NULL); + CGContextSetFillColorSpace (state->cgDrawContext, patternSpace); + CGContextSetFillPattern (state->cgDrawContext, pattern, &patternAlpha); + CGContextSetStrokeColorSpace (state->cgDrawContext, patternSpace); + CGContextSetStrokePattern (state->cgDrawContext, 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 (state->cgDrawContext, CGSizeMake (0, 0)); + + CGPatternRelease (pattern); + + state->action = DO_DIRECT; + return CAIRO_STATUS_SUCCESS; +} + + /* Quartz does not support repeating gradients. We handle repeating gradients by manually extending the gradient and repeating color stops. We need to @@ -1149,7 +1293,6 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state, const cairo_clip_t *clip = composite->clip; cairo_bool_t needs_temp; cairo_status_t status; - cairo_format_t format = _cairo_format_from_content (composite->surface->content); state->layer = NULL; state->image = NULL; @@ -1251,143 +1394,9 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state, return _cairo_quartz_setup_gradient_source (state, gpat, &extents); } - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT))) - { - 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; - - if (pat_surf->backend->type == 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) { - cairo_matrix_invert (&m); - _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); - state->rect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); - state->layer = quartz_surf->cgLayer; - state->action = DO_LAYER; - return CAIRO_STATUS_SUCCESS; - } - } - - _cairo_surface_get_extents (composite->surface, &extents); - status = _cairo_surface_to_cgimage (pat_surf, &extents, format, - &m, clip, &img); - if (unlikely (status)) - return status; - - state->image = img; - - if (state->filter == kCGInterpolationNone && _cairo_matrix_is_translation (&m)) { - m.x0 = -ceil (m.x0 - 0.5); - m.y0 = -ceil (m.y0 - 0.5); - } else { - cairo_matrix_invert (&m); - } - - _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); - - if (pat_surf->type != CAIRO_SURFACE_TYPE_RECORDING) { - is_bounded = _cairo_surface_get_extents (pat_surf, &extents); - assert (is_bounded); - } - - srcRect = CGRectMake (0, 0, extents.width, extents.height); - - if (source->extend == CAIRO_EXTEND_NONE) { - int x, y; - if (op == CAIRO_OPERATOR_SOURCE && - (pat_surf->content == CAIRO_CONTENT_ALPHA || - ! _cairo_matrix_is_integer_translation (&m, &x, &y))) - { - state->layer = CGLayerCreateWithContext (surface->cgContext, - state->clipRect.size, - NULL); - state->cgDrawContext = CGLayerGetContext (state->layer); - CGContextTranslateCTM (state->cgDrawContext, - -state->clipRect.origin.x, - -state->clipRect.origin.y); - } - - CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1); - - state->rect = srcRect; - state->action = DO_IMAGE; - return CAIRO_STATUS_SUCCESS; - } - - CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1); - - /* 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 (state->cgDrawContext), - state->transform); - - 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->rect = srcRect; - state->action = DO_TILED_IMAGE; - return CAIRO_STATUS_SUCCESS; - } - - /* Fall through to generic SURFACE case */ - } - - if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { - cairo_quartz_float_t patternAlpha = 1.0f; - CGColorSpaceRef patternSpace; - CGPatternRef pattern = NULL; - cairo_int_status_t status; - status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, clip, &pattern); - if (unlikely (status)) - return status; - - patternSpace = CGColorSpaceCreatePattern (NULL); - CGContextSetFillColorSpace (state->cgDrawContext, patternSpace); - CGContextSetFillPattern (state->cgDrawContext, pattern, &patternAlpha); - CGContextSetStrokeColorSpace (state->cgDrawContext, patternSpace); - CGContextSetStrokePattern (state->cgDrawContext, 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 (state->cgDrawContext, CGSizeMake (0, 0)); - - CGPatternRelease (pattern); - - state->action = DO_DIRECT; - return CAIRO_STATUS_SUCCESS; - } + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) + return _cairo_quartz_setup_pattern_source (state, source, surface, clip, op); return CAIRO_INT_STATUS_UNSUPPORTED; } |