cairo-spans-compositor.c 35.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
 *
 * Copyright © 2002 University of Southern California
 * Copyright © 2005 Red Hat, Inc.
 * Copyright © 2011 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it either under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * (the "LGPL") or, at your option, under the terms of the Mozilla
 * Public License Version 1.1 (the "MPL"). If you do not alter this
 * notice, a recipient may use your version of this file under either
 * the MPL or the LGPL.
 *
 * You should have received a copy of the LGPL along with this library
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
 * You should have received a copy of the MPL along with this library
 * in the file COPYING-MPL-1.1
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
 * the specific language governing rights and limitations.
 *
 * The Original Code is the cairo graphics library.
 *
 * The Initial Developer of the Original Code is University of Southern
 * California.
 *
 * Contributor(s):
 *	Carl D. Worth <cworth@cworth.org>
 *      Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
 *	Chris Wilson <chris@chris-wilson.co.uk>
 */

#include "cairoint.h"

#include "cairo-compositor-private.h"
45
#include "cairo-clip-inline.h"
46 47 48
#include "cairo-clip-private.h"
#include "cairo-image-surface-private.h"
#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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
#include "cairo-spans-compositor-private.h"
#include "cairo-surface-subsurface-private.h"
#include "cairo-surface-snapshot-private.h"
#include "cairo-surface-observer-private.h"

typedef struct {
    cairo_polygon_t	*polygon;
    cairo_fill_rule_t	 fill_rule;
    cairo_antialias_t	 antialias;
} composite_spans_info_t;

static cairo_int_status_t
composite_polygon (const cairo_spans_compositor_t	*compositor,
		   cairo_composite_rectangles_t		 *extents,
		   cairo_polygon_t			*polygon,
		   cairo_fill_rule_t			 fill_rule,
		   cairo_antialias_t			 antialias);

static cairo_int_status_t
composite_boxes (const cairo_spans_compositor_t *compositor,
		 cairo_composite_rectangles_t *extents,
		 cairo_boxes_t		*boxes);

static cairo_int_status_t
clip_and_composite_polygon (const cairo_spans_compositor_t	*compositor,
			    cairo_composite_rectangles_t	 *extents,
			    cairo_polygon_t			*polygon,
			    cairo_fill_rule_t			 fill_rule,
			    cairo_antialias_t			 antialias);
static cairo_surface_t *
get_clip_surface (const cairo_spans_compositor_t *compositor,
		  cairo_surface_t *dst,
		  const cairo_clip_t *clip,
		  const cairo_rectangle_int_t *extents)
{
    cairo_composite_rectangles_t composite;
    cairo_surface_t *surface;
    cairo_box_t box;
    cairo_polygon_t polygon;
    const cairo_clip_path_t *clip_path;
    cairo_antialias_t antialias;
    cairo_fill_rule_t fill_rule;
    cairo_int_status_t status;

    assert (clip->path);

98 99 100 101 102
    surface = _cairo_surface_create_scratch (dst,
					     CAIRO_CONTENT_ALPHA,
					     extents->width,
					     extents->height,
					     CAIRO_COLOR_TRANSPARENT);
103 104 105 106 107 108 109 110 111 112 113

    _cairo_box_from_rectangle (&box, extents);
    _cairo_polygon_init (&polygon, &box, 1);

    clip_path = clip->path;
    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
						clip_path->tolerance,
						&polygon);
    if (unlikely (status))
	goto cleanup_polygon;

