5a1ea4a6d847a3c3346b7a3ed6354a852cc4998d
[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 static cairo_int_status_t
763 composite_one_glyph (void                               *_dst,
764                      cairo_operator_t                    op,
765                      cairo_surface_t                    *_src,
766                      int                                 src_x,
767                      int                                 src_y,
768                      int                                 dst_x,
769                      int                                 dst_y,
770                      cairo_composite_glyphs_info_t       *info)
771 {
772     cairo_image_surface_t *glyph_surface;
773     cairo_scaled_glyph_t *scaled_glyph;
774     cairo_status_t status;
775     int x, y;
776
777     TRACE ((stderr, "%s\n", __FUNCTION__));
778
779     status = _cairo_scaled_glyph_lookup (info->font,
780                                          info->glyphs[0].index,
781                                          CAIRO_SCALED_GLYPH_INFO_SURFACE,
782                                          &scaled_glyph);
783
784     if (unlikely (status))
785         return status;
786
787     glyph_surface = scaled_glyph->surface;
788     if (glyph_surface->width == 0 || glyph_surface->height == 0)
789         return CAIRO_INT_STATUS_NOTHING_TO_DO;
790
791     /* round glyph locations to the nearest pixel */
792     /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
793     x = _cairo_lround (info->glyphs[0].x -
794                        glyph_surface->base.device_transform.x0);
795     y = _cairo_lround (info->glyphs[0].y -
796                        glyph_surface->base.device_transform.y0);
797
798     pixman_image_composite32 (_pixman_operator (op),
799                               ((cairo_image_source_t *)_src)->pixman_image,
800                               glyph_surface->pixman_image,
801                               to_pixman_image (_dst),
802                               x + src_x,  y + src_y,
803                               0, 0,
804                               x - dst_x, y - dst_y,
805                               glyph_surface->width,
806                               glyph_surface->height);
807
808     return CAIRO_INT_STATUS_SUCCESS;
809 }
810
811 static cairo_int_status_t
812 composite_glyphs_via_mask (void                         *_dst,
813                            cairo_operator_t              op,
814                            cairo_surface_t              *_src,
815                            int                           src_x,
816                            int                           src_y,
817                            int                           dst_x,
818                            int                           dst_y,
819                            cairo_composite_glyphs_info_t *info)
820 {
821     cairo_scaled_glyph_t *glyph_cache[64];
822     cairo_bool_t component_alpha = FALSE;
823     uint8_t buf[2048];
824     pixman_image_t *mask;
825     cairo_status_t status;
826     int i;
827
828     TRACE ((stderr, "%s\n", __FUNCTION__));
829
830     /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit
831      * optimised paths through pixman. Should we increase the bit
832      * depth of the target surface, we should reconsider the appropriate
833      * mask formats.
834      */
835     i = (info->extents.width + 3) & ~3;
836     if (i * info->extents.height > (int) sizeof (buf)) {
837         mask = pixman_image_create_bits (PIXMAN_a8,
838                                         info->extents.width,
839                                         info->extents.height,
840                                         NULL, 0);
841     } else {
842         memset (buf, 0, i * info->extents.height);
843         mask = pixman_image_create_bits (PIXMAN_a8,
844                                         info->extents.width,
845                                         info->extents.height,
846                                         (uint32_t *)buf, i);
847     }
848     if (unlikely (mask == NULL))
849         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
850
851     memset (glyph_cache, 0, sizeof (glyph_cache));
852     status = CAIRO_STATUS_SUCCESS;
853
854     for (i = 0; i < info->num_glyphs; i++) {
855         cairo_image_surface_t *glyph_surface;
856         cairo_scaled_glyph_t *scaled_glyph;
857         unsigned long glyph_index = info->glyphs[i].index;
858         int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
859         int x, y;
860
861         scaled_glyph = glyph_cache[cache_index];
862         if (scaled_glyph == NULL ||
863             _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
864         {
865             status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
866                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
867                                                  &scaled_glyph);
868
869             if (unlikely (status)) {
870                 pixman_image_unref (mask);
871                 return status;
872             }
873
874             glyph_cache[cache_index] = scaled_glyph;
875         }
876
877         glyph_surface = scaled_glyph->surface;
878         if (glyph_surface->width && glyph_surface->height) {
879             if (glyph_surface->base.content & CAIRO_CONTENT_COLOR &&
880                 ! component_alpha) {
881                 pixman_image_t *ca_mask;
882
883                 ca_mask = pixman_image_create_bits (PIXMAN_a8r8g8b8,
884                                                     info->extents.width,
885                                                     info->extents.height,
886                                                     NULL, 0);
887                 if (unlikely (ca_mask == NULL)) {
888                     pixman_image_unref (mask);
889                     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
890                 }
891
892                 pixman_image_composite32 (PIXMAN_OP_SRC,
893                                           mask, 0, ca_mask,
894                                           0, 0,
895                                           0, 0,
896                                           0, 0,
897                                           info->extents.width,
898                                           info->extents.height);
899                 pixman_image_unref (mask);
900                 mask = ca_mask;
901                 component_alpha = TRUE;
902             }
903
904             /* round glyph locations to the nearest pixel */
905             /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
906             x = _cairo_lround (info->glyphs[i].x -
907                                glyph_surface->base.device_transform.x0);
908             y = _cairo_lround (info->glyphs[i].y -
909                                glyph_surface->base.device_transform.y0);
910
911             pixman_image_composite32 (PIXMAN_OP_ADD,
912                                       glyph_surface->pixman_image, NULL, mask,
913                                       0, 0,
914                                       0, 0,
915                                       x - info->extents.x, y - info->extents.y,
916                                       glyph_surface->width,
917                                       glyph_surface->height);
918         }
919     }
920
921     if (component_alpha)
922         pixman_image_set_component_alpha (mask, TRUE);
923
924     pixman_image_composite32 (_pixman_operator (op),
925                               ((cairo_image_source_t *)_src)->pixman_image,
926                               mask,
927                               to_pixman_image (_dst),
928                               info->extents.x + src_x, info->extents.y + src_y,
929                               0, 0,
930                               info->extents.x - dst_x, info->extents.y - dst_y,
931                               info->extents.width, info->extents.height);
932     pixman_image_unref (mask);
933
934     return CAIRO_STATUS_SUCCESS;
935 }
936
937 static cairo_int_status_t
938 composite_glyphs (void                          *_dst,
939                   cairo_operator_t               op,
940                   cairo_surface_t               *_src,
941                   int                            src_x,
942                   int                            src_y,
943                   int                            dst_x,
944                   int                            dst_y,
945                   cairo_composite_glyphs_info_t *info)
946 {
947     cairo_scaled_glyph_t *glyph_cache[64];
948     pixman_image_t *dst, *src;
949     cairo_status_t status;
950     int i;
951
952     TRACE ((stderr, "%s\n", __FUNCTION__));
953
954     if (info->num_glyphs == 1)
955         return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
956
957     if (info->use_mask)
958         return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
959
960     op = _pixman_operator (op);
961     dst = to_pixman_image (_dst);
962     src = ((cairo_image_source_t *)_src)->pixman_image;
963
964     memset (glyph_cache, 0, sizeof (glyph_cache));
965     status = CAIRO_STATUS_SUCCESS;
966
967     for (i = 0; i < info->num_glyphs; i++) {
968         int x, y;
969         cairo_image_surface_t *glyph_surface;
970         cairo_scaled_glyph_t *scaled_glyph;
971         unsigned long glyph_index = info->glyphs[i].index;
972         int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
973
974         scaled_glyph = glyph_cache[cache_index];
975         if (scaled_glyph == NULL ||
976             _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
977         {
978             status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
979                                                  CAIRO_SCALED_GLYPH_INFO_SURFACE,
980                                                  &scaled_glyph);
981
982             if (unlikely (status))
983                 break;
984
985             glyph_cache[cache_index] = scaled_glyph;
986         }
987
988         glyph_surface = scaled_glyph->surface;
989         if (glyph_surface->width && glyph_surface->height) {
990             /* round glyph locations to the nearest pixel */
991             /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
992             x = _cairo_lround (info->glyphs[i].x -
993                                glyph_surface->base.device_transform.x0);
994             y = _cairo_lround (info->glyphs[i].y -
995                                glyph_surface->base.device_transform.y0);
996
997             pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst,
998                                       x + src_x,  y + src_y,
999                                       0, 0,
1000                                       x - dst_x, y - dst_y,
1001                                       glyph_surface->width,
1002                                       glyph_surface->height);
1003         }
1004     }
1005
1006     return status;
1007 }
1008
1009 static cairo_int_status_t
1010 check_composite (const cairo_composite_rectangles_t *extents)
1011 {
1012     return CAIRO_STATUS_SUCCESS;
1013 }
1014
1015 const cairo_compositor_t *
1016 _cairo_image_traps_compositor_get (void)
1017 {
1018     static cairo_traps_compositor_t compositor;
1019
1020     if (compositor.base.delegate == NULL) {
1021         _cairo_traps_compositor_init (&compositor,
1022                                       &__cairo_no_compositor);
1023         compositor.acquire = acquire;
1024         compositor.release = release;
1025         compositor.set_clip_region = set_clip_region;
1026         compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
1027         compositor.draw_image_boxes = draw_image_boxes;
1028         //compositor.copy_boxes = copy_boxes;
1029         compositor.fill_boxes = fill_boxes;
1030         compositor.check_composite = check_composite;
1031         compositor.composite = composite;
1032         compositor.lerp = lerp;
1033         //compositor.check_composite_boxes = check_composite_boxes;
1034         compositor.composite_boxes = composite_boxes;
1035         //compositor.check_composite_traps = check_composite_traps;
1036         compositor.composite_traps = composite_traps;
1037         //compositor.check_composite_tristrip = check_composite_traps;
1038         compositor.composite_tristrip = composite_tristrip;
1039         compositor.check_composite_glyphs = check_composite_glyphs;
1040         compositor.composite_glyphs = composite_glyphs;
1041     }
1042
1043     return &compositor.base;
1044 }
1045
1046 const cairo_compositor_t *
1047 _cairo_image_mask_compositor_get (void)
1048 {
1049     static cairo_mask_compositor_t compositor;
1050
1051     if (compositor.base.delegate == NULL) {
1052         _cairo_mask_compositor_init (&compositor,
1053                                      _cairo_image_traps_compositor_get ());
1054         compositor.acquire = acquire;
1055         compositor.release = release;
1056         compositor.set_clip_region = set_clip_region;
1057         compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
1058         compositor.draw_image_boxes = draw_image_boxes;
1059         compositor.fill_rectangles = fill_rectangles;
1060         compositor.fill_boxes = fill_boxes;
1061         //compositor.check_composite = check_composite;
1062         compositor.composite = composite;
1063         //compositor.lerp = lerp;
1064         //compositor.check_composite_boxes = check_composite_boxes;
1065         compositor.composite_boxes = composite_boxes;
1066         compositor.check_composite_glyphs = check_composite_glyphs;
1067         compositor.composite_glyphs = composite_glyphs;
1068     }
1069
1070     return &compositor.base;
1071 }
1072
1073 #if PIXMAN_HAS_COMPOSITOR
1074 typedef struct _cairo_image_span_renderer {
1075     cairo_span_renderer_t base;
1076
1077     pixman_image_compositor_t *compositor;
1078     pixman_image_t *src, *mask;
1079     float opacity;
1080     cairo_rectangle_int_t extents;
1081 } cairo_image_span_renderer_t;
1082 COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
1083
1084 static cairo_status_t
1085 _cairo_image_bounded_opaque_spans (void *abstract_renderer,
1086                                    int y, int height,
1087                                    const cairo_half_open_span_t *spans,
1088                                    unsigned num_spans)
1089 {
1090     cairo_image_span_renderer_t *r = abstract_renderer;
1091
1092     if (num_spans == 0)
1093         return CAIRO_STATUS_SUCCESS;
1094
1095     do {
1096         if (spans[0].coverage)
1097             pixman_image_compositor_blt (r->compositor,
1098                                          spans[0].x, y,
1099                                          spans[1].x - spans[0].x, height,
1100                                          spans[0].coverage);
1101         spans++;
1102     } while (--num_spans > 1);
1103
1104     return CAIRO_STATUS_SUCCESS;
1105 }
1106
1107 static cairo_status_t
1108 _cairo_image_bounded_spans (void *abstract_renderer,
1109                             int y, int height,
1110                             const cairo_half_open_span_t *spans,
1111                             unsigned num_spans)
1112 {
1113     cairo_image_span_renderer_t *r = abstract_renderer;
1114
1115     if (num_spans == 0)
1116         return CAIRO_STATUS_SUCCESS;
1117
1118     do {
1119         if (spans[0].coverage) {
1120             pixman_image_compositor_blt (r->compositor,
1121                                          spans[0].x, y,
1122                                          spans[1].x - spans[0].x, height,
1123                                          r->opacity * spans[0].coverage);
1124         }
1125         spans++;
1126     } while (--num_spans > 1);
1127
1128     return CAIRO_STATUS_SUCCESS;
1129 }
1130
1131 static cairo_status_t
1132 _cairo_image_unbounded_spans (void *abstract_renderer,
1133                               int y, int height,
1134                               const cairo_half_open_span_t *spans,
1135                               unsigned num_spans)
1136 {
1137     cairo_image_span_renderer_t *r = abstract_renderer;
1138
1139     assert (y + height <= r->extents.height);
1140     if (y > r->extents.y) {
1141         pixman_image_compositor_blt (r->compositor,
1142                                      r->extents.x, r->extents.y,
1143                                      r->extents.width, y - r->extents.y,
1144                                      0);
1145     }
1146
1147     if (num_spans == 0) {
1148         pixman_image_compositor_blt (r->compositor,
1149                                      r->extents.x, y,
1150                                      r->extents.width,  height,
1151                                      0);
1152     } else {
1153         if (spans[0].x != r->extents.x) {
1154             pixman_image_compositor_blt (r->compositor,
1155                                          r->extents.x, y,
1156                                          spans[0].x - r->extents.x,
1157                                          height,
1158                                          0);
1159         }
1160
1161         do {
1162             assert (spans[0].x < r->extents.x + r->extents.width);
1163             pixman_image_compositor_blt (r->compositor,
1164                                          spans[0].x, y,
1165                                          spans[1].x - spans[0].x, height,
1166                                          r->opacity * spans[0].coverage);
1167             spans++;
1168         } while (--num_spans > 1);
1169
1170         if (spans[0].x != r->extents.x + r->extents.width) {
1171             assert (spans[0].x < r->extents.x + r->extents.width);
1172             pixman_image_compositor_blt (r->compositor,
1173                                          spans[0].x,     y,
1174                                          r->extents.x + r->extents.width - spans[0].x, height,
1175                                          0);
1176         }
1177     }
1178
1179     r->extents.y = y + height;
1180     return CAIRO_STATUS_SUCCESS;
1181 }
1182
1183 static cairo_status_t
1184 _cairo_image_clipped_spans (void *abstract_renderer,
1185                             int y, int height,
1186                             const cairo_half_open_span_t *spans,
1187                             unsigned num_spans)
1188 {
1189     cairo_image_span_renderer_t *r = abstract_renderer;
1190
1191     assert (num_spans);
1192
1193     do {
1194         if (! spans[0].inverse)
1195             pixman_image_compositor_blt (r->compositor,
1196                                          spans[0].x, y,
1197                                          spans[1].x - spans[0].x, height,
1198                                          r->opacity * spans[0].coverage);
1199         spans++;
1200     } while (--num_spans > 1);
1201
1202     r->extents.y = y + height;
1203     return CAIRO_STATUS_SUCCESS;
1204 }
1205
1206 static cairo_status_t
1207 _cairo_image_finish_unbounded_spans (void *abstract_renderer)
1208 {
1209     cairo_image_span_renderer_t *r = abstract_renderer;
1210
1211     if (r->extents.y < r->extents.height) {
1212         pixman_image_compositor_blt (r->compositor,
1213                                      r->extents.x, r->extents.y,
1214                                      r->extents.width,
1215                                      r->extents.height - r->extents.y,
1216                                      0);
1217     }
1218
1219     return CAIRO_STATUS_SUCCESS;
1220 }
1221
1222 static cairo_int_status_t
1223 span_renderer_init (cairo_abstract_span_renderer_t      *_r,
1224                     const cairo_composite_rectangles_t *composite,
1225                     cairo_bool_t                         needs_clip)
1226 {
1227     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
1228     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
1229     const cairo_pattern_t *source = &composite->source_pattern.base;
1230     cairo_operator_t op = composite->op;
1231     int src_x, src_y;
1232     int mask_x, mask_y;
1233
1234     TRACE ((stderr, "%s\n", __FUNCTION__));
1235
1236     if (op == CAIRO_OPERATOR_CLEAR) {
1237         op = PIXMAN_OP_LERP_CLEAR;
1238     } else if (dst->base.is_clear &&
1239                (op == CAIRO_OPERATOR_SOURCE ||
1240                 op == CAIRO_OPERATOR_OVER ||
1241                 op == CAIRO_OPERATOR_ADD)) {
1242         op = PIXMAN_OP_SRC;
1243     } else if (op == CAIRO_OPERATOR_SOURCE) {
1244         op = PIXMAN_OP_LERP_SRC;
1245     } else {
1246         op = _pixman_operator (op);
1247     }
1248
1249     r->compositor = NULL;
1250     r->mask = NULL;
1251     r->src = _pixman_image_for_pattern (dst, source, FALSE,
1252                                         &composite->unbounded,
1253                                         &composite->source_sample_area,
1254                                         &src_x, &src_y);
1255     if (unlikely (r->src == NULL))
1256         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1257
1258     r->opacity = 1.0;
1259     if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
1260         r->opacity = composite->mask_pattern.solid.color.alpha;
1261     } else {
1262         r->mask = _pixman_image_for_pattern (dst,
1263                                              &composite->mask_pattern.base,
1264                                              TRUE,
1265                                              &composite->unbounded,
1266                                              &composite->mask_sample_area,
1267                                              &mask_x, &mask_y);
1268         if (unlikely (r->mask == NULL))
1269             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1270
1271         /* XXX Component-alpha? */
1272         if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
1273             _cairo_pattern_is_opaque (source, &composite->source_sample_area))
1274         {
1275             pixman_image_unref (r->src);
1276             r->src = r->mask;
1277             src_x = mask_x;
1278             src_y = mask_y;
1279             r->mask = NULL;
1280         }
1281     }
1282
1283     if (composite->is_bounded) {
1284         if (r->opacity == 1.)
1285             r->base.render_rows = _cairo_image_bounded_opaque_spans;
1286         else
1287             r->base.render_rows = _cairo_image_bounded_spans;
1288         r->base.finish = NULL;
1289     } else {
1290         if (needs_clip)
1291             r->base.render_rows = _cairo_image_clipped_spans;
1292         else
1293             r->base.render_rows = _cairo_image_unbounded_spans;
1294         r->base.finish = _cairo_image_finish_unbounded_spans;
1295         r->extents = composite->unbounded;
1296         r->extents.height += r->extents.y;
1297     }
1298
1299     r->compositor =
1300         pixman_image_create_compositor (op, r->src, r->mask, dst->pixman_image,
1301                                         composite->unbounded.x + src_x,
1302                                         composite->unbounded.y + src_y,
1303                                         composite->unbounded.x + mask_x,
1304                                         composite->unbounded.y + mask_y,
1305                                         composite->unbounded.x,
1306                                         composite->unbounded.y,
1307                                         composite->unbounded.width,
1308                                         composite->unbounded.height);
1309     if (unlikely (r->compositor == NULL))
1310         return CAIRO_INT_STATUS_NOTHING_TO_DO;
1311
1312     return CAIRO_STATUS_SUCCESS;
1313 }
1314
1315 static void
1316 span_renderer_fini (cairo_abstract_span_renderer_t *_r,
1317                     cairo_int_status_t status)
1318 {
1319     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
1320
1321     TRACE ((stderr, "%s\n", __FUNCTION__));
1322
1323     if (status == CAIRO_INT_STATUS_SUCCESS && r->base.finish)
1324         r->base.finish (r);
1325
1326     if (r->compositor)
1327         pixman_image_compositor_destroy (r->compositor);
1328
1329     if (r->src)
1330         pixman_image_unref (r->src);
1331     if (r->mask)
1332         pixman_image_unref (r->mask);
1333 }
1334 #else
1335 typedef struct _cairo_image_span_renderer {
1336     cairo_span_renderer_t base;
1337
1338     const cairo_composite_rectangles_t *composite;
1339
1340     float opacity;
1341     uint8_t op;
1342     int bpp;
1343
1344     pixman_image_t *src, *mask;
1345     union {
1346         struct fill {
1347             int stride;
1348             uint8_t *data;
1349             uint32_t pixel;
1350         } fill;
1351         struct blit {
1352             int stride;
1353             uint8_t *data;
1354             int src_stride;
1355             uint8_t *src_data;
1356         } blit;
1357         struct composite {
1358             pixman_image_t *dst;
1359             int src_x, src_y;
1360             int mask_x, mask_y;
1361         } composite;
1362         struct finish {
1363             cairo_rectangle_int_t extents;
1364             int src_x, src_y;
1365             int stride;
1366             uint8_t *data;
1367         } mask;
1368     } u;
1369     uint8_t buf[sizeof(cairo_abstract_span_renderer_t)-128];
1370 } cairo_image_span_renderer_t;
1371 COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
1372
1373 static cairo_status_t
1374 _cairo_image_spans (void *abstract_renderer,
1375                     int y, int height,
1376                     const cairo_half_open_span_t *spans,
1377                     unsigned num_spans)
1378 {
1379     cairo_image_span_renderer_t *r = abstract_renderer;
1380     uint8_t *mask, *row;
1381     int len;
1382
1383     if (num_spans == 0)
1384         return CAIRO_STATUS_SUCCESS;
1385
1386     mask = r->u.mask.data + (y - r->u.mask.extents.y) * r->u.mask.stride;
1387     mask += spans[0].x - r->u.mask.extents.x;
1388     row = mask;
1389
1390     do {
1391         len = spans[1].x - spans[0].x;
1392         if (spans[0].coverage) {
1393             *row++ = r->opacity * spans[0].coverage;
1394             if (--len)
1395                 memset (row, row[-1], len);
1396         }
1397         row += len;
1398         spans++;
1399     } while (--num_spans > 1);
1400
1401     len = row - mask;
1402     row = mask;
1403     while (--height) {
1404         mask += r->u.mask.stride;
1405         memcpy (mask, row, len);
1406     }
1407
1408     return CAIRO_STATUS_SUCCESS;
1409 }
1410
1411 static cairo_status_t
1412 _cairo_image_spans_and_zero (void *abstract_renderer,
1413                              int y, int height,
1414                              const cairo_half_open_span_t *spans,
1415                              unsigned num_spans)
1416 {
1417     cairo_image_span_renderer_t *r = abstract_renderer;
1418     uint8_t *mask;
1419     int len;
1420
1421     mask = r->u.mask.data;
1422     if (y > r->u.mask.extents.y) {
1423         len = (y - r->u.mask.extents.y) * r->u.mask.stride;
1424         memset (mask, 0, len);
1425         mask += len;
1426     }
1427
1428     r->u.mask.extents.y = y + height;
1429     r->u.mask.data = mask + height * r->u.mask.stride;
1430     if (num_spans == 0) {
1431         memset (mask, 0, height * r->u.mask.stride);
1432     } else {
1433         uint8_t *row = mask;
1434
1435         if (spans[0].x != r->u.mask.extents.x) {
1436             len = spans[0].x - r->u.mask.extents.x;
1437             memset (row, 0, len);
1438             row += len;
1439         }
1440
1441         do {
1442             len = spans[1].x - spans[0].x;
1443             *row++ = r->opacity * spans[0].coverage;
1444             if (len > 1) {
1445                 memset (row, row[-1], --len);
1446                 row += len;
1447             }
1448             spans++;
1449         } while (--num_spans > 1);
1450
1451         if (spans[0].x != r->u.mask.extents.x + r->u.mask.extents.width) {
1452             len = r->u.mask.extents.x + r->u.mask.extents.width - spans[0].x;
1453             memset (row, 0, len);
1454         }
1455
1456         row = mask;
1457         while (--height) {
1458             mask += r->u.mask.stride;
1459             memcpy (mask, row, r->u.mask.extents.width);
1460         }
1461     }
1462
1463     return CAIRO_STATUS_SUCCESS;
1464 }
1465
1466 static cairo_status_t
1467 _cairo_image_finish_spans_and_zero (void *abstract_renderer)
1468 {
1469     cairo_image_span_renderer_t *r = abstract_renderer;
1470
1471     if (r->u.mask.extents.y < r->u.mask.extents.height)
1472         memset (r->u.mask.data, 0, (r->u.mask.extents.height - r->u.mask.extents.y) * r->u.mask.stride);
1473
1474     return CAIRO_STATUS_SUCCESS;
1475 }
1476
1477 static cairo_status_t
1478 _fill8_spans (void *abstract_renderer, int y, int h,
1479                const cairo_half_open_span_t *spans, unsigned num_spans)
1480 {
1481     cairo_image_span_renderer_t *r = abstract_renderer;
1482
1483     if (num_spans == 0)
1484         return CAIRO_STATUS_SUCCESS;
1485
1486     if (likely(h == 1)) {
1487         do {
1488             if (spans[0].coverage) {
1489                 int len = spans[1].x - spans[0].x;
1490                 uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
1491                 if (len == 1)
1492                     *d = r->u.fill.pixel;
1493                 else
1494                     memset(d, r->u.fill.pixel, len);
1495             }
1496             spans++;
1497         } while (--num_spans > 1);
1498     } else {
1499         do {
1500             if (spans[0].coverage) {
1501                 int yy = y, hh = h;
1502                 do {
1503                     int len = spans[1].x - spans[0].x;
1504                     uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
1505                     if (len == 1)
1506                         *d = r->u.fill.pixel;
1507                     else
1508                         memset(d, r->u.fill.pixel, len);
1509                     yy++;
1510                 } while (--hh);
1511             }
1512             spans++;
1513         } while (--num_spans > 1);
1514     }
1515
1516     return CAIRO_STATUS_SUCCESS;
1517 }
1518
1519 static cairo_status_t
1520 _fill16_spans (void *abstract_renderer, int y, int h,
1521                const cairo_half_open_span_t *spans, unsigned num_spans)
1522 {
1523     cairo_image_span_renderer_t *r = abstract_renderer;
1524
1525     if (num_spans == 0)
1526         return CAIRO_STATUS_SUCCESS;
1527
1528     if (likely(h == 1)) {
1529         do {
1530             if (spans[0].coverage) {
1531                 int len = spans[1].x - spans[0].x;
1532                 uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*2);
1533                 while (len--)
1534                     *d++ = r->u.fill.pixel;
1535             }
1536             spans++;
1537         } while (--num_spans > 1);
1538     } else {
1539         do {
1540             if (spans[0].coverage) {
1541                 int yy = y, hh = h;
1542                 do {
1543                     int len = spans[1].x - spans[0].x;
1544                     uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*2);
1545                     while (len--)
1546                         *d++ = r->u.fill.pixel;
1547                     yy++;
1548                 } while (--hh);
1549             }
1550             spans++;
1551         } while (--num_spans > 1);
1552     }
1553
1554     return CAIRO_STATUS_SUCCESS;
1555 }
1556
1557 static cairo_status_t
1558 _fill32_spans (void *abstract_renderer, int y, int h,
1559                const cairo_half_open_span_t *spans, unsigned num_spans)
1560 {
1561     cairo_image_span_renderer_t *r = abstract_renderer;
1562
1563     if (num_spans == 0)
1564         return CAIRO_STATUS_SUCCESS;
1565
1566     if (likely(h == 1)) {
1567         do {
1568             if (spans[0].coverage) {
1569                 int len = spans[1].x - spans[0].x;
1570                 if (len > 32) {
1571                     pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
1572                                  spans[0].x, y, len, 1, r->u.fill.pixel);
1573                 } else {
1574                     uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
1575                     while (len--)
1576                         *d++ = r->u.fill.pixel;
1577                 }
1578             }
1579             spans++;
1580         } while (--num_spans > 1);
1581     } else {
1582         do {
1583             if (spans[0].coverage) {
1584                 if (spans[1].x - spans[0].x > 16) {
1585                     pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
1586                                  spans[0].x, y, spans[1].x - spans[0].x, h,
1587                                  r->u.fill.pixel);
1588                 } else {
1589                     int yy = y, hh = h;
1590                     do {
1591                         int len = spans[1].x - spans[0].x;
1592                         uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
1593                         while (len--)
1594                             *d++ = r->u.fill.pixel;
1595                         yy++;
1596                     } while (--hh);
1597                 }
1598             }
1599             spans++;
1600         } while (--num_spans > 1);
1601     }
1602
1603     return CAIRO_STATUS_SUCCESS;
1604 }
1605
1606 #if 0
1607 static cairo_status_t
1608 _fill_spans (void *abstract_renderer, int y, int h,
1609              const cairo_half_open_span_t *spans, unsigned num_spans)
1610 {
1611     cairo_image_span_renderer_t *r = abstract_renderer;
1612
1613     if (num_spans == 0)
1614         return CAIRO_STATUS_SUCCESS;
1615
1616     do {
1617         if (spans[0].coverage) {
1618                 pixman_fill ((uint32_t *) r->data, r->stride, r->bpp,
1619                              spans[0].x, y,
1620                              spans[1].x - spans[0].x, h,
1621                              r->pixel);
1622         }
1623         spans++;
1624     } while (--num_spans > 1);
1625
1626     return CAIRO_STATUS_SUCCESS;
1627 }
1628 #endif
1629
1630 static cairo_status_t
1631 _blit_spans (void *abstract_renderer, int y, int h,
1632              const cairo_half_open_span_t *spans, unsigned num_spans)
1633 {
1634     cairo_image_span_renderer_t *r = abstract_renderer;
1635     int cpp;
1636
1637     if (num_spans == 0)
1638         return CAIRO_STATUS_SUCCESS;
1639
1640     cpp = r->bpp/8;
1641     if (likely (h == 1)) {
1642         uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
1643         uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
1644         do {
1645             if (spans[0].coverage) {
1646                 void *s = src + spans[0].x*cpp;
1647                 void *d = dst + spans[0].x*cpp;
1648                 int len = (spans[1].x - spans[0].x) * cpp;
1649                 switch (len) {
1650                 case 1:
1651                     *(uint8_t *)d = *(uint8_t *)s;
1652                     break;
1653                 case 2:
1654                     *(uint16_t *)d = *(uint16_t *)s;
1655                     break;
1656                 case 4:
1657                     *(uint32_t *)d = *(uint32_t *)s;
1658                     break;
1659 #if HAVE_UINT64_T
1660                 case 8:
1661                     *(uint64_t *)d = *(uint64_t *)s;
1662                     break;
1663 #endif
1664                 default:
1665                     memcpy(d, s, len);
1666                     break;
1667                 }
1668             }
1669             spans++;
1670         } while (--num_spans > 1);
1671     } else {
1672         do {
1673             if (spans[0].coverage) {
1674                 int yy = y, hh = h;
1675                 do {
1676                     void *src = r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x*cpp;
1677                     void *dst = r->u.blit.data + yy*r->u.blit.stride + spans[0].x*cpp;
1678                     int len = (spans[1].x - spans[0].x) * cpp;
1679                     switch (len) {
1680                     case 1:
1681                         *(uint8_t *)dst = *(uint8_t *)src;
1682                         break;
1683                     case 2:
1684                         *(uint16_t *)dst = *(uint16_t *)src;
1685                         break;
1686                     case 4:
1687                         *(uint32_t *)dst = *(uint32_t *)src;
1688                         break;
1689 #if HAVE_UINT64_T
1690                     case 8:
1691                         *(uint64_t *)dst = *(uint64_t *)src;
1692                         break;
1693 #endif
1694                     default:
1695                         memcpy(dst, src, len);
1696                         break;
1697                     }
1698                     yy++;
1699                 } while (--hh);
1700             }
1701             spans++;
1702         } while (--num_spans > 1);
1703     }
1704
1705     return CAIRO_STATUS_SUCCESS;
1706 }
1707
1708 static cairo_status_t
1709 _mono_spans (void *abstract_renderer, int y, int h,
1710              const cairo_half_open_span_t *spans, unsigned num_spans)
1711 {
1712     cairo_image_span_renderer_t *r = abstract_renderer;
1713
1714     if (num_spans == 0)
1715         return CAIRO_STATUS_SUCCESS;
1716
1717     do {
1718         if (spans[0].coverage) {
1719             pixman_image_composite32 (r->op,
1720                                       r->src, NULL, r->u.composite.dst,
1721                                       spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1722                                       0, 0,
1723                                       spans[0].x, y,
1724                                       spans[1].x - spans[0].x, h);
1725         }
1726         spans++;
1727     } while (--num_spans > 1);
1728
1729     return CAIRO_STATUS_SUCCESS;
1730 }
1731
1732 static cairo_status_t
1733 _mono_unbounded_spans (void *abstract_renderer, int y, int h,
1734                        const cairo_half_open_span_t *spans, unsigned num_spans)
1735 {
1736     cairo_image_span_renderer_t *r = abstract_renderer;
1737
1738     if (num_spans == 0) {
1739         pixman_image_composite32 (PIXMAN_OP_CLEAR,
1740                                   r->src, NULL, r->u.composite.dst,
1741                                   spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1742                                   0, 0,
1743                                   r->composite->unbounded.x, y,
1744                                   r->composite->unbounded.width, h);
1745         r->u.composite.mask_y = y + h;
1746         return CAIRO_STATUS_SUCCESS;
1747     }
1748
1749     if (y != r->u.composite.mask_y) {
1750         pixman_image_composite32 (PIXMAN_OP_CLEAR,
1751                                   r->src, NULL, r->u.composite.dst,
1752                                   spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1753                                   0, 0,
1754                                   r->composite->unbounded.x, r->u.composite.mask_y,
1755                                   r->composite->unbounded.width, y - r->u.composite.mask_y);
1756     }
1757
1758     if (spans[0].x != r->composite->unbounded.x) {
1759             pixman_image_composite32 (PIXMAN_OP_CLEAR,
1760                                       r->src, NULL, r->u.composite.dst,
1761                                       spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1762                                       0, 0,
1763                                       r->composite->unbounded.x, y,
1764                                       spans[0].x - r->composite->unbounded.x, h);
1765     }
1766
1767     do {
1768         int op = spans[0].coverage ? r->op : PIXMAN_OP_CLEAR;
1769         pixman_image_composite32 (op,
1770                                   r->src, NULL, r->u.composite.dst,
1771                                   spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1772                                   0, 0,
1773                                   spans[0].x, y,
1774                                   spans[1].x - spans[0].x, h);
1775         spans++;
1776     } while (--num_spans > 1);
1777
1778     if (spans[0].x != r->composite->unbounded.x + r->composite->unbounded.width) {
1779             pixman_image_composite32 (PIXMAN_OP_CLEAR,
1780                                       r->src, NULL, r->u.composite.dst,
1781                                       spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
1782                                       0, 0,
1783                                       spans[0].x, y,
1784                                       r->composite->unbounded.x + r->composite->unbounded.width - spans[0].x, h);
1785     }
1786
1787     r->u.composite.mask_y = y + h;
1788     return CAIRO_STATUS_SUCCESS;
1789 }
1790
1791 static cairo_status_t
1792 _mono_finish_unbounded_spans (void *abstract_renderer)
1793 {
1794     cairo_image_span_renderer_t *r = abstract_renderer;
1795
1796     if (r->u.composite.mask_y < r->composite->unbounded.y + r->composite->unbounded.height) {
1797         pixman_image_composite32 (PIXMAN_OP_CLEAR,
1798                                   r->src, NULL, r->u.composite.dst,
1799                                   r->composite->unbounded.x + r->u.composite.src_x,  r->u.composite.mask_y + r->u.composite.src_y,
1800                                   0, 0,
1801                                   r->composite->unbounded.x, r->u.composite.mask_y,
1802                                   r->composite->unbounded.width,
1803                                   r->composite->unbounded.y + r->composite->unbounded.height - r->u.composite.mask_y);
1804     }
1805
1806     return CAIRO_STATUS_SUCCESS;
1807 }
1808
1809 static cairo_int_status_t
1810 mono_renderer_init (cairo_image_span_renderer_t *r,
1811                     const cairo_composite_rectangles_t *composite,
1812                     cairo_antialias_t                    antialias,
1813                     cairo_bool_t                         needs_clip)
1814 {
1815     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
1816
1817     if (antialias != CAIRO_ANTIALIAS_NONE)
1818         return CAIRO_INT_STATUS_UNSUPPORTED;
1819
1820     if (!_cairo_pattern_is_opaque_solid (&composite->mask_pattern.base))
1821         return CAIRO_INT_STATUS_UNSUPPORTED;
1822
1823     r->base.render_rows = NULL;
1824     if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
1825         const cairo_color_t *color;
1826
1827         color = &composite->source_pattern.solid.color;
1828         if (composite->op == CAIRO_OPERATOR_CLEAR)
1829             color = CAIRO_COLOR_TRANSPARENT;
1830
1831         if (fill_reduces_to_source (composite->op, color, dst) &&
1832             color_to_pixel (color, dst->pixman_format, &r->u.fill.pixel)) {
1833             /* Use plain C for the fill operations as the span length is
1834              * typically small, too small to payback the startup overheads of
1835              * using SSE2 etc.
1836              */
1837             switch (PIXMAN_FORMAT_BPP(dst->pixman_format)) {
1838             case 8: r->base.render_rows = _fill8_spans; break;
1839             case 16: r->base.render_rows = _fill16_spans; break;
1840             case 32: r->base.render_rows = _fill32_spans; break;
1841             default: break;
1842             }
1843             r->u.fill.data = dst->data;
1844             r->u.fill.stride = dst->stride;
1845         }
1846     } else if ((composite->op == CAIRO_OPERATOR_SOURCE ||
1847                 (composite->op == CAIRO_OPERATOR_OVER &&
1848                  (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) &&
1849                composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
1850                composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE &&
1851                to_image_surface(composite->source_pattern.surface.surface)->format == dst->format)
1852     {
1853        cairo_image_surface_t *src =
1854            to_image_surface(composite->source_pattern.surface.surface);
1855        int tx, ty;
1856
1857         if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix,
1858                                                  &tx, &ty) &&
1859             composite->bounded.x + tx >= 0 &&
1860             composite->bounded.y + ty >= 0 &&
1861             composite->bounded.x + composite->bounded.width +  tx <= src->width &&
1862             composite->bounded.y + composite->bounded.height + ty <= src->height) {
1863
1864             r->u.blit.stride = dst->stride;
1865             r->u.blit.data = dst->data;
1866             r->u.blit.src_stride = src->stride;
1867             r->u.blit.src_data = src->data + src->stride * ty + tx * 4;
1868             r->base.render_rows = _blit_spans;
1869         }
1870     }
1871
1872     if (r->base.render_rows == NULL) {
1873         r->src = _pixman_image_for_pattern (dst, &composite->source_pattern.base, FALSE,
1874                                             &composite->unbounded,
1875                                             &composite->source_sample_area,
1876                                             &r->u.composite.src_x, &r->u.composite.src_y);
1877         if (unlikely (r->src == NULL))
1878             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1879
1880         r->u.composite.dst = to_pixman_image (composite->surface);
1881         r->op = _pixman_operator (composite->op);
1882         if (composite->is_bounded == 0) {
1883             r->base.render_rows = _mono_unbounded_spans;
1884             r->base.finish = _mono_finish_unbounded_spans;
1885             r->u.composite.mask_y = composite->unbounded.y;
1886         } else
1887             r->base.render_rows = _mono_spans;
1888     }
1889     r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
1890
1891     return CAIRO_INT_STATUS_SUCCESS;
1892 }
1893
1894 #define ONE_HALF 0x7f
1895 #define RB_MASK 0x00ff00ff
1896 #define RB_ONE_HALF 0x007f007f
1897 #define RB_MASK_PLUS_ONE 0x01000100
1898 #define G_SHIFT 8
1899 static inline uint32_t
1900 mul8x2_8 (uint32_t a, uint8_t b)
1901 {
1902     uint32_t t = (a & RB_MASK) * b + RB_ONE_HALF;
1903     return ((t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT) & RB_MASK;
1904 }
1905
1906 static inline uint32_t
1907 add8x2_8x2 (uint32_t a, uint32_t b)
1908 {
1909     uint32_t t = a + b;
1910     t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK);
1911     return t & RB_MASK;
1912 }
1913
1914 static inline uint8_t
1915 mul8_8 (uint8_t a, uint8_t b)
1916 {
1917     uint16_t t = a * (uint16_t)b + ONE_HALF;
1918     return ((t >> G_SHIFT) + t) >> G_SHIFT;
1919 }
1920
1921 static inline uint32_t
1922 lerp8x4 (uint32_t src, uint8_t a, uint32_t dst)
1923 {
1924     uint8_t ia = ~a;
1925     uint32_t r1, r2;
1926
1927     r1 = add8x2_8x2 (mul8x2_8 (src, a),
1928                      mul8x2_8 (dst, ia));
1929     r2 = add8x2_8x2 (mul8x2_8 (src >> G_SHIFT, a),
1930                      mul8x2_8 (dst >> G_SHIFT, ia));
1931
1932     return r1 | (r2 << G_SHIFT);
1933 }
1934
1935 static cairo_status_t
1936 _fill_a8_lerp_opaque_spans (void *abstract_renderer, int y, int h,
1937                             const cairo_half_open_span_t *spans, unsigned num_spans)
1938 {
1939     cairo_image_span_renderer_t *r = abstract_renderer;
1940
1941     if (num_spans == 0)
1942         return CAIRO_STATUS_SUCCESS;
1943
1944     if (likely(h == 1)) {
1945         uint8_t *d = r->u.fill.data + r->u.fill.stride*y;
1946         do {
1947             uint8_t a = spans[0].coverage;
1948             if (a) {
1949                 int len = spans[1].x - spans[0].x;
1950                 if (a == 0xff) {
1951                     memset(d + spans[0].x, r->u.fill.pixel, len);
1952                 } else {
1953                     uint8_t s = mul8_8(a, r->u.fill.pixel);
1954                     uint8_t *dst = d + spans[0].x;
1955                     a = ~a;
1956                     while (len--) {
1957                         uint8_t t = mul8_8(*dst, a);
1958                         *dst++ = t + s;
1959                     }
1960                 }
1961             }
1962             spans++;
1963         } while (--num_spans > 1);
1964     } else {
1965         do {
1966             uint8_t a = spans[0].coverage;
1967             if (a) {
1968                 int yy = y, hh = h;
1969                 if (a == 0xff) {
1970                     do {
1971                         int len = spans[1].x - spans[0].x;
1972                         uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
1973                         memset(d, r->u.fill.pixel, len);
1974                         yy++;
1975                     } while (--hh);
1976                 } else {
1977                     uint8_t s = mul8_8(a, r->u.fill.pixel);
1978                     a = ~a;
1979                     do {
1980                         int len = spans[1].x - spans[0].x;
1981                         uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
1982                         while (len--) {
1983                             uint8_t t = mul8_8(*d, a);
1984                             *d++ = t + s;
1985                         }
1986                         yy++;
1987                     } while (--hh);
1988                 }
1989             }
1990             spans++;
1991         } while (--num_spans > 1);
1992     }
1993
1994     return CAIRO_STATUS_SUCCESS;
1995 }
1996
1997 static cairo_status_t
1998 _fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h,
1999                                 const cairo_half_open_span_t *spans, unsigned num_spans)
2000 {
2001     cairo_image_span_renderer_t *r = abstract_renderer;
2002
2003     if (num_spans == 0)
2004         return CAIRO_STATUS_SUCCESS;
2005
2006     if (likely(h == 1)) {
2007         do {
2008             uint8_t a = spans[0].coverage;
2009             if (a) {
2010                 int len = spans[1].x - spans[0].x;
2011                 uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
2012                 if (a == 0xff) {
2013                     if (len > 31) {
2014                         pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
2015                                      spans[0].x, y, len, 1, r->u.fill.pixel);
2016                     } else {
2017                         uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
2018                         while (len--)
2019                             *d++ = r->u.fill.pixel;
2020                     }
2021                 } else while (len--) {
2022                     *d = lerp8x4 (r->u.fill.pixel, a, *d);
2023                     d++;
2024                 }
2025             }
2026             spans++;
2027         } while (--num_spans > 1);
2028     } else {
2029         do {
2030             uint8_t a = spans[0].coverage;
2031             if (a) {
2032                 if (a == 0xff) {
2033                     if (spans[1].x - spans[0].x > 16) {
2034                         pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
2035                                      spans[0].x, y, spans[1].x - spans[0].x, h,
2036                                      r->u.fill.pixel);
2037                     } else {
2038                         int yy = y, hh = h;
2039                         do {
2040                             int len = spans[1].x - spans[0].x;
2041                             uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
2042                             while (len--)
2043                                 *d++ = r->u.fill.pixel;
2044                             yy++;
2045                         } while (--hh);
2046                     }
2047                 } else {
2048                     int yy = y, hh = h;
2049                     do {
2050                         int len = spans[1].x - spans[0].x;
2051                         uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
2052                         while (len--) {
2053                             *d = lerp8x4 (r->u.fill.pixel, a, *d);
2054                             d++;
2055                         }
2056                         yy++;
2057                     } while (--hh);
2058                 }
2059             }
2060             spans++;
2061         } while (--num_spans > 1);
2062     }
2063
2064     return CAIRO_STATUS_SUCCESS;
2065 }
2066
2067 static cairo_status_t
2068 _fill_a8_lerp_spans (void *abstract_renderer, int y, int h,
2069                      const cairo_half_open_span_t *spans, unsigned num_spans)
2070 {
2071     cairo_image_span_renderer_t *r = abstract_renderer;
2072
2073     if (num_spans == 0)
2074         return CAIRO_STATUS_SUCCESS;
2075
2076     if (likely(h == 1)) {
2077         do {
2078             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2079             if (a) {
2080                 int len = spans[1].x - spans[0].x;
2081                 uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
2082                 uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
2083                 uint16_t ia = ~a;
2084                 while (len--) {
2085                     uint16_t t = *d*ia + p;
2086                     *d++ = (t + (t>>8)) >> 8;
2087                 }
2088             }
2089             spans++;
2090         } while (--num_spans > 1);
2091     } else {
2092         do {
2093             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2094             if (a) {
2095                 int yy = y, hh = h;
2096                 uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
2097                 uint16_t ia = ~a;
2098                 do {
2099                     int len = spans[1].x - spans[0].x;
2100                     uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
2101                     while (len--) {
2102                         uint16_t t = *d*ia + p;
2103                         *d++ = (t + (t>>8)) >> 8;
2104                     }
2105                     yy++;
2106                 } while (--hh);
2107             }
2108             spans++;
2109         } while (--num_spans > 1);
2110     }
2111
2112     return CAIRO_STATUS_SUCCESS;
2113 }
2114
2115 static cairo_status_t
2116 _fill_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
2117                          const cairo_half_open_span_t *spans, unsigned num_spans)
2118 {
2119     cairo_image_span_renderer_t *r = abstract_renderer;
2120
2121     if (num_spans == 0)
2122         return CAIRO_STATUS_SUCCESS;
2123
2124     if (likely(h == 1)) {
2125         do {
2126             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2127             if (a) {
2128                 int len = spans[1].x - spans[0].x;
2129                 uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
2130                 while (len--) {
2131                     *d = lerp8x4 (r->u.fill.pixel, a, *d);
2132                     d++;
2133                 }
2134             }
2135             spans++;
2136         } while (--num_spans > 1);
2137     } else {
2138         do {
2139             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2140             if (a) {
2141                 int yy = y, hh = h;
2142                 do {
2143                     int len = spans[1].x - spans[0].x;
2144                     uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
2145                     while (len--) {
2146                         *d = lerp8x4 (r->u.fill.pixel, a, *d);
2147                         d++;
2148                     }
2149                     yy++;
2150                 } while (--hh);
2151             }
2152             spans++;
2153         } while (--num_spans > 1);
2154     }
2155
2156     return CAIRO_STATUS_SUCCESS;
2157 }
2158
2159 static cairo_status_t
2160 _blit_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
2161                          const cairo_half_open_span_t *spans, unsigned num_spans)
2162 {
2163     cairo_image_span_renderer_t *r = abstract_renderer;
2164
2165     if (num_spans == 0)
2166         return CAIRO_STATUS_SUCCESS;
2167
2168     if (likely(h == 1)) {
2169         uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
2170         uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
2171         do {
2172             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2173             if (a) {
2174                 uint32_t *s = (uint32_t*)src + spans[0].x;
2175                 uint32_t *d = (uint32_t*)dst + spans[0].x;
2176                 int len = spans[1].x - spans[0].x;
2177                 if (a == 0xff) {
2178                     if (len == 1)
2179                         *d = *s;
2180                     else
2181                         memcpy(d, s, len*4);
2182                 } else {
2183                     while (len--) {
2184                         *d = lerp8x4 (*s, a, *d);
2185                         s++, d++;
2186                     }
2187                 }
2188             }
2189             spans++;
2190         } while (--num_spans > 1);
2191     } else {
2192         do {
2193             uint8_t a = mul8_8 (spans[0].coverage, r->op);
2194             if (a) {
2195                 int yy = y, hh = h;
2196                 do {
2197                     uint32_t *s = (uint32_t *)(r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x * 4);
2198                     uint32_t *d = (uint32_t *)(r->u.blit.data + yy*r->u.blit.stride + spans[0].x * 4);
2199                     int len = spans[1].x - spans[0].x;
2200                     if (a == 0xff) {
2201                         if (len == 1)
2202                             *d = *s;
2203                         else
2204                             memcpy(d, s, len * 4);
2205                     } else {
2206                         while (len--) {
2207                             *d = lerp8x4 (*s, a, *d);
2208                             s++, d++;
2209                         }
2210                     }
2211                     yy++;
2212                 } while (--hh);
2213             }
2214             spans++;
2215         } while (--num_spans > 1);
2216     }
2217
2218     return CAIRO_STATUS_SUCCESS;
2219 }
2220
2221 static cairo_status_t
2222 _inplace_spans (void *abstract_renderer,
2223                 int y, int h,
2224                 const cairo_half_open_span_t *spans,
2225                 unsigned num_spans)
2226 {
2227     cairo_image_span_renderer_t *r = abstract_renderer;
2228     uint8_t *mask;
2229     int x0, x1;
2230
2231     if (num_spans == 0)
2232         return CAIRO_STATUS_SUCCESS;
2233
2234     if (num_spans == 2 && spans[0].coverage == 0xff) {
2235         pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst,
2236                                   spans[0].x + r->u.composite.src_x,
2237                                   y + r->u.composite.src_y,
2238                                   0, 0,
2239                                   spans[0].x, y,
2240                                   spans[1].x - spans[0].x, h);
2241         return CAIRO_STATUS_SUCCESS;
2242     }
2243
2244     mask = (uint8_t *)pixman_image_get_data (r->mask);
2245     x0 = spans[0].x;
2246     do {
2247         int len = spans[1].x - spans[0].x;
2248         *mask++ = spans[0].coverage;
2249         if (len > 1) {
2250             memset (mask, spans[0].coverage, --len);
2251             mask += len;
2252         }
2253         x1 = spans[1].x;
2254         spans++;
2255     } while (--num_spans > 1);
2256
2257     pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
2258                               x0 + r->u.composite.src_x,
2259                               y + r->u.composite.src_y,
2260                               0, 0,
2261                               x0, y,
2262                               x1 - x0, h);
2263
2264     return CAIRO_STATUS_SUCCESS;
2265 }
2266
2267 static cairo_status_t
2268 _inplace_src_spans (void *abstract_renderer,
2269                     int y, int h,
2270                     const cairo_half_open_span_t *spans,
2271                     unsigned num_spans)
2272 {
2273     cairo_image_span_renderer_t *r = abstract_renderer;
2274     uint8_t *m;
2275     int x0;
2276
2277     if (num_spans == 0)
2278         return CAIRO_STATUS_SUCCESS;
2279
2280     x0 = spans[0].x;
2281     m = r->buf;
2282     do {
2283         int len = spans[1].x - spans[0].x;
2284         if (spans[0].coverage == 0xff) {
2285             if (spans[0].x != x0) {
2286 #if PIXMAN_HAS_OP_LERP
2287                 pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
2288                                           r->src, r->mask, r->u.composite.dst,
2289                                           x0 + r->u.composite.src_x,
2290                                           y + r->u.composite.src_y,
2291                                           0, 0,
2292                                           x0, y,
2293                                           spans[0].x - x0, h);
2294 #else
2295                 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
2296                                           r->mask, NULL, r->u.composite.dst,
2297                                           0, 0,
2298                                           0, 0,
2299                                           x0, y,
2300                                           spans[0].x - x0, h);
2301                 pixman_image_composite32 (PIXMAN_OP_ADD,
2302                                           r->src, r->mask, r->u.composite.dst,
2303                                           x0 + r->u.composite.src_x,
2304                                           y + r->u.composite.src_y,
2305                                           0, 0,
2306                                           x0, y,
2307                                           spans[0].x - x0, h);
2308 #endif
2309             }
2310
2311             pixman_image_composite32 (PIXMAN_OP_SRC,
2312                                       r->src, NULL, r->u.composite.dst,
2313                                       spans[0].x + r->u.composite.src_x,
2314                                       y + r->u.composite.src_y,
2315                                       0, 0,
2316                                       spans[0].x, y,
2317                                       spans[1].x - spans[0].x, h);
2318
2319             m = r->buf;
2320             x0 = spans[1].x;
2321         } else if (spans[0].coverage == 0x0) {
2322             if (spans[0].x != x0) {
2323 #if PIXMAN_HAS_OP_LERP
2324                 pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
2325                                           r->src, r->mask, r->u.composite.dst,
2326                                           x0 + r->u.composite.src_x,
2327                                           y + r->u.composite.src_y,
2328                                           0, 0,
2329                                           x0, y,
2330                                           spans[0].x - x0, h);
2331 #else
2332                 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
2333                                           r->mask, NULL, r->u.composite.dst,
2334                                           0, 0,
2335                                           0, 0,
2336                                           x0, y,
2337                                           spans[0].x - x0, h);
2338                 pixman_image_composite32 (PIXMAN_OP_ADD,
2339                                           r->src, r->mask, r->u.composite.dst,
2340                                           x0 + r->u.composite.src_x,
2341                                           y + r->u.composite.src_y,
2342                                           0, 0,
2343                                           x0, y,
2344                                           spans[0].x - x0, h);
2345 #endif
2346             }
2347
2348             m = r->buf;
2349             x0 = spans[1].x;
2350         } else {
2351             *m++ = spans[0].coverage;
2352             if (len > 1) {
2353                 memset (m, spans[0].coverage, --len);
2354                 m += len;
2355             }
2356         }
2357         spans++;
2358     } while (--num_spans > 1);
2359
2360     if (spans[0].x != x0) {
2361 #if PIXMAN_HAS_OP_LERP
2362         pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
2363                                   r->src, r->mask, r->u.composite.dst,
2364                                   x0 + r->u.composite.src_x,
2365                                   y + r->u.composite.src_y,
2366                                   0, 0,
2367                                   x0, y,
2368                                   spans[0].x - x0, h);
2369 #else
2370         pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
2371                                   r->mask, NULL, r->u.composite.dst,
2372                                   0, 0,
2373                                   0, 0,
2374                                   x0, y,
2375                                   spans[0].x - x0, h);
2376         pixman_image_composite32 (PIXMAN_OP_ADD,
2377                                   r->src, r->mask, r->u.composite.dst,
2378                                   x0 + r->u.composite.src_x,
2379                                   y + r->u.composite.src_y,
2380                                   0, 0,
2381                                   x0, y,
2382                                   spans[0].x - x0, h);
2383 #endif
2384     }
2385
2386     return CAIRO_STATUS_SUCCESS;
2387 }
2388
2389 static cairo_int_status_t
2390 inplace_renderer_init (cairo_image_span_renderer_t      *r,
2391                        const cairo_composite_rectangles_t *composite,
2392                        cairo_antialias_t                 antialias,
2393                        cairo_bool_t                      needs_clip)
2394 {
2395     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
2396
2397     if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
2398         return CAIRO_INT_STATUS_UNSUPPORTED;
2399
2400     r->base.render_rows = NULL;
2401     r->op = composite->mask_pattern.solid.color.alpha_short >> 8;
2402
2403     if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
2404         const cairo_color_t *color;
2405
2406         color = &composite->source_pattern.solid.color;
2407         if (composite->op == CAIRO_OPERATOR_CLEAR)
2408             color = CAIRO_COLOR_TRANSPARENT;
2409
2410         if (fill_reduces_to_source (composite->op, color, dst) &&
2411             color_to_pixel (color, dst->pixman_format, &r->u.fill.pixel)) {
2412             /* Use plain C for the fill operations as the span length is
2413              * typically small, too small to payback the startup overheads of
2414              * using SSE2 etc.
2415              */
2416             if (r->op == 0xff) {
2417                 switch (dst->format) {
2418                 case CAIRO_FORMAT_A8:
2419                     r->base.render_rows = _fill_a8_lerp_opaque_spans;
2420                     break;
2421                 case CAIRO_FORMAT_RGB24:
2422                 case CAIRO_FORMAT_ARGB32:
2423                     r->base.render_rows = _fill_xrgb32_lerp_opaque_spans;
2424                     break;
2425                 case CAIRO_FORMAT_A1:
2426                 case CAIRO_FORMAT_RGB16_565:
2427                 case CAIRO_FORMAT_RGB30:
2428                 case CAIRO_FORMAT_INVALID:
2429                 default: break;
2430                 }
2431             } else {
2432                 switch (dst->format) {
2433                 case CAIRO_FORMAT_A8:
2434                     r->base.render_rows = _fill_a8_lerp_spans;
2435                     break;
2436                 case CAIRO_FORMAT_RGB24:
2437                 case CAIRO_FORMAT_ARGB32:
2438                     r->base.render_rows = _fill_xrgb32_lerp_spans;
2439                     break;
2440                 case CAIRO_FORMAT_A1:
2441                 case CAIRO_FORMAT_RGB16_565:
2442                 case CAIRO_FORMAT_RGB30:
2443                 case CAIRO_FORMAT_INVALID:
2444                 default: break;
2445                 }
2446             }
2447             r->u.fill.data = dst->data;
2448             r->u.fill.stride = dst->stride;
2449         }
2450     } else if ((dst->format == CAIRO_FORMAT_ARGB32 || dst->format == CAIRO_FORMAT_RGB24) &&
2451                (composite->op == CAIRO_OPERATOR_SOURCE ||
2452                 (composite->op == CAIRO_OPERATOR_OVER &&
2453                  (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) &&
2454                composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
2455                composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE &&
2456                to_image_surface(composite->source_pattern.surface.surface)->format == dst->format)
2457     {
2458        cairo_image_surface_t *src =
2459            to_image_surface(composite->source_pattern.surface.surface);
2460        int tx, ty;
2461
2462         if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix,
2463                                                  &tx, &ty) &&
2464             composite->bounded.x + tx >= 0 &&
2465             composite->bounded.y + ty >= 0 &&
2466             composite->bounded.x + composite->bounded.width + tx <= src->width &&
2467             composite->bounded.y + composite->bounded.height + ty <= src->height) {
2468
2469             assert(PIXMAN_FORMAT_BPP(dst->pixman_format) == 32);
2470             r->u.blit.stride = dst->stride;
2471             r->u.blit.data = dst->data;
2472             r->u.blit.src_stride = src->stride;
2473             r->u.blit.src_data = src->data + src->stride * ty + tx * 4;
2474             r->base.render_rows = _blit_xrgb32_lerp_spans;
2475         }
2476     }
2477     if (r->base.render_rows == NULL) {
2478         unsigned int width;
2479         const cairo_pattern_t *src = &composite->source_pattern.base;
2480
2481         if (r->op != 0xff)
2482             return CAIRO_INT_STATUS_UNSUPPORTED;
2483
2484         if (composite->is_bounded == 0)
2485             return CAIRO_INT_STATUS_UNSUPPORTED;
2486
2487         width = (composite->bounded.width + 3) & ~3;
2488         r->base.render_rows = _inplace_spans;
2489         if (dst->base.is_clear &&
2490             (composite->op == CAIRO_OPERATOR_SOURCE ||
2491              composite->op == CAIRO_OPERATOR_OVER ||
2492              composite->op == CAIRO_OPERATOR_ADD)) {
2493             r->op = PIXMAN_OP_SRC;
2494         } else if (composite->op == CAIRO_OPERATOR_SOURCE) {
2495             r->base.render_rows = _inplace_src_spans;
2496             r->u.composite.mask_y = r->composite->unbounded.y;
2497             width = (composite->unbounded.width + 3) & ~3;
2498         } else if (composite->op == CAIRO_OPERATOR_CLEAR) {
2499             r->op = PIXMAN_OP_OUT_REVERSE;
2500             src = NULL;
2501         } else {
2502             r->op = _pixman_operator (composite->op);
2503         }
2504
2505         if (width > sizeof (r->buf))
2506             return CAIRO_INT_STATUS_UNSUPPORTED;
2507
2508         r->src = _pixman_image_for_pattern (dst, src, FALSE,
2509                                             &composite->bounded,
2510                                             &composite->source_sample_area,
2511                                             &r->u.composite.src_x, &r->u.composite.src_y);
2512         if (unlikely (r->src == NULL))
2513             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2514
2515         /* Create an effectively unbounded mask by repeating the single line */
2516         r->mask = pixman_image_create_bits (PIXMAN_a8,
2517                                             width, composite->unbounded.height,
2518                                             (uint32_t *)r->buf, 0);
2519         if (unlikely (r->mask == NULL)) {
2520             pixman_image_unref (r->src);
2521             return _cairo_error(CAIRO_STATUS_NO_MEMORY);
2522         }
2523
2524         r->u.composite.dst = dst->pixman_image;
2525     }
2526
2527     r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
2528
2529     return CAIRO_INT_STATUS_SUCCESS;
2530 }
2531
2532 static cairo_int_status_t
2533 span_renderer_init (cairo_abstract_span_renderer_t      *_r,
2534                     const cairo_composite_rectangles_t *composite,
2535                     cairo_antialias_t                    antialias,
2536                     cairo_bool_t                         needs_clip)
2537 {
2538     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
2539     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
2540     const cairo_pattern_t *source = &composite->source_pattern.base;
2541     cairo_operator_t op = composite->op;
2542     cairo_int_status_t status;
2543
2544     TRACE ((stderr, "%s\n", __FUNCTION__));
2545
2546     if (needs_clip)
2547         return CAIRO_INT_STATUS_UNSUPPORTED;
2548
2549     r->composite = composite;
2550     r->mask = NULL;
2551     r->src = NULL;
2552     r->base.finish = NULL;
2553
2554     status = mono_renderer_init (r, composite, antialias, needs_clip);
2555     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2556         return status;
2557
2558     status = inplace_renderer_init (r, composite, antialias, needs_clip);
2559     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2560         return status;
2561
2562     r->bpp = 0;
2563
2564     if (op == CAIRO_OPERATOR_CLEAR) {
2565 #if PIXMAN_HAS_OP_LERP
2566         op = PIXMAN_OP_LERP_CLEAR;
2567 #else
2568         source = &_cairo_pattern_white.base;
2569         op = PIXMAN_OP_OUT_REVERSE;
2570 #endif
2571     } else if (dst->base.is_clear &&
2572                (op == CAIRO_OPERATOR_SOURCE ||
2573                 op == CAIRO_OPERATOR_OVER ||
2574                 op == CAIRO_OPERATOR_ADD)) {
2575         op = PIXMAN_OP_SRC;
2576     } else if (op == CAIRO_OPERATOR_SOURCE) {
2577 #if PIXMAN_HAS_OP_LERP
2578         op = PIXMAN_OP_LERP_SRC;
2579 #else
2580         return CAIRO_INT_STATUS_UNSUPPORTED;
2581 #endif
2582     } else {
2583         op = _pixman_operator (op);
2584     }
2585     r->op = op;
2586
2587     r->src = _pixman_image_for_pattern (dst, source, FALSE,
2588                                         &composite->unbounded,
2589                                         &composite->source_sample_area,
2590                                         &r->u.mask.src_x, &r->u.mask.src_y);
2591     if (unlikely (r->src == NULL))
2592         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2593
2594     r->opacity = 1.0;
2595     if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
2596         r->opacity = composite->mask_pattern.solid.color.alpha;
2597     } else {
2598         pixman_image_t *mask;
2599         int mask_x, mask_y;
2600
2601         mask = _pixman_image_for_pattern (dst,
2602                                           &composite->mask_pattern.base,
2603                                           TRUE,
2604                                           &composite->unbounded,
2605                                           &composite->mask_sample_area,
2606                                           &mask_x, &mask_y);
2607         if (unlikely (mask == NULL))
2608             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2609
2610         /* XXX Component-alpha? */
2611         if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
2612             _cairo_pattern_is_opaque (source, &composite->source_sample_area))
2613         {
2614             pixman_image_unref (r->src);
2615             r->src = mask;
2616             r->u.mask.src_x = mask_x;
2617             r->u.mask.src_y = mask_y;
2618             mask = NULL;
2619         }
2620
2621         if (mask) {
2622             pixman_image_unref (mask);
2623             return CAIRO_INT_STATUS_UNSUPPORTED;
2624         }
2625     }
2626
2627     r->u.mask.extents = composite->unbounded;
2628     r->u.mask.stride = (r->u.mask.extents.width + 3) & ~3;
2629     if (r->u.mask.extents.height * r->u.mask.stride > (int)sizeof (r->buf)) {
2630         r->mask = pixman_image_create_bits (PIXMAN_a8,
2631                                             r->u.mask.extents.width,
2632                                             r->u.mask.extents.height,
2633                                             NULL, 0);
2634
2635         r->base.render_rows = _cairo_image_spans;
2636         r->base.finish = NULL;
2637     } else {
2638         r->mask = pixman_image_create_bits (PIXMAN_a8,
2639                                             r->u.mask.extents.width,
2640                                             r->u.mask.extents.height,
2641                                             (uint32_t *)r->buf, r->u.mask.stride);
2642
2643         r->base.render_rows = _cairo_image_spans_and_zero;
2644         r->base.finish = _cairo_image_finish_spans_and_zero;
2645     }
2646     if (unlikely (r->mask == NULL))
2647         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2648
2649     r->u.mask.data = (uint8_t *) pixman_image_get_data (r->mask);
2650     r->u.mask.stride = pixman_image_get_stride (r->mask);
2651
2652     r->u.mask.extents.height += r->u.mask.extents.y;
2653     return CAIRO_STATUS_SUCCESS;
2654 }
2655
2656 static void
2657 span_renderer_fini (cairo_abstract_span_renderer_t *_r,
2658                     cairo_int_status_t status)
2659 {
2660     cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
2661
2662     TRACE ((stderr, "%s\n", __FUNCTION__));
2663
2664     if (likely (status == CAIRO_INT_STATUS_SUCCESS && r->bpp == 0)) {
2665         const cairo_composite_rectangles_t *composite = r->composite;
2666
2667         if (r->base.finish)
2668             r->base.finish (r);
2669
2670         pixman_image_composite32 (r->op, r->src, r->mask,
2671                                   to_pixman_image (composite->surface),
2672                                   composite->unbounded.x + r->u.mask.src_x,
2673                                   composite->unbounded.y + r->u.mask.src_y,
2674                                   0, 0,
2675                                   composite->unbounded.x,
2676                                   composite->unbounded.y,
2677                                   composite->unbounded.width,
2678                                   composite->unbounded.height);
2679     }
2680
2681     if (r->src)
2682         pixman_image_unref (r->src);
2683     if (r->mask)
2684         pixman_image_unref (r->mask);
2685 }
2686 #endif
2687
2688 const cairo_compositor_t *
2689 _cairo_image_spans_compositor_get (void)
2690 {
2691     static cairo_spans_compositor_t spans;
2692     static cairo_compositor_t shape;
2693
2694     if (spans.base.delegate == NULL) {
2695         _cairo_shape_mask_compositor_init (&shape,
2696                                            _cairo_image_traps_compositor_get());
2697         shape.glyphs = NULL;
2698
2699         _cairo_spans_compositor_init (&spans, &shape);
2700
2701         spans.flags = 0;
2702 #if PIXMAN_HAS_OP_LERP
2703         spans.flags |= CAIRO_SPANS_COMPOSITOR_HAS_LERP;
2704 #endif
2705
2706         //spans.acquire = acquire;
2707         //spans.release = release;
2708         spans.fill_boxes = fill_boxes;
2709         spans.draw_image_boxes = draw_image_boxes;
2710         //spans.copy_boxes = copy_boxes;
2711         spans.pattern_to_surface = _cairo_image_source_create_for_pattern;
2712         //spans.check_composite_boxes = check_composite_boxes;
2713         spans.composite_boxes = composite_boxes;
2714         //spans.check_span_renderer = check_span_renderer;
2715         spans.renderer_init = span_renderer_init;
2716         spans.renderer_fini = span_renderer_fini;
2717     }
2718
2719     return &spans.base;
2720 }