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