114 115
    polygon.num_limits = 0;

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    antialias = clip_path->antialias;
    fill_rule = clip_path->fill_rule;

    if (clip->boxes) {
	cairo_polygon_t intersect;
	cairo_boxes_t tmp;

	_cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes);
	status= _cairo_polygon_init_boxes (&intersect, &tmp);
	if (unlikely (status))
	    goto cleanup_polygon;

	status = _cairo_polygon_intersect (&polygon, fill_rule,
					   &intersect, CAIRO_FILL_RULE_WINDING);
	_cairo_polygon_fini (&intersect);

	if (unlikely (status))
	    goto cleanup_polygon;

	fill_rule = CAIRO_FILL_RULE_WINDING;
    }

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
    polygon.limits = NULL;
    polygon.num_limits = 0;

    clip_path = clip_path->prev;
    while (clip_path) {
	if (clip_path->antialias == antialias) {
	    cairo_polygon_t next;

	    _cairo_polygon_init (&next, NULL, 0);
	    status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
							clip_path->tolerance,
							&next);
	    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
		status = _cairo_polygon_intersect (&polygon, fill_rule,
						   &next, clip_path->fill_rule);
	    _cairo_polygon_fini (&next);
	    if (unlikely (status))
		goto cleanup_polygon;

	    fill_rule = CAIRO_FILL_RULE_WINDING;
	}

	clip_path = clip_path->prev;
    }

    _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
    status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
							   CAIRO_OPERATOR_ADD,
							   &_cairo_pattern_white.base,
							   &polygon,
							   NULL);
    if (unlikely (status))
	goto cleanup_polygon;

    status = composite_polygon (compositor, &composite,
				&polygon, fill_rule, antialias);
    _cairo_composite_rectangles_fini (&composite);
    _cairo_polygon_fini (&polygon);
    if (unlikely (status))
	goto error;

    _cairo_polygon_init (&polygon, &box, 1);

    clip_path = clip->path;
    antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT;
    clip_path = clip_path->prev;
    while (clip_path) {
	if (clip_path->antialias == antialias) {
	    if (polygon.num_edges == 0) {
		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
							    clip_path->tolerance,
							    &polygon);

		fill_rule = clip_path->fill_rule;
		polygon.limits = NULL;
		polygon.num_limits = 0;
	    } else {
		cairo_polygon_t next;

		_cairo_polygon_init (&next, NULL, 0);
		status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
							    clip_path->tolerance,
							    &next);
		if (likely (status == CAIRO_INT_STATUS_SUCCESS))
		    status = _cairo_polygon_intersect (&polygon, fill_rule,
						       &next, clip_path->fill_rule);
		_cairo_polygon_fini (&next);
		fill_rule = CAIRO_FILL_RULE_WINDING;
	    }
	    if (unlikely (status))
		goto error;
	}

	clip_path = clip_path->prev;
    }

    if (polygon.num_edges) {
	_cairo_polygon_translate (&polygon, -extents->x, -extents->y);
	status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
							       CAIRO_OPERATOR_IN,
							       &_cairo_pattern_white.base,
							       &polygon,
							       NULL);
	if (unlikely (status))
	    goto cleanup_polygon;

	status = composite_polygon (compositor, &composite,
				    &polygon, fill_rule, antialias);
	_cairo_composite_rectangles_fini (&composite);
	_cairo_polygon_fini (&polygon);
	if (unlikely (status))
	    goto error;
    }

    return surface;

cleanup_polygon:
    _cairo_polygon_fini (&polygon);
error:
    cairo_surface_destroy (surface);
238
    return _cairo_int_surface_create_in_error (status);
239 240 241 242 243 244 245 246 247 248 249
}

static cairo_int_status_t
fixup_unbounded_mask (const cairo_spans_compositor_t *compositor,
		      const cairo_composite_rectangles_t *extents,
		      cairo_boxes_t *boxes)
{
    cairo_composite_rectangles_t composite;
    cairo_surface_t *clip;
    cairo_int_status_t status;

250 251
    TRACE((stderr, "%s\n", __FUNCTION__));

252 253
    clip = get_clip_surface (compositor, extents->surface, extents->clip,
			     &extents->unbounded);
254 255 256 257
    if (unlikely (clip->status)) {
	if ((cairo_int_status_t)clip->status == CAIRO_INT_STATUS_NOTHING_TO_DO)
	    return CAIRO_STATUS_SUCCESS;

258
	return clip->status;
259
    }
260 261 262

    status = _cairo_composite_rectangles_init_for_boxes (&composite,
							 extents->surface,
263 264
							 CAIRO_OPERATOR_CLEAR,
							 &_cairo_pattern_clear.base,
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
							 boxes,
							 NULL);
    if (unlikely (status))
	goto cleanup_clip;

    _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip);
    composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
    composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE;

    status = composite_boxes (compositor, &composite, boxes);

    _cairo_pattern_fini (&composite.mask_pattern.base);
    _cairo_composite_rectangles_fini (&composite);

cleanup_clip:
    cairo_surface_destroy (clip);
    return status;
}

static cairo_int_status_t
fixup_unbounded_polygon (const cairo_spans_compositor_t *compositor,
			 const cairo_composite_rectangles_t *extents,
			 cairo_boxes_t *boxes)
{
    cairo_polygon_t polygon, intersect;
    cairo_composite_rectangles_t composite;
    cairo_fill_rule_t fill_rule;
    cairo_antialias_t antialias;
    cairo_int_status_t status;

295 296
    TRACE((stderr, "%s\n", __FUNCTION__));

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
    /* Can we treat the clip as a regular clear-polygon and use it to fill? */
    status = _cairo_clip_get_polygon (extents->clip, &polygon,
				      &fill_rule, &antialias);
    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    status= _cairo_polygon_init_boxes (&intersect, boxes);
    if (unlikely (status))
	goto cleanup_polygon;

    status = _cairo_polygon_intersect (&polygon, fill_rule,
				       &intersect, CAIRO_FILL_RULE_WINDING);
    _cairo_polygon_fini (&intersect);

    if (unlikely (status))
	goto cleanup_polygon;

    status = _cairo_composite_rectangles_init_for_polygon (&composite,
							   extents->surface,
316 317
							   CAIRO_OPERATOR_CLEAR,
							   &_cairo_pattern_clear.base,
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
							   &polygon,
							   NULL);
    if (unlikely (status))
	goto cleanup_polygon;

    status = composite_polygon (compositor, &composite,
				&polygon, fill_rule, antialias);

    _cairo_composite_rectangles_fini (&composite);
cleanup_polygon:
    _cairo_polygon_fini (&polygon);

    return status;
}

