Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2002 University of Southern California
5
 * Copyright © 2005 Red Hat, Inc.
6
 * Copyright © 2011 Intel Corporation
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it either under the terms of the GNU Lesser General Public
10
 * License version 2.1 as published by the Free Software Foundation
11
 * (the "LGPL") or, at your option, under the terms of the Mozilla
12
 * Public License Version 1.1 (the "MPL"). If you do not alter this
13
 * notice, a recipient may use your version of this file under either
14
 * the MPL or the LGPL.
15
 *
16
 * You should have received a copy of the LGPL along with this library
17
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19
 * You should have received a copy of the MPL along with this library
20
 * in the file COPYING-MPL-1.1
21
 *
22
 * The contents of this file are subject to the Mozilla Public License
23
 * Version 1.1 (the "License"); you may not use this file except in
24
 * compliance with the License. You may obtain a copy of the License at
25
 * http://www.mozilla.org/MPL/
26
 *
27
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29
 * the specific language governing rights and limitations.
30
 *
31
 * The Original Code is the cairo graphics library.
32
 *
33
 * The Initial Developer of the Original Code is University of Southern
34
 * California.
35
 *
36
 * Contributor(s):
37
 *	Carl D. Worth 
38
 *      Joonas Pihlaja 
39
 *	Chris Wilson 
40
 */
41
 
42
#include "cairoint.h"
43
 
44
#include "cairo-compositor-private.h"
45
#include "cairo-clip-inline.h"
46
#include "cairo-clip-private.h"
47
#include "cairo-image-surface-private.h"
48
#include "cairo-paginated-private.h"
49
#include "cairo-pattern-inline.h"
50
#include "cairo-region-private.h"
51
#include "cairo-recording-surface-inline.h"
52
#include "cairo-spans-compositor-private.h"
53
#include "cairo-surface-subsurface-private.h"
54
#include "cairo-surface-snapshot-private.h"
55
#include "cairo-surface-observer-private.h"
56
 
57
typedef struct {
58
    cairo_polygon_t	*polygon;
59
    cairo_fill_rule_t	 fill_rule;
60
    cairo_antialias_t	 antialias;
61
} composite_spans_info_t;
62
 
63
static cairo_int_status_t
64
composite_polygon (const cairo_spans_compositor_t	*compositor,
65
		   cairo_composite_rectangles_t		 *extents,
66
		   cairo_polygon_t			*polygon,
67
		   cairo_fill_rule_t			 fill_rule,
68
		   cairo_antialias_t			 antialias);
69
 
70
static cairo_int_status_t
71
composite_boxes (const cairo_spans_compositor_t *compositor,
72
		 cairo_composite_rectangles_t *extents,
73
		 cairo_boxes_t		*boxes);
74
 
75
static cairo_int_status_t
76
clip_and_composite_polygon (const cairo_spans_compositor_t	*compositor,
77
			    cairo_composite_rectangles_t	 *extents,
78
			    cairo_polygon_t			*polygon,
79
			    cairo_fill_rule_t			 fill_rule,
80
			    cairo_antialias_t			 antialias);
81
static cairo_surface_t *
82
get_clip_surface (const cairo_spans_compositor_t *compositor,
83
		  cairo_surface_t *dst,
84
		  const cairo_clip_t *clip,
85
		  const cairo_rectangle_int_t *extents)
86
{
87
    cairo_composite_rectangles_t composite;
88
    cairo_surface_t *surface;
89
    cairo_box_t box;
90
    cairo_polygon_t polygon;
91
    const cairo_clip_path_t *clip_path;
92
    cairo_antialias_t antialias;
93
    cairo_fill_rule_t fill_rule;
94
    cairo_int_status_t status;
95
 
96
    assert (clip->path);
97
 
98
    surface = _cairo_surface_create_similar_solid (dst,
99
						   CAIRO_CONTENT_ALPHA,
100
						   extents->width,
101
						   extents->height,
102
						   CAIRO_COLOR_TRANSPARENT);
103
 
104
    _cairo_box_from_rectangle (&box, extents);
105
    _cairo_polygon_init (&polygon, &box, 1);
106
 
107
    clip_path = clip->path;
108
    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
109
						clip_path->tolerance,
110
						&polygon);
111
    if (unlikely (status))
112
	goto cleanup_polygon;
113
 
114
    polygon.num_limits = 0;
115
 
116
    antialias = clip_path->antialias;
117
    fill_rule = clip_path->fill_rule;
118
 
119
    if (clip->boxes) {
120
	cairo_polygon_t intersect;
121
	cairo_boxes_t tmp;
122
 
123
	_cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes);
124
	status= _cairo_polygon_init_boxes (&intersect, &tmp);
125
	if (unlikely (status))
126
	    goto cleanup_polygon;
127
 
128
	status = _cairo_polygon_intersect (&polygon, fill_rule,
129
					   &intersect, CAIRO_FILL_RULE_WINDING);
130
	_cairo_polygon_fini (&intersect);
131
 
132
	if (unlikely (status))
133
	    goto cleanup_polygon;
134
 
135
	fill_rule = CAIRO_FILL_RULE_WINDING;
136
    }
137
 
138
    polygon.limits = NULL;
139
    polygon.num_limits = 0;
140
 
141
    clip_path = clip_path->prev;
