beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-spans-compositor.c
blobefbae254bf4829a93ac15242be3469e9fc2e5320
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
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
6 * Copyright © 2011 Intel Corporation
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.
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
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/
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.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
34 * California.
36 * Contributor(s):
37 * Carl D. Worth <cworth@cworth.org>
38 * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
39 * Chris Wilson <chris@chris-wilson.co.uk>
42 #include "cairoint.h"
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"
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;
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);
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);
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)
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;
96 assert (clip->path);
98 surface = _cairo_surface_create_scratch (dst,
99 CAIRO_CONTENT_ALPHA,
100 extents->width,
101 extents->height,
102 CAIRO_COLOR_TRANSPARENT);
104 _cairo_box_from_rectangle (&box, extents);
105 _cairo_polygon_init (&polygon, &box, 1);
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;
114 polygon.num_limits = 0;
116 antialias = clip_path->antialias;
117 fill_rule = clip_path->fill_rule;
119 if (clip->boxes) {
120 cairo_polygon_t intersect;
121 cairo_boxes_t tmp;
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;
128 status = _cairo_polygon_intersect (&polygon, fill_rule,
129 &intersect, CAIRO_FILL_RULE_WINDING);
130 _cairo_polygon_fini (&intersect);
132 if (unlikely (status))
133 goto cleanup_polygon;
135 fill_rule = CAIRO_FILL_RULE_WINDING;
138 polygon.limits = NULL;
139 polygon.num_limits = 0;
141 clip_path = clip_path->prev;
142 while (clip_path) {
143 if (clip_path->antialias == antialias) {
144 cairo_polygon_t next;
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;
157 fill_rule = CAIRO_FILL_RULE_WINDING;
160 clip_path = clip_path->prev;
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;
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;
179 _cairo_polygon_init (&polygon, &box, 1);
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);
191 fill_rule = clip_path->fill_rule;
192 polygon.limits = NULL;
193 polygon.num_limits = 0;
194 } else {
195 cairo_polygon_t next;
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;
207 if (unlikely (status))
208 goto error;
211 clip_path = clip_path->prev;
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;
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;
232 return surface;
234 cleanup_polygon:
235 _cairo_polygon_fini (&polygon);
236 error:
237 cairo_surface_destroy (surface);
238 return _cairo_int_surface_create_in_error (status);
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)
246 cairo_composite_rectangles_t composite;
247 cairo_surface_t *clip;
248 cairo_int_status_t status;
250 TRACE((stderr, "%s\n", __FUNCTION__));
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;
258 return clip->status;
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;
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;
274 status = composite_boxes (compositor, &composite, boxes);
276 _cairo_pattern_fini (&composite.mask_pattern.base);
277 _cairo_composite_rectangles_fini (&composite);
279 cleanup_clip:
280 cairo_surface_destroy (clip);
281 return status;
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)
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;
295 TRACE((stderr, "%s\n", __FUNCTION__));
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;
303 status= _cairo_polygon_init_boxes (&intersect, boxes);
304 if (unlikely (status))
305 goto cleanup_polygon;
307 status = _cairo_polygon_intersect (&polygon, fill_rule,
308 &intersect, CAIRO_FILL_RULE_WINDING);
309 _cairo_polygon_fini (&intersect);
311 if (unlikely (status))
312 goto cleanup_polygon;
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;
323 status = composite_polygon (compositor, &composite,
324 &polygon, fill_rule, antialias);
326 _cairo_composite_rectangles_fini (&composite);
327 cleanup_polygon:
328 _cairo_polygon_fini (&polygon);
330 return status;
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)
338 cairo_boxes_t tmp, clear;
339 cairo_box_t box;
340 cairo_int_status_t status;
342 assert (boxes->is_pixel_aligned);
344 TRACE ((stderr, "%s\n", __FUNCTION__));
345 if (extents->bounded.width == extents->unbounded.width &&
346 extents->bounded.height == extents->unbounded.height)
348 return CAIRO_STATUS_SUCCESS;
351 /* subtract the drawn boxes from the unbounded area */
352 _cairo_boxes_init (&clear);
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);
359 if (boxes->num_boxes) {
360 _cairo_boxes_init (&tmp);
362 status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
363 assert (status == CAIRO_INT_STATUS_SUCCESS);
365 tmp.chunks.next = &boxes->chunks;
366 tmp.num_boxes += boxes->num_boxes;
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);
378 status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
379 assert (status == CAIRO_INT_STATUS_SUCCESS);
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;
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;
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);
419 error:
420 _cairo_boxes_fini (&clear);
421 return status;
424 static cairo_surface_t *
425 unwrap_source (const cairo_pattern_t *pattern)
427 cairo_rectangle_int_t limit;
429 return _cairo_pattern_get_source ((cairo_surface_pattern_t *)pattern,
430 &limit);
433 static cairo_bool_t
434 is_recording_pattern (const cairo_pattern_t *pattern)
436 cairo_surface_t *surface;
438 if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
439 return FALSE;
441 surface = ((const cairo_surface_pattern_t *) pattern)->surface;
442 return _cairo_surface_is_recording (surface);
445 static cairo_bool_t
446 recording_pattern_contains_sample (const cairo_pattern_t *pattern,
447 const cairo_rectangle_int_t *sample)
449 cairo_recording_surface_t *surface;
451 if (! is_recording_pattern (pattern))
452 return FALSE;
454 if (pattern->extend == CAIRO_EXTEND_NONE)
455 return TRUE;
457 surface = (cairo_recording_surface_t *) unwrap_source (pattern);
458 if (surface->unbounded)
459 return TRUE;
461 return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
464 static cairo_bool_t
465 op_reduces_to_source (const cairo_composite_rectangles_t *extents,
466 cairo_bool_t no_mask)
468 if (extents->op == CAIRO_OPERATOR_SOURCE)
469 return TRUE;
471 if (extents->surface->is_clear)
472 return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
474 if (no_mask && extents->op == CAIRO_OPERATOR_OVER)
475 return _cairo_pattern_is_opaque (&extents->source_pattern.base,
476 &extents->source_sample_area);
478 return FALSE;
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)
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;
493 TRACE ((stderr, "%s\n", __FUNCTION__));
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;
499 if (! _cairo_matrix_is_integer_translation (&source->base.matrix, &tx, &ty))
500 return CAIRO_INT_STATUS_UNSUPPORTED;
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;
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;
510 tx += limit.x;
511 ty += limit.y;
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);
521 return status;
524 static cairo_bool_t
525 _clip_is_region (const cairo_clip_t *clip)
527 int i;
529 if (clip->is_region)
530 return TRUE;
532 if (clip->path)
533 return FALSE;
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;
541 return TRUE;
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)
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;
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;
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;
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));
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;
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))
586 cairo_clip_t *recording_clip;
587 const cairo_pattern_t *source = &extents->source_pattern.base;
588 const cairo_matrix_t *m;
589 cairo_matrix_t matrix;
591 /* XXX could also do tiling repeat modes... */
593 /* first clear the area about to be overwritten */
594 if (! dst->is_clear) {
595 status = compositor->fill_boxes (dst,
596 CAIRO_OPERATOR_CLEAR,
597 CAIRO_COLOR_TRANSPARENT,
598 boxes);
599 if (unlikely (status))
600 return status;
602 dst->is_clear = TRUE;
605 m = &source->matrix;
606 if (_cairo_surface_has_device_transform (dst)) {
607 cairo_matrix_multiply (&matrix,
608 &source->matrix,
609 &dst->device_transform);
610 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 _cairo_clip_destroy (recording_clip);
618 return status;
621 status = CAIRO_INT_STATUS_UNSUPPORTED;
622 if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
623 const cairo_color_t *color;
625 color = &((cairo_solid_pattern_t *) source)->color;
626 if (op_is_source)
627 op = CAIRO_OPERATOR_SOURCE;
628 status = compositor->fill_boxes (dst, op, color, boxes);
629 } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
630 status = upload_boxes (compositor, extents, boxes);
632 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
633 cairo_surface_t *src;
634 cairo_surface_t *mask = NULL;
635 int src_x, src_y;
636 int mask_x = 0, mask_y = 0;
638 /* All typical cases will have been resolved before now... */
639 if (need_clip_mask) {
640 mask = get_clip_surface (compositor, dst, extents->clip,
641 &extents->bounded);
642 if (unlikely (mask->status))
643 return mask->status;
645 mask_x = -extents->bounded.x;
646 mask_y = -extents->bounded.y;
649 /* XXX but this is still ugly */
650 if (! no_mask) {
651 src = compositor->pattern_to_surface (dst,
652 &extents->mask_pattern.base,
653 TRUE,
654 &extents->bounded,
655 &extents->mask_sample_area,
656 &src_x, &src_y);
657 if (unlikely (src->status)) {
658 cairo_surface_destroy (mask);
659 return src->status;
662 if (mask != NULL) {
663 status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN,
664 src, NULL,
665 src_x, src_y,
666 0, 0,
667 mask_x, mask_y,
668 boxes, &extents->bounded);
670 cairo_surface_destroy (src);
671 } else {
672 mask = src;
673 mask_x = src_x;
674 mask_y = src_y;
678 src = compositor->pattern_to_surface (dst, source, FALSE,
679 &extents->bounded,
680 &extents->source_sample_area,
681 &src_x, &src_y);
682 if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
683 status = compositor->composite_boxes (dst, op, src, mask,
684 src_x, src_y,
685 mask_x, mask_y,
686 0, 0,
687 boxes, &extents->bounded);
688 cairo_surface_destroy (src);
689 } else
690 status = src->status;
692 cairo_surface_destroy (mask);
695 if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded)
696 status = fixup_unbounded_boxes (compositor, extents, boxes);
698 return status;
701 static cairo_bool_t
702 composite_needs_clip (const cairo_composite_rectangles_t *composite,
703 const cairo_box_t *extents)
705 return !_cairo_clip_contains_box (composite->clip, extents);
708 static cairo_int_status_t
709 composite_boxes (const cairo_spans_compositor_t *compositor,
710 cairo_composite_rectangles_t *extents,
711 cairo_boxes_t *boxes)
713 cairo_abstract_span_renderer_t renderer;
714 cairo_rectangular_scan_converter_t converter;
715 const struct _cairo_boxes_chunk *chunk;
716 cairo_int_status_t status;
717 cairo_box_t box;
719 TRACE ((stderr, "%s\n", __FUNCTION__));
720 _cairo_box_from_rectangle (&box, &extents->unbounded);
721 if (composite_needs_clip (extents, &box)) {
722 TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
723 return CAIRO_INT_STATUS_UNSUPPORTED;
726 _cairo_rectangular_scan_converter_init (&converter, &extents->unbounded);
727 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
728 const cairo_box_t *box = chunk->base;
729 int i;
731 for (i = 0; i < chunk->count; i++) {
732 status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
733 if (unlikely (status))
734 goto cleanup_converter;
738 status = compositor->renderer_init (&renderer, extents,
739 CAIRO_ANTIALIAS_DEFAULT, FALSE);
740 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
741 status = converter.base.generate (&converter.base, &renderer.base);
742 compositor->renderer_fini (&renderer, status);
744 cleanup_converter:
745 converter.base.destroy (&converter.base);
746 return status;
749 static cairo_int_status_t
750 composite_polygon (const cairo_spans_compositor_t *compositor,
751 cairo_composite_rectangles_t *extents,
752 cairo_polygon_t *polygon,
753 cairo_fill_rule_t fill_rule,
754 cairo_antialias_t antialias)
756 cairo_abstract_span_renderer_t renderer;
757 cairo_scan_converter_t *converter;
758 cairo_bool_t needs_clip;
759 cairo_int_status_t status;
761 if (extents->is_bounded)
762 needs_clip = extents->clip->path != NULL;
763 else
764 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 return CAIRO_INT_STATUS_UNSUPPORTED;
769 converter = _cairo_clip_tor_scan_converter_create (extents->clip,
770 polygon,
771 fill_rule, antialias);
772 } else {
773 const cairo_rectangle_int_t *r = &extents->unbounded;
775 if (antialias == CAIRO_ANTIALIAS_FAST) {
776 converter = _cairo_tor22_scan_converter_create (r->x, r->y,
777 r->x + r->width,
778 r->y + r->height,
779 fill_rule, antialias);
780 status = _cairo_tor22_scan_converter_add_polygon (converter, polygon);
781 } else if (antialias == CAIRO_ANTIALIAS_NONE) {
782 converter = _cairo_mono_scan_converter_create (r->x, r->y,
783 r->x + r->width,
784 r->y + r->height,
785 fill_rule);
786 status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
787 } else {
788 converter = _cairo_tor_scan_converter_create (r->x, r->y,
789 r->x + r->width,
790 r->y + r->height,
791 fill_rule, antialias);
792 status = _cairo_tor_scan_converter_add_polygon (converter, polygon);
795 if (unlikely (status))
796 goto cleanup_converter;
798 status = compositor->renderer_init (&renderer, extents,
799 antialias, needs_clip);
800 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
801 status = converter->generate (converter, &renderer.base);
802 compositor->renderer_fini (&renderer, status);
804 cleanup_converter:
805 converter->destroy (converter);
806 return status;
809 static cairo_int_status_t
810 trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
811 cairo_boxes_t *boxes)
813 cairo_box_t box;
815 _cairo_boxes_extents (boxes, &box);
816 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
819 static cairo_int_status_t
820 trim_extents_to_polygon (cairo_composite_rectangles_t *extents,
821 cairo_polygon_t *polygon)
823 return _cairo_composite_rectangles_intersect_mask_extents (extents,
824 &polygon->extents);
827 static cairo_int_status_t
828 clip_and_composite_boxes (const cairo_spans_compositor_t *compositor,
829 cairo_composite_rectangles_t *extents,
830 cairo_boxes_t *boxes)
832 cairo_int_status_t status;
833 cairo_polygon_t polygon;
835 TRACE ((stderr, "%s\n", __FUNCTION__));
836 status = trim_extents_to_boxes (extents, boxes);
837 if (unlikely (status))
838 return status;
840 if (boxes->num_boxes == 0) {
841 if (extents->is_bounded)
842 return CAIRO_STATUS_SUCCESS;
844 return fixup_unbounded_boxes (compositor, extents, boxes);
847 /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
848 if (extents->clip->path != NULL && extents->is_bounded) {
849 cairo_polygon_t polygon;
850 cairo_fill_rule_t fill_rule;
851 cairo_antialias_t antialias;
852 cairo_clip_t *clip;
854 clip = _cairo_clip_copy (extents->clip);
855 clip = _cairo_clip_intersect_boxes (clip, boxes);
856 if (_cairo_clip_is_all_clipped (clip))
857 return CAIRO_INT_STATUS_NOTHING_TO_DO;
859 status = _cairo_clip_get_polygon (clip, &polygon,
860 &fill_rule, &antialias);
861 _cairo_clip_path_destroy (clip->path);
862 clip->path = NULL;
863 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
864 cairo_clip_t *saved_clip = extents->clip;
865 extents->clip = clip;
867 status = clip_and_composite_polygon (compositor, extents, &polygon,
868 fill_rule, antialias);
870 clip = extents->clip;
871 extents->clip = saved_clip;
873 _cairo_polygon_fini (&polygon);
875 _cairo_clip_destroy (clip);
877 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
878 return status;
881 if (boxes->is_pixel_aligned) {
882 status = composite_aligned_boxes (compositor, extents, boxes);
883 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
884 return status;
887 status = composite_boxes (compositor, extents, boxes);
888 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
889 return status;
891 status = _cairo_polygon_init_boxes (&polygon, boxes);
892 if (unlikely (status))
893 return status;
895 status = composite_polygon (compositor, extents, &polygon,
896 CAIRO_FILL_RULE_WINDING,
897 CAIRO_ANTIALIAS_DEFAULT);
898 _cairo_polygon_fini (&polygon);
900 return status;
903 static cairo_int_status_t
904 clip_and_composite_polygon (const cairo_spans_compositor_t *compositor,
905 cairo_composite_rectangles_t *extents,
906 cairo_polygon_t *polygon,
907 cairo_fill_rule_t fill_rule,
908 cairo_antialias_t antialias)
910 cairo_int_status_t status;
912 TRACE ((stderr, "%s\n", __FUNCTION__));
914 /* XXX simply uses polygon limits.point extemities, tessellation? */
915 status = trim_extents_to_polygon (extents, polygon);
916 if (unlikely (status))
917 return status;
919 if (_cairo_polygon_is_empty (polygon)) {
920 cairo_boxes_t boxes;
922 if (extents->is_bounded)
923 return CAIRO_STATUS_SUCCESS;
925 _cairo_boxes_init (&boxes);
926 extents->bounded.width = extents->bounded.height = 0;
927 return fixup_unbounded_boxes (compositor, extents, &boxes);
930 if (extents->is_bounded && extents->clip->path) {
931 cairo_polygon_t clipper;
932 cairo_antialias_t clip_antialias;
933 cairo_fill_rule_t clip_fill_rule;
935 TRACE((stderr, "%s - combining shape with clip polygon\n",
936 __FUNCTION__));
938 status = _cairo_clip_get_polygon (extents->clip,
939 &clipper,
940 &clip_fill_rule,
941 &clip_antialias);
942 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
943 cairo_clip_t *old_clip;
945 if (clip_antialias == antialias) {
946 status = _cairo_polygon_intersect (polygon, fill_rule,
947 &clipper, clip_fill_rule);
948 _cairo_polygon_fini (&clipper);
949 if (unlikely (status))
950 return status;
952 old_clip = extents->clip;
953 extents->clip = _cairo_clip_copy_region (extents->clip);
954 _cairo_clip_destroy (old_clip);
956 status = trim_extents_to_polygon (extents, polygon);
957 if (unlikely (status))
958 return status;
960 fill_rule = CAIRO_FILL_RULE_WINDING;
961 } else {
962 _cairo_polygon_fini (&clipper);
967 return composite_polygon (compositor, extents,
968 polygon, fill_rule, antialias);
971 /* high-level compositor interface */
973 static cairo_int_status_t
974 _cairo_spans_compositor_paint (const cairo_compositor_t *_compositor,
975 cairo_composite_rectangles_t *extents)
977 const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
978 cairo_boxes_t boxes;
979 cairo_int_status_t status;
981 TRACE ((stderr, "%s\n", __FUNCTION__));
982 _cairo_clip_steal_boxes (extents->clip, &boxes);
983 status = clip_and_composite_boxes (compositor, extents, &boxes);
984 _cairo_clip_unsteal_boxes (extents->clip, &boxes);
986 return status;
989 static cairo_int_status_t
990 _cairo_spans_compositor_mask (const cairo_compositor_t *_compositor,
991 cairo_composite_rectangles_t *extents)
993 const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
994 cairo_int_status_t status;
995 cairo_boxes_t boxes;
997 TRACE ((stderr, "%s\n", __FUNCTION__));
998 _cairo_clip_steal_boxes (extents->clip, &boxes);
999 status = clip_and_composite_boxes (compositor, extents, &boxes);
1000 _cairo_clip_unsteal_boxes (extents->clip, &boxes);
1002 return status;
1005 static cairo_int_status_t
1006 _cairo_spans_compositor_stroke (const cairo_compositor_t *_compositor,
1007 cairo_composite_rectangles_t *extents,
1008 const cairo_path_fixed_t *path,
1009 const cairo_stroke_style_t *style,
1010 const cairo_matrix_t *ctm,
1011 const cairo_matrix_t *ctm_inverse,
1012 double tolerance,
1013 cairo_antialias_t antialias)
1015 const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
1016 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));
1022 status = CAIRO_INT_STATUS_UNSUPPORTED;
1023 if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
1024 cairo_boxes_t boxes;
1026 _cairo_boxes_init (&boxes);
1027 if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
1028 _cairo_boxes_limit (&boxes,
1029 extents->clip->boxes,
1030 extents->clip->num_boxes);
1032 status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
1033 style,
1034 ctm,
1035 antialias,
1036 &boxes);
1037 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1038 status = clip_and_composite_boxes (compositor, extents, &boxes);
1039 _cairo_boxes_fini (&boxes);
1042 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1043 cairo_polygon_t polygon;
1044 cairo_fill_rule_t fill_rule = CAIRO_FILL_RULE_WINDING;
1046 if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
1047 &extents->mask))
1049 if (extents->clip->num_boxes == 1) {
1050 _cairo_polygon_init (&polygon, extents->clip->boxes, 1);
1051 } else {
1052 cairo_box_t limits;
1053 _cairo_box_from_rectangle (&limits, &extents->unbounded);
1054 _cairo_polygon_init (&polygon, &limits, 1);
1057 else
1059 _cairo_polygon_init (&polygon, NULL, 0);
1061 status = _cairo_path_fixed_stroke_to_polygon (path,
1062 style,
1063 ctm, ctm_inverse,
1064 tolerance,
1065 &polygon);
1066 TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1067 polygon.num_limits = 0;
1069 if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
1070 status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
1071 extents->clip->boxes,
1072 extents->clip->num_boxes);
1074 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1075 cairo_clip_t *saved_clip = extents->clip;
1077 if (extents->is_bounded) {
1078 extents->clip = _cairo_clip_copy_path (extents->clip);
1079 extents->clip = _cairo_clip_intersect_box(extents->clip,
1080 &polygon.extents);
1083 status = clip_and_composite_polygon (compositor, extents, &polygon,
1084 fill_rule, antialias);
1086 if (extents->is_bounded) {
1087 _cairo_clip_destroy (extents->clip);
1088 extents->clip = saved_clip;
1091 _cairo_polygon_fini (&polygon);
1094 return status;
1097 static cairo_int_status_t
1098 _cairo_spans_compositor_fill (const cairo_compositor_t *_compositor,
1099 cairo_composite_rectangles_t *extents,
1100 const cairo_path_fixed_t *path,
1101 cairo_fill_rule_t fill_rule,
1102 double tolerance,
1103 cairo_antialias_t antialias)
1105 const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
1106 cairo_int_status_t status;
1108 TRACE((stderr, "%s op=%d, antialias=%d\n", __FUNCTION__, extents->op, antialias));
1110 status = CAIRO_INT_STATUS_UNSUPPORTED;
1111 if (_cairo_path_fixed_fill_is_rectilinear (path)) {
1112 cairo_boxes_t boxes;
1114 TRACE((stderr, "%s - rectilinear\n", __FUNCTION__));
1116 _cairo_boxes_init (&boxes);
1117 if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
1118 _cairo_boxes_limit (&boxes,
1119 extents->clip->boxes,
1120 extents->clip->num_boxes);
1121 status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
1122 fill_rule,
1123 antialias,
1124 &boxes);
1125 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1126 status = clip_and_composite_boxes (compositor, extents, &boxes);
1127 _cairo_boxes_fini (&boxes);
1129 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1130 cairo_polygon_t polygon;
1132 TRACE((stderr, "%s - polygon\n", __FUNCTION__));
1134 if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
1135 &extents->mask))
1137 TRACE((stderr, "%s - clipping to bounds\n", __FUNCTION__));
1138 if (extents->clip->num_boxes == 1) {
1139 _cairo_polygon_init (&polygon, extents->clip->boxes, 1);
1140 } else {
1141 cairo_box_t limits;
1142 _cairo_box_from_rectangle (&limits, &extents->unbounded);
1143 _cairo_polygon_init (&polygon, &limits, 1);
1146 else
1148 _cairo_polygon_init (&polygon, NULL, 0);
1151 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1152 TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1153 polygon.num_limits = 0;
1155 if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
1156 TRACE((stderr, "%s - polygon intersect with %d clip boxes\n",
1157 __FUNCTION__, extents->clip->num_boxes));
1158 status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
1159 extents->clip->boxes,
1160 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;
1166 if (extents->is_bounded) {
1167 TRACE((stderr, "%s - polygon discard clip boxes\n",
1168 __FUNCTION__));
1169 extents->clip = _cairo_clip_copy_path (extents->clip);
1170 extents->clip = _cairo_clip_intersect_box(extents->clip,
1171 &polygon.extents);
1174 status = clip_and_composite_polygon (compositor, extents, &polygon,
1175 fill_rule, antialias);
1177 if (extents->is_bounded) {
1178 _cairo_clip_destroy (extents->clip);
1179 extents->clip = saved_clip;
1182 _cairo_polygon_fini (&polygon);
1184 TRACE((stderr, "%s - polygon status=%d\n", __FUNCTION__, status));
1187 return status;
1190 void
1191 _cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
1192 const cairo_compositor_t *delegate)
1194 compositor->base.delegate = delegate;
1196 compositor->base.paint = _cairo_spans_compositor_paint;
1197 compositor->base.mask = _cairo_spans_compositor_mask;
1198 compositor->base.fill = _cairo_spans_compositor_fill;
1199 compositor->base.stroke = _cairo_spans_compositor_stroke;
1200 compositor->base.glyphs = NULL;