static cairo_int_status_t
fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor,
		       const cairo_composite_rectangles_t *extents,
		       cairo_boxes_t *boxes)
{
    cairo_boxes_t tmp, clear;
    cairo_box_t box;
    cairo_int_status_t status;

    assert (boxes->is_pixel_aligned);

Chris Wilson's avatar
Chris Wilson committed
344
    TRACE ((stderr, "%s\n", __FUNCTION__));
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
    if (extents->bounded.width  == extents->unbounded.width &&
	extents->bounded.height == extents->unbounded.height)
    {
	return CAIRO_STATUS_SUCCESS;
    }

    /* subtract the drawn boxes from the unbounded area */
    _cairo_boxes_init (&clear);

    box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
    box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
    box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
    box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);

    if (boxes->num_boxes) {
	_cairo_boxes_init (&tmp);

	status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	tmp.chunks.next = &boxes->chunks;
	tmp.num_boxes += boxes->num_boxes;

	status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
							  CAIRO_FILL_RULE_WINDING,
							  &clear);
	tmp.chunks.next = NULL;
	if (unlikely (status))
	    goto error;
    } else {
	box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
	box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);

	status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
	assert (status == CAIRO_INT_STATUS_SUCCESS);
    }

    /* If we have a clip polygon, we need to intersect with that as well */
    if (extents->clip->path) {
	status = fixup_unbounded_polygon (compositor, extents, &clear);
	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
	    status = fixup_unbounded_mask (compositor, extents, &clear);
    } else {
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
	/* Otherwise just intersect with the clip boxes */
	if (extents->clip->num_boxes) {
	    _cairo_boxes_init_for_array (&tmp,
					 extents->clip->boxes,
					 extents->clip->num_boxes);
	    status = _cairo_boxes_intersect (&clear, &tmp, &clear);
	    if (unlikely (status))
		goto error;
	}

	if (clear.is_pixel_aligned) {
	    status = compositor->fill_boxes (extents->surface,
					     CAIRO_OPERATOR_CLEAR,
					     CAIRO_COLOR_TRANSPARENT,
					     &clear);
	} else {
	    cairo_composite_rectangles_t composite;

	    status = _cairo_composite_rectangles_init_for_boxes (&composite,
								 extents->surface,
								 CAIRO_OPERATOR_CLEAR,
								 &_cairo_pattern_clear.base,
								 &clear,
								 NULL);
	    if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
		status = composite_boxes (compositor, &composite, &clear);
		_cairo_composite_rectangles_fini (&composite);
	    }
	}
417 418 419 420 421 422 423 424
    }

error:
    _cairo_boxes_fini (&clear);
    return status;
}

static cairo_surface_t *
425
unwrap_source (const cairo_pattern_t *pattern)
426
{
427
    cairo_rectangle_int_t limit;
428

429 430
    return _cairo_pattern_get_source ((cairo_surface_pattern_t *)pattern,
				      &limit);
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
}

static cairo_bool_t
is_recording_pattern (const cairo_pattern_t *pattern)
{
    cairo_surface_t *surface;

    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
	return FALSE;

    surface = ((const cairo_surface_pattern_t *) pattern)->surface;
    return _cairo_surface_is_recording (surface);
}

static cairo_bool_t
recording_pattern_contains_sample (const cairo_pattern_t *pattern,
				   const cairo_rectangle_int_t *sample)
{
    cairo_recording_surface_t *surface;

    if (! is_recording_pattern (pattern))
	return FALSE;

    if (pattern->extend == CAIRO_EXTEND_NONE)
	return TRUE;

457
    surface = (cairo_recording_surface_t *) unwrap_source (pattern);
458 459 460
    if (surface->unbounded)
	return TRUE;

461
    return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
462 463 464
}

static cairo_bool_t
465 466
op_reduces_to_source (const cairo_composite_rectangles_t *extents,
		      cairo_bool_t no_mask)
467 468 469 470 471 472 473
{
    if (extents->op == CAIRO_OPERATOR_SOURCE)
	return TRUE;

    if (extents->surface->is_clear)
	return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;

474 475 476 477
    if (no_mask && extents->op == CAIRO_OPERATOR_OVER)
	return _cairo_pattern_is_opaque (&extents->source_pattern.base,
					 &extents->source_sample_area);

478 479 480
    return FALSE;
}

