Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-image-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 © 2003 University of Southern California
5  * Copyright © 2009,2010,2011 Intel Corporation
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it either under the terms of the GNU Lesser General Public
9  * License version 2.1 as published by the Free Software Foundation
10  * (the "LGPL") or, at your option, under the terms of the Mozilla
11  * Public License Version 1.1 (the "MPL"). If you do not alter this
12  * notice, a recipient may use your version of this file under either
13  * the MPL or the LGPL.
14  *
15  * You should have received a copy of the LGPL along with this library
16  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18  * You should have received a copy of the MPL along with this library
19  * in the file COPYING-MPL-1.1
20  *
21  * The contents of this file are subject to the Mozilla Public License
22  * Version 1.1 (the "License"); you may not use this file except in
23  * compliance with the License. You may obtain a copy of the License at
24  * http://www.mozilla.org/MPL/
25  *
26  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28  * the specific language governing rights and limitations.
29  *
30  * The Original Code is the cairo graphics library.
31  *
32  * The Initial Developer of the Original Code is University of Southern
33  * California.
34  *
35  * Contributor(s):
36  *      Carl D. Worth <cworth@cworth.org>
37  *      Chris Wilson <chris@chris-wilson.co.uk>
38  */
39
40 /* The primarily reason for keeping a traps-compositor around is
41  * for validating cairo-xlib (which currently also uses traps).
42  */
43
44 #include "cairoint.h"
45
46 #include "cairo-image-surface-private.h"
47
48 #include "cairo-compositor-private.h"
49 #include "cairo-spans-compositor-private.h"
50
51 #include "cairo-region-private.h"
52 #include "cairo-traps-private.h"
53 #include "cairo-tristrip-private.h"
54
55 static pixman_image_t *
56 to_pixman_image (cairo_surface_t *s)
57 {
58     return ((cairo_image_surface_t *)s)->pixman_image;
59 }
60
61 static cairo_int_status_t
62 acquire (void *abstract_dst)
63 {
64     return CAIRO_STATUS_SUCCESS;
65 }
66
67 static cairo_int_status_t
68 release (void *abstract_dst)
69 {
70     return CAIRO_STATUS_SUCCESS;
71 }
72
73 static cairo_int_status_t
74 set_clip_region (void *_surface,
75                  cairo_region_t *region)
76 {
77     cairo_image_surface_t *surface = _surface;
78     pixman_region32_t *rgn = region ? &region->rgn : NULL;
79
80     if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn))
81         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
82
83     return CAIRO_STATUS_SUCCESS;
84 }
85
86 static cairo_int_status_t
87 draw_image_boxes (void *_dst,
88                   cairo_image_surface_t *image,
89                   cairo_boxes_t *boxes,
90                   int dx, int dy)
91 {
92     cairo_image_surface_t *dst = _dst;
93     struct _cairo_boxes_chunk *chunk;
94     int i;
95
96     TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes));
97
98     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
99         for (i = 0; i < chunk->count; i++) {
100             cairo_box_t *b = &chunk->base[i];
101             int x = _cairo_fixed_integer_part (b->p1.x);
102             int y = _cairo_fixed_integer_part (b->p1.y);
103             int w = _cairo_fixed_integer_part (b->p2.x) - x;
104             int h = _cairo_fixed_integer_part (b->p2.y) - y;
105             if (dst->pixman_format != image->pixman_format ||
106                 ! pixman_blt ((uint32_t *)image->data, (uint32_t *)dst->data,
107                               image->stride / sizeof (uint32_t),
108                               dst->stride / sizeof (uint32_t),
109                               PIXMAN_FORMAT_BPP (image->pixman_format),
110                               PIXMAN_FORMAT_BPP (dst->pixman_format),
111                               x + dx, y + dy,
112                               x, y,
113                               w, h))
114             {
115                 pixman_image_composite32 (PIXMAN_OP_SRC,
116                                           image->pixman_image, NULL, dst->pixman_image,
117                                           x + dx, y + dy,
118                                           0, 0,
119                                           x, y,
120                                           w, h);
121             }
122         }
123     }
124     return CAIRO_STATUS_SUCCESS;
125 }
126
127 static inline uint32_t
128 color_to_uint32 (const cairo_color_t *color)
129 {
130     return
131         (color->alpha_short >> 8 << 24) |
132         (color->red_short >> 8 << 16)   |
133         (color->green_short & 0xff00)   |
134         (color->blue_short >> 8);
135 }
136
137 static inline cairo_bool_t
138 color_to_pixel (const cairo_color_t     *color,
139                 pixman_format_code_t     format,
140                 uint32_t                *pixel)
141 {
142     uint32_t c;
143
144     if (!(format == PIXMAN_a8r8g8b8     ||
145           format == PIXMAN_x8r8g8b8     ||
146           format == PIXMAN_a8b8g8r8     ||
147           format == PIXMAN_x8b8g8r8     ||
148           format == PIXMAN_b8g8r8a8     ||
149           format == PIXMAN_b8g8r8x8     ||
150           format == PIXMAN_r5g6b5       ||
151           format == PIXMAN_b5g6r5       ||
152           format == PIXMAN_a8))
153     {
154         return FALSE;
155     }
156
157     c = color_to_uint32 (color);
158
159     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
160         c = ((c & 0xff000000) >>  0) |
161             ((c & 0x00ff0000) >> 16) |
162             ((c & 0x0000ff00) >>  0) |
163             ((c & 0x000000ff) << 16);
164     }
165
166     if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
167         c = ((c & 0xff000000) >> 24) |
168             ((c & 0x00ff0000) >>  8) |
169             ((c & 0x0000ff00) <<  8) |
170             ((c & 0x000000ff) << 24);
171     }
172
173     if (format == PIXMAN_a8) {
174         c = c >> 24;
175     } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
176         c = ((((c) >> 3) & 0x001f) |
177              (((c) >> 5) & 0x07e0) |
178              (((c) >> 8) & 0xf800));
179     }
180
181     *pixel = c;
182     return TRUE;
183 }
184
185 static pixman_op_t
186 _pixman_operator (cairo_operator_t op)
187 {
188     switch ((int) op) {
189     case CAIRO_OPERATOR_CLEAR:
190         return PIXMAN_OP_CLEAR;
191
192     case CAIRO_OPERATOR_SOURCE:
193         return PIXMAN_OP_SRC;
194     case CAIRO_OPERATOR_OVER:
195         return PIXMAN_OP_OVER;
196     case CAIRO_OPERATOR_IN:
197         return PIXMAN_OP_IN;
198     case CAIRO_OPERATOR_OUT:
199         return PIXMAN_OP_OUT;
200     case CAIRO_OPERATOR_ATOP:
201         return PIXMAN_OP_ATOP;
202
203     case CAIRO_OPERATOR_DEST:
204         return PIXMAN_OP_DST;
205     case CAIRO_OPERATOR_DEST_OVER:
206         return PIXMAN_OP_OVER_REVERSE;
207     case CAIRO_OPERATOR_DEST_IN:
208         return PIXMAN_OP_IN_REVERSE;
209     case CAIRO_OPERATOR_DEST_OUT:
210         return PIXMAN_OP_OUT_REVERSE;
211     case CAIRO_OPERATOR_DEST_ATOP:
212         return PIXMAN_OP_ATOP_REVERSE;
213
214     case CAIRO_OPERATOR_XOR:
215         return PIXMAN_OP_XOR;
216     case CAIRO_OPERATOR_ADD:
217         return PIXMAN_OP_ADD;
218     case CAIRO_OPERATOR_SATURATE:
219         return PIXMAN_OP_SATURATE;
220
221     case CAIRO_OPERATOR_MULTIPLY:
222         return PIXMAN_OP_MULTIPLY;
223     case CAIRO_OPERATOR_SCREEN:
224         return PIXMAN_OP_SCREEN;
225     case CAIRO_OPERATOR_OVERLAY:
226         return PIXMAN_OP_OVERLAY;
227     case CAIRO_OPERATOR_DARKEN:
228         return PIXMAN_OP_DARKEN;
229     case CAIRO_OPERATOR_LIGHTEN:
230         return PIXMAN_OP_LIGHTEN;
231     case CAIRO_OPERATOR_COLOR_DODGE:
232         return PIXMAN_OP_COLOR_DODGE;
233     case CAIRO_OPERATOR_COLOR_BURN:
234         return PIXMAN_OP_COLOR_BURN;
235     case CAIRO_OPERATOR_HARD_LIGHT:
236         return PIXMAN_OP_HARD_LIGHT;
237     case CAIRO_OPERATOR_SOFT_LIGHT:
238         return PIXMAN_OP_SOFT_LIGHT;
239     case CAIRO_OPERATOR_DIFFERENCE:
240         return PIXMAN_OP_DIFFERENCE;
241     case CAIRO_OPERATOR_EXCLUSION:
242         return PIXMAN_OP_EXCLUSION;
243     case CAIRO_OPERATOR_HSL_HUE:
244         return PIXMAN_OP_HSL_HUE;
245     case CAIRO_OPERATOR_HSL_SATURATION:
246         return PIXMAN_OP_HSL_SATURATION;
247     case CAIRO_OPERATOR_HSL_COLOR:
248         return PIXMAN_OP_HSL_COLOR;
249     case CAIRO_OPERATOR_HSL_LUMINOSITY:
250         return PIXMAN_OP_HSL_LUMINOSITY;
251
252     default:
253         ASSERT_NOT_REACHED;
254         return PIXMAN_OP_OVER;
255     }
256 }
257
258 static cairo_bool_t
259 fill_reduces_to_source (cairo_operator_t op,
260                         const cairo_color_t *color,
261                         cairo_image_surface_t *dst)
262 {
263     if (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR)
264         return TRUE;
265     if (op == CAIRO_OPERATOR_OVER && CAIRO_COLOR_IS_OPAQUE (color))
266         return TRUE;
267     if (dst->base.is_clear)
268         return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD;
269
270     return FALSE;
271 }
272
273 static cairo_int_status_t
274 fill_rectangles (void                   *_dst,
275                  cairo_operator_t        op,
276                  const cairo_color_t    *color,
277                  cairo_rectangle_int_t  *rects,
278                  int                     num_rects)
279 {
280     cairo_image_surface_t *dst = _dst;
281     uint32_t pixel;
282     int i;
283
284     TRACE ((stderr, "%s\n", __FUNCTION__));
285
286     if (fill_reduces_to_source (op, color, dst) &&
287         color_to_pixel (color, dst->pixman_format, &pixel))
288     {
289         for (i = 0; i < num_rects; i++) {
290             pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
291                          PIXMAN_FORMAT_BPP (dst->pixman_format),
292                          rects[i].x, rects[i].y,
293                          rects[i].width, rects[i].height,
294                          pixel);
295         }
296     }
297     else
298     {
299         pixman_image_t *src = _pixman_image_for_color (color);
300
301         op = _pixman_operator (op);
302         for (i = 0; i < num_rects; i++) {
303             pixman_image_composite32 (op,
304                                       src, NULL, dst->pixman_image,
305                                       0, 0,
306                                       0, 0,
307                                       rects[i].x, rects[i].y,
308                                       rects[i].width, rects[i].height);
309         }
310
311         pixman_image_unref (src);
312     }
313
314     return CAIRO_STATUS_SUCCESS;
315 }
316
317 static cairo_int_status_t
318 fill_boxes (void                *_dst,
319             cairo_operator_t     op,
320             const cairo_color_t *color,
321             cairo_boxes_t       *boxes)
322 {
323     cairo_image_surface_t *dst = _dst;
324     struct _cairo_boxes_chunk *chunk;
325     uint32_t pixel;
326     int i;
327
328     TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes));
329
330     if (fill_reduces_to_source (op, color, dst) &&
331         color_to_pixel (color, dst->pixman_format, &pixel))
332     {
333         for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
334             for (i = 0; i < chunk->count; i++) {
335                 int x = _cairo_fixed_integer_part (chunk->base[i].p1.x);
336                 int y = _cairo_fixed_integer_part (chunk->base[i].p1.y);
337                 int w = _cairo_fixed_integer_part (chunk->base[i].p2.x) - x;
338                 int h = _cairo_fixed_integer_part (chunk->base[i].p2.y) - y;
339                 pixman_fill ((uint32_t *) dst->data,
340                              dst->stride / sizeof (uint32_t),
341                              PIXMAN_FORMAT_BPP (dst->pixman_format),
342                              x, y, w, h, pixel);
343             }
344         }
345     }
346     else
347     {
348         pixman_image_t *src = _pixman_image_for_color (color);
349
350         op = _pixman_operator (op);
351         for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
352             for (i = 0; i < chunk->count; i++) {
353                 int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
354                 int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
355                 int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
356                 int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
357                 pixman_image_composite32 (op,
358                                           src, NULL, dst->pixman_image,
359                                           0, 0,
360                                           0, 0,
361                                           x1, y1,
362                                           x2-x1, y2-y1);
363             }
364         }
365
366         pixman_image_unref (src);
367     }
368
369     return CAIRO_STATUS_SUCCESS;
370 }
371
372 static cairo_int_status_t
373 composite (void                 *_dst,
374            cairo_operator_t     op,
375            cairo_surface_t      *abstract_src,
376            cairo_surface_t      *abstract_mask,
377            int                  src_x,
378            int                  src_y,
379            int                  mask_x,
380            int                  mask_y,
381            int                  dst_x,
382            int                  dst_y,
383            unsigned int         width,
384            unsigned int         height)
385 {
386     cairo_image_source_t *src = (cairo_image_source_t *)abstract_src;
387     cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
388
389     TRACE ((stderr, "%s\n", __FUNCTION__));
390
391     if (mask) {
392         pixman_image_composite32 (_pixman_operator (op),
393                                   src->pixman_image, mask->pixman_image, to_pixman_image (_dst),
394                                   src_x, src_y,
395                                   mask_x, mask_y,
396                                   dst_x, dst_y,
397                                   width, height);
398     } else {
399         pixman_image_composite32 (_pixman_operator (op),
400                                   src->pixman_image, NULL, to_pixman_image (_dst),
401                                   src_x, src_y,
402                                   0, 0,
403                                   dst_x, dst_y,
404                                   width, height);
405     }
406
407     return CAIRO_STATUS_SUCCESS;
408 }
409
410 static cairo_int_status_t
411 lerp (void                      *_dst,
412       cairo_surface_t           *abstract_src,
413       cairo_surface_t           *abstract_mask,
414       int                       src_x,
415       int                       src_y,
416       int                       mask_x,
417       int                       mask_y,
418       int                       dst_x,
419       int                       dst_y,
420       unsigned int              width,
421       unsigned int              height)
422 {
423     cairo_image_surface_t *dst = _dst;
424     cairo_image_source_t *src = (cairo_image_source_t *)abstract_src;
425     cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
426
427     TRACE ((stderr, "%s\n", __FUNCTION__));
428
429 #if PIXMAN_HAS_OP_LERP
430     pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
431                               src->pixman_image, mask->pixman_image, dst->pixman_image,
432                               src_x,  src_y,
433                               mask_x, mask_y,
434                               dst_x,  dst_y,
435                               width,  height);
436 #else
437     /* Punch the clip out of the destination */
438     TRACE ((stderr, "%s - OUT_REVERSE (mask=%d/%p, dst=%d/%p)\n",
439             __FUNCTION__,
440             mask->base.unique_id, mask->pixman_image,
441             dst->base.unique_id, dst->pixman_image));
442     pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
443                               mask->pixman_image, NULL, dst->pixman_image,
444                               mask_x, mask_y,
445                               0,      0,
446                               dst_x,  dst_y,
447                               width,  height);
448
449     /* Now add the two results together */
450     TRACE ((stderr, "%s - ADD (src=%d/%p, mask=%d/%p, dst=%d/%p)\n",
451             __FUNCTION__,
452             src->base.unique_id, src->pixman_image,
453             mask->base.unique_id, mask->pixman_image,
454             dst->base.unique_id, dst->pixman_image));
455     pixman_image_composite32 (PIXMAN_OP_ADD,
456                               src->pixman_image, mask->pixman_image, dst->pixman_image,
457                               src_x,  src_y,
458                               mask_x, mask_y,
459                               dst_x,  dst_y,
460                               width,  height);
461 #endif
462
463     return CAIRO_STATUS_SUCCESS;
464 }
465
466 static cairo_int_status_t
467 composite_boxes (void                   *_dst,
468                  cairo_operator_t       op,
469                  cairo_surface_t        *abstract_src,
470                  cairo_surface_t        *abstract_mask,
471                  int                    src_x,
472                  int                    src_y,
473                  int                    mask_x,
474                  int                    mask_y,
475                  int                    dst_x,
476                  int                    dst_y,
477                  cairo_boxes_t          *boxes,
478                  const cairo_rectangle_int_t  *extents)
479 {
480     pixman_image_t *dst = to_pixman_image (_dst);
481     pixman_image_t *src = ((cairo_image_source_t *)abstract_src)->pixman_image;
482     pixman_image_t *mask = abstract_mask ? ((cairo_image_source_t *)abstract_mask)->pixman_image : NULL;
483     pixman_image_t *free_src = NULL;
484     struct _cairo_boxes_chunk *chunk;
485     int i;
486
487     /* XXX consider using a region? saves multiple prepare-composite */
488     TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes));
489
490     if (((cairo_surface_t *)_dst)->is_clear &&
491         (op == CAIRO_OPERATOR_SOURCE ||
492          op == CAIRO_OPERATOR_OVER ||
493          op == CAIRO_OPERATOR_ADD)) {
494         op = PIXMAN_OP_SRC;
495     } else if (mask) {
496         if (op == CAIRO_OPERATOR_CLEAR) {
497 #if PIXMAN_HAS_OP_LERP
498             op = PIXMAN_OP_LERP_CLEAR;
499 #else
500             free_src = src = _pixman_image_for_color (CAIRO_COLOR_WHITE);
501             op = PIXMAN_OP_OUT_REVERSE;
502 #endif
503         } else if (op == CAIRO_OPERATOR_SOURCE) {
504 #if PIXMAN_HAS_OP_LERP
505             op = PIXMAN_OP_LERP_SRC;
506 #else
507             return CAIRO_INT_STATUS_UNSUPPORTED;
508 #endif
509         } else {
510             op = _pixman_operator (op);
511         }
512     } else {
513         op = _pixman_operator (op);
514     }
515
516     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
517         for (i = 0; i < chunk->count; i++) {
518             int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
519             int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
520             int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
521             int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
522
523             pixman_image_composite32 (op, src, mask, dst,
524                                       x1 + src_x, y1 + src_y,
525                                       x1 + mask_x, y1 + mask_y,
526                                       x1 + dst_x, y1 + dst_y,
527                                       x2 - x1, y2 - y1);
528         }
529     }
530
531     if (free_src)
532         pixman_image_unref (free_src);
533
534     return CAIRO_STATUS_SUCCESS;
535 }
536
537 #define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
538 #define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
539
540 static cairo_bool_t
541 line_exceeds_16_16 (const cairo_line_t *line)
542 {
543     return
544         line->p1.x <= CAIRO_FIXED_16_16_MIN ||
545         line->p1.x >= CAIRO_FIXED_16_16_MAX ||
546
547         line->p2.x <= CAIRO_FIXED_16_16_MIN ||
548         line->p2.x >= CAIRO_FIXED_16_16_MAX ||
549
550         line->p1.y <= CAIRO_FIXED_16_16_MIN ||
551         line->p1.y >= CAIRO_FIXED_16_16_MAX ||
552
553         line->p2.y <= CAIRO_FIXED_16_16_MIN ||
554         line->p2.y >= CAIRO_FIXED_16_16_MAX;
555 }
556
557 static void
558 project_line_x_onto_16_16 (const cairo_line_t *line,
559                            cairo_fixed_t top,
560                            cairo_fixed_t bottom,
561                            pixman_line_fixed_t *out)
562 {
563     /* XXX use fixed-point arithmetic? */
564     cairo_point_double_t p1, p2;
565     double m;
566
567     p1.x = _cairo_fixed_to_double (line->p1.x);
568     p1.y = _cairo_fixed_to_double (line->p1.y);
569
570     p2.x = _cairo_fixed_to_double (line->p2.x);
571     p2.y = _cairo_fixed_to_double (line->p2.y);
572
573     m = (p2.x - p1.x) / (p2.y - p1.y);
574     out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
575     out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
576 }
577
578 void
579 _pixman_image_add_traps (pixman_image_t *image,
580                          int dst_x, int dst_y,
581                          cairo_traps_t *traps)
582 {
583     cairo_trapezoid_t *t = traps->traps;
584     int num_traps = traps->num_traps;
585     while (num_traps--) {
586         pixman_trapezoid_t trap;
587
588         /* top/bottom will be clamped to surface bounds */
589         trap.top = _cairo_fixed_to_16_16 (t->top);
590         trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
591
592         /* However, all the other coordinates will have been left untouched so
593          * as not to introduce numerical error. Recompute them if they
594          * exceed the 16.16 limits.
595          */
596         if (unlikely (line_exceeds_16_16 (&t->left))) {
597             project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
598             trap.left.p1.y = trap.top;
599             trap.left.p2.y = trap.bottom;
600         } else {
601             trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
602             trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
603             trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
604             trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
605         }
606
607         if (unlikely (line_exceeds_16_16 (&t->right))) {
608             project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
609             trap.right.p1.y = trap.top;
610             trap.right.p2.y = trap.bottom;
611         } else {
612             trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
613             trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
614             trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
615             trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
616         }
617
618         pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
619         t++;
620     }
621 }
622
623 static cairo_int_status_t
624 composite_traps (void                   *_dst,
625                  cairo_operator_t       op,
626                  cairo_surface_t        *abstract_src,
627                  int                    src_x,
628                  int                    src_y,
629                  int                    dst_x,
630                  int                    dst_y,
631                  const cairo_rectangle_int_t *extents,
632                  cairo_antialias_t      antialias,
633                  cairo_traps_t          *traps)
634 {
635     cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
636     cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
637     pixman_image_t *mask;
638     pixman_format_code_t format;
639
640     TRACE ((stderr, "%s\n", __FUNCTION__));
641
642     /* Special case adding trapezoids onto a mask surface; we want to avoid
643      * creating an intermediate temporary mask unnecessarily.
644      *
645      * We make the assumption here that the portion of the trapezoids
646      * contained within the surface is bounded by [dst_x,dst_y,width,height];
647      * the Cairo core code passes bounds based on the trapezoid extents.
648      */
649     format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
650     if (dst->pixman_format == format &&
651         (abstract_src == NULL ||
652          (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
653     {
654         _pixman_image_add_traps (dst->pixman_image, dst_x, dst_y, traps);
655         return CAIRO_STATUS_SUCCESS;
656     }
657
658     mask = pixman_image_create_bits (format,
659                                      extents->width, extents->height,
660                                      NULL, 0);
661     if (unlikely (mask == NULL))
662         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
663
664     _pixman_image_add_traps (mask, extents->x, extents->y, traps);
665     pixman_image_composite32 (_pixman_operator (op),
666                               src->pixman_image, mask, dst->pixman_image,
667                               extents->x + src_x, extents->y + src_y,
668                               0, 0,
669                               extents->x - dst_x, extents->y - dst_y,
670                               extents->width, extents->height);
671
672     pixman_image_unref (mask);
673
674     return  CAIRO_STATUS_SUCCESS;
675 }
676
677 static void
678 set_point (pixman_point_fixed_t *p, cairo_point_t *c)
679 {
680     p->x = _cairo_fixed_to_16_16 (c->x);
681     p->y = _cairo_fixed_to_16_16 (c->y);
682 }
683
684 void
685 _pixman_image_add_tristrip (pixman_image_t *image,
686                             int dst_x, int dst_y,
687                             cairo_tristrip_t *strip)
688 {
689     pixman_triangle_t tri;
690     pixman_point_fixed_t *p[3] = {&tri.p1, &tri.p2, &tri.p3 };
691     int n;
692
693     set_point (p[0], &strip->points[0]);
694     set_point (p[1], &strip->points[1]);
695     set_point (p[2], &strip->points[2]);
696     pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
697     for (n = 3; n < strip->num_points; n++) {
698         set_point (p[n%3], &strip->points[n]);
699         pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
700     }
701 }
702
703 static cairo_int_status_t
704 composite_tristrip (void                        *_dst,
705                     cairo_operator_t    op,
706                     cairo_surface_t     *abstract_src,
707                     int                 src_x,
708                     int                 src_y,
709                     int                 dst_x,
710                     int                 dst_y,
711                     const cairo_rectangle_int_t *extents,
712                     cairo_antialias_t   antialias,
713                     cairo_tristrip_t    *strip)
714 {
715     cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
716     cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
717     pixman_image_t *mask;
718     pixman_format_code_t format;
719
720     TRACE ((stderr, "%s\n", __FUNCTION__));
721
722     if (strip->num_points < 3)
723         return CAIRO_STATUS_SUCCESS;
724
725     format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
726     if (dst->pixman_format == format &&
727         (abstract_src == NULL ||
728          (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
729     {
730         _pixman_image_add_tristrip (dst->pixman_image, dst_x, dst_y, strip);
731         return CAIRO_STATUS_SUCCESS;
732     }
733
734     mask = pixman_image_create_bits (format,
735                                      extents->width, extents->height,
736                                      NULL, 0);
737     if (unlikely (mask == NULL))
738         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
739
740     _pixman_image_add_tristrip (mask, extents->x, extents->y, strip);
741     pixman_image_composite32 (_pixman_operator (op),
742                               src->pixman_image, mask, dst->pixman_image,
743                               extents->x + src_x, extents->y + src_y,
744                               0, 0,
745                               extents->x - dst_x, extents->y - dst_y,
746                               extents->width, extents->height);
747
748     pixman_image_unref (mask);
749
750     return  CAIRO_STATUS_SUCCESS;
751 }
752
753 static cairo_int_status_t
754 check_composite_glyphs (const cairo_composite_rectangles_t *extents,
755                         cairo_scaled_font_t *scaled_font,
756                         cairo_glyph_t *glyphs,
757                         int *num_glyphs)
758 {
759     return CAIRO_STATUS_SUCCESS;
760 }
761
762 #if HAS_PIXMAN_GLYPHS
763 static pixman_glyph_cache_t *global_glyph_cache;
764
765 static inline pixman_glyph_cache_t *
766 get_glyph_cache (void)
767 {
768     if (!global_glyph_cache)
769         global_glyph_cache = pixman_glyph_cache_create ();
770
771     return global_glyph_cache;
772 }
773
774 void
775 _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
776                                 cairo_scaled_glyph_t *scaled_glyph)
777 {
778     CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
779
780     if (global_glyph_cache) {
781         pixman_glyph_cache_remove (
782             global_glyph_cache, scaled_font,
783             (void *)_cairo_scaled_glyph_index (scaled_glyph));
784     }
785
786     CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
787 }
788
789 static cairo_int_status_t
790 composite_glyphs (void                          *_dst,
791                   cairo_operator_t               op,
792                   cairo_surface_t               *_src,
793                   int                            src_x,
794                   int                            src_y,
795                   int                            dst_x,
796                   int                            dst_y,
797                   cairo_composite_glyphs_info_t *info)
798 {
799     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
800     pixman_glyph_cache_t *glyph_cache;
801     pixman_glyph_t pglyphs_stack[CAIRO_STACK_ARRAY_LENGTH (pixman_glyph_t)];
802     pixman_glyph_t *pglyphs = pglyphs_stack;
803     pixman_glyph_t *pg;
804     int i;
805
806     TRACE ((stderr, "%s\n", __FUNCTION__));
807
808     CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
809
810     glyph_cache = get_glyph_cache();
811     if (unlikely (glyph_cache == NULL)) {
812         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
813         goto out_unlock;
814     }
815
816     pixman_glyph_cache_freeze (glyph_cache);
817
818     if (info->num_glyphs > ARRAY_LENGTH (pglyphs_stack)) {
819         pglyphs = _cairo_malloc_ab (info->num_glyphs, sizeof (pixman_glyph_t));
820         if (unlikely (pglyphs == NULL)) {
821             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
822             goto out_thaw;
823         }
824     }
825
826     pg = pglyphs;
827     for (i = 0; i < info->num_glyphs; i++) {
828         unsigned long index = info->glyphs[i].index;
829         const void *glyph;
830
831         glyph = pixman_glyph_cache_lookup (glyph_cache, info->font, (void *)index);
832         if (!glyph) {
833             cairo_scaled_glyph_t *scaled_glyph;
834             cairo_image_surface_t *glyph_surface;
835
836             /* This call can actually end up recursing, so we have to
837              * drop the mutex around it.
838              */
839             CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
840             status = _cairo_scaled_glyph_lookup (info->font, index,
841                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
842                                                  &scaled_glyph);
843             CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
844
845             if (unlikely (status))
846                 goto out_thaw;
847
848             glyph_surface = scaled_glyph->surface;
849             glyph = pixman_glyph_cache_insert (glyph_cache, info->font, (void *)index,
850                                                glyph_surface->base.device_transform.x0,
851                                                glyph_surface->base.device_transform.y0,
852                                                glyph_surface->pixman_image);
853             if (unlikely (!glyph)) {
854                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
855                 goto out_thaw;
856             }
857         }
858
859         pg->x = _cairo_lround (info->glyphs[i].x);
860         pg->y = _cairo_lround (info->glyphs[i].y);
861         pg->glyph = glyph;
862         pg++;
863     }
864
865     if (info->use_mask) {
866         pixman_format_code_t mask_format;
867
868         mask_format = pixman_glyph_get_mask_format (glyph_cache, pg - pglyphs, pglyphs);
869
870         pixman_composite_glyphs (_pixman_operator (op),
871                                  ((cairo_image_source_t *)_src)->pixman_image,
872                                  to_pixman_image (_dst),
873                                  mask_format,
874                                  info->extents.x + src_x, info->extents.y + src_y,
875                                  info->extents.x, info->extents.y,
876                                  info->extents.x - dst_x, info->extents.y - dst_y,
877                                  info->extents.width, info->extents.height,
878                                  glyph_cache, pg - pglyphs, pglyphs);
879     } else {
880         pixman_composite_glyphs_no_mask (_pixman_operator (op),
881                                          ((cairo_image_source_t *)_src)->pixman_image,
882                                          to_pixman_image (_dst),
883                                          src_x, src_y,
884                                          - dst_x, - dst_y,
885                                          glyph_cache, pg - pglyphs, pglyphs);
886     }
887
888 out_thaw:
889     pixman_glyph_cache_thaw (glyph_cache);
890
891     if (pglyphs != pglyphs_stack)
892         free(pglyphs);
893
894 out_unlock:
895     CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
896     return status;
897 }
898 #else
899 void
900 _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
901                                 cairo_scaled_glyph_t *scaled_glyph)
902 {
903 }
904
905 static cairo_int_status_t
906 composite_one_glyph (void                               *_dst,
907                      cairo_operator_t                    op,
908                      cairo_surface_t                    *_src,
909                      int                                 src_x,
910                      int                                 src_y,
911                      int                                 dst_x,
912                      int                                 dst_y,
913                      cairo_composite_glyphs_info_t       *info)
914 {
915     cairo_image_surface_t *glyph_surface;
916     cairo_scaled_glyph_t *scaled_glyph;
917     cairo_status_t status;
918     int x, y;
919
920     TRACE ((stderr, "%s\n", __FUNCTION__));
921
922     status = _cairo_scaled_glyph_lookup (info->font,
923                                          info->glyphs[0].index,
924                                          CAIRO_SCALED_GLYPH_INFO_SURFACE,
925                                          &scaled_glyph);
926
927     if (unlikely (status))
928         return status;
929
930     glyph_surface = scaled_glyph->surface;
931     if (glyph_surface->width == 0 || glyph_surface->height == 0)
932         return CAIRO_INT_STATUS_NOTHING_TO_DO;
933
934     /* round glyph locations to the nearest pixel */
935     /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
936     x = _cairo_lround (info->glyphs[0].x -
937                        glyph_surface->base.device_transform.x0);
938     y = _cairo_lround (info->glyphs[0].y -
939                        glyph_surface->base.device_transform.y0);
940
941     pixman_image_composite32 (_pixman_operator (op),
942                               ((cairo_image_source_t *)_src)->pixman_image,
943                               glyph_surface->pixman_image,
944                               to_pixman_image (_dst),
945                               x + src_x,  y + src_y,
946                               0, 0,
947                               x - dst_x, y - dst_y,
948                               glyph_surface->width,
949                               glyph_surface->height);
950
951     return CAIRO_INT_STATUS_SUCCESS;
952 }
953
954 static cairo_int_status_t
955 composite_glyphs_via_mask (void                         *_dst,
956                            cairo_operator_t              op,
957                            cairo_surface_t              *_src,
958                            int                           src_x,
959                            int                           src_y,
960                            int                           dst_x,
961                            int                           dst_y,
962                            cairo_composite_glyphs_info_t *info)
963 {
964     cairo_scaled_glyph_t *glyph_cache[64];
965     pixman_image_t *white = _pixman_image_for_color (CAIRO_COLOR_WHITE);
966     cairo_scaled_glyph_t *scaled_glyph;
967     uint8_t buf[2048];
968     pixman_image_t *mask;
969     pixman_format_code_t format;
970     cairo_status_t status;
971     int i;
972
973     TRACE ((stderr, "%s\n", __FUNCTION__));
974
975     if (unlikely (white == NULL))
976         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
977
978     /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit
979      * optimised paths through pixman. Should we increase the bit
980      * depth of the target surface, we should reconsider the appropriate
981      * mask formats.
982      */
983
984     status = _cairo_scaled_glyph_lookup (info->font,
985                                          info->glyphs[0].index,
986                                          CAIRO_SCALED_GLYPH_INFO_SURFACE,
987                                          &scaled_glyph);
988     if (unlikely (status)) {
989         pixman_image_unref (white);
990         return status;
991     }
992
993     memset (glyph_cache, 0, sizeof (glyph_cache));
994     glyph_cache[info->glyphs[0].index % ARRAY_LENGTH (glyph_cache)] = scaled_glyph;
995
996     format = PIXMAN_a8;
997     i = (info->extents.width + 3) & ~3;
998     if (scaled_glyph->surface->base.content & CAIRO_CONTENT_COLOR) {
999         format = PIXMAN_a8r8g8b8;
1000         i = info->extents.width * 4;
1001     }
1002
1003     if (i * info->extents.height > (int) sizeof (buf)) {
1004         mask = pixman_image_create_bits (format,
1005                                         info->extents.width,
1006                                         info->extents.height,
1007                                         NULL, 0);
1008     } else {
1009         memset (buf, 0, i * info->extents.height);
1010         mask = pixman_image_create_bits (format,
1011                                         info->extents.width,
1012                                         info->extents.height,
1013                                         (uint32_t *)buf, i);
1014     }
1015     if (unlikely (mask == NULL)) {
1016         pixman_image_unref (white);
1017         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1018     }
1019
1020     status = CAIRO_STATUS_SUCCESS;
1021     for (i = 0; i < info->num_glyphs; i++) {
1022         unsigned long glyph_index = info->glyphs[i].index;
1023         int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
1024         cairo_image_surface_t *glyph_surface;
1025         int x, y;
1026
1027         scaled_glyph = glyph_cache[cache_index];
1028         if (scaled_glyph == NULL ||
1029             _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
1030         {
1031             status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
1032                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
1033                                                  &scaled_glyph);
1034
1035             if (unlikely (status)) {
1036                 pixman_image_unref (mask);
1037                 pixman_image_unref (white);
1038                 return status;
1039             }
1040
1041             glyph_cache[cache_index] = scaled_glyph;
1042         }
1043
1044         glyph_surface = scaled_glyph->surface;
1045         if (glyph_surface->width && glyph_surface->height) {
1046             if (glyph_surface->base.content & CAIRO_CONTENT_COLOR &&
1047                 format == PIXMAN_a8) {
1048                 pixman_image_t *ca_mask;
1049
1050                 format = PIXMAN_a8r8g8b8;
1051                 ca_mask = pixman_image_create_bits (format,
1052                                                     info->extents.width,
1053                                                     info->extents.height,
1054                                                     NULL, 0);
1055                 if (unlikely (ca_mask == NULL)) {
1056                     pixman_image_unref (mask);
1057                     pixman_image_unref (white);
1058                     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1059                 }
1060
1061                 pixman_image_composite32 (PIXMAN_OP_SRC,
1062                                           white, mask, ca_mask,
1063                                           0, 0,
1064                                           0, 0,
1065                                           0, 0,
1066                                           info->extents.width,
1067                                           info->extents.height);
1068                 pixman_image_unref (mask);
1069                 mask = ca_mask;
1070             }
1071
1072             /* round glyph locations to the nearest pixel */
1073             /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
1074             x = _cairo_lround (info->glyphs[i].x -
1075                                glyph_surface->base.device_transform.x0);
1076             y = _cairo_lround (info->glyphs[i].y -
1077                                glyph_surface->base.device_transform.y0);
1078
1079             if (glyph_surface->pixman_format == format) {
1080                 pixman_image_composite32 (PIXMAN_OP_ADD,
1081                                           glyph_surface->pixman_image, NULL, mask,
1082                                           0, 0,
1083                                           0, 0,
1084                                           x - info->extents.x, y - info->extents.y,
1085                                           glyph_surface->width,
1086                                           glyph_surface->height);
1087             } else {
1088                 pixman_image_composite32 (PIXMAN_OP_ADD,
1089                                           white, glyph_surface->pixman_image, mask,
1090                                           0, 0,
1091                                           0, 0,
1092                                           x - info->extents.x, y - info->extents.y,
1093                                           glyph_surface->width,
1094                                           glyph_surface->height);
1095             }
1096         }
1097     }
1098
1099     if (format == PIXMAN_a8r8g8b8)
1100         pixman_image_set_component_alpha (mask, TRUE);
1101
1102     pixman_image_composite32 (_pixman_operator (op),
1103                               ((cairo_image_source_t *)_src)->pixman_image,
1104                               mask,
1105                               to_pixman_image (_dst),
1106                               info->extents.x + src_x, info->extents.y + src_y,
1107                               0, 0,
1108                               info->extents.x - dst_x, info->extents.y - dst_y,
1109                               info->extents.width, info->extents.height);
1110     pixman_image_unref (mask);
1111     pixman_image_unref (white);
1112
1113     return CAIRO_STATUS_SUCCESS;
1114 }
1115
1116 static cairo_int_status_t
1117 composite_glyphs (void                          *_dst,
1118                   cairo_operator_t               op,
1119                   cairo_surface_t               *_src,
1120                   int                            src_x,
1121                   int                            src_y,
1122                   int                            dst_x,
1123                   int                            dst_y,
1124                   cairo_composite_glyphs_info_t *info)
1125 {
1126     cairo_scaled_glyph_t *glyph_cache[64];
1127     pixman_image_t *dst, *src;
1128     cairo_status_t status;
1129     int i;
1130
1131     TRACE ((stderr, "%s\n", __FUNCTION__));
1132
1133     if (info->num_glyphs == 1)
1134         return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
1135
1136     if (info->use_mask)
1137         return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
1138
1139     op = _pixman_operator (op);
1140     dst = to_pixman_image (_dst);
1141     src = ((cairo_image_source_t *)_src)->pixman_image;
1142
1143     memset (glyph_cache, 0, sizeof (glyph_cache));
1144     status = CAIRO_STATUS_SUCCESS;
1145
1146     for (i = 0; i < info->num_glyphs; i++) {
1147         int x, y;
1148         cairo_image_surface_t *glyph_surface;
1149         cairo_scaled_glyph_t *scaled_glyph;
1150         unsigned long glyph_index = info->glyphs[i].index;
1151         int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
1152
1153         scaled_glyph = glyph_cache[cache_index];
1154         if (scaled_glyph == NULL ||
1155             _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
1156         {
1157             status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
1158                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
1159                                                  &scaled_glyph);
1160
1161             if (unlikely (status))
1162                 break;
1163
1164             glyph_cache[cache_index] = scaled_glyph;
1165         }
1166
1167         glyph_surface = scaled_glyph->surface;
1168         if (glyph_surface->width && glyph_surface->height) {
1169             /* round glyph locations to the nearest pixel */
1170             /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
1171             x = _cairo_lround (info->glyphs[i].x -
1172                                glyph_surface->base.device_transform.x0);
1173             y = _cairo_lround (info->glyphs[i].y -
1174                                glyph_surface->base.device_transform.y0);
1175
1176             pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst,
1177                                       x + src_x,  y + src_y,
1178                                       0, 0,
1179                                       x - dst_x, y - dst_y,
1180                                       glyph_surface->width,
1181                                       glyph_surface->height);
1182         }
1183     }
1184
1185     return status;
1186 }
1187 #endif
1188
1189 static cairo_int_status_t
1190 check_composite (const cairo_composite_rectangles_t *extents)
1191 {
1192     return CAIRO_STATUS_SUCCESS;
1193 }
1194
1195 const cairo_compositor_t *
1196 _cairo_image_traps_compositor_get (void)
1197 {
1198     static cairo_traps_compositor_t compositor;
1199
1200     if (compositor.base.delegate == NULL) {
1201         _cairo_traps_compositor_init (&compositor,
1202                                       &__cairo_no_compositor);
1203         compositor.acquire = acquire;
1204         compositor.release = release;
1205         compositor.set_clip_region = set_clip_region;
1206         compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
1207         compositor.draw_image_boxes = draw_image_boxes;
1208         //compositor.copy_boxes = copy_boxes;
1209         compositor.fill_boxes = fill_boxes;
1210         compositor.check_composite = check_composite;
1211         compositor.composite = composite;
1212         compositor.lerp = lerp;
1213         //compositor.check_composite_boxes = check_composite_boxes;
1214         compositor.composite_boxes = composite_boxes;
1215         //compositor.check_composite_traps = check_composite_traps;
1216         compositor.composite_traps = composite_traps;
1217         //compositor.check_composite_tristrip = check_composite_traps;
1218         compositor.composite_tristrip = composite_tristrip;
1219         compositor.check_composite_glyphs = check_composite_glyphs;
1220         compositor.composite_glyphs = composite_glyphs;
1221     }
1222
1223     return &compositor.base;
1224 }
1225
1226 const cairo_compositor_t *
1227 _cairo_image_mask_compositor_get (void)
1228 {
1229     static cairo_mask_compositor_t compositor;
1230
1231     if (compositor.base.delegate == NULL) {
1232         _cairo_mask_compositor_init (&compositor,
1233                                      _cairo_image_traps_compositor_get ());
1234         compositor.acquire = acquire;
1235         compositor.release = release;
1236         compositor.set_clip_region = set_clip_region;
1237         compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
1238         compositor.draw_image_boxes = draw_image_boxes;
1239         compositor.fill_rectangles = fill_rectangles;
1240         compositor.fill_boxes = fill_boxes;
1241         //compositor.check_composite = check_composite;
1242         compositor.composite = composite;
1243         //compositor.lerp = lerp;
1244         //compositor.check_composite_boxes = check_composite_boxes;
1245         compositor.composite_boxes = composite_boxes;
1246         compositor.check_composite_glyphs = check_composite_glyphs;
1247         compositor.composite_glyphs = composite_glyphs;
1248     }
1249
1250     return &compositor.base;
1251 }
1252
1253 #if PIXMAN_HAS_COMPOSITOR
1254 typedef struct _cairo_image_span_renderer {
1255     cairo_span_renderer_t base;
1256
1257     pixman_image_compositor_t *compositor;
1258     pixman_image_t *src, *mask;
1259     float opacity;
1260     cairo_rectangle_int_t extents;
1261 } cairo_image_span_renderer_t;
1262 COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
1263
1264 static cairo_status_t
1265 _cairo_image_bounded_opaque_spans (void *abstract_renderer,
1266                                    int y, int height,
1267                                    const cairo_half_open_span_t *spans,
1268                                    unsigned num_spans)
1269 {
1270     cairo_image_span_renderer_t *r = abstract_renderer;
1271
1272     if (num_spans == 0)
1273         return CAIRO_STATUS_SUCCESS;
1274
1275     do {
1276         if (spans[0].coverage)
1277             pixman_image_compositor_blt (r->compositor,
1278                                          spans[0].x, y,
1279                                          spans[1].x - spans[0].x, height,
1280                                          spans[0].coverage);
1281         spans++;
1282     } while (--num_spans > 1);
1283
1284     return CAIRO_STATUS_SUCCESS;
1285 }
1286
1287 static cairo_status_t
1288 _cairo_image_bounded_spans (void *abstract_renderer,
1289                             int y, int height,
1290                             const cairo_half_open_span_t *spans,
1291                             unsigned num_spans)
1292 {
1293     cairo_image_span_renderer_t *r = abstract_renderer;
1294
1295     if (num_spans == 0)
1296         return CAIRO_STATUS_SUCCESS;
1297
1298     do {
1299         if (spans[0].coverage) {
1300             pixman_image_compositor_blt (r->compositor,
1301                                          spans[0].x, y,
1302                                          spans[1].x - spans[0].x, height,
1303                                          r->opacity * spans[0].coverage);
1304         }
1305         spans++;
1306     } while (--num_spans > 1);
1307
1308     return CAIRO_STATUS_SUCCESS;
1309 }
1310
1311 static cairo_status_t
1312 _cairo_image_unbounded_spans (void *abstract_renderer,
1313                               int y, int height,
1314                               const cairo_half_open_span_t *spans,
1315                               unsigned num_spans)
1316 {
1317     cairo_image_span_renderer_t *r = abstract_renderer;
1318
1319     assert (y + height <= r->extents.height);
1320     if (y > r->extents.y) {
1321         pixman_image_compositor_blt (r->compositor,
1322                                      r->extents.x, r->extents.y,
1323                                      r->extents.width, y - r->extents.y,
1324                                      0);
1325     }
1326
1327     if (num_spans == 0) {
1328         pixman_image_compositor_blt (r->compositor,
1329                                      r->extents.x, y,
1330                                      r->extents.width,  height,
1331                                      0);
1332     } else {
1333         if (spans[0].x != r->extents.x) {
1334             pixman_image_compositor_blt (r->compositor,
1335                                          r->extents.x, y,
1336                                          spans[0].x - r->extents.x,
1337                                          height,
1338                                          0);
1339         }
1340
1341         do {
1342             assert (spans[0].x < r->extents.x + r->extents.width);
1343             pixman_image_compositor_blt (r->compositor,
1344                                          spans[0].x, y,
1345                                          spans[1].x - spans[0].x, height,
1346                                          r->opacity * spans[0].coverage);
1347             spans++;
1348         } while (--num_spans > 1);
1349
1350         if (spans[0].x != r->extents.x + r->extents.width) {
1351             assert (spans[0].x < r->extents.x + r->extents.width);
1352             pixman_image_compositor_blt (r->compositor,
1353                                          spans[0].x,     y,
1354                                          r->extents.x + r->extents.width - spans[0].x, height,
1355                                          0);
1356         }
1357     }
1358
1359     r->extents.y = y + height;
1360     return CAIRO_STATUS_SUCCESS;
1361 }
1362
1363 static cairo_status_t
1364 _cairo_image_clipped_spans (void *abstract_renderer,
1365                             int y, int height,
1366                             const cairo_half_open_span_t *spans,
1367                             unsigned num_spans)
1368 {
1369     cairo_image_span_renderer_t *r = abstract_renderer;
1370
1371     assert (num_spans);
1372
1373     do {
1374         if (! spans[0].inverse)
1375             pixman_image_compositor_blt (r->compositor,
1376                                          spans[0].x, y,
1377                                          spans[1].x - spans[0].x, height,
1378                                          r->opacity * spans[0].coverage);
1379         spans++;
1380     } while (--num_spans > 1);
1381
1382     r->extents.y = y + height;
1383     return CAIRO_STATUS_SUCCESS;
1384 }
1385
1386 static cairo_status_t
1387 _cairo_image_finish_unbounded_spans (void *abstract_renderer)
1388 {
1389     cairo_image_span_renderer_t *r = abstract_renderer;
1390
1391     if (r->extents.y < r->extents.height) {
1392         pixman_image_compositor_blt (r->compositor,
1393                                      r->extents.x, r->extents.y,
1394                                      r->extents.width,
1395                                      r->extents.height - r->extents.y,
1396                                      0);
1397     }
1398
1399     return CAIRO_STATUS_SUCCESS;
1400 }
1401
1402 static cairo_int_status_t
1403 span_renderer_init (cairo_abstract_span_renderer_t      *_r,
1404                     const cairo_composite_rectangles_t *composite,
1405                     cairo_bool_t                         needs_clip)
1406 {
1407     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
1408     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
1409     const cairo_pattern_t *source = &composite->source_pattern.base;
1410     cairo_operator_t op = composite->op;
1411     int src_x, src_y;
1412     int mask_x, mask_y;
1413
1414     TRACE ((stderr, "%s\n", __FUNCTION__));
1415
1416     if (op == CAIRO_OPERATOR_CLEAR) {
1417         op = PIXMAN_OP_LERP_CLEAR;
1418     } else if (dst->base.is_clear &&
1419                (op == CAIRO_OPERATOR_SOURCE ||
1420                 op == CAIRO_OPERATOR_OVER ||
1421                 op == CAIRO_OPERATOR_ADD)) {
1422         op = PIXMAN_OP_SRC;
1423     } else if (op == CAIRO_OPERATOR_SOURCE) {
1424         op = PIXMAN_OP_LERP_SRC;
1425     } else {
1426         op = _pixman_operator (op);
1427     }
1428
1429     r->compositor = NULL;
1430     r->mask = NULL;
1431     r->src = _pixman_image_for_pattern (dst, source, FALSE,
1432                                         &composite->unbounded,
1433                                         &composite->source_sample_area,
1434                                         &src_x, &src_y);
1435     if (unlikely (r->src == NULL))
1436         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1437
1438     r->opacity = 1.0;
1439     if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
1440         r->opacity = composite->mask_pattern.solid.color.alpha;
1441     } else {
1442         r->mask = _pixman_image_for_pattern (dst,
1443                                              &composite->mask_pattern.base,
1444                                              TRUE,
1445                                              &composite->unbounded,
1446                                              &composite->mask_sample_area,
1447                                              &mask_x, &mask_y);
1448         if (unlikely (r->mask == NULL))
1449             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1450
1451         /* XXX Component-alpha? */
1452         if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
1453             _cairo_pattern_is_opaque (source, &composite->source_sample_area))
1454         {
1455             pixman_image_unref (r->src);
1456             r->src = r->mask;
1457             src_x = mask_x;
1458             src_y = mask_y;
1459             r->mask = NULL;
1460         }
1461     }
1462
1463     if (composite->is_bounded) {
1464         if (r->opacity == 1.)
1465             r->base.render_rows = _cairo_image_bounded_opaque_spans;
1466         else
1467             r->base.render_rows = _cairo_image_bounded_spans;
1468         r->base.finish = NULL;
1469     } else {
1470         if (needs_clip)
1471             r->base.render_rows = _cairo_image_clipped_spans;
1472         else
1473             r->base.render_rows = _cairo_image_unbounded_spans;
1474         r->base.finish = _cairo_image_finish_unbounded_spans;
1475         r->extents = composite->unbounded;
1476         r->extents.height += r->extents.y;
1477     }
1478
1479     r->compositor =
1480         pixman_image_create_compositor (op, r->src, r->mask, dst->pixman_image,
1481                                         composite->unbounded.x + src_x,
1482                                         composite->unbounded.y + src_y,
1483                                         composite->unbounded.x + mask_x,
1484                                         composite->unbounded.y + mask_y,
1485                                         composite->unbounded.x,
1486                                         composite->unbounded.y,
1487                                         composite->unbounded.width,
1488                                         composite->unbounded.height);
1489     if (unlikely (r->compositor == NULL))
1490         return CAIRO_INT_STATUS_NOTHING_TO_DO;
1491
1492     return CAIRO_STATUS_SUCCESS;
1493 }
1494
1495 static void
1496 span_renderer_fini (cairo_abstract_span_renderer_t *_r,
1497                     cairo_int_status_t status)
1498 {
1499     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
1500
1501     TRACE ((stderr, "%s\n", __FUNCTION__));
1502
1503     if (status == CAIRO_INT_STATUS_SUCCESS && r->base.finish)
1504         r->base.finish (r);
1505
1506     if (r->compositor)
1507         pixman_image_compositor_destroy (r->compositor);
1508
1509     if (r->src)
1510         pixman_image_unref (r->src);
1511     if (r->mask)
1512         pixman_image_unref (r->mask);
1513 }
1514 #else
1515 typedef struct _cairo_image_span_renderer {
1516     cairo_span_renderer_t base;
1517
1518     const cairo_composite_rectangles_t *composite;
1519
1520     float opacity;
1521     uint8_t op;
1522     int bpp;
1523
1524     pixman_image_t *src, *mask;
1525     union {
1526         struct fill {
1527             int stride;
1528             uint8_t *data;
1529             uint32_t pixel;
1530         } fill;
1531         struct blit {
1532             int stride;
1533             uint8_t *data;
1534             int src_stride;
1535             uint8_t *src_data;
1536         } blit;
1537         struct composite {
1538             pixman_image_t *dst;
1539             int src_x, src_y;
1540             int mask_x, mask_y;
1541         } composite;
1542         struct finish {
1543             cairo_rectangle_int_t extents;
1544             int src_x, src_y;
1545             int stride;
1546             uint8_t *data;
1547         } mask;
1548     } u;
1549     uint8_t buf[sizeof(cairo_abstract_span_renderer_t)-128];
1550 } cairo_image_span_renderer_t;
1551 COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
1552
1553 static cairo_status_t
1554 _cairo_image_spans (void *abstract_renderer,
1555                     int y, int height,
1556                     const cairo_half_open_span_t *spans,
1557                     unsigned num_spans)
1558 {
1559     cairo_image_span_renderer_t *r = abstract_renderer;
1560     uint8_t *mask, *row;
1561     int len;
1562
1563     if (num_spans == 0)
1564         return CAIRO_STATUS_SUCCESS;
1565
1566     mask = r->u.mask.data + (y - r->u.mask.extents.y) * r->u.mask.stride;
1567     mask += spans[0].x - r->u.mask.extents.x;
1568     row = mask;
1569
1570     do {
1571         len = spans[1].x - spans[0].x;
1572         if (spans[0].coverage) {
1573             *row++ = r->opacity * spans[0].coverage;
1574             if (--len)
1575                 memset (row, row[-1], len);
1576         }
1577         row += len;
1578         spans++;
1579     } while (--num_spans > 1);
1580
1581     len = row - mask;
1582     row = mask;
1583     while (--height) {
1584         mask += r->u.mask.stride;
1585         memcpy (mask, row, len);
1586     }
1587
1588     return CAIRO_STATUS_SUCCESS;
1589 }
1590
1591 static cairo_status_t
1592 _cairo_image_spans_and_zero (void *abstract_renderer,
1593                              int y, int height,
1594                              const cairo_half_open_span_t *spans,
1595                              unsigned num_spans)
1596 {
1597     cairo_image_span_renderer_t *r = abstract_renderer;
1598     uint8_t *mask;
1599     int len;
1600
1601     mask = r->u.mask.data;
1602     if (y > r->u.mask.extents.y) {
1603         len = (y - r->u.mask.extents.y) * r->u.mask.stride;
1604         memset (mask, 0, len);
1605         mask += len;
1606     }
1607
1608     r->u.mask.extents.y = y + height;
1609     r->u.mask.data = mask + height * r->u.mask.stride;
1610     if (num_spans == 0) {
1611         memset (mask, 0, height * r->u.mask.stride);
1612     } else {
1613         uint8_t *row = mask;
1614
1615         if (spans[0].x != r->u.mask.extents.x) {
1616             len = spans[0].x - r->u.mask.extents.x;
1617             memset (row, 0, len);
1618             row += len;
1619         }
1620
1621         do {
1622             len = spans[1].x - spans[0].x;
1623             *row++ = r->opacity * spans[0].coverage;
1624             if (len > 1) {
1625                 memset (row, row[-1], --len);
1626                 row += len;
1627             }
1628             spans++;
1629         } while (--num_spans > 1);
1630
1631         if (spans[0].x != r->u.mask.extents.x + r->u.mask.extents.width) {
1632             len = r->u.mask.extents.x + r->u.mask.extents.width - spans[0].x;
1633             memset (row, 0, len);
1634         }
1635
1636         row = mask;
1637         while (--height) {
1638             mask += r->u.mask.stride;
1639             memcpy (mask, row, r->u.mask.extents.width);
1640         }
1641     }
1642
1643     return CAIRO_STATUS_SUCCESS;
1644 }
1645
1646 static cairo_status_t
1647 _cairo_image_finish_spans_and_zero (void *abstract_renderer)
1648 {
1649     cairo_image_span_renderer_t *r = abstract_renderer;
1650
1651     if (r->u.mask.extents.y < r->u.mask.extents.height)
1652         memset (r->u.mask.data, 0, (r->u.mask.extents.height - r->u.mask.extents.y) * r->u.mask.stride);
1653
1654     return CAIRO_STATUS_SUCCESS;
1655 }
1656
1657 static cairo_status_t
1658 _fill8_spans (void *abstract_renderer, int y, int h,
1659                const cairo_half_open_span_t *spans, unsigned num_spans)
1660 {
1661     cairo_image_span_renderer_t *r = abstract_renderer;
1662
1663     if (num_spans == 0)
1664         return CAIRO_STATUS_SUCCESS;
1665
1666     if (likely(h == 1)) {
1667         do {
1668             if (spans[0].coverage) {
1669                 int len = spans[1].x - spans[0].x;
1670                 uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
1671                 if (len == 1)
1672                     *d = r->u.fill.pixel;
1673                 else
1674                     memset(d, r->u.fill.pixel, len);
1675             }
1676             spans++;
1677         } while (--num_spans > 1);
1678     } else {
1679         do {
1680             if (spans[0].coverage) {
1681                 int yy = y, hh = h;
1682                 do {
1683                     int len = spans[1].x - spans[0].x;
1684                     uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
1685                     if (len == 1)
1686                         *d = r->u.fill.pixel;
1687                     else
1688                         memset(d, r->u.fill.pixel, len);
1689                     yy++;
1690                 } while (--hh);
1691             }
1692             spans++;
1693         } while (--num_spans > 1);
1694     }
1695
1696     return CAIRO_STATUS_SUCCESS;
1697 }
1698
1699 static cairo_status_t
1700 _fill16_spans (void *abstract_renderer, int y, int h,
1701                const cairo_half_open_span_t *spans, unsigned num_spans)
1702 {
1703     cairo_image_span_renderer_t *r = abstract_renderer;
1704
1705     if (num_spans == 0)
1706         return CAIRO_STATUS_SUCCESS;
1707
1708     if (likely(h == 1)) {
1709         do {
1710             if (spans[0].coverage) {
1711                 int len = spans[1].x - spans[0].x;
1712                 uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*2);
1713                 while (len--)
1714                     *d++ = r->u.fill.pixel;
1715             }
1716             spans++;
1717         } while (--num_spans > 1);
1718     } else {
1719         do {
1720             if (spans[0].coverage) {
1721                 int yy = y, hh = h;
1722                 do {
1723                     int len = spans[1].x - spans[0].x;
1724                     uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*2);
1725                     while (len--)
1726                         *d++ = r->u.fill.pixel;
1727                     yy++;
1728                 } while (--hh);
1729             }
1730             spans++;
1731         } while (--num_spans > 1);
1732     }
1733
1734     return CAIRO_STATUS_SUCCESS;
1735 }
1736
1737 static cairo_status_t
1738 _fill32_spans (void *abstract_renderer, int y, int h,
1739                const cairo_half_open_span_t *spans, unsigned num_spans)
1740 {
1741     cairo_image_span_renderer_t *r = abstract_renderer;
1742
1743     if (num_spans == 0)
1744         return CAIRO_STATUS_SUCCESS;
1745
1746     if (likely(h == 1)) {
1747         do {
1748             if (spans[0].coverage) {
1749                 int len = spans[1].x - spans[0].x;
1750                 if (len > 32) {
1751                     pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
1752                                  spans[0].x, y, len, 1, r->u.fill.pixel);
1753                 } else {
1754                     uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
1755                     while (len--)
1756                         *d++ = r->u.fill.pixel;
1757                 }
1758             }
1759             spans++;
1760         } while (--num_spans > 1);
1761     } else {
1762         do {
1763             if (spans[0].coverage) {
1764                 if (spans[1].x - spans[0].x > 16) {
1765                     pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
1766                                  spans[0].x, y, spans[1].x - spans[0].x, h,
1767                                  r->u.fill.pixel);
1768                 } else {
1769                     int yy = y, hh = h;
1770                     do {
1771                         int len = spans[1].x - spans[0].x;
1772                         uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
1773                         while (len--)
1774                             *d++ = r->u.fill.pixel;
1775                         yy++;
1776                     } while (--hh);
1777                 }
1778             }
1779             spans++;
1780         } while (--num_spans > 1);
1781     }
1782
1783     return CAIRO_STATUS_SUCCESS;
1784 }
1785
1786 #if 0
1787 static cairo_status_t
1788 _fill_spans (void *abstract_renderer, int y, int h,
1789              const cairo_half_open_span_t *spans, unsigned num_spans)
1790 {
1791     cairo_image_span_renderer_t *r = abstract_renderer;
1792
1793     if (num_spans == 0)
1794         return CAIRO_STATUS_SUCCESS;
1795
1796     do {
1797         if (spans[0].coverage) {
1798                 pixman_fill ((uint32_t *) r->data, r->stride, r->bpp,
1799                              spans[0].x, y,
1800                              spans[1].x - spans[0].x, h,
1801                              r->pixel);
1802         }
1803         spans++;
1804     } while (--num_spans > 1);
1805
1806     return CAIRO_STATUS_SUCCESS;
1807 }
1808 #endif
1809
1810 static cairo_status_t
1811 _blit_spans (void *abstract_renderer, int y, int h,
1812              const cairo_half_open_span_t *spans, unsigned num_spans)
1813 {
1814     cairo_image_span_renderer_t *r = abstract_renderer;
1815     int cpp;
1816
1817     if (num_spans == 0)
1818         return CAIRO_STATUS_SUCCESS;
1819
1820     cpp = r->bpp/8;
1821     if (likely (h == 1)) {
1822         uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
1823         uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
1824         do {
1825             if (spans[0].coverage) {
1826                 void *s = src + spans[0].x*cpp;
1827                 void *d = dst + spans[0].x*cpp;
1828                 int len = (spans[1].x - spans[0].x) * cpp;
1829                 switch (len) {
1830                 case 1:
1831                     *(uint8_t *)d = *(uint8_t *)s;
1832                     break;
1833                 case 2:
1834                     *(uint16_t *)d = *(uint16_t *)s;
1835                     break;
1836                 case 4:
1837                     *(uint32_t *)d = *(uint32_t *)s;
1838                     break;
1839 #if HAVE_UINT64_T
1840                 case 8:
1841                     *(uint64_t *)d = *(uint64_t *)s;
1842                     break;
1843 #endif
1844                 default:
1845                     memcpy(d, s, len);
1846                     break;
1847                 }
1848             }
1849             spans++;
1850         } while (--num_spans > 1);
1851     } else {
1852         do {
1853             if (spans[0].coverage) {
1854                 int yy = y, hh = h;
1855                 do {
1856                     void *src = r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x*cpp;
1857                     void *dst = r->u.blit.data + yy*r->u.blit.stride + spans[0].x*cpp;
1858                     int len = (spans[1].x - spans[0].x) * cpp;
1859                     switch (len) {
1860                     case 1:
1861                         *(uint8_t *)dst = *(uint8_t *)src;
1862                         break;
1863                     case 2:
1864                         *(uint16_t *)dst = *(uint16_t *)src;
1865                         break;
1866                     case 4:
1867                         *(uint32_t *)dst = *(uint32_t *)src;
1868                         break;
1869 #if HAVE_UINT64_T
1870                     case 8:
1871                         *(uint64_t *)dst = *(uint64_t *)src;
1872                         break;
1873 #endif
1874                     default:
1875                         memcpy(dst, src, len);
1876                         break;
1877                     }
1878                     yy++;
1879                 } while (--hh);
1880             }
1881             spans++;
1882         } while (--num_spans > 1);
1883     }
1884
1885     return CAIRO_STATUS_SUCCESS;
1886 }
1887
1888 static cairo_status_t
1889 _mono_spans (void *abstract_renderer, int y, int h,
1890              const cairo_half_open_span_t *spans, unsigned num_spans)
1891 {
1892     cairo_image_span_renderer_t *r = abstract_renderer;
1893
1894     if (num_spans == 0)
1895         return CAIRO_STATUS_SUCCESS;
1896
1897     do {
1898         if (spans[0].coverage) {
1899             pixman_image_composite32 (r->op,
1900                                       r->src, NULL, r->u.composite.dst,
1901                                       spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1902                                       0, 0,
1903                                       spans[0].x, y,
1904                                       spans[1].x - spans[0].x, h);
1905         }
1906         spans++;
1907     } while (--num_spans > 1);
1908
1909     return CAIRO_STATUS_SUCCESS;
1910 }
1911
1912 static cairo_status_t
1913 _mono_unbounded_spans (void *abstract_renderer, int y, int h,
1914                        const cairo_half_open_span_t *spans, unsigned num_spans)
1915 {
1916     cairo_image_span_renderer_t *r = abstract_renderer;
1917
1918     if (num_spans == 0) {
1919         pixman_image_composite32 (PIXMAN_OP_CLEAR,
1920                                   r->src, NULL, r->u.composite.dst,
1921                                   spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1922                                   0, 0,
1923                                   r->composite->unbounded.x, y,
1924                                   r->composite->unbounded.width, h);
1925         r->u.composite.mask_y = y + h;
1926         return CAIRO_STATUS_SUCCESS;
1927     }
1928
1929     if (y != r->u.composite.mask_y) {
1930         pixman_image_composite32 (PIXMAN_OP_CLEAR,
1931                                   r->src, NULL, r->u.composite.dst,
1932                                   spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1933                                   0, 0,
1934                                   r->composite->unbounded.x, r->u.composite.mask_y,
1935                                   r->composite->unbounded.width, y - r->u.composite.mask_y);
1936     }
1937
1938     if (spans[0].x != r->composite->unbounded.x) {
1939             pixman_image_composite32 (PIXMAN_OP_CLEAR,
1940                                       r->src, NULL, r->u.composite.dst,
1941                                       spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1942                                       0, 0,
1943                                       r->composite->unbounded.x, y,
1944                                       spans[0].x - r->composite->unbounded.x, h);
1945     }
1946
1947     do {
1948         int op = spans[0].coverage ? r->op : PIXMAN_OP_CLEAR;
1949         pixman_image_composite32 (op,
1950                                   r->src, NULL, r->u.composite.dst,
1951                                   spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1952                                   0, 0,
1953                                   spans[0].x, y,
1954                                   spans[1].x - spans[0].x, h);
1955         spans++;
1956     } while (--num_spans > 1);
1957
1958     if (spans[0].x != r->composite->unbounded.x + r->composite->unbounded.width) {
1959             pixman_image_composite32 (PIXMAN_OP_CLEAR,
1960                                       r->src, NULL, r->u.composite.dst,
1961                                       spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1962                                       0, 0,
1963                                       spans[0].x, y,
1964                                       r->composite->unbounded.x + r->composite->unbounded.width - spans[0].x, h);
1965     }
1966
1967     r->u.composite.mask_y = y + h;
1968     return CAIRO_STATUS_SUCCESS;
1969 }
1970
1971 static cairo_status_t
1972 _mono_finish_unbounded_spans (void *abstract_renderer)
1973 {
1974     cairo_image_span_renderer_t *r = abstract_renderer;
1975
1976     if (r->u.composite.mask_y < r->composite->unbounded.y + r->composite->unbounded.height) {
1977         pixman_image_composite32 (PIXMAN_OP_CLEAR,
1978                                   r->src, NULL, r->u.composite.dst,
1979                                   r->composite->unbounded.x + r->u.composite.src_x,  r->u.composite.mask_y + r->u.composite.src_y,
1980                                   0, 0,
1981                                   r->composite->unbounded.x, r->u.composite.mask_y,
1982                                   r->composite->unbounded.width,
1983                                   r->composite->unbounded.y + r->composite->unbounded.height - r->u.composite.mask_y);
1984     }
1985
1986     return CAIRO_STATUS_SUCCESS;
1987 }
1988
1989 static cairo_int_status_t
1990 mono_renderer_init (cairo_image_span_renderer_t *r,
1991                     const cairo_composite_rectangles_t *composite,
1992                     cairo_antialias_t                    antialias,
1993                     cairo_bool_t                         needs_clip)
1994 {
1995     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
1996
1997     if (antialias != CAIRO_ANTIALIAS_NONE)
1998         return CAIRO_INT_STATUS_UNSUPPORTED;
1999
2000     if (!_cairo_pattern_is_opaque_solid (&composite->mask_pattern.base))
2001         return CAIRO_INT_STATUS_UNSUPPORTED;
2002
2003     r->base.render_rows = NULL;
2004     if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
2005         const cairo_color_t *color;
2006
2007         color = &composite->source_pattern.solid.color;
2008         if (composite->op == CAIRO_OPERATOR_CLEAR)
2009             color = CAIRO_COLOR_TRANSPARENT;
2010
2011         if (fill_reduces_to_source (composite->op, color, dst) &&
2012             color_to_pixel (color, dst->pixman_format, &r->u.fill.pixel)) {
2013             /* Use plain C for the fill operations as the span length is
2014              * typically small, too small to payback the startup overheads of
2015              * using SSE2 etc.
2016              */
2017             switch (PIXMAN_FORMAT_BPP(dst->pixman_format)) {
2018             case 8: r->base.render_rows = _fill8_spans; break;
2019             case 16: r->base.render_rows = _fill16_spans; break;
2020             case 32: r->base.render_rows = _fill32_spans; break;
2021             default: break;
2022             }
2023             r->u.fill.data = dst->data;
2024             r->u.fill.stride = dst->stride;
2025         }
2026     } else if ((composite->op == CAIRO_OPERATOR_SOURCE ||
2027                 (composite->op == CAIRO_OPERATOR_OVER &&
2028                  (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) &&
2029                composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
2030                composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE &&
2031                to_image_surface(composite->source_pattern.surface.surface)->format == dst->format)
2032     {
2033        cairo_image_surface_t *src =
2034            to_image_surface(composite->source_pattern.surface.surface);
2035        int tx, ty;
2036
2037         if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix,
2038                                                  &tx, &ty) &&
2039             composite->bounded.x + tx >= 0 &&
2040             composite->bounded.y + ty >= 0 &&
2041             composite->bounded.x + composite->bounded.width +  tx <= src->width &&
2042             composite->bounded.y + composite->bounded.height + ty <= src->height) {
2043
2044             r->u.blit.stride = dst->stride;
2045             r->u.blit.data = dst->data;
2046             r->u.blit.src_stride = src->stride;
2047             r->u.blit.src_data = src->data + src->stride * ty + tx * 4;
2048             r->base.render_rows = _blit_spans;
2049         }
2050     }
2051
2052     if (r->base.render_rows == NULL) {
2053         r->src = _pixman_image_for_pattern (dst, &composite->source_pattern.base, FALSE,
2054                                             &composite->unbounded,
2055                                             &composite->source_sample_area,
2056                                             &r->u.composite.src_x, &r->u.composite.src_y);
2057         if (unlikely (r->src == NULL))
2058             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2059
2060         r->u.composite.dst = to_pixman_image (composite->surface);
2061         r->op = _pixman_operator (composite->op);
2062         if (composite->is_bounded == 0) {
2063             r->base.render_rows = _mono_unbounded_spans;
2064             r->base.finish = _mono_finish_unbounded_spans;
2065             r->u.composite.mask_y = composite->unbounded.y;
2066         } else
2067             r->base.render_rows = _mono_spans;
2068     }
2069     r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
2070
2071     return CAIRO_INT_STATUS_SUCCESS;
2072 }
2073
2074 #define ONE_HALF 0x7f
2075 #define RB_MASK 0x00ff00ff
2076 #define RB_ONE_HALF 0x007f007f
2077 #define RB_MASK_PLUS_ONE 0x01000100
2078 #define G_SHIFT 8
2079 static inline uint32_t
2080 mul8x2_8 (uint32_t a, uint8_t b)
2081 {
2082     uint32_t t = (a & RB_MASK) * b + RB_ONE_HALF;
2083     return ((t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT) & RB_MASK;
2084 }
2085
2086 static inline uint32_t
2087 add8x2_8x2 (uint32_t a, uint32_t b)
2088 {
2089     uint32_t t = a + b;
2090     t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK);
2091     return t & RB_MASK;
2092 }
2093
2094 static inline uint8_t
2095 mul8_8 (uint8_t a, uint8_t b)
2096 {
2097     uint16_t t = a * (uint16_t)b + ONE_HALF;
2098     return ((t >> G_SHIFT) + t) >> G_SHIFT;
2099 }
2100
2101 static inline uint32_t
2102 lerp8x4 (uint32_t src, uint8_t a, uint32_t dst)
2103 {
2104     return (add8x2_8x2 (mul8x2_8 (src, a),
2105                         mul8x2_8 (dst, ~a)) |
2106             add8x2_8x2 (mul8x2_8 (src >> G_SHIFT, a),
2107                         mul8x2_8 (dst >> G_SHIFT, ~a)) << G_SHIFT);
2108 }
2109
2110 static cairo_status_t
2111 _fill_a8_lerp_opaque_spans (void *abstract_renderer, int y, int h,
2112                             const cairo_half_open_span_t *spans, unsigned num_spans)
2113 {
2114     cairo_image_span_renderer_t *r = abstract_renderer;
2115
2116     if (num_spans == 0)
2117         return CAIRO_STATUS_SUCCESS;
2118
2119     if (likely(h == 1)) {
2120         uint8_t *d = r->u.fill.data + r->u.fill.stride*y;
2121         do {
2122             uint8_t a = spans[0].coverage;
2123             if (a) {
2124                 int len = spans[1].x - spans[0].x;
2125                 if (a == 0xff) {
2126                     memset(d + spans[0].x, r->u.fill.pixel, len);
2127                 } else {
2128                     uint8_t s = mul8_8(a, r->u.fill.pixel);
2129                     uint8_t *dst = d + spans[0].x;
2130                     a = ~a;
2131                     while (len--) {
2132                         uint8_t t = mul8_8(*dst, a);
2133                         *dst++ = t + s;
2134                     }
2135                 }
2136             }
2137             spans++;
2138         } while (--num_spans > 1);
2139     } else {
2140         do {
2141             uint8_t a = spans[0].coverage;
2142             if (a) {
2143                 int yy = y, hh = h;
2144                 if (a == 0xff) {
2145                     do {
2146                         int len = spans[1].x - spans[0].x;
2147                         uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
2148                         memset(d, r->u.fill.pixel, len);
2149                         yy++;
2150                     } while (--hh);
2151                 } else {
2152                     uint8_t s = mul8_8(a, r->u.fill.pixel);
2153                     a = ~a;
2154                     do {
2155                         int len = spans[1].x - spans[0].x;
2156                         uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
2157                         while (len--) {
2158                             uint8_t t = mul8_8(*d, a);
2159                             *d++ = t + s;
2160                         }
2161                         yy++;
2162                     } while (--hh);
2163                 }
2164             }
2165             spans++;
2166         } while (--num_spans > 1);
2167     }
2168
2169     return CAIRO_STATUS_SUCCESS;
2170 }
2171
2172 static cairo_status_t
2173 _fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h,
2174                                 const cairo_half_open_span_t *spans, unsigned num_spans)
2175 {
2176     cairo_image_span_renderer_t *r = abstract_renderer;
2177
2178     if (num_spans == 0)
2179         return CAIRO_STATUS_SUCCESS;
2180
2181     if (likely(h == 1)) {
2182         do {
2183             uint8_t a = spans[0].coverage;
2184             if (a) {
2185                 int len = spans[1].x - spans[0].x;
2186                 uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
2187                 if (a == 0xff) {
2188                     if (len > 31) {
2189                         pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
2190                                      spans[0].x, y, len, 1, r->u.fill.pixel);
2191                     } else {
2192                         uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
2193                         while (len--)
2194                             *d++ = r->u.fill.pixel;
2195                     }
2196                 } else while (len--) {
2197                     *d = lerp8x4 (r->u.fill.pixel, a, *d);
2198                     d++;
2199                 }
2200             }
2201             spans++;
2202         } while (--num_spans > 1);
2203     } else {
2204         do {
2205             uint8_t a = spans[0].coverage;
2206             if (a) {
2207                 if (a == 0xff) {
2208                     if (spans[1].x - spans[0].x > 16) {
2209                         pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
2210                                      spans[0].x, y, spans[1].x - spans[0].x, h,
2211                                      r->u.fill.pixel);
2212                     } else {
2213                         int yy = y, hh = h;
2214                         do {
2215                             int len = spans[1].x - spans[0].x;
2216                             uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
2217                             while (len--)
2218                                 *d++ = r->u.fill.pixel;
2219                             yy++;
2220                         } while (--hh);
2221                     }
2222                 } else {
2223                     int yy = y, hh = h;
2224                     do {
2225                         int len = spans[1].x - spans[0].x;
2226                         uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
2227                         while (len--) {
2228                             *d = lerp8x4 (r->u.fill.pixel, a, *d);
2229                             d++;
2230                         }
2231                         yy++;
2232                     } while (--hh);
2233                 }
2234             }
2235             spans++;
2236         } while (--num_spans > 1);
2237     }
2238
2239     return CAIRO_STATUS_SUCCESS;
2240 }
2241
2242 static cairo_status_t
2243 _fill_a8_lerp_spans (void *abstract_renderer, int y, int h,
2244                      const cairo_half_open_span_t *spans, unsigned num_spans)
2245 {
2246     cairo_image_span_renderer_t *r = abstract_renderer;
2247
2248     if (num_spans == 0)
2249         return CAIRO_STATUS_SUCCESS;
2250
2251     if (likely(h == 1)) {
2252         do {
2253             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2254             if (a) {
2255                 int len = spans[1].x - spans[0].x;
2256                 uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
2257                 uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
2258                 uint16_t ia = ~a;
2259                 while (len--) {
2260                     uint16_t t = *d*ia + p;
2261                     *d++ = (t + (t>>8)) >> 8;
2262                 }
2263             }
2264             spans++;
2265         } while (--num_spans > 1);
2266     } else {
2267         do {
2268             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2269             if (a) {
2270                 int yy = y, hh = h;
2271                 uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
2272                 uint16_t ia = ~a;
2273                 do {
2274                     int len = spans[1].x - spans[0].x;
2275                     uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
2276                     while (len--) {
2277                         uint16_t t = *d*ia + p;
2278                         *d++ = (t + (t>>8)) >> 8;
2279                     }
2280                     yy++;
2281                 } while (--hh);
2282             }
2283             spans++;
2284         } while (--num_spans > 1);
2285     }
2286
2287     return CAIRO_STATUS_SUCCESS;
2288 }
2289
2290 static cairo_status_t
2291 _fill_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
2292                          const cairo_half_open_span_t *spans, unsigned num_spans)
2293 {
2294     cairo_image_span_renderer_t *r = abstract_renderer;
2295
2296     if (num_spans == 0)
2297         return CAIRO_STATUS_SUCCESS;
2298
2299     if (likely(h == 1)) {
2300         do {
2301             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2302             if (a) {
2303                 int len = spans[1].x - spans[0].x;
2304                 uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
2305                 while (len--) {
2306                     *d = lerp8x4 (r->u.fill.pixel, a, *d);
2307                     d++;
2308                 }
2309             }
2310             spans++;
2311         } while (--num_spans > 1);
2312     } else {
2313         do {
2314             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2315             if (a) {
2316                 int yy = y, hh = h;
2317                 do {
2318                     int len = spans[1].x - spans[0].x;
2319                     uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
2320                     while (len--) {
2321                         *d = lerp8x4 (r->u.fill.pixel, a, *d);
2322                         d++;
2323                     }
2324                     yy++;
2325                 } while (--hh);
2326             }
2327             spans++;
2328         } while (--num_spans > 1);
2329     }
2330
2331     return CAIRO_STATUS_SUCCESS;
2332 }
2333
2334 static cairo_status_t
2335 _blit_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
2336                          const cairo_half_open_span_t *spans, unsigned num_spans)
2337 {
2338     cairo_image_span_renderer_t *r = abstract_renderer;
2339
2340     if (num_spans == 0)
2341         return CAIRO_STATUS_SUCCESS;
2342
2343     if (likely(h == 1)) {
2344         uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
2345         uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
2346         do {
2347             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2348             if (a) {
2349                 uint32_t *s = (uint32_t*)src + spans[0].x;
2350                 uint32_t *d = (uint32_t*)dst + spans[0].x;
2351                 int len = spans[1].x - spans[0].x;
2352                 if (a == 0xff) {
2353                     if (len == 1)
2354                         *d = *s;
2355                     else
2356                         memcpy(d, s, len*4);
2357                 } else {
2358                     while (len--) {
2359                         *d = lerp8x4 (*s, a, *d);
2360                         s++, d++;
2361                     }
2362                 }
2363             }
2364             spans++;
2365         } while (--num_spans > 1);
2366     } else {
2367         do {
2368             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2369             if (a) {
2370                 int yy = y, hh = h;
2371                 do {
2372                     uint32_t *s = (uint32_t *)(r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x * 4);
2373                     uint32_t *d = (uint32_t *)(r->u.blit.data + yy*r->u.blit.stride + spans[0].x * 4);
2374                     int len = spans[1].x - spans[0].x;
2375                     if (a == 0xff) {
2376                         if (len == 1)
2377                             *d = *s;
2378                         else
2379                             memcpy(d, s, len * 4);
2380                     } else {
2381                         while (len--) {
2382                             *d = lerp8x4 (*s, a, *d);
2383                             s++, d++;
2384                         }
2385                     }
2386                     yy++;
2387                 } while (--hh);
2388             }
2389             spans++;
2390         } while (--num_spans > 1);
2391     }
2392
2393     return CAIRO_STATUS_SUCCESS;
2394 }
2395
2396 static cairo_status_t
2397 _inplace_spans (void *abstract_renderer,
2398                 int y, int h,
2399                 const cairo_half_open_span_t *spans,
2400                 unsigned num_spans)
2401 {
2402     cairo_image_span_renderer_t *r = abstract_renderer;
2403     uint8_t *mask;
2404     int x0, x1;
2405
2406     if (num_spans == 0)
2407         return CAIRO_STATUS_SUCCESS;
2408
2409     if (num_spans == 2 && spans[0].coverage == 0xff) {
2410         pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst,
2411                                   spans[0].x + r->u.composite.src_x,
2412                                   y + r->u.composite.src_y,
2413                                   0, 0,
2414                                   spans[0].x, y,
2415                                   spans[1].x - spans[0].x, h);
2416         return CAIRO_STATUS_SUCCESS;
2417     }
2418
2419     mask = (uint8_t *)pixman_image_get_data (r->mask);
2420     x0 = spans[0].x;
2421     do {
2422         int len = spans[1].x - spans[0].x;
2423         *mask++ = spans[0].coverage;
2424         if (len > 1) {
2425             memset (mask, spans[0].coverage, --len);
2426             mask += len;
2427         }
2428         x1 = spans[1].x;
2429         spans++;
2430     } while (--num_spans > 1);
2431
2432     pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
2433                               x0 + r->u.composite.src_x,
2434                               y + r->u.composite.src_y,
2435                               0, 0,
2436                               x0, y,
2437                               x1 - x0, h);
2438
2439     return CAIRO_STATUS_SUCCESS;
2440 }
2441
2442 static cairo_status_t
2443 _inplace_src_spans (void *abstract_renderer,
2444                     int y, int h,
2445                     const cairo_half_open_span_t *spans,
2446                     unsigned num_spans)
2447 {
2448     cairo_image_span_renderer_t *r = abstract_renderer;
2449     uint8_t *m;
2450     int x0;
2451
2452     if (num_spans == 0)
2453         return CAIRO_STATUS_SUCCESS;
2454
2455     x0 = spans[0].x;
2456     m = r->buf;
2457     do {
2458         int len = spans[1].x - spans[0].x;
2459         if (spans[0].coverage == 0xff) {
2460             if (spans[0].x != x0) {
2461 #if PIXMAN_HAS_OP_LERP
2462                 pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
2463                                           r->src, r->mask, r->u.composite.dst,
2464                                           x0 + r->u.composite.src_x,
2465                                           y + r->u.composite.src_y,
2466                                           0, 0,
2467                                           x0, y,
2468                                           spans[0].x - x0, h);
2469 #else
2470                 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
2471                                           r->mask, NULL, r->u.composite.dst,
2472                                           0, 0,
2473                                           0, 0,
2474                                           x0, y,
2475                                           spans[0].x - x0, h);
2476                 pixman_image_composite32 (PIXMAN_OP_ADD,
2477                                           r->src, r->mask, r->u.composite.dst,
2478                                           x0 + r->u.composite.src_x,
2479                                           y + r->u.composite.src_y,
2480                                           0, 0,
2481                                           x0, y,
2482                                           spans[0].x - x0, h);
2483 #endif
2484             }
2485
2486             pixman_image_composite32 (PIXMAN_OP_SRC,
2487                                       r->src, NULL, r->u.composite.dst,
2488                                       spans[0].x + r->u.composite.src_x,
2489                                       y + r->u.composite.src_y,
2490                                       0, 0,
2491                                       spans[0].x, y,
2492                                       spans[1].x - spans[0].x, h);
2493
2494             m = r->buf;
2495             x0 = spans[1].x;
2496         } else if (spans[0].coverage == 0x0) {
2497             if (spans[0].x != x0) {
2498 #if PIXMAN_HAS_OP_LERP
2499                 pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
2500                                           r->src, r->mask, r->u.composite.dst,
2501                                           x0 + r->u.composite.src_x,
2502                                           y + r->u.composite.src_y,
2503                                           0, 0,
2504                                           x0, y,
2505                                           spans[0].x - x0, h);
2506 #else
2507                 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
2508                                           r->mask, NULL, r->u.composite.dst,
2509                                           0, 0,
2510                                           0, 0,
2511                                           x0, y,
2512                                           spans[0].x - x0, h);
2513                 pixman_image_composite32 (PIXMAN_OP_ADD,
2514                                           r->src, r->mask, r->u.composite.dst,
2515                                           x0 + r->u.composite.src_x,
2516                                           y + r->u.composite.src_y,
2517                                           0, 0,
2518                                           x0, y,
2519                                           spans[0].x - x0, h);
2520 #endif
2521             }
2522
2523             m = r->buf;
2524             x0 = spans[1].x;
2525         } else {
2526             *m++ = spans[0].coverage;
2527             if (len > 1) {
2528                 memset (m, spans[0].coverage, --len);
2529                 m += len;
2530             }
2531         }
2532         spans++;
2533     } while (--num_spans > 1);
2534
2535     if (spans[0].x != x0) {
2536 #if PIXMAN_HAS_OP_LERP
2537         pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
2538                                   r->src, r->mask, r->u.composite.dst,
2539                                   x0 + r->u.composite.src_x,
2540                                   y + r->u.composite.src_y,
2541                                   0, 0,
2542                                   x0, y,
2543                                   spans[0].x - x0, h);
2544 #else
2545         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
2546                                   r->mask, NULL, r->u.composite.dst,
2547                                   0, 0,
2548                                   0, 0,
2549                                   x0, y,
2550                                   spans[0].x - x0, h);
2551         pixman_image_composite32 (PIXMAN_OP_ADD,
2552                                   r->src, r->mask, r->u.composite.dst,
2553                                   x0 + r->u.composite.src_x,
2554                                   y + r->u.composite.src_y,
2555                                   0, 0,
2556                                   x0, y,
2557                                   spans[0].x - x0, h);
2558 #endif
2559     }
2560
2561     return CAIRO_STATUS_SUCCESS;
2562 }
2563
2564 static cairo_int_status_t
2565 inplace_renderer_init (cairo_image_span_renderer_t      *r,
2566                        const cairo_composite_rectangles_t *composite,
2567                        cairo_antialias_t                 antialias,
2568                        cairo_bool_t                      needs_clip)
2569 {
2570     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
2571
2572     if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
2573         return CAIRO_INT_STATUS_UNSUPPORTED;
2574
2575     r->base.render_rows = NULL;
2576     r->op = composite->mask_pattern.solid.color.alpha_short >> 8;
2577
2578     if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
2579         const cairo_color_t *color;
2580
2581         color = &composite->source_pattern.solid.color;
2582         if (composite->op == CAIRO_OPERATOR_CLEAR)
2583             color = CAIRO_COLOR_TRANSPARENT;
2584
2585         if (fill_reduces_to_source (composite->op, color, dst) &&
2586             color_to_pixel (color, dst->pixman_format, &r->u.fill.pixel)) {
2587             /* Use plain C for the fill operations as the span length is
2588              * typically small, too small to payback the startup overheads of
2589              * using SSE2 etc.
2590              */
2591             if (r->op == 0xff) {
2592                 switch (dst->format) {
2593                 case CAIRO_FORMAT_A8:
2594                     r->base.render_rows = _fill_a8_lerp_opaque_spans;
2595                     break;
2596                 case CAIRO_FORMAT_RGB24:
2597                 case CAIRO_FORMAT_ARGB32:
2598                     r->base.render_rows = _fill_xrgb32_lerp_opaque_spans;
2599                     break;
2600                 case CAIRO_FORMAT_A1:
2601                 case CAIRO_FORMAT_RGB16_565:
2602                 case CAIRO_FORMAT_RGB30:
2603                 case CAIRO_FORMAT_INVALID:
2604                 default: break;
2605                 }
2606             } else {
2607                 switch (dst->format) {
2608                 case CAIRO_FORMAT_A8:
2609                     r->base.render_rows = _fill_a8_lerp_spans;
2610                     break;
2611                 case CAIRO_FORMAT_RGB24:
2612                 case CAIRO_FORMAT_ARGB32:
2613                     r->base.render_rows = _fill_xrgb32_lerp_spans;
2614                     break;
2615                 case CAIRO_FORMAT_A1:
2616                 case CAIRO_FORMAT_RGB16_565:
2617                 case CAIRO_FORMAT_RGB30:
2618                 case CAIRO_FORMAT_INVALID:
2619                 default: break;
2620                 }
2621             }
2622             r->u.fill.data = dst->data;
2623             r->u.fill.stride = dst->stride;
2624         }
2625     } else if ((dst->format == CAIRO_FORMAT_ARGB32 || dst->format == CAIRO_FORMAT_RGB24) &&
2626                (composite->op == CAIRO_OPERATOR_SOURCE ||
2627                 (composite->op == CAIRO_OPERATOR_OVER &&
2628                  (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) &&
2629                composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
2630                composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE &&
2631                to_image_surface(composite->source_pattern.surface.surface)->format == dst->format)
2632     {
2633        cairo_image_surface_t *src =
2634            to_image_surface(composite->source_pattern.surface.surface);
2635        int tx, ty;
2636
2637         if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix,
2638                                                  &tx, &ty) &&
2639             composite->bounded.x + tx >= 0 &&
2640             composite->bounded.y + ty >= 0 &&
2641             composite->bounded.x + composite->bounded.width + tx <= src->width &&
2642             composite->bounded.y + composite->bounded.height + ty <= src->height) {
2643
2644             assert(PIXMAN_FORMAT_BPP(dst->pixman_format) == 32);
2645             r->u.blit.stride = dst->stride;
2646             r->u.blit.data = dst->data;
2647             r->u.blit.src_stride = src->stride;
2648             r->u.blit.src_data = src->data + src->stride * ty + tx * 4;
2649             r->base.render_rows = _blit_xrgb32_lerp_spans;
2650         }
2651     }
2652     if (r->base.render_rows == NULL) {
2653         unsigned int width;
2654         const cairo_pattern_t *src = &composite->source_pattern.base;
2655
2656         if (r->op != 0xff)
2657             return CAIRO_INT_STATUS_UNSUPPORTED;
2658
2659         if (composite->is_bounded == 0)
2660             return CAIRO_INT_STATUS_UNSUPPORTED;
2661
2662         width = (composite->bounded.width + 3) & ~3;
2663         r->base.render_rows = _inplace_spans;
2664         if (dst->base.is_clear &&
2665             (composite->op == CAIRO_OPERATOR_SOURCE ||
2666              composite->op == CAIRO_OPERATOR_OVER ||
2667              composite->op == CAIRO_OPERATOR_ADD)) {
2668             r->op = PIXMAN_OP_SRC;
2669         } else if (composite->op == CAIRO_OPERATOR_SOURCE) {
2670             r->base.render_rows = _inplace_src_spans;
2671             r->u.composite.mask_y = r->composite->unbounded.y;
2672             width = (composite->unbounded.width + 3) & ~3;
2673         } else if (composite->op == CAIRO_OPERATOR_CLEAR) {
2674             r->op = PIXMAN_OP_OUT_REVERSE;
2675             src = NULL;
2676         } else {
2677             r->op = _pixman_operator (composite->op);
2678         }
2679
2680         if (width > sizeof (r->buf))
2681             return CAIRO_INT_STATUS_UNSUPPORTED;
2682
2683         r->src = _pixman_image_for_pattern (dst, src, FALSE,
2684                                             &composite->bounded,
2685                                             &composite->source_sample_area,
2686                                             &r->u.composite.src_x, &r->u.composite.src_y);
2687         if (unlikely (r->src == NULL))
2688             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2689
2690         /* Create an effectively unbounded mask by repeating the single line */
2691         r->mask = pixman_image_create_bits (PIXMAN_a8,
2692                                             width, composite->unbounded.height,
2693                                             (uint32_t *)r->buf, 0);
2694         if (unlikely (r->mask == NULL)) {
2695             pixman_image_unref (r->src);
2696             return _cairo_error(CAIRO_STATUS_NO_MEMORY);
2697         }
2698
2699         r->u.composite.dst = dst->pixman_image;
2700     }
2701
2702     r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
2703
2704     return CAIRO_INT_STATUS_SUCCESS;
2705 }
2706
2707 static cairo_int_status_t
2708 span_renderer_init (cairo_abstract_span_renderer_t      *_r,
2709                     const cairo_composite_rectangles_t *composite,
2710                     cairo_antialias_t                    antialias,
2711                     cairo_bool_t                         needs_clip)
2712 {
2713     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
2714     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
2715     const cairo_pattern_t *source = &composite->source_pattern.base;
2716     cairo_operator_t op = composite->op;
2717     cairo_int_status_t status;
2718
2719     TRACE ((stderr, "%s: antialias=%d, needs_clip=%d\n", __FUNCTION__,
2720             antialias, needs_clip));
2721
2722     if (needs_clip)
2723         return CAIRO_INT_STATUS_UNSUPPORTED;
2724
2725     r->composite = composite;
2726     r->mask = NULL;
2727     r->src = NULL;
2728     r->base.finish = NULL;
2729
2730     status = mono_renderer_init (r, composite, antialias, needs_clip);
2731     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2732         return status;
2733
2734     status = inplace_renderer_init (r, composite, antialias, needs_clip);
2735     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2736         return status;
2737
2738     r->bpp = 0;
2739
2740     if (op == CAIRO_OPERATOR_CLEAR) {
2741 #if PIXMAN_HAS_OP_LERP
2742         op = PIXMAN_OP_LERP_CLEAR;
2743 #else
2744         source = &_cairo_pattern_white.base;
2745         op = PIXMAN_OP_OUT_REVERSE;
2746 #endif
2747     } else if (dst->base.is_clear &&
2748                (op == CAIRO_OPERATOR_SOURCE ||
2749                 op == CAIRO_OPERATOR_OVER ||
2750                 op == CAIRO_OPERATOR_ADD)) {
2751         op = PIXMAN_OP_SRC;
2752     } else if (op == CAIRO_OPERATOR_SOURCE) {
2753 #if PIXMAN_HAS_OP_LERP
2754         op = PIXMAN_OP_LERP_SRC;
2755 #else
2756         return CAIRO_INT_STATUS_UNSUPPORTED;
2757 #endif
2758     } else {
2759         op = _pixman_operator (op);
2760     }
2761     r->op = op;
2762
2763     r->src = _pixman_image_for_pattern (dst, source, FALSE,
2764                                         &composite->unbounded,
2765                                         &composite->source_sample_area,
2766                                         &r->u.mask.src_x, &r->u.mask.src_y);
2767     if (unlikely (r->src == NULL))
2768         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2769
2770     r->opacity = 1.0;
2771     if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
2772         r->opacity = composite->mask_pattern.solid.color.alpha;
2773     } else {
2774         pixman_image_t *mask;
2775         int mask_x, mask_y;
2776
2777         mask = _pixman_image_for_pattern (dst,
2778                                           &composite->mask_pattern.base,
2779                                           TRUE,
2780                                           &composite->unbounded,
2781                                           &composite->mask_sample_area,
2782                                           &mask_x, &mask_y);
2783         if (unlikely (mask == NULL))
2784             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2785
2786         /* XXX Component-alpha? */
2787         if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
2788             _cairo_pattern_is_opaque (source, &composite->source_sample_area))
2789         {
2790             pixman_image_unref (r->src);
2791             r->src = mask;
2792             r->u.mask.src_x = mask_x;
2793             r->u.mask.src_y = mask_y;
2794             mask = NULL;
2795         }
2796
2797         if (mask) {
2798             pixman_image_unref (mask);
2799             return CAIRO_INT_STATUS_UNSUPPORTED;
2800         }
2801     }
2802
2803     r->u.mask.extents = composite->unbounded;
2804     r->u.mask.stride = (r->u.mask.extents.width + 3) & ~3;
2805     if (r->u.mask.extents.height * r->u.mask.stride > (int)sizeof (r->buf)) {
2806         r->mask = pixman_image_create_bits (PIXMAN_a8,
2807                                             r->u.mask.extents.width,
2808                                             r->u.mask.extents.height,
2809                                             NULL, 0);
2810
2811         r->base.render_rows = _cairo_image_spans;
2812         r->base.finish = NULL;
2813     } else {
2814         r->mask = pixman_image_create_bits (PIXMAN_a8,
2815                                             r->u.mask.extents.width,
2816                                             r->u.mask.extents.height,
2817                                             (uint32_t *)r->buf, r->u.mask.stride);
2818
2819         r->base.render_rows = _cairo_image_spans_and_zero;
2820         r->base.finish = _cairo_image_finish_spans_and_zero;
2821     }
2822     if (unlikely (r->mask == NULL))
2823         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2824
2825     r->u.mask.data = (uint8_t *) pixman_image_get_data (r->mask);
2826     r->u.mask.stride = pixman_image_get_stride (r->mask);
2827
2828     r->u.mask.extents.height += r->u.mask.extents.y;
2829     return CAIRO_STATUS_SUCCESS;
2830 }
2831
2832 static void
2833 span_renderer_fini (cairo_abstract_span_renderer_t *_r,
2834                     cairo_int_status_t status)
2835 {
2836     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
2837
2838     TRACE ((stderr, "%s\n", __FUNCTION__));
2839
2840     if (likely (status == CAIRO_INT_STATUS_SUCCESS && r->bpp == 0)) {
2841         const cairo_composite_rectangles_t *composite = r->composite;
2842
2843         if (r->base.finish)
2844             r->base.finish (r);
2845
2846         pixman_image_composite32 (r->op, r->src, r->mask,
2847                                   to_pixman_image (composite->surface),
2848                                   composite->unbounded.x + r->u.mask.src_x,
2849                                   composite->unbounded.y + r->u.mask.src_y,
2850                                   0, 0,
2851                                   composite->unbounded.x,
2852                                   composite->unbounded.y,
2853                                   composite->unbounded.width,
2854                                   composite->unbounded.height);
2855     }
2856
2857     if (r->src)
2858         pixman_image_unref (r->src);
2859     if (r->mask)
2860         pixman_image_unref (r->mask);
2861 }
2862 #endif
2863
2864 const cairo_compositor_t *
2865 _cairo_image_spans_compositor_get (void)
2866 {
2867     static cairo_spans_compositor_t spans;
2868     static cairo_compositor_t shape;
2869
2870     if (spans.base.delegate == NULL) {
2871         _cairo_shape_mask_compositor_init (&shape,
2872                                            _cairo_image_traps_compositor_get());
2873         shape.glyphs = NULL;
2874
2875         _cairo_spans_compositor_init (&spans, &shape);
2876
2877         spans.flags = 0;
2878 #if PIXMAN_HAS_OP_LERP
2879         spans.flags |= CAIRO_SPANS_COMPOSITOR_HAS_LERP;
2880 #endif
2881
2882         //spans.acquire = acquire;
2883         //spans.release = release;
2884         spans.fill_boxes = fill_boxes;
2885         spans.draw_image_boxes = draw_image_boxes;
2886         //spans.copy_boxes = copy_boxes;
2887         spans.pattern_to_surface = _cairo_image_source_create_for_pattern;
2888         //spans.check_composite_boxes = check_composite_boxes;
2889         spans.composite_boxes = composite_boxes;
2890         //spans.check_span_renderer = check_span_renderer;
2891         spans.renderer_init = span_renderer_init;
2892         spans.renderer_fini = span_renderer_fini;
2893     }
2894
2895     return &spans.base;
2896 }