6cc9a7b009c2717db098bc131d5299b2340bfda2
[framework/graphics/cairo.git] / src / cairo-spans-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-compositor-private.h"
45 #include "cairo-clip-inline.h"
46 #include "cairo-clip-private.h"
47 #include "cairo-image-surface-private.h"
48 #include "cairo-paginated-private.h"
49 #include "cairo-pattern-inline.h"
50 #include "cairo-region-private.h"
51 #include "cairo-recording-surface-inline.h"
52 #include "cairo-spans-compositor-private.h"
53 #include "cairo-surface-subsurface-private.h"
54 #include "cairo-surface-snapshot-private.h"
55 #include "cairo-surface-observer-private.h"
56
57 typedef struct {
58     cairo_polygon_t     *polygon;
59     cairo_fill_rule_t    fill_rule;
60     cairo_antialias_t    antialias;
61 } composite_spans_info_t;
62
63 static cairo_int_status_t
64 composite_polygon (const cairo_spans_compositor_t       *compositor,
65                    cairo_composite_rectangles_t          *extents,
66                    cairo_polygon_t                      *polygon,
67                    cairo_fill_rule_t                     fill_rule,
68                    cairo_antialias_t                     antialias);
69
70 static cairo_int_status_t
71 composite_boxes (const cairo_spans_compositor_t *compositor,
72                  cairo_composite_rectangles_t *extents,
73                  cairo_boxes_t          *boxes);
74
75 static cairo_int_status_t
76 clip_and_composite_polygon (const cairo_spans_compositor_t      *compositor,
77                             cairo_composite_rectangles_t         *extents,
78                             cairo_polygon_t                     *polygon,
79                             cairo_fill_rule_t                    fill_rule,
80                             cairo_antialias_t                    antialias);
81 static cairo_surface_t *
82 get_clip_surface (const cairo_spans_compositor_t *compositor,
83                   cairo_surface_t *dst,
84                   const cairo_clip_t *clip,
85                   const cairo_rectangle_int_t *extents)
86 {
87     cairo_composite_rectangles_t composite;
88     cairo_surface_t *surface;
89     cairo_box_t box;
90     cairo_polygon_t polygon;
91     const cairo_clip_path_t *clip_path;
92     cairo_antialias_t antialias;
93     cairo_fill_rule_t fill_rule;
94     cairo_int_status_t status;
95
96     assert (clip->path);
97
98     surface = _cairo_surface_create_similar_solid (dst,
99                                                    CAIRO_CONTENT_ALPHA,
100                                                    extents->width,
101                                                    extents->height,
102                                                    CAIRO_COLOR_TRANSPARENT);
103
104     _cairo_box_from_rectangle (&box, extents);
105     _cairo_polygon_init (&polygon, &box, 1);
106
107     clip_path = clip->path;
108     status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
109                                                 clip_path->tolerance,
110                                                 &polygon);
111     if (unlikely (status))
112         goto cleanup_polygon;
113
114     antialias = clip_path->antialias;
115     fill_rule = clip_path->fill_rule;
116
117     if (clip->boxes) {
118         cairo_polygon_t intersect;
119         cairo_boxes_t tmp;
120
121         _cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes);
122         status= _cairo_polygon_init_boxes (&intersect, &tmp);
123         if (unlikely (status))
124             goto cleanup_polygon;
125
126         status = _cairo_polygon_intersect (&polygon, fill_rule,
127                                            &intersect, CAIRO_FILL_RULE_WINDING);
128         _cairo_polygon_fini (&intersect);
129
130         if (unlikely (status))
131             goto cleanup_polygon;
132
133         fill_rule = CAIRO_FILL_RULE_WINDING;
134     }
135
136     polygon.limits = NULL;
137     polygon.num_limits = 0;
138
139     clip_path = clip_path->prev;
140     while (clip_path) {
141         if (clip_path->antialias == antialias) {
142             cairo_polygon_t next;
143
144             _cairo_polygon_init (&next, NULL, 0);
145             status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
146                                                         clip_path->tolerance,
147                                                         &next);
148             if (likely (status == CAIRO_INT_STATUS_SUCCESS))
149                 status = _cairo_polygon_intersect (&polygon, fill_rule,
150                                                    &next, clip_path->fill_rule);
151             _cairo_polygon_fini (&next);
152             if (unlikely (status))
153                 goto cleanup_polygon;
154
155             fill_rule = CAIRO_FILL_RULE_WINDING;
156         }
157
158         clip_path = clip_path->prev;
159     }
160
161     _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
162     status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
163                                                            CAIRO_OPERATOR_ADD,
164                                                            &_cairo_pattern_white.base,
165                                                            &polygon,
166                                                            NULL);
167     if (unlikely (status))
168         goto cleanup_polygon;
169
170     status = composite_polygon (compositor, &composite,
171                                 &polygon, fill_rule, antialias);
172     _cairo_composite_rectangles_fini (&composite);
173     _cairo_polygon_fini (&polygon);
174     if (unlikely (status))
175         goto error;
176
177     _cairo_polygon_init (&polygon, &box, 1);
178
179     clip_path = clip->path;
180     antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT;
181     clip_path = clip_path->prev;
182     while (clip_path) {
183         if (clip_path->antialias == antialias) {
184             if (polygon.num_edges == 0) {
185                 status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
186                                                             clip_path->tolerance,
187                                                             &polygon);
188
189                 fill_rule = clip_path->fill_rule;
190                 polygon.limits = NULL;
191                 polygon.num_limits = 0;
192             } else {
193                 cairo_polygon_t next;
194
195                 _cairo_polygon_init (&next, NULL, 0);
196                 status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
197                                                             clip_path->tolerance,
198                                                             &next);
199                 if (likely (status == CAIRO_INT_STATUS_SUCCESS))
200                     status = _cairo_polygon_intersect (&polygon, fill_rule,
201                                                        &next, clip_path->fill_rule);
202                 _cairo_polygon_fini (&next);
203                 fill_rule = CAIRO_FILL_RULE_WINDING;
204             }
205             if (unlikely (status))
206                 goto error;
207         }
208
209         clip_path = clip_path->prev;
210     }
211
212     if (polygon.num_edges) {
213         _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
214         status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
215                                                                CAIRO_OPERATOR_IN,
216                                                                &_cairo_pattern_white.base,
217                                                                &polygon,
218                                                                NULL);
219         if (unlikely (status))
220             goto cleanup_polygon;
221
222         status = composite_polygon (compositor, &composite,
223                                     &polygon, fill_rule, antialias);
224         _cairo_composite_rectangles_fini (&composite);
225         _cairo_polygon_fini (&polygon);
226         if (unlikely (status))
227             goto error;
228     }
229
230     return surface;
231
232 cleanup_polygon:
233     _cairo_polygon_fini (&polygon);
234 error:
235     cairo_surface_destroy (surface);
236     return _cairo_int_surface_create_in_error (status);
237 }
238
239 static cairo_int_status_t
240 fixup_unbounded_mask (const cairo_spans_compositor_t *compositor,
241                       const cairo_composite_rectangles_t *extents,
242                       cairo_boxes_t *boxes)
243 {
244     cairo_composite_rectangles_t composite;
245     cairo_surface_t *clip;
246     cairo_int_status_t status;
247
248     TRACE((stderr, "%s\n", __FUNCTION__));
249
250     clip = get_clip_surface (compositor, extents->surface, extents->clip,
251                              &extents->unbounded);
252     if (unlikely (clip->status)) {
253         if ((cairo_int_status_t)clip->status == CAIRO_INT_STATUS_NOTHING_TO_DO)
254             return CAIRO_STATUS_SUCCESS;
255
256         return clip->status;
257     }
258
259     status = _cairo_composite_rectangles_init_for_boxes (&composite,
260                                                          extents->surface,
261                                                          CAIRO_OPERATOR_CLEAR,
262                                                          &_cairo_pattern_clear.base,
263                                                          boxes,
264                                                          NULL);
265     if (unlikely (status))
266         goto cleanup_clip;
267
268     _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip);
269     composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
270     composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE;
271
272     status = composite_boxes (compositor, &composite, boxes);
273
274     _cairo_pattern_fini (&composite.mask_pattern.base);
275     _cairo_composite_rectangles_fini (&composite);
276
277 cleanup_clip:
278     cairo_surface_destroy (clip);
279     return status;
280 }
281
282 static cairo_int_status_t
283 fixup_unbounded_polygon (const cairo_spans_compositor_t *compositor,
284                          const cairo_composite_rectangles_t *extents,
285                          cairo_boxes_t *boxes)
286 {
287     cairo_polygon_t polygon, intersect;
288     cairo_composite_rectangles_t composite;
289     cairo_fill_rule_t fill_rule;
290     cairo_antialias_t antialias;
291     cairo_int_status_t status;
292
293     TRACE((stderr, "%s\n", __FUNCTION__));
294
295     /* Can we treat the clip as a regular clear-polygon and use it to fill? */
296     status = _cairo_clip_get_polygon (extents->clip, &polygon,
297                                       &fill_rule, &antialias);
298     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
299         return status;
300
301     status= _cairo_polygon_init_boxes (&intersect, boxes);
302     if (unlikely (status))
303         goto cleanup_polygon;
304
305     status = _cairo_polygon_intersect (&polygon, fill_rule,
306                                        &intersect, CAIRO_FILL_RULE_WINDING);
307     _cairo_polygon_fini (&intersect);
308
309     if (unlikely (status))
310         goto cleanup_polygon;
311
312     status = _cairo_composite_rectangles_init_for_polygon (&composite,
313                                                            extents->surface,
314                                                            CAIRO_OPERATOR_CLEAR,
315                                                            &_cairo_pattern_clear.base,
316                                                            &polygon,
317                                                            NULL);
318     if (unlikely (status))
319         goto cleanup_polygon;
320
321     status = composite_polygon (compositor, &composite,
322                                 &polygon, fill_rule, antialias);
323
324     _cairo_composite_rectangles_fini (&composite);
325 cleanup_polygon:
326     _cairo_polygon_fini (&polygon);
327
328     return status;
329 }
330
331 static cairo_int_status_t
332 fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor,
333                        const cairo_composite_rectangles_t *extents,
334                        cairo_boxes_t *boxes)
335 {
336     cairo_boxes_t tmp, clear;
337     cairo_box_t box;
338     cairo_int_status_t status;
339
340     assert (boxes->is_pixel_aligned);
341
342     TRACE ((stderr, "%s\n", __FUNCTION__));
343     if (extents->bounded.width  == extents->unbounded.width &&
344         extents->bounded.height == extents->unbounded.height)
345     {
346         return CAIRO_STATUS_SUCCESS;
347     }
348
349     /* subtract the drawn boxes from the unbounded area */
350     _cairo_boxes_init (&clear);
351
352     box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
353     box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
354     box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
355     box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
356
357     if (boxes->num_boxes) {
358         _cairo_boxes_init (&tmp);
359
360         status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
361         assert (status == CAIRO_INT_STATUS_SUCCESS);
362
363         tmp.chunks.next = &boxes->chunks;
364         tmp.num_boxes += boxes->num_boxes;
365
366         status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
367                                                           CAIRO_FILL_RULE_WINDING,
368                                                           &clear);
369         tmp.chunks.next = NULL;
370         if (unlikely (status))
371             goto error;
372     } else {
373         box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
374         box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
375
376         status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
377         assert (status == CAIRO_INT_STATUS_SUCCESS);
378     }
379
380     /* If we have a clip polygon, we need to intersect with that as well */
381     if (extents->clip->path) {
382         status = fixup_unbounded_polygon (compositor, extents, &clear);
383         if (status == CAIRO_INT_STATUS_UNSUPPORTED)
384             status = fixup_unbounded_mask (compositor, extents, &clear);
385     } else {
386         /* Otherwise just intersect with the clip boxes */
387         if (extents->clip->num_boxes) {
388             _cairo_boxes_init_for_array (&tmp,
389                                          extents->clip->boxes,
390                                          extents->clip->num_boxes);
391             status = _cairo_boxes_intersect (&clear, &tmp, &clear);
392             if (unlikely (status))
393                 goto error;
394         }
395
396         if (clear.is_pixel_aligned) {
397             status = compositor->fill_boxes (extents->surface,
398                                              CAIRO_OPERATOR_CLEAR,
399                                              CAIRO_COLOR_TRANSPARENT,
400                                              &clear);
401         } else {
402             cairo_composite_rectangles_t composite;
403
404             status = _cairo_composite_rectangles_init_for_boxes (&composite,
405                                                                  extents->surface,
406                                                                  CAIRO_OPERATOR_CLEAR,
407                                                                  &_cairo_pattern_clear.base,
408                                                                  &clear,
409                                                                  NULL);
410             if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
411                 status = composite_boxes (compositor, &composite, &clear);
412                 _cairo_composite_rectangles_fini (&composite);
413             }
414         }
415     }
416
417 error:
418     _cairo_boxes_fini (&clear);
419     return status;
420 }
421
422 static cairo_surface_t *
423 unwrap_source (const cairo_pattern_t *pattern)
424 {
425     cairo_rectangle_int_t limit;
426
427     return _cairo_pattern_get_source ((cairo_surface_pattern_t *)pattern,
428                                       &limit);
429 }
430
431 static cairo_bool_t
432 is_recording_pattern (const cairo_pattern_t *pattern)
433 {
434     cairo_surface_t *surface;
435
436     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
437         return FALSE;
438
439     surface = ((const cairo_surface_pattern_t *) pattern)->surface;
440     return _cairo_surface_is_recording (surface);
441 }
442
443 static cairo_bool_t
444 recording_pattern_contains_sample (const cairo_pattern_t *pattern,
445                                    const cairo_rectangle_int_t *sample)
446 {
447     cairo_recording_surface_t *surface;
448
449     if (! is_recording_pattern (pattern))
450         return FALSE;
451
452     if (pattern->extend == CAIRO_EXTEND_NONE)
453         return TRUE;
454
455     surface = (cairo_recording_surface_t *) unwrap_source (pattern);
456     if (surface->unbounded)
457         return TRUE;
458
459     return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
460 }
461
462 static cairo_bool_t
463 op_reduces_to_source (const cairo_composite_rectangles_t *extents,
464                       cairo_bool_t no_mask)
465 {
466     if (extents->op == CAIRO_OPERATOR_SOURCE)
467         return TRUE;
468
469     if (extents->surface->is_clear)
470         return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
471
472     if (no_mask && extents->op == CAIRO_OPERATOR_OVER)
473         return _cairo_pattern_is_opaque (&extents->source_pattern.base,
474                                          &extents->source_sample_area);
475
476     return FALSE;
477 }
478
479 static cairo_status_t
480 upload_boxes (const cairo_spans_compositor_t *compositor,
481               const cairo_composite_rectangles_t *extents,
482               cairo_boxes_t *boxes)
483 {
484     cairo_surface_t *dst = extents->surface;
485     const cairo_surface_pattern_t *source = &extents->source_pattern.surface;
486     cairo_surface_t *src;
487     cairo_rectangle_int_t limit;
488     cairo_int_status_t status;
489     int tx, ty;
490
491     TRACE ((stderr, "%s\n", __FUNCTION__));
492
493     src = _cairo_pattern_get_source(source, &limit);
494     if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
495         return CAIRO_INT_STATUS_UNSUPPORTED;
496
497     if (! _cairo_matrix_is_integer_translation (&source->base.matrix, &tx, &ty))
498         return CAIRO_INT_STATUS_UNSUPPORTED;
499
500     /* Check that the data is entirely within the image */
501     if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
502         return CAIRO_INT_STATUS_UNSUPPORTED;
503
504     if (extents->bounded.x + extents->bounded.width  + tx > limit.x + limit.width ||
505         extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
506         return CAIRO_INT_STATUS_UNSUPPORTED;
507
508     tx += limit.x;
509     ty += limit.y;
510
511     if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
512         status = compositor->draw_image_boxes (dst,
513                                                (cairo_image_surface_t *)src,
514                                                boxes, tx, ty);
515     else
516         status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
517                                          tx, ty);
518
519     return status;
520 }
521
522 static cairo_bool_t
523 _clip_is_region (const cairo_clip_t *clip)
524 {
525     int i;
526
527     if (clip->is_region)
528         return TRUE;
529
530     if (clip->path)
531         return FALSE;
532
533     for (i = 0; i < clip->num_boxes; i++) {
534         const cairo_box_t *b = &clip->boxes[i];
535         if (!_cairo_fixed_is_integer (b->p1.x | b->p1.y |  b->p2.x | b->p2.y))
536             return FALSE;
537     }
538
539     return TRUE;
540 }
541
542 static cairo_int_status_t
543 composite_aligned_boxes (const cairo_spans_compositor_t         *compositor,
544                          const cairo_composite_rectangles_t     *extents,
545                          cairo_boxes_t                          *boxes)
546 {
547     cairo_surface_t *dst = extents->surface;
548     cairo_operator_t op = extents->op;
549     const cairo_pattern_t *source = &extents->source_pattern.base;
550     cairo_int_status_t status;
551     cairo_bool_t need_clip_mask = ! _clip_is_region (extents->clip);
552     cairo_bool_t op_is_source;
553     cairo_bool_t no_mask;
554     cairo_bool_t inplace;
555
556     TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n",
557             __FUNCTION__, need_clip_mask, extents->is_bounded));
558     if (need_clip_mask && ! extents->is_bounded)
559         return CAIRO_INT_STATUS_UNSUPPORTED;
560
561     no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
562         CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color);
563     op_is_source = op_reduces_to_source (extents, no_mask);
564     inplace = ! need_clip_mask && op_is_source && no_mask;
565
566     TRACE ((stderr, "%s: op-is-source=%d [op=%d], no-mask=%d, inplace=%d\n",
567             __FUNCTION__, op_is_source, op, no_mask, inplace));
568
569     if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
570         /* SOURCE with a mask is actually a LERP in cairo semantics */
571         if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0)
572             return CAIRO_INT_STATUS_UNSUPPORTED;
573     }
574
575     /* Are we just copying a recording surface? */
576     if (inplace &&
577         recording_pattern_contains_sample (&extents->source_pattern.base,
578                                            &extents->source_sample_area))
579     {
580         cairo_clip_t *recording_clip;
581         const cairo_pattern_t *source = &extents->source_pattern.base;
582
583         /* XXX could also do tiling repeat modes... */
584
585         /* first clear the area about to be overwritten */
586         if (! dst->is_clear)
587             status = compositor->fill_boxes (dst,
588                                              CAIRO_OPERATOR_CLEAR,
589                                              CAIRO_COLOR_TRANSPARENT,
590                                              boxes);
591
592         recording_clip = _cairo_clip_from_boxes (boxes);
593         status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
594                                                             &source->matrix,
595                                                             dst, recording_clip);
596         _cairo_clip_destroy (recording_clip);
597
598         return status;
599     }
600
601     status = CAIRO_INT_STATUS_UNSUPPORTED;
602     if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
603         const cairo_color_t *color;
604
605         color = &((cairo_solid_pattern_t *) source)->color;
606         if (op_is_source)
607             op = CAIRO_OPERATOR_SOURCE;
608         status = compositor->fill_boxes (dst, op, color, boxes);
609     } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
610         status = upload_boxes (compositor, extents, boxes);
611     }
612     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
613         cairo_surface_t *src;
614         cairo_surface_t *mask = NULL;
615         int src_x, src_y;
616         int mask_x = 0, mask_y = 0;
617
618         /* All typical cases will have been resolved before now... */
619         if (need_clip_mask) {
620             mask = get_clip_surface (compositor, dst, extents->clip,
621                                      &extents->bounded);
622             if (unlikely (mask->status))
623                 return mask->status;
624
625             mask_x = -extents->bounded.x;
626             mask_y = -extents->bounded.y;
627         }
628
629         /* XXX but this is still ugly */
630         if (! no_mask) {
631             src = compositor->pattern_to_surface (dst,
632                                                   &extents->mask_pattern.base,
633                                                   TRUE,
634                                                   &extents->bounded,
635                                                   &extents->mask_sample_area,
636                                                   &src_x, &src_y);
637             if (unlikely (src->status)) {
638                 cairo_surface_destroy (mask);
639                 return src->status;
640             }
641
642             if (mask != NULL) {
643                 status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN,
644                                                       src, NULL,
645                                                       src_x, src_y,
646                                                       0, 0,
647                                                       mask_x, mask_y,
648                                                       boxes, &extents->bounded);
649
650                 cairo_surface_destroy (src);
651             } else {
652                 mask = src;
653                 mask_x = src_x;
654                 mask_y = src_y;
655             }
656         }
657
658         src = compositor->pattern_to_surface (dst, source, FALSE,
659                                               &extents->bounded,
660                                               &extents->source_sample_area,
661                                               &src_x, &src_y);
662         if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
663             status = compositor->composite_boxes (dst, op, src, mask,
664                                                   src_x, src_y,
665                                                   mask_x, mask_y,
666                                                   0, 0,
667                                                   boxes, &extents->bounded);
668             cairo_surface_destroy (src);
669         } else
670             status = src->status;
671
672         cairo_surface_destroy (mask);
673     }
674
675     if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded)
676         status = fixup_unbounded_boxes (compositor, extents, boxes);
677
678     return status;
679 }
680
681 static cairo_bool_t
682 composite_needs_clip (const cairo_composite_rectangles_t *composite,
683                       const cairo_box_t *extents)
684 {
685     return !_cairo_clip_contains_box (composite->clip, extents);
686 }
687
688 static cairo_int_status_t
689 composite_boxes (const cairo_spans_compositor_t *compositor,
690                  cairo_composite_rectangles_t *extents,
691                  cairo_boxes_t          *boxes)
692 {
693     cairo_abstract_span_renderer_t renderer;
694     cairo_rectangular_scan_converter_t converter;
695     const struct _cairo_boxes_chunk *chunk;
696     cairo_int_status_t status;
697     cairo_box_t box;
698
699     TRACE ((stderr, "%s\n", __FUNCTION__));
700     _cairo_box_from_rectangle (&box, &extents->unbounded);
701     if (composite_needs_clip (extents, &box))
702         return CAIRO_INT_STATUS_UNSUPPORTED;
703
704     _cairo_rectangular_scan_converter_init (&converter, &extents->unbounded);
705     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
706         const cairo_box_t *box = chunk->base;
707         int i;
708
709         for (i = 0; i < chunk->count; i++) {
710             status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
711             if (unlikely (status))
712                 goto cleanup_converter;
713         }
714     }
715
716     status = compositor->renderer_init (&renderer, extents,
717                                         CAIRO_ANTIALIAS_DEFAULT, FALSE);
718     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
719         status = converter.base.generate (&converter.base, &renderer.base);
720     compositor->renderer_fini (&renderer, status);
721
722 cleanup_converter:
723     converter.base.destroy (&converter.base);
724     return status;
725 }
726
727 static cairo_int_status_t
728 composite_polygon (const cairo_spans_compositor_t       *compositor,
729                    cairo_composite_rectangles_t          *extents,
730                    cairo_polygon_t                      *polygon,
731                    cairo_fill_rule_t                     fill_rule,
732                    cairo_antialias_t                     antialias)
733 {
734     cairo_abstract_span_renderer_t renderer;
735     cairo_scan_converter_t *converter;
736     cairo_bool_t needs_clip;
737     cairo_int_status_t status;
738
739     needs_clip = ! extents->is_bounded &&
740         (! _clip_is_region (extents->clip) || extents->clip->num_boxes > 1);
741     TRACE ((stderr, "%s - needs_clip=%d\n", __FUNCTION__, needs_clip));
742     if (needs_clip) {
743         return CAIRO_INT_STATUS_UNSUPPORTED;
744         converter = _cairo_clip_tor_scan_converter_create (extents->clip,
745                                                            polygon,
746                                                            fill_rule, antialias);
747     } else {
748         const cairo_rectangle_int_t *r = &extents->unbounded;
749
750         if (antialias == CAIRO_ANTIALIAS_FAST) {
751             converter = _cairo_tor22_scan_converter_create (r->x, r->y,
752                                                             r->x + r->width,
753                                                             r->y + r->height,
754                                                             fill_rule, antialias);
755             status = _cairo_tor22_scan_converter_add_polygon (converter, polygon);
756         } else if (antialias == CAIRO_ANTIALIAS_NONE) {
757             converter = _cairo_mono_scan_converter_create (r->x, r->y,
758                                                            r->x + r->width,
759                                                            r->y + r->height,
760                                                            fill_rule);
761             status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
762         } else {
763             converter = _cairo_tor_scan_converter_create (r->x, r->y,
764                                                           r->x + r->width,
765                                                           r->y + r->height,
766                                                           fill_rule, antialias);
767             status = _cairo_tor_scan_converter_add_polygon (converter, polygon);
768         }
769     }
770     if (unlikely (status))
771         goto cleanup_converter;
772
773     status = compositor->renderer_init (&renderer, extents,
774                                         antialias, needs_clip);
775     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
776         status = converter->generate (converter, &renderer.base);
777     compositor->renderer_fini (&renderer, status);
778
779 cleanup_converter:
780     converter->destroy (converter);
781     return status;
782 }
783
784 static cairo_int_status_t
785 trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
786                        cairo_boxes_t *boxes)
787 {
788     cairo_box_t box;
789
790     _cairo_boxes_extents (boxes, &box);
791     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
792 }
793
794 static cairo_int_status_t
795 trim_extents_to_polygon (cairo_composite_rectangles_t *extents,
796                          cairo_polygon_t *polygon)
797 {
798     return _cairo_composite_rectangles_intersect_mask_extents (extents,
799                                                                &polygon->extents);
800 }
801
802 static cairo_int_status_t
803 clip_and_composite_boxes (const cairo_spans_compositor_t        *compositor,
804                           cairo_composite_rectangles_t          *extents,
805                           cairo_boxes_t                         *boxes)
806 {
807     cairo_int_status_t status;
808     cairo_polygon_t polygon;
809
810     TRACE ((stderr, "%s\n", __FUNCTION__));
811     status = trim_extents_to_boxes (extents, boxes);
812     if (unlikely (status))
813         return status;
814
815     if (boxes->num_boxes == 0) {
816         if (extents->is_bounded)
817             return CAIRO_STATUS_SUCCESS;
818
819         return fixup_unbounded_boxes (compositor, extents, boxes);
820     }
821
822     /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
823     if (extents->clip->path != NULL && extents->is_bounded) {
824         cairo_polygon_t polygon;
825         cairo_fill_rule_t fill_rule;
826         cairo_antialias_t antialias;
827         cairo_clip_t *clip;
828
829         clip = _cairo_clip_copy (extents->clip);
830         clip = _cairo_clip_intersect_boxes (clip, boxes);
831         if (_cairo_clip_is_all_clipped (clip))
832             return CAIRO_INT_STATUS_NOTHING_TO_DO;
833
834         status = _cairo_clip_get_polygon (clip, &polygon,
835                                           &fill_rule, &antialias);
836         _cairo_clip_path_destroy (clip->path);
837         clip->path = NULL;
838         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
839             cairo_clip_t *saved_clip = extents->clip;
840             extents->clip = clip;
841
842             status = clip_and_composite_polygon (compositor, extents, &polygon,
843                                                  fill_rule, antialias);
844
845             clip = extents->clip;
846             extents->clip = saved_clip;
847
848             _cairo_polygon_fini (&polygon);
849         }
850         _cairo_clip_destroy (clip);
851
852         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
853             return status;
854     }
855
856     if (boxes->is_pixel_aligned) {
857         status = composite_aligned_boxes (compositor, extents, boxes);
858         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
859             return status;
860     }
861
862     status = composite_boxes (compositor, extents, boxes);
863     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
864         return status;
865
866     status = _cairo_polygon_init_boxes (&polygon, boxes);
867     if (unlikely (status))
868         return status;
869
870     status = composite_polygon (compositor, extents, &polygon,
871                                 CAIRO_FILL_RULE_WINDING,
872                                 CAIRO_ANTIALIAS_DEFAULT);
873     _cairo_polygon_fini (&polygon);
874
875     return status;
876 }
877
878 static cairo_int_status_t
879 clip_and_composite_polygon (const cairo_spans_compositor_t      *compositor,
880                             cairo_composite_rectangles_t         *extents,
881                             cairo_polygon_t                     *polygon,
882                             cairo_fill_rule_t                    fill_rule,
883                             cairo_antialias_t                    antialias)
884 {
885     cairo_int_status_t status;
886
887     TRACE ((stderr, "%s\n", __FUNCTION__));
888
889     /* XXX simply uses polygon limits.point extemities, tessellation? */
890     status = trim_extents_to_polygon (extents, polygon);
891     if (unlikely (status))
892         return status;
893
894     if (_cairo_polygon_is_empty (polygon)) {
895         cairo_boxes_t boxes;
896
897         if (extents->is_bounded)
898             return CAIRO_STATUS_SUCCESS;
899
900         _cairo_boxes_init (&boxes);
901         extents->bounded.width = extents->bounded.height = 0;
902         return fixup_unbounded_boxes (compositor, extents, &boxes);
903     }
904
905     if (extents->is_bounded && extents->clip->path) {
906         cairo_polygon_t clipper;
907         cairo_antialias_t clip_antialias;
908         cairo_fill_rule_t clip_fill_rule;
909
910         TRACE((stderr, "%s - combining shape with clip polygon\n",
911                __FUNCTION__));
912
913         status = _cairo_clip_get_polygon (extents->clip,
914                                           &clipper,
915                                           &clip_fill_rule,
916                                           &clip_antialias);
917         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
918             cairo_clip_t *old_clip;
919
920             if (clip_antialias == antialias) {
921                 /* refresh limits after trimming extents */
922                 _cairo_polygon_limit_to_clip(polygon, extents->clip);
923
924                 status = _cairo_polygon_intersect (polygon, fill_rule,
925                                                    &clipper, clip_fill_rule);
926                 _cairo_polygon_fini (&clipper);
927                 if (unlikely (status))
928                     return status;
929
930                 old_clip = extents->clip;
931                 extents->clip = _cairo_clip_copy_region (extents->clip);
932                 _cairo_clip_destroy (old_clip);
933
934                 status = trim_extents_to_polygon (extents, polygon);
935                 if (unlikely (status))
936                     return status;
937             } else {
938                 _cairo_polygon_fini (&clipper);
939             }
940         }
941     }
942
943     return composite_polygon (compositor, extents,
944                               polygon, fill_rule, antialias);
945 }
946
947 /* high-level compositor interface */
948
949 static cairo_int_status_t
950 _cairo_spans_compositor_paint (const cairo_compositor_t         *_compositor,
951                                cairo_composite_rectangles_t     *extents)
952 {
953     const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
954     cairo_boxes_t boxes;
955     cairo_int_status_t status;
956
957     TRACE ((stderr, "%s\n", __FUNCTION__));
958     _cairo_clip_steal_boxes (extents->clip, &boxes);
959     status = clip_and_composite_boxes (compositor, extents, &boxes);
960     _cairo_clip_unsteal_boxes (extents->clip, &boxes);
961
962     return status;
963 }
964
965 static cairo_int_status_t
966 _cairo_spans_compositor_mask (const cairo_compositor_t          *_compositor,
967                               cairo_composite_rectangles_t      *extents)
968 {
969     const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
970     cairo_int_status_t status;
971     cairo_boxes_t boxes;
972
973     TRACE ((stderr, "%s\n", __FUNCTION__));
974     _cairo_clip_steal_boxes (extents->clip, &boxes);
975     status = clip_and_composite_boxes (compositor, extents, &boxes);
976     _cairo_clip_unsteal_boxes (extents->clip, &boxes);
977
978     return status;
979 }
980
981 static cairo_int_status_t
982 _cairo_spans_compositor_stroke (const cairo_compositor_t        *_compositor,
983                                 cairo_composite_rectangles_t     *extents,
984                                 const cairo_path_fixed_t        *path,
985                                 const cairo_stroke_style_t      *style,
986                                 const cairo_matrix_t            *ctm,
987                                 const cairo_matrix_t            *ctm_inverse,
988                                 double                           tolerance,
989                                 cairo_antialias_t                antialias)
990 {
991     const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
992     cairo_int_status_t status;
993
994     TRACE_ (_cairo_debug_print_path (stderr, path));
995
996     status = CAIRO_INT_STATUS_UNSUPPORTED;
997     if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
998         cairo_boxes_t boxes;
999
1000         _cairo_boxes_init (&boxes);
1001         if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
1002             _cairo_boxes_limit (&boxes,
1003                                 extents->clip->boxes,
1004                                 extents->clip->num_boxes);
1005
1006         status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
1007                                                                 style,
1008                                                                 ctm,
1009                                                                 antialias,
1010                                                                 &boxes);
1011         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1012             status = clip_and_composite_boxes (compositor, extents, &boxes);
1013         _cairo_boxes_fini (&boxes);
1014     }
1015
1016     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1017         cairo_polygon_t polygon;
1018         cairo_fill_rule_t fill_rule = CAIRO_FILL_RULE_WINDING;
1019
1020         if (extents->mask.width  > extents->unbounded.width ||
1021             extents->mask.height > extents->unbounded.height)
1022         {
1023             cairo_box_t limits;
1024             _cairo_box_from_rectangle (&limits, &extents->unbounded);
1025             _cairo_polygon_init (&polygon, &limits, 1);
1026         }
1027         else
1028         {
1029             _cairo_polygon_init (&polygon, NULL, 0);
1030         }
1031         status = _cairo_path_fixed_stroke_to_polygon (path,
1032                                                       style,
1033                                                       ctm, ctm_inverse,
1034                                                       tolerance,
1035                                                       &polygon);
1036         TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1037         if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
1038             status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
1039                                                           extents->clip->boxes,
1040                                                           extents->clip->num_boxes);
1041         }
1042         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1043             cairo_clip_t *saved_clip = extents->clip;
1044
1045             if (extents->is_bounded) {
1046                 extents->clip = _cairo_clip_copy_path (extents->clip);
1047                 extents->clip = _cairo_clip_intersect_box(extents->clip,
1048                                                           &polygon.extents);
1049             }
1050
1051             status = clip_and_composite_polygon (compositor, extents, &polygon,
1052                                                  fill_rule, antialias);
1053
1054             if (extents->is_bounded) {
1055                 _cairo_clip_destroy (extents->clip);
1056                 extents->clip = saved_clip;
1057             }
1058         }
1059         _cairo_polygon_fini (&polygon);
1060     }
1061
1062     return status;
1063 }
1064
1065 static cairo_int_status_t
1066 _cairo_spans_compositor_fill (const cairo_compositor_t          *_compositor,
1067                               cairo_composite_rectangles_t       *extents,
1068                               const cairo_path_fixed_t          *path,
1069                               cairo_fill_rule_t                  fill_rule,
1070                               double                             tolerance,
1071                               cairo_antialias_t                  antialias)
1072 {
1073     const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
1074     cairo_int_status_t status;
1075
1076     TRACE((stderr, "%s op=%d, antialias=%d\n", __FUNCTION__, extents->op, antialias));
1077
1078     status = CAIRO_INT_STATUS_UNSUPPORTED;
1079     if (_cairo_path_fixed_fill_is_rectilinear (path)) {
1080         cairo_boxes_t boxes;
1081
1082         TRACE((stderr, "%s - rectilinear\n", __FUNCTION__));
1083
1084         _cairo_boxes_init (&boxes);
1085         if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
1086             _cairo_boxes_limit (&boxes,
1087                                 extents->clip->boxes,
1088                                 extents->clip->num_boxes);
1089         status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
1090                                                               fill_rule,
1091                                                               antialias,
1092                                                               &boxes);
1093         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
1094             status = clip_and_composite_boxes (compositor, extents, &boxes);
1095         _cairo_boxes_fini (&boxes);
1096     }
1097     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1098         cairo_polygon_t polygon;
1099
1100         TRACE((stderr, "%s - polygon\n", __FUNCTION__));
1101
1102         if (extents->mask.width  > extents->unbounded.width ||
1103             extents->mask.height > extents->unbounded.height)
1104         {
1105             cairo_box_t limits;
1106             TRACE((stderr, "%s - clipping to bounds\n", __FUNCTION__));
1107             _cairo_box_from_rectangle (&limits, &extents->unbounded);
1108             _cairo_polygon_init (&polygon, &limits, 1);
1109         }
1110         else
1111         {
1112             _cairo_polygon_init (&polygon, NULL, 0);
1113         }
1114
1115         status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1116         if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
1117             TRACE((stderr, "%s - polygon intersect with %d clip boxes\n",
1118                    __FUNCTION__, extents->clip->num_boxes));
1119             status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
1120                                                           extents->clip->boxes,
1121                                                           extents->clip->num_boxes);
1122         }
1123         if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
1124             cairo_clip_t *saved_clip = extents->clip;
1125
1126             if (extents->is_bounded) {
1127                 TRACE((stderr, "%s - polygon discard clip boxes\n",
1128                        __FUNCTION__));
1129                 extents->clip = _cairo_clip_copy_path (extents->clip);
1130                 extents->clip = _cairo_clip_intersect_box(extents->clip,
1131                                                           &polygon.extents);
1132             }
1133
1134             status = clip_and_composite_polygon (compositor, extents, &polygon,
1135                                                  fill_rule, antialias);
1136
1137             if (extents->is_bounded) {
1138                 _cairo_clip_destroy (extents->clip);
1139                 extents->clip = saved_clip;
1140             }
1141         }
1142         _cairo_polygon_fini (&polygon);
1143
1144         TRACE((stderr, "%s - polygon status=%d\n", __FUNCTION__, status));
1145     }
1146
1147     return status;
1148 }
1149
1150 void
1151 _cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
1152                               const cairo_compositor_t  *delegate)
1153 {
1154     compositor->base.delegate = delegate;
1155
1156     compositor->base.paint  = _cairo_spans_compositor_paint;
1157     compositor->base.mask   = _cairo_spans_compositor_mask;
1158     compositor->base.fill   = _cairo_spans_compositor_fill;
1159     compositor->base.stroke = _cairo_spans_compositor_stroke;
1160     compositor->base.glyphs = NULL;
1161 }