1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/cairo/quartz-refactor-surface-setup.patch Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,290 @@ 1.4 +From: Robert O'Callahan <robert@ocallahan.org> 1.5 +Bug 593270. Part 1: Move surface setup code to a helper function. r=jrmuizel,a=joe 1.6 + 1.7 +diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c 1.8 +--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c 1.9 ++++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c 1.10 +@@ -1455,16 +1455,147 @@ _cairo_quartz_setup_radial_source (cairo 1.11 + extend, extend); 1.12 + 1.13 + CGColorSpaceRelease(rgb); 1.14 + CGFunctionRelease(gradFunc); 1.15 + 1.16 + state->action = DO_SHADING; 1.17 + } 1.18 + 1.19 ++static void 1.20 ++_cairo_quartz_setup_surface_source (cairo_quartz_surface_t *surface, 1.21 ++ const cairo_surface_pattern_t *spat, 1.22 ++ cairo_rectangle_int_t *extents, 1.23 ++ cairo_quartz_drawing_state_t *state) 1.24 ++{ 1.25 ++ const cairo_pattern_t *source = &spat->base; 1.26 ++ CGContextRef context = state->context; 1.27 ++ 1.28 ++ if (source->extend == CAIRO_EXTEND_NONE || 1.29 ++ (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)) 1.30 ++ { 1.31 ++ cairo_surface_t *pat_surf = spat->surface; 1.32 ++ CGImageRef img; 1.33 ++ cairo_matrix_t m = spat->base.matrix; 1.34 ++ cairo_rectangle_int_t extents; 1.35 ++ CGAffineTransform xform; 1.36 ++ CGRect srcRect; 1.37 ++ cairo_fixed_t fw, fh; 1.38 ++ cairo_bool_t is_bounded; 1.39 ++ cairo_status_t status; 1.40 ++ 1.41 ++ cairo_matrix_invert(&m); 1.42 ++ _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); 1.43 ++ 1.44 ++ /* Draw nonrepeating CGLayer surface using DO_LAYER */ 1.45 ++ if (source->extend == CAIRO_EXTEND_NONE || 1.46 ++ (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)) 1.47 ++ cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; 1.48 ++ if (quartz_surf->cgLayer) { 1.49 ++ state->imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); 1.50 ++ state->layer = quartz_surf->cgLayer; 1.51 ++ state->action = DO_LAYER; 1.52 ++ return; 1.53 ++ } 1.54 ++ } 1.55 ++ 1.56 ++ status = _cairo_surface_to_cgimage (pat_surf, &img); 1.57 ++ if (status) { 1.58 ++ state->action = DO_UNSUPPORTED; 1.59 ++ return; 1.60 ++ } 1.61 ++ if (img == NULL) { 1.62 ++ state->action = DO_NOTHING; 1.63 ++ return; 1.64 ++ } 1.65 ++ 1.66 ++ /* XXXroc what is this for? */ 1.67 ++ CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); 1.68 ++ 1.69 ++ state->image = img; 1.70 ++ 1.71 ++ is_bounded = _cairo_surface_get_extents (pat_surf, &extents); 1.72 ++ assert (is_bounded); 1.73 ++ 1.74 ++ if (source->extend == CAIRO_EXTEND_NONE) { 1.75 ++ state->imageRect = CGRectMake (0, 0, extents.width, extents.height); 1.76 ++ state->action = DO_IMAGE; 1.77 ++ return; 1.78 ++ } 1.79 ++ 1.80 ++ /* Quartz seems to tile images at pixel-aligned regions only -- this 1.81 ++ * leads to seams if the image doesn't end up scaling to fill the 1.82 ++ * space exactly. The CGPattern tiling approach doesn't have this 1.83 ++ * problem. Check if we're going to fill up the space (within some 1.84 ++ * epsilon), and if not, fall back to the CGPattern type. 1.85 ++ */ 1.86 ++ 1.87 ++ xform = CGAffineTransformConcat (CGContextGetCTM (context), 1.88 ++ state->transform); 1.89 ++ 1.90 ++ srcRect = CGRectMake (0, 0, extents.width, extents.height); 1.91 ++ srcRect = CGRectApplyAffineTransform (srcRect, xform); 1.92 ++ 1.93 ++ fw = _cairo_fixed_from_double (srcRect.size.width); 1.94 ++ fh = _cairo_fixed_from_double (srcRect.size.height); 1.95 ++ 1.96 ++ if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON && 1.97 ++ (fh & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON) 1.98 ++ { 1.99 ++ /* We're good to use DrawTiledImage, but ensure that 1.100 ++ * the math works out */ 1.101 ++ 1.102 ++ srcRect.size.width = round(srcRect.size.width); 1.103 ++ srcRect.size.height = round(srcRect.size.height); 1.104 ++ 1.105 ++ xform = CGAffineTransformInvert (xform); 1.106 ++ 1.107 ++ srcRect = CGRectApplyAffineTransform (srcRect, xform); 1.108 ++ 1.109 ++ state->imageRect = srcRect; 1.110 ++ state->action = DO_TILED_IMAGE; 1.111 ++ return; 1.112 ++ } 1.113 ++ 1.114 ++ /* Fall through to generic SURFACE case */ 1.115 ++ } 1.116 ++ 1.117 ++ CGFloat patternAlpha = 1.0f; 1.118 ++ CGColorSpaceRef patternSpace; 1.119 ++ CGPatternRef pattern; 1.120 ++ cairo_int_status_t status; 1.121 ++ 1.122 ++ status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern); 1.123 ++ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { 1.124 ++ state->action = DO_NOTHING; 1.125 ++ return; 1.126 ++ } 1.127 ++ if (status) { 1.128 ++ state->action = DO_UNSUPPORTED; 1.129 ++ return; 1.130 ++ } 1.131 ++ 1.132 ++ patternSpace = CGColorSpaceCreatePattern (NULL); 1.133 ++ CGContextSetFillColorSpace (context, patternSpace); 1.134 ++ CGContextSetFillPattern (context, pattern, &patternAlpha); 1.135 ++ CGContextSetStrokeColorSpace (context, patternSpace); 1.136 ++ CGContextSetStrokePattern (context, pattern, &patternAlpha); 1.137 ++ CGColorSpaceRelease (patternSpace); 1.138 ++ 1.139 ++ /* Quartz likes to munge the pattern phase (as yet unexplained 1.140 ++ * why); force it to 0,0 as we've already baked in the correct 1.141 ++ * pattern translation into the pattern matrix 1.142 ++ */ 1.143 ++ CGContextSetPatternPhase (context, CGSizeMake(0,0)); 1.144 ++ 1.145 ++ state->pattern = pattern; 1.146 ++ state->action = DO_PATTERN; 1.147 ++ return; 1.148 ++} 1.149 ++ 1.150 + /** 1.151 + * Call this before any operation that can modify the contents of a 1.152 + * cairo_quartz_surface_t. 1.153 + */ 1.154 + static void 1.155 + _cairo_quartz_surface_will_change (cairo_quartz_surface_t *surface) 1.156 + { 1.157 + if (surface->bitmapContextImage) { 1.158 +@@ -1566,133 +1697,19 @@ _cairo_quartz_setup_state (cairo_quartz_ 1.159 + } 1.160 + 1.161 + if (source->type == CAIRO_PATTERN_TYPE_RADIAL) { 1.162 + const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source; 1.163 + _cairo_quartz_setup_radial_source (surface, rpat, extents, &state); 1.164 + return state; 1.165 + } 1.166 + 1.167 +- if (source->type == CAIRO_PATTERN_TYPE_SURFACE && 1.168 +- (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT))) 1.169 +- { 1.170 ++ if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { 1.171 + const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source; 1.172 +- cairo_surface_t *pat_surf = spat->surface; 1.173 +- CGImageRef img; 1.174 +- cairo_matrix_t m = spat->base.matrix; 1.175 +- cairo_rectangle_int_t extents; 1.176 +- CGAffineTransform xform; 1.177 +- CGRect srcRect; 1.178 +- cairo_fixed_t fw, fh; 1.179 +- cairo_bool_t is_bounded; 1.180 +- 1.181 +- cairo_matrix_invert(&m); 1.182 +- _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); 1.183 +- 1.184 +- if (cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { 1.185 +- cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; 1.186 +- if (quartz_surf->cgLayer && source->extend == CAIRO_EXTEND_NONE) { 1.187 +- state.imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); 1.188 +- state.layer = quartz_surf->cgLayer; 1.189 +- state.action = DO_LAYER; 1.190 +- return state; 1.191 +- } 1.192 +- } 1.193 +- 1.194 +- status = _cairo_surface_to_cgimage (pat_surf, &img); 1.195 +- if (status) { 1.196 +- state.action = DO_UNSUPPORTED; 1.197 +- return state; 1.198 +- } 1.199 +- if (img == NULL) { 1.200 +- state.action = DO_NOTHING; 1.201 +- return state; 1.202 +- } 1.203 +- 1.204 +- CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); 1.205 +- 1.206 +- state.image = img; 1.207 +- 1.208 +- is_bounded = _cairo_surface_get_extents (pat_surf, &extents); 1.209 +- assert (is_bounded); 1.210 +- 1.211 +- if (source->extend == CAIRO_EXTEND_NONE) { 1.212 +- state.imageRect = CGRectMake (0, 0, extents.width, extents.height); 1.213 +- state.action = DO_IMAGE; 1.214 +- return state; 1.215 +- } 1.216 +- 1.217 +- /* Quartz seems to tile images at pixel-aligned regions only -- this 1.218 +- * leads to seams if the image doesn't end up scaling to fill the 1.219 +- * space exactly. The CGPattern tiling approach doesn't have this 1.220 +- * problem. Check if we're going to fill up the space (within some 1.221 +- * epsilon), and if not, fall back to the CGPattern type. 1.222 +- */ 1.223 +- 1.224 +- xform = CGAffineTransformConcat (CGContextGetCTM (context), 1.225 +- state.transform); 1.226 +- 1.227 +- srcRect = CGRectMake (0, 0, extents.width, extents.height); 1.228 +- srcRect = CGRectApplyAffineTransform (srcRect, xform); 1.229 +- 1.230 +- fw = _cairo_fixed_from_double (srcRect.size.width); 1.231 +- fh = _cairo_fixed_from_double (srcRect.size.height); 1.232 +- 1.233 +- if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON && 1.234 +- (fh & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON) 1.235 +- { 1.236 +- /* We're good to use DrawTiledImage, but ensure that 1.237 +- * the math works out */ 1.238 +- 1.239 +- srcRect.size.width = round(srcRect.size.width); 1.240 +- srcRect.size.height = round(srcRect.size.height); 1.241 +- 1.242 +- xform = CGAffineTransformInvert (xform); 1.243 +- 1.244 +- srcRect = CGRectApplyAffineTransform (srcRect, xform); 1.245 +- 1.246 +- state.imageRect = srcRect; 1.247 +- state.action = DO_TILED_IMAGE; 1.248 +- return state; 1.249 +- } 1.250 +- 1.251 +- /* Fall through to generic SURFACE case */ 1.252 +- } 1.253 +- 1.254 +- if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { 1.255 +- CGFloat patternAlpha = 1.0f; 1.256 +- CGColorSpaceRef patternSpace; 1.257 +- CGPatternRef pattern; 1.258 +- cairo_int_status_t status; 1.259 +- 1.260 +- status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern); 1.261 +- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { 1.262 +- state.action = DO_NOTHING; 1.263 +- return state; 1.264 +- } 1.265 +- if (status) { 1.266 +- state.action = DO_UNSUPPORTED; 1.267 +- return state; 1.268 +- } 1.269 +- 1.270 +- patternSpace = CGColorSpaceCreatePattern (NULL); 1.271 +- CGContextSetFillColorSpace (context, patternSpace); 1.272 +- CGContextSetFillPattern (context, pattern, &patternAlpha); 1.273 +- CGContextSetStrokeColorSpace (context, patternSpace); 1.274 +- CGContextSetStrokePattern (context, pattern, &patternAlpha); 1.275 +- CGColorSpaceRelease (patternSpace); 1.276 +- 1.277 +- /* Quartz likes to munge the pattern phase (as yet unexplained 1.278 +- * why); force it to 0,0 as we've already baked in the correct 1.279 +- * pattern translation into the pattern matrix 1.280 +- */ 1.281 +- CGContextSetPatternPhase (context, CGSizeMake(0,0)); 1.282 +- 1.283 +- state.pattern = pattern; 1.284 +- state.action = DO_PATTERN; 1.285 ++ _cairo_quartz_setup_surface_source (surface, spat, extents, &state); 1.286 + return state; 1.287 + } 1.288 + 1.289 + state.action = DO_UNSUPPORTED; 1.290 + return state; 1.291 + } 1.292 + 1.293 + /**