481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
static cairo_status_t
upload_boxes (const cairo_spans_compositor_t *compositor,
	      const cairo_composite_rectangles_t *extents,
	      cairo_boxes_t *boxes)
{
    cairo_surface_t *dst = extents->surface;
    const cairo_surface_pattern_t *source = &extents->source_pattern.surface;
    cairo_surface_t *src;
    cairo_rectangle_int_t limit;
    cairo_int_status_t status;
    int tx, ty;

    TRACE ((stderr, "%s\n", __FUNCTION__));

    src = _cairo_pattern_get_source(source, &limit);
    if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    if (! _cairo_matrix_is_integer_translation (&source->base.matrix, &tx, &ty))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    /* Check that the data is entirely within the image */
    if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    if (extents->bounded.x + extents->bounded.width  + tx > limit.x + limit.width ||
	extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    tx += limit.x;
    ty += limit.y;

    if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
	status = compositor->draw_image_boxes (dst,
					       (cairo_image_surface_t *)src,
					       boxes, tx, ty);
    else
	status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
					 tx, ty);

    return status;
}

524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
static cairo_bool_t
_clip_is_region (const cairo_clip_t *clip)
{
    int i;

    if (clip->is_region)
	return TRUE;

    if (clip->path)
	return FALSE;

    for (i = 0; i < clip->num_boxes; i++) {
	const cairo_box_t *b = &clip->boxes[i];
	if (!_cairo_fixed_is_integer (b->p1.x | b->p1.y |  b->p2.x | b->p2.y))
	    return FALSE;
    }

    return TRUE;
}

544 545 546 547 548 549 550 551 552
static cairo_int_status_t
composite_aligned_boxes (const cairo_spans_compositor_t		*compositor,
			 const cairo_composite_rectangles_t	*extents,
			 cairo_boxes_t				*boxes)
{
    cairo_surface_t *dst = extents->surface;
    cairo_operator_t op = extents->op;
    const cairo_pattern_t *source = &extents->source_pattern.base;
    cairo_int_status_t status;
553
    cairo_bool_t need_clip_mask = ! _clip_is_region (extents->clip);
554 555 556 557
    cairo_bool_t op_is_source;
    cairo_bool_t no_mask;
    cairo_bool_t inplace;

Chris Wilson's avatar
Chris Wilson committed
558 559
    TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n",
	    __FUNCTION__, need_clip_mask, extents->is_bounded));
560 561
    if (need_clip_mask && ! extents->is_bounded) {
	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 567
	CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color);
    op_is_source = op_reduces_to_source (extents, no_mask);
568 569
    inplace = ! need_clip_mask && op_is_source && no_mask;

Chris Wilson's avatar
Chris Wilson committed
570 571 572
    TRACE ((stderr, "%s: op-is-source=%d [op=%d], no-mask=%d, inplace=%d\n",
	    __FUNCTION__, op_is_source, op, no_mask, inplace));

573 574
    if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
	/* SOURCE with a mask is actually a LERP in cairo semantics */
575 576
	if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0) {
	    TRACE ((stderr, "%s: unsupported lerp\n", __FUNCTION__));
577
	    return CAIRO_INT_STATUS_UNSUPPORTED;
578
	}
579 580 581 582 583 584 585 586 587
    }

    /* Are we just copying a recording surface? */
    if (inplace &&
	recording_pattern_contains_sample (&extents->source_pattern.base,
					   &extents->source_sample_area))
    {
	cairo_clip_t *recording_clip;
	const cairo_pattern_t *source = &extents->source_pattern.base;
588 589
	const cairo_matrix_t *m;
	cairo_matrix_t matrix;
590 591 592 593

	/* XXX could also do tiling repeat modes... */

	/* first clear the area about to be overwritten */
594
	if (! dst->is_clear) {
595 596 597 598
	    status = compositor->fill_boxes (dst,
					     CAIRO_OPERATOR_CLEAR,
					     CAIRO_COLOR_TRANSPARENT,
					     boxes);
599 600 601 602 603
	    if (unlikely (status))
		return status;

	    dst->is_clear = TRUE;
	}
604

605 606 607 608 609 610 611 612
	m = &source->matrix;
	if (_cairo_surface_has_device_transform (dst)) {
	    cairo_matrix_multiply (&matrix,
				   &source->matrix,
				   &dst->device_transform);
	    m = &matrix;
	}

613
	recording_clip = _cairo_clip_from_boxes (boxes);
614
	status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
615
							    m, dst, recording_clip);
616 617 618 619 620
	_cairo_clip_destroy (recording_clip);

	return status;
    }

621
    status = CAIRO_INT_STATUS_UNSUPPORTED;
622 623 624 625 626 627 628 629
    if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
	const cairo_color_t *color;

	color = &((cairo_solid_pattern_t *) source)->color;
	if (op_is_source)
	    op = CAIRO_OPERATOR_SOURCE;
	status = compositor->fill_boxes (dst, op, color, boxes);
    } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
