|
1 From: Robert O'Callahan <robert@ocallahan.org> |
|
2 Bug 593270. Part 1: Move surface setup code to a helper function. r=jrmuizel,a=joe |
|
3 |
|
4 diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c |
|
5 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c |
|
6 +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c |
|
7 @@ -1455,16 +1455,147 @@ _cairo_quartz_setup_radial_source (cairo |
|
8 extend, extend); |
|
9 |
|
10 CGColorSpaceRelease(rgb); |
|
11 CGFunctionRelease(gradFunc); |
|
12 |
|
13 state->action = DO_SHADING; |
|
14 } |
|
15 |
|
16 +static void |
|
17 +_cairo_quartz_setup_surface_source (cairo_quartz_surface_t *surface, |
|
18 + const cairo_surface_pattern_t *spat, |
|
19 + cairo_rectangle_int_t *extents, |
|
20 + cairo_quartz_drawing_state_t *state) |
|
21 +{ |
|
22 + const cairo_pattern_t *source = &spat->base; |
|
23 + CGContextRef context = state->context; |
|
24 + |
|
25 + if (source->extend == CAIRO_EXTEND_NONE || |
|
26 + (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)) |
|
27 + { |
|
28 + cairo_surface_t *pat_surf = spat->surface; |
|
29 + CGImageRef img; |
|
30 + cairo_matrix_t m = spat->base.matrix; |
|
31 + cairo_rectangle_int_t extents; |
|
32 + CGAffineTransform xform; |
|
33 + CGRect srcRect; |
|
34 + cairo_fixed_t fw, fh; |
|
35 + cairo_bool_t is_bounded; |
|
36 + cairo_status_t status; |
|
37 + |
|
38 + cairo_matrix_invert(&m); |
|
39 + _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); |
|
40 + |
|
41 + /* Draw nonrepeating CGLayer surface using DO_LAYER */ |
|
42 + if (source->extend == CAIRO_EXTEND_NONE || |
|
43 + (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)) |
|
44 + cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; |
|
45 + if (quartz_surf->cgLayer) { |
|
46 + state->imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); |
|
47 + state->layer = quartz_surf->cgLayer; |
|
48 + state->action = DO_LAYER; |
|
49 + return; |
|
50 + } |
|
51 + } |
|
52 + |
|
53 + status = _cairo_surface_to_cgimage (pat_surf, &img); |
|
54 + if (status) { |
|
55 + state->action = DO_UNSUPPORTED; |
|
56 + return; |
|
57 + } |
|
58 + if (img == NULL) { |
|
59 + state->action = DO_NOTHING; |
|
60 + return; |
|
61 + } |
|
62 + |
|
63 + /* XXXroc what is this for? */ |
|
64 + CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); |
|
65 + |
|
66 + state->image = img; |
|
67 + |
|
68 + is_bounded = _cairo_surface_get_extents (pat_surf, &extents); |
|
69 + assert (is_bounded); |
|
70 + |
|
71 + if (source->extend == CAIRO_EXTEND_NONE) { |
|
72 + state->imageRect = CGRectMake (0, 0, extents.width, extents.height); |
|
73 + state->action = DO_IMAGE; |
|
74 + return; |
|
75 + } |
|
76 + |
|
77 + /* Quartz seems to tile images at pixel-aligned regions only -- this |
|
78 + * leads to seams if the image doesn't end up scaling to fill the |
|
79 + * space exactly. The CGPattern tiling approach doesn't have this |
|
80 + * problem. Check if we're going to fill up the space (within some |
|
81 + * epsilon), and if not, fall back to the CGPattern type. |
|
82 + */ |
|
83 + |
|
84 + xform = CGAffineTransformConcat (CGContextGetCTM (context), |
|
85 + state->transform); |
|
86 + |
|
87 + srcRect = CGRectMake (0, 0, extents.width, extents.height); |
|
88 + srcRect = CGRectApplyAffineTransform (srcRect, xform); |
|
89 + |
|
90 + fw = _cairo_fixed_from_double (srcRect.size.width); |
|
91 + fh = _cairo_fixed_from_double (srcRect.size.height); |
|
92 + |
|
93 + if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON && |
|
94 + (fh & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON) |
|
95 + { |
|
96 + /* We're good to use DrawTiledImage, but ensure that |
|
97 + * the math works out */ |
|
98 + |
|
99 + srcRect.size.width = round(srcRect.size.width); |
|
100 + srcRect.size.height = round(srcRect.size.height); |
|
101 + |
|
102 + xform = CGAffineTransformInvert (xform); |
|
103 + |
|
104 + srcRect = CGRectApplyAffineTransform (srcRect, xform); |
|
105 + |
|
106 + state->imageRect = srcRect; |
|
107 + state->action = DO_TILED_IMAGE; |
|
108 + return; |
|
109 + } |
|
110 + |
|
111 + /* Fall through to generic SURFACE case */ |
|
112 + } |
|
113 + |
|
114 + CGFloat patternAlpha = 1.0f; |
|
115 + CGColorSpaceRef patternSpace; |
|
116 + CGPatternRef pattern; |
|
117 + cairo_int_status_t status; |
|
118 + |
|
119 + status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern); |
|
120 + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { |
|
121 + state->action = DO_NOTHING; |
|
122 + return; |
|
123 + } |
|
124 + if (status) { |
|
125 + state->action = DO_UNSUPPORTED; |
|
126 + return; |
|
127 + } |
|
128 + |
|
129 + patternSpace = CGColorSpaceCreatePattern (NULL); |
|
130 + CGContextSetFillColorSpace (context, patternSpace); |
|
131 + CGContextSetFillPattern (context, pattern, &patternAlpha); |
|
132 + CGContextSetStrokeColorSpace (context, patternSpace); |
|
133 + CGContextSetStrokePattern (context, pattern, &patternAlpha); |
|
134 + CGColorSpaceRelease (patternSpace); |
|
135 + |
|
136 + /* Quartz likes to munge the pattern phase (as yet unexplained |
|
137 + * why); force it to 0,0 as we've already baked in the correct |
|
138 + * pattern translation into the pattern matrix |
|
139 + */ |
|
140 + CGContextSetPatternPhase (context, CGSizeMake(0,0)); |
|
141 + |
|
142 + state->pattern = pattern; |
|
143 + state->action = DO_PATTERN; |
|
144 + return; |
|
145 +} |
|
146 + |
|
147 /** |
|
148 * Call this before any operation that can modify the contents of a |
|
149 * cairo_quartz_surface_t. |
|
150 */ |
|
151 static void |
|
152 _cairo_quartz_surface_will_change (cairo_quartz_surface_t *surface) |
|
153 { |
|
154 if (surface->bitmapContextImage) { |
|
155 @@ -1566,133 +1697,19 @@ _cairo_quartz_setup_state (cairo_quartz_ |
|
156 } |
|
157 |
|
158 if (source->type == CAIRO_PATTERN_TYPE_RADIAL) { |
|
159 const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source; |
|
160 _cairo_quartz_setup_radial_source (surface, rpat, extents, &state); |
|
161 return state; |
|
162 } |
|
163 |
|
164 - if (source->type == CAIRO_PATTERN_TYPE_SURFACE && |
|
165 - (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT))) |
|
166 - { |
|
167 + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
|
168 const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source; |
|
169 - cairo_surface_t *pat_surf = spat->surface; |
|
170 - CGImageRef img; |
|
171 - cairo_matrix_t m = spat->base.matrix; |
|
172 - cairo_rectangle_int_t extents; |
|
173 - CGAffineTransform xform; |
|
174 - CGRect srcRect; |
|
175 - cairo_fixed_t fw, fh; |
|
176 - cairo_bool_t is_bounded; |
|
177 - |
|
178 - cairo_matrix_invert(&m); |
|
179 - _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); |
|
180 - |
|
181 - if (cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) { |
|
182 - cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; |
|
183 - if (quartz_surf->cgLayer && source->extend == CAIRO_EXTEND_NONE) { |
|
184 - state.imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); |
|
185 - state.layer = quartz_surf->cgLayer; |
|
186 - state.action = DO_LAYER; |
|
187 - return state; |
|
188 - } |
|
189 - } |
|
190 - |
|
191 - status = _cairo_surface_to_cgimage (pat_surf, &img); |
|
192 - if (status) { |
|
193 - state.action = DO_UNSUPPORTED; |
|
194 - return state; |
|
195 - } |
|
196 - if (img == NULL) { |
|
197 - state.action = DO_NOTHING; |
|
198 - return state; |
|
199 - } |
|
200 - |
|
201 - CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); |
|
202 - |
|
203 - state.image = img; |
|
204 - |
|
205 - is_bounded = _cairo_surface_get_extents (pat_surf, &extents); |
|
206 - assert (is_bounded); |
|
207 - |
|
208 - if (source->extend == CAIRO_EXTEND_NONE) { |
|
209 - state.imageRect = CGRectMake (0, 0, extents.width, extents.height); |
|
210 - state.action = DO_IMAGE; |
|
211 - return state; |
|
212 - } |
|
213 - |
|
214 - /* Quartz seems to tile images at pixel-aligned regions only -- this |
|
215 - * leads to seams if the image doesn't end up scaling to fill the |
|
216 - * space exactly. The CGPattern tiling approach doesn't have this |
|
217 - * problem. Check if we're going to fill up the space (within some |
|
218 - * epsilon), and if not, fall back to the CGPattern type. |
|
219 - */ |
|
220 - |
|
221 - xform = CGAffineTransformConcat (CGContextGetCTM (context), |
|
222 - state.transform); |
|
223 - |
|
224 - srcRect = CGRectMake (0, 0, extents.width, extents.height); |
|
225 - srcRect = CGRectApplyAffineTransform (srcRect, xform); |
|
226 - |
|
227 - fw = _cairo_fixed_from_double (srcRect.size.width); |
|
228 - fh = _cairo_fixed_from_double (srcRect.size.height); |
|
229 - |
|
230 - if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON && |
|
231 - (fh & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON) |
|
232 - { |
|
233 - /* We're good to use DrawTiledImage, but ensure that |
|
234 - * the math works out */ |
|
235 - |
|
236 - srcRect.size.width = round(srcRect.size.width); |
|
237 - srcRect.size.height = round(srcRect.size.height); |
|
238 - |
|
239 - xform = CGAffineTransformInvert (xform); |
|
240 - |
|
241 - srcRect = CGRectApplyAffineTransform (srcRect, xform); |
|
242 - |
|
243 - state.imageRect = srcRect; |
|
244 - state.action = DO_TILED_IMAGE; |
|
245 - return state; |
|
246 - } |
|
247 - |
|
248 - /* Fall through to generic SURFACE case */ |
|
249 - } |
|
250 - |
|
251 - if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
|
252 - CGFloat patternAlpha = 1.0f; |
|
253 - CGColorSpaceRef patternSpace; |
|
254 - CGPatternRef pattern; |
|
255 - cairo_int_status_t status; |
|
256 - |
|
257 - status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern); |
|
258 - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { |
|
259 - state.action = DO_NOTHING; |
|
260 - return state; |
|
261 - } |
|
262 - if (status) { |
|
263 - state.action = DO_UNSUPPORTED; |
|
264 - return state; |
|
265 - } |
|
266 - |
|
267 - patternSpace = CGColorSpaceCreatePattern (NULL); |
|
268 - CGContextSetFillColorSpace (context, patternSpace); |
|
269 - CGContextSetFillPattern (context, pattern, &patternAlpha); |
|
270 - CGContextSetStrokeColorSpace (context, patternSpace); |
|
271 - CGContextSetStrokePattern (context, pattern, &patternAlpha); |
|
272 - CGColorSpaceRelease (patternSpace); |
|
273 - |
|
274 - /* Quartz likes to munge the pattern phase (as yet unexplained |
|
275 - * why); force it to 0,0 as we've already baked in the correct |
|
276 - * pattern translation into the pattern matrix |
|
277 - */ |
|
278 - CGContextSetPatternPhase (context, CGSizeMake(0,0)); |
|
279 - |
|
280 - state.pattern = pattern; |
|
281 - state.action = DO_PATTERN; |
|
282 + _cairo_quartz_setup_surface_source (surface, spat, extents, &state); |
|
283 return state; |
|
284 } |
|
285 |
|
286 state.action = DO_UNSUPPORTED; |
|
287 return state; |
|
288 } |
|
289 |
|
290 /** |