142
    while (clip_path) {
143
	if (clip_path->antialias == antialias) {
144
	    cairo_polygon_t next;
145
 
146
	    _cairo_polygon_init (&next, NULL, 0);
147
	    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
148
							clip_path->tolerance,
149
							&next);
150
	    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
151
		status = _cairo_polygon_intersect (&polygon, fill_rule,
152
						   &next, clip_path->fill_rule);
153
	    _cairo_polygon_fini (&next);
154
	    if (unlikely (status))
155
		goto cleanup_polygon;
156
 
157
	    fill_rule = CAIRO_FILL_RULE_WINDING;
158
	}
159
 
160
	clip_path = clip_path->prev;
161
    }
162
 
163
    _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
164
    status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
165
							   CAIRO_OPERATOR_ADD,
166
							   &_cairo_pattern_white.base,
167
							   &polygon,
168
							   NULL);
169
    if (unlikely (status))
170
	goto cleanup_polygon;
171
 
172
    status = composite_polygon (compositor, &composite,
173
				&polygon, fill_rule, antialias);
174
    _cairo_composite_rectangles_fini (&composite);
175
    _cairo_polygon_fini (&polygon);
176
    if (unlikely (status))
177
	goto error;
178
 
179
    _cairo_polygon_init (&polygon, &box, 1);
180
 
181
    clip_path = clip->path;
182
    antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT;
183
    clip_path = clip_path->prev;
184
    while (clip_path) {
185
	if (clip_path->antialias == antialias) {
186
	    if (polygon.num_edges == 0) {
187
		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
188
							    clip_path->tolerance,
189
							    &polygon);
190
 
191
		fill_rule = clip_path->fill_rule;
192
		polygon.limits = NULL;
193
		polygon.num_limits = 0;
194
	    } else {
195
		cairo_polygon_t next;
196
 
197
		_cairo_polygon_init (&next, NULL, 0);
198
		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
199
							    clip_path->tolerance,
200
							    &next);
201
		if (likely (status == CAIRO_INT_STATUS_SUCCESS))
202
		    status = _cairo_polygon_intersect (&polygon, fill_rule,
203
						       &next, clip_path->fill_rule);
204
		_cairo_polygon_fini (&next);
205
		fill_rule = CAIRO_FILL_RULE_WINDING;
206
	    }
207
	    if (unlikely (status))
208
		goto error;
209
	}
210
 
211
	clip_path = clip_path->prev;
212
    }
213
 
214
    if (polygon.num_edges) {
215
	_cairo_polygon_translate (&polygon, -extents->x, -extents->y);
216
	status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
217
							       CAIRO_OPERATOR_IN,
218
							       &_cairo_pattern_white.base,
219
							       &polygon,
220
							       NULL);
221
	if (unlikely (status))
222
	    goto cleanup_polygon;
223
 
224
	status = composite_polygon (compositor, &composite,
225
				    &polygon, fill_rule, antialias);
226
	_cairo_composite_rectangles_fini (&composite);
227
	_cairo_polygon_fini (&polygon);
228
	if (unlikely (status))
229
	    goto error;
230
    }
231
 
232
    return surface;
233
 
234
cleanup_polygon:
235
    _cairo_polygon_fini (&polygon);
236
error:
237
    cairo_surface_destroy (surface);
238
    return _cairo_int_surface_create_in_error (status);
239
}
240
 
241
static cairo_int_status_t
242
fixup_unbounded_mask (const cairo_spans_compositor_t *compositor,
243
		      const cairo_composite_rectangles_t *extents,
244
		      cairo_boxes_t *boxes)
245
{
246
    cairo_composite_rectangles_t composite;
247
    cairo_surface_t *clip;
248
    cairo_int_status_t status;
249
 
250
    TRACE((stderr, "%s\n", __FUNCTION__));
251
 
252
    clip = get_clip_surface (compositor, extents->surface, extents->clip,
253
			     &extents->unbounded);
254
    if (unlikely (clip->status)) {
255
	if ((cairo_int_status_t)clip->status == CAIRO_INT_STATUS_NOTHING_TO_DO)
256
	    return CAIRO_STATUS_SUCCESS;
257
 
258
	return clip->status;
259
    }
260
 
261
    status = _cairo_composite_rectangles_init_for_boxes (&composite,
262
							 extents->surface,
263
							 CAIRO_OPERATOR_CLEAR,
264
							 &_cairo_pattern_clear.base,
265
							 boxes,
266
							 NULL);
267
    if (unlikely (status))
268
	goto cleanup_clip;
269
 
270
    _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip);
271
    composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
272
    composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE;
273
 
274
    status = composite_boxes (compositor, &composite, boxes);
275
 
276
    _cairo_pattern_fini (&composite.mask_pattern.base);
277
    _cairo_composite_rectangles_fini (&composite);
278
 
279
cleanup_clip:
280
    cairo_surface_destroy (clip);
281
    return status;
282
}
283
 
284
static cairo_int_status_t
285
fixup_unbounded_polygon (const cairo_spans_compositor_t *compositor,
286
			 const cairo_composite_rectangles_t *extents,
287
			 cairo_boxes_t *boxes)
