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