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