288
{
289
    cairo_polygon_t polygon, intersect;
290
    cairo_composite_rectangles_t composite;
291
    cairo_fill_rule_t fill_rule;
292
    cairo_antialias_t antialias;
293
    cairo_int_status_t status;
294
 
295
    TRACE((stderr, "%s\n", __FUNCTION__));
296
 
297
    /* Can we treat the clip as a regular clear-polygon and use it to fill? */
298
    status = _cairo_clip_get_polygon (extents->clip, &polygon,
299
				      &fill_rule, &antialias);
300
    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
301
	return status;
302
 
303
    status= _cairo_polygon_init_boxes (&intersect, boxes);
304
    if (unlikely (status))
305
	goto cleanup_polygon;
306
 
307
    status = _cairo_polygon_intersect (&polygon, fill_rule,
308
				       &intersect, CAIRO_FILL_RULE_WINDING);
309
    _cairo_polygon_fini (&intersect);
310
 
311
    if (unlikely (status))
312
	goto cleanup_polygon;
313
 
314
    status = _cairo_composite_rectangles_init_for_polygon (&composite,
315
							   extents->surface,
316
							   CAIRO_OPERATOR_CLEAR,
317
							   &_cairo_pattern_clear.base,
318
							   &polygon,
319
							   NULL);
320
    if (unlikely (status))
321
	goto cleanup_polygon;
322
 
323
    status = composite_polygon (compositor, &composite,
324
				&polygon, fill_rule, antialias);
325
 
326
    _cairo_composite_rectangles_fini (&composite);
327
cleanup_polygon:
328
    _cairo_polygon_fini (&polygon);
329
 
330
    return status;
331
}
332
 
333
static cairo_int_status_t
334
fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor,
335
		       const cairo_composite_rectangles_t *extents,
336
		       cairo_boxes_t *boxes)
337
{
338
    cairo_boxes_t tmp, clear;
339
    cairo_box_t box;
340
    cairo_int_status_t status;
341
 
342
    assert (boxes->is_pixel_aligned);
343
 
344
    TRACE ((stderr, "%s\n", __FUNCTION__));
345
    if (extents->bounded.width  == extents->unbounded.width &&
346
	extents->bounded.height == extents->unbounded.height)
347
    {
348
	return CAIRO_STATUS_SUCCESS;
349
    }
350
 
351
    /* subtract the drawn boxes from the unbounded area */
352
    _cairo_boxes_init (&clear);
353
 
354
    box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
355
    box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
356
    box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
357
    box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
358
 
359
    if (boxes->num_boxes) {
360
	_cairo_boxes_init (&tmp);
361
 
362
	status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
363
	assert (status == CAIRO_INT_STATUS_SUCCESS);
364
 
365
	tmp.chunks.next = &boxes->chunks;
366
	tmp.num_boxes += boxes->num_boxes;
367
 
368
	status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
369
							  CAIRO_FILL_RULE_WINDING,
370
							  &clear);
371
	tmp.chunks.next = NULL;
372
	if (unlikely (status))
373
	    goto error;
374
    } else {
375
	box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
376
	box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
377
 
378
	status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
379
	assert (status == CAIRO_INT_STATUS_SUCCESS);
380
    }
381
 
382
    /* If we have a clip polygon, we need to intersect with that as well */
383
    if (extents->clip->path) {
384
	status = fixup_unbounded_polygon (compositor, extents, &clear);
385
	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
386
	    status = fixup_unbounded_mask (compositor, extents, &clear);
387
    } else {
388
	/* Otherwise just intersect with the clip boxes */
389
	if (extents->clip->num_boxes) {
390
	    _cairo_boxes_init_for_array (&tmp,
391
					 extents->clip->boxes,
392
					 extents->clip->num_boxes);
393
	    status = _cairo_boxes_intersect (&clear, &tmp, &clear);
394
	    if (unlikely (status))
395
		goto error;
396
	}
397
 
398
	if (clear.is_pixel_aligned) {
399
	    status = compositor->fill_boxes (extents->surface,
400
					     CAIRO_OPERATOR_CLEAR,
401
					     CAIRO_COLOR_TRANSPARENT,
402
					     &clear);
403
	} else {
404
	    cairo_composite_rectangles_t composite;
405
 
406
	    status = _cairo_composite_rectangles_init_for_boxes (&composite,
407
								 extents->surface,
408
								 CAIRO_OPERATOR_CLEAR,
409
								 &_cairo_pattern_clear.base,
410
								 &clear,
411
								 NULL);
412
	    if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
413
		status = composite_boxes (compositor, &composite, &clear);
414
		_cairo_composite_rectangles_fini (&composite);
415
	    }
416
	}
417
    }
418
 
419
error:
420
    _cairo_boxes_fini (&clear);
421
    return status;
422
}
423
 
424
static cairo_surface_t *
425
unwrap_source (const cairo_pattern_t *pattern)
426
{
427
    cairo_rectangle_int_t limit;
428
 
429
    return _cairo_pattern_get_source ((cairo_surface_pattern_t *)pattern,
430
				      &limit);
431
}
432
 
433
static cairo_bool_t
434
is_recording_pattern (const cairo_pattern_t *pattern)
435
{
436
    cairo_surface_t *surface;
437
 
438
    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
439
	return FALSE;
440
 
441
    surface = ((const cairo_surface_pattern_t *) pattern)->surface;
442
    return _cairo_surface_is_recording (surface);
443
}
444
 
445
static cairo_bool_t
446
recording_pattern_contains_sample (const cairo_pattern_t *pattern,
447
				   const cairo_rectangle_int_t *sample)
448
{
449
    cairo_recording_surface_t *surface;
450
 
451
    if (! is_recording_pattern (pattern))
452
	return FALSE;
453
 
454
    if (pattern->extend == CAIRO_EXTEND_NONE)
455
	return TRUE;
456
 
457
    surface = (cairo_recording_surface_t *) unwrap_source (pattern);
458
    if (surface->unbounded)
459
	return TRUE;
460
 
461
    return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
462
}
463
 