630
	status = upload_boxes (compositor, extents, boxes);
631 632
    }
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
	cairo_surface_t *src;
	cairo_surface_t *mask = NULL;
	int src_x, src_y;
	int mask_x = 0, mask_y = 0;

	/* All typical cases will have been resolved before now... */
	if (need_clip_mask) {
	    mask = get_clip_surface (compositor, dst, extents->clip,
				     &extents->bounded);
	    if (unlikely (mask->status))
		return mask->status;

	    mask_x = -extents->bounded.x;
	    mask_y = -extents->bounded.y;
	}

	/* XXX but this is still ugly */
	if (! no_mask) {
	    src = compositor->pattern_to_surface (dst,
						  &extents->mask_pattern.base,
						  TRUE,
						  &extents->bounded,
						  &extents->mask_sample_area,
						  &src_x, &src_y);
	    if (unlikely (src->status)) {
		cairo_surface_destroy (mask);
		return src->status;
	    }

	    if (mask != NULL) {
		status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN,
						      src, NULL,
						      src_x, src_y,
						      0, 0,
						      mask_x, mask_y,
						      boxes, &extents->bounded);

		cairo_surface_destroy (src);
	    } else {
		mask = src;
		mask_x = src_x;
		mask_y = src_y;
	    }
	}

	src = compositor->pattern_to_surface (dst, source, FALSE,
					      &extents->bounded,
					      &extents->source_sample_area,
					      &src_x, &src_y);
	if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
	    status = compositor->composite_boxes (dst, op, src, mask,
						  src_x, src_y,
						  mask_x, mask_y,
						  0, 0,
						  boxes, &extents->bounded);
	    cairo_surface_destroy (src);
	} else
	    status = src->status;

	cairo_surface_destroy (mask);
    }

    if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded)
	status = fixup_unbounded_boxes (compositor, extents, boxes);

    return status;
}

static cairo_bool_t
702
composite_needs_clip (const cairo_composite_rectangles_t *composite,
703 704
		      const cairo_box_t *extents)
{
705
    return !_cairo_clip_contains_box (composite->clip, extents);
706 707 708 709 710 711 712 713 714 715 716 717 718
}

static cairo_int_status_t
composite_boxes (const cairo_spans_compositor_t *compositor,
		 cairo_composite_rectangles_t *extents,
		 cairo_boxes_t		*boxes)
{
    cairo_abstract_span_renderer_t renderer;
    cairo_rectangular_scan_converter_t converter;
    const struct _cairo_boxes_chunk *chunk;
    cairo_int_status_t status;
    cairo_box_t box;

Chris Wilson's avatar
Chris Wilson committed
719
    TRACE ((stderr, "%s\n", __FUNCTION__));
720
    _cairo_box_from_rectangle (&box, &extents->unbounded);
721 722
    if (composite_needs_clip (extents, &box)) {
	TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
723
	return CAIRO_INT_STATUS_UNSUPPORTED;
724
    }
725

726
    _cairo_rectangular_scan_converter_init (&converter, &extents->unbounded);
727 728 729 730 731 732 733 734 735 736 737
    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
	const cairo_box_t *box = chunk->base;
	int i;

	for (i = 0; i < chunk->count; i++) {
	    status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
	    if (unlikely (status))
		goto cleanup_converter;
	}
    }

738 739
    status = compositor->renderer_init (&renderer, extents,
					CAIRO_ANTIALIAS_DEFAULT, FALSE);
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
	status = converter.base.generate (&converter.base, &renderer.base);
    compositor->renderer_fini (&renderer, status);

cleanup_converter:
    converter.base.destroy (&converter.base);
    return status;
}

