Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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;
8 void *imageData;
9 cairo_surface_t *imageSurfaceEquiv;
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;
29 typedef struct cairo_quartz_image_surface {
30 cairo_surface_t base;
32 cairo_rectangle_int_t extents;
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 }
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;
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;
85 cairo_surface_t *fallback;
86 CGImageRef img;
88 cairo_status_t status;
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 + }
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;
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
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 }
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;
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 }
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 }
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);
196 rgb = CGColorSpaceCreateDeviceRGB();
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));
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 }
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);
221 CGColorSpaceRelease(rgb);
222 CGFunctionRelease(gradFunc);
224 - return DO_SHADING;
225 + state->action = DO_SHADING;
226 }
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);
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 }
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 }
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);
279 rgb = CGColorSpaceCreateDeviceRGB();
281 start = CGPointMake (c1x, c1y);
282 end = CGPointMake (c2x, c2y);
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 }
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);
310 CGColorSpaceRelease(rgb);
311 CGFunctionRelease(gradFunc);
313 - return DO_SHADING;
314 + state->action = DO_SHADING;
315 }
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 + }
363 if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
364 cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
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);
379 - return DO_SOLID;
380 + state.action = DO_SOLID;
381 + return state;
382 }
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 }
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 }
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;
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 + }
426 CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1);
428 - surface->sourceImage = img;
429 + state.image = img;
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);
435 is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
436 assert (is_bounded);
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 }
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 */
453 - xform = CGAffineTransformConcat (CGContextGetCTM (surface->cgContext),
454 - surface->sourceTransform);
455 + xform = CGAffineTransformConcat (CGContextGetCTM (context),
456 + state.transform);
458 srcRect = CGRectMake (0, 0, extents.width, extents.height);
459 srcRect = CGRectApplyAffineTransform (srcRect, xform);
461 fw = _cairo_fixed_from_double (srcRect.size.width);
462 fh = _cairo_fixed_from_double (srcRect.size.height);
464 if ((fw & CAIRO_FIXED_FRAC_MASK) <= CAIRO_FIXED_EPSILON &&
465 @@ -1657,111 +1724,109 @@ _cairo_quartz_setup_source (cairo_quartz
467 srcRect.size.width = round(srcRect.size.width);
468 srcRect.size.height = round(srcRect.size.height);
470 xform = CGAffineTransformInvert (xform);
472 srcRect = CGRectApplyAffineTransform (srcRect, xform);
474 - surface->sourceImageRect = srcRect;
475 -
476 - return DO_TILED_IMAGE;
477 + state.imageRect = srcRect;
478 + state.action = DO_TILED_IMAGE;
479 + return state;
480 }
482 /* Fall through to generic SURFACE case */
483 }
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;
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);
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 }
539 - return DO_UNSUPPORTED;
540 + state.action = DO_UNSUPPORTED;
541 + return state;
542 }
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 }
565 - if (surface->sourceShading) {
566 - CGShadingRelease(surface->sourceShading);
567 - surface->sourceShading = NULL;
568 + if (state->imageSurface) {
569 + cairo_surface_destroy(state->imageSurface);
570 }
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 }
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 }
629 /*
630 * get source/dest image implementation
631 */
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;
646 ND((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
648 if (IS_EMPTY(surface))
649 return CAIRO_STATUS_SUCCESS;
651 rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
652 if (unlikely (rv))
653 return rv;
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 }
692 - _cairo_quartz_teardown_source (surface, source);
693 + _cairo_quartz_teardown_state (&state);
695 ND((stderr, "-- paint\n"));
696 return rv;
697 }
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;
716 ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
718 if (IS_EMPTY(surface))
719 return CAIRO_STATUS_SUCCESS;
721 rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
722 if (unlikely (rv))
723 return rv;
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 }
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;
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) {
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 }
807 BAIL:
808 - _cairo_quartz_teardown_source (surface, source);
809 -
810 - CGContextRestoreGState (surface->cgContext);
811 + _cairo_quartz_teardown_state (&state);
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;
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;
835 ND((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type));
837 if (IS_EMPTY(surface))
838 return CAIRO_STATUS_SUCCESS;
840 rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
841 if (unlikely (rv))
842 return rv;
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 + }
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);
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);
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);
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;
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 }
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);
1009 ND((stderr, "-- stroke\n"));
1010 return rv;
1011 }
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];
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;
1031 cairo_bool_t isClipping = FALSE;
1032 cairo_bool_t didForceFontSmoothing = FALSE;
1034 if (IS_EMPTY(surface))
1035 @@ -2450,65 +2489,59 @@ _cairo_quartz_surface_show_glyphs (void
1037 if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ)
1038 return CAIRO_INT_STATUS_UNSUPPORTED;
1040 rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
1041 if (unlikely (rv))
1042 return rv;
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 }
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 }
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);
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 }
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);
1126 - CGContextSetTextMatrix (surface->cgContext, textTransform);
1127 + CGContextSetTextMatrix (state.context, textTransform);
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;
1134 cg_glyphs[0] = glyphs[0].index;
1136 @@ -2569,40 +2602,38 @@ _cairo_quartz_surface_show_glyphs (void
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
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);
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 }
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);
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;