464
static cairo_bool_t
465
op_reduces_to_source (const cairo_composite_rectangles_t *extents,
466
		      cairo_bool_t no_mask)
467
{
468
    if (extents->op == CAIRO_OPERATOR_SOURCE)
469
	return TRUE;
470
 
471
    if (extents->surface->is_clear)
472
	return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
473
 
474
    if (no_mask && extents->op == CAIRO_OPERATOR_OVER)
475
	return _cairo_pattern_is_opaque (&extents->source_pattern.base,
476
					 &extents->source_sample_area);
477
 
478
    return FALSE;
479
}
480
 
481
static cairo_status_t
482
upload_boxes (const cairo_spans_compositor_t *compositor,
483
	      const cairo_composite_rectangles_t *extents,
484
	      cairo_boxes_t *boxes)
485
{
486
    cairo_surface_t *dst = extents->surface;
487
    const cairo_surface_pattern_t *source = &extents->source_pattern.surface;
488
    cairo_surface_t *src;
489
    cairo_rectangle_int_t limit;
490
    cairo_int_status_t status;
491
    int tx, ty;
492
 
493
    TRACE ((stderr, "%s\n", __FUNCTION__));
494
 
495
    src = _cairo_pattern_get_source(source, &limit);
496
    if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
497
	return CAIRO_INT_STATUS_UNSUPPORTED;
498
 
499
    if (! _cairo_matrix_is_integer_translation (&source->base.matrix, &tx, &ty))
500
	return CAIRO_INT_STATUS_UNSUPPORTED;
501
 
502
    /* Check that the data is entirely within the image */
503
    if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
504
	return CAIRO_INT_STATUS_UNSUPPORTED;
505
 
506
    if (extents->bounded.x + extents->bounded.width  + tx > limit.x + limit.width ||
507
	extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
508
	return CAIRO_INT_STATUS_UNSUPPORTED;
509
 
510
    tx += limit.x;
511
    ty += limit.y;
512
 
513
    if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
514
	status = compositor->draw_image_boxes (dst,
515
					       (cairo_image_surface_t *)src,
516
					       boxes, tx, ty);
517
    else
518
	status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
519
					 tx, ty);
520
 
521
    return status;
522
}
523
 
524
static cairo_bool_t
525
_clip_is_region (const cairo_clip_t *clip)
526
{
527
    int i;
528
 
529
    if (clip->is_region)
530
	return TRUE;
531
 
532
    if (clip->path)
533
	return FALSE;
534
 
535
    for (i = 0; i < clip->num_boxes; i++) {
536
	const cairo_box_t *b = &clip->boxes[i];
537
	if (!_cairo_fixed_is_integer (b->p1.x | b->p1.y |  b->p2.x | b->p2.y))
538
	    return FALSE;
539
    }
540
 
541
    return TRUE;
542
}
543
 
544
static cairo_int_status_t
545
composite_aligned_boxes (const cairo_spans_compositor_t		*compositor,
546
			 const cairo_composite_rectangles_t	*extents,
547
			 cairo_boxes_t				*boxes)
548
{
549
    cairo_surface_t *dst = extents->surface;
550
    cairo_operator_t op = extents->op;
551
    const cairo_pattern_t *source = &extents->source_pattern.base;
552
    cairo_int_status_t status;
553
    cairo_bool_t need_clip_mask = ! _clip_is_region (extents->clip);
554
    cairo_bool_t op_is_source;
555
    cairo_bool_t no_mask;
556
    cairo_bool_t inplace;
557
 
558
    TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n",
559
	    __FUNCTION__, need_clip_mask, extents->is_bounded));
560
    if (need_clip_mask && ! extents->is_bounded) {
561
	TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
562
	return CAIRO_INT_STATUS_UNSUPPORTED;
563
    }
564
 
565
    no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
566
	CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color);
567
    op_is_source = op_reduces_to_source (extents, no_mask);
568
    inplace = ! need_clip_mask && op_is_source && no_mask;
569
 
570
    TRACE ((stderr, "%s: op-is-source=%d [op=%d], no-mask=%d, inplace=%d\n",
571
	    __FUNCTION__, op_is_source, op, no_mask, inplace));
572
 
573
    if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
574
	/* SOURCE with a mask is actually a LERP in cairo semantics */
575
	if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0) {
576
	    TRACE ((stderr, "%s: unsupported lerp\n", __FUNCTION__));
577
	    return CAIRO_INT_STATUS_UNSUPPORTED;
578
	}
579
    }
580
 
581
    /* Are we just copying a recording surface? */
582
    if (inplace &&
583
	recording_pattern_contains_sample (&extents->source_pattern.base,
584
					   &extents->source_sample_area))
585
    {
586
	cairo_clip_t *recording_clip;
587
	const cairo_pattern_t *source = &extents->source_pattern.base;
588
 
589
	/* XXX could also do tiling repeat modes... */
590
 
591
	/* first clear the area about to be overwritten */
592
	if (! dst->is_clear) {
593
	    status = compositor->fill_boxes (dst,
594
					     CAIRO_OPERATOR_CLEAR,
595
					     CAIRO_COLOR_TRANSPARENT,
596
					     boxes);
597
	    if (unlikely (status))
598
		return status;
599
 
600
	    dst->is_clear = TRUE;
601
	}
602
 
603
	recording_clip = _cairo_clip_from_boxes (boxes);
604
	status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
605
							    &source->matrix,
606
							    dst, recording_clip);