static cairo_int_status_t
composite_polygon (const cairo_spans_compositor_t	*compositor,
		   cairo_composite_rectangles_t		 *extents,
		   cairo_polygon_t			*polygon,
		   cairo_fill_rule_t			 fill_rule,
		   cairo_antialias_t			 antialias)
{
    cairo_abstract_span_renderer_t renderer;
    cairo_scan_converter_t *converter;
    cairo_bool_t needs_clip;
    cairo_int_status_t status;

761 762 763 764
    if (extents->is_bounded)
	needs_clip = extents->clip->path != NULL;
    else
	needs_clip = !_clip_is_region (extents->clip) || extents->clip->num_boxes > 1;
765
    TRACE ((stderr, "%s - needs_clip=%d\n", __FUNCTION__, needs_clip));
766
    if (needs_clip) {
767
	TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
768 769 770 771 772
	return CAIRO_INT_STATUS_UNSUPPORTED;
	converter = _cairo_clip_tor_scan_converter_create (extents->clip,
							   polygon,
							   fill_rule, antialias);
    } else {
773
	const cairo_rectangle_int_t *r = &extents->unbounded;
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797

	if (antialias == CAIRO_ANTIALIAS_FAST) {
	    converter = _cairo_tor22_scan_converter_create (r->x, r->y,
							    r->x + r->width,
							    r->y + r->height,
							    fill_rule, antialias);
	    status = _cairo_tor22_scan_converter_add_polygon (converter, polygon);
	} else if (antialias == CAIRO_ANTIALIAS_NONE) {
	    converter = _cairo_mono_scan_converter_create (r->x, r->y,
							   r->x + r->width,
							   r->y + r->height,
							   fill_rule);
	    status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
	} else {
	    converter = _cairo_tor_scan_converter_create (r->x, r->y,
							  r->x + r->width,
							  r->y + r->height,
							  fill_rule, antialias);
	    status = _cairo_tor_scan_converter_add_polygon (converter, polygon);
	}
    }
    if (unlikely (status))
	goto cleanup_converter;

798 799
    status = compositor->renderer_init (&renderer, extents,
					antialias, needs_clip);
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
	status = converter->generate (converter, &renderer.base);
    compositor->renderer_fini (&renderer, status);

cleanup_converter:
    converter->destroy (converter);
    return status;
}

static cairo_int_status_t
trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
		       cairo_boxes_t *boxes)
{
    cairo_box_t box;

    _cairo_boxes_extents (boxes, &box);
    return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
}

static cairo_int_status_t
trim_extents_to_polygon (cairo_composite_rectangles_t *extents,
			 cairo_polygon_t *polygon)
{
    return _cairo_composite_rectangles_intersect_mask_extents (extents,
							       &polygon->extents);
}

static cairo_int_status_t
clip_and_composite_boxes (const cairo_spans_compositor_t	*compositor,
			  cairo_composite_rectangles_t		*extents,
			  cairo_boxes_t				*boxes)
{
    cairo_int_status_t status;
    cairo_polygon_t polygon;

Chris Wilson's avatar
Chris Wilson committed
835
    TRACE ((stderr, "%s\n", __FUNCTION__));
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
    status = trim_extents_to_boxes (extents, boxes);
    if (unlikely (status))
	return status;

    if (boxes->num_boxes == 0) {
	if (extents->is_bounded)
	    return CAIRO_STATUS_SUCCESS;

	return fixup_unbounded_boxes (compositor, extents, boxes);
    }

    /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
    if (extents->clip->path != NULL && extents->is_bounded) {
	cairo_polygon_t polygon;
	cairo_fill_rule_t fill_rule;
	cairo_antialias_t antialias;
	cairo_clip_t *clip;

	clip = _cairo_clip_copy (extents->clip);
	clip = _cairo_clip_intersect_boxes (clip, boxes);
856 857 858
	if (_cairo_clip_is_all_clipped (clip))
	    return CAIRO_INT_STATUS_NOTHING_TO_DO;

859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
	status = _cairo_clip_get_polygon (clip, &polygon,
					  &fill_rule, &antialias);
	_cairo_clip_path_destroy (clip->path);
	clip->path = NULL;
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
	    cairo_clip_t *saved_clip = extents->clip;
	    extents->clip = clip;

	    status = clip_and_composite_polygon (compositor, extents, &polygon,
						 fill_rule, antialias);

	    clip = extents->clip;
	    extents->clip = saved_clip;

	    _cairo_polygon_fini (&polygon);
	}
	_cairo_clip_destroy (clip);

	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    return status;
    }

    if (boxes->is_pixel_aligned) {
	status = composite_aligned_boxes (compositor, extents, boxes);
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    return status;
    }

    status = composite_boxes (compositor, extents, boxes);
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    status = _cairo_polygon_init_boxes (&polygon, boxes);
    if (unlikely (status))
	return status;

    status = composite_polygon (compositor, extents, &polygon,
				CAIRO_FILL_RULE_WINDING,
				CAIRO_ANTIALIAS_DEFAULT);
    _cairo_polygon_fini (&polygon);

    return status;
}

