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
37 * Carl D. Worth <cworth@cworth.org>
38 * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
39 * Chris Wilson <chris@chris-wilson.co.uk>
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"
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
,
84 const cairo_clip_t
*clip
,
85 const cairo_rectangle_int_t
*extents
)
87 cairo_composite_rectangles_t composite
;
88 cairo_surface_t
*surface
;
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
;
98 surface
= _cairo_surface_create_scratch (dst
,
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
,
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
;
120 cairo_polygon_t intersect
;
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
;
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
,
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
,
166 &_cairo_pattern_white
.base
,
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
))
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
;
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
,
191 fill_rule
= clip_path
->fill_rule
;
192 polygon
.limits
= NULL
;
193 polygon
.num_limits
= 0;
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
,
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
))
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
,
218 &_cairo_pattern_white
.base
,
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
))
235 _cairo_polygon_fini (&polygon
);
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
;
261 status
= _cairo_composite_rectangles_init_for_boxes (&composite
,
263 CAIRO_OPERATOR_CLEAR
,
264 &_cairo_pattern_clear
.base
,
267 if (unlikely (status
))
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
);
280 cairo_surface_destroy (clip
);
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
)
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
,
316 CAIRO_OPERATOR_CLEAR
,
317 &_cairo_pattern_clear
.base
,
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
);
328 _cairo_polygon_fini (&polygon
);
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
;
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
,
371 tmp
.chunks
.next
= NULL
;
372 if (unlikely (status
))
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
);
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
))
398 if (clear
.is_pixel_aligned
) {
399 status
= compositor
->fill_boxes (extents
->surface
,
400 CAIRO_OPERATOR_CLEAR
,
401 CAIRO_COLOR_TRANSPARENT
,
404 cairo_composite_rectangles_t composite
;
406 status
= _cairo_composite_rectangles_init_for_boxes (&composite
,
408 CAIRO_OPERATOR_CLEAR
,
409 &_cairo_pattern_clear
.base
,
412 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
)) {
413 status
= composite_boxes (compositor
, &composite
, &clear
);
414 _cairo_composite_rectangles_fini (&composite
);
420 _cairo_boxes_fini (&clear
);
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
,
434 is_recording_pattern (const cairo_pattern_t
*pattern
)
436 cairo_surface_t
*surface
;
438 if (pattern
->type
!= CAIRO_PATTERN_TYPE_SURFACE
)
441 surface
= ((const cairo_surface_pattern_t
*) pattern
)->surface
;
442 return _cairo_surface_is_recording (surface
);
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
))
454 if (pattern
->extend
== CAIRO_EXTEND_NONE
)
457 surface
= (cairo_recording_surface_t
*) unwrap_source (pattern
);
458 if (surface
->unbounded
)
461 return _cairo_rectangle_contains_rectangle (&surface
->extents
, sample
);
465 op_reduces_to_source (const cairo_composite_rectangles_t
*extents
,
466 cairo_bool_t no_mask
)
468 if (extents
->op
== CAIRO_OPERATOR_SOURCE
)
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
);
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
;
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
;
513 if (src
->type
== CAIRO_SURFACE_TYPE_IMAGE
)
514 status
= compositor
->draw_image_boxes (dst
,
515 (cairo_image_surface_t
*)src
,
518 status
= compositor
->copy_boxes (dst
, src
, boxes
, &extents
->bounded
,
525 _clip_is_region (const cairo_clip_t
*clip
)
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
))
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? */
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
,
599 if (unlikely (status
))
602 dst
->is_clear
= TRUE
;
606 if (_cairo_surface_has_device_transform (dst
)) {
607 cairo_matrix_multiply (&matrix
,
609 &dst
->device_transform
);
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
);
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
;
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
;
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
,
642 if (unlikely (mask
->status
))
645 mask_x
= -extents
->bounded
.x
;
646 mask_y
= -extents
->bounded
.y
;
649 /* XXX but this is still ugly */
651 src
= compositor
->pattern_to_surface (dst
,
652 &extents
->mask_pattern
.base
,
655 &extents
->mask_sample_area
,
657 if (unlikely (src
->status
)) {
658 cairo_surface_destroy (mask
);
663 status
= compositor
->composite_boxes (mask
, CAIRO_OPERATOR_IN
,
668 boxes
, &extents
->bounded
);
670 cairo_surface_destroy (src
);
678 src
= compositor
->pattern_to_surface (dst
, source
, FALSE
,
680 &extents
->source_sample_area
,
682 if (likely (src
->status
== CAIRO_STATUS_SUCCESS
)) {
683 status
= compositor
->composite_boxes (dst
, op
, src
, mask
,
687 boxes
, &extents
->bounded
);
688 cairo_surface_destroy (src
);
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
);
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
;
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
;
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
);
745 converter
.base
.destroy (&converter
.base
);
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
;
764 needs_clip
= !_clip_is_region (extents
->clip
) || extents
->clip
->num_boxes
> 1;
765 TRACE ((stderr
, "%s - needs_clip=%d\n", __FUNCTION__
, 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
,
771 fill_rule
, antialias
);
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
,
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
,
786 status
= _cairo_mono_scan_converter_add_polygon (converter
, polygon
);
788 converter
= _cairo_tor_scan_converter_create (r
->x
, r
->y
,
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
);
805 converter
->destroy (converter
);
809 static cairo_int_status_t
810 trim_extents_to_boxes (cairo_composite_rectangles_t
*extents
,
811 cairo_boxes_t
*boxes
)
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
,
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
))
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
;
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
);
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
)
881 if (boxes
->is_pixel_aligned
) {
882 status
= composite_aligned_boxes (compositor
, extents
, boxes
);
883 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
887 status
= composite_boxes (compositor
, extents
, boxes
);
888 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
891 status
= _cairo_polygon_init_boxes (&polygon
, boxes
);
892 if (unlikely (status
))
895 status
= composite_polygon (compositor
, extents
, &polygon
,
896 CAIRO_FILL_RULE_WINDING
,
897 CAIRO_ANTIALIAS_DEFAULT
);
898 _cairo_polygon_fini (&polygon
);
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
))
919 if (_cairo_polygon_is_empty (polygon
)) {
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",
938 status
= _cairo_clip_get_polygon (extents
->clip
,
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
))
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
))
960 fill_rule
= CAIRO_FILL_RULE_WINDING
;
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
;
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
);
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
;
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
);
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
,
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
,
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
,
1049 if (extents
->clip
->num_boxes
== 1) {
1050 _cairo_polygon_init (&polygon
, extents
->clip
->boxes
, 1);
1053 _cairo_box_from_rectangle (&limits
, &extents
->unbounded
);
1054 _cairo_polygon_init (&polygon
, &limits
, 1);
1059 _cairo_polygon_init (&polygon
, NULL
, 0);
1061 status
= _cairo_path_fixed_stroke_to_polygon (path
,
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
,
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
);
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
,
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
,
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
,
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);
1142 _cairo_box_from_rectangle (&limits
, &extents
->unbounded
);
1143 _cairo_polygon_init (&polygon
, &limits
, 1);
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",
1169 extents
->clip
= _cairo_clip_copy_path (extents
->clip
);
1170 extents
->clip
= _cairo_clip_intersect_box(extents
->clip
,
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
));
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
;