607
	_cairo_clip_destroy (recording_clip);
608
 
609
	return status;
610
    }
611
 
612
    status = CAIRO_INT_STATUS_UNSUPPORTED;
613
    if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
614
	const cairo_color_t *color;
615
 
616
	color = &((cairo_solid_pattern_t *) source)->color;
617
	if (op_is_source)
618
	    op = CAIRO_OPERATOR_SOURCE;
619
	status = compositor->fill_boxes (dst, op, color, boxes);
620
    } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
621
	status = upload_boxes (compositor, extents, boxes);
622
    }
623
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
624
	cairo_surface_t *src;
625
	cairo_surface_t *mask = NULL;
626
	int src_x, src_y;
627
	int mask_x = 0, mask_y = 0;
628
 
629
	/* All typical cases will have been resolved before now... */
630
	if (need_clip_mask) {
631
	    mask = get_clip_surface (compositor, dst, extents->clip,
632
				     &extents->bounded);
633
	    if (unlikely (mask->status))
634
		return mask->status;
635
 
636
	    mask_x = -extents->bounded.x;
637
	    mask_y = -extents->bounded.y;
638
	}
639
 
640
	/* XXX but this is still ugly */
641
	if (! no_mask) {
642
	    src = compositor->pattern_to_surface (dst,
643
						  &extents->mask_pattern.base,
644
						  TRUE,
645
						  &extents->bounded,
646
						  &extents->mask_sample_area,
647
						  &src_x, &src_y);
648
	    if (unlikely (src->status)) {
649
		cairo_surface_destroy (mask);
650
		return src->status;
651
	    }
652
 
653
	    if (mask != NULL) {
654
		status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN,
655
						      src, NULL,
656
						      src_x, src_y,
657
						      0, 0,
658
						      mask_x, mask_y,
659
						      boxes, &extents->bounded);
660
 
661
		cairo_surface_destroy (src);
662
	    } else {
663
		mask = src;
664
		mask_x = src_x;
665
		mask_y = src_y;
666
	    }
667
	}
668
 
669
	src = compositor->pattern_to_surface (dst, source, FALSE,
670
					      &extents->bounded,
671
					      &extents->source_sample_area,
672
					      &src_x, &src_y);
673
	if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
674
	    status = compositor->composite_boxes (dst, op, src, mask,
675
						  src_x, src_y,
676
						  mask_x, mask_y,
677
						  0, 0,
678
						  boxes, &extents->bounded);
679
	    cairo_surface_destroy (src);
680
	} else
681
	    status = src->status;
682
 
683
	cairo_surface_destroy (mask);
684
    }
685
 
686
    if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded)
687
	status = fixup_unbounded_boxes (compositor, extents, boxes);
688
 
689
    return status;
690
}
691
 
692
static cairo_bool_t
693
composite_needs_clip (const cairo_composite_rectangles_t *composite,
694
		      const cairo_box_t *extents)
695
{
696
    return !_cairo_clip_contains_box (composite->clip, extents);
697
}
698
 
699
static cairo_int_status_t
700
composite_boxes (const cairo_spans_compositor_t *compositor,
701
		 cairo_composite_rectangles_t *extents,
702
		 cairo_boxes_t		*boxes)
703
{
704
    cairo_abstract_span_renderer_t renderer;
705
    cairo_rectangular_scan_converter_t converter;
706
    const struct _cairo_boxes_chunk *chunk;
707
    cairo_int_status_t status;
708
    cairo_box_t box;
709
 
710
    TRACE ((stderr, "%s\n", __FUNCTION__));
711
    _cairo_box_from_rectangle (&box, &extents->unbounded);
712
    if (composite_needs_clip (extents, &box)) {
713
	TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
714
	return CAIRO_INT_STATUS_UNSUPPORTED;
715
    }
716
 
717
    _cairo_rectangular_scan_converter_init (&converter, &extents->unbounded);
718
    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
719
	const cairo_box_t *box = chunk->base;
720
	int i;
721
 
722
	for (i = 0; i < chunk->count; i++) {
723
	    status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
724
	    if (unlikely (status))
725
		goto cleanup_converter;
726
	}
727
    }
728
 
729
    status = compositor->renderer_init (&renderer, extents,
730
					CAIRO_ANTIALIAS_DEFAULT, FALSE);
731
    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
732
	status = converter.base.generate (&converter.base, &renderer.base);
733
    compositor->renderer_fini (&renderer, status);
734
 
735
cleanup_converter:
736
    converter.base.destroy (&converter.base);
737
    return status;
738
}
739
 
740
static cairo_int_status_t
741
composite_polygon (const cairo_spans_compositor_t	*compositor,
742
		   cairo_composite_rectangles_t		 *extents,
743
		   cairo_polygon_t			*polygon,
744
		   cairo_fill_rule_t			 fill_rule,
745
		   cairo_antialias_t			 antialias)