static cairo_int_status_t
clip_and_composite_polygon (const cairo_spans_compositor_t	*compositor,
			    cairo_composite_rectangles_t	 *extents,
			    cairo_polygon_t			*polygon,
			    cairo_fill_rule_t			 fill_rule,
			    cairo_antialias_t			 antialias)
{
    cairo_int_status_t status;

Chris Wilson's avatar
Chris Wilson committed
912 913
    TRACE ((stderr, "%s\n", __FUNCTION__));

914 915 916 917 918
    /* XXX simply uses polygon limits.point extemities, tessellation? */
    status = trim_extents_to_polygon (extents, polygon);
    if (unlikely (status))
	return status;

919 920 921 922 923 924 925
    if (_cairo_polygon_is_empty (polygon)) {
	cairo_boxes_t boxes;

	if (extents->is_bounded)
	    return CAIRO_STATUS_SUCCESS;

	_cairo_boxes_init (&boxes);
926
	extents->bounded.width = extents->bounded.height = 0;
927 928 929 930 931 932 933 934
	return fixup_unbounded_boxes (compositor, extents, &boxes);
    }

    if (extents->is_bounded && extents->clip->path) {
	cairo_polygon_t clipper;
	cairo_antialias_t clip_antialias;
	cairo_fill_rule_t clip_fill_rule;

935 936 937
	TRACE((stderr, "%s - combining shape with clip polygon\n",
	       __FUNCTION__));

938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
	status = _cairo_clip_get_polygon (extents->clip,
					  &clipper,
					  &clip_fill_rule,
					  &clip_antialias);
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
	    cairo_clip_t *old_clip;

	    if (clip_antialias == antialias) {
		status = _cairo_polygon_intersect (polygon, fill_rule,
						   &clipper, clip_fill_rule);
		_cairo_polygon_fini (&clipper);
		if (unlikely (status))
		    return status;

		old_clip = extents->clip;
		extents->clip = _cairo_clip_copy_region (extents->clip);
		_cairo_clip_destroy (old_clip);
955 956 957 958

		status = trim_extents_to_polygon (extents, polygon);
		if (unlikely (status))
		    return status;
959 960

		fill_rule = CAIRO_FILL_RULE_WINDING;
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
	    } else {
		_cairo_polygon_fini (&clipper);
	    }
	}
    }

    return composite_polygon (compositor, extents,
			      polygon, fill_rule, antialias);
}

/* high-level compositor interface */

static cairo_int_status_t
_cairo_spans_compositor_paint (const cairo_compositor_t		*_compositor,
			       cairo_composite_rectangles_t	*extents)
{
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
    cairo_boxes_t boxes;
    cairo_int_status_t status;

Chris Wilson's avatar
Chris Wilson committed
981
    TRACE ((stderr, "%s\n", __FUNCTION__));
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
    _cairo_clip_steal_boxes (extents->clip, &boxes);
    status = clip_and_composite_boxes (compositor, extents, &boxes);
    _cairo_clip_unsteal_boxes (extents->clip, &boxes);

    return status;
}

static cairo_int_status_t
_cairo_spans_compositor_mask (const cairo_compositor_t		*_compositor,
			      cairo_composite_rectangles_t	*extents)
{
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
    cairo_int_status_t status;
    cairo_boxes_t boxes;

Chris Wilson's avatar
Chris Wilson committed
997
    TRACE ((stderr, "%s\n", __FUNCTION__));
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
    _cairo_clip_steal_boxes (extents->clip, &boxes);
    status = clip_and_composite_boxes (compositor, extents, &boxes);
    _cairo_clip_unsteal_boxes (extents->clip, &boxes);

    return status;
}

static cairo_int_status_t
_cairo_spans_compositor_stroke (const cairo_compositor_t	*_compositor,
				cairo_composite_rectangles_t	 *extents,
				const cairo_path_fixed_t	*path,
				const cairo_stroke_style_t	*style,
				const cairo_matrix_t		*ctm,
				const cairo_matrix_t		*ctm_inverse,
				double				 tolerance,
				cairo_antialias_t		 antialias)
{
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
    cairo_int_status_t status;

1018
    TRACE ((stderr, "%s\n", __FUNCTION__));
1019
    TRACE_ (_cairo_debug_print_path (stderr, path));
1020
    TRACE_ (_cairo_debug_print_clip (stderr, extents->clip));
1021

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
    status = CAIRO_INT_STATUS_UNSUPPORTED;
    if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
	cairo_boxes_t boxes;

	_cairo_boxes_init (&boxes);
	if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
	    _cairo_boxes_limit (&boxes,
				extents->clip->boxes,
				extents->clip->num_boxes);

	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
								style,
								ctm,
								antialias,
								&boxes);
	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
	    status = clip_and_composite_boxes (compositor, extents, &boxes);
	_cairo_boxes_fini (&boxes);
    }

    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	cairo_polygon_t polygon;
Uli Schlachter's avatar
Uli Schlachter committed
1044
	cairo_box_t limits;
1045
	cairo_fill_rule_t fill_rule = CAIRO_FILL_RULE_WINDING;
1046

1047 1048
	if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
						   &extents->mask))
1049
	{
1050 1051 1052 1053 1054 1055
	    if (extents->clip->num_boxes == 1) {
		_cairo_polygon_init (&polygon, extents->clip->boxes, 1);
	    } else {
		_cairo_box_from_rectangle (&limits, &extents->unbounded);
		_cairo_polygon_init (&polygon, &limits, 1);
	    }
1056 1057 1058
	}
	else
	{
1059
	    _cairo_polygon_init (&polygon, NULL, 0);
1060 1061 1062 1063 1064 1065
	}
	status = _cairo_path_fixed_stroke_to_polygon (path,
						      style,
						      ctm, ctm_inverse,
						      tolerance,
						      &polygon);
