beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-traps-compositor.c
blob3414fc2684a157aef75e5e5fd71b4eb5da548922
1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
6 * Copyright © 2011 Intel Corporation
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
34 * California.
36 * Contributor(s):
37 * Carl D. Worth <cworth@cworth.org>
38 * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
39 * Chris Wilson <chris@chris-wilson.co.uk>
42 #include "cairoint.h"
44 #include "cairo-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"
63 typedef cairo_int_status_t
64 (*draw_func_t) (const cairo_traps_compositor_t *compositor,
65 cairo_surface_t *dst,
66 void *closure,
67 cairo_operator_t op,
68 cairo_surface_t *src,
69 int src_x,
70 int src_y,
71 int dst_x,
72 int dst_y,
73 const cairo_rectangle_int_t *extents,
74 cairo_clip_t *clip);
76 static void do_unaligned_row(void (*blt)(void *closure,
77 int16_t x, int16_t y,
78 int16_t w, int16_t h,
79 uint16_t coverage),
80 void *closure,
81 const cairo_box_t *b,
82 int tx, int y, int h,
83 uint16_t coverage)
85 int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
86 int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
87 if (x2 > x1) {
88 if (! _cairo_fixed_is_integer (b->p1.x)) {
89 blt(closure, x1, y, 1, h,
90 coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
91 x1++;
94 if (x2 > x1)
95 blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
97 if (! _cairo_fixed_is_integer (b->p2.x))
98 blt(closure, x2, y, 1, h,
99 coverage * _cairo_fixed_fractional_part (b->p2.x));
100 } else
101 blt(closure, x1, y, 1, h,
102 coverage * (b->p2.x - b->p1.x));
105 static void do_unaligned_box(void (*blt)(void *closure,
106 int16_t x, int16_t y,
107 int16_t w, int16_t h,
108 uint16_t coverage),
109 void *closure,
110 const cairo_box_t *b, int tx, int ty)
112 int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
113 int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
114 if (y2 > y1) {
115 if (! _cairo_fixed_is_integer (b->p1.y)) {
116 do_unaligned_row(blt, closure, b, tx, y1, 1,
117 256 - _cairo_fixed_fractional_part (b->p1.y));
118 y1++;
121 if (y2 > y1)
122 do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
124 if (! _cairo_fixed_is_integer (b->p2.y))
125 do_unaligned_row(blt, closure, b, tx, y2, 1,
126 _cairo_fixed_fractional_part (b->p2.y));
127 } else
128 do_unaligned_row(blt, closure, b, tx, y1, 1,
129 b->p2.y - b->p1.y);
132 struct blt_in {
133 const cairo_traps_compositor_t *compositor;
134 cairo_surface_t *dst;
135 cairo_boxes_t boxes;
138 static void blt_in(void *closure,
139 int16_t x, int16_t y,
140 int16_t w, int16_t h,
141 uint16_t coverage)
143 struct blt_in *info = closure;
144 cairo_color_t color;
146 if (CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage))
147 return;
149 _cairo_box_from_integers (&info->boxes.chunks.base[0], x, y, w, h);
151 _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff);
152 info->compositor->fill_boxes (info->dst,
153 CAIRO_OPERATOR_IN, &color,
154 &info->boxes);
157 static void
158 add_rect_with_offset (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2, int dx, int dy)
160 cairo_box_t box;
161 cairo_int_status_t status;
163 box.p1.x = _cairo_fixed_from_int (x1 - dx);
164 box.p1.y = _cairo_fixed_from_int (y1 - dy);
165 box.p2.x = _cairo_fixed_from_int (x2 - dx);
166 box.p2.y = _cairo_fixed_from_int (y2 - dy);
168 status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
169 assert (status == CAIRO_INT_STATUS_SUCCESS);
172 static cairo_int_status_t
173 combine_clip_as_traps (const cairo_traps_compositor_t *compositor,
174 cairo_surface_t *mask,
175 const cairo_clip_t *clip,
176 const cairo_rectangle_int_t *extents)
178 cairo_polygon_t polygon;
179 cairo_fill_rule_t fill_rule;
180 cairo_antialias_t antialias;
181 cairo_traps_t traps;
182 cairo_surface_t *src;
183 cairo_box_t box;
184 cairo_rectangle_int_t fixup;
185 int src_x, src_y;
186 cairo_int_status_t status;
188 TRACE ((stderr, "%s\n", __FUNCTION__));
190 status = _cairo_clip_get_polygon (clip, &polygon,
191 &fill_rule, &antialias);
192 if (status)
193 return status;
195 _cairo_traps_init (&traps);
196 status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
197 &polygon,
198 fill_rule);
199 _cairo_polygon_fini (&polygon);
200 if (unlikely (status))
201 return status;
203 src = compositor->pattern_to_surface (mask, NULL, FALSE,
204 extents, NULL,
205 &src_x, &src_y);
206 if (unlikely (src->status)) {
207 _cairo_traps_fini (&traps);
208 return src->status;
211 status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, src,
212 src_x, src_y,
213 extents->x, extents->y,
214 extents,
215 antialias, &traps);
217 _cairo_traps_extents (&traps, &box);
218 _cairo_box_round_to_rectangle (&box, &fixup);
219 _cairo_traps_fini (&traps);
220 cairo_surface_destroy (src);
222 if (unlikely (status))
223 return status;
225 if (! _cairo_rectangle_intersect (&fixup, extents))
226 return CAIRO_STATUS_SUCCESS;
228 if (fixup.width < extents->width || fixup.height < extents->height) {
229 cairo_boxes_t clear;
231 _cairo_boxes_init (&clear);
233 /* top */
234 if (fixup.y != extents->y) {
235 add_rect_with_offset (&clear,
236 extents->x, extents->y,
237 extents->x + extents->width,
238 fixup.y,
239 extents->x, extents->y);
241 /* left */
242 if (fixup.x != extents->x) {
243 add_rect_with_offset (&clear,
244 extents->x, fixup.y,
245 fixup.x,
246 fixup.y + fixup.height,
247 extents->x, extents->y);
249 /* right */
250 if (fixup.x + fixup.width != extents->x + extents->width) {
251 add_rect_with_offset (&clear,
252 fixup.x + fixup.width,
253 fixup.y,
254 extents->x + extents->width,
255 fixup.y + fixup.height,
256 extents->x, extents->y);
258 /* bottom */
259 if (fixup.y + fixup.height != extents->y + extents->height) {
260 add_rect_with_offset (&clear,
261 extents->x,
262 fixup.y + fixup.height,
263 extents->x + extents->width,
264 extents->y + extents->height,
265 extents->x, extents->y);
268 status = compositor->fill_boxes (mask,
269 CAIRO_OPERATOR_CLEAR,
270 CAIRO_COLOR_TRANSPARENT,
271 &clear);
273 _cairo_boxes_fini (&clear);
276 return status;
279 static cairo_status_t
280 __clip_to_surface (const cairo_traps_compositor_t *compositor,
281 const cairo_composite_rectangles_t *composite,
282 const cairo_rectangle_int_t *extents,
283 cairo_surface_t **surface)
285 cairo_surface_t *mask;
286 cairo_polygon_t polygon;
287 cairo_fill_rule_t fill_rule;
288 cairo_antialias_t antialias;
289 cairo_traps_t traps;
290 cairo_boxes_t clear;
291 cairo_surface_t *src;
292 int src_x, src_y;
293 cairo_int_status_t status;
295 TRACE ((stderr, "%s\n", __FUNCTION__));
297 status = _cairo_clip_get_polygon (composite->clip, &polygon,
298 &fill_rule, &antialias);
299 if (status)
300 return status;
302 _cairo_traps_init (&traps);
303 status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
304 &polygon,
305 fill_rule);
306 _cairo_polygon_fini (&polygon);
307 if (unlikely (status))
308 return status;
310 mask = _cairo_surface_create_scratch (composite->surface,
311 CAIRO_CONTENT_ALPHA,
312 extents->width,
313 extents->height,
314 NULL);
315 if (unlikely (mask->status)) {
316 _cairo_traps_fini (&traps);
317 return status;
320 src = compositor->pattern_to_surface (mask, NULL, FALSE,
321 extents, NULL,
322 &src_x, &src_y);
323 if (unlikely (status = src->status))
324 goto error;
326 status = compositor->acquire (mask);
327 if (unlikely (status))
328 goto error;
330 _cairo_boxes_init_from_rectangle (&clear,
331 0, 0,
332 extents->width,
333 extents->height);
334 status = compositor->fill_boxes (mask,
335 CAIRO_OPERATOR_CLEAR,
336 CAIRO_COLOR_TRANSPARENT,
337 &clear);
338 if (unlikely (status))
339 goto error_release;
341 status = compositor->composite_traps (mask, CAIRO_OPERATOR_ADD, src,
342 src_x, src_y,
343 extents->x, extents->y,
344 extents,
345 antialias, &traps);
346 if (unlikely (status))
347 goto error_release;
349 compositor->release (mask);
350 *surface = mask;
351 out:
352 cairo_surface_destroy (src);
353 _cairo_traps_fini (&traps);
354 return status;
356 error_release:
357 compositor->release (mask);
358 error:
359 cairo_surface_destroy (mask);
360 goto out;
363 static cairo_surface_t *
364 traps_get_clip_surface (const cairo_traps_compositor_t *compositor,
365 const cairo_composite_rectangles_t *composite,
366 const cairo_rectangle_int_t *extents)
368 cairo_surface_t *surface = NULL;
369 cairo_int_status_t status;
371 TRACE ((stderr, "%s\n", __FUNCTION__));
373 status = __clip_to_surface (compositor, composite, extents, &surface);
374 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
375 surface = _cairo_surface_create_scratch (composite->surface,
376 CAIRO_CONTENT_ALPHA,
377 extents->width,
378 extents->height,
379 CAIRO_COLOR_WHITE);
380 if (unlikely (surface->status))
381 return surface;
383 status = _cairo_clip_combine_with_surface (composite->clip, surface,
384 extents->x, extents->y);
386 if (unlikely (status)) {
387 cairo_surface_destroy (surface);
388 surface = _cairo_surface_create_in_error (status);
391 return surface;
394 static void blt_unaligned_boxes(const cairo_traps_compositor_t *compositor,
395 cairo_surface_t *surface,
396 int dx, int dy,
397 cairo_box_t *boxes,
398 int num_boxes)
400 struct blt_in info;
401 int i;
403 info.compositor = compositor;
404 info.dst = surface;
405 _cairo_boxes_init (&info.boxes);
406 info.boxes.num_boxes = 1;
407 for (i = 0; i < num_boxes; i++) {
408 cairo_box_t *b = &boxes[i];
410 if (! _cairo_fixed_is_integer (b->p1.x) ||
411 ! _cairo_fixed_is_integer (b->p1.y) ||
412 ! _cairo_fixed_is_integer (b->p2.x) ||
413 ! _cairo_fixed_is_integer (b->p2.y))
415 do_unaligned_box(blt_in, &info, b, dx, dy);
420 static cairo_surface_t *
421 create_composite_mask (const cairo_traps_compositor_t *compositor,
422 cairo_surface_t *dst,
423 void *draw_closure,
424 draw_func_t draw_func,
425 draw_func_t mask_func,
426 const cairo_composite_rectangles_t *extents)
428 cairo_surface_t *surface, *src;
429 cairo_int_status_t status;
430 int src_x, src_y;
432 TRACE ((stderr, "%s\n", __FUNCTION__));
434 surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA,
435 extents->bounded.width,
436 extents->bounded.height,
437 NULL);
438 if (unlikely (surface->status))
439 return surface;
441 src = compositor->pattern_to_surface (surface,
442 &_cairo_pattern_white.base,
443 FALSE,
444 &extents->bounded,
445 &extents->bounded,
446 &src_x, &src_y);
447 if (unlikely (src->status)) {
448 cairo_surface_destroy (surface);
449 return src;
452 status = compositor->acquire (surface);
453 if (unlikely (status)) {
454 cairo_surface_destroy (src);
455 cairo_surface_destroy (surface);
456 return _cairo_surface_create_in_error (status);
459 if (!surface->is_clear) {
460 cairo_boxes_t clear;
462 _cairo_boxes_init_from_rectangle (&clear,
463 0, 0,
464 extents->bounded.width,
465 extents->bounded.height);
466 status = compositor->fill_boxes (surface,
467 CAIRO_OPERATOR_CLEAR,
468 CAIRO_COLOR_TRANSPARENT,
469 &clear);
470 if (unlikely (status))
471 goto error;
473 surface->is_clear = TRUE;
476 if (mask_func) {
477 status = mask_func (compositor, surface, draw_closure,
478 CAIRO_OPERATOR_SOURCE, src, src_x, src_y,
479 extents->bounded.x, extents->bounded.y,
480 &extents->bounded, extents->clip);
481 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
482 surface->is_clear = FALSE;
483 goto out;
485 if (unlikely (status != CAIRO_INT_STATUS_UNSUPPORTED))
486 goto error;
489 /* Is it worth setting the clip region here? */
490 status = draw_func (compositor, surface, draw_closure,
491 CAIRO_OPERATOR_ADD, src, src_x, src_y,
492 extents->bounded.x, extents->bounded.y,
493 &extents->bounded, NULL);
494 if (unlikely (status))
495 goto error;
497 surface->is_clear = FALSE;
498 if (extents->clip->path != NULL) {
499 status = combine_clip_as_traps (compositor, surface,
500 extents->clip, &extents->bounded);
501 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
502 status = _cairo_clip_combine_with_surface (extents->clip, surface,
503 extents->bounded.x,
504 extents->bounded.y);
506 if (unlikely (status))
507 goto error;
508 } else if (extents->clip->boxes) {
509 blt_unaligned_boxes(compositor, surface,
510 extents->bounded.x, extents->bounded.y,
511 extents->clip->boxes, extents->clip->num_boxes);
515 out:
516 compositor->release (surface);
517 cairo_surface_destroy (src);
518 return surface;
520 error:
521 compositor->release (surface);
522 if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
523 cairo_surface_destroy (surface);
524 surface = _cairo_surface_create_in_error (status);
526 cairo_surface_destroy (src);
527 return surface;
530 /* Handles compositing with a clip surface when the operator allows
531 * us to combine the clip with the mask
533 static cairo_status_t
534 clip_and_composite_with_mask (const cairo_traps_compositor_t *compositor,
535 const cairo_composite_rectangles_t*extents,
536 draw_func_t draw_func,
537 draw_func_t mask_func,
538 void *draw_closure,
539 cairo_operator_t op,
540 cairo_surface_t *src,
541 int src_x, int src_y)
543 cairo_surface_t *dst = extents->surface;
544 cairo_surface_t *mask;
546 TRACE ((stderr, "%s\n", __FUNCTION__));
548 mask = create_composite_mask (compositor, dst, draw_closure,
549 draw_func, mask_func,
550 extents);
551 if (unlikely (mask->status))
552 return mask->status;
554 if (mask->is_clear)
555 goto skip;
557 if (src != NULL || dst->content != CAIRO_CONTENT_ALPHA) {
558 compositor->composite (dst, op, src, mask,
559 extents->bounded.x + src_x,
560 extents->bounded.y + src_y,
561 0, 0,
562 extents->bounded.x, extents->bounded.y,
563 extents->bounded.width, extents->bounded.height);
564 } else {
565 compositor->composite (dst, op, mask, NULL,
566 0, 0,
567 0, 0,
568 extents->bounded.x, extents->bounded.y,
569 extents->bounded.width, extents->bounded.height);
572 skip:
573 cairo_surface_destroy (mask);
574 return CAIRO_STATUS_SUCCESS;
577 /* Handles compositing with a clip surface when we have to do the operation
578 * in two pieces and combine them together.
580 static cairo_status_t
581 clip_and_composite_combine (const cairo_traps_compositor_t *compositor,
582 const cairo_composite_rectangles_t*extents,
583 draw_func_t draw_func,
584 void *draw_closure,
585 cairo_operator_t op,
586 cairo_surface_t *src,
587 int src_x, int src_y)
589 cairo_surface_t *dst = extents->surface;
590 cairo_surface_t *tmp, *clip;
591 cairo_status_t status;
593 TRACE ((stderr, "%s\n", __FUNCTION__));
595 tmp = _cairo_surface_create_scratch (dst, dst->content,
596 extents->bounded.width,
597 extents->bounded.height,
598 NULL);
599 if (unlikely (tmp->status))
600 return tmp->status;
602 status = compositor->acquire (tmp);
603 if (unlikely (status)) {
604 cairo_surface_destroy (tmp);
605 return status;
608 compositor->composite (tmp,
609 dst->is_clear ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
610 dst, NULL,
611 extents->bounded.x, extents->bounded.y,
612 0, 0,
613 0, 0,
614 extents->bounded.width, extents->bounded.height);
616 status = draw_func (compositor, tmp, draw_closure, op,
617 src, src_x, src_y,
618 extents->bounded.x, extents->bounded.y,
619 &extents->bounded, NULL);
621 if (unlikely (status))
622 goto cleanup;
624 clip = traps_get_clip_surface (compositor, extents, &extents->bounded);
625 if (unlikely ((status = clip->status)))
626 goto cleanup;
628 if (dst->is_clear) {
629 compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
630 0, 0,
631 0, 0,
632 extents->bounded.x, extents->bounded.y,
633 extents->bounded.width, extents->bounded.height);
634 } else {
635 compositor->lerp (dst, tmp, clip,
636 0, 0,
637 0,0,
638 extents->bounded.x, extents->bounded.y,
639 extents->bounded.width, extents->bounded.height);
641 cairo_surface_destroy (clip);
643 cleanup:
644 compositor->release (tmp);
645 cairo_surface_destroy (tmp);
647 return status;
650 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
651 * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
653 static cairo_status_t
654 clip_and_composite_source (const cairo_traps_compositor_t *compositor,
655 cairo_surface_t *dst,
656 draw_func_t draw_func,
657 draw_func_t mask_func,
658 void *draw_closure,
659 cairo_surface_t *src,
660 int src_x,
661 int src_y,
662 const cairo_composite_rectangles_t *extents)
664 cairo_surface_t *mask;
666 TRACE ((stderr, "%s\n", __FUNCTION__));
668 /* Create a surface that is mask IN clip */
669 mask = create_composite_mask (compositor, dst, draw_closure,
670 draw_func, mask_func,
671 extents);
672 if (unlikely (mask->status))
673 return mask->status;
675 if (mask->is_clear)
676 goto skip;
678 if (dst->is_clear) {
679 compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask,
680 extents->bounded.x + src_x, extents->bounded.y + src_y,
681 0, 0,
682 extents->bounded.x, extents->bounded.y,
683 extents->bounded.width, extents->bounded.height);
684 } else {
685 compositor->lerp (dst, src, mask,
686 extents->bounded.x + src_x, extents->bounded.y + src_y,
687 0, 0,
688 extents->bounded.x, extents->bounded.y,
689 extents->bounded.width, extents->bounded.height);
692 skip:
693 cairo_surface_destroy (mask);
695 return CAIRO_STATUS_SUCCESS;
698 static cairo_bool_t
699 can_reduce_alpha_op (cairo_operator_t op)
701 int iop = op;
702 switch (iop) {
703 case CAIRO_OPERATOR_OVER:
704 case CAIRO_OPERATOR_SOURCE:
705 case CAIRO_OPERATOR_ADD:
706 return TRUE;
707 default:
708 return FALSE;
712 static cairo_bool_t
713 reduce_alpha_op (cairo_composite_rectangles_t *extents)
715 cairo_surface_t *dst = extents->surface;
716 cairo_operator_t op = extents->op;
717 const cairo_pattern_t *pattern = &extents->source_pattern.base;
718 return dst->is_clear &&
719 dst->content == CAIRO_CONTENT_ALPHA &&
720 _cairo_pattern_is_opaque_solid (pattern) &&
721 can_reduce_alpha_op (op);
724 static cairo_status_t
725 fixup_unbounded_with_mask (const cairo_traps_compositor_t *compositor,
726 const cairo_composite_rectangles_t *extents)
728 cairo_surface_t *dst = extents->surface;
729 cairo_surface_t *mask;
731 TRACE ((stderr, "%s\n", __FUNCTION__));
733 /* XXX can we avoid querying the clip surface again? */
734 mask = traps_get_clip_surface (compositor, extents, &extents->unbounded);
735 if (unlikely (mask->status))
736 return mask->status;
738 /* top */
739 if (extents->bounded.y != extents->unbounded.y) {
740 int x = extents->unbounded.x;
741 int y = extents->unbounded.y;
742 int width = extents->unbounded.width;
743 int height = extents->bounded.y - y;
745 compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
746 0, 0,
747 0, 0,
748 x, y,
749 width, height);
752 /* left */
753 if (extents->bounded.x != extents->unbounded.x) {
754 int x = extents->unbounded.x;
755 int y = extents->bounded.y;
756 int width = extents->bounded.x - x;
757 int height = extents->bounded.height;
759 compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
760 0, y - extents->unbounded.y,
761 0, 0,
762 x, y,
763 width, height);
766 /* right */
767 if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
768 int x = extents->bounded.x + extents->bounded.width;
769 int y = extents->bounded.y;
770 int width = extents->unbounded.x + extents->unbounded.width - x;
771 int height = extents->bounded.height;
773 compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
774 x - extents->unbounded.x, y - extents->unbounded.y,
775 0, 0,
776 x, y,
777 width, height);
780 /* bottom */
781 if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
782 int x = extents->unbounded.x;
783 int y = extents->bounded.y + extents->bounded.height;
784 int width = extents->unbounded.width;
785 int height = extents->unbounded.y + extents->unbounded.height - y;
787 compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
788 0, y - extents->unbounded.y,
789 0, 0,
790 x, y,
791 width, height);
794 cairo_surface_destroy (mask);
796 return CAIRO_STATUS_SUCCESS;
799 static void
800 add_rect (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2)
802 cairo_box_t box;
803 cairo_int_status_t status;
805 box.p1.x = _cairo_fixed_from_int (x1);
806 box.p1.y = _cairo_fixed_from_int (y1);
807 box.p2.x = _cairo_fixed_from_int (x2);
808 box.p2.y = _cairo_fixed_from_int (y2);
810 status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
811 assert (status == CAIRO_INT_STATUS_SUCCESS);
814 static cairo_status_t
815 fixup_unbounded (const cairo_traps_compositor_t *compositor,
816 cairo_composite_rectangles_t *extents,
817 cairo_boxes_t *boxes)
819 cairo_surface_t *dst = extents->surface;
820 cairo_boxes_t clear, tmp;
821 cairo_box_t box;
822 cairo_int_status_t status;
824 TRACE ((stderr, "%s\n", __FUNCTION__));
826 if (extents->bounded.width == extents->unbounded.width &&
827 extents->bounded.height == extents->unbounded.height)
829 return CAIRO_STATUS_SUCCESS;
832 assert (extents->clip->path == NULL);
834 /* subtract the drawn boxes from the unbounded area */
835 _cairo_boxes_init (&clear);
837 box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
838 box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
839 box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
840 box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
842 if (boxes == NULL) {
843 if (extents->bounded.width == 0 || extents->bounded.height == 0) {
844 goto empty;
845 } else {
846 /* top */
847 if (extents->bounded.y != extents->unbounded.y) {
848 add_rect (&clear,
849 extents->unbounded.x, extents->unbounded.y,
850 extents->unbounded.x + extents->unbounded.width,
851 extents->bounded.y);
853 /* left */
854 if (extents->bounded.x != extents->unbounded.x) {
855 add_rect (&clear,
856 extents->unbounded.x, extents->bounded.y,
857 extents->bounded.x,
858 extents->bounded.y + extents->bounded.height);
860 /* right */
861 if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
862 add_rect (&clear,
863 extents->bounded.x + extents->bounded.width,
864 extents->bounded.y,
865 extents->unbounded.x + extents->unbounded.width,
866 extents->bounded.y + extents->bounded.height);
868 /* bottom */
869 if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
870 add_rect (&clear,
871 extents->unbounded.x,
872 extents->bounded.y + extents->bounded.height,
873 extents->unbounded.x + extents->unbounded.width,
874 extents->unbounded.y + extents->unbounded.height);
877 } else if (boxes->num_boxes) {
878 _cairo_boxes_init (&tmp);
880 assert (boxes->is_pixel_aligned);
882 status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
883 assert (status == CAIRO_INT_STATUS_SUCCESS);
885 tmp.chunks.next = &boxes->chunks;
886 tmp.num_boxes += boxes->num_boxes;
888 status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
889 CAIRO_FILL_RULE_WINDING,
890 &clear);
891 tmp.chunks.next = NULL;
892 if (unlikely (status))
893 goto error;
894 } else {
895 empty:
896 box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
897 box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
899 status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
900 assert (status == CAIRO_INT_STATUS_SUCCESS);
903 /* Now intersect with the clip boxes */
904 if (extents->clip->num_boxes) {
905 _cairo_boxes_init_for_array (&tmp,
906 extents->clip->boxes,
907 extents->clip->num_boxes);
908 status = _cairo_boxes_intersect (&clear, &tmp, &clear);
909 if (unlikely (status))
910 goto error;
913 status = compositor->fill_boxes (dst,
914 CAIRO_OPERATOR_CLEAR,
915 CAIRO_COLOR_TRANSPARENT,
916 &clear);
918 error:
919 _cairo_boxes_fini (&clear);
920 return status;
923 enum {
924 NEED_CLIP_REGION = 0x1,
925 NEED_CLIP_SURFACE = 0x2,
926 FORCE_CLIP_REGION = 0x4,
929 static cairo_bool_t
930 need_bounded_clip (cairo_composite_rectangles_t *extents)
932 unsigned int flags = 0;
934 if (extents->clip->num_boxes > 1 ||
935 extents->mask.width > extents->unbounded.width ||
936 extents->mask.height > extents->unbounded.height)
938 flags |= NEED_CLIP_REGION;
941 if (extents->clip->num_boxes > 1 ||
942 extents->mask.width > extents->bounded.width ||
943 extents->mask.height > extents->bounded.height)
945 flags |= FORCE_CLIP_REGION;
948 if (! _cairo_clip_is_region (extents->clip))
949 flags |= NEED_CLIP_SURFACE;
951 return flags;
954 static cairo_bool_t
955 need_unbounded_clip (cairo_composite_rectangles_t *extents)
957 unsigned int flags = 0;
958 if (! extents->is_bounded) {
959 flags |= NEED_CLIP_REGION;
960 if (! _cairo_clip_is_region (extents->clip))
961 flags |= NEED_CLIP_SURFACE;
963 if (extents->clip->path != NULL)
964 flags |= NEED_CLIP_SURFACE;
965 return flags;
968 static cairo_status_t
969 clip_and_composite (const cairo_traps_compositor_t *compositor,
970 cairo_composite_rectangles_t *extents,
971 draw_func_t draw_func,
972 draw_func_t mask_func,
973 void *draw_closure,
974 unsigned int need_clip)
976 cairo_surface_t *dst = extents->surface;
977 cairo_operator_t op = extents->op;
978 cairo_pattern_t *source = &extents->source_pattern.base;
979 cairo_surface_t *src;
980 int src_x, src_y;
981 cairo_region_t *clip_region = NULL;
982 cairo_status_t status = CAIRO_STATUS_SUCCESS;
984 TRACE ((stderr, "%s\n", __FUNCTION__));
986 if (reduce_alpha_op (extents)) {
987 op = CAIRO_OPERATOR_ADD;
988 source = NULL;
991 if (op == CAIRO_OPERATOR_CLEAR) {
992 op = CAIRO_OPERATOR_DEST_OUT;
993 source = NULL;
996 compositor->acquire (dst);
998 if (need_clip & NEED_CLIP_REGION) {
999 const cairo_rectangle_int_t *limit;
1001 if ((need_clip & FORCE_CLIP_REGION) == 0)
1002 limit = &extents->unbounded;
1003 else
1004 limit = &extents->destination;
1006 clip_region = _cairo_clip_get_region (extents->clip);
1007 if (clip_region != NULL &&
1008 cairo_region_contains_rectangle (clip_region,
1009 limit) == CAIRO_REGION_OVERLAP_IN)
1010 clip_region = NULL;
1012 if (clip_region != NULL) {
1013 status = compositor->set_clip_region (dst, clip_region);
1014 if (unlikely (status)) {
1015 compositor->release (dst);
1016 return status;
1021 if (extents->bounded.width == 0 || extents->bounded.height == 0)
1022 goto skip;
1024 src = compositor->pattern_to_surface (dst, source, FALSE,
1025 &extents->bounded,
1026 &extents->source_sample_area,
1027 &src_x, &src_y);
1028 if (unlikely (status = src->status))
1029 goto error;
1031 if (op == CAIRO_OPERATOR_SOURCE) {
1032 status = clip_and_composite_source (compositor, dst,
1033 draw_func, mask_func, draw_closure,
1034 src, src_x, src_y,
1035 extents);
1036 } else {
1037 if (need_clip & NEED_CLIP_SURFACE) {
1038 if (extents->is_bounded) {
1039 status = clip_and_composite_with_mask (compositor, extents,
1040 draw_func, mask_func,
1041 draw_closure,
1042 op, src, src_x, src_y);
1043 } else {
1044 status = clip_and_composite_combine (compositor, extents,
1045 draw_func, draw_closure,
1046 op, src, src_x, src_y);
1048 } else {
1049 status = draw_func (compositor,
1050 dst, draw_closure,
1051 op, src, src_x, src_y,
1052 0, 0,
1053 &extents->bounded,
1054 extents->clip);
1057 cairo_surface_destroy (src);
1059 skip:
1060 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
1061 if (need_clip & NEED_CLIP_SURFACE)
1062 status = fixup_unbounded_with_mask (compositor, extents);
1063 else
1064 status = fixup_unbounded (compositor, extents, NULL);
1067 error:
1068 if (clip_region)
1069 compositor->set_clip_region (dst, NULL);
1071 compositor->release (dst);
1073 return status;
1076 /* meta-ops */
1078 typedef struct {
1079 cairo_traps_t traps;
1080 cairo_antialias_t antialias;
1081 } composite_traps_info_t;
1083 static cairo_int_status_t
1084 composite_traps (const cairo_traps_compositor_t *compositor,
1085 cairo_surface_t *dst,
1086 void *closure,
1087 cairo_operator_t op,
1088 cairo_surface_t *src,
1089 int src_x, int src_y,
1090 int dst_x, int dst_y,
1091 const cairo_rectangle_int_t *extents,
1092 cairo_clip_t *clip)
1094 composite_traps_info_t *info = closure;
1096 TRACE ((stderr, "%s\n", __FUNCTION__));
1098 return compositor->composite_traps (dst, op, src,
1099 src_x - dst_x, src_y - dst_y,
1100 dst_x, dst_y,
1101 extents,
1102 info->antialias, &info->traps);
1105 typedef struct {
1106 cairo_tristrip_t strip;
1107 cairo_antialias_t antialias;
1108 } composite_tristrip_info_t;
1110 static cairo_int_status_t
1111 composite_tristrip (const cairo_traps_compositor_t *compositor,
1112 cairo_surface_t *dst,
1113 void *closure,
1114 cairo_operator_t op,
1115 cairo_surface_t *src,
1116 int src_x, int src_y,
1117 int dst_x, int dst_y,
1118 const cairo_rectangle_int_t *extents,
1119 cairo_clip_t *clip)
1121 composite_tristrip_info_t *info = closure;
1123 TRACE ((stderr, "%s\n", __FUNCTION__));
1125 return compositor->composite_tristrip (dst, op, src,
1126 src_x - dst_x, src_y - dst_y,
1127 dst_x, dst_y,
1128 extents,
1129 info->antialias, &info->strip);
1132 static cairo_bool_t
1133 is_recording_pattern (const cairo_pattern_t *pattern)
1135 cairo_surface_t *surface;
1137 if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
1138 return FALSE;
1140 surface = ((const cairo_surface_pattern_t *) pattern)->surface;
1141 surface = _cairo_surface_get_source (surface, NULL);
1142 return _cairo_surface_is_recording (surface);
1145 static cairo_surface_t *
1146 recording_pattern_get_surface (const cairo_pattern_t *pattern)
1148 cairo_surface_t *surface;
1150 surface = ((const cairo_surface_pattern_t *) pattern)->surface;
1151 return _cairo_surface_get_source (surface, NULL);
1154 static cairo_bool_t
1155 recording_pattern_contains_sample (const cairo_pattern_t *pattern,
1156 const cairo_rectangle_int_t *sample)
1158 cairo_recording_surface_t *surface;
1160 if (! is_recording_pattern (pattern))
1161 return FALSE;
1163 if (pattern->extend == CAIRO_EXTEND_NONE)
1164 return TRUE;
1166 surface = (cairo_recording_surface_t *) recording_pattern_get_surface (pattern);
1167 if (surface->unbounded)
1168 return TRUE;
1170 return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
1173 static cairo_bool_t
1174 op_reduces_to_source (cairo_composite_rectangles_t *extents)
1176 if (extents->op == CAIRO_OPERATOR_SOURCE)
1177 return TRUE;
1179 if (extents->surface->is_clear)
1180 return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
1182 return FALSE;
1185 static cairo_status_t
1186 composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
1187 cairo_composite_rectangles_t *extents,
1188 cairo_boxes_t *boxes)
1190 cairo_surface_t *dst = extents->surface;
1191 cairo_operator_t op = extents->op;
1192 cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (extents->clip);
1193 cairo_bool_t op_is_source;
1194 cairo_status_t status;
1196 TRACE ((stderr, "%s\n", __FUNCTION__));
1198 if (need_clip_mask &&
1199 (! extents->is_bounded || extents->op == CAIRO_OPERATOR_SOURCE))
1201 return CAIRO_INT_STATUS_UNSUPPORTED;
1204 op_is_source = op_reduces_to_source (extents);
1206 /* Are we just copying a recording surface? */
1207 if (! need_clip_mask && op_is_source &&
1208 recording_pattern_contains_sample (&extents->source_pattern.base,
1209 &extents->source_sample_area))
1211 cairo_clip_t *recording_clip;
1212 const cairo_pattern_t *source = &extents->source_pattern.base;
1213 const cairo_matrix_t *m;
1214 cairo_matrix_t matrix;
1216 /* XXX could also do tiling repeat modes... */
1218 /* first clear the area about to be overwritten */
1219 if (! dst->is_clear) {
1220 status = compositor->acquire (dst);
1221 if (unlikely (status))
1222 return status;
1224 status = compositor->fill_boxes (dst,
1225 CAIRO_OPERATOR_CLEAR,
1226 CAIRO_COLOR_TRANSPARENT,
1227 boxes);
1228 compositor->release (dst);
1229 if (unlikely (status))
1230 return status;
1233 m = &source->matrix;
1234 if (_cairo_surface_has_device_transform (dst)) {
1235 cairo_matrix_multiply (&matrix,
1236 &source->matrix,
1237 &dst->device_transform);
1238 m = &matrix;
1241 recording_clip = _cairo_clip_from_boxes (boxes);
1242 status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
1243 m, dst, recording_clip);
1244 _cairo_clip_destroy (recording_clip);
1246 return status;
1249 status = compositor->acquire (dst);
1250 if (unlikely (status))
1251 return status;
1253 if (! need_clip_mask &&
1254 (op == CAIRO_OPERATOR_CLEAR ||
1255 extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID))
1257 const cairo_color_t *color;
1259 if (op == CAIRO_OPERATOR_CLEAR) {
1260 color = CAIRO_COLOR_TRANSPARENT;
1261 } else {
1262 color = &((cairo_solid_pattern_t *) &extents->source_pattern)->color;
1263 if (op_is_source)
1264 op = CAIRO_OPERATOR_SOURCE;
1267 status = compositor->fill_boxes (dst, op, color, boxes);
1269 else
1271 cairo_surface_t *src, *mask = NULL;
1272 cairo_pattern_t *source = &extents->source_pattern.base;
1273 int src_x, src_y;
1274 int mask_x = 0, mask_y = 0;
1276 if (need_clip_mask) {
1277 mask = traps_get_clip_surface (compositor,
1278 extents, &extents->bounded);
1279 if (unlikely (mask->status))
1280 return mask->status;
1282 mask_x = -extents->bounded.x;
1283 mask_y = -extents->bounded.y;
1285 if (op == CAIRO_OPERATOR_CLEAR) {
1286 source = NULL;
1287 op = CAIRO_OPERATOR_DEST_OUT;
1289 } else if (op_is_source)
1290 op = CAIRO_OPERATOR_SOURCE;
1292 src = compositor->pattern_to_surface (dst, source, FALSE,
1293 &extents->bounded,
1294 &extents->source_sample_area,
1295 &src_x, &src_y);
1296 if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
1297 status = compositor->composite_boxes (dst, op, src, mask,
1298 src_x, src_y,
1299 mask_x, mask_y,
1300 0, 0,
1301 boxes, &extents->bounded);
1302 cairo_surface_destroy (src);
1303 } else
1304 status = src->status;
1306 cairo_surface_destroy (mask);
1309 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
1310 status = fixup_unbounded (compositor, extents, boxes);
1312 compositor->release (dst);
1314 return status;
1317 static cairo_status_t
1318 upload_boxes (const cairo_traps_compositor_t *compositor,
1319 cairo_composite_rectangles_t *extents,
1320 cairo_boxes_t *boxes)
1322 cairo_surface_t *dst = extents->surface;
1323 const cairo_pattern_t *source = &extents->source_pattern.base;
1324 cairo_surface_t *src;
1325 cairo_rectangle_int_t limit;
1326 cairo_int_status_t status;
1327 int tx, ty;
1329 TRACE ((stderr, "%s\n", __FUNCTION__));
1331 src = _cairo_pattern_get_source((cairo_surface_pattern_t *)source,
1332 &limit);
1333 if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
1334 return CAIRO_INT_STATUS_UNSUPPORTED;
1336 if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
1337 return CAIRO_INT_STATUS_UNSUPPORTED;
1339 /* Check that the data is entirely within the image */
1340 if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
1341 return CAIRO_INT_STATUS_UNSUPPORTED;
1343 if (extents->bounded.x + extents->bounded.width + tx > limit.x + limit.width ||
1344 extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
1345 return CAIRO_INT_STATUS_UNSUPPORTED;
1347 tx += limit.x;
1348 ty += limit.y;
1350 if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
1351 status = compositor->draw_image_boxes (dst,
1352 (cairo_image_surface_t *)src,
1353 boxes, tx, ty);
1354 else
1355 status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
1356 tx, ty);
1358 return status;
1361 static cairo_int_status_t
1362 trim_extents_to_traps (cairo_composite_rectangles_t *extents,
1363 cairo_traps_t *traps)
1365 cairo_box_t box;
1367 _cairo_traps_extents (traps, &box);
1368 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
1371 static cairo_int_status_t
1372 trim_extents_to_tristrip (cairo_composite_rectangles_t *extents,
1373 cairo_tristrip_t *strip)
1375 cairo_box_t box;
1377 _cairo_tristrip_extents (strip, &box);
1378 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
1381 static cairo_int_status_t
1382 trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
1383 cairo_boxes_t *boxes)
1385 cairo_box_t box;
1387 _cairo_boxes_extents (boxes, &box);
1388 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
1391 static cairo_int_status_t
1392 boxes_for_traps (cairo_boxes_t *boxes,
1393 cairo_traps_t *traps,
1394 cairo_antialias_t antialias)
1396 int i, j;
1398 /* first check that the traps are rectilinear */
1399 if (antialias == CAIRO_ANTIALIAS_NONE) {
1400 for (i = 0; i < traps->num_traps; i++) {
1401 const cairo_trapezoid_t *t = &traps->traps[i];
1402 if (_cairo_fixed_integer_round_down (t->left.p1.x) !=
1403 _cairo_fixed_integer_round_down (t->left.p2.x) ||
1404 _cairo_fixed_integer_round_down (t->right.p1.x) !=
1405 _cairo_fixed_integer_round_down (t->right.p2.x))
1407 return CAIRO_INT_STATUS_UNSUPPORTED;
1410 } else {
1411 for (i = 0; i < traps->num_traps; i++) {
1412 const cairo_trapezoid_t *t = &traps->traps[i];
1413 if (t->left.p1.x != t->left.p2.x || t->right.p1.x != t->right.p2.x)
1414 return CAIRO_INT_STATUS_UNSUPPORTED;
1418 _cairo_boxes_init (boxes);
1420 boxes->chunks.base = (cairo_box_t *) traps->traps;
1421 boxes->chunks.size = traps->num_traps;
1423 if (antialias != CAIRO_ANTIALIAS_NONE) {
1424 for (i = j = 0; i < traps->num_traps; i++) {
1425 /* Note the traps and boxes alias so we need to take the local copies first. */
1426 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
1427 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
1428 cairo_fixed_t y1 = traps->traps[i].top;
1429 cairo_fixed_t y2 = traps->traps[i].bottom;
1431 if (x1 == x2 || y1 == y2)
1432 continue;
1434 boxes->chunks.base[j].p1.x = x1;
1435 boxes->chunks.base[j].p1.y = y1;
1436 boxes->chunks.base[j].p2.x = x2;
1437 boxes->chunks.base[j].p2.y = y2;
1438 j++;
1440 if (boxes->is_pixel_aligned) {
1441 boxes->is_pixel_aligned =
1442 _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
1443 _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
1446 } else {
1447 boxes->is_pixel_aligned = TRUE;
1449 for (i = j = 0; i < traps->num_traps; i++) {
1450 /* Note the traps and boxes alias so we need to take the local copies first. */
1451 cairo_fixed_t x1 = traps->traps[i].left.p1.x;
1452 cairo_fixed_t x2 = traps->traps[i].right.p1.x;
1453 cairo_fixed_t y1 = traps->traps[i].top;
1454 cairo_fixed_t y2 = traps->traps[i].bottom;
1456 /* round down here to match Pixman's behavior when using traps. */
1457 boxes->chunks.base[j].p1.x = _cairo_fixed_round_down (x1);
1458 boxes->chunks.base[j].p1.y = _cairo_fixed_round_down (y1);
1459 boxes->chunks.base[j].p2.x = _cairo_fixed_round_down (x2);
1460 boxes->chunks.base[j].p2.y = _cairo_fixed_round_down (y2);
1461 j += (boxes->chunks.base[j].p1.x != boxes->chunks.base[j].p2.x &&
1462 boxes->chunks.base[j].p1.y != boxes->chunks.base[j].p2.y);
1465 boxes->chunks.count = j;
1466 boxes->num_boxes = j;
1468 return CAIRO_INT_STATUS_SUCCESS;
1471 static cairo_status_t
1472 clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
1473 cairo_composite_rectangles_t *extents,
1474 cairo_boxes_t *boxes);
1476 static cairo_status_t
1477 clip_and_composite_polygon (const cairo_traps_compositor_t *compositor,
1478 cairo_composite_rectangles_t *extents,
1479 cairo_polygon_t *polygon,
1480 cairo_antialias_t antialias,
1481 cairo_fill_rule_t fill_rule,
1482 cairo_bool_t curvy)
1484 composite_traps_info_t traps;
1485 cairo_surface_t *dst = extents->surface;
1486 cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
1487 cairo_int_status_t status;
1489 TRACE ((stderr, "%s\n", __FUNCTION__));
1491 if (polygon->num_edges == 0) {
1492 status = CAIRO_INT_STATUS_SUCCESS;
1494 if (! extents->is_bounded) {
1495 cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
1497 if (clip_region &&
1498 cairo_region_contains_rectangle (clip_region,
1499 &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
1500 clip_region = NULL;
1502 if (clip_region != NULL) {
1503 status = compositor->set_clip_region (dst, clip_region);
1504 if (unlikely (status))
1505 return status;
1508 if (clip_surface)
1509 status = fixup_unbounded_with_mask (compositor, extents);
1510 else
1511 status = fixup_unbounded (compositor, extents, NULL);
1513 if (clip_region != NULL)
1514 compositor->set_clip_region (dst, NULL);
1517 return status;
1520 if (extents->clip->path != NULL && extents->is_bounded) {
1521 cairo_polygon_t clipper;
1522 cairo_fill_rule_t clipper_fill_rule;
1523 cairo_antialias_t clipper_antialias;
1525 status = _cairo_clip_get_polygon (extents->clip,
1526 &clipper,
1527 &clipper_fill_rule,
1528 &clipper_antialias);
1529 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1530 if (clipper_antialias == antialias) {
1531 status = _cairo_polygon_intersect (polygon, fill_rule,
1532 &clipper, clipper_fill_rule);
1533 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1534 cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip);
1535 _cairo_clip_destroy (extents->clip);
1536 extents->clip = clip;
1538 fill_rule = CAIRO_FILL_RULE_WINDING;
1540 _cairo_polygon_fini (&clipper);
1545 if (antialias == CAIRO_ANTIALIAS_NONE && curvy) {
1546 cairo_boxes_t boxes;
1548 _cairo_boxes_init (&boxes);
1549 status = _cairo_rasterise_polygon_to_boxes (polygon, fill_rule, &boxes);
1550 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1551 assert (boxes.is_pixel_aligned);
1552 status = clip_and_composite_boxes (compositor, extents, &boxes);
1554 _cairo_boxes_fini (&boxes);
1555 if ((status != CAIRO_INT_STATUS_UNSUPPORTED))
1556 return status;
1559 _cairo_traps_init (&traps.traps);
1561 if (antialias == CAIRO_ANTIALIAS_NONE && curvy) {
1562 status = _cairo_rasterise_polygon_to_traps (polygon, fill_rule, antialias, &traps.traps);
1563 } else {
1564 status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
1566 if (unlikely (status))
1567 goto CLEANUP_TRAPS;
1569 status = trim_extents_to_traps (extents, &traps.traps);
1570 if (unlikely (status))
1571 goto CLEANUP_TRAPS;
1573 /* Use a fast path if the trapezoids consist of a set of boxes. */
1574 status = CAIRO_INT_STATUS_UNSUPPORTED;
1575 if (1) {
1576 cairo_boxes_t boxes;
1578 status = boxes_for_traps (&boxes, &traps.traps, antialias);
1579 if (status == CAIRO_INT_STATUS_SUCCESS) {
1580 status = clip_and_composite_boxes (compositor, extents, &boxes);
1581 /* XXX need to reconstruct the traps! */
1582 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
1585 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1586 /* Otherwise render the trapezoids to a mask and composite in the usual
1587 * fashion.
1589 unsigned int flags = 0;
1591 /* For unbounded operations, the X11 server will estimate the
1592 * affected rectangle and apply the operation to that. However,
1593 * there are cases where this is an overestimate (e.g. the
1594 * clip-fill-{eo,nz}-unbounded test).
1596 * The clip will trim that overestimate to our expectations.
1598 if (! extents->is_bounded)
1599 flags |= FORCE_CLIP_REGION;
1601 traps.antialias = antialias;
1602 status = clip_and_composite (compositor, extents,
1603 composite_traps, NULL, &traps,
1604 need_unbounded_clip (extents) | flags);
1607 CLEANUP_TRAPS:
1608 _cairo_traps_fini (&traps.traps);
1610 return status;
1613 struct composite_opacity_info {
1614 const cairo_traps_compositor_t *compositor;
1615 uint8_t op;
1616 cairo_surface_t *dst;
1617 cairo_surface_t *src;
1618 int src_x, src_y;
1619 double opacity;
1622 static void composite_opacity(void *closure,
1623 int16_t x, int16_t y,
1624 int16_t w, int16_t h,
1625 uint16_t coverage)
1627 struct composite_opacity_info *info = closure;
1628 const cairo_traps_compositor_t *compositor = info->compositor;
1629 cairo_surface_t *mask;
1630 int mask_x, mask_y;
1631 cairo_color_t color;
1632 cairo_solid_pattern_t solid;
1634 _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage);
1635 _cairo_pattern_init_solid (&solid, &color);
1636 mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE,
1637 &_cairo_unbounded_rectangle,
1638 &_cairo_unbounded_rectangle,
1639 &mask_x, &mask_y);
1640 if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
1641 if (info->src) {
1642 compositor->composite (info->dst, info->op, info->src, mask,
1643 x + info->src_x, y + info->src_y,
1644 mask_x, mask_y,
1645 x, y,
1646 w, h);
1647 } else {
1648 compositor->composite (info->dst, info->op, mask, NULL,
1649 mask_x, mask_y,
1650 0, 0,
1651 x, y,
1652 w, h);
1656 cairo_surface_destroy (mask);
1660 static cairo_int_status_t
1661 composite_opacity_boxes (const cairo_traps_compositor_t *compositor,
1662 cairo_surface_t *dst,
1663 void *closure,
1664 cairo_operator_t op,
1665 cairo_surface_t *src,
1666 int src_x,
1667 int src_y,
1668 int dst_x,
1669 int dst_y,
1670 const cairo_rectangle_int_t *extents,
1671 cairo_clip_t *clip)
1673 const cairo_solid_pattern_t *mask = closure;
1674 struct composite_opacity_info info;
1675 int i;
1677 TRACE ((stderr, "%s\n", __FUNCTION__));
1679 info.compositor = compositor;
1680 info.op = op;
1681 info.dst = dst;
1683 info.src = src;
1684 info.src_x = src_x;
1685 info.src_y = src_y;
1687 info.opacity = mask->color.alpha / (double) 0xffff;
1689 /* XXX for lots of boxes create a clip region for the fully opaque areas */
1690 for (i = 0; i < clip->num_boxes; i++)
1691 do_unaligned_box(composite_opacity, &info,
1692 &clip->boxes[i], dst_x, dst_y);
1694 return CAIRO_STATUS_SUCCESS;
1697 static cairo_int_status_t
1698 composite_boxes (const cairo_traps_compositor_t *compositor,
1699 cairo_surface_t *dst,
1700 void *closure,
1701 cairo_operator_t op,
1702 cairo_surface_t *src,
1703 int src_x,
1704 int src_y,
1705 int dst_x,
1706 int dst_y,
1707 const cairo_rectangle_int_t *extents,
1708 cairo_clip_t *clip)
1710 cairo_traps_t traps;
1711 cairo_status_t status;
1713 TRACE ((stderr, "%s\n", __FUNCTION__));
1715 status = _cairo_traps_init_boxes (&traps, closure);
1716 if (unlikely (status))
1717 return status;
1719 status = compositor->composite_traps (dst, op, src,
1720 src_x - dst_x, src_y - dst_y,
1721 dst_x, dst_y,
1722 extents,
1723 CAIRO_ANTIALIAS_DEFAULT, &traps);
1724 _cairo_traps_fini (&traps);
1726 return status;
1729 static cairo_status_t
1730 clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
1731 cairo_composite_rectangles_t *extents,
1732 cairo_boxes_t *boxes)
1734 cairo_int_status_t status;
1736 TRACE ((stderr, "%s\n", __FUNCTION__));
1738 if (boxes->num_boxes == 0 && extents->is_bounded)
1739 return CAIRO_STATUS_SUCCESS;
1741 status = trim_extents_to_boxes (extents, boxes);
1742 if (unlikely (status))
1743 return status;
1745 if (boxes->is_pixel_aligned && extents->clip->path == NULL &&
1746 extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
1747 (op_reduces_to_source (extents) ||
1748 (extents->op == CAIRO_OPERATOR_OVER &&
1749 (extents->source_pattern.surface.surface->content & CAIRO_CONTENT_ALPHA) == 0)))
1751 status = upload_boxes (compositor, extents, boxes);
1752 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1753 return status;
1756 /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
1757 if (extents->clip->path != NULL && extents->is_bounded) {
1758 cairo_polygon_t polygon;
1759 cairo_fill_rule_t fill_rule;
1760 cairo_antialias_t antialias;
1761 cairo_clip_t *clip;
1763 clip = _cairo_clip_copy (extents->clip);
1764 clip = _cairo_clip_intersect_boxes (clip, boxes);
1765 if (_cairo_clip_is_all_clipped (clip))
1766 return CAIRO_INT_STATUS_NOTHING_TO_DO;
1768 status = _cairo_clip_get_polygon (clip, &polygon,
1769 &fill_rule, &antialias);
1770 _cairo_clip_path_destroy (clip->path);
1771 clip->path = NULL;
1772 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1773 cairo_clip_t *saved_clip = extents->clip;
1774 extents->clip = clip;
1776 status = clip_and_composite_polygon (compositor, extents, &polygon,
1777 antialias, fill_rule, FALSE);
1779 clip = extents->clip;
1780 extents->clip = saved_clip;
1782 _cairo_polygon_fini (&polygon);
1784 _cairo_clip_destroy (clip);
1786 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1787 return status;
1790 /* Use a fast path if the boxes are pixel aligned (or nearly aligned!) */
1791 if (boxes->is_pixel_aligned) {
1792 status = composite_aligned_boxes (compositor, extents, boxes);
1793 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1794 return status;
1797 return clip_and_composite (compositor, extents,
1798 composite_boxes, NULL, boxes,
1799 need_unbounded_clip (extents));
1802 static cairo_int_status_t
1803 composite_traps_as_boxes (const cairo_traps_compositor_t *compositor,
1804 cairo_composite_rectangles_t *extents,
1805 composite_traps_info_t *info)
1807 cairo_boxes_t boxes;
1809 TRACE ((stderr, "%s\n", __FUNCTION__));
1811 if (! _cairo_traps_to_boxes (&info->traps, info->antialias, &boxes))
1812 return CAIRO_INT_STATUS_UNSUPPORTED;
1814 return clip_and_composite_boxes (compositor, extents, &boxes);
1817 static cairo_int_status_t
1818 clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
1819 cairo_composite_rectangles_t *extents,
1820 composite_traps_info_t *info,
1821 unsigned flags)
1823 cairo_int_status_t status;
1825 TRACE ((stderr, "%s\n", __FUNCTION__));
1827 status = trim_extents_to_traps (extents, &info->traps);
1828 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
1829 return status;
1831 status = CAIRO_INT_STATUS_UNSUPPORTED;
1832 if ((flags & FORCE_CLIP_REGION) == 0)
1833 status = composite_traps_as_boxes (compositor, extents, info);
1834 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1835 /* For unbounded operations, the X11 server will estimate the
1836 * affected rectangle and apply the operation to that. However,
1837 * there are cases where this is an overestimate (e.g. the
1838 * clip-fill-{eo,nz}-unbounded test).
1840 * The clip will trim that overestimate to our expectations.
1842 if (! extents->is_bounded)
1843 flags |= FORCE_CLIP_REGION;
1845 status = clip_and_composite (compositor, extents,
1846 composite_traps, NULL, info,
1847 need_unbounded_clip (extents) | flags);
1850 return status;
1853 static cairo_int_status_t
1854 clip_and_composite_tristrip (const cairo_traps_compositor_t *compositor,
1855 cairo_composite_rectangles_t *extents,
1856 composite_tristrip_info_t *info)
1858 cairo_int_status_t status;
1859 unsigned int flags = 0;
1861 TRACE ((stderr, "%s\n", __FUNCTION__));
1863 status = trim_extents_to_tristrip (extents, &info->strip);
1864 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
1865 return status;
1867 if (! extents->is_bounded)
1868 flags |= FORCE_CLIP_REGION;
1870 status = clip_and_composite (compositor, extents,
1871 composite_tristrip, NULL, info,
1872 need_unbounded_clip (extents) | flags);
1874 return status;
1877 struct composite_mask {
1878 cairo_surface_t *mask;
1879 int mask_x, mask_y;
1882 static cairo_int_status_t
1883 composite_mask (const cairo_traps_compositor_t *compositor,
1884 cairo_surface_t *dst,
1885 void *closure,
1886 cairo_operator_t op,
1887 cairo_surface_t *src,
1888 int src_x,
1889 int src_y,
1890 int dst_x,
1891 int dst_y,
1892 const cairo_rectangle_int_t *extents,
1893 cairo_clip_t *clip)
1895 struct composite_mask *data = closure;
1897 TRACE ((stderr, "%s\n", __FUNCTION__));
1899 if (src != NULL) {
1900 compositor->composite (dst, op, src, data->mask,
1901 extents->x + src_x, extents->y + src_y,
1902 extents->x + data->mask_x, extents->y + data->mask_y,
1903 extents->x - dst_x, extents->y - dst_y,
1904 extents->width, extents->height);
1905 } else {
1906 compositor->composite (dst, op, data->mask, NULL,
1907 extents->x + data->mask_x, extents->y + data->mask_y,
1908 0, 0,
1909 extents->x - dst_x, extents->y - dst_y,
1910 extents->width, extents->height);
1913 return CAIRO_STATUS_SUCCESS;
1916 struct composite_box_info {
1917 const cairo_traps_compositor_t *compositor;
1918 cairo_surface_t *dst;
1919 cairo_surface_t *src;
1920 int src_x, src_y;
1921 uint8_t op;
1924 static void composite_box(void *closure,
1925 int16_t x, int16_t y,
1926 int16_t w, int16_t h,
1927 uint16_t coverage)
1929 struct composite_box_info *info = closure;
1930 const cairo_traps_compositor_t *compositor = info->compositor;
1932 TRACE ((stderr, "%s\n", __FUNCTION__));
1934 if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) {
1935 cairo_surface_t *mask;
1936 cairo_color_t color;
1937 cairo_solid_pattern_t solid;
1938 int mask_x, mask_y;
1940 _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff);
1941 _cairo_pattern_init_solid (&solid, &color);
1943 mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE,
1944 &_cairo_unbounded_rectangle,
1945 &_cairo_unbounded_rectangle,
1946 &mask_x, &mask_y);
1948 if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
1949 compositor->composite (info->dst, info->op, info->src, mask,
1950 x + info->src_x, y + info->src_y,
1951 mask_x, mask_y,
1952 x, y,
1953 w, h);
1956 cairo_surface_destroy (mask);
1957 } else {
1958 compositor->composite (info->dst, info->op, info->src, NULL,
1959 x + info->src_x, y + info->src_y,
1960 0, 0,
1961 x, y,
1962 w, h);
1966 static cairo_int_status_t
1967 composite_mask_clip_boxes (const cairo_traps_compositor_t *compositor,
1968 cairo_surface_t *dst,
1969 void *closure,
1970 cairo_operator_t op,
1971 cairo_surface_t *src,
1972 int src_x,
1973 int src_y,
1974 int dst_x,
1975 int dst_y,
1976 const cairo_rectangle_int_t *extents,
1977 cairo_clip_t *clip)
1979 struct composite_mask *data = closure;
1980 struct composite_box_info info;
1981 int i;
1983 TRACE ((stderr, "%s\n", __FUNCTION__));
1985 info.compositor = compositor;
1986 info.op = CAIRO_OPERATOR_SOURCE;
1987 info.dst = dst;
1988 info.src = data->mask;
1989 info.src_x = data->mask_x;
1990 info.src_y = data->mask_y;
1992 info.src_x += dst_x;
1993 info.src_y += dst_y;
1995 for (i = 0; i < clip->num_boxes; i++)
1996 do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
1998 return CAIRO_STATUS_SUCCESS;
2001 static cairo_int_status_t
2002 composite_mask_clip (const cairo_traps_compositor_t *compositor,
2003 cairo_surface_t *dst,
2004 void *closure,
2005 cairo_operator_t op,
2006 cairo_surface_t *src,
2007 int src_x,
2008 int src_y,
2009 int dst_x,
2010 int dst_y,
2011 const cairo_rectangle_int_t *extents,
2012 cairo_clip_t *clip)
2014 struct composite_mask *data = closure;
2015 cairo_polygon_t polygon;
2016 cairo_fill_rule_t fill_rule;
2017 composite_traps_info_t info;
2018 cairo_status_t status;
2020 TRACE ((stderr, "%s\n", __FUNCTION__));
2022 status = _cairo_clip_get_polygon (clip, &polygon,
2023 &fill_rule, &info.antialias);
2024 if (unlikely (status))
2025 return status;
2027 _cairo_traps_init (&info.traps);
2028 status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps,
2029 &polygon,
2030 fill_rule);
2031 _cairo_polygon_fini (&polygon);
2032 if (unlikely (status))
2033 return status;
2035 status = composite_traps (compositor, dst, &info,
2036 CAIRO_OPERATOR_SOURCE,
2037 data->mask,
2038 data->mask_x + dst_x, data->mask_y + dst_y,
2039 dst_x, dst_y,
2040 extents, NULL);
2041 _cairo_traps_fini (&info.traps);
2043 return status;
2046 /* high-level compositor interface */
2048 static cairo_int_status_t
2049 _cairo_traps_compositor_paint (const cairo_compositor_t *_compositor,
2050 cairo_composite_rectangles_t *extents)
2052 cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
2053 cairo_boxes_t boxes;
2054 cairo_int_status_t status;
2056 TRACE ((stderr, "%s\n", __FUNCTION__));
2058 status = compositor->check_composite (extents);
2059 if (unlikely (status))
2060 return status;
2062 _cairo_clip_steal_boxes (extents->clip, &boxes);
2063 status = clip_and_composite_boxes (compositor, extents, &boxes);
2064 _cairo_clip_unsteal_boxes (extents->clip, &boxes);
2066 return status;
2069 static cairo_int_status_t
2070 _cairo_traps_compositor_mask (const cairo_compositor_t *_compositor,
2071 cairo_composite_rectangles_t *extents)
2073 const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
2074 cairo_int_status_t status;
2076 TRACE ((stderr, "%s\n", __FUNCTION__));
2078 status = compositor->check_composite (extents);
2079 if (unlikely (status))
2080 return status;
2082 if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
2083 extents->clip->path == NULL) {
2084 status = clip_and_composite (compositor, extents,
2085 composite_opacity_boxes,
2086 composite_opacity_boxes,
2087 &extents->mask_pattern,
2088 need_unbounded_clip (extents));
2089 } else {
2090 struct composite_mask data;
2092 data.mask = compositor->pattern_to_surface (extents->surface,
2093 &extents->mask_pattern.base,
2094 TRUE,
2095 &extents->bounded,
2096 &extents->mask_sample_area,
2097 &data.mask_x,
2098 &data.mask_y);
2099 if (unlikely (data.mask->status))
2100 return data.mask->status;
2102 status = clip_and_composite (compositor, extents,
2103 composite_mask,
2104 extents->clip->path ? composite_mask_clip : composite_mask_clip_boxes,
2105 &data, need_bounded_clip (extents));
2107 cairo_surface_destroy (data.mask);
2110 return status;
2113 static cairo_int_status_t
2114 _cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor,
2115 cairo_composite_rectangles_t *extents,
2116 const cairo_path_fixed_t *path,
2117 const cairo_stroke_style_t *style,
2118 const cairo_matrix_t *ctm,
2119 const cairo_matrix_t *ctm_inverse,
2120 double tolerance,
2121 cairo_antialias_t antialias)
2123 const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
2124 cairo_int_status_t status;
2126 TRACE ((stderr, "%s\n", __FUNCTION__));
2128 status = compositor->check_composite (extents);
2129 if (unlikely (status))
2130 return status;
2132 status = CAIRO_INT_STATUS_UNSUPPORTED;
2133 if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
2134 cairo_boxes_t boxes;
2136 _cairo_boxes_init_with_clip (&boxes, extents->clip);
2137 status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
2138 style,
2139 ctm,
2140 antialias,
2141 &boxes);
2142 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2143 status = clip_and_composite_boxes (compositor, extents, &boxes);
2144 _cairo_boxes_fini (&boxes);
2147 if (status == CAIRO_INT_STATUS_UNSUPPORTED && 0 &&
2148 _cairo_clip_is_region (extents->clip)) /* XXX */
2150 composite_tristrip_info_t info;
2152 info.antialias = antialias;
2153 _cairo_tristrip_init_with_clip (&info.strip, extents->clip);
2154 status = _cairo_path_fixed_stroke_to_tristrip (path, style,
2155 ctm, ctm_inverse,
2156 tolerance,
2157 &info.strip);
2158 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2159 status = clip_and_composite_tristrip (compositor, extents, &info);
2160 _cairo_tristrip_fini (&info.strip);
2163 if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
2164 path->has_curve_to && antialias == CAIRO_ANTIALIAS_NONE) {
2165 cairo_polygon_t polygon;
2167 _cairo_polygon_init_with_clip (&polygon, extents->clip);
2168 status = _cairo_path_fixed_stroke_to_polygon (path, style,
2169 ctm, ctm_inverse,
2170 tolerance,
2171 &polygon);
2172 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2173 status = clip_and_composite_polygon (compositor,
2174 extents, &polygon,
2175 CAIRO_ANTIALIAS_NONE,
2176 CAIRO_FILL_RULE_WINDING,
2177 TRUE);
2178 _cairo_polygon_fini (&polygon);
2181 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
2182 cairo_int_status_t (*func) (const cairo_path_fixed_t *path,
2183 const cairo_stroke_style_t *stroke_style,
2184 const cairo_matrix_t *ctm,
2185 const cairo_matrix_t *ctm_inverse,
2186 double tolerance,
2187 cairo_traps_t *traps);
2188 composite_traps_info_t info;
2189 unsigned flags;
2191 if (antialias == CAIRO_ANTIALIAS_BEST || antialias == CAIRO_ANTIALIAS_GOOD) {
2192 func = _cairo_path_fixed_stroke_polygon_to_traps;
2193 flags = 0;
2194 } else {
2195 func = _cairo_path_fixed_stroke_to_traps;
2196 flags = need_bounded_clip (extents) & ~NEED_CLIP_SURFACE;
2199 info.antialias = antialias;
2200 _cairo_traps_init_with_clip (&info.traps, extents->clip);
2201 status = func (path, style, ctm, ctm_inverse, tolerance, &info.traps);
2202 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2203 status = clip_and_composite_traps (compositor, extents, &info, flags);
2204 _cairo_traps_fini (&info.traps);
2207 return status;
2210 static cairo_int_status_t
2211 _cairo_traps_compositor_fill (const cairo_compositor_t *_compositor,
2212 cairo_composite_rectangles_t *extents,
2213 const cairo_path_fixed_t *path,
2214 cairo_fill_rule_t fill_rule,
2215 double tolerance,
2216 cairo_antialias_t antialias)
2218 const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
2219 cairo_int_status_t status;
2221 TRACE ((stderr, "%s\n", __FUNCTION__));
2223 status = compositor->check_composite (extents);
2224 if (unlikely (status))
2225 return status;
2227 status = CAIRO_INT_STATUS_UNSUPPORTED;
2228 if (_cairo_path_fixed_fill_is_rectilinear (path)) {
2229 cairo_boxes_t boxes;
2231 _cairo_boxes_init_with_clip (&boxes, extents->clip);
2232 status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
2233 fill_rule,
2234 antialias,
2235 &boxes);
2236 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2237 status = clip_and_composite_boxes (compositor, extents, &boxes);
2238 _cairo_boxes_fini (&boxes);
2241 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
2242 cairo_polygon_t polygon;
2244 #if 0
2245 if (extents->mask.width > extents->unbounded.width ||
2246 extents->mask.height > extents->unbounded.height)
2248 cairo_box_t limits;
2249 _cairo_box_from_rectangle (&limits, &extents->unbounded);
2250 _cairo_polygon_init (&polygon, &limits, 1);
2252 else
2254 _cairo_polygon_init (&polygon, NULL, 0);
2257 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
2258 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
2259 status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
2260 extents->clip->boxes,
2261 extents->clip->num_boxes);
2263 #else
2264 _cairo_polygon_init_with_clip (&polygon, extents->clip);
2265 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
2266 #endif
2267 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
2268 status = clip_and_composite_polygon (compositor, extents, &polygon,
2269 antialias, fill_rule, path->has_curve_to);
2271 _cairo_polygon_fini (&polygon);
2274 return status;
2277 static cairo_int_status_t
2278 composite_glyphs (const cairo_traps_compositor_t *compositor,
2279 cairo_surface_t *dst,
2280 void *closure,
2281 cairo_operator_t op,
2282 cairo_surface_t *src,
2283 int src_x, int src_y,
2284 int dst_x, int dst_y,
2285 const cairo_rectangle_int_t *extents,
2286 cairo_clip_t *clip)
2288 cairo_composite_glyphs_info_t *info = closure;
2290 TRACE ((stderr, "%s\n", __FUNCTION__));
2292 if (op == CAIRO_OPERATOR_ADD && (dst->content & CAIRO_CONTENT_COLOR) == 0)
2293 info->use_mask = 0;
2295 return compositor->composite_glyphs (dst, op, src,
2296 src_x, src_y,
2297 dst_x, dst_y,
2298 info);
2301 static cairo_int_status_t
2302 _cairo_traps_compositor_glyphs (const cairo_compositor_t *_compositor,
2303 cairo_composite_rectangles_t *extents,
2304 cairo_scaled_font_t *scaled_font,
2305 cairo_glyph_t *glyphs,
2306 int num_glyphs,
2307 cairo_bool_t overlap)
2309 const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
2310 cairo_int_status_t status;
2312 TRACE ((stderr, "%s\n", __FUNCTION__));
2314 status = compositor->check_composite (extents);
2315 if (unlikely (status))
2316 return status;
2318 _cairo_scaled_font_freeze_cache (scaled_font);
2319 status = compositor->check_composite_glyphs (extents,
2320 scaled_font, glyphs,
2321 &num_glyphs);
2322 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
2323 cairo_composite_glyphs_info_t info;
2325 info.font = scaled_font;
2326 info.glyphs = glyphs;
2327 info.num_glyphs = num_glyphs;
2328 info.use_mask = overlap || ! extents->is_bounded;
2329 info.extents = extents->bounded;
2331 status = clip_and_composite (compositor, extents,
2332 composite_glyphs, NULL, &info,
2333 need_bounded_clip (extents) | FORCE_CLIP_REGION);
2335 _cairo_scaled_font_thaw_cache (scaled_font);
2337 return status;
2340 void
2341 _cairo_traps_compositor_init (cairo_traps_compositor_t *compositor,
2342 const cairo_compositor_t *delegate)
2344 compositor->base.delegate = delegate;
2346 compositor->base.paint = _cairo_traps_compositor_paint;
2347 compositor->base.mask = _cairo_traps_compositor_mask;
2348 compositor->base.fill = _cairo_traps_compositor_fill;
2349 compositor->base.stroke = _cairo_traps_compositor_stroke;
2350 compositor->base.glyphs = _cairo_traps_compositor_glyphs;