746
{
747
    cairo_abstract_span_renderer_t renderer;
748
    cairo_scan_converter_t *converter;
749
    cairo_bool_t needs_clip;
750
    cairo_int_status_t status;
751
 
752
    if (extents->is_bounded)
753
	needs_clip = extents->clip->path != NULL;
754
    else
755
	needs_clip = !_clip_is_region (extents->clip) || extents->clip->num_boxes > 1;
756
    TRACE ((stderr, "%s - needs_clip=%d\n", __FUNCTION__, needs_clip));
757
    if (needs_clip) {
758
	TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
759
	return CAIRO_INT_STATUS_UNSUPPORTED;
760
	converter = _cairo_clip_tor_scan_converter_create (extents->clip,
761
							   polygon,
762
							   fill_rule, antialias);
763
    } else {
764
	const cairo_rectangle_int_t *r = &extents->unbounded;
765
 
766
	if (antialias == CAIRO_ANTIALIAS_FAST) {
767
	    converter = _cairo_tor22_scan_converter_create (r->x, r->y,
768
							    r->x + r->width,
769
							    r->y + r->height,
770
							    fill_rule, antialias);
771
	    status = _cairo_tor22_scan_converter_add_polygon (converter, polygon);
772
	} else if (antialias == CAIRO_ANTIALIAS_NONE) {
773
	    converter = _cairo_mono_scan_converter_create (r->x, r->y,
774
							   r->x + r->width,
775
							   r->y + r->height,
776
							   fill_rule);
777
	    status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
778
	} else {
779
	    converter = _cairo_tor_scan_converter_create (r->x, r->y,
780
							  r->x + r->width,
781
							  r->y + r->height,
782
							  fill_rule, antialias);
783
	    status = _cairo_tor_scan_converter_add_polygon (converter, polygon);
784
	}
785
    }
786
    if (unlikely (status))
787
	goto cleanup_converter;
788
 
789
    status = compositor->renderer_init (&renderer, extents,
790
					antialias, needs_clip);
791
    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
792
	status = converter->generate (converter, &renderer.base);
793
    compositor->renderer_fini (&renderer, status);
794
 
795
cleanup_converter:
796
    converter->destroy (converter);
797
    return status;
798
}
799
 
800
static cairo_int_status_t
801
trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
802
		       cairo_boxes_t *boxes)
803
{
804
    cairo_box_t box;
805
 
806
    _cairo_boxes_extents (boxes, &box);
807
    return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
808
}
809
 
810
static cairo_int_status_t
811
trim_extents_to_polygon (cairo_composite_rectangles_t *extents,
812
			 cairo_polygon_t *polygon)
813
{
814
    return _cairo_composite_rectangles_intersect_mask_extents (extents,
815
							       &polygon->extents);
816
}
817
 
818
static cairo_int_status_t
819
clip_and_composite_boxes (const cairo_spans_compositor_t	*compositor,
820
			  cairo_composite_rectangles_t		*extents,
821
			  cairo_boxes_t				*boxes)
822
{
823
    cairo_int_status_t status;
824
    cairo_polygon_t polygon;
825
 
826
    TRACE ((stderr, "%s\n", __FUNCTION__));
827
    status = trim_extents_to_boxes (extents, boxes);
828
    if (unlikely (status))
829
	return status;
830
 
831
    if (boxes->num_boxes == 0) {
832
	if (extents->is_bounded)
833
	    return CAIRO_STATUS_SUCCESS;
834
 
835
	return fixup_unbounded_boxes (compositor, extents, boxes);
836
    }
837
 
838
    /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
839
    if (extents->clip->path != NULL && extents->is_bounded) {
840
	cairo_polygon_t polygon;
841
	cairo_fill_rule_t fill_rule;
842
	cairo_antialias_t antialias;
843
	cairo_clip_t *clip;
844
 
845
	clip = _cairo_clip_copy (extents->clip);
846
	clip = _cairo_clip_intersect_boxes (clip, boxes);
847
	if (_cairo_clip_is_all_clipped (clip))
848
	    return CAIRO_INT_STATUS_NOTHING_TO_DO;
849
 
850
	status = _cairo_clip_get_polygon (clip, &polygon,
851
					  &fill_rule, &antialias);
852
	_cairo_clip_path_destroy (clip->path);
853
	clip->path = NULL;
854
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
855
	    cairo_clip_t *saved_clip = extents->clip;
856
	    extents->clip = clip;
857
 
858
	    status = clip_and_composite_polygon (compositor, extents, &polygon,
859
						 fill_rule, antialias);
860
 
861
	    clip = extents->clip;
862
	    extents->clip = saved_clip;
863
 
864
	    _cairo_polygon_fini (&polygon);
865
	}
866
	_cairo_clip_destroy (clip);
867
 
868
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
869
	    return status;
870
    }
871
 
872
    if (boxes->is_pixel_aligned) {
873
	status = composite_aligned_boxes (compositor, extents, boxes);
874
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
875
	    return status;
876
    }
877
 
878
    status = composite_boxes (compositor, extents, boxes);
879
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
880
	return status;
881
 
882
    status = _cairo_polygon_init_boxes (&polygon, boxes);
883
    if (unlikely (status))
884
	return status;
885
 
886
    status = composite_polygon (compositor, extents, &polygon,
887
				CAIRO_FILL_RULE_WINDING,
888
				CAIRO_ANTIALIAS_DEFAULT);
889
    _cairo_polygon_fini (&polygon);
890
 
891
    return status;
892
}
893
 
894
static cairo_int_status_t
895
clip_and_composite_polygon (const cairo_spans_compositor_t	*compositor,
896
			    cairo_composite_rectangles_t	 *extents,
897
			    cairo_polygon_t			*polygon,
898
			    cairo_fill_rule_t			 fill_rule,
899
			    cairo_antialias_t			 antialias)