1066
	TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1067 1068
	polygon.num_limits = 0;

1069 1070 1071 1072 1073
	if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
	    status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
							  extents->clip->boxes,
							  extents->clip->num_boxes);
	}
1074
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1075 1076 1077 1078 1079 1080 1081 1082
	    cairo_clip_t *saved_clip = extents->clip;

	    if (extents->is_bounded) {
		extents->clip = _cairo_clip_copy_path (extents->clip);
		extents->clip = _cairo_clip_intersect_box(extents->clip,
							  &polygon.extents);
	    }

1083
	    status = clip_and_composite_polygon (compositor, extents, &polygon,
1084 1085
						 fill_rule, antialias);

1086
	    if (extents->is_bounded) {
1087 1088 1089
		_cairo_clip_destroy (extents->clip);
		extents->clip = saved_clip;
	    }
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
	}
	_cairo_polygon_fini (&polygon);
    }

    return status;
}

static cairo_int_status_t
_cairo_spans_compositor_fill (const cairo_compositor_t		*_compositor,
			      cairo_composite_rectangles_t	 *extents,
			      const cairo_path_fixed_t		*path,
			      cairo_fill_rule_t			 fill_rule,
			      double				 tolerance,
			      cairo_antialias_t			 antialias)
{
    const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
    cairo_int_status_t status;

1108 1109
    TRACE((stderr, "%s op=%d, antialias=%d\n", __FUNCTION__, extents->op, antialias));

1110 1111 1112 1113
    status = CAIRO_INT_STATUS_UNSUPPORTED;
    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
	cairo_boxes_t boxes;

1114 1115
	TRACE((stderr, "%s - rectilinear\n", __FUNCTION__));

1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
	_cairo_boxes_init (&boxes);
	if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
	    _cairo_boxes_limit (&boxes,
				extents->clip->boxes,
				extents->clip->num_boxes);
	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
							      fill_rule,
							      antialias,
							      &boxes);
	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
	    status = clip_and_composite_boxes (compositor, extents, &boxes);
	_cairo_boxes_fini (&boxes);
    }
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	cairo_polygon_t polygon;
Matthias Clasen's avatar
Matthias Clasen committed
1131
	cairo_box_t limits;
1132

1133 1134
	TRACE((stderr, "%s - polygon\n", __FUNCTION__));

1135 1136
	if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
						   &extents->mask))
1137
	{
1138
	    TRACE((stderr, "%s - clipping to bounds\n", __FUNCTION__));
1139 1140 1141 1142 1143 1144
	    if (extents->clip->num_boxes == 1) {
		_cairo_polygon_init (&polygon, extents->clip->boxes, 1);
	    } else {
		_cairo_box_from_rectangle (&limits, &extents->unbounded);
		_cairo_polygon_init (&polygon, &limits, 1);
	    }
1145 1146 1147 1148 1149 1150 1151
	}
	else
	{
	    _cairo_polygon_init (&polygon, NULL, 0);
	}

	status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1152 1153 1154
	TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
	polygon.num_limits = 0;

1155
	if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
1156 1157
	    TRACE((stderr, "%s - polygon intersect with %d clip boxes\n",
		   __FUNCTION__, extents->clip->num_boxes));
1158 1159 1160 1161
	    status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
							  extents->clip->boxes,
							  extents->clip->num_boxes);
	}
1162
	TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1163
	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1164
	    cairo_clip_t *saved_clip = extents->clip;
1165

1166
	    if (extents->is_bounded) {
1167 1168
		TRACE((stderr, "%s - polygon discard clip boxes\n",
		       __FUNCTION__));
1169 1170 1171
		extents->clip = _cairo_clip_copy_path (extents->clip);
		extents->clip = _cairo_clip_intersect_box(extents->clip,
							  &polygon.extents);
1172
	    }
1173

1174 1175
	    status = clip_and_composite_polygon (compositor, extents, &polygon,
						 fill_rule, antialias);
1176

1177
	    if (extents->is_bounded) {
1178 1179 1180
		_cairo_clip_destroy (extents->clip);
		extents->clip = saved_clip;
	    }
1181 1182
	}
	_cairo_polygon_fini (&polygon);
1183 1184

	TRACE((stderr, "%s - polygon status=%d\n", __FUNCTION__, status));
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
    }

    return status;
}

void
_cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
			      const cairo_compositor_t  *delegate)
{
    compositor->base.delegate = delegate;

    compositor->base.paint  = _cairo_spans_compositor_paint;
    compositor->base.mask   = _cairo_spans_compositor_mask;
    compositor->base.fill   = _cairo_spans_compositor_fill;
    compositor->base.stroke = _cairo_spans_compositor_stroke;
    compositor->base.glyphs = NULL;
}