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