900
{
901
    cairo_int_status_t status;
902
 
903
    TRACE ((stderr, "%s\n", __FUNCTION__));
904
 
905
    /* XXX simply uses polygon limits.point extemities, tessellation? */
906
    status = trim_extents_to_polygon (extents, polygon);
907
    if (unlikely (status))
908
	return status;
909
 
910
    if (_cairo_polygon_is_empty (polygon)) {
911
	cairo_boxes_t boxes;
912
 
913
	if (extents->is_bounded)
914
	    return CAIRO_STATUS_SUCCESS;
915
 
916
	_cairo_boxes_init (&boxes);
917
	extents->bounded.width = extents->bounded.height = 0;
918
	return fixup_unbounded_boxes (compositor, extents, &boxes);
919
    }
920
 
921
    if (extents->is_bounded && extents->clip->path) {
922
	cairo_polygon_t clipper;
923
	cairo_antialias_t clip_antialias;
924
	cairo_fill_rule_t clip_fill_rule;
925
 
926
	TRACE((stderr, "%s - combining shape with clip polygon\n",
927
	       __FUNCTION__));
928
 
929
	status = _cairo_clip_get_polygon (extents->clip,
930
					  &clipper,
931
					  &clip_fill_rule,
932
					  &clip_antialias);
933
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
934
	    cairo_clip_t *old_clip;
935
 
936
	    if (clip_antialias == antialias) {
937
		status = _cairo_polygon_intersect (polygon, fill_rule,
938
						   &clipper, clip_fill_rule);
939
		_cairo_polygon_fini (&clipper);
940
		if (unlikely (status))
941
		    return status;
942
 
943
		old_clip = extents->clip;
944
		extents->clip = _cairo_clip_copy_region (extents->clip);
945
		_cairo_clip_destroy (old_clip);
946
 
947
		status = trim_extents_to_polygon (extents, polygon);
948
		if (unlikely (status))
949
		    return status;
950
 
951
		fill_rule = CAIRO_FILL_RULE_WINDING;
952
	    } else {
953
		_cairo_polygon_fini (&clipper);
954
	    }
955
	}
956
    }
957
 
958
    return composite_polygon (compositor, extents,
959
			      polygon, fill_rule, antialias);
960
}
961
 
962
/* high-level compositor interface */
963
 
964
static cairo_int_status_t
965
_cairo_spans_compositor_paint (const cairo_compositor_t		*_compositor,
966
			       cairo_composite_rectangles_t	*extents)
967
{
968
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
969
    cairo_boxes_t boxes;
970
    cairo_int_status_t status;
971
 
972
    TRACE ((stderr, "%s\n", __FUNCTION__));
973
    _cairo_clip_steal_boxes (extents->clip, &boxes);
974
    status = clip_and_composite_boxes (compositor, extents, &boxes);
975
    _cairo_clip_unsteal_boxes (extents->clip, &boxes);
976
 
977
    return status;
978
}
979
 
980
static cairo_int_status_t
981
_cairo_spans_compositor_mask (const cairo_compositor_t		*_compositor,
982
			      cairo_composite_rectangles_t	*extents)
983
{
984
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
985
    cairo_int_status_t status;
986
    cairo_boxes_t boxes;
987
 
988
    TRACE ((stderr, "%s\n", __FUNCTION__));
989
    _cairo_clip_steal_boxes (extents->clip, &boxes);
990
    status = clip_and_composite_boxes (compositor, extents, &boxes);
991
    _cairo_clip_unsteal_boxes (extents->clip, &boxes);
992
 
993
    return status;
994
}
995
 
996
static cairo_int_status_t
997
_cairo_spans_compositor_stroke (const cairo_compositor_t	*_compositor,
998
				cairo_composite_rectangles_t	 *extents,
999
				const cairo_path_fixed_t	*path,
1000
				const cairo_stroke_style_t	*style,
1001
				const cairo_matrix_t		*ctm,
1002
				const cairo_matrix_t		*ctm_inverse,
1003
				double				 tolerance,
1004
				cairo_antialias_t		 antialias)
1005
{
1006
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
1007
    cairo_int_status_t status;
1008
 
1009
    TRACE ((stderr, "%s\n", __FUNCTION__));
1010
    TRACE_ (_cairo_debug_print_path (stderr, path));
1011
    TRACE_ (_cairo_debug_print_clip (stderr, extents->clip));
1012
 
1013
    status = CAIRO_INT_STATUS_UNSUPPORTED;
1014
    if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
1015
	cairo_boxes_t boxes;
1016
 
1017
	_cairo_boxes_init (&boxes);
1018
	if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
1019
	    _cairo_boxes_limit (&boxes,
1020
				extents->clip->boxes,
1021
				extents->clip->num_boxes);
1022
 
1023
	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
1024
								style,
1025
								ctm,
1026
								antialias,
1027
								&boxes);
1028
	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1029
	    status = clip_and_composite_boxes (compositor, extents, &boxes);
1030
	_cairo_boxes_fini (&boxes);
1031
    }
1032
 
1033
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1034
	cairo_polygon_t polygon;
1035
	cairo_fill_rule_t fill_rule = CAIRO_FILL_RULE_WINDING;
1036
 
1037
	if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
1038
						   &extents->mask))
1039
	{
1040
	    if (extents->clip->num_boxes == 1) {
1041
		_cairo_polygon_init (&polygon, extents->clip->boxes, 1);
1042
	    } else {
1043
		cairo_box_t limits;
1044
		_cairo_box_from_rectangle (&limits, &extents->unbounded);
1045
		_cairo_polygon_init (&polygon, &limits, 1);
1046
	    }
1047
	}
