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