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-box-inline.h"
45 #include "cairo-boxes-private.h"
46 #include "cairo-clip-inline.h"
47 #include "cairo-clip-private.h"
48 #include "cairo-composite-rectangles-private.h"
49 #include "cairo-compositor-private.h"
50 #include "cairo-error-private.h"
51 #include "cairo-image-surface-private.h"
52 #include "cairo-pattern-inline.h"
53 #include "cairo-paginated-private.h"
54 #include "cairo-recording-surface-inline.h"
55 #include "cairo-surface-subsurface-private.h"
56 #include "cairo-surface-snapshot-inline.h"
57 #include "cairo-surface-observer-private.h"
58 #include "cairo-region-private.h"
59 #include "cairo-spans-private.h"
60 #include "cairo-traps-private.h"
61 #include "cairo-tristrip-private.h"
62 #include "cairo-ttrace.h"
64 typedef cairo_int_status_t
65 (*draw_func_t) (const cairo_traps_compositor_t *compositor,
74 const cairo_rectangle_int_t *extents,
77 static void do_unaligned_row(void (*blt)(void *closure,
86 int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
87 int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
89 if (! _cairo_fixed_is_integer (b->p1.x)) {
90 blt(closure, x1, y, 1, h,
91 coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
96 blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
98 if (! _cairo_fixed_is_integer (b->p2.x))
99 blt(closure, x2, y, 1, h,
100 coverage * _cairo_fixed_fractional_part (b->p2.x));
102 blt(closure, x1, y, 1, h,
103 coverage * (b->p2.x - b->p1.x));
106 static void do_unaligned_box(void (*blt)(void *closure,
107 int16_t x, int16_t y,
108 int16_t w, int16_t h,
111 const cairo_box_t *b, int tx, int ty)
113 int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
114 int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
116 if (! _cairo_fixed_is_integer (b->p1.y)) {
117 do_unaligned_row(blt, closure, b, tx, y1, 1,
118 256 - _cairo_fixed_fractional_part (b->p1.y));
123 do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
125 if (! _cairo_fixed_is_integer (b->p2.y))
126 do_unaligned_row(blt, closure, b, tx, y2, 1,
127 _cairo_fixed_fractional_part (b->p2.y));
129 do_unaligned_row(blt, closure, b, tx, y1, 1,
134 const cairo_traps_compositor_t *compositor;
135 cairo_surface_t *dst;
139 static void blt_in(void *closure,
140 int16_t x, int16_t y,
141 int16_t w, int16_t h,
144 struct blt_in *info = closure;
147 if (CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage))
150 _cairo_box_from_integers (&info->boxes.chunks.base[0], x, y, w, h);
152 _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff);
153 info->compositor->fill_boxes (info->dst,
154 CAIRO_OPERATOR_IN, &color,
159 add_rect_with_offset (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2, int dx, int dy)
162 cairo_int_status_t status;
164 box.p1.x = _cairo_fixed_from_int (x1 - dx);
165 box.p1.y = _cairo_fixed_from_int (y1 - dy);
166 box.p2.x = _cairo_fixed_from_int (x2 - dx);
167 box.p2.y = _cairo_fixed_from_int (y2 - dy);
169 status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
170 assert (status == CAIRO_INT_STATUS_SUCCESS);
173 static cairo_int_status_t
174 combine_clip_as_traps (const cairo_traps_compositor_t *compositor,
175 cairo_surface_t *mask,
176 const cairo_clip_t *clip,
177 const cairo_rectangle_int_t *extents,
178 const cairo_bool_t draw_color_glyph)
180 cairo_polygon_t polygon;
181 cairo_fill_rule_t fill_rule;
182 cairo_antialias_t antialias;
184 cairo_surface_t *src;
186 cairo_rectangle_int_t fixup;
188 cairo_int_status_t status;
190 TRACE ((stderr, "%s\n", __FUNCTION__));
192 status = _cairo_clip_get_polygon (clip, &polygon,
193 &fill_rule, &antialias);
197 _cairo_traps_init (&traps);
198 status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
201 _cairo_polygon_fini (&polygon);
202 if (unlikely (status))
205 src = compositor->pattern_to_surface (mask, NULL, FALSE,
208 if (unlikely (src->status)) {
209 _cairo_traps_fini (&traps);
213 if (draw_color_glyph)
214 status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, mask,
216 extents->x, extents->y,
220 status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, src,
222 extents->x, extents->y,
226 _cairo_traps_extents (&traps, &box);
227 _cairo_box_round_to_rectangle (&box, &fixup);
228 _cairo_traps_fini (&traps);
229 cairo_surface_destroy (src);
231 if (unlikely (status))
234 if (! _cairo_rectangle_intersect (&fixup, extents))
235 return CAIRO_STATUS_SUCCESS;
237 if (fixup.width < extents->width || fixup.height < extents->height) {
240 _cairo_boxes_init (&clear);
243 if (fixup.y != extents->y) {
244 add_rect_with_offset (&clear,
245 extents->x, extents->y,
246 extents->x + extents->width,
248 extents->x, extents->y);
251 if (fixup.x != extents->x) {
252 add_rect_with_offset (&clear,
255 fixup.y + fixup.height,
256 extents->x, extents->y);
259 if (fixup.x + fixup.width != extents->x + extents->width) {
260 add_rect_with_offset (&clear,
261 fixup.x + fixup.width,
263 extents->x + extents->width,
264 fixup.y + fixup.height,
265 extents->x, extents->y);
268 if (fixup.y + fixup.height != extents->y + extents->height) {
269 add_rect_with_offset (&clear,
271 fixup.y + fixup.height,
272 extents->x + extents->width,
273 extents->y + extents->height,
274 extents->x, extents->y);
277 status = compositor->fill_boxes (mask,
278 CAIRO_OPERATOR_CLEAR,
279 CAIRO_COLOR_TRANSPARENT,
282 _cairo_boxes_fini (&clear);
288 static cairo_status_t
289 __clip_to_surface (const cairo_traps_compositor_t *compositor,
290 const cairo_composite_rectangles_t *composite,
291 const cairo_rectangle_int_t *extents,
292 cairo_surface_t **surface)
294 cairo_surface_t *mask;
295 cairo_polygon_t polygon;
296 cairo_fill_rule_t fill_rule;
297 cairo_antialias_t antialias;
300 cairo_surface_t *src;
302 cairo_int_status_t status;
304 TRACE ((stderr, "%s\n", __FUNCTION__));
306 status = _cairo_clip_get_polygon (composite->clip, &polygon,
307 &fill_rule, &antialias);
311 _cairo_traps_init (&traps);
312 status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
315 _cairo_polygon_fini (&polygon);
316 if (unlikely (status))
319 mask = _cairo_surface_create_scratch (composite->surface,
324 if (unlikely (mask->status)) {
325 _cairo_traps_fini (&traps);
329 src = compositor->pattern_to_surface (mask, NULL, FALSE,
332 if (unlikely (status = src->status))
335 status = compositor->acquire (mask);
336 if (unlikely (status))
339 _cairo_boxes_init_from_rectangle (&clear,
343 status = compositor->fill_boxes (mask,
344 CAIRO_OPERATOR_CLEAR,
345 CAIRO_COLOR_TRANSPARENT,
347 if (unlikely (status))
350 status = compositor->composite_traps (mask, CAIRO_OPERATOR_ADD, src,
352 extents->x, extents->y,
355 if (unlikely (status))
358 compositor->release (mask);
361 cairo_surface_destroy (src);
362 _cairo_traps_fini (&traps);
366 compositor->release (mask);
368 cairo_surface_destroy (mask);
372 static cairo_surface_t *
373 traps_get_clip_surface (const cairo_traps_compositor_t *compositor,
374 const cairo_composite_rectangles_t *composite,
375 const cairo_rectangle_int_t *extents)
377 cairo_surface_t *surface = NULL;
378 cairo_int_status_t status;
380 TRACE ((stderr, "%s\n", __FUNCTION__));
382 status = __clip_to_surface (compositor, composite, extents, &surface);
383 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
384 surface = _cairo_surface_create_scratch (composite->surface,
389 if (unlikely (surface->status))
392 status = _cairo_clip_combine_with_surface (composite->clip, surface,
393 extents->x, extents->y);
395 if (unlikely (status)) {
396 cairo_surface_destroy (surface);
397 surface = _cairo_surface_create_in_error (status);
403 static void blt_unaligned_boxes(const cairo_traps_compositor_t *compositor,
404 cairo_surface_t *surface,
412 info.compositor = compositor;
414 _cairo_boxes_init (&info.boxes);
415 info.boxes.num_boxes = 1;
416 for (i = 0; i < num_boxes; i++) {
417 cairo_box_t *b = &boxes[i];
419 if (! _cairo_fixed_is_integer (b->p1.x) ||
420 ! _cairo_fixed_is_integer (b->p1.y) ||
421 ! _cairo_fixed_is_integer (b->p2.x) ||
422 ! _cairo_fixed_is_integer (b->p2.y))
424 do_unaligned_box(blt_in, &info, b, dx, dy);
429 static cairo_surface_t *
430 create_composite_mask (const cairo_traps_compositor_t *compositor,
431 cairo_surface_t *dst,
433 draw_func_t draw_func,
434 draw_func_t mask_func,
435 const cairo_composite_rectangles_t *extents)
437 cairo_surface_t *surface, *src;
438 cairo_int_status_t status;
440 cairo_bool_t draw_color_glyph = FALSE;
442 TRACE ((stderr, "%s\n", __FUNCTION__));
444 surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA,
445 extents->bounded.width,
446 extents->bounded.height,
448 if (unlikely (surface->status))
451 /* FIXME: This is more like an ugly hack and wasteful. Reason
452 for this code is that we don't know whether the mask surface
453 should alpha-only or argb32 before we render a glyph.
456 src = compositor->pattern_to_surface (surface,
457 &_cairo_pattern_white.base,
462 if (unlikely (src->status)) {
463 cairo_surface_destroy (surface);
467 status = compositor->acquire (surface);
468 if (unlikely (status)) {
469 cairo_surface_destroy (src);
470 cairo_surface_destroy (surface);
471 return _cairo_surface_create_in_error (status);
474 if (!surface->is_clear) {
477 _cairo_boxes_init_from_rectangle (&clear,
479 extents->bounded.width,
480 extents->bounded.height);
481 status = compositor->fill_boxes (surface,
482 CAIRO_OPERATOR_CLEAR,
483 CAIRO_COLOR_TRANSPARENT,
485 if (unlikely (status))
488 surface->is_clear = TRUE;
492 status = mask_func (compositor, surface, draw_closure,
493 CAIRO_OPERATOR_SOURCE, src, src_x, src_y,
494 extents->bounded.x, extents->bounded.y,
495 &extents->bounded, extents->clip);
496 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
497 surface->is_clear = FALSE;
500 if (unlikely (status != CAIRO_INT_STATUS_UNSUPPORTED))
504 /* Is it worth setting the clip region here? */
505 status = draw_func (compositor, surface, draw_closure,
506 CAIRO_OPERATOR_ADD, src, src_x, src_y,
507 extents->bounded.x, extents->bounded.y,
508 &extents->bounded, NULL);
509 if (unlikely (status)) {
510 if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR_ALPHA)
513 compositor->release (surface);
514 cairo_surface_destroy (surface);
515 cairo_surface_destroy (src);
516 surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_COLOR_ALPHA,
517 extents->bounded.width,
518 extents->bounded.height);
519 if (unlikely (surface->status))
521 /* we are drawing color glyph */
522 draw_color_glyph = TRUE;
527 surface->is_clear = FALSE;
528 if (extents->clip->path != NULL) {
529 status = combine_clip_as_traps (compositor, surface,
530 extents->clip, &extents->bounded,
532 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
533 status = _cairo_clip_combine_with_surface (extents->clip, surface,
537 if (unlikely (status))
539 } else if (extents->clip->boxes) {
540 blt_unaligned_boxes(compositor, surface,
541 extents->bounded.x, extents->bounded.y,
542 extents->clip->boxes, extents->clip->num_boxes);
547 compositor->release (surface);
548 cairo_surface_destroy (src);
552 compositor->release (surface);
553 if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
554 cairo_surface_destroy (surface);
555 surface = _cairo_surface_create_in_error (status);
557 cairo_surface_destroy (src);
561 /* Handles compositing with a clip surface when the operator allows
562 * us to combine the clip with the mask
564 static cairo_status_t
565 clip_and_composite_with_mask (const cairo_traps_compositor_t *compositor,
566 const cairo_composite_rectangles_t*extents,
567 draw_func_t draw_func,
568 draw_func_t mask_func,
571 cairo_surface_t *src,
572 int src_x, int src_y)
574 cairo_surface_t *dst = extents->surface;
575 cairo_surface_t *mask;
577 TRACE ((stderr, "%s\n", __FUNCTION__));
579 mask = create_composite_mask (compositor, dst, draw_closure,
580 draw_func, mask_func,
582 if (unlikely (mask->status))
588 if (mask->content == CAIRO_CONTENT_ALPHA) {
589 /* This is real mask */
590 if (src != NULL || dst->content != CAIRO_CONTENT_ALPHA) {
591 compositor->composite (dst, op, src, mask,
592 extents->bounded.x + src_x,
593 extents->bounded.y + src_y,
595 extents->bounded.x, extents->bounded.y,
596 extents->bounded.width, extents->bounded.height);
598 compositor->composite (dst, op, mask, NULL,
601 extents->bounded.x, extents->bounded.y,
602 extents->bounded.width, extents->bounded.height);
606 compositor->composite (dst, op, mask, NULL,
608 extents->bounded.x + src_x,
609 extents->bounded.y + src_y,
610 extents->bounded.x, extents->bounded.y,
611 extents->bounded.width, extents->bounded.height);
614 cairo_surface_destroy (mask);
615 return CAIRO_STATUS_SUCCESS;
618 /* Handles compositing with a clip surface when we have to do the operation
619 * in two pieces and combine them together.
621 static cairo_status_t
622 clip_and_composite_combine (const cairo_traps_compositor_t *compositor,
623 const cairo_composite_rectangles_t*extents,
624 draw_func_t draw_func,
627 cairo_surface_t *src,
628 int src_x, int src_y)
630 cairo_surface_t *dst = extents->surface;
631 cairo_surface_t *tmp, *clip;
632 cairo_status_t status;
634 TRACE ((stderr, "%s\n", __FUNCTION__));
636 tmp = _cairo_surface_create_scratch (dst, dst->content,
637 extents->bounded.width,
638 extents->bounded.height,
640 if (unlikely (tmp->status)) {
641 status = tmp->status;
642 cairo_surface_destroy (tmp);
646 status = compositor->acquire (tmp);
647 if (unlikely (status)) {
648 cairo_surface_destroy (tmp);
652 compositor->composite (tmp,
653 dst->is_clear ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
655 extents->bounded.x, extents->bounded.y,
658 extents->bounded.width, extents->bounded.height);
660 status = draw_func (compositor, tmp, draw_closure, op,
662 extents->bounded.x, extents->bounded.y,
663 &extents->bounded, NULL);
665 if (unlikely (status))
668 clip = traps_get_clip_surface (compositor, extents, &extents->bounded);
669 if (unlikely ((status = clip->status)))
673 compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
676 extents->bounded.x, extents->bounded.y,
677 extents->bounded.width, extents->bounded.height);
679 compositor->lerp (dst, tmp, clip,
682 extents->bounded.x, extents->bounded.y,
683 extents->bounded.width, extents->bounded.height);
685 cairo_surface_destroy (clip);
688 compositor->release (tmp);
689 cairo_surface_destroy (tmp);
694 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
695 * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
697 static cairo_status_t
698 clip_and_composite_source (const cairo_traps_compositor_t *compositor,
699 cairo_surface_t *dst,
700 draw_func_t draw_func,
701 draw_func_t mask_func,
703 cairo_surface_t *src,
706 const cairo_composite_rectangles_t *extents)
708 cairo_surface_t *mask = NULL;
709 /* create a white color pattern */
710 cairo_pattern_t *white_pattern = _cairo_pattern_create_solid (CAIRO_COLOR_WHITE);
711 cairo_surface_t *white_mask =
712 compositor->pattern_to_surface (dst, white_pattern, TRUE,
714 &extents->source_sample_area,
716 if (unlikely (white_mask->status))
719 TRACE ((stderr, "%s\n", __FUNCTION__));
721 /* Create a surface that is mask IN clip */
722 mask = create_composite_mask (compositor, dst, draw_closure,
723 draw_func, mask_func,
725 if (unlikely (mask->status))
732 compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask,
733 extents->bounded.x + src_x, extents->bounded.y + src_y,
735 extents->bounded.x, extents->bounded.y,
736 extents->bounded.width, extents->bounded.height);
738 if (mask->content == CAIRO_CONTENT_ALPHA)
739 compositor->lerp (dst, src, mask,
740 extents->bounded.x + src_x, extents->bounded.y + src_y,
742 extents->bounded.x, extents->bounded.y,
743 extents->bounded.width, extents->bounded.height);
745 compositor->lerp_color_glyph (dst, mask, white_mask,
747 extents->bounded.x + src_x, extents->bounded.y + src_y,
748 extents->bounded.x, extents->bounded.y,
749 extents->bounded.width, extents->bounded.height);
753 cairo_surface_destroy (mask);
754 cairo_surface_destroy (white_mask);
755 cairo_pattern_destroy (white_pattern);
757 return CAIRO_STATUS_SUCCESS;
761 can_reduce_alpha_op (cairo_operator_t op)
765 case CAIRO_OPERATOR_OVER:
766 case CAIRO_OPERATOR_SOURCE:
767 case CAIRO_OPERATOR_ADD:
775 reduce_alpha_op (cairo_composite_rectangles_t *extents)
777 cairo_surface_t *dst = extents->surface;
778 cairo_operator_t op = extents->op;
779 const cairo_pattern_t *pattern = &extents->source_pattern.base;
780 return dst->is_clear &&
781 dst->content == CAIRO_CONTENT_ALPHA &&
782 _cairo_pattern_is_opaque_solid (pattern) &&
783 can_reduce_alpha_op (op);
786 static cairo_status_t
787 fixup_unbounded_with_mask (const cairo_traps_compositor_t *compositor,
788 const cairo_composite_rectangles_t *extents)
790 cairo_surface_t *dst = extents->surface;
791 cairo_surface_t *mask;
793 TRACE ((stderr, "%s\n", __FUNCTION__));
795 /* XXX can we avoid querying the clip surface again? */
796 mask = traps_get_clip_surface (compositor, extents, &extents->unbounded);
797 if (unlikely (mask->status))
801 if (extents->bounded.y != extents->unbounded.y) {
802 int x = extents->unbounded.x;
803 int y = extents->unbounded.y;
804 int width = extents->unbounded.width;
805 int height = extents->bounded.y - y;
807 compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
815 if (extents->bounded.x != extents->unbounded.x) {
816 int x = extents->unbounded.x;
817 int y = extents->bounded.y;
818 int width = extents->bounded.x - x;
819 int height = extents->bounded.height;
821 compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
822 0, y - extents->unbounded.y,
829 if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
830 int x = extents->bounded.x + extents->bounded.width;
831 int y = extents->bounded.y;
832 int width = extents->unbounded.x + extents->unbounded.width - x;
833 int height = extents->bounded.height;
835 compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
836 x - extents->unbounded.x, y - extents->unbounded.y,
843 if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
844 int x = extents->unbounded.x;
845 int y = extents->bounded.y + extents->bounded.height;
846 int width = extents->unbounded.width;
847 int height = extents->unbounded.y + extents->unbounded.height - y;
849 compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
850 0, y - extents->unbounded.y,
856 cairo_surface_destroy (mask);
858 return CAIRO_STATUS_SUCCESS;
862 add_rect (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2)
865 cairo_int_status_t status;
867 box.p1.x = _cairo_fixed_from_int (x1);
868 box.p1.y = _cairo_fixed_from_int (y1);
869 box.p2.x = _cairo_fixed_from_int (x2);
870 box.p2.y = _cairo_fixed_from_int (y2);
872 status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
873 assert (status == CAIRO_INT_STATUS_SUCCESS);
876 static cairo_status_t
877 fixup_unbounded (const cairo_traps_compositor_t *compositor,
878 cairo_composite_rectangles_t *extents,
879 cairo_boxes_t *boxes)
881 cairo_surface_t *dst = extents->surface;
882 cairo_boxes_t clear, tmp;
884 cairo_int_status_t status;
886 TRACE ((stderr, "%s\n", __FUNCTION__));
888 if (extents->bounded.width == extents->unbounded.width &&
889 extents->bounded.height == extents->unbounded.height)
891 return CAIRO_STATUS_SUCCESS;
894 assert (extents->clip->path == NULL);
896 /* subtract the drawn boxes from the unbounded area */
897 _cairo_boxes_init (&clear);
899 box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
900 box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
901 box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
902 box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
905 if (extents->bounded.width == 0 || extents->bounded.height == 0) {
909 if (extents->bounded.y != extents->unbounded.y) {
911 extents->unbounded.x, extents->unbounded.y,
912 extents->unbounded.x + extents->unbounded.width,
916 if (extents->bounded.x != extents->unbounded.x) {
918 extents->unbounded.x, extents->bounded.y,
920 extents->bounded.y + extents->bounded.height);
923 if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
925 extents->bounded.x + extents->bounded.width,
927 extents->unbounded.x + extents->unbounded.width,
928 extents->bounded.y + extents->bounded.height);
931 if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
933 extents->unbounded.x,
934 extents->bounded.y + extents->bounded.height,
935 extents->unbounded.x + extents->unbounded.width,
936 extents->unbounded.y + extents->unbounded.height);
939 } else if (boxes->num_boxes) {
940 _cairo_boxes_init (&tmp);
942 assert (boxes->is_pixel_aligned);
944 status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
945 assert (status == CAIRO_INT_STATUS_SUCCESS);
947 tmp.chunks.next = &boxes->chunks;
948 tmp.num_boxes += boxes->num_boxes;
950 status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
951 CAIRO_FILL_RULE_WINDING,
953 tmp.chunks.next = NULL;
954 if (unlikely (status))
958 box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
959 box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
961 status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
962 assert (status == CAIRO_INT_STATUS_SUCCESS);
965 /* Now intersect with the clip boxes */
966 if (extents->clip->num_boxes) {
967 _cairo_boxes_init_for_array (&tmp,
968 extents->clip->boxes,
969 extents->clip->num_boxes);
970 status = _cairo_boxes_intersect (&clear, &tmp, &clear);
971 if (unlikely (status))
975 status = compositor->fill_boxes (dst,
976 CAIRO_OPERATOR_CLEAR,
977 CAIRO_COLOR_TRANSPARENT,
981 _cairo_boxes_fini (&clear);
986 NEED_CLIP_REGION = 0x1,
987 NEED_CLIP_SURFACE = 0x2,
988 FORCE_CLIP_REGION = 0x4,
992 need_bounded_clip (cairo_composite_rectangles_t *extents)
994 unsigned int flags = 0;
996 if (extents->clip->num_boxes > 1 ||
997 extents->mask.width > extents->unbounded.width ||
998 extents->mask.height > extents->unbounded.height)
1000 flags |= NEED_CLIP_REGION;
1003 if (extents->clip->num_boxes > 1 ||
1004 extents->mask.width > extents->bounded.width ||
1005 extents->mask.height > extents->bounded.height)
1007 flags |= FORCE_CLIP_REGION;
1010 if (! _cairo_clip_is_region (extents->clip))
1011 flags |= NEED_CLIP_SURFACE;
1017 need_unbounded_clip (cairo_composite_rectangles_t *extents)
1019 unsigned int flags = 0;
1020 if (! extents->is_bounded) {
1021 flags |= NEED_CLIP_REGION;
1022 if (! _cairo_clip_is_region (extents->clip))
1023 flags |= NEED_CLIP_SURFACE;
1025 if (extents->clip->path != NULL)
1026 flags |= NEED_CLIP_SURFACE;
1030 static cairo_status_t
1031 clip_and_composite (const cairo_traps_compositor_t *compositor,
1032 cairo_composite_rectangles_t *extents,
1033 draw_func_t draw_func,
1034 draw_func_t mask_func,
1036 unsigned int need_clip)
1038 cairo_surface_t *dst = extents->surface;
1039 cairo_operator_t op = extents->op;
1040 cairo_pattern_t *source = &extents->source_pattern.base;
1041 cairo_surface_t *src;
1043 cairo_region_t *clip_region = NULL;
1044 cairo_status_t status = CAIRO_STATUS_SUCCESS;
1046 TRACE ((stderr, "%s\n", __FUNCTION__));
1048 if (reduce_alpha_op (extents)) {
1049 op = CAIRO_OPERATOR_ADD;
1053 if (op == CAIRO_OPERATOR_CLEAR) {
1054 op = CAIRO_OPERATOR_DEST_OUT;
1058 compositor->acquire (dst);
1060 if (need_clip & NEED_CLIP_REGION) {
1061 const cairo_rectangle_int_t *limit;
1063 if ((need_clip & FORCE_CLIP_REGION) == 0)
1064 limit = &extents->unbounded;
1066 limit = &extents->destination;
1068 clip_region = _cairo_clip_get_region (extents->clip);
1069 if (clip_region != NULL &&
1070 cairo_region_contains_rectangle (clip_region,
1071 limit) == CAIRO_REGION_OVERLAP_IN)
1074 if (clip_region != NULL) {
1075 status = compositor->set_clip_region (dst, clip_region);
1076 if (unlikely (status)) {
1077 compositor->release (dst);
1083 if (extents->bounded.width == 0 || extents->bounded.height == 0)
1086 src = compositor->pattern_to_surface (dst, source, FALSE,
1088 &extents->source_sample_area,
1090 if (unlikely (status = src->status))
1093 if (op == CAIRO_OPERATOR_SOURCE) {
1094 status = clip_and_composite_source (compositor, dst,
1095 draw_func, mask_func, draw_closure,
1099 if (need_clip & NEED_CLIP_SURFACE) {
1100 if (extents->is_bounded) {
1101 status = clip_and_composite_with_mask (compositor, extents,
1102 draw_func, mask_func,
1104 op, src, src_x, src_y);
1106 status = clip_and_composite_combine (compositor, extents,
1107 draw_func, draw_closure,
1108 op, src, src_x, src_y);
1111 status = draw_func (compositor,
1113 op, src, src_x, src_y,
1119 cairo_surface_destroy (src);
1122 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
1123 if (need_clip & NEED_CLIP_SURFACE)
1124 status = fixup_unbounded_with_mask (compositor, extents);
1126 status = fixup_unbounded (compositor, extents, NULL);
1131 compositor->set_clip_region (dst, NULL);
1133 compositor->release (dst);
1141 cairo_traps_t traps;
1142 cairo_antialias_t antialias;
1143 } composite_traps_info_t;
1145 static cairo_int_status_t
1146 composite_traps (const cairo_traps_compositor_t *compositor,
1147 cairo_surface_t *dst,
1149 cairo_operator_t op,
1150 cairo_surface_t *src,
1151 int src_x, int src_y,
1152 int dst_x, int dst_y,
1153 const cairo_rectangle_int_t *extents,
1156 composite_traps_info_t *info = closure;
1158 TRACE ((stderr, "%s\n", __FUNCTION__));
1160 return compositor->composite_traps (dst, op, src,
1161 src_x - dst_x, src_y - dst_y,
1164 info->antialias, &info->traps);
1168 cairo_tristrip_t strip;
1169 cairo_antialias_t antialias;
1170 } composite_tristrip_info_t;
1172 static cairo_int_status_t
1173 composite_tristrip (const cairo_traps_compositor_t *compositor,
1174 cairo_surface_t *dst,
1176 cairo_operator_t op,
1177 cairo_surface_t *src,
1178 int src_x, int src_y,
1179 int dst_x, int dst_y,
1180 const cairo_rectangle_int_t *extents,
1183 composite_tristrip_info_t *info = closure;
1185 TRACE ((stderr, "%s\n", __FUNCTION__));
1187 return compositor->composite_tristrip (dst, op, src,
1188 src_x - dst_x, src_y - dst_y,
1191 info->antialias, &info->strip);
1195 is_recording_pattern (const cairo_pattern_t *pattern)
1197 cairo_surface_t *surface;
1199 if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
1202 surface = ((const cairo_surface_pattern_t *) pattern)->surface;
1203 surface = _cairo_surface_get_source (surface, NULL);
1204 return _cairo_surface_is_recording (surface);
1207 static cairo_surface_t *
1208 recording_pattern_get_surface (const cairo_pattern_t *pattern)
1210 cairo_surface_t *surface;
1212 surface = ((const cairo_surface_pattern_t *) pattern)->surface;
1213 return _cairo_surface_get_source (surface, NULL);
1217 recording_pattern_contains_sample (const cairo_pattern_t *pattern,
1218 const cairo_rectangle_int_t *sample)
1220 cairo_recording_surface_t *surface;
1222 if (! is_recording_pattern (pattern))
1225 if (pattern->extend == CAIRO_EXTEND_NONE)
1228 surface = (cairo_recording_surface_t *) recording_pattern_get_surface (pattern);
1229 if (surface->unbounded)
1232 return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
1236 op_reduces_to_source (cairo_composite_rectangles_t *extents)
1238 if (extents->op == CAIRO_OPERATOR_SOURCE)
1241 if (extents->surface->is_clear)
1242 return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
1247 static cairo_status_t
1248 composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
1249 cairo_composite_rectangles_t *extents,
1250 cairo_boxes_t *boxes)
1252 cairo_surface_t *dst = extents->surface;
1253 cairo_operator_t op = extents->op;
1254 cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (extents->clip);
1255 cairo_bool_t op_is_source;
1256 cairo_status_t status;
1258 TRACE ((stderr, "%s\n", __FUNCTION__));
1260 if (need_clip_mask &&
1261 (! extents->is_bounded || extents->op == CAIRO_OPERATOR_SOURCE))
1263 return CAIRO_INT_STATUS_UNSUPPORTED;
1266 op_is_source = op_reduces_to_source (extents);
1268 /* Are we just copying a recording surface? */
1269 if (! need_clip_mask && op_is_source &&
1270 recording_pattern_contains_sample (&extents->source_pattern.base,
1271 &extents->source_sample_area))
1273 cairo_clip_t *recording_clip;
1274 const cairo_pattern_t *source = &extents->source_pattern.base;
1275 const cairo_matrix_t *m;
1276 cairo_matrix_t matrix;
1278 /* XXX could also do tiling repeat modes... */
1280 /* first clear the area about to be overwritten */
1281 if (! dst->is_clear) {
1282 status = compositor->acquire (dst);
1283 if (unlikely (status))
1286 status = compositor->fill_boxes (dst,
1287 CAIRO_OPERATOR_CLEAR,
1288 CAIRO_COLOR_TRANSPARENT,
1290 compositor->release (dst);
1291 if (unlikely (status))
1295 m = &source->matrix;
1296 if (_cairo_surface_has_device_transform (dst)) {
1297 cairo_matrix_multiply (&matrix,
1299 &dst->device_transform);
1303 recording_clip = _cairo_clip_from_boxes (boxes);
1304 status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
1305 m, dst, recording_clip);
1306 _cairo_clip_destroy (recording_clip);
1311 status = compositor->acquire (dst);
1312 if (unlikely (status))
1315 if (! need_clip_mask &&
1316 (op == CAIRO_OPERATOR_CLEAR ||
1317 extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID))
1319 const cairo_color_t *color;
1321 if (op == CAIRO_OPERATOR_CLEAR) {
1322 color = CAIRO_COLOR_TRANSPARENT;
1324 color = &((cairo_solid_pattern_t *) &extents->source_pattern)->color;
1326 op = CAIRO_OPERATOR_SOURCE;
1329 status = compositor->fill_boxes (dst, op, color, boxes);
1333 cairo_surface_t *src, *mask = NULL;
1334 cairo_pattern_t *source = &extents->source_pattern.base;
1336 int mask_x = 0, mask_y = 0;
1338 if (need_clip_mask) {
1339 mask = traps_get_clip_surface (compositor,
1340 extents, &extents->bounded);
1341 if (unlikely (mask->status))
1342 return mask->status;
1344 mask_x = -extents->bounded.x;
1345 mask_y = -extents->bounded.y;
1347 if (op == CAIRO_OPERATOR_CLEAR) {
1349 op = CAIRO_OPERATOR_DEST_OUT;
1351 } else if (op_is_source)
1352 op = CAIRO_OPERATOR_SOURCE;
1354 src = compositor->pattern_to_surface (dst, source, FALSE,
1356 &extents->source_sample_area,
1358 if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
1359 status = compositor->composite_boxes (dst, op, src, mask,
1363 boxes, &extents->bounded);
1364 cairo_surface_destroy (src);
1366 status = src->status;
1368 cairo_surface_destroy (mask);
1371 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
1372 status = fixup_unbounded (compositor, extents, boxes);
1374 compositor->release (dst);
1379 static cairo_status_t
1380 upload_boxes (const cairo_traps_compositor_t *compositor,
1381 cairo_composite_rectangles_t *extents,
1382 cairo_boxes_t *boxes)
1384 cairo_surface_t *dst = extents->surface;
1385 const cairo_pattern_t *source = &extents->source_pattern.base;
1386 cairo_surface_t *src;
1387 cairo_rectangle_int_t limit;
1388 cairo_int_status_t status;
1391 TRACE ((stderr, "%s\n", __FUNCTION__));
1393 src = _cairo_pattern_get_source((cairo_surface_pattern_t *)source,
1395 if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
1396 return CAIRO_INT_STATUS_UNSUPPORTED;
1398 if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
1399 return CAIRO_INT_STATUS_UNSUPPORTED;
1401 /* Check that the data is entirely within the image */
1402 if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
1403 return CAIRO_INT_STATUS_UNSUPPORTED;
1405 if (extents->bounded.x + extents->bounded.width + tx > limit.x + limit.width ||
1406 extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
1407 return CAIRO_INT_STATUS_UNSUPPORTED;
1412 if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
1413 status = compositor->draw_image_boxes (dst,
1414 (cairo_image_surface_t *)src,
1417 status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
1423 static cairo_int_status_t
1424 trim_extents_to_traps (cairo_composite_rectangles_t *extents,
1425 cairo_traps_t *traps)
1429 _cairo_traps_extents (traps, &box);
1430 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
1433 static cairo_int_status_t
1434 trim_extents_to_tristrip (cairo_composite_rectangles_t *extents,
1435 cairo_tristrip_t *strip)
1439 _cairo_tristrip_extents (strip, &box);
1440 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
1443 static cairo_int_status_t
1444 trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
1445 cairo_boxes_t *boxes)
1449 _cairo_boxes_extents (boxes, &box);
1450 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
1453 static cairo_int_status_t
1454 boxes_for_traps (cairo_boxes_t *boxes,
1455 cairo_traps_t *traps,
1456 cairo_antialias_t antialias)
1460 /* first check that the traps are rectilinear */
1461 if (antialias == CAIRO_ANTIALIAS_NONE) {
1462 for (i = 0; i < traps->num_traps; i++) {
1463 const cairo_trapezoid_t *t = &traps->traps[i];
1464 if (_cairo_fixed_integer_round_down (t->left.p1.x) !=
1465 _cairo_fixed_integer_round_down (t->left.p2.x) ||
1466 _cairo_fixed_integer_round_down (t->right.p1.x) !=
1467 _cairo_fixed_integer_round_down (t->right.p2.x))
1469 return CAIRO_INT_STATUS_UNSUPPORTED;
1473 for (i = 0; i < traps->num_traps; i++) {
1474 const cairo_trapezoid_t *t = &traps->traps[i];
1475 if (t->left.p1.x != t->left.p2.x || t->right.p1.x != t->right.p2.x)
1476 return CAIRO_INT_STATUS_UNSUPPORTED;
1480 _cairo_boxes_init (boxes);
1482 boxes->chunks.base = (cairo_box_t *) traps->traps;
1483 boxes->chunks.size = traps->num_traps;
1485 if (antialias != CAIRO_ANTIALIAS_NONE) {
1486 for (i = j = 0; i < traps->num_traps; i++) {
1487 /* Note the traps and boxes alias so we need to take the local copies first. */
1488 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
1489 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
1490 cairo_fixed_t y1 = traps->traps[i].top;
1491 cairo_fixed_t y2 = traps->traps[i].bottom;
1493 if (x1 == x2 || y1 == y2)
1496 boxes->chunks.base[j].p1.x = x1;
1497 boxes->chunks.base[j].p1.y = y1;
1498 boxes->chunks.base[j].p2.x = x2;
1499 boxes->chunks.base[j].p2.y = y2;
1502 if (boxes->is_pixel_aligned) {
1503 boxes->is_pixel_aligned =
1504 _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
1505 _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
1509 boxes->is_pixel_aligned = TRUE;
1511 for (i = j = 0; i < traps->num_traps; i++) {
1512 /* Note the traps and boxes alias so we need to take the local copies first. */
1513 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
1514 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
1515 cairo_fixed_t y1 = traps->traps[i].top;
1516 cairo_fixed_t y2 = traps->traps[i].bottom;
1518 /* round down here to match Pixman's behavior when using traps. */
1519 boxes->chunks.base[j].p1.x = _cairo_fixed_round_down (x1);
1520 boxes->chunks.base[j].p1.y = _cairo_fixed_round_down (y1);
1521 boxes->chunks.base[j].p2.x = _cairo_fixed_round_down (x2);
1522 boxes->chunks.base[j].p2.y = _cairo_fixed_round_down (y2);
1523 j += (boxes->chunks.base[j].p1.x != boxes->chunks.base[j].p2.x &&
1524 boxes->chunks.base[j].p1.y != boxes->chunks.base[j].p2.y);
1527 boxes->chunks.count = j;
1528 boxes->num_boxes = j;
1530 return CAIRO_INT_STATUS_SUCCESS;
1533 static cairo_status_t
1534 clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
1535 cairo_composite_rectangles_t *extents,
1536 cairo_boxes_t *boxes);
1538 static cairo_status_t
1539 clip_and_composite_polygon (const cairo_traps_compositor_t *compositor,
1540 cairo_composite_rectangles_t *extents,
1541 cairo_polygon_t *polygon,
1542 cairo_antialias_t antialias,
1543 cairo_fill_rule_t fill_rule,
1546 composite_traps_info_t traps;
1547 cairo_surface_t *dst = extents->surface;
1548 cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
1549 cairo_int_status_t status;
1551 TRACE ((stderr, "%s\n", __FUNCTION__));
1553 if (polygon->num_edges == 0) {
1554 status = CAIRO_INT_STATUS_SUCCESS;
1556 if (! extents->is_bounded) {
1557 cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
1560 cairo_region_contains_rectangle (clip_region,
1561 &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
1564 if (clip_region != NULL) {
1565 status = compositor->set_clip_region (dst, clip_region);
1566 if (unlikely (status))
1571 status = fixup_unbounded_with_mask (compositor, extents);
1573 status = fixup_unbounded (compositor, extents, NULL);
1575 if (clip_region != NULL)
1576 compositor->set_clip_region (dst, NULL);
1582 if (extents->clip->path != NULL && extents->is_bounded) {
1583 cairo_polygon_t clipper;
1584 cairo_fill_rule_t clipper_fill_rule;
1585 cairo_antialias_t clipper_antialias;
1587 status = _cairo_clip_get_polygon (extents->clip,
1590 &clipper_antialias);
1591 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1592 if (clipper_antialias == antialias) {
1593 status = _cairo_polygon_intersect (polygon, fill_rule,
1594 &clipper, clipper_fill_rule);
1595 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1596 cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip);
1597 _cairo_clip_destroy (extents->clip);
1598 extents->clip = clip;
1600 fill_rule = CAIRO_FILL_RULE_WINDING;
1602 _cairo_polygon_fini (&clipper);
1607 if (antialias == CAIRO_ANTIALIAS_NONE && curvy) {
1608 cairo_boxes_t boxes;
1610 _cairo_boxes_init (&boxes);
1611 status = _cairo_rasterise_polygon_to_boxes (polygon, fill_rule, &boxes);
1612 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1613 assert (boxes.is_pixel_aligned);
1614 status = clip_and_composite_boxes (compositor, extents, &boxes);
1616 _cairo_boxes_fini (&boxes);
1617 if ((status != CAIRO_INT_STATUS_UNSUPPORTED))
1621 _cairo_traps_init (&traps.traps);
1623 if (antialias == CAIRO_ANTIALIAS_NONE && curvy) {
1624 status = _cairo_rasterise_polygon_to_traps (polygon, fill_rule, antialias, &traps.traps);
1626 status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
1628 if (unlikely (status))
1631 status = trim_extents_to_traps (extents, &traps.traps);
1632 if (unlikely (status))
1635 /* Use a fast path if the trapezoids consist of a set of boxes. */
1636 status = CAIRO_INT_STATUS_UNSUPPORTED;
1638 cairo_boxes_t boxes;
1640 status = boxes_for_traps (&boxes, &traps.traps, antialias);
1641 if (status == CAIRO_INT_STATUS_SUCCESS) {
1642 status = clip_and_composite_boxes (compositor, extents, &boxes);
1643 /* XXX need to reconstruct the traps! */
1644 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
1647 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1648 /* Otherwise render the trapezoids to a mask and composite in the usual
1651 unsigned int flags = 0;
1653 /* For unbounded operations, the X11 server will estimate the
1654 * affected rectangle and apply the operation to that. However,
1655 * there are cases where this is an overestimate (e.g. the
1656 * clip-fill-{eo,nz}-unbounded test).
1658 * The clip will trim that overestimate to our expectations.
1660 if (! extents->is_bounded)
1661 flags |= FORCE_CLIP_REGION;
1663 traps.antialias = antialias;
1664 status = clip_and_composite (compositor, extents,
1665 composite_traps, NULL, &traps,
1666 need_unbounded_clip (extents) | flags);
1670 _cairo_traps_fini (&traps.traps);
1675 struct composite_opacity_info {
1676 const cairo_traps_compositor_t *compositor;
1678 cairo_surface_t *dst;
1679 cairo_surface_t *src;
1684 static void composite_opacity(void *closure,
1685 int16_t x, int16_t y,
1686 int16_t w, int16_t h,
1689 struct composite_opacity_info *info = closure;
1690 const cairo_traps_compositor_t *compositor = info->compositor;
1691 cairo_surface_t *mask;
1693 cairo_color_t color;
1694 cairo_solid_pattern_t solid;
1696 _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage);
1697 _cairo_pattern_init_solid (&solid, &color);
1698 mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE,
1699 &_cairo_unbounded_rectangle,
1700 &_cairo_unbounded_rectangle,
1702 if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
1704 compositor->composite (info->dst, info->op, info->src, mask,
1705 x + info->src_x, y + info->src_y,
1710 compositor->composite (info->dst, info->op, mask, NULL,
1718 cairo_surface_destroy (mask);
1722 static cairo_int_status_t
1723 composite_opacity_boxes (const cairo_traps_compositor_t *compositor,
1724 cairo_surface_t *dst,
1726 cairo_operator_t op,
1727 cairo_surface_t *src,
1732 const cairo_rectangle_int_t *extents,
1735 const cairo_solid_pattern_t *mask = closure;
1736 struct composite_opacity_info info;
1739 TRACE ((stderr, "%s\n", __FUNCTION__));
1741 info.compositor = compositor;
1749 info.opacity = mask->color.alpha / (double) 0xffff;
1751 /* XXX for lots of boxes create a clip region for the fully opaque areas */
1752 for (i = 0; i < clip->num_boxes; i++)
1753 do_unaligned_box(composite_opacity, &info,
1754 &clip->boxes[i], dst_x, dst_y);
1756 return CAIRO_STATUS_SUCCESS;
1759 static cairo_int_status_t
1760 composite_boxes (const cairo_traps_compositor_t *compositor,
1761 cairo_surface_t *dst,
1763 cairo_operator_t op,
1764 cairo_surface_t *src,
1769 const cairo_rectangle_int_t *extents,
1772 cairo_traps_t traps;
1773 cairo_status_t status;
1775 TRACE ((stderr, "%s\n", __FUNCTION__));
1777 status = _cairo_traps_init_boxes (&traps, closure);
1778 if (unlikely (status))
1781 status = compositor->composite_traps (dst, op, src,
1782 src_x - dst_x, src_y - dst_y,
1785 CAIRO_ANTIALIAS_DEFAULT, &traps);
1786 _cairo_traps_fini (&traps);
1791 static cairo_status_t
1792 clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
1793 cairo_composite_rectangles_t *extents,
1794 cairo_boxes_t *boxes)
1796 cairo_int_status_t status;
1798 TRACE ((stderr, "%s\n", __FUNCTION__));
1800 if (boxes->num_boxes == 0 && extents->is_bounded)
1801 return CAIRO_STATUS_SUCCESS;
1803 status = trim_extents_to_boxes (extents, boxes);
1804 if (unlikely (status))
1807 if (boxes->is_pixel_aligned && extents->clip->path == NULL &&
1808 extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
1809 (op_reduces_to_source (extents) ||
1810 (extents->op == CAIRO_OPERATOR_OVER &&
1811 (extents->source_pattern.surface.surface->content & CAIRO_CONTENT_ALPHA) == 0)))
1813 status = upload_boxes (compositor, extents, boxes);
1814 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1818 /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
1819 if (extents->clip->path != NULL && extents->is_bounded) {
1820 cairo_polygon_t polygon;
1821 cairo_fill_rule_t fill_rule;
1822 cairo_antialias_t antialias;
1825 clip = _cairo_clip_copy (extents->clip);
1826 clip = _cairo_clip_intersect_boxes (clip, boxes);
1827 if (_cairo_clip_is_all_clipped (clip))
1828 return CAIRO_INT_STATUS_NOTHING_TO_DO;
1830 status = _cairo_clip_get_polygon (clip, &polygon,
1831 &fill_rule, &antialias);
1832 _cairo_clip_path_destroy (clip->path);
1834 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1835 cairo_clip_t *saved_clip = extents->clip;
1836 extents->clip = clip;
1838 status = clip_and_composite_polygon (compositor, extents, &polygon,
1839 antialias, fill_rule, FALSE);
1841 clip = extents->clip;
1842 extents->clip = saved_clip;
1844 _cairo_polygon_fini (&polygon);
1846 _cairo_clip_destroy (clip);
1848 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1852 /* Use a fast path if the boxes are pixel aligned (or nearly aligned!) */
1853 if (boxes->is_pixel_aligned) {
1854 status = composite_aligned_boxes (compositor, extents, boxes);
1855 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1859 return clip_and_composite (compositor, extents,
1860 composite_boxes, NULL, boxes,
1861 need_unbounded_clip (extents));
1864 static cairo_int_status_t
1865 composite_traps_as_boxes (const cairo_traps_compositor_t *compositor,
1866 cairo_composite_rectangles_t *extents,
1867 composite_traps_info_t *info)
1869 cairo_boxes_t boxes;
1871 TRACE ((stderr, "%s\n", __FUNCTION__));
1873 if (! _cairo_traps_to_boxes (&info->traps, info->antialias, &boxes))
1874 return CAIRO_INT_STATUS_UNSUPPORTED;
1876 return clip_and_composite_boxes (compositor, extents, &boxes);
1879 static cairo_int_status_t
1880 clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
1881 cairo_composite_rectangles_t *extents,
1882 composite_traps_info_t *info,
1885 cairo_int_status_t status;
1887 TRACE ((stderr, "%s\n", __FUNCTION__));
1889 status = trim_extents_to_traps (extents, &info->traps);
1890 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
1893 status = CAIRO_INT_STATUS_UNSUPPORTED;
1894 if ((flags & FORCE_CLIP_REGION) == 0)
1895 status = composite_traps_as_boxes (compositor, extents, info);
1896 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1897 /* For unbounded operations, the X11 server will estimate the
1898 * affected rectangle and apply the operation to that. However,
1899 * there are cases where this is an overestimate (e.g. the
1900 * clip-fill-{eo,nz}-unbounded test).
1902 * The clip will trim that overestimate to our expectations.
1904 if (! extents->is_bounded)
1905 flags |= FORCE_CLIP_REGION;
1907 status = clip_and_composite (compositor, extents,
1908 composite_traps, NULL, info,
1909 need_unbounded_clip (extents) | flags);
1915 static cairo_int_status_t
1916 clip_and_composite_tristrip (const cairo_traps_compositor_t *compositor,
1917 cairo_composite_rectangles_t *extents,
1918 composite_tristrip_info_t *info)
1920 cairo_int_status_t status;
1921 unsigned int flags = 0;
1923 TRACE ((stderr, "%s\n", __FUNCTION__));
1925 status = trim_extents_to_tristrip (extents, &info->strip);
1926 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
1929 if (! extents->is_bounded)
1930 flags |= FORCE_CLIP_REGION;
1932 status = clip_and_composite (compositor, extents,
1933 composite_tristrip, NULL, info,
1934 need_unbounded_clip (extents) | flags);
1939 struct composite_mask {
1940 cairo_surface_t *mask;
1944 static cairo_int_status_t
1945 composite_mask (const cairo_traps_compositor_t *compositor,
1946 cairo_surface_t *dst,
1948 cairo_operator_t op,
1949 cairo_surface_t *src,
1954 const cairo_rectangle_int_t *extents,
1957 struct composite_mask *data = closure;
1959 TRACE ((stderr, "%s\n", __FUNCTION__));
1962 compositor->composite (dst, op, src, data->mask,
1963 extents->x + src_x, extents->y + src_y,
1964 extents->x + data->mask_x, extents->y + data->mask_y,
1965 extents->x - dst_x, extents->y - dst_y,
1966 extents->width, extents->height);
1968 compositor->composite (dst, op, data->mask, NULL,
1969 extents->x + data->mask_x, extents->y + data->mask_y,
1971 extents->x - dst_x, extents->y - dst_y,
1972 extents->width, extents->height);
1975 return CAIRO_STATUS_SUCCESS;
1978 struct composite_box_info {
1979 const cairo_traps_compositor_t *compositor;
1980 cairo_surface_t *dst;
1981 cairo_surface_t *src;
1986 static void composite_box(void *closure,
1987 int16_t x, int16_t y,
1988 int16_t w, int16_t h,
1991 struct composite_box_info *info = closure;
1992 const cairo_traps_compositor_t *compositor = info->compositor;
1994 TRACE ((stderr, "%s\n", __FUNCTION__));
1996 if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) {
1997 cairo_surface_t *mask;
1998 cairo_color_t color;
1999 cairo_solid_pattern_t solid;
2002 _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff);
2003 _cairo_pattern_init_solid (&solid, &color);
2005 mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE,
2006 &_cairo_unbounded_rectangle,
2007 &_cairo_unbounded_rectangle,
2010 if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
2011 compositor->composite (info->dst, info->op, info->src, mask,
2012 x + info->src_x, y + info->src_y,
2018 cairo_surface_destroy (mask);
2020 compositor->composite (info->dst, info->op, info->src, NULL,
2021 x + info->src_x, y + info->src_y,
2028 static cairo_int_status_t
2029 composite_mask_clip_boxes (const cairo_traps_compositor_t *compositor,
2030 cairo_surface_t *dst,
2032 cairo_operator_t op,
2033 cairo_surface_t *src,
2038 const cairo_rectangle_int_t *extents,
2041 struct composite_mask *data = closure;
2042 struct composite_box_info info;
2045 TRACE ((stderr, "%s\n", __FUNCTION__));
2047 info.compositor = compositor;
2048 info.op = CAIRO_OPERATOR_SOURCE;
2050 info.src = data->mask;
2051 info.src_x = data->mask_x;
2052 info.src_y = data->mask_y;
2054 info.src_x += dst_x;
2055 info.src_y += dst_y;
2057 for (i = 0; i < clip->num_boxes; i++)
2058 do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
2060 return CAIRO_STATUS_SUCCESS;
2063 static cairo_int_status_t
2064 composite_mask_clip (const cairo_traps_compositor_t *compositor,
2065 cairo_surface_t *dst,
2067 cairo_operator_t op,
2068 cairo_surface_t *src,
2073 const cairo_rectangle_int_t *extents,
2076 struct composite_mask *data = closure;
2077 cairo_polygon_t polygon;
2078 cairo_fill_rule_t fill_rule;
2079 composite_traps_info_t info;
2080 cairo_status_t status;
2082 TRACE ((stderr, "%s\n", __FUNCTION__));
2084 status = _cairo_clip_get_polygon (clip, &polygon,
2085 &fill_rule, &info.antialias);
2086 if (unlikely (status))
2089 _cairo_traps_init (&info.traps);
2090 status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps,
2093 _cairo_polygon_fini (&polygon);
2094 if (unlikely (status))
2097 status = composite_traps (compositor, dst, &info,
2098 CAIRO_OPERATOR_SOURCE,
2100 data->mask_x + dst_x, data->mask_y + dst_y,
2103 _cairo_traps_fini (&info.traps);
2108 /* high-level compositor interface */
2110 static cairo_int_status_t
2111 _cairo_traps_compositor_paint (const cairo_compositor_t *_compositor,
2112 cairo_composite_rectangles_t *extents)
2114 CAIRO_TRACE_BEGIN (__func__);
2115 cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
2116 cairo_boxes_t boxes;
2117 cairo_int_status_t status;
2119 TRACE ((stderr, "%s\n", __FUNCTION__));
2121 status = compositor->check_composite (extents);
2122 if (unlikely (status)) {
2123 CAIRO_TRACE_END (__func__);
2127 _cairo_clip_steal_boxes (extents->clip, &boxes);
2128 status = clip_and_composite_boxes (compositor, extents, &boxes);
2129 _cairo_clip_unsteal_boxes (extents->clip, &boxes);
2131 CAIRO_TRACE_END (__func__);
2135 static cairo_int_status_t
2136 _cairo_traps_compositor_mask (const cairo_compositor_t *_compositor,
2137 cairo_composite_rectangles_t *extents)
2139 CAIRO_TRACE_BEGIN (__func__);
2140 const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
2141 cairo_int_status_t status;
2143 TRACE ((stderr, "%s\n", __FUNCTION__));
2145 status = compositor->check_composite (extents);
2146 if (unlikely (status)) {
2147 CAIRO_TRACE_END (__func__);
2151 if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
2152 extents->clip->path == NULL) {
2153 status = clip_and_composite (compositor, extents,
2154 composite_opacity_boxes,
2155 composite_opacity_boxes,
2156 &extents->mask_pattern,
2157 need_unbounded_clip (extents));
2159 struct composite_mask data;
2161 data.mask = compositor->pattern_to_surface (extents->surface,
2162 &extents->mask_pattern.base,
2165 &extents->mask_sample_area,
2168 if (unlikely (data.mask->status)) {
2169 CAIRO_TRACE_END (__func__);
2170 return data.mask->status;
2173 status = clip_and_composite (compositor, extents,
2175 extents->clip->path ? composite_mask_clip : composite_mask_clip_boxes,
2176 &data, need_bounded_clip (extents));
2178 cairo_surface_destroy (data.mask);
2181 CAIRO_TRACE_END (__func__);
2185 static cairo_int_status_t
2186 _cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor,
2187 cairo_composite_rectangles_t *extents,
2188 const cairo_path_fixed_t *path,
2189 const cairo_stroke_style_t *style,
2190 const cairo_matrix_t *ctm,
2191 const cairo_matrix_t *ctm_inverse,
2193 cairo_antialias_t antialias)
2195 CAIRO_TRACE_BEGIN (__func__);
2196 const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
2197 cairo_int_status_t status;
2199 TRACE ((stderr, "%s\n", __FUNCTION__));
2201 status = compositor->check_composite (extents);
2202 if (unlikely (status)) {
2203 CAIRO_TRACE_END (__func__);
2207 status = CAIRO_INT_STATUS_UNSUPPORTED;
2208 if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
2209 cairo_boxes_t boxes;
2211 _cairo_boxes_init_with_clip (&boxes, extents->clip);
2212 status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
2217 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2218 status = clip_and_composite_boxes (compositor, extents, &boxes);
2219 _cairo_boxes_fini (&boxes);
2222 if (status == CAIRO_INT_STATUS_UNSUPPORTED && 0 &&
2223 _cairo_clip_is_region (extents->clip)) /* XXX */
2225 composite_tristrip_info_t info;
2227 info.antialias = antialias;
2228 _cairo_tristrip_init_with_clip (&info.strip, extents->clip);
2229 status = _cairo_path_fixed_stroke_to_tristrip (path, style,
2233 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2234 status = clip_and_composite_tristrip (compositor, extents, &info);
2235 _cairo_tristrip_fini (&info.strip);
2238 if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
2239 path->has_curve_to && antialias == CAIRO_ANTIALIAS_NONE) {
2240 cairo_polygon_t polygon;
2242 _cairo_polygon_init_with_clip (&polygon, extents->clip);
2243 status = _cairo_path_fixed_stroke_to_polygon (path, style,
2247 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2248 status = clip_and_composite_polygon (compositor,
2250 CAIRO_ANTIALIAS_NONE,
2251 CAIRO_FILL_RULE_WINDING,
2253 _cairo_polygon_fini (&polygon);
2256 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
2257 cairo_int_status_t (*func) (const cairo_path_fixed_t *path,
2258 const cairo_stroke_style_t *stroke_style,
2259 const cairo_matrix_t *ctm,
2260 const cairo_matrix_t *ctm_inverse,
2262 cairo_traps_t *traps);
2263 composite_traps_info_t info;
2266 if (antialias == CAIRO_ANTIALIAS_BEST || antialias == CAIRO_ANTIALIAS_GOOD) {
2267 func = _cairo_path_fixed_stroke_polygon_to_traps;
2270 func = _cairo_path_fixed_stroke_to_traps;
2271 flags = need_bounded_clip (extents) & ~NEED_CLIP_SURFACE;
2274 info.antialias = antialias;
2275 _cairo_traps_init_with_clip (&info.traps, extents->clip);
2276 status = func (path, style, ctm, ctm_inverse, tolerance, &info.traps);
2277 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2278 status = clip_and_composite_traps (compositor, extents, &info, flags);
2279 _cairo_traps_fini (&info.traps);
2282 CAIRO_TRACE_END (__func__);
2286 static cairo_int_status_t
2287 _cairo_traps_compositor_fill (const cairo_compositor_t *_compositor,
2288 cairo_composite_rectangles_t *extents,
2289 const cairo_path_fixed_t *path,
2290 cairo_fill_rule_t fill_rule,
2292 cairo_antialias_t antialias)
2294 CAIRO_TRACE_BEGIN (__func__);
2295 const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
2296 cairo_int_status_t status;
2298 TRACE ((stderr, "%s\n", __FUNCTION__));
2300 status = compositor->check_composite (extents);
2301 if (unlikely (status)) {
2302 CAIRO_TRACE_END (__func__);
2306 status = CAIRO_INT_STATUS_UNSUPPORTED;
2307 if (_cairo_path_fixed_fill_is_rectilinear (path)) {
2308 cairo_boxes_t boxes;
2310 _cairo_boxes_init_with_clip (&boxes, extents->clip);
2311 status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
2315 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2316 status = clip_and_composite_boxes (compositor, extents, &boxes);
2317 _cairo_boxes_fini (&boxes);
2320 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
2321 cairo_polygon_t polygon;
2324 if (extents->mask.width > extents->unbounded.width ||
2325 extents->mask.height > extents->unbounded.height)
2328 _cairo_box_from_rectangle (&limits, &extents->unbounded);
2329 _cairo_polygon_init (&polygon, &limits, 1);
2333 _cairo_polygon_init (&polygon, NULL, 0);
2336 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
2337 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
2338 status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
2339 extents->clip->boxes,
2340 extents->clip->num_boxes);
2343 _cairo_polygon_init_with_clip (&polygon, extents->clip);
2344 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
2346 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
2347 status = clip_and_composite_polygon (compositor, extents, &polygon,
2348 antialias, fill_rule, path->has_curve_to);
2350 _cairo_polygon_fini (&polygon);
2353 CAIRO_TRACE_END (__func__);
2357 static cairo_int_status_t
2358 composite_glyphs (const cairo_traps_compositor_t *compositor,
2359 cairo_surface_t *dst,
2361 cairo_operator_t op,
2362 cairo_surface_t *src,
2363 int src_x, int src_y,
2364 int dst_x, int dst_y,
2365 const cairo_rectangle_int_t *extents,
2368 cairo_composite_glyphs_info_t *info = closure;
2370 TRACE ((stderr, "%s\n", __FUNCTION__));
2372 if (op == CAIRO_OPERATOR_ADD && (dst->content & CAIRO_CONTENT_COLOR) == 0)
2375 return compositor->composite_glyphs (dst, op, src,
2381 static cairo_int_status_t
2382 _cairo_traps_compositor_glyphs (const cairo_compositor_t *_compositor,
2383 cairo_composite_rectangles_t *extents,
2384 cairo_scaled_font_t *scaled_font,
2385 cairo_glyph_t *glyphs,
2387 cairo_bool_t overlap)
2389 CAIRO_TRACE_BEGIN (__func__);
2390 const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
2391 cairo_int_status_t status;
2393 TRACE ((stderr, "%s\n", __FUNCTION__));
2395 status = compositor->check_composite (extents);
2396 if (unlikely (status)) {
2397 CAIRO_TRACE_END (__func__);
2401 _cairo_scaled_font_freeze_cache (scaled_font);
2402 status = compositor->check_composite_glyphs (extents,
2403 scaled_font, glyphs,
2405 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
2406 cairo_composite_glyphs_info_t info;
2408 info.font = scaled_font;
2409 info.glyphs = glyphs;
2410 info.num_glyphs = num_glyphs;
2411 info.use_mask = overlap || ! extents->is_bounded;
2412 info.extents = extents->bounded;
2414 status = clip_and_composite (compositor, extents,
2415 composite_glyphs, NULL, &info,
2416 need_bounded_clip (extents) | FORCE_CLIP_REGION);
2418 _cairo_scaled_font_thaw_cache (scaled_font);
2420 CAIRO_TRACE_END (__func__);
2425 _cairo_traps_compositor_init (cairo_traps_compositor_t *compositor,
2426 const cairo_compositor_t *delegate)
2428 compositor->base.delegate = delegate;
2430 compositor->base.paint = _cairo_traps_compositor_paint;
2431 compositor->base.mask = _cairo_traps_compositor_mask;
2432 compositor->base.fill = _cairo_traps_compositor_fill;
2433 compositor->base.stroke = _cairo_traps_compositor_stroke;
2434 compositor->base.glyphs = _cairo_traps_compositor_glyphs;