1048
	else
1049
	{
1050
	    _cairo_polygon_init (&polygon, NULL, 0);
1051
	}
1052
	status = _cairo_path_fixed_stroke_to_polygon (path,
1053
						      style,
1054
						      ctm, ctm_inverse,
1055
						      tolerance,
1056
						      &polygon);
1057
	TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1058
	polygon.num_limits = 0;
1059
 
1060
	if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
1061
	    status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
1062
							  extents->clip->boxes,
1063
							  extents->clip->num_boxes);
1064
	}
1065
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1066
	    cairo_clip_t *saved_clip = extents->clip;
1067
 
1068
	    if (extents->is_bounded) {
1069
		extents->clip = _cairo_clip_copy_path (extents->clip);
1070
		extents->clip = _cairo_clip_intersect_box(extents->clip,
1071
							  &polygon.extents);
1072
	    }
1073
 
1074
	    status = clip_and_composite_polygon (compositor, extents, &polygon,
1075
						 fill_rule, antialias);
1076
 
1077
	    if (extents->is_bounded) {
1078
		_cairo_clip_destroy (extents->clip);
1079
		extents->clip = saved_clip;
1080
	    }
1081
	}
1082
	_cairo_polygon_fini (&polygon);
1083
    }
1084
 
1085
    return status;
1086
}
1087
 
1088
static cairo_int_status_t
1089
_cairo_spans_compositor_fill (const cairo_compositor_t		*_compositor,
1090
			      cairo_composite_rectangles_t	 *extents,
1091
			      const cairo_path_fixed_t		*path,
1092
			      cairo_fill_rule_t			 fill_rule,
1093
			      double				 tolerance,
1094
			      cairo_antialias_t			 antialias)
1095
{
1096
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
1097
    cairo_int_status_t status;
1098
 
1099
    TRACE((stderr, "%s op=%d, antialias=%d\n", __FUNCTION__, extents->op, antialias));
1100
 
1101
    status = CAIRO_INT_STATUS_UNSUPPORTED;
1102
    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
1103
	cairo_boxes_t boxes;
1104
 
1105
	TRACE((stderr, "%s - rectilinear\n", __FUNCTION__));
1106
 
1107
	_cairo_boxes_init (&boxes);
1108
	if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
1109
	    _cairo_boxes_limit (&boxes,
1110
				extents->clip->boxes,
1111
				extents->clip->num_boxes);
1112
	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
1113
							      fill_rule,
1114
							      antialias,
1115
							      &boxes);
1116
	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1117
	    status = clip_and_composite_boxes (compositor, extents, &boxes);
1118
	_cairo_boxes_fini (&boxes);
1119
    }
1120
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1121
	cairo_polygon_t polygon;
1122
 
1123
	TRACE((stderr, "%s - polygon\n", __FUNCTION__));
1124
 
1125
	if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
1126
						   &extents->mask))
1127
	{
1128
	    TRACE((stderr, "%s - clipping to bounds\n", __FUNCTION__));
1129
	    if (extents->clip->num_boxes == 1) {
1130
		_cairo_polygon_init (&polygon, extents->clip->boxes, 1);
1131
	    } else {
1132
		cairo_box_t limits;
1133
		_cairo_box_from_rectangle (&limits, &extents->unbounded);
1134
		_cairo_polygon_init (&polygon, &limits, 1);
1135
	    }
1136
	}
1137
	else
1138
	{
1139
	    _cairo_polygon_init (&polygon, NULL, 0);
1140
	}
1141
 
1142
	status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1143
	TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1144
	polygon.num_limits = 0;
1145
 
1146
	if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
1147
	    TRACE((stderr, "%s - polygon intersect with %d clip boxes\n",
1148
		   __FUNCTION__, extents->clip->num_boxes));
1149
	    status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
1150
							  extents->clip->boxes,
1151
							  extents->clip->num_boxes);
1152
	}
1153
	TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1154
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1155
	    cairo_clip_t *saved_clip = extents->clip;
1156
 
1157
	    if (extents->is_bounded) {
1158
		TRACE((stderr, "%s - polygon discard clip boxes\n",
1159
		       __FUNCTION__));
1160
		extents->clip = _cairo_clip_copy_path (extents->clip);
1161
		extents->clip = _cairo_clip_intersect_box(extents->clip,
1162
							  &polygon.extents);
1163
	    }
1164
 
1165
	    status = clip_and_composite_polygon (compositor, extents, &polygon,
1166
						 fill_rule, antialias);
1167
 
1168
	    if (extents->is_bounded) {
1169
		_cairo_clip_destroy (extents->clip);
1170
		extents->clip = saved_clip;
1171
	    }
1172
	}
1173
	_cairo_polygon_fini (&polygon);
1174
 
1175
	TRACE((stderr, "%s - polygon status=%d\n", __FUNCTION__, status));
1176
    }
1177
 
1178
    return status;
1179
}
1180
 
1181
void
1182
_cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
1183
			      const cairo_compositor_t  *delegate)
1184
{
1185
    compositor->base.delegate = delegate;
1186
 
1187
    compositor->base.paint  = _cairo_spans_compositor_paint;
1188
    compositor->base.mask   = _cairo_spans_compositor_mask;
1189
    compositor->base.fill   = _cairo_spans_compositor_fill;
1190
    compositor->base.stroke = _cairo_spans_compositor_stroke;
1191
    compositor->base.glyphs = NULL;
1192
}