eeee20c80d37bf530b9608db844c28ada341f09f
[framework/graphics/cairo.git] / src / cairo-traps-compositor.c
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
3  *
4  * Copyright © 2002 University of Southern California
5  * Copyright © 2005 Red Hat, Inc.
6  * Copyright © 2011 Intel Corporation
7  *
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.
15  *
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
21  *
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/
26  *
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.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is University of Southern
34  * California.
35  *
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>
40  */
41
42 #include "cairoint.h"
43
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
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);
75
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)
84 {
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++;
92         }
93
94         if (x2 > x1)
95             blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
96
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));
103 }
104
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)
111 {
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++;
119         }
120
121         if (y2 > y1)
122             do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
123
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);
130 }
131
132 struct blt_in {
133     const cairo_traps_compositor_t *compositor;
134     cairo_surface_t *dst;
135     cairo_boxes_t boxes;
136 };
137
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)
142 {
143     struct blt_in *info = closure;
144     cairo_color_t color;
145
146     if (CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage))
147         return;
148
149     _cairo_box_from_integers (&info->boxes.chunks.base[0], x, y, w, h);
150
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);
155 }
156
157 static void
158 add_rect_with_offset (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2, int dx, int dy)
159 {
160     cairo_box_t box;
161     cairo_int_status_t status;
162
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);
167
168     status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
169     assert (status == CAIRO_INT_STATUS_SUCCESS);
170 }
171
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)
177 {
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;
187
188     TRACE ((stderr, "%s\n", __FUNCTION__));
189
190     status = _cairo_clip_get_polygon (clip, &polygon,
191                                       &fill_rule, &antialias);
192     if (status)
193         return status;
194
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;
202
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;
209     }
210
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);
216
217     _cairo_traps_extents (&traps, &box);
218     _cairo_box_round_to_rectangle (&box, &fixup);
219     _cairo_traps_fini (&traps);
220     cairo_surface_destroy (src);
221
222     if (unlikely (status))
223         return status;
224
225     if (! _cairo_rectangle_intersect (&fixup, extents))
226         return CAIRO_STATUS_SUCCESS;
227
228     if (fixup.width < extents->width || fixup.height < extents->height) {
229         cairo_boxes_t clear;
230
231         _cairo_boxes_init (&clear);
232
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);
240         }
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);
248         }
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);
257         }
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);
266         }
267
268         status = compositor->fill_boxes (mask,
269                                          CAIRO_OPERATOR_CLEAR,
270                                          CAIRO_COLOR_TRANSPARENT,
271                                          &clear);
272
273         _cairo_boxes_fini (&clear);
274     }
275
276     return status;
277 }
278
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)
284 {
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;
294
295     TRACE ((stderr, "%s\n", __FUNCTION__));
296
297     status = _cairo_clip_get_polygon (composite->clip, &polygon,
298                                       &fill_rule, &antialias);
299     if (status)
300         return status;
301
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;
309
310     mask = _cairo_surface_create_similar_scratch (composite->surface,
311                                                   CAIRO_CONTENT_ALPHA,
312                                                   extents->width,
313                                                   extents->height);
314     if (unlikely (mask->status)) {
315         _cairo_traps_fini (&traps);
316         return status;
317     }
318
319     src = compositor->pattern_to_surface (mask, NULL, FALSE,
320                                           extents, NULL,
321                                           &src_x, &src_y);
322     if (unlikely (status = src->status))
323         goto error;
324
325     status = compositor->acquire (mask);
326     if (unlikely (status))
327         goto error;
328
329     _cairo_boxes_init_from_rectangle (&clear,
330                                       0, 0,
331                                       extents->width,
332                                       extents->height);
333     status = compositor->fill_boxes (mask,
334                                      CAIRO_OPERATOR_CLEAR,
335                                      CAIRO_COLOR_TRANSPARENT,
336                                      &clear);
337     if (unlikely (status))
338         goto error_release;
339
340     status = compositor->composite_traps (mask, CAIRO_OPERATOR_ADD, src,
341                                           src_x, src_y,
342                                           extents->x, extents->y,
343                                           extents,
344                                           antialias, &traps);
345     if (unlikely (status))
346         goto error_release;
347
348     compositor->release (mask);
349     *surface = mask;
350 out:
351     cairo_surface_destroy (src);
352     _cairo_traps_fini (&traps);
353     return status;
354
355 error_release:
356     compositor->release (mask);
357 error:
358     cairo_surface_destroy (mask);
359     goto out;
360 }
361
362 static cairo_surface_t *
363 traps_get_clip_surface (const cairo_traps_compositor_t *compositor,
364                         const cairo_composite_rectangles_t *composite,
365                         const cairo_rectangle_int_t *extents)
366 {
367     cairo_surface_t *surface = NULL;
368     cairo_int_status_t status;
369
370     TRACE ((stderr, "%s\n", __FUNCTION__));
371
372     status = __clip_to_surface (compositor, composite, extents, &surface);
373     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
374         surface = _cairo_surface_create_similar_solid (composite->surface,
375                                                        CAIRO_CONTENT_ALPHA,
376                                                        extents->width,
377                                                        extents->height,
378                                                        CAIRO_COLOR_WHITE);
379         if (unlikely (surface->status))
380             return surface;
381
382         status = _cairo_clip_combine_with_surface (composite->clip, surface,
383                                                    extents->x, extents->y);
384     }
385     if (unlikely (status)) {
386         cairo_surface_destroy (surface);
387         surface = _cairo_surface_create_in_error (status);
388     }
389
390     return surface;
391 }
392
393 static void blt_unaligned_boxes(const cairo_traps_compositor_t *compositor,
394                                 cairo_surface_t *surface,
395                                 int dx, int dy,
396                                 cairo_box_t *boxes,
397                                 int num_boxes)
398 {
399     struct blt_in info;
400     int i;
401
402     info.compositor = compositor;
403     info.dst = surface;
404     _cairo_boxes_init (&info.boxes);
405     info.boxes.num_boxes = 1;
406     for (i = 0; i < num_boxes; i++) {
407         cairo_box_t *b = &boxes[i];
408
409         if (! _cairo_fixed_is_integer (b->p1.x) ||
410             ! _cairo_fixed_is_integer (b->p1.y) ||
411             ! _cairo_fixed_is_integer (b->p2.x) ||
412             ! _cairo_fixed_is_integer (b->p2.y))
413         {
414             do_unaligned_box(blt_in, &info, b, dx, dy);
415         }
416     }
417 }
418
419 static cairo_surface_t *
420 create_composite_mask (const cairo_traps_compositor_t *compositor,
421                        cairo_surface_t          *dst,
422                        void                     *draw_closure,
423                        draw_func_t               draw_func,
424                        draw_func_t               mask_func,
425                        const cairo_composite_rectangles_t *extents)
426 {
427     cairo_surface_t *surface, *src;
428     cairo_int_status_t status;
429     int src_x, src_y;
430
431     TRACE ((stderr, "%s\n", __FUNCTION__));
432
433     surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA,
434                                                      extents->bounded.width,
435                                                      extents->bounded.height);
436     if (unlikely (surface->status))
437         return surface;
438
439     src = compositor->pattern_to_surface (surface,
440                                           &_cairo_pattern_white.base,
441                                           FALSE,
442                                           &extents->bounded,
443                                           &extents->bounded,
444                                           &src_x, &src_y);
445     if (unlikely (src->status)) {
446         cairo_surface_destroy (surface);
447         return src;
448     }
449
450     status = compositor->acquire (surface);
451     if (unlikely (status)) {
452         cairo_surface_destroy (src);
453         cairo_surface_destroy (surface);
454         return _cairo_surface_create_in_error (status);
455     }
456
457     if (!surface->is_clear) {
458         cairo_boxes_t clear;
459
460         _cairo_boxes_init_from_rectangle (&clear,
461                                           0, 0,
462                                           extents->bounded.width,
463                                           extents->bounded.height);
464         status = compositor->fill_boxes (surface,
465                                          CAIRO_OPERATOR_CLEAR,
466                                          CAIRO_COLOR_TRANSPARENT,
467                                          &clear);
468         if (unlikely (status))
469             goto error;
470
471         surface->is_clear = TRUE;
472     }
473
474     if (mask_func) {
475         status = mask_func (compositor, surface, draw_closure,
476                             CAIRO_OPERATOR_SOURCE, src, src_x, src_y,
477                             extents->bounded.x, extents->bounded.y,
478                             &extents->bounded, extents->clip);
479         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
480             surface->is_clear = FALSE;
481             goto out;
482         }
483         if (unlikely (status != CAIRO_INT_STATUS_UNSUPPORTED))
484             goto error;
485     }
486
487     /* Is it worth setting the clip region here? */
488     status = draw_func (compositor, surface, draw_closure,
489                         CAIRO_OPERATOR_ADD, src, src_x, src_y,
490                         extents->bounded.x, extents->bounded.y,
491                         &extents->bounded, NULL);
492     if (unlikely (status))
493         goto error;
494
495     surface->is_clear = FALSE;
496     if (extents->clip->path != NULL) {
497         status = combine_clip_as_traps (compositor, surface,
498                                         extents->clip, &extents->bounded);
499         if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
500             status = _cairo_clip_combine_with_surface (extents->clip, surface,
501                                                        extents->bounded.x,
502                                                        extents->bounded.y);
503         }
504         if (unlikely (status))
505             goto error;
506     } else if (extents->clip->boxes) {
507         blt_unaligned_boxes(compositor, surface,
508                             extents->bounded.x, extents->bounded.y,
509                             extents->clip->boxes, extents->clip->num_boxes);
510
511     }
512
513 out:
514     compositor->release (surface);
515     cairo_surface_destroy (src);
516     return surface;
517
518 error:
519     compositor->release (surface);
520     if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
521         cairo_surface_destroy (surface);
522         surface = _cairo_surface_create_in_error (status);
523     }
524     cairo_surface_destroy (src);
525     return surface;
526 }
527
528 /* Handles compositing with a clip surface when the operator allows
529  * us to combine the clip with the mask
530  */
531 static cairo_status_t
532 clip_and_composite_with_mask (const cairo_traps_compositor_t *compositor,
533                               const cairo_composite_rectangles_t*extents,
534                               draw_func_t                draw_func,
535                               draw_func_t                mask_func,
536                               void                      *draw_closure,
537                               cairo_operator_t           op,
538                               cairo_surface_t   *src,
539                               int src_x, int src_y)
540 {
541     cairo_surface_t *dst = extents->surface;
542     cairo_surface_t *mask;
543
544     TRACE ((stderr, "%s\n", __FUNCTION__));
545
546     mask = create_composite_mask (compositor, dst, draw_closure,
547                                   draw_func, mask_func,
548                                   extents);
549     if (unlikely (mask->status))
550         return mask->status;
551
552     if (mask->is_clear)
553         goto skip;
554
555     if (src != NULL || dst->content != CAIRO_CONTENT_ALPHA) {
556         compositor->composite (dst, op, src, mask,
557                                extents->bounded.x + src_x,
558                                extents->bounded.y + src_y,
559                                0, 0,
560                                extents->bounded.x,      extents->bounded.y,
561                                extents->bounded.width,  extents->bounded.height);
562     } else {
563         compositor->composite (dst, op, mask, NULL,
564                                0, 0,
565                                0, 0,
566                                extents->bounded.x,      extents->bounded.y,
567                                extents->bounded.width,  extents->bounded.height);
568     }
569
570 skip:
571     cairo_surface_destroy (mask);
572     return CAIRO_STATUS_SUCCESS;
573 }
574
575 /* Handles compositing with a clip surface when we have to do the operation
576  * in two pieces and combine them together.
577  */
578 static cairo_status_t
579 clip_and_composite_combine (const cairo_traps_compositor_t *compositor,
580                             const cairo_composite_rectangles_t*extents,
581                             draw_func_t          draw_func,
582                             void                        *draw_closure,
583                             cairo_operator_t             op,
584                             cairo_surface_t     *src,
585                             int src_x, int src_y)
586 {
587     cairo_surface_t *dst = extents->surface;
588     cairo_surface_t *tmp, *clip;
589     cairo_status_t status;
590
591     TRACE ((stderr, "%s\n", __FUNCTION__));
592
593     tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
594                                                  extents->bounded.width,
595                                                  extents->bounded.height);
596     if (unlikely (tmp->status))
597         return tmp->status;
598
599     status = compositor->acquire (tmp);
600     if (unlikely (status)) {
601         cairo_surface_destroy (tmp);
602         return status;
603     }
604
605     compositor->composite (tmp,
606                            dst->is_clear ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
607                            dst, NULL,
608                            extents->bounded.x,      extents->bounded.y,
609                            0, 0,
610                            0, 0,
611                            extents->bounded.width,  extents->bounded.height);
612
613     status = draw_func (compositor, tmp, draw_closure, op,
614                         src, src_x, src_y,
615                         extents->bounded.x, extents->bounded.y,
616                         &extents->bounded, NULL);
617
618     if (unlikely (status))
619         goto cleanup;
620
621     clip = traps_get_clip_surface (compositor, extents, &extents->bounded);
622     if (unlikely ((status = clip->status)))
623         goto cleanup;
624
625     if (dst->is_clear) {
626         compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
627                                0, 0,
628                                0, 0,
629                                extents->bounded.x,      extents->bounded.y,
630                                extents->bounded.width,  extents->bounded.height);
631     } else {
632         compositor->lerp (dst, tmp, clip,
633                           0, 0,
634                           0,0,
635                           extents->bounded.x,     extents->bounded.y,
636                           extents->bounded.width, extents->bounded.height);
637     }
638     cairo_surface_destroy (clip);
639
640 cleanup:
641     compositor->release (tmp);
642     cairo_surface_destroy (tmp);
643
644     return status;
645 }
646
647 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
648  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
649  */
650 static cairo_status_t
651 clip_and_composite_source (const cairo_traps_compositor_t       *compositor,
652                            cairo_surface_t                      *dst,
653                            draw_func_t                           draw_func,
654                            draw_func_t                           mask_func,
655                            void                                 *draw_closure,
656                            cairo_surface_t              *src,
657                            int src_x,
658                            int src_y,
659                            const cairo_composite_rectangles_t   *extents)
660 {
661     cairo_surface_t *mask;
662
663     TRACE ((stderr, "%s\n", __FUNCTION__));
664
665     /* Create a surface that is mask IN clip */
666     mask = create_composite_mask (compositor, dst, draw_closure,
667                                   draw_func, mask_func,
668                                   extents);
669     if (unlikely (mask->status))
670         return mask->status;
671
672     if (mask->is_clear)
673         goto skip;
674
675     if (dst->is_clear) {
676         compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask,
677                                extents->bounded.x + src_x, extents->bounded.y + src_y,
678                                0, 0,
679                                extents->bounded.x,      extents->bounded.y,
680                                extents->bounded.width,  extents->bounded.height);
681     } else {
682         compositor->lerp (dst, src, mask,
683                           extents->bounded.x + src_x, extents->bounded.y + src_y,
684                           0, 0,
685                           extents->bounded.x,     extents->bounded.y,
686                           extents->bounded.width, extents->bounded.height);
687     }
688
689 skip:
690     cairo_surface_destroy (mask);
691
692     return CAIRO_STATUS_SUCCESS;
693 }
694
695 static cairo_bool_t
696 can_reduce_alpha_op (cairo_operator_t op)
697 {
698     int iop = op;
699     switch (iop) {
700     case CAIRO_OPERATOR_OVER:
701     case CAIRO_OPERATOR_SOURCE:
702     case CAIRO_OPERATOR_ADD:
703         return TRUE;
704     default:
705         return FALSE;
706     }
707 }
708
709 static cairo_bool_t
710 reduce_alpha_op (cairo_composite_rectangles_t *extents)
711 {
712     cairo_surface_t *dst = extents->surface;
713     cairo_operator_t op = extents->op;
714     const cairo_pattern_t *pattern = &extents->source_pattern.base;
715     return dst->is_clear &&
716            dst->content == CAIRO_CONTENT_ALPHA &&
717            _cairo_pattern_is_opaque_solid (pattern) &&
718            can_reduce_alpha_op (op);
719 }
720
721 static cairo_status_t
722 fixup_unbounded_with_mask (const cairo_traps_compositor_t *compositor,
723                            const cairo_composite_rectangles_t *extents)
724 {
725     cairo_surface_t *dst = extents->surface;
726     cairo_surface_t *mask;
727
728     TRACE ((stderr, "%s\n", __FUNCTION__));
729
730     /* XXX can we avoid querying the clip surface again? */
731     mask = traps_get_clip_surface (compositor, extents, &extents->unbounded);
732     if (unlikely (mask->status))
733         return mask->status;
734
735     /* top */
736     if (extents->bounded.y != extents->unbounded.y) {
737         int x = extents->unbounded.x;
738         int y = extents->unbounded.y;
739         int width = extents->unbounded.width;
740         int height = extents->bounded.y - y;
741
742         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
743                                0, 0,
744                                0, 0,
745                                x, y,
746                                width, height);
747     }
748
749     /* left */
750     if (extents->bounded.x != extents->unbounded.x) {
751         int x = extents->unbounded.x;
752         int y = extents->bounded.y;
753         int width = extents->bounded.x - x;
754         int height = extents->bounded.height;
755
756         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
757                                0, y - extents->unbounded.y,
758                                0, 0,
759                                x, y,
760                                width, height);
761     }
762
763     /* right */
764     if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
765         int x = extents->bounded.x + extents->bounded.width;
766         int y = extents->bounded.y;
767         int width = extents->unbounded.x + extents->unbounded.width - x;
768         int height = extents->bounded.height;
769
770         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
771                                x - extents->unbounded.x, y - extents->unbounded.y,
772                                0, 0,
773                                x, y,
774                                width, height);
775     }
776
777     /* bottom */
778     if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
779         int x = extents->unbounded.x;
780         int y = extents->bounded.y + extents->bounded.height;
781         int width = extents->unbounded.width;
782         int height = extents->unbounded.y + extents->unbounded.height - y;
783
784         compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
785                                0, y - extents->unbounded.y,
786                                0, 0,
787                                x, y,
788                                width, height);
789     }
790
791     cairo_surface_destroy (mask);
792
793     return CAIRO_STATUS_SUCCESS;
794 }
795
796 static void
797 add_rect (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2)
798 {
799     cairo_box_t box;
800     cairo_int_status_t status;
801
802     box.p1.x = _cairo_fixed_from_int (x1);
803     box.p1.y = _cairo_fixed_from_int (y1);
804     box.p2.x = _cairo_fixed_from_int (x2);
805     box.p2.y = _cairo_fixed_from_int (y2);
806
807     status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
808     assert (status == CAIRO_INT_STATUS_SUCCESS);
809 }
810
811 static cairo_status_t
812 fixup_unbounded (const cairo_traps_compositor_t *compositor,
813                  cairo_composite_rectangles_t *extents,
814                  cairo_boxes_t *boxes)
815 {
816     cairo_surface_t *dst = extents->surface;
817     cairo_boxes_t clear, tmp;
818     cairo_box_t box;
819     cairo_int_status_t status;
820
821     TRACE ((stderr, "%s\n", __FUNCTION__));
822
823     if (extents->bounded.width  == extents->unbounded.width &&
824         extents->bounded.height == extents->unbounded.height)
825     {
826         return CAIRO_STATUS_SUCCESS;
827     }
828
829     assert (extents->clip->path == NULL);
830
831     /* subtract the drawn boxes from the unbounded area */
832     _cairo_boxes_init (&clear);
833
834     box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
835     box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
836     box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
837     box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
838
839     if (boxes == NULL) {
840         if (extents->bounded.width == 0 || extents->bounded.height == 0) {
841             goto empty;
842         } else {
843             /* top */
844             if (extents->bounded.y != extents->unbounded.y) {
845                 add_rect (&clear,
846                           extents->unbounded.x, extents->unbounded.y,
847                           extents->unbounded.x + extents->unbounded.width,
848                           extents->bounded.y);
849             }
850             /* left */
851             if (extents->bounded.x != extents->unbounded.x) {
852                 add_rect (&clear,
853                           extents->unbounded.x, extents->bounded.y,
854                           extents->bounded.x,
855                           extents->bounded.y + extents->bounded.height);
856             }
857             /* right */
858             if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
859                 add_rect (&clear,
860                           extents->bounded.x + extents->bounded.width,
861                           extents->bounded.y,
862                           extents->unbounded.x + extents->unbounded.width,
863                           extents->bounded.y + extents->bounded.height);
864             }
865             /* bottom */
866             if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
867                 add_rect (&clear,
868                           extents->unbounded.x,
869                           extents->bounded.y + extents->bounded.height,
870                           extents->unbounded.x + extents->unbounded.width,
871                           extents->unbounded.y + extents->unbounded.height);
872             }
873         }
874     } else if (boxes->num_boxes) {
875         _cairo_boxes_init (&tmp);
876
877         assert (boxes->is_pixel_aligned);
878
879         status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
880         assert (status == CAIRO_INT_STATUS_SUCCESS);
881
882         tmp.chunks.next = &boxes->chunks;
883         tmp.num_boxes += boxes->num_boxes;
884
885         status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
886                                                           CAIRO_FILL_RULE_WINDING,
887                                                           &clear);
888         tmp.chunks.next = NULL;
889         if (unlikely (status))
890             goto error;
891     } else {
892 empty:
893         box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
894         box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
895
896         status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
897         assert (status == CAIRO_INT_STATUS_SUCCESS);
898     }
899
900     /* Now intersect with the clip boxes */
901     if (extents->clip->num_boxes) {
902         _cairo_boxes_init_for_array (&tmp,
903                                      extents->clip->boxes,
904                                      extents->clip->num_boxes);
905         status = _cairo_boxes_intersect (&clear, &tmp, &clear);
906         if (unlikely (status))
907             goto error;
908     }
909
910     status = compositor->fill_boxes (dst,
911                                      CAIRO_OPERATOR_CLEAR,
912                                      CAIRO_COLOR_TRANSPARENT,
913                                      &clear);
914
915 error:
916     _cairo_boxes_fini (&clear);
917     return status;
918 }
919
920 enum {
921     NEED_CLIP_REGION = 0x1,
922     NEED_CLIP_SURFACE = 0x2,
923     FORCE_CLIP_REGION = 0x4,
924 };
925
926 static cairo_bool_t
927 need_bounded_clip (cairo_composite_rectangles_t *extents)
928 {
929     unsigned int flags = 0;
930
931     if (extents->unbounded.width < extents->destination.width ||
932         extents->unbounded.height < extents->destination.height)
933     {
934         flags |= NEED_CLIP_REGION;
935     }
936
937     if (! _cairo_clip_is_region (extents->clip))
938         flags |= NEED_CLIP_SURFACE;
939
940     return flags;
941 }
942
943 static cairo_bool_t
944 need_unbounded_clip (cairo_composite_rectangles_t *extents)
945 {
946     unsigned int flags = 0;
947     if (! extents->is_bounded) {
948         flags |= NEED_CLIP_REGION;
949         if (! _cairo_clip_is_region (extents->clip))
950             flags |= NEED_CLIP_SURFACE;
951     }
952     if (extents->clip->path != NULL)
953         flags |= NEED_CLIP_SURFACE;
954     return flags;
955 }
956
957 static cairo_status_t
958 clip_and_composite (const cairo_traps_compositor_t *compositor,
959                     cairo_composite_rectangles_t *extents,
960                     draw_func_t          draw_func,
961                     draw_func_t          mask_func,
962                     void                *draw_closure,
963                     unsigned int need_clip)
964 {
965     cairo_surface_t *dst = extents->surface;
966     cairo_operator_t op = extents->op;
967     cairo_pattern_t *source = &extents->source_pattern.base;
968     cairo_surface_t *src;
969     int src_x, src_y;
970     cairo_region_t *clip_region = NULL;
971     cairo_status_t status = CAIRO_STATUS_SUCCESS;
972
973     TRACE ((stderr, "%s\n", __FUNCTION__));
974
975     if (reduce_alpha_op (extents)) {
976         op = CAIRO_OPERATOR_ADD;
977         source = NULL;
978     }
979
980     if (op == CAIRO_OPERATOR_CLEAR) {
981         op = CAIRO_OPERATOR_DEST_OUT;
982         source = NULL;
983     }
984
985     compositor->acquire (dst);
986
987     if (need_clip & NEED_CLIP_REGION) {
988         const cairo_rectangle_int_t *limit;
989
990         if ((need_clip & FORCE_CLIP_REGION) == 0)
991             limit = &extents->unbounded;
992         else
993             limit = &extents->destination;
994
995         clip_region = _cairo_clip_get_region (extents->clip);
996         if (clip_region != NULL &&
997             cairo_region_contains_rectangle (clip_region,
998                                              limit) == CAIRO_REGION_OVERLAP_IN)
999             clip_region = NULL;
1000
1001         if (clip_region != NULL) {
1002             status = compositor->set_clip_region (dst, clip_region);
1003             if (unlikely (status)) {
1004                 compositor->release (dst);
1005                 return status;
1006             }
1007         }
1008     }
1009
1010     if (extents->bounded.width == 0 || extents->bounded.height == 0)
1011         goto skip;
1012
1013     src = compositor->pattern_to_surface (dst, source, FALSE,
1014                                           &extents->bounded,
1015                                           &extents->source_sample_area,
1016                                           &src_x, &src_y);
1017     if (unlikely (status = src->status))
1018         goto error;
1019
1020     if (op == CAIRO_OPERATOR_SOURCE) {
1021         status = clip_and_composite_source (compositor, dst,
1022                                             draw_func, mask_func, draw_closure,
1023                                             src, src_x, src_y,
1024                                             extents);
1025     } else {
1026         if (need_clip & NEED_CLIP_SURFACE) {
1027             if (extents->is_bounded) {
1028                 status = clip_and_composite_with_mask (compositor, extents,
1029                                                        draw_func, mask_func,
1030                                                        draw_closure,
1031                                                        op, src, src_x, src_y);
1032             } else {
1033                 status = clip_and_composite_combine (compositor, extents,
1034                                                      draw_func, draw_closure,
1035                                                      op, src, src_x, src_y);
1036             }
1037         } else {
1038             status = draw_func (compositor,
1039                                 dst, draw_closure,
1040                                 op, src, src_x, src_y,
1041                                 0, 0,
1042                                 &extents->bounded,
1043                                 extents->clip);
1044         }
1045     }
1046     cairo_surface_destroy (src);
1047
1048 skip:
1049     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
1050         if (need_clip & NEED_CLIP_SURFACE)
1051             status = fixup_unbounded_with_mask (compositor, extents);
1052         else
1053             status = fixup_unbounded (compositor, extents, NULL);
1054     }
1055
1056 error:
1057     if (clip_region)
1058         compositor->set_clip_region (dst, NULL);
1059
1060     compositor->release (dst);
1061
1062     return status;
1063 }
1064
1065 /* meta-ops */
1066
1067 typedef struct {
1068     cairo_traps_t traps;
1069     cairo_antialias_t antialias;
1070 } composite_traps_info_t;
1071
1072 static cairo_int_status_t
1073 composite_traps (const cairo_traps_compositor_t *compositor,
1074                  cairo_surface_t                *dst,
1075                  void                            *closure,
1076                  cairo_operator_t                op,
1077                  cairo_surface_t                *src,
1078                  int src_x, int src_y,
1079                  int dst_x, int dst_y,
1080                  const cairo_rectangle_int_t *extents,
1081                  cairo_clip_t                   *clip)
1082 {
1083     composite_traps_info_t *info = closure;
1084
1085     TRACE ((stderr, "%s\n", __FUNCTION__));
1086
1087     return compositor->composite_traps (dst, op, src,
1088                                         src_x - dst_x, src_y - dst_y,
1089                                         dst_x, dst_y,
1090                                         extents,
1091                                         info->antialias, &info->traps);
1092 }
1093
1094 typedef struct {
1095     cairo_tristrip_t strip;
1096     cairo_antialias_t antialias;
1097 } composite_tristrip_info_t;
1098
1099 static cairo_int_status_t
1100 composite_tristrip (const cairo_traps_compositor_t *compositor,
1101                     cairo_surface_t             *dst,
1102                     void                                 *closure,
1103                     cairo_operator_t             op,
1104                     cairo_surface_t             *src,
1105                     int src_x, int src_y,
1106                     int dst_x, int dst_y,
1107                     const cairo_rectangle_int_t *extents,
1108                     cairo_clip_t                        *clip)
1109 {
1110     composite_tristrip_info_t *info = closure;
1111
1112     TRACE ((stderr, "%s\n", __FUNCTION__));
1113
1114     return compositor->composite_tristrip (dst, op, src,
1115                                            src_x - dst_x, src_y - dst_y,
1116                                            dst_x, dst_y,
1117                                            extents,
1118                                            info->antialias, &info->strip);
1119 }
1120
1121 static cairo_bool_t
1122 is_recording_pattern (const cairo_pattern_t *pattern)
1123 {
1124     cairo_surface_t *surface;
1125
1126     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
1127         return FALSE;
1128
1129     surface = ((const cairo_surface_pattern_t *) pattern)->surface;
1130     surface = _cairo_surface_get_source (surface, NULL);
1131     return _cairo_surface_is_recording (surface);
1132 }
1133
1134 static cairo_surface_t *
1135 recording_pattern_get_surface (const cairo_pattern_t *pattern)
1136 {
1137     cairo_surface_t *surface;
1138
1139     surface = ((const cairo_surface_pattern_t *) pattern)->surface;
1140     return _cairo_surface_get_source (surface, NULL);
1141 }
1142
1143 static cairo_bool_t
1144 recording_pattern_contains_sample (const cairo_pattern_t *pattern,
1145                                    const cairo_rectangle_int_t *sample)
1146 {
1147     cairo_recording_surface_t *surface;
1148
1149     if (! is_recording_pattern (pattern))
1150         return FALSE;
1151
1152     if (pattern->extend == CAIRO_EXTEND_NONE)
1153         return TRUE;
1154
1155     surface = (cairo_recording_surface_t *) recording_pattern_get_surface (pattern);
1156     if (surface->unbounded)
1157         return TRUE;
1158
1159     return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
1160 }
1161
1162 static cairo_bool_t
1163 op_reduces_to_source (cairo_composite_rectangles_t *extents)
1164 {
1165     if (extents->op == CAIRO_OPERATOR_SOURCE)
1166         return TRUE;
1167
1168     if (extents->surface->is_clear)
1169         return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
1170
1171     return FALSE;
1172 }
1173
1174 static cairo_status_t
1175 composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
1176                          cairo_composite_rectangles_t *extents,
1177                          cairo_boxes_t *boxes)
1178 {
1179     cairo_surface_t *dst = extents->surface;
1180     cairo_operator_t op = extents->op;
1181     cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (extents->clip);
1182     cairo_bool_t op_is_source;
1183     cairo_status_t status;
1184
1185     TRACE ((stderr, "%s\n", __FUNCTION__));
1186
1187     if (need_clip_mask &&
1188         (! extents->is_bounded || extents->op == CAIRO_OPERATOR_SOURCE))
1189     {
1190         return CAIRO_INT_STATUS_UNSUPPORTED;
1191     }
1192
1193     op_is_source = op_reduces_to_source (extents);
1194
1195     /* Are we just copying a recording surface? */
1196     if (! need_clip_mask && op_is_source &&
1197         recording_pattern_contains_sample (&extents->source_pattern.base,
1198                                            &extents->source_sample_area))
1199     {
1200         cairo_clip_t *recording_clip;
1201         cairo_pattern_t *source = &extents->source_pattern.base;
1202
1203         /* XXX could also do tiling repeat modes... */
1204
1205         /* first clear the area about to be overwritten */
1206         if (! dst->is_clear) {
1207             status = compositor->acquire (dst);
1208             if (unlikely (status))
1209                 return status;
1210
1211             status = compositor->fill_boxes (dst,
1212                                              CAIRO_OPERATOR_CLEAR,
1213                                              CAIRO_COLOR_TRANSPARENT,
1214                                              boxes);
1215             compositor->release (dst);
1216             if (unlikely (status))
1217                 return status;
1218         }
1219
1220         recording_clip = _cairo_clip_from_boxes (boxes);
1221         status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
1222                                                             &source->matrix,
1223                                                             dst, recording_clip);
1224         _cairo_clip_destroy (recording_clip);
1225
1226         return status;
1227     }
1228
1229     status = compositor->acquire (dst);
1230     if (unlikely (status))
1231         return status;
1232
1233     if (! need_clip_mask &&
1234         (op == CAIRO_OPERATOR_CLEAR ||
1235          extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID))
1236     {
1237         const cairo_color_t *color;
1238
1239         if (op == CAIRO_OPERATOR_CLEAR) {
1240             color = CAIRO_COLOR_TRANSPARENT;
1241         } else {
1242             color = &((cairo_solid_pattern_t *) &extents->source_pattern)->color;
1243             if (op_is_source)
1244                 op = CAIRO_OPERATOR_SOURCE;
1245         }
1246
1247         status = compositor->fill_boxes (dst, op, color, boxes);
1248     }
1249     else
1250     {
1251         cairo_surface_t *src, *mask = NULL;
1252         cairo_pattern_t *source = &extents->source_pattern.base;
1253         int src_x, src_y;
1254         int mask_x = 0, mask_y = 0;
1255
1256         if (need_clip_mask) {
1257             mask = traps_get_clip_surface (compositor,
1258                                            extents, &extents->bounded);
1259             if (unlikely (mask->status))
1260                 return mask->status;
1261
1262             mask_x = -extents->bounded.x;
1263             mask_y = -extents->bounded.y;
1264
1265             if (op == CAIRO_OPERATOR_CLEAR) {
1266                 source = NULL;
1267                 op = CAIRO_OPERATOR_DEST_OUT;
1268             }
1269         } else if (op_is_source)
1270             op = CAIRO_OPERATOR_SOURCE;
1271
1272         src = compositor->pattern_to_surface (dst, source, FALSE,
1273                                               &extents->bounded,
1274                                               &extents->source_sample_area,
1275                                               &src_x, &src_y);
1276         if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
1277             status = compositor->composite_boxes (dst, op, src, mask,
1278                                                   src_x, src_y,
1279                                                   mask_x, mask_y,
1280                                                   0, 0,
1281                                                   boxes, &extents->bounded);
1282             cairo_surface_destroy (src);
1283         } else
1284             status = src->status;
1285
1286         cairo_surface_destroy (mask);
1287     }
1288
1289     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
1290         status = fixup_unbounded (compositor, extents, boxes);
1291
1292     compositor->release (dst);
1293
1294     return status;
1295 }
1296
1297 static cairo_status_t
1298 upload_boxes (const cairo_traps_compositor_t *compositor,
1299               cairo_composite_rectangles_t *extents,
1300               cairo_boxes_t *boxes)
1301 {
1302     cairo_surface_t *dst = extents->surface;
1303     const cairo_pattern_t *source = &extents->source_pattern.base;
1304     cairo_surface_t *src;
1305     cairo_rectangle_int_t limit;
1306     cairo_int_status_t status;
1307     int tx, ty;
1308
1309     TRACE ((stderr, "%s\n", __FUNCTION__));
1310
1311     src = _cairo_pattern_get_source((cairo_surface_pattern_t *)source,
1312                                     &limit);
1313     if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
1314         return CAIRO_INT_STATUS_UNSUPPORTED;
1315
1316     if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
1317         return CAIRO_INT_STATUS_UNSUPPORTED;
1318
1319     /* Check that the data is entirely within the image */
1320     if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
1321         return CAIRO_INT_STATUS_UNSUPPORTED;
1322
1323     if (extents->bounded.x + extents->bounded.width  + tx > limit.x + limit.width ||
1324         extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
1325         return CAIRO_INT_STATUS_UNSUPPORTED;
1326
1327     tx += limit.x;
1328     ty += limit.y;
1329
1330     if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
1331         status = compositor->draw_image_boxes (dst,
1332                                                (cairo_image_surface_t *)src,
1333                                                boxes, tx, ty);
1334     else
1335         status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
1336                                          tx, ty);
1337
1338     return status;
1339 }
1340
1341 static cairo_int_status_t
1342 trim_extents_to_traps (cairo_composite_rectangles_t *extents,
1343                        cairo_traps_t *traps)
1344 {
1345     cairo_box_t box;
1346
1347     _cairo_traps_extents (traps, &box);
1348     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
1349 }
1350
1351 static cairo_int_status_t
1352 trim_extents_to_tristrip (cairo_composite_rectangles_t *extents,
1353                           cairo_tristrip_t *strip)
1354 {
1355     cairo_box_t box;
1356
1357     _cairo_tristrip_extents (strip, &box);
1358     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
1359 }
1360
1361 static cairo_int_status_t
1362 trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
1363                        cairo_boxes_t *boxes)
1364 {
1365     cairo_box_t box;
1366
1367     _cairo_boxes_extents (boxes, &box);
1368     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
1369 }
1370
1371 static cairo_int_status_t
1372 boxes_for_traps (cairo_boxes_t *boxes,
1373                  cairo_traps_t *traps,
1374                  cairo_antialias_t antialias)
1375 {
1376     int i;
1377
1378     /* first check that the traps are rectilinear */
1379     if (antialias == CAIRO_ANTIALIAS_NONE) {
1380         for (i = 0; i < traps->num_traps; i++) {
1381             const cairo_trapezoid_t *t = &traps->traps[i];
1382             if (_cairo_fixed_integer_round_down (t->left.p1.x) !=
1383                 _cairo_fixed_integer_round_down (t->left.p2.x) ||
1384                 _cairo_fixed_integer_round_down (t->right.p1.x) !=
1385                 _cairo_fixed_integer_round_down (t->right.p2.x))
1386             {
1387                 return CAIRO_INT_STATUS_UNSUPPORTED;
1388             }
1389         }
1390     } else {
1391         for (i = 0; i < traps->num_traps; i++) {
1392             const cairo_trapezoid_t *t = &traps->traps[i];
1393             if (t->left.p1.x != t->left.p2.x || t->right.p1.x != t->right.p2.x)
1394                 return CAIRO_INT_STATUS_UNSUPPORTED;
1395         }
1396     }
1397
1398     _cairo_boxes_init (boxes);
1399
1400     boxes->num_boxes    = traps->num_traps;
1401     boxes->chunks.base  = (cairo_box_t *) traps->traps;
1402     boxes->chunks.count = traps->num_traps;
1403     boxes->chunks.size  = traps->num_traps;
1404
1405     if (antialias != CAIRO_ANTIALIAS_NONE) {
1406         for (i = 0; i < traps->num_traps; i++) {
1407             /* Note the traps and boxes alias so we need to take the local copies first. */
1408             cairo_fixed_t x1 = traps->traps[i].left.p1.x;
1409             cairo_fixed_t x2 = traps->traps[i].right.p1.x;
1410             cairo_fixed_t y1 = traps->traps[i].top;
1411             cairo_fixed_t y2 = traps->traps[i].bottom;
1412
1413             boxes->chunks.base[i].p1.x = x1;
1414             boxes->chunks.base[i].p1.y = y1;
1415             boxes->chunks.base[i].p2.x = x2;
1416             boxes->chunks.base[i].p2.y = y2;
1417
1418             if (boxes->is_pixel_aligned) {
1419                 boxes->is_pixel_aligned =
1420                     _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
1421                     _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
1422             }
1423         }
1424     } else {
1425         boxes->is_pixel_aligned = TRUE;
1426
1427         for (i = 0; i < traps->num_traps; i++) {
1428             /* Note the traps and boxes alias so we need to take the local copies first. */
1429             cairo_fixed_t x1 = traps->traps[i].left.p1.x;
1430             cairo_fixed_t x2 = traps->traps[i].right.p1.x;
1431             cairo_fixed_t y1 = traps->traps[i].top;
1432             cairo_fixed_t y2 = traps->traps[i].bottom;
1433
1434             /* round down here to match Pixman's behavior when using traps. */
1435             boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
1436             boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
1437             boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
1438             boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
1439         }
1440     }
1441
1442     return CAIRO_INT_STATUS_SUCCESS;
1443 }
1444
1445 static cairo_status_t
1446 clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
1447                           cairo_composite_rectangles_t *extents,
1448                           cairo_boxes_t *boxes);
1449
1450 static cairo_status_t
1451 clip_and_composite_polygon (const cairo_traps_compositor_t *compositor,
1452                             cairo_composite_rectangles_t *extents,
1453                             cairo_polygon_t *polygon,
1454                             cairo_antialias_t antialias,
1455                             cairo_fill_rule_t fill_rule,
1456                             cairo_bool_t curvy)
1457 {
1458     composite_traps_info_t traps;
1459     cairo_surface_t *dst = extents->surface;
1460     cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
1461     cairo_int_status_t status;
1462
1463     TRACE ((stderr, "%s\n", __FUNCTION__));
1464
1465     if (polygon->num_edges == 0) {
1466         status = CAIRO_INT_STATUS_SUCCESS;
1467
1468         if (! extents->is_bounded) {
1469             cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
1470
1471             if (clip_region &&
1472                 cairo_region_contains_rectangle (clip_region,
1473                                                  &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
1474                 clip_region = NULL;
1475
1476             if (clip_region != NULL) {
1477                 status = compositor->set_clip_region (dst, clip_region);
1478                 if (unlikely (status))
1479                     return status;
1480             }
1481
1482             if (clip_surface)
1483                 status = fixup_unbounded_with_mask (compositor, extents);
1484             else
1485                 status = fixup_unbounded (compositor, extents, NULL);
1486
1487             if (clip_region != NULL)
1488                 compositor->set_clip_region (dst, NULL);
1489         }
1490
1491         return status;
1492     }
1493
1494     if (extents->clip->path != NULL && extents->is_bounded) {
1495         cairo_polygon_t clipper;
1496         cairo_fill_rule_t clipper_fill_rule;
1497         cairo_antialias_t clipper_antialias;
1498
1499         status = _cairo_clip_get_polygon (extents->clip,
1500                                           &clipper,
1501                                           &clipper_fill_rule,
1502                                           &clipper_antialias);
1503         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1504             if (clipper_antialias == antialias) {
1505                 status = _cairo_polygon_intersect (polygon, fill_rule,
1506                                                    &clipper, clipper_fill_rule);
1507                 if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1508                     cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip);
1509                     _cairo_clip_destroy (extents->clip);
1510                     extents->clip = clip;
1511
1512                     fill_rule = CAIRO_FILL_RULE_WINDING;
1513                 }
1514                 _cairo_polygon_fini (&clipper);
1515             }
1516         }
1517     }
1518
1519     if (antialias == CAIRO_ANTIALIAS_NONE && curvy) {
1520         cairo_boxes_t boxes;
1521
1522         _cairo_boxes_init (&boxes);
1523         status = _cairo_rasterise_polygon_to_boxes (polygon, fill_rule, &boxes);
1524         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1525             assert (boxes.is_pixel_aligned);
1526             status = clip_and_composite_boxes (compositor, extents, &boxes);
1527         }
1528         _cairo_boxes_fini (&boxes);
1529         if ((status != CAIRO_INT_STATUS_UNSUPPORTED))
1530             return status;
1531     }
1532
1533     _cairo_traps_init (&traps.traps);
1534
1535     if (antialias == CAIRO_ANTIALIAS_NONE && curvy) {
1536         status = _cairo_rasterise_polygon_to_traps (polygon, fill_rule, antialias, &traps.traps);
1537     } else {
1538         status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
1539     }
1540     if (unlikely (status))
1541         goto CLEANUP_TRAPS;
1542
1543     status = trim_extents_to_traps (extents, &traps.traps);
1544     if (unlikely (status))
1545         goto CLEANUP_TRAPS;
1546
1547     /* Use a fast path if the trapezoids consist of a set of boxes.  */
1548     status = CAIRO_INT_STATUS_UNSUPPORTED;
1549     if (1) {
1550         cairo_boxes_t boxes;
1551
1552         status = boxes_for_traps (&boxes, &traps.traps, antialias);
1553         if (status == CAIRO_INT_STATUS_SUCCESS) {
1554             status = clip_and_composite_boxes (compositor, extents, &boxes);
1555             /* XXX need to reconstruct the traps! */
1556             assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
1557         }
1558     }
1559     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1560         /* Otherwise render the trapezoids to a mask and composite in the usual
1561          * fashion.
1562          */
1563         unsigned int flags = 0;
1564
1565         /* For unbounded operations, the X11 server will estimate the
1566          * affected rectangle and apply the operation to that. However,
1567          * there are cases where this is an overestimate (e.g. the
1568          * clip-fill-{eo,nz}-unbounded test).
1569          *
1570          * The clip will trim that overestimate to our expectations.
1571          */
1572         if (! extents->is_bounded)
1573                 flags |= FORCE_CLIP_REGION;
1574
1575         traps.antialias = antialias;
1576         status = clip_and_composite (compositor, extents,
1577                                      composite_traps, NULL, &traps,
1578                                      need_unbounded_clip (extents) | flags);
1579     }
1580
1581 CLEANUP_TRAPS:
1582     _cairo_traps_fini (&traps.traps);
1583
1584     return status;
1585 }
1586
1587 struct composite_opacity_info {
1588     const cairo_traps_compositor_t *compositor;
1589     uint8_t op;
1590     cairo_surface_t *dst;
1591     cairo_surface_t *src;
1592     int src_x, src_y;
1593     double opacity;
1594 };
1595
1596 static void composite_opacity(void *closure,
1597                               int16_t x, int16_t y,
1598                               int16_t w, int16_t h,
1599                               uint16_t coverage)
1600 {
1601     struct composite_opacity_info *info = closure;
1602     const cairo_traps_compositor_t *compositor = info->compositor;
1603     cairo_surface_t *mask;
1604     int mask_x, mask_y;
1605     cairo_color_t color;
1606     cairo_solid_pattern_t solid;
1607
1608     _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage);
1609     _cairo_pattern_init_solid (&solid, &color);
1610     mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE,
1611                                            &_cairo_unbounded_rectangle,
1612                                            &_cairo_unbounded_rectangle,
1613                                            &mask_x, &mask_y);
1614     if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
1615         if (info->src) {
1616             compositor->composite (info->dst, info->op, info->src, mask,
1617                                    x + info->src_x,  y + info->src_y,
1618                                    mask_x,           mask_y,
1619                                    x,                y,
1620                                    w,                h);
1621         } else {
1622             compositor->composite (info->dst, info->op, mask, NULL,
1623                                    mask_x,            mask_y,
1624                                    0,                 0,
1625                                    x,                 y,
1626                                    w,                 h);
1627         }
1628     }
1629
1630     cairo_surface_destroy (mask);
1631 }
1632
1633
1634 static cairo_int_status_t
1635 composite_opacity_boxes (const cairo_traps_compositor_t *compositor,
1636                          cairo_surface_t                *dst,
1637                          void                           *closure,
1638                          cairo_operator_t                op,
1639                          cairo_surface_t                *src,
1640                          int                             src_x,
1641                          int                             src_y,
1642                          int                             dst_x,
1643                          int                             dst_y,
1644                          const cairo_rectangle_int_t    *extents,
1645                          cairo_clip_t                   *clip)
1646 {
1647     const cairo_solid_pattern_t *mask = closure;
1648     struct composite_opacity_info info;
1649     int i;
1650
1651     TRACE ((stderr, "%s\n", __FUNCTION__));
1652
1653     info.compositor = compositor;
1654     info.op = op;
1655     info.dst = dst;
1656
1657     info.src = src;
1658     info.src_x = src_x;
1659     info.src_y = src_y;
1660
1661     info.opacity = mask->color.alpha / (double) 0xffff;
1662
1663     /* XXX for lots of boxes create a clip region for the fully opaque areas */
1664     for (i = 0; i < clip->num_boxes; i++)
1665         do_unaligned_box(composite_opacity, &info,
1666                          &clip->boxes[i], dst_x, dst_y);
1667
1668     return CAIRO_STATUS_SUCCESS;
1669 }
1670
1671 static cairo_int_status_t
1672 composite_boxes (const cairo_traps_compositor_t *compositor,
1673                  cairo_surface_t                *dst,
1674                  void                           *closure,
1675                  cairo_operator_t                op,
1676                  cairo_surface_t                *src,
1677                  int                             src_x,
1678                  int                             src_y,
1679                  int                             dst_x,
1680                  int                             dst_y,
1681                  const cairo_rectangle_int_t    *extents,
1682                  cairo_clip_t                   *clip)
1683 {
1684     cairo_traps_t traps;
1685     cairo_status_t status;
1686
1687     TRACE ((stderr, "%s\n", __FUNCTION__));
1688
1689     status = _cairo_traps_init_boxes (&traps, closure);
1690     if (unlikely (status))
1691         return status;
1692
1693     status = compositor->composite_traps (dst, op, src,
1694                                           src_x - dst_x, src_y - dst_y,
1695                                           dst_x, dst_y,
1696                                           extents,
1697                                           CAIRO_ANTIALIAS_DEFAULT, &traps);
1698     _cairo_traps_fini (&traps);
1699
1700     return status;
1701 }
1702
1703 static cairo_status_t
1704 clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
1705                           cairo_composite_rectangles_t *extents,
1706                           cairo_boxes_t *boxes)
1707 {
1708     cairo_int_status_t status;
1709
1710     TRACE ((stderr, "%s\n", __FUNCTION__));
1711
1712     if (boxes->num_boxes == 0 && extents->is_bounded)
1713         return CAIRO_STATUS_SUCCESS;
1714
1715     status = trim_extents_to_boxes (extents, boxes);
1716     if (unlikely (status))
1717         return status;
1718
1719     if (boxes->is_pixel_aligned && extents->clip->path == NULL &&
1720         extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
1721         (op_reduces_to_source (extents) ||
1722          (extents->op == CAIRO_OPERATOR_OVER &&
1723           (extents->source_pattern.surface.surface->content & CAIRO_CONTENT_ALPHA) == 0)))
1724     {
1725         status = upload_boxes (compositor, extents, boxes);
1726         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1727             return status;
1728     }
1729
1730     /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
1731     if (extents->clip->path != NULL && extents->is_bounded) {
1732         cairo_polygon_t polygon;
1733         cairo_fill_rule_t fill_rule;
1734         cairo_antialias_t antialias;
1735         cairo_clip_t *clip;
1736
1737         clip = _cairo_clip_copy (extents->clip);
1738         clip = _cairo_clip_intersect_boxes (clip, boxes);
1739         if (_cairo_clip_is_all_clipped (clip))
1740             return CAIRO_INT_STATUS_NOTHING_TO_DO;
1741
1742         status = _cairo_clip_get_polygon (clip, &polygon,
1743                                           &fill_rule, &antialias);
1744         _cairo_clip_path_destroy (clip->path);
1745         clip->path = NULL;
1746         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1747             cairo_clip_t *saved_clip = extents->clip;
1748             extents->clip = clip;
1749
1750             status = clip_and_composite_polygon (compositor, extents, &polygon,
1751                                                  antialias, fill_rule, FALSE);
1752
1753             clip = extents->clip;
1754             extents->clip = saved_clip;
1755
1756             _cairo_polygon_fini (&polygon);
1757         }
1758         _cairo_clip_destroy (clip);
1759
1760         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1761             return status;
1762     }
1763
1764     /* Use a fast path if the boxes are pixel aligned (or nearly aligned!) */
1765     if (boxes->is_pixel_aligned) {
1766         status = composite_aligned_boxes (compositor, extents, boxes);
1767         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1768             return status;
1769     }
1770
1771     return clip_and_composite (compositor, extents,
1772                                composite_boxes, NULL, boxes,
1773                                need_unbounded_clip (extents));
1774 }
1775
1776 static cairo_int_status_t
1777 composite_traps_as_boxes (const cairo_traps_compositor_t *compositor,
1778                           cairo_composite_rectangles_t *extents,
1779                           composite_traps_info_t *info)
1780 {
1781     cairo_boxes_t boxes;
1782
1783     TRACE ((stderr, "%s\n", __FUNCTION__));
1784
1785     if (! _cairo_traps_to_boxes (&info->traps, info->antialias, &boxes))
1786         return CAIRO_INT_STATUS_UNSUPPORTED;
1787
1788     return clip_and_composite_boxes (compositor, extents, &boxes);
1789 }
1790
1791 static cairo_int_status_t
1792 clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
1793                           cairo_composite_rectangles_t *extents,
1794                           composite_traps_info_t *info)
1795 {
1796     cairo_int_status_t status;
1797
1798     TRACE ((stderr, "%s\n", __FUNCTION__));
1799
1800     status = trim_extents_to_traps (extents, &info->traps);
1801     if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
1802         return status;
1803
1804     status = composite_traps_as_boxes (compositor, extents, info);
1805     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1806         unsigned int flags = 0;
1807
1808         /* For unbounded operations, the X11 server will estimate the
1809          * affected rectangle and apply the operation to that. However,
1810          * there are cases where this is an overestimate (e.g. the
1811          * clip-fill-{eo,nz}-unbounded test).
1812          *
1813          * The clip will trim that overestimate to our expectations.
1814          */
1815         if (! extents->is_bounded)
1816             flags |= FORCE_CLIP_REGION;
1817
1818         status = clip_and_composite (compositor, extents,
1819                                      composite_traps, NULL, info,
1820                                      need_unbounded_clip (extents) | flags);
1821     }
1822
1823     return status;
1824 }
1825
1826 static cairo_int_status_t
1827 clip_and_composite_tristrip (const cairo_traps_compositor_t *compositor,
1828                              cairo_composite_rectangles_t *extents,
1829                              composite_tristrip_info_t *info)
1830 {
1831     cairo_int_status_t status;
1832     unsigned int flags = 0;
1833
1834     TRACE ((stderr, "%s\n", __FUNCTION__));
1835
1836     status = trim_extents_to_tristrip (extents, &info->strip);
1837     if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
1838         return status;
1839
1840     if (! extents->is_bounded)
1841         flags |= FORCE_CLIP_REGION;
1842
1843     status = clip_and_composite (compositor, extents,
1844                                  composite_tristrip, NULL, info,
1845                                  need_unbounded_clip (extents) | flags);
1846
1847     return status;
1848 }
1849
1850 struct composite_mask {
1851     cairo_surface_t *mask;
1852     int mask_x, mask_y;
1853 };
1854
1855 static cairo_int_status_t
1856 composite_mask (const cairo_traps_compositor_t *compositor,
1857                 cairo_surface_t                 *dst,
1858                 void                            *closure,
1859                 cairo_operator_t                 op,
1860                 cairo_surface_t                 *src,
1861                 int                              src_x,
1862                 int                              src_y,
1863                 int                              dst_x,
1864                 int                              dst_y,
1865                 const cairo_rectangle_int_t     *extents,
1866                 cairo_clip_t                    *clip)
1867 {
1868     struct composite_mask *data = closure;
1869
1870     TRACE ((stderr, "%s\n", __FUNCTION__));
1871
1872     if (src != NULL) {
1873         compositor->composite (dst, op, src, data->mask,
1874                                extents->x + src_x, extents->y + src_y,
1875                                extents->x + data->mask_x, extents->y + data->mask_y,
1876                                extents->x - dst_x,  extents->y - dst_y,
1877                                extents->width,      extents->height);
1878     } else {
1879         compositor->composite (dst, op, data->mask, NULL,
1880                                extents->x + data->mask_x, extents->y + data->mask_y,
1881                                0, 0,
1882                                extents->x - dst_x,  extents->y - dst_y,
1883                                extents->width,      extents->height);
1884     }
1885
1886     return CAIRO_STATUS_SUCCESS;
1887 }
1888
1889 struct composite_box_info {
1890     const cairo_traps_compositor_t *compositor;
1891     cairo_surface_t *dst;
1892     cairo_surface_t *src;
1893     int src_x, src_y;
1894     uint8_t op;
1895 };
1896
1897 static void composite_box(void *closure,
1898                           int16_t x, int16_t y,
1899                           int16_t w, int16_t h,
1900                           uint16_t coverage)
1901 {
1902     struct composite_box_info *info = closure;
1903     const cairo_traps_compositor_t *compositor = info->compositor;
1904
1905     TRACE ((stderr, "%s\n", __FUNCTION__));
1906
1907     if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) {
1908         cairo_surface_t *mask;
1909         cairo_color_t color;
1910         cairo_solid_pattern_t solid;
1911         int mask_x, mask_y;
1912
1913         _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff);
1914         _cairo_pattern_init_solid (&solid, &color);
1915
1916         mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE,
1917                                                &_cairo_unbounded_rectangle,
1918                                                &_cairo_unbounded_rectangle,
1919                                                &mask_x, &mask_y);
1920
1921         if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
1922             compositor->composite (info->dst, info->op, info->src, mask,
1923                                    x + info->src_x,  y + info->src_y,
1924                                    mask_x,           mask_y,
1925                                    x,                y,
1926                                    w,                h);
1927         }
1928
1929         cairo_surface_destroy (mask);
1930     } else {
1931         compositor->composite (info->dst, info->op, info->src, NULL,
1932                                x + info->src_x,  y + info->src_y,
1933                                0,                0,
1934                                x,                y,
1935                                w,                h);
1936     }
1937 }
1938
1939 static cairo_int_status_t
1940 composite_mask_clip_boxes (const cairo_traps_compositor_t *compositor,
1941                            cairo_surface_t              *dst,
1942                            void                         *closure,
1943                            cairo_operator_t              op,
1944                            cairo_surface_t              *src,
1945                            int                           src_x,
1946                            int                           src_y,
1947                            int                           dst_x,
1948                            int                           dst_y,
1949                            const cairo_rectangle_int_t  *extents,
1950                            cairo_clip_t                 *clip)
1951 {
1952     struct composite_mask *data = closure;
1953     struct composite_box_info info;
1954     int i;
1955
1956     TRACE ((stderr, "%s\n", __FUNCTION__));
1957
1958     info.compositor = compositor;
1959     info.op = CAIRO_OPERATOR_SOURCE;
1960     info.dst = dst;
1961     info.src = data->mask;
1962     info.src_x = data->mask_x;
1963     info.src_y = data->mask_y;
1964
1965     info.src_x += dst_x;
1966     info.src_y += dst_y;
1967
1968     for (i = 0; i < clip->num_boxes; i++)
1969         do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
1970
1971     return CAIRO_STATUS_SUCCESS;
1972 }
1973
1974 static cairo_int_status_t
1975 composite_mask_clip (const cairo_traps_compositor_t *compositor,
1976                      cairo_surface_t                    *dst,
1977                      void                               *closure,
1978                      cairo_operator_t                    op,
1979                      cairo_surface_t                    *src,
1980                      int                                 src_x,
1981                      int                                 src_y,
1982                      int                                 dst_x,
1983                      int                                 dst_y,
1984                      const cairo_rectangle_int_t        *extents,
1985                      cairo_clip_t                       *clip)
1986 {
1987     struct composite_mask *data = closure;
1988     cairo_polygon_t polygon;
1989     cairo_fill_rule_t fill_rule;
1990     composite_traps_info_t info;
1991     cairo_status_t status;
1992
1993     TRACE ((stderr, "%s\n", __FUNCTION__));
1994
1995     status = _cairo_clip_get_polygon (clip, &polygon,
1996                                       &fill_rule, &info.antialias);
1997     if (unlikely (status))
1998         return status;
1999
2000     _cairo_traps_init (&info.traps);
2001     status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps,
2002                                                         &polygon,
2003                                                         fill_rule);
2004     _cairo_polygon_fini (&polygon);
2005     if (unlikely (status))
2006         return status;
2007
2008     status = composite_traps (compositor, dst, &info,
2009                               CAIRO_OPERATOR_SOURCE,
2010                               data->mask,
2011                               data->mask_x + dst_x, data->mask_y + dst_y,
2012                               dst_x, dst_y,
2013                               extents, NULL);
2014     _cairo_traps_fini (&info.traps);
2015
2016     return status;
2017 }
2018
2019 /* high-level compositor interface */
2020
2021 static cairo_int_status_t
2022 _cairo_traps_compositor_paint (const cairo_compositor_t *_compositor,
2023                                cairo_composite_rectangles_t *extents)
2024 {
2025     cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
2026     cairo_boxes_t boxes;
2027     cairo_int_status_t status;
2028
2029     TRACE ((stderr, "%s\n", __FUNCTION__));
2030
2031     status = compositor->check_composite (extents);
2032     if (unlikely (status))
2033         return status;
2034
2035      _cairo_clip_steal_boxes (extents->clip, &boxes);
2036      status = clip_and_composite_boxes (compositor, extents, &boxes);
2037      _cairo_clip_unsteal_boxes (extents->clip, &boxes);
2038
2039     return status;
2040 }
2041
2042 static cairo_int_status_t
2043 _cairo_traps_compositor_mask (const cairo_compositor_t *_compositor,
2044                               cairo_composite_rectangles_t *extents)
2045 {
2046     const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
2047     cairo_int_status_t status;
2048
2049     TRACE ((stderr, "%s\n", __FUNCTION__));
2050
2051     status = compositor->check_composite (extents);
2052     if (unlikely (status))
2053         return status;
2054
2055     if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
2056         extents->clip->path == NULL) {
2057         status = clip_and_composite (compositor, extents,
2058                                      composite_opacity_boxes,
2059                                      composite_opacity_boxes,
2060                                      &extents->mask_pattern,
2061                                      need_unbounded_clip (extents));
2062     } else {
2063         struct composite_mask data;
2064
2065         data.mask = compositor->pattern_to_surface (extents->surface,
2066                                                     &extents->mask_pattern.base,
2067                                                     TRUE,
2068                                                     &extents->bounded,
2069                                                     &extents->mask_sample_area,
2070                                                     &data.mask_x,
2071                                                     &data.mask_y);
2072         if (unlikely (data.mask->status))
2073             return data.mask->status;
2074
2075         status = clip_and_composite (compositor, extents,
2076                                      composite_mask,
2077                                      extents->clip->path ? composite_mask_clip : composite_mask_clip_boxes,
2078                                      &data, need_bounded_clip (extents));
2079
2080         cairo_surface_destroy (data.mask);
2081     }
2082
2083     return status;
2084 }
2085
2086 static cairo_int_status_t
2087 _cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor,
2088                                 cairo_composite_rectangles_t *extents,
2089                                 const cairo_path_fixed_t *path,
2090                                 const cairo_stroke_style_t *style,
2091                                 const cairo_matrix_t    *ctm,
2092                                 const cairo_matrix_t    *ctm_inverse,
2093                                 double                   tolerance,
2094                                 cairo_antialias_t        antialias)
2095 {
2096     const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
2097     cairo_int_status_t status;
2098
2099     TRACE ((stderr, "%s\n", __FUNCTION__));
2100
2101     status = compositor->check_composite (extents);
2102     if (unlikely (status))
2103         return status;
2104
2105     status = CAIRO_INT_STATUS_UNSUPPORTED;
2106     if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
2107         cairo_boxes_t boxes;
2108
2109         _cairo_boxes_init_with_clip (&boxes, extents->clip);
2110         status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
2111                                                                 style,
2112                                                                 ctm,
2113                                                                 antialias,
2114                                                                 &boxes);
2115         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2116             status = clip_and_composite_boxes (compositor, extents, &boxes);
2117         _cairo_boxes_fini (&boxes);
2118     }
2119
2120     if (status == CAIRO_INT_STATUS_UNSUPPORTED && 0 &&
2121         _cairo_clip_is_region (extents->clip)) /* XXX */
2122     {
2123         composite_tristrip_info_t info;
2124
2125         info.antialias = antialias;
2126         _cairo_tristrip_init_with_clip (&info.strip, extents->clip);
2127         status = _cairo_path_fixed_stroke_to_tristrip (path, style,
2128                                                        ctm, ctm_inverse,
2129                                                        tolerance,
2130                                                        &info.strip);
2131         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2132             status = clip_and_composite_tristrip (compositor, extents, &info);
2133         _cairo_tristrip_fini (&info.strip);
2134     }
2135
2136     if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
2137         path->has_curve_to && antialias == CAIRO_ANTIALIAS_NONE) {
2138         cairo_polygon_t polygon;
2139
2140         _cairo_polygon_init_with_clip (&polygon, extents->clip);
2141         status = _cairo_path_fixed_stroke_to_polygon (path, style,
2142                                                       ctm, ctm_inverse,
2143                                                       tolerance,
2144                                                       &polygon);
2145         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2146             status = clip_and_composite_polygon (compositor,
2147                                                  extents, &polygon,
2148                                                  CAIRO_ANTIALIAS_NONE,
2149                                                  CAIRO_FILL_RULE_WINDING,
2150                                                  TRUE);
2151         _cairo_polygon_fini (&polygon);
2152     }
2153
2154     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
2155         composite_traps_info_t info;
2156
2157         info.antialias = antialias;
2158         _cairo_traps_init_with_clip (&info.traps, extents->clip);
2159         status = _cairo_path_fixed_stroke_to_traps (path, style,
2160                                                     ctm, ctm_inverse,
2161                                                     tolerance,
2162                                                     &info.traps);
2163         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2164             status = clip_and_composite_traps (compositor, extents, &info);
2165         _cairo_traps_fini (&info.traps);
2166     }
2167
2168     return status;
2169 }
2170
2171 static cairo_int_status_t
2172 _cairo_traps_compositor_fill (const cairo_compositor_t *_compositor,
2173                               cairo_composite_rectangles_t *extents,
2174                               const cairo_path_fixed_t  *path,
2175                               cairo_fill_rule_t          fill_rule,
2176                               double                     tolerance,
2177                               cairo_antialias_t          antialias)
2178 {
2179     const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
2180     cairo_int_status_t status;
2181
2182     TRACE ((stderr, "%s\n", __FUNCTION__));
2183
2184     status = compositor->check_composite (extents);
2185     if (unlikely (status))
2186         return status;
2187
2188     status = CAIRO_INT_STATUS_UNSUPPORTED;
2189     if (_cairo_path_fixed_fill_is_rectilinear (path)) {
2190         cairo_boxes_t boxes;
2191
2192         _cairo_boxes_init_with_clip (&boxes, extents->clip);
2193         status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
2194                                                               fill_rule,
2195                                                               antialias,
2196                                                               &boxes);
2197         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
2198             status = clip_and_composite_boxes (compositor, extents, &boxes);
2199         _cairo_boxes_fini (&boxes);
2200     }
2201
2202     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
2203         cairo_polygon_t polygon;
2204
2205 #if 0
2206         if (extents->mask.width  > extents->unbounded.width ||
2207             extents->mask.height > extents->unbounded.height)
2208         {
2209             cairo_box_t limits;
2210             _cairo_box_from_rectangle (&limits, &extents->unbounded);
2211             _cairo_polygon_init (&polygon, &limits, 1);
2212         }
2213         else
2214         {
2215             _cairo_polygon_init (&polygon, NULL, 0);
2216         }
2217
2218         status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
2219         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
2220             status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
2221                                                           extents->clip->boxes,
2222                                                           extents->clip->num_boxes);
2223         }
2224 #else
2225         _cairo_polygon_init_with_clip (&polygon, extents->clip);
2226         status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
2227 #endif
2228         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
2229             status = clip_and_composite_polygon (compositor, extents, &polygon,
2230                                                  antialias, fill_rule, path->has_curve_to);
2231         }
2232         _cairo_polygon_fini (&polygon);
2233     }
2234
2235     return status;
2236 }
2237
2238 static cairo_int_status_t
2239 composite_glyphs (const cairo_traps_compositor_t *compositor,
2240                   cairo_surface_t       *dst,
2241                   void *closure,
2242                   cairo_operator_t       op,
2243                   cairo_surface_t       *src,
2244                   int src_x, int src_y,
2245                   int dst_x, int dst_y,
2246                   const cairo_rectangle_int_t *extents,
2247                   cairo_clip_t          *clip)
2248 {
2249     cairo_composite_glyphs_info_t *info = closure;
2250
2251     TRACE ((stderr, "%s\n", __FUNCTION__));
2252
2253     if (op == CAIRO_OPERATOR_ADD && (dst->content & CAIRO_CONTENT_COLOR) == 0)
2254         info->use_mask = 0;
2255
2256     return compositor->composite_glyphs (dst, op, src,
2257                                          src_x, src_y,
2258                                          dst_x, dst_y,
2259                                          info);
2260 }
2261
2262 static cairo_int_status_t
2263 _cairo_traps_compositor_glyphs (const cairo_compositor_t        *_compositor,
2264                                 cairo_composite_rectangles_t    *extents,
2265                                 cairo_scaled_font_t             *scaled_font,
2266                                 cairo_glyph_t                   *glyphs,
2267                                 int                              num_glyphs,
2268                                 cairo_bool_t                     overlap)
2269 {
2270     const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
2271     cairo_int_status_t status;
2272
2273     TRACE ((stderr, "%s\n", __FUNCTION__));
2274
2275     status = compositor->check_composite (extents);
2276     if (unlikely (status))
2277         return status;
2278
2279     _cairo_scaled_font_freeze_cache (scaled_font);
2280     status = compositor->check_composite_glyphs (extents,
2281                                                  scaled_font, glyphs,
2282                                                  &num_glyphs);
2283     if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
2284         cairo_composite_glyphs_info_t info;
2285         unsigned flags = 0;
2286
2287         info.font = scaled_font;
2288         info.glyphs = glyphs;
2289         info.num_glyphs = num_glyphs;
2290         info.use_mask = overlap || ! extents->is_bounded;
2291         info.extents = extents->bounded;
2292
2293         if (extents->mask.width > extents->bounded.width ||
2294             extents->mask.height > extents->bounded.height)
2295         {
2296             flags |= FORCE_CLIP_REGION;
2297         }
2298
2299         status = clip_and_composite (compositor, extents,
2300                                      composite_glyphs, NULL, &info,
2301                                      need_bounded_clip (extents) |
2302                                      flags);
2303     }
2304     _cairo_scaled_font_thaw_cache (scaled_font);
2305
2306     return status;
2307 }
2308
2309 void
2310 _cairo_traps_compositor_init (cairo_traps_compositor_t *compositor,
2311                               const cairo_compositor_t  *delegate)
2312 {
2313     compositor->base.delegate = delegate;
2314
2315     compositor->base.paint = _cairo_traps_compositor_paint;
2316     compositor->base.mask = _cairo_traps_compositor_mask;
2317     compositor->base.fill = _cairo_traps_compositor_fill;
2318     compositor->base.stroke = _cairo_traps_compositor_stroke;
2319     compositor->base.glyphs = _cairo_traps_compositor_glyphs;
2320 }