|
1 diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h |
|
2 --- a/gfx/cairo/cairo/src/cairo-quartz-private.h |
|
3 +++ b/gfx/cairo/cairo/src/cairo-quartz-private.h |
|
4 @@ -50,30 +50,16 @@ typedef struct cairo_quartz_surface { |
|
5 CGContextRef cgContext; |
|
6 CGAffineTransform cgContextBaseCTM; |
|
7 |
|
8 void *imageData; |
|
9 cairo_surface_t *imageSurfaceEquiv; |
|
10 |
|
11 cairo_surface_clipper_t clipper; |
|
12 cairo_rectangle_int_t extents; |
|
13 - |
|
14 - /* These are stored while drawing operations are in place, set up |
|
15 - * by quartz_setup_source() and quartz_finish_source() |
|
16 - */ |
|
17 - CGAffineTransform sourceTransform; |
|
18 - |
|
19 - CGImageRef sourceImage; |
|
20 - cairo_surface_t *sourceImageSurface; |
|
21 - CGRect sourceImageRect; |
|
22 - |
|
23 - CGShadingRef sourceShading; |
|
24 - CGPatternRef sourcePattern; |
|
25 - |
|
26 - CGInterpolationQuality oldInterpolationQuality; |
|
27 } cairo_quartz_surface_t; |
|
28 |
|
29 typedef struct cairo_quartz_image_surface { |
|
30 cairo_surface_t base; |
|
31 |
|
32 cairo_rectangle_int_t extents; |
|
33 |
|
34 CGImageRef image; |
|
35 diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c |
|
36 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c |
|
37 +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c |
|
38 @@ -1333,36 +1333,59 @@ _cairo_quartz_cairo_repeating_surface_pa |
|
39 return CAIRO_STATUS_SUCCESS; |
|
40 } |
|
41 |
|
42 typedef enum { |
|
43 DO_SOLID, |
|
44 DO_SHADING, |
|
45 DO_PATTERN, |
|
46 DO_IMAGE, |
|
47 + DO_TILED_IMAGE, |
|
48 DO_UNSUPPORTED, |
|
49 - DO_NOTHING, |
|
50 - DO_TILED_IMAGE |
|
51 + DO_NOTHING |
|
52 } cairo_quartz_action_t; |
|
53 |
|
54 -static cairo_quartz_action_t |
|
55 +/* State used during a drawing operation. */ |
|
56 +typedef struct { |
|
57 + CGContextRef context; |
|
58 + cairo_quartz_action_t action; |
|
59 + |
|
60 + // Used with DO_SHADING, DO_IMAGE and DO_TILED_IMAGE |
|
61 + CGAffineTransform transform; |
|
62 + |
|
63 + // Used with DO_IMAGE and DO_TILED_IMAGE |
|
64 + CGImageRef image; |
|
65 + cairo_surface_t *imageSurface; |
|
66 + CGRect imageRect; |
|
67 + |
|
68 + // Used with DO_SHADING |
|
69 + CGShadingRef shading; |
|
70 + |
|
71 + // Used with DO_PATTERN |
|
72 + CGPatternRef pattern; |
|
73 +} cairo_quartz_drawing_state_t; |
|
74 + |
|
75 +static void |
|
76 _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface, |
|
77 - const cairo_pattern_t *source) |
|
78 + const cairo_pattern_t *source, |
|
79 + cairo_quartz_drawing_state_t *state) |
|
80 { |
|
81 - CGRect clipBox = CGContextGetClipBoundingBox (surface->cgContext); |
|
82 + CGRect clipBox = CGContextGetClipBoundingBox (state->context); |
|
83 double x0, y0, w, h; |
|
84 |
|
85 cairo_surface_t *fallback; |
|
86 CGImageRef img; |
|
87 |
|
88 cairo_status_t status; |
|
89 |
|
90 if (clipBox.size.width == 0.0f || |
|
91 - clipBox.size.height == 0.0f) |
|
92 - return DO_NOTHING; |
|
93 + clipBox.size.height == 0.0f) { |
|
94 + state->action = DO_NOTHING; |
|
95 + return; |
|
96 + } |
|
97 |
|
98 x0 = floor(clipBox.origin.x); |
|
99 y0 = floor(clipBox.origin.y); |
|
100 w = ceil(clipBox.origin.x + clipBox.size.width) - x0; |
|
101 h = ceil(clipBox.origin.y + clipBox.size.height) - y0; |
|
102 |
|
103 /* Create a temporary the size of the clip surface, and position |
|
104 * it so that the device origin coincides with the original surface */ |
|
105 @@ -1396,73 +1419,79 @@ _cairo_quartz_setup_fallback_source (cai |
|
106 &fallback->device_transform_inverse); |
|
107 status = _cairo_surface_paint (fallback, |
|
108 CAIRO_OPERATOR_SOURCE, |
|
109 &pattern.base, NULL); |
|
110 } |
|
111 #endif |
|
112 |
|
113 status = _cairo_surface_to_cgimage (&surface->base, fallback, &img); |
|
114 - if (status) |
|
115 - return DO_UNSUPPORTED; |
|
116 - if (img == NULL) |
|
117 - return DO_NOTHING; |
|
118 - |
|
119 - surface->sourceImageRect = CGRectMake (0.0, 0.0, w, h); |
|
120 - surface->sourceImage = img; |
|
121 - surface->sourceImageSurface = fallback; |
|
122 - surface->sourceTransform = CGAffineTransformMakeTranslation (x0, y0); |
|
123 - |
|
124 - return DO_IMAGE; |
|
125 + if (status) { |
|
126 + state->action = DO_UNSUPPORTED; |
|
127 + return; |
|
128 + } |
|
129 + if (img == NULL) { |
|
130 + state->action = DO_NOTHING; |
|
131 + return; |
|
132 + } |
|
133 + |
|
134 + state->imageRect = CGRectMake (0.0, 0.0, w, h); |
|
135 + state->image = img; |
|
136 + state->imageSurface = fallback; |
|
137 + state->transform = CGAffineTransformMakeTranslation (x0, y0); |
|
138 + state->action = DO_IMAGE; |
|
139 } |
|
140 |
|
141 /* |
|
142 Quartz does not support repeating radients. We handle repeating gradients |
|
143 by manually extending the gradient and repeating color stops. We need to |
|
144 minimize the number of repetitions since Quartz seems to sample our color |
|
145 function across the entire range, even if part of that range is not needed |
|
146 for the visible area of the gradient, and it samples with some fixed resolution, |
|
147 so if the gradient range is too large it samples with very low resolution and |
|
148 the gradient is very coarse. CreateRepeatingLinearGradientFunction and |
|
149 CreateRepeatingRadialGradientFunction compute the number of repetitions needed |
|
150 based on the extents of the object (the clip region cannot be used here since |
|
151 we don't want the rasterization of the entire gradient to depend on the |
|
152 clip region). |
|
153 */ |
|
154 -static cairo_quartz_action_t |
|
155 +static void |
|
156 _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface, |
|
157 const cairo_linear_pattern_t *lpat, |
|
158 - cairo_rectangle_int_t *extents) |
|
159 + cairo_rectangle_int_t *extents, |
|
160 + cairo_quartz_drawing_state_t *state) |
|
161 { |
|
162 const cairo_pattern_t *abspat = &lpat->base.base; |
|
163 cairo_matrix_t mat; |
|
164 CGPoint start, end; |
|
165 CGFunctionRef gradFunc; |
|
166 CGColorSpaceRef rgb; |
|
167 bool extend = abspat->extend == CAIRO_EXTEND_PAD; |
|
168 |
|
169 if (lpat->base.n_stops == 0) { |
|
170 - CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.); |
|
171 - CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.); |
|
172 - return DO_SOLID; |
|
173 + CGContextSetRGBStrokeColor (state->context, 0., 0., 0., 0.); |
|
174 + CGContextSetRGBFillColor (state->context, 0., 0., 0., 0.); |
|
175 + state->action = DO_SOLID; |
|
176 + return; |
|
177 } |
|
178 |
|
179 if (lpat->p1.x == lpat->p2.x && |
|
180 lpat->p1.y == lpat->p2.y) { |
|
181 /* Quartz handles cases where the vector has no length very |
|
182 * differently from pixman. |
|
183 * Whatever the correct behaviour is, let's at least have only pixman's |
|
184 * implementation to worry about. |
|
185 */ |
|
186 - return _cairo_quartz_setup_fallback_source (surface, abspat); |
|
187 + _cairo_quartz_setup_fallback_source (surface, abspat, state); |
|
188 + return; |
|
189 } |
|
190 |
|
191 mat = abspat->matrix; |
|
192 cairo_matrix_invert (&mat); |
|
193 - _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform); |
|
194 + _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform); |
|
195 |
|
196 rgb = CGColorSpaceCreateDeviceRGB(); |
|
197 |
|
198 start = CGPointMake (_cairo_fixed_to_double (lpat->p1.x), |
|
199 _cairo_fixed_to_double (lpat->p1.y)); |
|
200 end = CGPointMake (_cairo_fixed_to_double (lpat->p2.x), |
|
201 _cairo_fixed_to_double (lpat->p2.y)); |
|
202 |
|
203 @@ -1472,31 +1501,32 @@ _cairo_quartz_setup_linear_source (cairo |
|
204 gradFunc = CreateGradientFunction (&lpat->base); |
|
205 } else { |
|
206 gradFunc = CreateRepeatingLinearGradientFunction (surface, |
|
207 &lpat->base, |
|
208 &start, &end, |
|
209 extents); |
|
210 } |
|
211 |
|
212 - surface->sourceShading = CGShadingCreateAxial (rgb, |
|
213 - start, end, |
|
214 - gradFunc, |
|
215 - extend, extend); |
|
216 + state->shading = CGShadingCreateAxial (rgb, |
|
217 + start, end, |
|
218 + gradFunc, |
|
219 + extend, extend); |
|
220 |
|
221 CGColorSpaceRelease(rgb); |
|
222 CGFunctionRelease(gradFunc); |
|
223 |
|
224 - return DO_SHADING; |
|
225 + state->action = DO_SHADING; |
|
226 } |
|
227 |
|
228 -static cairo_quartz_action_t |
|
229 +static void |
|
230 _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface, |
|
231 const cairo_radial_pattern_t *rpat, |
|
232 - cairo_rectangle_int_t *extents) |
|
233 + cairo_rectangle_int_t *extents, |
|
234 + cairo_quartz_drawing_state_t *state) |
|
235 { |
|
236 const cairo_pattern_t *abspat = &rpat->base.base; |
|
237 cairo_matrix_t mat; |
|
238 CGPoint start, end; |
|
239 CGFunctionRef gradFunc; |
|
240 CGColorSpaceRef rgb; |
|
241 bool extend = abspat->extend == CAIRO_EXTEND_PAD; |
|
242 double c1x = _cairo_fixed_to_double (rpat->c1.x); |
|
243 @@ -1505,35 +1535,37 @@ _cairo_quartz_setup_radial_source (cairo |
|
244 double c2y = _cairo_fixed_to_double (rpat->c2.y); |
|
245 double r1 = _cairo_fixed_to_double (rpat->r1); |
|
246 double r2 = _cairo_fixed_to_double (rpat->r2); |
|
247 double dx = c1x - c2x; |
|
248 double dy = c1y - c2y; |
|
249 double centerDistance = sqrt (dx*dx + dy*dy); |
|
250 |
|
251 if (rpat->base.n_stops == 0) { |
|
252 - CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.); |
|
253 - CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.); |
|
254 - return DO_SOLID; |
|
255 + CGContextSetRGBStrokeColor (state->context, 0., 0., 0., 0.); |
|
256 + CGContextSetRGBFillColor (state->context, 0., 0., 0., 0.); |
|
257 + state->action = DO_SOLID; |
|
258 + return; |
|
259 } |
|
260 |
|
261 if (r2 <= centerDistance + r1 + 1e-6 && /* circle 2 doesn't contain circle 1 */ |
|
262 r1 <= centerDistance + r2 + 1e-6) { /* circle 1 doesn't contain circle 2 */ |
|
263 /* Quartz handles cases where neither circle contains the other very |
|
264 * differently from pixman. |
|
265 * Whatever the correct behaviour is, let's at least have only pixman's |
|
266 * implementation to worry about. |
|
267 * Note that this also catches the cases where r1 == r2. |
|
268 */ |
|
269 - return _cairo_quartz_setup_fallback_source (surface, abspat); |
|
270 + _cairo_quartz_setup_fallback_source (surface, abspat, state); |
|
271 + return; |
|
272 } |
|
273 |
|
274 mat = abspat->matrix; |
|
275 cairo_matrix_invert (&mat); |
|
276 - _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform); |
|
277 + _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform); |
|
278 |
|
279 rgb = CGColorSpaceCreateDeviceRGB(); |
|
280 |
|
281 start = CGPointMake (c1x, c1y); |
|
282 end = CGPointMake (c2x, c2y); |
|
283 |
|
284 if (abspat->extend == CAIRO_EXTEND_NONE || |
|
285 abspat->extend == CAIRO_EXTEND_PAD) |
|
286 @@ -1542,111 +1574,146 @@ _cairo_quartz_setup_radial_source (cairo |
|
287 } else { |
|
288 gradFunc = CreateRepeatingRadialGradientFunction (surface, |
|
289 &rpat->base, |
|
290 &start, &r1, |
|
291 &end, &r2, |
|
292 extents); |
|
293 } |
|
294 |
|
295 - surface->sourceShading = CGShadingCreateRadial (rgb, |
|
296 - start, |
|
297 - r1, |
|
298 - end, |
|
299 - r2, |
|
300 - gradFunc, |
|
301 - extend, extend); |
|
302 + state->shading = CGShadingCreateRadial (rgb, |
|
303 + start, |
|
304 + r1, |
|
305 + end, |
|
306 + r2, |
|
307 + gradFunc, |
|
308 + extend, extend); |
|
309 |
|
310 CGColorSpaceRelease(rgb); |
|
311 CGFunctionRelease(gradFunc); |
|
312 |
|
313 - return DO_SHADING; |
|
314 + state->action = DO_SHADING; |
|
315 } |
|
316 |
|
317 -static cairo_quartz_action_t |
|
318 -_cairo_quartz_setup_source (cairo_quartz_surface_t *surface, |
|
319 - const cairo_pattern_t *source, |
|
320 - cairo_rectangle_int_t *extents) |
|
321 +/** |
|
322 + * Sets up internal state to be used to draw the source mask, stored in |
|
323 + * cairo_quartz_state_t. Guarantees to call CGContextSaveGState on |
|
324 + * surface->cgContext. |
|
325 + */ |
|
326 +static cairo_quartz_drawing_state_t |
|
327 +_cairo_quartz_setup_state (cairo_quartz_surface_t *surface, |
|
328 + const cairo_pattern_t *source, |
|
329 + cairo_operator_t op, |
|
330 + cairo_rectangle_int_t *extents) |
|
331 { |
|
332 - assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern)); |
|
333 - |
|
334 - surface->oldInterpolationQuality = CGContextGetInterpolationQuality (surface->cgContext); |
|
335 - CGContextSetInterpolationQuality (surface->cgContext, _cairo_quartz_filter_to_quartz (source->filter)); |
|
336 + CGContextRef context = surface->cgContext; |
|
337 + cairo_quartz_drawing_state_t state; |
|
338 + cairo_status_t status; |
|
339 + |
|
340 + state.context = context; |
|
341 + state.image = NULL; |
|
342 + state.imageSurface = NULL; |
|
343 + state.shading = NULL; |
|
344 + state.pattern = NULL; |
|
345 + |
|
346 + // Save before we change the pattern, colorspace, etc. so that |
|
347 + // we can restore and make sure that quartz releases our |
|
348 + // pattern (which may be stack allocated) |
|
349 + CGContextSaveGState(context); |
|
350 + |
|
351 + CGContextSetInterpolationQuality (context, _cairo_quartz_filter_to_quartz (source->filter)); |
|
352 + |
|
353 + status = _cairo_quartz_surface_set_cairo_operator (surface, op); |
|
354 + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { |
|
355 + state.action = DO_NOTHING; |
|
356 + return state; |
|
357 + } |
|
358 + if (status) { |
|
359 + state.action = DO_UNSUPPORTED; |
|
360 + return state; |
|
361 + } |
|
362 |
|
363 if (source->type == CAIRO_PATTERN_TYPE_SOLID) { |
|
364 cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; |
|
365 |
|
366 - CGContextSetRGBStrokeColor (surface->cgContext, |
|
367 + CGContextSetRGBStrokeColor (context, |
|
368 solid->color.red, |
|
369 solid->color.green, |
|
370 solid->color.blue, |
|
371 solid->color.alpha); |
|
372 - CGContextSetRGBFillColor (surface->cgContext, |
|
373 + CGContextSetRGBFillColor (context, |
|
374 solid->color.red, |
|
375 solid->color.green, |
|
376 solid->color.blue, |
|
377 solid->color.alpha); |
|
378 |
|
379 - return DO_SOLID; |
|
380 + state.action = DO_SOLID; |
|
381 + return state; |
|
382 } |
|
383 |
|
384 if (source->type == CAIRO_PATTERN_TYPE_LINEAR) { |
|
385 const cairo_linear_pattern_t *lpat = (const cairo_linear_pattern_t *)source; |
|
386 - return _cairo_quartz_setup_linear_source (surface, lpat, extents); |
|
387 + _cairo_quartz_setup_linear_source (surface, lpat, extents, &state); |
|
388 + return state; |
|
389 } |
|
390 |
|
391 if (source->type == CAIRO_PATTERN_TYPE_RADIAL) { |
|
392 const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source; |
|
393 - return _cairo_quartz_setup_radial_source (surface, rpat, extents); |
|
394 + _cairo_quartz_setup_radial_source (surface, rpat, extents, &state); |
|
395 + return state; |
|
396 } |
|
397 |
|
398 if (source->type == CAIRO_PATTERN_TYPE_SURFACE && |
|
399 (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT))) |
|
400 { |
|
401 const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source; |
|
402 cairo_surface_t *pat_surf = spat->surface; |
|
403 CGImageRef img; |
|
404 cairo_matrix_t m = spat->base.matrix; |
|
405 cairo_rectangle_int_t extents; |
|
406 - cairo_status_t status; |
|
407 CGAffineTransform xform; |
|
408 CGRect srcRect; |
|
409 cairo_fixed_t fw, fh; |
|
410 cairo_bool_t is_bounded; |
|
411 |
|
412 status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img); |
|
413 - if (status) |
|
414 - return DO_UNSUPPORTED; |
|
415 - if (img == NULL) |
|
416 - return DO_NOTHING; |
|
417 + if (status) { |
|
418 + state.action = DO_UNSUPPORTED; |
|
419 + return state; |
|
420 + } |
|
421 + if (img == NULL) { |
|
422 + state.action = DO_NOTHING; |
|
423 + return state; |
|
424 + } |
|
425 |
|
426 CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1); |
|
427 |
|
428 - surface->sourceImage = img; |
|
429 + state.image = img; |
|
430 |
|
431 cairo_matrix_invert(&m); |
|
432 - _cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceTransform); |
|
433 + _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform); |
|
434 |
|
435 is_bounded = _cairo_surface_get_extents (pat_surf, &extents); |
|
436 assert (is_bounded); |
|
437 |
|
438 if (source->extend == CAIRO_EXTEND_NONE) { |
|
439 - surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height); |
|
440 - return DO_IMAGE; |
|
441 + state.imageRect = CGRectMake (0, 0, extents.width, extents.height); |
|
442 + state.action = DO_IMAGE; |
|
443 + return state; |
|
444 } |
|
445 |
|
446 /* Quartz seems to tile images at pixel-aligned regions only -- this |
|
447 * leads to seams if the image doesn't end up scaling to fill the |
|
448 * space exactly. The CGPattern tiling approach doesn't have this |
|
449 * problem. Check if we're going to fill up the space (within some |
|
450 * epsilon), and if not, fall back to the CGPattern type. |
|
451 */ |
|
452 |
|
453 - xform = CGAffineTransformConcat (CGContextGetCTM (surface->cgContext), |
|
454 - surface->sourceTransform); |
|
455 + xform = CGAffineTransformConcat (CGContextGetCTM (context), |
|
456 + state.transform); |
|
457 |
|
458 srcRect = CGRectMake (0, 0, extents.width, extents.height); |
|
459 srcRect = CGRectApplyAffineTransform (srcRect, xform); |
|
460 |
|
461 fw = _cairo_fixed_from_double (srcRect.size.width); |
|
462 fh = _cairo_fixed_from_double (srcRect.size.height); |
|
463 |
|
464 if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON && |
|
465 @@ -1657,111 +1724,109 @@ _cairo_quartz_setup_source (cairo_quartz |
|
466 |
|
467 srcRect.size.width = round(srcRect.size.width); |
|
468 srcRect.size.height = round(srcRect.size.height); |
|
469 |
|
470 xform = CGAffineTransformInvert (xform); |
|
471 |
|
472 srcRect = CGRectApplyAffineTransform (srcRect, xform); |
|
473 |
|
474 - surface->sourceImageRect = srcRect; |
|
475 - |
|
476 - return DO_TILED_IMAGE; |
|
477 + state.imageRect = srcRect; |
|
478 + state.action = DO_TILED_IMAGE; |
|
479 + return state; |
|
480 } |
|
481 |
|
482 /* Fall through to generic SURFACE case */ |
|
483 } |
|
484 |
|
485 if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
|
486 CGFloat patternAlpha = 1.0f; |
|
487 CGColorSpaceRef patternSpace; |
|
488 CGPatternRef pattern; |
|
489 cairo_int_status_t status; |
|
490 |
|
491 status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern); |
|
492 - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) |
|
493 - return DO_NOTHING; |
|
494 - if (status) |
|
495 - return DO_UNSUPPORTED; |
|
496 - |
|
497 - // Save before we change the pattern, colorspace, etc. so that |
|
498 - // we can restore and make sure that quartz releases our |
|
499 - // pattern (which may be stack allocated) |
|
500 - CGContextSaveGState(surface->cgContext); |
|
501 - |
|
502 - patternSpace = CGColorSpaceCreatePattern(NULL); |
|
503 - CGContextSetFillColorSpace (surface->cgContext, patternSpace); |
|
504 - CGContextSetFillPattern (surface->cgContext, pattern, &patternAlpha); |
|
505 - CGContextSetStrokeColorSpace (surface->cgContext, patternSpace); |
|
506 - CGContextSetStrokePattern (surface->cgContext, pattern, &patternAlpha); |
|
507 + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { |
|
508 + state.action = DO_NOTHING; |
|
509 + return state; |
|
510 + } |
|
511 + if (status) { |
|
512 + state.action = DO_UNSUPPORTED; |
|
513 + return state; |
|
514 + } |
|
515 + |
|
516 + patternSpace = CGColorSpaceCreatePattern (NULL); |
|
517 + CGContextSetFillColorSpace (context, patternSpace); |
|
518 + CGContextSetFillPattern (context, pattern, &patternAlpha); |
|
519 + CGContextSetStrokeColorSpace (context, patternSpace); |
|
520 + CGContextSetStrokePattern (context, pattern, &patternAlpha); |
|
521 CGColorSpaceRelease (patternSpace); |
|
522 |
|
523 /* Quartz likes to munge the pattern phase (as yet unexplained |
|
524 * why); force it to 0,0 as we've already baked in the correct |
|
525 * pattern translation into the pattern matrix |
|
526 */ |
|
527 - CGContextSetPatternPhase (surface->cgContext, CGSizeMake(0,0)); |
|
528 - |
|
529 - surface->sourcePattern = pattern; |
|
530 - |
|
531 - return DO_PATTERN; |
|
532 + CGContextSetPatternPhase (context, CGSizeMake(0,0)); |
|
533 + |
|
534 + state.pattern = pattern; |
|
535 + state.action = DO_PATTERN; |
|
536 + return state; |
|
537 } |
|
538 |
|
539 - return DO_UNSUPPORTED; |
|
540 + state.action = DO_UNSUPPORTED; |
|
541 + return state; |
|
542 } |
|
543 |
|
544 +/** |
|
545 + * 1) Tears down internal state used to draw the source |
|
546 + * 2) Does CGContextRestoreGState(state->context) |
|
547 + */ |
|
548 static void |
|
549 -_cairo_quartz_teardown_source (cairo_quartz_surface_t *surface, |
|
550 - const cairo_pattern_t *source) |
|
551 +_cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state) |
|
552 { |
|
553 - CGContextSetInterpolationQuality (surface->cgContext, surface->oldInterpolationQuality); |
|
554 - |
|
555 - if (surface->sourceImage) { |
|
556 - CGImageRelease(surface->sourceImage); |
|
557 - surface->sourceImage = NULL; |
|
558 - |
|
559 - cairo_surface_destroy(surface->sourceImageSurface); |
|
560 - surface->sourceImageSurface = NULL; |
|
561 + if (state->image) { |
|
562 + CGImageRelease(state->image); |
|
563 } |
|
564 |
|
565 - if (surface->sourceShading) { |
|
566 - CGShadingRelease(surface->sourceShading); |
|
567 - surface->sourceShading = NULL; |
|
568 + if (state->imageSurface) { |
|
569 + cairo_surface_destroy(state->imageSurface); |
|
570 } |
|
571 |
|
572 - if (surface->sourcePattern) { |
|
573 - CGPatternRelease(surface->sourcePattern); |
|
574 - // To tear down the pattern and colorspace |
|
575 - CGContextRestoreGState(surface->cgContext); |
|
576 - |
|
577 - surface->sourcePattern = NULL; |
|
578 + if (state->shading) { |
|
579 + CGShadingRelease(state->shading); |
|
580 } |
|
581 + |
|
582 + if (state->pattern) { |
|
583 + CGPatternRelease(state->pattern); |
|
584 + } |
|
585 + |
|
586 + CGContextRestoreGState(state->context); |
|
587 } |
|
588 |
|
589 |
|
590 static void |
|
591 -_cairo_quartz_draw_image (cairo_quartz_surface_t *surface, cairo_operator_t op, cairo_quartz_action_t action) |
|
592 +_cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state, cairo_operator_t op) |
|
593 { |
|
594 - assert (surface && surface->sourceImage && (action == DO_IMAGE || action == DO_TILED_IMAGE)); |
|
595 - |
|
596 - CGContextConcatCTM (surface->cgContext, surface->sourceTransform); |
|
597 - CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height); |
|
598 - CGContextScaleCTM (surface->cgContext, 1, -1); |
|
599 - |
|
600 - if (action == DO_IMAGE) { |
|
601 - CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage); |
|
602 - if (!_cairo_operator_bounded_by_source(op)) { |
|
603 - CGContextBeginPath (surface->cgContext); |
|
604 - CGContextAddRect (surface->cgContext, surface->sourceImageRect); |
|
605 - CGContextAddRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext)); |
|
606 - CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 0); |
|
607 - CGContextEOFillPath (surface->cgContext); |
|
608 + assert (state && state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)); |
|
609 + |
|
610 + CGContextConcatCTM (state->context, state->transform); |
|
611 + CGContextTranslateCTM (state->context, 0, state->imageRect.size.height); |
|
612 + CGContextScaleCTM (state->context, 1, -1); |
|
613 + |
|
614 + if (state->action == DO_IMAGE) { |
|
615 + CGContextDrawImage (state->context, state->imageRect, state->image); |
|
616 + if (!_cairo_operator_bounded_by_source (op)) { |
|
617 + CGContextBeginPath (state->context); |
|
618 + CGContextAddRect (state->context, state->imageRect); |
|
619 + CGContextAddRect (state->context, CGContextGetClipBoundingBox (state->context)); |
|
620 + CGContextSetRGBFillColor (state->context, 0, 0, 0, 0); |
|
621 + CGContextEOFillPath (state->context); |
|
622 } |
|
623 } else |
|
624 - CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage); |
|
625 + CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image); |
|
626 } |
|
627 |
|
628 |
|
629 /* |
|
630 * get source/dest image implementation |
|
631 */ |
|
632 |
|
633 /* Read the image from the surface's front buffer */ |
|
634 @@ -2098,52 +2163,44 @@ _cairo_quartz_surface_get_extents (void |
|
635 static cairo_int_status_t |
|
636 _cairo_quartz_surface_paint (void *abstract_surface, |
|
637 cairo_operator_t op, |
|
638 const cairo_pattern_t *source, |
|
639 cairo_clip_t *clip) |
|
640 { |
|
641 cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; |
|
642 cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; |
|
643 - cairo_quartz_action_t action; |
|
644 + cairo_quartz_drawing_state_t state; |
|
645 |
|
646 ND((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type)); |
|
647 |
|
648 if (IS_EMPTY(surface)) |
|
649 return CAIRO_STATUS_SUCCESS; |
|
650 |
|
651 rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip); |
|
652 if (unlikely (rv)) |
|
653 return rv; |
|
654 |
|
655 - rv = _cairo_quartz_surface_set_cairo_operator (surface, op); |
|
656 - if (unlikely (rv)) |
|
657 - return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv; |
|
658 - |
|
659 - action = _cairo_quartz_setup_source (surface, source, NULL); |
|
660 - |
|
661 - if (action == DO_SOLID || action == DO_PATTERN) { |
|
662 - CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x, |
|
663 - surface->extents.y, |
|
664 - surface->extents.width, |
|
665 - surface->extents.height)); |
|
666 - } else if (action == DO_SHADING) { |
|
667 - CGContextSaveGState (surface->cgContext); |
|
668 - CGContextConcatCTM (surface->cgContext, surface->sourceTransform); |
|
669 - CGContextDrawShading (surface->cgContext, surface->sourceShading); |
|
670 - CGContextRestoreGState (surface->cgContext); |
|
671 - } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) { |
|
672 - CGContextSaveGState (surface->cgContext); |
|
673 - _cairo_quartz_draw_image (surface, op, action); |
|
674 - CGContextRestoreGState (surface->cgContext); |
|
675 - } else if (action != DO_NOTHING) { |
|
676 + state = _cairo_quartz_setup_state (surface, source, op, NULL); |
|
677 + |
|
678 + if (state.action == DO_SOLID || state.action == DO_PATTERN) { |
|
679 + CGContextFillRect (state.context, CGRectMake(surface->extents.x, |
|
680 + surface->extents.y, |
|
681 + surface->extents.width, |
|
682 + surface->extents.height)); |
|
683 + } else if (state.action == DO_SHADING) { |
|
684 + CGContextConcatCTM (state.context, state.transform); |
|
685 + CGContextDrawShading (state.context, state.shading); |
|
686 + } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { |
|
687 + _cairo_quartz_draw_image (&state, op); |
|
688 + } else if (state.action != DO_NOTHING) { |
|
689 rv = CAIRO_INT_STATUS_UNSUPPORTED; |
|
690 } |
|
691 |
|
692 - _cairo_quartz_teardown_source (surface, source); |
|
693 + _cairo_quartz_teardown_state (&state); |
|
694 |
|
695 ND((stderr, "-- paint\n")); |
|
696 return rv; |
|
697 } |
|
698 |
|
699 static cairo_bool_t |
|
700 _cairo_quartz_source_needs_extents (const cairo_pattern_t *source) |
|
701 { |
|
702 @@ -2170,91 +2227,83 @@ _cairo_quartz_surface_fill (void *abstra |
|
703 cairo_path_fixed_t *path, |
|
704 cairo_fill_rule_t fill_rule, |
|
705 double tolerance, |
|
706 cairo_antialias_t antialias, |
|
707 cairo_clip_t *clip) |
|
708 { |
|
709 cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; |
|
710 cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; |
|
711 - cairo_quartz_action_t action; |
|
712 + cairo_quartz_drawing_state_t state; |
|
713 quartz_stroke_t stroke; |
|
714 CGPathRef path_for_unbounded = NULL; |
|
715 |
|
716 ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type)); |
|
717 |
|
718 if (IS_EMPTY(surface)) |
|
719 return CAIRO_STATUS_SUCCESS; |
|
720 |
|
721 rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip); |
|
722 if (unlikely (rv)) |
|
723 return rv; |
|
724 |
|
725 - rv = _cairo_quartz_surface_set_cairo_operator (surface, op); |
|
726 - if (unlikely (rv)) |
|
727 - return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv; |
|
728 - |
|
729 - CGContextSaveGState (surface->cgContext); |
|
730 - |
|
731 - CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE)); |
|
732 - |
|
733 if (_cairo_quartz_source_needs_extents (source)) |
|
734 { |
|
735 /* We don't need precise extents since these are only used to |
|
736 compute the number of gradient reptitions needed to cover the |
|
737 object. */ |
|
738 cairo_rectangle_int_t path_extents; |
|
739 _cairo_path_fixed_approximate_fill_extents (path, &path_extents); |
|
740 - action = _cairo_quartz_setup_source (surface, source, &path_extents); |
|
741 + state = _cairo_quartz_setup_state (surface, source, op, &path_extents); |
|
742 } else { |
|
743 - action = _cairo_quartz_setup_source (surface, source, NULL); |
|
744 + state = _cairo_quartz_setup_state (surface, source, op, NULL); |
|
745 } |
|
746 |
|
747 - CGContextBeginPath (surface->cgContext); |
|
748 - |
|
749 - stroke.cgContext = surface->cgContext; |
|
750 + CGContextSetShouldAntialias (state.context, (antialias != CAIRO_ANTIALIAS_NONE)); |
|
751 + |
|
752 + CGContextBeginPath (state.context); |
|
753 + |
|
754 + stroke.cgContext = state.context; |
|
755 stroke.ctm_inverse = NULL; |
|
756 rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); |
|
757 if (rv) |
|
758 goto BAIL; |
|
759 |
|
760 if (!_cairo_operator_bounded_by_mask(op) && CGContextCopyPathPtr) |
|
761 - path_for_unbounded = CGContextCopyPathPtr (surface->cgContext); |
|
762 - |
|
763 - if (action == DO_SOLID || action == DO_PATTERN) { |
|
764 + path_for_unbounded = CGContextCopyPathPtr (state.context); |
|
765 + |
|
766 + if (state.action == DO_SOLID || state.action == DO_PATTERN) { |
|
767 if (fill_rule == CAIRO_FILL_RULE_WINDING) |
|
768 - CGContextFillPath (surface->cgContext); |
|
769 + CGContextFillPath (state.context); |
|
770 else |
|
771 - CGContextEOFillPath (surface->cgContext); |
|
772 - } else if (action == DO_SHADING) { |
|
773 + CGContextEOFillPath (state.context); |
|
774 + } else if (state.action == DO_SHADING) { |
|
775 |
|
776 // we have to clip and then paint the shading; we can't fill |
|
777 // with the shading |
|
778 if (fill_rule == CAIRO_FILL_RULE_WINDING) |
|
779 - CGContextClip (surface->cgContext); |
|
780 + CGContextClip (state.context); |
|
781 else |
|
782 - CGContextEOClip (surface->cgContext); |
|
783 - |
|
784 - CGContextConcatCTM (surface->cgContext, surface->sourceTransform); |
|
785 - CGContextDrawShading (surface->cgContext, surface->sourceShading); |
|
786 - } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) { |
|
787 + CGContextEOClip (state.context); |
|
788 + |
|
789 + CGContextConcatCTM (state.context, state.transform); |
|
790 + CGContextDrawShading (state.context, state.shading); |
|
791 + } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { |
|
792 if (fill_rule == CAIRO_FILL_RULE_WINDING) |
|
793 - CGContextClip (surface->cgContext); |
|
794 + CGContextClip (state.context); |
|
795 else |
|
796 - CGContextEOClip (surface->cgContext); |
|
797 - |
|
798 - _cairo_quartz_draw_image (surface, op, action); |
|
799 - } else if (action != DO_NOTHING) { |
|
800 + CGContextEOClip (state.context); |
|
801 + |
|
802 + _cairo_quartz_draw_image (&state, op); |
|
803 + } else if (state.action != DO_NOTHING) { |
|
804 rv = CAIRO_INT_STATUS_UNSUPPORTED; |
|
805 } |
|
806 |
|
807 BAIL: |
|
808 - _cairo_quartz_teardown_source (surface, source); |
|
809 - |
|
810 - CGContextRestoreGState (surface->cgContext); |
|
811 + _cairo_quartz_teardown_state (&state); |
|
812 |
|
813 if (path_for_unbounded) { |
|
814 unbounded_op_data_t ub; |
|
815 ub.op = UNBOUNDED_STROKE_FILL; |
|
816 ub.u.stroke_fill.cgPath = path_for_unbounded; |
|
817 ub.u.stroke_fill.fill_rule = fill_rule; |
|
818 |
|
819 _cairo_quartz_fixup_unbounded_operation (surface, &ub, antialias); |
|
820 @@ -2274,44 +2323,49 @@ _cairo_quartz_surface_stroke (void *abst |
|
821 cairo_matrix_t *ctm, |
|
822 cairo_matrix_t *ctm_inverse, |
|
823 double tolerance, |
|
824 cairo_antialias_t antialias, |
|
825 cairo_clip_t *clip) |
|
826 { |
|
827 cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; |
|
828 cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; |
|
829 - cairo_quartz_action_t action; |
|
830 + cairo_quartz_drawing_state_t state; |
|
831 quartz_stroke_t stroke; |
|
832 CGAffineTransform origCTM, strokeTransform; |
|
833 CGPathRef path_for_unbounded = NULL; |
|
834 |
|
835 ND((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type)); |
|
836 |
|
837 if (IS_EMPTY(surface)) |
|
838 return CAIRO_STATUS_SUCCESS; |
|
839 |
|
840 rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip); |
|
841 if (unlikely (rv)) |
|
842 return rv; |
|
843 |
|
844 - rv = _cairo_quartz_surface_set_cairo_operator (surface, op); |
|
845 - if (unlikely (rv)) |
|
846 - return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv; |
|
847 + if (_cairo_quartz_source_needs_extents (source)) |
|
848 + { |
|
849 + cairo_rectangle_int_t path_extents; |
|
850 + _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents); |
|
851 + state = _cairo_quartz_setup_state (surface, source, op, &path_extents); |
|
852 + } else { |
|
853 + state = _cairo_quartz_setup_state (surface, source, op, NULL); |
|
854 + } |
|
855 |
|
856 // Turning antialiasing off used to cause misrendering with |
|
857 // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels). |
|
858 // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases. |
|
859 - CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE)); |
|
860 - CGContextSetLineWidth (surface->cgContext, style->line_width); |
|
861 - CGContextSetLineCap (surface->cgContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap)); |
|
862 - CGContextSetLineJoin (surface->cgContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join)); |
|
863 - CGContextSetMiterLimit (surface->cgContext, style->miter_limit); |
|
864 - |
|
865 - origCTM = CGContextGetCTM (surface->cgContext); |
|
866 + CGContextSetShouldAntialias (state.context, (antialias != CAIRO_ANTIALIAS_NONE)); |
|
867 + CGContextSetLineWidth (state.context, style->line_width); |
|
868 + CGContextSetLineCap (state.context, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap)); |
|
869 + CGContextSetLineJoin (state.context, _cairo_quartz_cairo_line_join_to_quartz (style->line_join)); |
|
870 + CGContextSetMiterLimit (state.context, style->miter_limit); |
|
871 + |
|
872 + origCTM = CGContextGetCTM (state.context); |
|
873 |
|
874 if (style->dash && style->num_dashes) { |
|
875 #define STATIC_DASH 32 |
|
876 CGFloat sdash[STATIC_DASH]; |
|
877 CGFloat *fdash = sdash; |
|
878 double offset = style->dash_offset; |
|
879 unsigned int max_dashes = style->num_dashes; |
|
880 unsigned int k; |
|
881 @@ -2330,90 +2384,75 @@ _cairo_quartz_surface_stroke (void *abst |
|
882 if (max_dashes > STATIC_DASH) |
|
883 fdash = _cairo_malloc_ab (max_dashes, sizeof (CGFloat)); |
|
884 if (fdash == NULL) |
|
885 return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
886 |
|
887 for (k = 0; k < max_dashes; k++) |
|
888 fdash[k] = (CGFloat) style->dash[k % style->num_dashes]; |
|
889 } |
|
890 - CGContextSetLineDash (surface->cgContext, offset, fdash, max_dashes); |
|
891 + CGContextSetLineDash (state.context, offset, fdash, max_dashes); |
|
892 if (fdash != sdash) |
|
893 free (fdash); |
|
894 } else |
|
895 - CGContextSetLineDash (surface->cgContext, 0, NULL, 0); |
|
896 - |
|
897 - CGContextSaveGState (surface->cgContext); |
|
898 - |
|
899 - |
|
900 - if (_cairo_quartz_source_needs_extents (source)) |
|
901 - { |
|
902 - cairo_rectangle_int_t path_extents; |
|
903 - _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents); |
|
904 - action = _cairo_quartz_setup_source (surface, source, &path_extents); |
|
905 - } else { |
|
906 - action = _cairo_quartz_setup_source (surface, source, NULL); |
|
907 - } |
|
908 + CGContextSetLineDash (state.context, 0, NULL, 0); |
|
909 |
|
910 _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform); |
|
911 - CGContextConcatCTM (surface->cgContext, strokeTransform); |
|
912 - |
|
913 - CGContextBeginPath (surface->cgContext); |
|
914 - |
|
915 - stroke.cgContext = surface->cgContext; |
|
916 + CGContextConcatCTM (state.context, strokeTransform); |
|
917 + |
|
918 + CGContextBeginPath (state.context); |
|
919 + |
|
920 + stroke.cgContext = state.context; |
|
921 stroke.ctm_inverse = ctm_inverse; |
|
922 rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); |
|
923 if (rv) |
|
924 goto BAIL; |
|
925 |
|
926 if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr) |
|
927 - path_for_unbounded = CGContextCopyPathPtr (surface->cgContext); |
|
928 - |
|
929 - if (action == DO_SOLID || action == DO_PATTERN) { |
|
930 - CGContextStrokePath (surface->cgContext); |
|
931 - } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) { |
|
932 - CGContextReplacePathWithStrokedPath (surface->cgContext); |
|
933 - CGContextClip (surface->cgContext); |
|
934 - |
|
935 - CGContextSetCTM (surface->cgContext, origCTM); |
|
936 - _cairo_quartz_draw_image (surface, op, action); |
|
937 - } else if (action == DO_SHADING) { |
|
938 - CGContextReplacePathWithStrokedPath (surface->cgContext); |
|
939 - CGContextClip (surface->cgContext); |
|
940 - |
|
941 - CGContextSetCTM (surface->cgContext, origCTM); |
|
942 - |
|
943 - CGContextConcatCTM (surface->cgContext, surface->sourceTransform); |
|
944 - CGContextDrawShading (surface->cgContext, surface->sourceShading); |
|
945 - } else if (action != DO_NOTHING) { |
|
946 + path_for_unbounded = CGContextCopyPathPtr (state.context); |
|
947 + |
|
948 + if (state.action == DO_SOLID || state.action == DO_PATTERN) { |
|
949 + CGContextStrokePath (state.context); |
|
950 + } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { |
|
951 + CGContextReplacePathWithStrokedPath (state.context); |
|
952 + CGContextClip (state.context); |
|
953 + |
|
954 + CGContextSetCTM (state.context, origCTM); |
|
955 + _cairo_quartz_draw_image (&state, op); |
|
956 + } else if (state.action == DO_SHADING) { |
|
957 + CGContextReplacePathWithStrokedPath (state.context); |
|
958 + CGContextClip (state.context); |
|
959 + |
|
960 + CGContextSetCTM (state.context, origCTM); |
|
961 + |
|
962 + CGContextConcatCTM (state.context, state.transform); |
|
963 + CGContextDrawShading (state.context, state.shading); |
|
964 + } else if (state.action != DO_NOTHING) { |
|
965 rv = CAIRO_INT_STATUS_UNSUPPORTED; |
|
966 + goto BAIL; |
|
967 } |
|
968 |
|
969 + if (path_for_unbounded) { |
|
970 + CGContextSetCTM (state.context, origCTM); |
|
971 + CGContextConcatCTM (state.context, strokeTransform); |
|
972 + |
|
973 + CGContextBeginPath (state.context); |
|
974 + CGContextAddPath (state.context, path_for_unbounded); |
|
975 + CGPathRelease (path_for_unbounded); |
|
976 + |
|
977 + CGContextReplacePathWithStrokedPath (state.context); |
|
978 + |
|
979 + CGContextAddRect (state.context, CGContextGetClipBoundingBox (state.context)); |
|
980 + |
|
981 + CGContextSetRGBFillColor (state.context, 0., 0., 0., 0.); |
|
982 + CGContextEOFillPath (state.context); |
|
983 + } |
|
984 + |
|
985 BAIL: |
|
986 - _cairo_quartz_teardown_source (surface, source); |
|
987 - |
|
988 - CGContextRestoreGState (surface->cgContext); |
|
989 - |
|
990 - if (path_for_unbounded) { |
|
991 - CGContextSaveGState (surface->cgContext); |
|
992 - CGContextConcatCTM (surface->cgContext, strokeTransform); |
|
993 - |
|
994 - CGContextBeginPath (surface->cgContext); |
|
995 - CGContextAddPath (surface->cgContext, path_for_unbounded); |
|
996 - CGPathRelease (path_for_unbounded); |
|
997 - |
|
998 - CGContextReplacePathWithStrokedPath (surface->cgContext); |
|
999 - |
|
1000 - CGContextAddRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext)); |
|
1001 - |
|
1002 - CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.); |
|
1003 - CGContextEOFillPath (surface->cgContext); |
|
1004 - |
|
1005 - CGContextRestoreGState (surface->cgContext); |
|
1006 - } |
|
1007 + _cairo_quartz_teardown_state (&state); |
|
1008 |
|
1009 ND((stderr, "-- stroke\n")); |
|
1010 return rv; |
|
1011 } |
|
1012 |
|
1013 #if CAIRO_HAS_QUARTZ_FONT |
|
1014 static cairo_int_status_t |
|
1015 _cairo_quartz_surface_show_glyphs (void *abstract_surface, |
|
1016 @@ -2429,17 +2468,17 @@ _cairo_quartz_surface_show_glyphs (void |
|
1017 #define STATIC_BUF_SIZE 64 |
|
1018 CGGlyph glyphs_static[STATIC_BUF_SIZE]; |
|
1019 CGSize cg_advances_static[STATIC_BUF_SIZE]; |
|
1020 CGGlyph *cg_glyphs = &glyphs_static[0]; |
|
1021 CGSize *cg_advances = &cg_advances_static[0]; |
|
1022 |
|
1023 cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; |
|
1024 cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; |
|
1025 - cairo_quartz_action_t action; |
|
1026 + cairo_quartz_drawing_state_t state; |
|
1027 float xprev, yprev; |
|
1028 int i; |
|
1029 CGFontRef cgfref = NULL; |
|
1030 |
|
1031 cairo_bool_t isClipping = FALSE; |
|
1032 cairo_bool_t didForceFontSmoothing = FALSE; |
|
1033 |
|
1034 if (IS_EMPTY(surface)) |
|
1035 @@ -2450,65 +2489,59 @@ _cairo_quartz_surface_show_glyphs (void |
|
1036 |
|
1037 if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ) |
|
1038 return CAIRO_INT_STATUS_UNSUPPORTED; |
|
1039 |
|
1040 rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip); |
|
1041 if (unlikely (rv)) |
|
1042 return rv; |
|
1043 |
|
1044 - rv = _cairo_quartz_surface_set_cairo_operator (surface, op); |
|
1045 - if (unlikely (rv)) |
|
1046 - return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv; |
|
1047 - |
|
1048 - CGContextSaveGState (surface->cgContext); |
|
1049 - |
|
1050 if (_cairo_quartz_source_needs_extents (source)) |
|
1051 { |
|
1052 cairo_rectangle_int_t glyph_extents; |
|
1053 _cairo_scaled_font_glyph_device_extents (scaled_font, glyphs, num_glyphs, |
|
1054 &glyph_extents, NULL); |
|
1055 - action = _cairo_quartz_setup_source (surface, source, &glyph_extents); |
|
1056 + state = _cairo_quartz_setup_state (surface, source, op, &glyph_extents); |
|
1057 } else { |
|
1058 - action = _cairo_quartz_setup_source (surface, source, NULL); |
|
1059 + state = _cairo_quartz_setup_state (surface, source, op, NULL); |
|
1060 } |
|
1061 |
|
1062 - if (action == DO_SOLID || action == DO_PATTERN) { |
|
1063 - CGContextSetTextDrawingMode (surface->cgContext, kCGTextFill); |
|
1064 - } else if (action == DO_IMAGE || action == DO_TILED_IMAGE || action == DO_SHADING) { |
|
1065 - CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip); |
|
1066 + if (state.action == DO_SOLID || state.action == DO_PATTERN) { |
|
1067 + CGContextSetTextDrawingMode (state.context, kCGTextFill); |
|
1068 + } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || state.action == DO_SHADING) { |
|
1069 + CGContextSetTextDrawingMode (state.context, kCGTextClip); |
|
1070 isClipping = TRUE; |
|
1071 } else { |
|
1072 - if (action != DO_NOTHING) |
|
1073 + if (state.action != DO_NOTHING) |
|
1074 rv = CAIRO_INT_STATUS_UNSUPPORTED; |
|
1075 goto BAIL; |
|
1076 } |
|
1077 |
|
1078 /* this doesn't addref */ |
|
1079 cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font); |
|
1080 - CGContextSetFont (surface->cgContext, cgfref); |
|
1081 - CGContextSetFontSize (surface->cgContext, 1.0); |
|
1082 + CGContextSetFont (state.context, cgfref); |
|
1083 + CGContextSetFontSize (state.context, 1.0); |
|
1084 |
|
1085 switch (scaled_font->options.antialias) { |
|
1086 case CAIRO_ANTIALIAS_SUBPIXEL: |
|
1087 - CGContextSetShouldAntialias (surface->cgContext, TRUE); |
|
1088 - CGContextSetShouldSmoothFonts (surface->cgContext, TRUE); |
|
1089 + CGContextSetShouldAntialias (state.context, TRUE); |
|
1090 + CGContextSetShouldSmoothFonts (state.context, TRUE); |
|
1091 if (CGContextSetAllowsFontSmoothingPtr && |
|
1092 - !CGContextGetAllowsFontSmoothingPtr (surface->cgContext)) |
|
1093 + !CGContextGetAllowsFontSmoothingPtr (state.context)) |
|
1094 { |
|
1095 didForceFontSmoothing = TRUE; |
|
1096 - CGContextSetAllowsFontSmoothingPtr (surface->cgContext, TRUE); |
|
1097 + CGContextSetAllowsFontSmoothingPtr (state.context, TRUE); |
|
1098 } |
|
1099 break; |
|
1100 case CAIRO_ANTIALIAS_NONE: |
|
1101 - CGContextSetShouldAntialias (surface->cgContext, FALSE); |
|
1102 + CGContextSetShouldAntialias (state.context, FALSE); |
|
1103 break; |
|
1104 case CAIRO_ANTIALIAS_GRAY: |
|
1105 - CGContextSetShouldAntialias (surface->cgContext, TRUE); |
|
1106 - CGContextSetShouldSmoothFonts (surface->cgContext, FALSE); |
|
1107 + CGContextSetShouldAntialias (state.context, TRUE); |
|
1108 + CGContextSetShouldSmoothFonts (state.context, FALSE); |
|
1109 break; |
|
1110 case CAIRO_ANTIALIAS_DEFAULT: |
|
1111 /* Don't do anything */ |
|
1112 break; |
|
1113 } |
|
1114 |
|
1115 if (num_glyphs > STATIC_BUF_SIZE) { |
|
1116 cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof(CGGlyph)); |
|
1117 @@ -2532,17 +2565,17 @@ _cairo_quartz_surface_show_glyphs (void |
|
1118 textTransform = CGAffineTransformScale (textTransform, 1.0, -1.0); |
|
1119 textTransform = CGAffineTransformConcat (CGAffineTransformMake(scaled_font->ctm.xx, |
|
1120 -scaled_font->ctm.yx, |
|
1121 -scaled_font->ctm.xy, |
|
1122 scaled_font->ctm.yy, |
|
1123 0., 0.), |
|
1124 textTransform); |
|
1125 |
|
1126 - CGContextSetTextMatrix (surface->cgContext, textTransform); |
|
1127 + CGContextSetTextMatrix (state.context, textTransform); |
|
1128 |
|
1129 /* Convert our glyph positions to glyph advances. We need n-1 advances, |
|
1130 * since the advance at index 0 is applied after glyph 0. */ |
|
1131 xprev = glyphs[0].x; |
|
1132 yprev = glyphs[0].y; |
|
1133 |
|
1134 cg_glyphs[0] = glyphs[0].index; |
|
1135 |
|
1136 @@ -2569,40 +2602,38 @@ _cairo_quartz_surface_show_glyphs (void |
|
1137 |
|
1138 #if 0 |
|
1139 for (i = 0; i < num_glyphs; i++) { |
|
1140 ND((stderr, "[%d: %d %f,%f]\n", i, cg_glyphs[i], cg_advances[i].width, cg_advances[i].height)); |
|
1141 } |
|
1142 #endif |
|
1143 |
|
1144 /* Translate to the first glyph's position before drawing */ |
|
1145 - ctm = CGContextGetCTM (surface->cgContext); |
|
1146 - CGContextTranslateCTM (surface->cgContext, glyphs[0].x, glyphs[0].y); |
|
1147 - |
|
1148 - CGContextShowGlyphsWithAdvances (surface->cgContext, |
|
1149 + ctm = CGContextGetCTM (state.context); |
|
1150 + CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y); |
|
1151 + |
|
1152 + CGContextShowGlyphsWithAdvances (state.context, |
|
1153 cg_glyphs, |
|
1154 cg_advances, |
|
1155 num_glyphs); |
|
1156 |
|
1157 - CGContextSetCTM (surface->cgContext, ctm); |
|
1158 - |
|
1159 - if (action == DO_IMAGE || action == DO_TILED_IMAGE) { |
|
1160 - _cairo_quartz_draw_image (surface, op, action); |
|
1161 - } else if (action == DO_SHADING) { |
|
1162 - CGContextConcatCTM (surface->cgContext, surface->sourceTransform); |
|
1163 - CGContextDrawShading (surface->cgContext, surface->sourceShading); |
|
1164 + CGContextSetCTM (state.context, ctm); |
|
1165 + |
|
1166 + if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) { |
|
1167 + _cairo_quartz_draw_image (&state, op); |
|
1168 + } else if (state.action == DO_SHADING) { |
|
1169 + CGContextConcatCTM (state.context, state.transform); |
|
1170 + CGContextDrawShading (state.context, state.shading); |
|
1171 } |
|
1172 |
|
1173 BAIL: |
|
1174 - _cairo_quartz_teardown_source (surface, source); |
|
1175 - |
|
1176 if (didForceFontSmoothing) |
|
1177 - CGContextSetAllowsFontSmoothingPtr (surface->cgContext, FALSE); |
|
1178 - |
|
1179 - CGContextRestoreGState (surface->cgContext); |
|
1180 + CGContextSetAllowsFontSmoothingPtr (state.context, FALSE); |
|
1181 + |
|
1182 + _cairo_quartz_teardown_state (&state); |
|
1183 |
|
1184 if (rv == CAIRO_STATUS_SUCCESS && |
|
1185 cgfref && |
|
1186 !_cairo_operator_bounded_by_mask (op)) |
|
1187 { |
|
1188 unbounded_op_data_t ub; |
|
1189 ub.op = UNBOUNDED_SHOW_GLYPHS; |
|
1190 |