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
#include "cairo-pixman-private.h"
56

            
57
static pixman_image_t *
58
144917
to_pixman_image (cairo_surface_t *s)
59
{
60
144917
    return ((cairo_image_surface_t *)s)->pixman_image;
61
}
62

            
63
static cairo_int_status_t
64
70113
acquire (void *abstract_dst)
65
{
66
70113
    return CAIRO_STATUS_SUCCESS;
67
}
68

            
69
static cairo_int_status_t
70
70113
release (void *abstract_dst)
71
{
72
70113
    return CAIRO_STATUS_SUCCESS;
73
}
74

            
75
static cairo_int_status_t
76
69312
set_clip_region (void *_surface,
77
		 cairo_region_t *region)
78
{
79
69312
    cairo_image_surface_t *surface = _surface;
80
69312
    pixman_region32_t *rgn = region ? &region->rgn : NULL;
81

            
82
69312
    if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn))
83
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
84

            
85
69312
    return CAIRO_STATUS_SUCCESS;
86
}
87

            
88
static cairo_int_status_t
89
3437
draw_image_boxes (void *_dst,
90
		  cairo_image_surface_t *image,
91
		  cairo_boxes_t *boxes,
92
		  int dx, int dy)
93
{
94
3437
    cairo_image_surface_t *dst = _dst;
95
    struct _cairo_boxes_chunk *chunk;
96
    int i;
97

            
98
    TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes));
99

            
100
6874
    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
101
8001
	for (i = 0; i < chunk->count; i++) {
102
4564
	    cairo_box_t *b = &chunk->base[i];
103
4564
	    int x = _cairo_fixed_integer_part (b->p1.x);
104
4564
	    int y = _cairo_fixed_integer_part (b->p1.y);
105
4564
	    int w = _cairo_fixed_integer_part (b->p2.x) - x;
106
4564
	    int h = _cairo_fixed_integer_part (b->p2.y) - y;
107
6228
	    if (dst->pixman_format != image->pixman_format ||
108
1664
		! pixman_blt ((uint32_t *)image->data, (uint32_t *)dst->data,
109
1664
			      image->stride / sizeof (uint32_t),
110
1664
			      dst->stride / sizeof (uint32_t),
111
1664
			      PIXMAN_FORMAT_BPP (image->pixman_format),
112
1664
			      PIXMAN_FORMAT_BPP (dst->pixman_format),
113
			      x + dx, y + dy,
114
			      x, y,
115
			      w, h))
116
	    {
117
2900
		pixman_image_composite32 (PIXMAN_OP_SRC,
118
					  image->pixman_image, NULL, dst->pixman_image,
119
					  x + dx, y + dy,
120
					  0, 0,
121
					  x, y,
122
					  w, h);
123
	    }
124
	}
125
    }
126
3437
    return CAIRO_STATUS_SUCCESS;
127
}
128

            
129
static inline uint32_t
130
581876
color_to_uint32 (const cairo_color_t *color)
131
{
132
    return
133
581876
        ((uint32_t)color->alpha_short >> 8 << 24) |
134
581876
        (color->red_short >> 8 << 16)   |
135
1163752
        (color->green_short & 0xff00)   |
136
581876
        (color->blue_short >> 8);
137
}
138

            
139
static inline cairo_bool_t
140
598302
color_to_pixel (const cairo_color_t	*color,
141
                pixman_format_code_t	 format,
142
                uint32_t		*pixel)
143
{
144
    uint32_t c;
145

            
146
632236
    if (!(format == PIXMAN_a8r8g8b8     ||
147
207946
          format == PIXMAN_x8r8g8b8     ||
148
207946
          format == PIXMAN_a8b8g8r8     ||
149
207946
          format == PIXMAN_x8b8g8r8     ||
150
207946
          format == PIXMAN_b8g8r8a8     ||
151
207946
          format == PIXMAN_b8g8r8x8     ||
152
33934
          format == PIXMAN_r5g6b5       ||
153
          format == PIXMAN_b5g6r5       ||
154
          format == PIXMAN_a8))
155
    {
156
16426
	return FALSE;
157
    }
158

            
159
581876
    c = color_to_uint32 (color);
160

            
161
581876
    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
162
	c = ((c & 0xff000000) >>  0) |
163
	    ((c & 0x00ff0000) >> 16) |
164
	    ((c & 0x0000ff00) >>  0) |
165
	    ((c & 0x000000ff) << 16);
166
    }
167

            
168
581876
    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
169
	c = ((c & 0xff000000) >> 24) |
170
	    ((c & 0x00ff0000) >>  8) |
171
	    ((c & 0x0000ff00) <<  8) |
172
	    ((c & 0x000000ff) << 24);
173
    }
174

            
175
581876
    if (format == PIXMAN_a8) {
176
17508
	c = c >> 24;
177
564368
    } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
178
174012
	c = ((((c) >> 3) & 0x001f) |
179
174012
	     (((c) >> 5) & 0x07e0) |
180
174012
	     (((c) >> 8) & 0xf800));
181
    }
182

            
183
581876
    *pixel = c;
184
581876
    return TRUE;
185
}
186

            
187
static pixman_op_t
188
360862
_pixman_operator (cairo_operator_t op)
189
{
190
360862
    switch ((int) op) {
191
    case CAIRO_OPERATOR_CLEAR:
192
	return PIXMAN_OP_CLEAR;
193

            
194
11803
    case CAIRO_OPERATOR_SOURCE:
195
11803
	return PIXMAN_OP_SRC;
196
241980
    case CAIRO_OPERATOR_OVER:
197
241980
	return PIXMAN_OP_OVER;
198
360
    case CAIRO_OPERATOR_IN:
199
360
	return PIXMAN_OP_IN;
200
48
    case CAIRO_OPERATOR_OUT:
201
48
	return PIXMAN_OP_OUT;
202
36
    case CAIRO_OPERATOR_ATOP:
203
36
	return PIXMAN_OP_ATOP;
204

            
205
    case CAIRO_OPERATOR_DEST:
206
	return PIXMAN_OP_DST;
207
39
    case CAIRO_OPERATOR_DEST_OVER:
208
39
	return PIXMAN_OP_OVER_REVERSE;
209
48
    case CAIRO_OPERATOR_DEST_IN:
210
48
	return PIXMAN_OP_IN_REVERSE;
211
726
    case CAIRO_OPERATOR_DEST_OUT:
212
726
	return PIXMAN_OP_OUT_REVERSE;
213
75
    case CAIRO_OPERATOR_DEST_ATOP:
214
75
	return PIXMAN_OP_ATOP_REVERSE;
215

            
216
49
    case CAIRO_OPERATOR_XOR:
217
49
	return PIXMAN_OP_XOR;
218
103926
    case CAIRO_OPERATOR_ADD:
219
103926
	return PIXMAN_OP_ADD;
220
48
    case CAIRO_OPERATOR_SATURATE:
221
48
	return PIXMAN_OP_SATURATE;
222

            
223
123
    case CAIRO_OPERATOR_MULTIPLY:
224
123
	return PIXMAN_OP_MULTIPLY;
225
114
    case CAIRO_OPERATOR_SCREEN:
226
114
	return PIXMAN_OP_SCREEN;
227
114
    case CAIRO_OPERATOR_OVERLAY:
228
114
	return PIXMAN_OP_OVERLAY;
229
114
    case CAIRO_OPERATOR_DARKEN:
230
114
	return PIXMAN_OP_DARKEN;
231
114
    case CAIRO_OPERATOR_LIGHTEN:
232
114
	return PIXMAN_OP_LIGHTEN;
233
114
    case CAIRO_OPERATOR_COLOR_DODGE:
234
114
	return PIXMAN_OP_COLOR_DODGE;
235
114
    case CAIRO_OPERATOR_COLOR_BURN:
236
114
	return PIXMAN_OP_COLOR_BURN;
237
114
    case CAIRO_OPERATOR_HARD_LIGHT:
238
114
	return PIXMAN_OP_HARD_LIGHT;
239
114
    case CAIRO_OPERATOR_SOFT_LIGHT:
240
114
	return PIXMAN_OP_SOFT_LIGHT;
241
119
    case CAIRO_OPERATOR_DIFFERENCE:
242
119
	return PIXMAN_OP_DIFFERENCE;
243
114
    case CAIRO_OPERATOR_EXCLUSION:
244
114
	return PIXMAN_OP_EXCLUSION;
245
114
    case CAIRO_OPERATOR_HSL_HUE:
246
114
	return PIXMAN_OP_HSL_HUE;
247
114
    case CAIRO_OPERATOR_HSL_SATURATION:
248
114
	return PIXMAN_OP_HSL_SATURATION;
249
114
    case CAIRO_OPERATOR_HSL_COLOR:
250
114
	return PIXMAN_OP_HSL_COLOR;
251
114
    case CAIRO_OPERATOR_HSL_LUMINOSITY:
252
114
	return PIXMAN_OP_HSL_LUMINOSITY;
253

            
254
    default:
255
	ASSERT_NOT_REACHED;
256
	return PIXMAN_OP_OVER;
257
    }
258
}
259

            
260
static cairo_bool_t
261
808521
__fill_reduces_to_source (cairo_operator_t op,
262
			  const cairo_color_t *color,
263
			  const cairo_image_surface_t *dst)
264
{
265
808521
    if (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR)
266
556507
	return TRUE;
267
252014
    if (op == CAIRO_OPERATOR_OVER && CAIRO_COLOR_IS_OPAQUE (color))
268
41690
	return TRUE;
269
210324
    if (dst->base.is_clear)
270
118
	return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD;
271

            
272
210206
    return FALSE;
273
}
274

            
275
static cairo_bool_t
276
808521
fill_reduces_to_source (cairo_operator_t op,
277
			const cairo_color_t *color,
278
			const cairo_image_surface_t *dst,
279
			uint32_t *pixel)
280
{
281
808521
    if (__fill_reduces_to_source (op, color, dst)) {
282
598302
	return color_to_pixel (color, dst->pixman_format, pixel);
283
    }
284

            
285
210219
    return FALSE;
286
}
287

            
288
static cairo_int_status_t
289
fill_rectangles (void			*_dst,
290
		 cairo_operator_t	 op,
291
		 const cairo_color_t	*color,
292
		 cairo_rectangle_int_t	*rects,
293
		 int			 num_rects)
294
{
295
    cairo_image_surface_t *dst = _dst;
296
    uint32_t pixel;
297
    int i;
298

            
299
    TRACE ((stderr, "%s\n", __FUNCTION__));
300

            
301
    if (fill_reduces_to_source (op, color, dst, &pixel)) {
302
	for (i = 0; i < num_rects; i++) {
303
	    pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
304
			 PIXMAN_FORMAT_BPP (dst->pixman_format),
305
			 rects[i].x, rects[i].y,
306
			 rects[i].width, rects[i].height,
307
			 pixel);
308
	}
309
    } else {
310
	pixman_image_t *src = _pixman_image_for_color (color);
311
	if (unlikely (src == NULL))
312
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
313

            
314
	op = _pixman_operator (op);
315
	for (i = 0; i < num_rects; i++) {
316
	    pixman_image_composite32 (op,
317
				      src, NULL, dst->pixman_image,
318
				      0, 0,
319
				      0, 0,
320
				      rects[i].x, rects[i].y,
321
				      rects[i].width, rects[i].height);
322
	}
323

            
324
	pixman_image_unref (src);
325
    }
326

            
327
    return CAIRO_STATUS_SUCCESS;
328
}
329

            
330
static cairo_int_status_t
331
628324
fill_boxes (void		*_dst,
332
	    cairo_operator_t	 op,
333
	    const cairo_color_t	*color,
334
	    cairo_boxes_t	*boxes)
335
{
336
628324
    cairo_image_surface_t *dst = _dst;
337
    struct _cairo_boxes_chunk *chunk;
338
    uint32_t pixel;
339
    int i;
340

            
341
    TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes));
342

            
343
628324
    if (fill_reduces_to_source (op, color, dst, &pixel)) {
344
1090860
	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
345
1125621
	    for (i = 0; i < chunk->count; i++) {
346
580143
		int x = _cairo_fixed_integer_part (chunk->base[i].p1.x);
347
580143
		int y = _cairo_fixed_integer_part (chunk->base[i].p1.y);
348
580143
		int w = _cairo_fixed_integer_part (chunk->base[i].p2.x) - x;
349
580143
		int h = _cairo_fixed_integer_part (chunk->base[i].p2.y) - y;
350
580143
		pixman_fill ((uint32_t *) dst->data,
351
580143
			     dst->stride / sizeof (uint32_t),
352
580143
			     PIXMAN_FORMAT_BPP (dst->pixman_format),
353
			     x, y, w, h, pixel);
354
	    }
355
	}
356
    }
357
    else
358
    {
359
82942
	pixman_image_t *src = _pixman_image_for_color (color);
360
82942
	if (unlikely (src == NULL))
361
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
362

            
363
82942
	op = _pixman_operator (op);
364
165884
	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
365
170177
	    for (i = 0; i < chunk->count; i++) {
366
87235
		int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
367
87235
		int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
368
87235
		int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
369
87235
		int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
370
87235
		pixman_image_composite32 (op,
371
					  src, NULL, dst->pixman_image,
372
					  0, 0,
373
					  0, 0,
374
					  x1, y1,
375
					  x2-x1, y2-y1);
376
	    }
377
	}
378

            
379
82942
	pixman_image_unref (src);
380
    }
381

            
382
628324
    return CAIRO_STATUS_SUCCESS;
383
}
384

            
385
static cairo_int_status_t
386
1341
composite (void			*_dst,
387
	   cairo_operator_t	op,
388
	   cairo_surface_t	*abstract_src,
389
	   cairo_surface_t	*abstract_mask,
390
	   int			src_x,
391
	   int			src_y,
392
	   int			mask_x,
393
	   int			mask_y,
394
	   int			dst_x,
395
	   int			dst_y,
396
	   unsigned int		width,
397
	   unsigned int		height)
398
{
399
1341
    cairo_image_source_t *src = (cairo_image_source_t *)abstract_src;
400
1341
    cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
401

            
402
    TRACE ((stderr, "%s\n", __FUNCTION__));
403

            
404
1341
    if (mask) {
405
42
	pixman_image_composite32 (_pixman_operator (op),
406
				  src->pixman_image, mask->pixman_image, to_pixman_image (_dst),
407
				  src_x, src_y,
408
				  mask_x, mask_y,
409
				  dst_x, dst_y,
410
				  width, height);
411
    } else {
412
1299
	pixman_image_composite32 (_pixman_operator (op),
413
				  src->pixman_image, NULL, to_pixman_image (_dst),
414
				  src_x, src_y,
415
				  0, 0,
416
				  dst_x, dst_y,
417
				  width, height);
418
    }
419

            
420
1341
    return CAIRO_STATUS_SUCCESS;
421
}
422

            
423
static cairo_int_status_t
424
534
lerp (void			*_dst,
425
      cairo_surface_t		*abstract_src,
426
      cairo_surface_t		*abstract_mask,
427
      int			src_x,
428
      int			src_y,
429
      int			mask_x,
430
      int			mask_y,
431
      int			dst_x,
432
      int			dst_y,
433
      unsigned int		width,
434
      unsigned int		height)
435
{
436
534
    cairo_image_surface_t *dst = _dst;
437
534
    cairo_image_source_t *src = (cairo_image_source_t *)abstract_src;
438
534
    cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
439

            
440
    TRACE ((stderr, "%s\n", __FUNCTION__));
441

            
442
#if PIXMAN_HAS_OP_LERP
443
    pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
444
			      src->pixman_image, mask->pixman_image, dst->pixman_image,
445
			      src_x,  src_y,
446
			      mask_x, mask_y,
447
			      dst_x,  dst_y,
448
			      width,  height);
449
#else
450
    /* Punch the clip out of the destination */
451
    TRACE ((stderr, "%s - OUT_REVERSE (mask=%d/%p, dst=%d/%p)\n",
452
	    __FUNCTION__,
453
	    mask->base.unique_id, mask->pixman_image,
454
	    dst->base.unique_id, dst->pixman_image));
455
534
    pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
456
			      mask->pixman_image, NULL, dst->pixman_image,
457
			      mask_x, mask_y,
458
			      0,      0,
459
			      dst_x,  dst_y,
460
			      width,  height);
461

            
462
    /* Now add the two results together */
463
    TRACE ((stderr, "%s - ADD (src=%d/%p, mask=%d/%p, dst=%d/%p)\n",
464
	    __FUNCTION__,
465
	    src->base.unique_id, src->pixman_image,
466
	    mask->base.unique_id, mask->pixman_image,
467
	    dst->base.unique_id, dst->pixman_image));
468
534
    pixman_image_composite32 (PIXMAN_OP_ADD,
469
			      src->pixman_image, mask->pixman_image, dst->pixman_image,
470
			      src_x,  src_y,
471
			      mask_x, mask_y,
472
			      dst_x,  dst_y,
473
			      width,  height);
474
#endif
475

            
476
534
    return CAIRO_STATUS_SUCCESS;
477
}
478

            
479
static cairo_int_status_t
480
74885
composite_boxes (void			*_dst,
481
		 cairo_operator_t	op,
482
		 cairo_surface_t	*abstract_src,
483
		 cairo_surface_t	*abstract_mask,
484
		 int			src_x,
485
		 int			src_y,
486
		 int			mask_x,
487
		 int			mask_y,
488
		 int			dst_x,
489
		 int			dst_y,
490
		 cairo_boxes_t		*boxes,
491
		 const cairo_rectangle_int_t  *extents)
492
{
493
74885
    pixman_image_t *dst = to_pixman_image (_dst);
494
74885
    pixman_image_t *src = ((cairo_image_source_t *)abstract_src)->pixman_image;
495
74885
    pixman_image_t *mask = abstract_mask ? ((cairo_image_source_t *)abstract_mask)->pixman_image : NULL;
496
74885
    pixman_image_t *free_src = NULL;
497
    struct _cairo_boxes_chunk *chunk;
498
    int i;
499

            
500
    /* XXX consider using a region? saves multiple prepare-composite */
501
    TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes));
502

            
503
74885
    if (((cairo_surface_t *)_dst)->is_clear &&
504
18109
	(op == CAIRO_OPERATOR_SOURCE ||
505
48
	 op == CAIRO_OPERATOR_OVER ||
506
	 op == CAIRO_OPERATOR_ADD)) {
507
18247
	op = PIXMAN_OP_SRC;
508
56638
    } else if (mask) {
509
2508
	if (op == CAIRO_OPERATOR_CLEAR) {
510
#if PIXMAN_HAS_OP_LERP
511
	    op = PIXMAN_OP_LERP_CLEAR;
512
#else
513
12
	    free_src = src = _pixman_image_for_color (CAIRO_COLOR_WHITE);
514
12
	    if (unlikely (src == NULL))
515
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
516
12
	    op = PIXMAN_OP_OUT_REVERSE;
517
#endif
518
2496
	} else if (op == CAIRO_OPERATOR_SOURCE) {
519
#if PIXMAN_HAS_OP_LERP
520
	    op = PIXMAN_OP_LERP_SRC;
521
#else
522
	    return CAIRO_INT_STATUS_UNSUPPORTED;
523
#endif
524
	} else {
525
2496
	    op = _pixman_operator (op);
526
	}
527
    } else {
528
54130
	op = _pixman_operator (op);
529
    }
530

            
531
149770
    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
532
149921
	for (i = 0; i < chunk->count; i++) {
533
75036
	    int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
534
75036
	    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
535
75036
	    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
536
75036
	    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
537

            
538
75036
	    pixman_image_composite32 (op, src, mask, dst,
539
				      x1 + src_x, y1 + src_y,
540
				      x1 + mask_x, y1 + mask_y,
541
				      x1 + dst_x, y1 + dst_y,
542
				      x2 - x1, y2 - y1);
543
	}
544
    }
545

            
546
74885
    if (free_src)
547
12
	pixman_image_unref (free_src);
548

            
549
74885
    return CAIRO_STATUS_SUCCESS;
550
}
551

            
552
#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
553
#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
554

            
555
static cairo_bool_t
556
13908
line_exceeds_16_16 (const cairo_line_t *line)
557
{
558
    return
559
27816
	line->p1.x <= CAIRO_FIXED_16_16_MIN ||
560
27816
	line->p1.x >= CAIRO_FIXED_16_16_MAX ||
561

            
562
27816
	line->p2.x <= CAIRO_FIXED_16_16_MIN ||
563
27816
	line->p2.x >= CAIRO_FIXED_16_16_MAX ||
564

            
565
27816
	line->p1.y <= CAIRO_FIXED_16_16_MIN ||
566
27816
	line->p1.y >= CAIRO_FIXED_16_16_MAX ||
567

            
568
41724
	line->p2.y <= CAIRO_FIXED_16_16_MIN ||
569
13908
	line->p2.y >= CAIRO_FIXED_16_16_MAX;
570
}
571

            
572
static void
573
project_line_x_onto_16_16 (const cairo_line_t *line,
574
			   cairo_fixed_t top,
575
			   cairo_fixed_t bottom,
576
			   pixman_line_fixed_t *out)
577
{
578
    /* XXX use fixed-point arithmetic? */
579
    cairo_point_double_t p1, p2;
580
    double m;
581

            
582
    p1.x = _cairo_fixed_to_double (line->p1.x);
583
    p1.y = _cairo_fixed_to_double (line->p1.y);
584

            
585
    p2.x = _cairo_fixed_to_double (line->p2.x);
586
    p2.y = _cairo_fixed_to_double (line->p2.y);
587

            
588
    m = (p2.x - p1.x) / (p2.y - p1.y);
589
    out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
590
    out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
591
}
592

            
593
void
594
555
_pixman_image_add_traps (pixman_image_t *image,
595
			 int dst_x, int dst_y,
596
			 cairo_traps_t *traps)
597
{
598
555
    cairo_trapezoid_t *t = traps->traps;
599
555
    int num_traps = traps->num_traps;
600
7509
    while (num_traps--) {
601
	pixman_trapezoid_t trap;
602

            
603
	/* top/bottom will be clamped to surface bounds */
604
6954
	trap.top = _cairo_fixed_to_16_16 (t->top);
605
6954
	trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
606

            
607
	/* However, all the other coordinates will have been left untouched so
608
	 * as not to introduce numerical error. Recompute them if they
609
	 * exceed the 16.16 limits.
610
	 */
611
6954
	if (unlikely (line_exceeds_16_16 (&t->left))) {
612
	    project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
613
	    trap.left.p1.y = trap.top;
614
	    trap.left.p2.y = trap.bottom;
615
	} else {
616
6954
	    trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
617
6954
	    trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
618
6954
	    trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
619
6954
	    trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
620
	}
621

            
622
6954
	if (unlikely (line_exceeds_16_16 (&t->right))) {
623
	    project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
624
	    trap.right.p1.y = trap.top;
625
	    trap.right.p2.y = trap.bottom;
626
	} else {
627
6954
	    trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
628
6954
	    trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
629
6954
	    trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
630
6954
	    trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
631
	}
632

            
633
6954
	pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
634
6954
	t++;
635
    }
636
555
}
637

            
638
static cairo_int_status_t
639
555
composite_traps (void			*_dst,
640
		 cairo_operator_t	op,
641
		 cairo_surface_t	*abstract_src,
642
		 int			src_x,
643
		 int			src_y,
644
		 int			dst_x,
645
		 int			dst_y,
646
		 const cairo_rectangle_int_t *extents,
647
		 cairo_antialias_t	antialias,
648
		 cairo_traps_t		*traps)
649
{
650
555
    cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
651
555
    cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
652
    cairo_int_status_t status;
653
    pixman_image_t *mask;
654
    pixman_format_code_t format;
655

            
656
    TRACE ((stderr, "%s\n", __FUNCTION__));
657

            
658
    /* pixman doesn't eliminate self-intersecting trapezoids/edges */
659
555
    status = _cairo_bentley_ottmann_tessellate_traps (traps,
660
						      CAIRO_FILL_RULE_WINDING);
661
555
    if (status != CAIRO_INT_STATUS_SUCCESS)
662
	    return status;
663

            
664
    /* Special case adding trapezoids onto a mask surface; we want to avoid
665
     * creating an intermediate temporary mask unnecessarily.
666
     *
667
     * We make the assumption here that the portion of the trapezoids
668
     * contained within the surface is bounded by [dst_x,dst_y,width,height];
669
     * the Cairo core code passes bounds based on the trapezoid extents.
670
     */
671
555
    format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
672
555
    if (dst->pixman_format == format &&
673
405
	(abstract_src == NULL ||
674
372
	 (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
675
    {
676
372
	_pixman_image_add_traps (dst->pixman_image, dst_x, dst_y, traps);
677
372
	return CAIRO_STATUS_SUCCESS;
678
    }
679

            
680
183
    mask = pixman_image_create_bits (format,
681
183
				     extents->width, extents->height,
682
				     NULL, 0);
683
183
    if (unlikely (mask == NULL))
684
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
685

            
686
183
    _pixman_image_add_traps (mask, extents->x, extents->y, traps);
687
183
    pixman_image_composite32 (_pixman_operator (op),
688
                              src->pixman_image, mask, dst->pixman_image,
689
183
                              extents->x + src_x, extents->y + src_y,
690
                              0, 0,
691
183
                              extents->x - dst_x, extents->y - dst_y,
692
183
                              extents->width, extents->height);
693

            
694
183
    pixman_image_unref (mask);
695

            
696
183
    return  CAIRO_STATUS_SUCCESS;
697
}
698

            
699
static void
700
set_point (pixman_point_fixed_t *p, cairo_point_t *c)
701
{
702
    p->x = _cairo_fixed_to_16_16 (c->x);
703
    p->y = _cairo_fixed_to_16_16 (c->y);
704
}
705

            
706
void
707
_pixman_image_add_tristrip (pixman_image_t *image,
708
			    int dst_x, int dst_y,
709
			    cairo_tristrip_t *strip)
710
{
711
    pixman_triangle_t tri;
712
    pixman_point_fixed_t *p[3] = {&tri.p1, &tri.p2, &tri.p3 };
713
    int n;
714

            
715
    set_point (p[0], &strip->points[0]);
716
    set_point (p[1], &strip->points[1]);
717
    set_point (p[2], &strip->points[2]);
718
    pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
719
    for (n = 3; n < strip->num_points; n++) {
720
	set_point (p[n%3], &strip->points[n]);
721
	pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
722
    }
723
}
724

            
725
static cairo_int_status_t
726
composite_tristrip (void			*_dst,
727
		    cairo_operator_t	op,
728
		    cairo_surface_t	*abstract_src,
729
		    int			src_x,
730
		    int			src_y,
731
		    int			dst_x,
732
		    int			dst_y,
733
		    const cairo_rectangle_int_t *extents,
734
		    cairo_antialias_t	antialias,
735
		    cairo_tristrip_t	*strip)
736
{
737
    cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
738
    cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
739
    pixman_image_t *mask;
740
    pixman_format_code_t format;
741

            
742
    TRACE ((stderr, "%s\n", __FUNCTION__));
743

            
744
    if (strip->num_points < 3)
745
	return CAIRO_STATUS_SUCCESS;
746

            
747
    if (1) { /* pixman doesn't eliminate self-intersecting triangles/edges */
748
	    cairo_int_status_t status;
749
	    cairo_traps_t traps;
750
	    int n;
751

            
752
	    _cairo_traps_init (&traps);
753
	    for (n = 0; n < strip->num_points; n++) {
754
		    cairo_point_t p[4];
755

            
756
		    p[0] = strip->points[0];
757
		    p[1] = strip->points[1];
758
		    p[2] = strip->points[2];
759
		    p[3] = strip->points[0];
760

            
761
		    _cairo_traps_tessellate_convex_quad (&traps, p);
762
	    }
763
	    status = composite_traps (_dst, op, abstract_src,
764
				      src_x, src_y,
765
				      dst_x, dst_y,
766
				      extents, antialias, &traps);
767
	    _cairo_traps_fini (&traps);
768

            
769
	    return status;
770
    }
771

            
772
    format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
773
    if (dst->pixman_format == format &&
774
	(abstract_src == NULL ||
775
	 (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
776
    {
777
	_pixman_image_add_tristrip (dst->pixman_image, dst_x, dst_y, strip);
778
	return CAIRO_STATUS_SUCCESS;
779
    }
780

            
781
    mask = pixman_image_create_bits (format,
782
				     extents->width, extents->height,
783
				     NULL, 0);
784
    if (unlikely (mask == NULL))
785
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
786

            
787
    _pixman_image_add_tristrip (mask, extents->x, extents->y, strip);
788
    pixman_image_composite32 (_pixman_operator (op),
789
                              src->pixman_image, mask, dst->pixman_image,
790
                              extents->x + src_x, extents->y + src_y,
791
                              0, 0,
792
                              extents->x - dst_x, extents->y - dst_y,
793
                              extents->width, extents->height);
794

            
795
    pixman_image_unref (mask);
796

            
797
    return  CAIRO_STATUS_SUCCESS;
798
}
799

            
800
static cairo_int_status_t
801
68607
check_composite_glyphs (const cairo_composite_rectangles_t *extents,
802
			cairo_scaled_font_t *scaled_font,
803
			cairo_glyph_t *glyphs,
804
			int *num_glyphs)
805
{
806
68607
    return CAIRO_STATUS_SUCCESS;
807
}
808

            
809
#if HAS_PIXMAN_GLYPHS
810
static pixman_glyph_cache_t *global_glyph_cache;
811

            
812
static inline pixman_glyph_cache_t *
813
68607
get_glyph_cache (void)
814
{
815
68607
    if (!global_glyph_cache)
816
228
	global_glyph_cache = pixman_glyph_cache_create ();
817

            
818
68607
    return global_glyph_cache;
819
}
820

            
821
void
822
608
_cairo_image_compositor_reset_static_data (void)
823
{
824
608
    CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
825

            
826
608
    if (global_glyph_cache)
827
	pixman_glyph_cache_destroy (global_glyph_cache);
828
608
    global_glyph_cache = NULL;
829

            
830
608
    CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
831
608
}
832

            
833
void
834
30
_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
835
				cairo_scaled_glyph_t *scaled_glyph)
836
{
837
30
    CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
838

            
839
30
    if (global_glyph_cache) {
840
30
	pixman_glyph_cache_remove (
841
	    global_glyph_cache, scaled_font,
842
30
	    (void *)scaled_glyph->hash_entry.hash);
843
    }
844

            
845
30
    CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
846
30
}
847

            
848
#define PHASE(x) ((int)(floor (4 * (x + 0.125)) - 4 * floor (x + 0.125)))
849
#define POSITION(x) ((int) floor (x + 0.125))
850

            
851
static cairo_int_status_t
852
68607
composite_glyphs (void				*_dst,
853
		  cairo_operator_t		 op,
854
		  cairo_surface_t		*_src,
855
		  int				 src_x,
856
		  int				 src_y,
857
		  int				 dst_x,
858
		  int				 dst_y,
859
		  cairo_composite_glyphs_info_t *info)
860
{
861
68607
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
862
    pixman_glyph_cache_t *glyph_cache;
863
    pixman_glyph_t pglyphs_stack[CAIRO_STACK_ARRAY_LENGTH (pixman_glyph_t)];
864
68607
    pixman_glyph_t *pglyphs = pglyphs_stack;
865
    pixman_glyph_t *pg;
866
    int i;
867

            
868
    TRACE ((stderr, "%s\n", __FUNCTION__));
869

            
870
68607
    CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
871

            
872
68607
    glyph_cache = get_glyph_cache();
873
68607
    if (unlikely (glyph_cache == NULL)) {
874
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
875
	goto out_unlock;
876
    }
877

            
878
68607
    pixman_glyph_cache_freeze (glyph_cache);
879

            
880
68607
    if (info->num_glyphs > ARRAY_LENGTH (pglyphs_stack)) {
881
15
	pglyphs = _cairo_malloc_ab (info->num_glyphs, sizeof (pixman_glyph_t));
882
15
	if (unlikely (pglyphs == NULL)) {
883
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
884
	    goto out_thaw;
885
	}
886
    }
887

            
888
68607
    pg = pglyphs;
889
951183
    for (i = 0; i < info->num_glyphs; i++) {
890
882576
	unsigned long index = info->glyphs[i].index;
891
	const void *glyph;
892
        unsigned long xphase, yphase;
893

            
894
882576
        xphase = PHASE(info->glyphs[i].x);
895
882576
        yphase = PHASE(info->glyphs[i].y);
896

            
897
882576
	index = index | (xphase << 24) | (yphase << 26);
898

            
899
882576
	glyph = pixman_glyph_cache_lookup (glyph_cache, info->font, (void *)(uintptr_t)index);
900
882576
	if (!glyph) {
901
	    cairo_scaled_glyph_t *scaled_glyph;
902
	    cairo_image_surface_t *glyph_surface;
903

            
904
	    /* This call can actually end up recursing, so we have to
905
	     * drop the mutex around it.
906
	     */
907
3555
	    CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
908
3555
	    status = _cairo_scaled_glyph_lookup (info->font, index,
909
						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
910
						 NULL, /* foreground color */
911
						 &scaled_glyph);
912
3555
	    CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
913

            
914
3555
	    if (unlikely (status))
915
		goto out_thaw;
916

            
917
3555
	    glyph_surface = scaled_glyph->surface;
918
3555
	    glyph = pixman_glyph_cache_insert (glyph_cache, info->font, (void *)(uintptr_t)index,
919
3555
					       glyph_surface->base.device_transform.x0,
920
3555
					       glyph_surface->base.device_transform.y0,
921
					       glyph_surface->pixman_image);
922
3555
	    if (unlikely (!glyph)) {
923
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
924
		goto out_thaw;
925
	    }
926
	}
927

            
928
882576
	pg->x = POSITION (info->glyphs[i].x);
929
882576
	pg->y = POSITION (info->glyphs[i].y);
930
882576
	pg->glyph = glyph;
931
882576
	pg++;
932
    }
933

            
934
68607
    if (info->use_mask) {
935
	pixman_format_code_t mask_format;
936

            
937
34785
	mask_format = pixman_glyph_get_mask_format (glyph_cache, pg - pglyphs, pglyphs);
938

            
939
34785
	pixman_composite_glyphs (_pixman_operator (op),
940
				 ((cairo_image_source_t *)_src)->pixman_image,
941
				 to_pixman_image (_dst),
942
				 mask_format,
943
34785
				 info->extents.x + src_x, info->extents.y + src_y,
944
				 info->extents.x, info->extents.y,
945
34785
				 info->extents.x - dst_x, info->extents.y - dst_y,
946
				 info->extents.width, info->extents.height,
947
34785
				 glyph_cache, pg - pglyphs, pglyphs);
948
    } else {
949
33822
	pixman_composite_glyphs_no_mask (_pixman_operator (op),
950
					 ((cairo_image_source_t *)_src)->pixman_image,
951
					 to_pixman_image (_dst),
952
					 src_x, src_y,
953
					 - dst_x, - dst_y,
954
33822
					 glyph_cache, pg - pglyphs, pglyphs);
955
    }
956

            
957
68607
out_thaw:
958
68607
    pixman_glyph_cache_thaw (glyph_cache);
959

            
960
68607
    if (pglyphs != pglyphs_stack)
961
15
	free(pglyphs);
962

            
963
68592
out_unlock:
964
68607
    CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
965
68607
    return status;
966
}
967
#else
968
void
969
_cairo_image_compositor_reset_static_data (void)
970
{
971
}
972

            
973
void
974
_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
975
				cairo_scaled_glyph_t *scaled_glyph)
976
{
977
}
978

            
979
static cairo_int_status_t
980
composite_one_glyph (void				*_dst,
981
		     cairo_operator_t			 op,
982
		     cairo_surface_t			*_src,
983
		     int				 src_x,
984
		     int				 src_y,
985
		     int				 dst_x,
986
		     int				 dst_y,
987
		     cairo_composite_glyphs_info_t	 *info)
988
{
989
    cairo_image_surface_t *glyph_surface;
990
    cairo_scaled_glyph_t *scaled_glyph;
991
    cairo_status_t status;
992
    int x, y;
993

            
994
    TRACE ((stderr, "%s\n", __FUNCTION__));
995

            
996
    status = _cairo_scaled_glyph_lookup (info->font,
997
					 info->glyphs[0].index,
998
					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
999
					 NULL, /* foreground color */
					 &scaled_glyph);
    if (unlikely (status))
	return status;
    glyph_surface = scaled_glyph->surface;
    if (glyph_surface->width == 0 || glyph_surface->height == 0)
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    /* round glyph locations to the nearest pixel */
    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
    x = _cairo_lround (info->glyphs[0].x -
		       glyph_surface->base.device_transform.x0);
    y = _cairo_lround (info->glyphs[0].y -
		       glyph_surface->base.device_transform.y0);
    pixman_image_composite32 (_pixman_operator (op),
			      ((cairo_image_source_t *)_src)->pixman_image,
			      glyph_surface->pixman_image,
			      to_pixman_image (_dst),
			      x + src_x,  y + src_y,
			      0, 0,
			      x - dst_x, y - dst_y,
			      glyph_surface->width,
			      glyph_surface->height);
    return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
composite_glyphs_via_mask (void				*_dst,
			   cairo_operator_t		 op,
			   cairo_surface_t		*_src,
			   int				 src_x,
			   int				 src_y,
			   int				 dst_x,
			   int				 dst_y,
			   cairo_composite_glyphs_info_t *info)
{
    cairo_scaled_glyph_t *glyph_cache[64];
    pixman_image_t *white = _pixman_image_for_color (CAIRO_COLOR_WHITE);
    cairo_scaled_glyph_t *scaled_glyph;
    uint8_t buf[2048];
    pixman_image_t *mask;
    pixman_format_code_t format;
    cairo_status_t status;
    int i;
    TRACE ((stderr, "%s\n", __FUNCTION__));
    if (unlikely (white == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit
     * optimised paths through pixman. Should we increase the bit
     * depth of the target surface, we should reconsider the appropriate
     * mask formats.
     */
    status = _cairo_scaled_glyph_lookup (info->font,
					 info->glyphs[0].index,
					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
					 NULL, /* foreground color */
					 &scaled_glyph);
    if (unlikely (status)) {
	pixman_image_unref (white);
	return status;
    }
    memset (glyph_cache, 0, sizeof (glyph_cache));
    glyph_cache[info->glyphs[0].index % ARRAY_LENGTH (glyph_cache)] = scaled_glyph;
    format = PIXMAN_a8;
    i = (info->extents.width + 3) & ~3;
    if (scaled_glyph->surface->base.content & CAIRO_CONTENT_COLOR) {
	format = PIXMAN_a8r8g8b8;
	i = info->extents.width * 4;
    }
    if (i * info->extents.height > (int) sizeof (buf)) {
	mask = pixman_image_create_bits (format,
					info->extents.width,
					info->extents.height,
					NULL, 0);
    } else {
	memset (buf, 0, i * info->extents.height);
	mask = pixman_image_create_bits (format,
					info->extents.width,
					info->extents.height,
					(uint32_t *)buf, i);
    }
    if (unlikely (mask == NULL)) {
	pixman_image_unref (white);
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }
    status = CAIRO_STATUS_SUCCESS;
    for (i = 0; i < info->num_glyphs; i++) {
	unsigned long glyph_index = info->glyphs[i].index;
	int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
	cairo_image_surface_t *glyph_surface;
	int x, y;
	scaled_glyph = glyph_cache[cache_index];
	if (scaled_glyph == NULL ||
	    _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
	{
	    status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
						 NULL, /* foreground color */
						 &scaled_glyph);
	    if (unlikely (status)) {
		pixman_image_unref (mask);
		pixman_image_unref (white);
		return status;
	    }
	    glyph_cache[cache_index] = scaled_glyph;
	}
	glyph_surface = scaled_glyph->surface;
	if (glyph_surface->width && glyph_surface->height) {
	    if (glyph_surface->base.content & CAIRO_CONTENT_COLOR &&
		format == PIXMAN_a8) {
		pixman_image_t *ca_mask;
		format = PIXMAN_a8r8g8b8;
		ca_mask = pixman_image_create_bits (format,
						    info->extents.width,
						    info->extents.height,
						    NULL, 0);
		if (unlikely (ca_mask == NULL)) {
		    pixman_image_unref (mask);
		    pixman_image_unref (white);
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
		}
		pixman_image_composite32 (PIXMAN_OP_SRC,
					  white, mask, ca_mask,
					  0, 0,
					  0, 0,
					  0, 0,
					  info->extents.width,
					  info->extents.height);
		pixman_image_unref (mask);
		mask = ca_mask;
	    }
	    /* round glyph locations to the nearest pixel */
	    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
	    x = _cairo_lround (info->glyphs[i].x -
			       glyph_surface->base.device_transform.x0);
	    y = _cairo_lround (info->glyphs[i].y -
			       glyph_surface->base.device_transform.y0);
	    if (glyph_surface->pixman_format == format) {
		pixman_image_composite32 (PIXMAN_OP_ADD,
					  glyph_surface->pixman_image, NULL, mask,
					  0, 0,
					  0, 0,
					  x - info->extents.x, y - info->extents.y,
					  glyph_surface->width,
					  glyph_surface->height);
	    } else {
		pixman_image_composite32 (PIXMAN_OP_ADD,
					  white, glyph_surface->pixman_image, mask,
					  0, 0,
					  0, 0,
					  x - info->extents.x, y - info->extents.y,
					  glyph_surface->width,
					  glyph_surface->height);
	    }
	}
    }
    if (format == PIXMAN_a8r8g8b8)
	pixman_image_set_component_alpha (mask, TRUE);
    pixman_image_composite32 (_pixman_operator (op),
			      ((cairo_image_source_t *)_src)->pixman_image,
			      mask,
			      to_pixman_image (_dst),
			      info->extents.x + src_x, info->extents.y + src_y,
			      0, 0,
			      info->extents.x - dst_x, info->extents.y - dst_y,
			      info->extents.width, info->extents.height);
    pixman_image_unref (mask);
    pixman_image_unref (white);
    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
composite_glyphs (void				*_dst,
		  cairo_operator_t		 op,
		  cairo_surface_t		*_src,
		  int				 src_x,
		  int				 src_y,
		  int				 dst_x,
		  int				 dst_y,
		  cairo_composite_glyphs_info_t *info)
{
    cairo_scaled_glyph_t *glyph_cache[64];
    pixman_image_t *dst, *src;
    cairo_status_t status;
    int i;
    TRACE ((stderr, "%s\n", __FUNCTION__));
    if (info->num_glyphs == 1)
	return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
    if (info->use_mask)
	return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
    op = _pixman_operator (op);
    dst = to_pixman_image (_dst);
    src = ((cairo_image_source_t *)_src)->pixman_image;
    memset (glyph_cache, 0, sizeof (glyph_cache));
    status = CAIRO_STATUS_SUCCESS;
    for (i = 0; i < info->num_glyphs; i++) {
	int x, y;
	cairo_image_surface_t *glyph_surface;
	cairo_scaled_glyph_t *scaled_glyph;
	unsigned long glyph_index = info->glyphs[i].index;
	int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
	scaled_glyph = glyph_cache[cache_index];
	if (scaled_glyph == NULL ||
	    _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
	{
	    status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
						 NULL, /* foreground color */
						 &scaled_glyph);
	    if (unlikely (status))
		break;
	    glyph_cache[cache_index] = scaled_glyph;
	}
	glyph_surface = scaled_glyph->surface;
	if (glyph_surface->width && glyph_surface->height) {
	    /* round glyph locations to the nearest pixel */
	    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
	    x = _cairo_lround (info->glyphs[i].x -
			       glyph_surface->base.device_transform.x0);
	    y = _cairo_lround (info->glyphs[i].y -
			       glyph_surface->base.device_transform.y0);
	    pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst,
                                      x + src_x,  y + src_y,
                                      0, 0,
                                      x - dst_x, y - dst_y,
				      glyph_surface->width,
				      glyph_surface->height);
	}
    }
    return status;
}
#endif
static cairo_int_status_t
69177
check_composite (const cairo_composite_rectangles_t *extents)
{
69177
    return CAIRO_STATUS_SUCCESS;
}
const cairo_compositor_t *
1742
_cairo_image_traps_compositor_get (void)
{
    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
    static cairo_traps_compositor_t compositor;
1742
    if (_cairo_atomic_init_once_enter(&once)) {
1742
	_cairo_traps_compositor_init(&compositor,
				     &__cairo_no_compositor);
1742
	compositor.acquire = acquire;
1742
	compositor.release = release;
1742
	compositor.set_clip_region = set_clip_region;
1742
	compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
1742
	compositor.draw_image_boxes = draw_image_boxes;
	//compositor.copy_boxes = copy_boxes;
1742
	compositor.fill_boxes = fill_boxes;
1742
	compositor.check_composite = check_composite;
1742
	compositor.composite = composite;
1742
	compositor.lerp = lerp;
	//compositor.check_composite_boxes = check_composite_boxes;
1742
	compositor.composite_boxes = composite_boxes;
	//compositor.check_composite_traps = check_composite_traps;
1742
	compositor.composite_traps = composite_traps;
	//compositor.check_composite_tristrip = check_composite_traps;
1742
	compositor.composite_tristrip = composite_tristrip;
1742
	compositor.check_composite_glyphs = check_composite_glyphs;
1742
	compositor.composite_glyphs = composite_glyphs;
	_cairo_atomic_init_once_leave(&once);
    }
1742
    return &compositor.base;
}
const cairo_compositor_t *
_cairo_image_mask_compositor_get (void)
{
    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
    static cairo_mask_compositor_t compositor;
    if (_cairo_atomic_init_once_enter(&once)) {
	_cairo_mask_compositor_init (&compositor,
				     _cairo_image_traps_compositor_get ());
	compositor.acquire = acquire;
	compositor.release = release;
	compositor.set_clip_region = set_clip_region;
	compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
	compositor.draw_image_boxes = draw_image_boxes;
	compositor.fill_rectangles = fill_rectangles;
	compositor.fill_boxes = fill_boxes;
	compositor.check_composite = check_composite;
	compositor.composite = composite;
	//compositor.lerp = lerp;
	//compositor.check_composite_boxes = check_composite_boxes;
	compositor.composite_boxes = composite_boxes;
	compositor.check_composite_glyphs = check_composite_glyphs;
	compositor.composite_glyphs = composite_glyphs;
	_cairo_atomic_init_once_leave(&once);
    }
    return &compositor.base;
}
#if PIXMAN_HAS_COMPOSITOR
typedef struct _cairo_image_span_renderer {
    cairo_span_renderer_t base;
    pixman_image_compositor_t *compositor;
    pixman_image_t *src, *mask;
    float opacity;
    cairo_rectangle_int_t extents;
} cairo_image_span_renderer_t;
COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
static cairo_status_t
_cairo_image_bounded_opaque_spans (void *abstract_renderer,
				   int y, int height,
				   const cairo_half_open_span_t *spans,
				   unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
    do {
	if (spans[0].coverage)
	    pixman_image_compositor_blt (r->compositor,
					 spans[0].x, y,
					 spans[1].x - spans[0].x, height,
					 spans[0].coverage);
	spans++;
    } while (--num_spans > 1);
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_image_bounded_spans (void *abstract_renderer,
			    int y, int height,
			    const cairo_half_open_span_t *spans,
			    unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
    do {
	if (spans[0].coverage) {
	    pixman_image_compositor_blt (r->compositor,
					 spans[0].x, y,
					 spans[1].x - spans[0].x, height,
					 r->opacity * spans[0].coverage);
	}
	spans++;
    } while (--num_spans > 1);
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_image_unbounded_spans (void *abstract_renderer,
			      int y, int height,
			      const cairo_half_open_span_t *spans,
			      unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    assert (y + height <= r->extents.height);
    if (y > r->extents.y) {
	pixman_image_compositor_blt (r->compositor,
				     r->extents.x, r->extents.y,
				     r->extents.width, y - r->extents.y,
				     0);
    }
    if (num_spans == 0) {
	pixman_image_compositor_blt (r->compositor,
				     r->extents.x, y,
				     r->extents.width,  height,
				     0);
    } else {
	if (spans[0].x != r->extents.x) {
	    pixman_image_compositor_blt (r->compositor,
					 r->extents.x, y,
					 spans[0].x - r->extents.x,
					 height,
					 0);
	}
	do {
	    assert (spans[0].x < r->extents.x + r->extents.width);
	    pixman_image_compositor_blt (r->compositor,
					 spans[0].x, y,
					 spans[1].x - spans[0].x, height,
					 r->opacity * spans[0].coverage);
	    spans++;
	} while (--num_spans > 1);
	if (spans[0].x != r->extents.x + r->extents.width) {
	    assert (spans[0].x < r->extents.x + r->extents.width);
	    pixman_image_compositor_blt (r->compositor,
					 spans[0].x,     y,
					 r->extents.x + r->extents.width - spans[0].x, height,
					 0);
	}
    }
    r->extents.y = y + height;
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_image_clipped_spans (void *abstract_renderer,
			    int y, int height,
			    const cairo_half_open_span_t *spans,
			    unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    assert (num_spans);
    do {
	if (! spans[0].inverse)
	    pixman_image_compositor_blt (r->compositor,
					 spans[0].x, y,
					 spans[1].x - spans[0].x, height,
					 r->opacity * spans[0].coverage);
	spans++;
    } while (--num_spans > 1);
    r->extents.y = y + height;
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_image_finish_unbounded_spans (void *abstract_renderer)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    if (r->extents.y < r->extents.height) {
	pixman_image_compositor_blt (r->compositor,
				     r->extents.x, r->extents.y,
				     r->extents.width,
				     r->extents.height - r->extents.y,
				     0);
    }
    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
span_renderer_init (cairo_abstract_span_renderer_t	*_r,
		    const cairo_composite_rectangles_t *composite,
		    cairo_bool_t			 needs_clip)
{
    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
    cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
    const cairo_pattern_t *source = &composite->source_pattern.base;
    cairo_operator_t op = composite->op;
    int src_x, src_y;
    int mask_x, mask_y;
    TRACE ((stderr, "%s\n", __FUNCTION__));
    if (op == CAIRO_OPERATOR_CLEAR) {
	op = PIXMAN_OP_LERP_CLEAR;
    } else if (dst->base.is_clear &&
	       (op == CAIRO_OPERATOR_SOURCE ||
		op == CAIRO_OPERATOR_OVER ||
		op == CAIRO_OPERATOR_ADD)) {
	op = PIXMAN_OP_SRC;
    } else if (op == CAIRO_OPERATOR_SOURCE) {
	op = PIXMAN_OP_LERP_SRC;
    } else {
	op = _pixman_operator (op);
    }
    r->compositor = NULL;
    r->mask = NULL;
    r->src = _pixman_image_for_pattern (dst, source, FALSE,
					&composite->unbounded,
					&composite->source_sample_area,
					&src_x, &src_y);
    if (unlikely (r->src == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    r->opacity = 1.0;
    if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
	r->opacity = composite->mask_pattern.solid.color.alpha;
    } else {
	r->mask = _pixman_image_for_pattern (dst,
					     &composite->mask_pattern.base,
					     TRUE,
					     &composite->unbounded,
					     &composite->mask_sample_area,
					     &mask_x, &mask_y);
	if (unlikely (r->mask == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	/* XXX Component-alpha? */
	if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
	    _cairo_pattern_is_opaque (source, &composite->source_sample_area))
	{
	    pixman_image_unref (r->src);
	    r->src = r->mask;
	    src_x = mask_x;
	    src_y = mask_y;
	    r->mask = NULL;
	}
    }
    if (composite->is_bounded) {
	if (r->opacity == 1.)
	    r->base.render_rows = _cairo_image_bounded_opaque_spans;
	else
	    r->base.render_rows = _cairo_image_bounded_spans;
	r->base.finish = NULL;
    } else {
	if (needs_clip)
	    r->base.render_rows = _cairo_image_clipped_spans;
	else
	    r->base.render_rows = _cairo_image_unbounded_spans;
        r->base.finish = _cairo_image_finish_unbounded_spans;
	r->extents = composite->unbounded;
	r->extents.height += r->extents.y;
    }
    r->compositor =
	pixman_image_create_compositor (op, r->src, r->mask, dst->pixman_image,
					composite->unbounded.x + src_x,
					composite->unbounded.y + src_y,
					composite->unbounded.x + mask_x,
					composite->unbounded.y + mask_y,
					composite->unbounded.x,
					composite->unbounded.y,
					composite->unbounded.width,
					composite->unbounded.height);
    if (unlikely (r->compositor == NULL))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    return CAIRO_STATUS_SUCCESS;
}
static void
span_renderer_fini (cairo_abstract_span_renderer_t *_r,
		    cairo_int_status_t status)
{
    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
    TRACE ((stderr, "%s\n", __FUNCTION__));
    if (status == CAIRO_INT_STATUS_SUCCESS && r->base.finish)
	r->base.finish (r);
    if (r->compositor)
	pixman_image_compositor_destroy (r->compositor);
    if (r->src)
	pixman_image_unref (r->src);
    if (r->mask)
	pixman_image_unref (r->mask);
}
#else
typedef struct _cairo_image_span_renderer {
    cairo_span_renderer_t base;
    const cairo_composite_rectangles_t *composite;
    float opacity;
    uint8_t op;
    int bpp;
    pixman_image_t *src, *mask;
    union {
	struct fill {
	    ptrdiff_t stride;
	    uint8_t *data;
	    uint32_t pixel;
	} fill;
	struct blit {
	    int stride;
	    uint8_t *data;
	    int src_stride;
	    uint8_t *src_data;
	} blit;
	struct composite {
	    pixman_image_t *dst;
	    int src_x, src_y;
	    int mask_x, mask_y;
	    int run_length;
	} composite;
	struct finish {
	    cairo_rectangle_int_t extents;
	    int src_x, src_y;
	    ptrdiff_t stride;
	    uint8_t *data;
	} mask;
    } u;
    uint8_t _buf[0];
#define SZ_BUF (int)(sizeof (cairo_abstract_span_renderer_t) - sizeof (cairo_image_span_renderer_t))
} cairo_image_span_renderer_t;
COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
static cairo_status_t
_cairo_image_spans (void *abstract_renderer,
		    int y, int height,
		    const cairo_half_open_span_t *spans,
		    unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    uint8_t *mask, *row;
    int len;
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
    mask = r->u.mask.data + (y - r->u.mask.extents.y) * r->u.mask.stride;
    mask += spans[0].x - r->u.mask.extents.x;
    row = mask;
    do {
	len = spans[1].x - spans[0].x;
	if (spans[0].coverage) {
	    *row++ = r->opacity * spans[0].coverage;
	    if (--len)
		memset (row, row[-1], len);
	}
	row += len;
	spans++;
    } while (--num_spans > 1);
    len = row - mask;
    row = mask;
    while (--height) {
	mask += r->u.mask.stride;
	memcpy (mask, row, len);
    }
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
1524
_cairo_image_spans_and_zero (void *abstract_renderer,
			     int y, int height,
			     const cairo_half_open_span_t *spans,
			     unsigned num_spans)
{
1524
    cairo_image_span_renderer_t *r = abstract_renderer;
    uint8_t *mask;
    int len;
1524
    mask = r->u.mask.data;
1524
    if (y > r->u.mask.extents.y) {
36
	len = (y - r->u.mask.extents.y) * r->u.mask.stride;
36
	memset (mask, 0, len);
36
	mask += len;
    }
1524
    r->u.mask.extents.y = y + height;
1524
    r->u.mask.data = mask + height * r->u.mask.stride;
1524
    if (num_spans == 0) {
396
	memset (mask, 0, height * r->u.mask.stride);
    } else {
1128
	uint8_t *row = mask;
1128
	if (spans[0].x != r->u.mask.extents.x) {
879
	    len = spans[0].x - r->u.mask.extents.x;
879
	    memset (row, 0, len);
879
	    row += len;
	}
	do {
9900
	    len = spans[1].x - spans[0].x;
9900
	    *row++ = r->opacity * spans[0].coverage;
9900
	    if (len > 1) {
2901
		memset (row, row[-1], --len);
2901
		row += len;
	    }
9900
	    spans++;
9900
	} while (--num_spans > 1);
1128
	if (spans[0].x != r->u.mask.extents.x + r->u.mask.extents.width) {
1011
	    len = r->u.mask.extents.x + r->u.mask.extents.width - spans[0].x;
1011
	    memset (row, 0, len);
	}
1128
	row = mask;
1242
	while (--height) {
114
	    mask += r->u.mask.stride;
114
	    memcpy (mask, row, r->u.mask.extents.width);
	}
    }
1524
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
72
_cairo_image_finish_spans_and_zero (void *abstract_renderer)
{
72
    cairo_image_span_renderer_t *r = abstract_renderer;
72
    if (r->u.mask.extents.y < r->u.mask.extents.height)
36
	memset (r->u.mask.data, 0, (r->u.mask.extents.height - r->u.mask.extents.y) * r->u.mask.stride);
72
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_fill8_spans (void *abstract_renderer, int y, int h,
	       const cairo_half_open_span_t *spans, unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
    if (likely(h == 1)) {
	do {
	    if (spans[0].coverage) {
		int len = spans[1].x - spans[0].x;
		uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
		if (len == 1)
		    *d = r->u.fill.pixel;
		else
		    memset(d, r->u.fill.pixel, len);
	    }
	    spans++;
	} while (--num_spans > 1);
    } else {
	do {
	    if (spans[0].coverage) {
		int yy = y, hh = h;
		do {
		    int len = spans[1].x - spans[0].x;
		    uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
		    if (len == 1)
			*d = r->u.fill.pixel;
		    else
			memset(d, r->u.fill.pixel, len);
		    yy++;
		} while (--hh);
	    }
	    spans++;
	} while (--num_spans > 1);
    }
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
9410
_fill16_spans (void *abstract_renderer, int y, int h,
	       const cairo_half_open_span_t *spans, unsigned num_spans)
{
9410
    cairo_image_span_renderer_t *r = abstract_renderer;
9410
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
9410
    if (likely(h == 1)) {
	do {
29582
	    if (spans[0].coverage) {
19495
		int len = spans[1].x - spans[0].x;
19495
		uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*2);
489558
		while (len-- > 0)
470063
		    *d++ = r->u.fill.pixel;
	    }
29582
	    spans++;
29582
	} while (--num_spans > 1);
    } else {
	do {
4
	    if (spans[0].coverage) {
3
		int yy = y, hh = h;
		do {
180
		    int len = spans[1].x - spans[0].x;
180
		    uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*2);
6180
		    while (len-- > 0)
6000
			*d++ = r->u.fill.pixel;
180
		    yy++;
180
		} while (--hh);
	    }
4
	    spans++;
4
	} while (--num_spans > 1);
    }
9410
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
18820
_fill32_spans (void *abstract_renderer, int y, int h,
	       const cairo_half_open_span_t *spans, unsigned num_spans)
{
18820
    cairo_image_span_renderer_t *r = abstract_renderer;
18820
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
18820
    if (likely(h == 1)) {
	do {
59164
	    if (spans[0].coverage) {
38990
		int len = spans[1].x - spans[0].x;
38990
		if (len > 32) {
6366
		    pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
6366
				 spans[0].x, y, len, 1, r->u.fill.pixel);
		} else {
32624
		    uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
225056
		    while (len-- > 0)
192432
			*d++ = r->u.fill.pixel;
		}
	    }
59164
	    spans++;
59164
	} while (--num_spans > 1);
    } else {
	do {
8
	    if (spans[0].coverage) {
6
		if (spans[1].x - spans[0].x > 16) {
6
		    pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
6
				 spans[0].x, y, spans[1].x - spans[0].x, h,
				 r->u.fill.pixel);
		} else {
		    int yy = y, hh = h;
		    do {
			int len = spans[1].x - spans[0].x;
			uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
			while (len-- > 0)
			    *d++ = r->u.fill.pixel;
			yy++;
		    } while (--hh);
		}
	    }
8
	    spans++;
8
	} while (--num_spans > 1);
    }
18820
    return CAIRO_STATUS_SUCCESS;
}
#if 0
static cairo_status_t
_fill_spans (void *abstract_renderer, int y, int h,
	     const cairo_half_open_span_t *spans, unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
    do {
	if (spans[0].coverage) {
		pixman_fill ((uint32_t *) r->data, r->stride, r->bpp,
			     spans[0].x, y,
			     spans[1].x - spans[0].x, h,
			     r->pixel);
	}
	spans++;
    } while (--num_spans > 1);
    return CAIRO_STATUS_SUCCESS;
}
#endif
static cairo_status_t
_blit_spans (void *abstract_renderer, int y, int h,
	     const cairo_half_open_span_t *spans, unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    int cpp;
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
    cpp = r->bpp/8;
    if (likely (h == 1)) {
	uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
	uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
	do {
	    if (spans[0].coverage) {
		void *s = src + spans[0].x*cpp;
		void *d = dst + spans[0].x*cpp;
		int len = (spans[1].x - spans[0].x) * cpp;
		switch (len) {
		case 1:
		    *(uint8_t *)d = *(uint8_t *)s;
		    break;
		case 2:
		    *(uint16_t *)d = *(uint16_t *)s;
		    break;
		case 4:
		    *(uint32_t *)d = *(uint32_t *)s;
		    break;
#if HAVE_UINT64_T
		case 8:
		    *(uint64_t *)d = *(uint64_t *)s;
		    break;
#endif
		default:
		    memcpy(d, s, len);
		    break;
		}
	    }
	    spans++;
	} while (--num_spans > 1);
    } else {
	do {
	    if (spans[0].coverage) {
		int yy = y, hh = h;
		do {
		    void *src = r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x*cpp;
		    void *dst = r->u.blit.data + yy*r->u.blit.stride + spans[0].x*cpp;
		    int len = (spans[1].x - spans[0].x) * cpp;
		    switch (len) {
		    case 1:
			*(uint8_t *)dst = *(uint8_t *)src;
			break;
		    case 2:
			*(uint16_t *)dst = *(uint16_t *)src;
			break;
		    case 4:
			*(uint32_t *)dst = *(uint32_t *)src;
			break;
#if HAVE_UINT64_T
		    case 8:
			*(uint64_t *)dst = *(uint64_t *)src;
			break;
#endif
		    default:
			memcpy(dst, src, len);
			break;
		    }
		    yy++;
		} while (--hh);
	    }
	    spans++;
	} while (--num_spans > 1);
    }
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
750
_mono_spans (void *abstract_renderer, int y, int h,
	     const cairo_half_open_span_t *spans, unsigned num_spans)
{
750
    cairo_image_span_renderer_t *r = abstract_renderer;
750
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
    do {
6186
	if (spans[0].coverage) {
3468
	    pixman_image_composite32 (r->op,
				      r->src, NULL, r->u.composite.dst,
3468
				      spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
				      0, 0,
3468
				      spans[0].x, y,
3468
				      spans[1].x - spans[0].x, h);
	}
6186
	spans++;
6186
    } while (--num_spans > 1);
750
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
66
_mono_unbounded_spans (void *abstract_renderer, int y, int h,
		       const cairo_half_open_span_t *spans, unsigned num_spans)
{
66
    cairo_image_span_renderer_t *r = abstract_renderer;
66
    if (num_spans == 0) {
	pixman_image_composite32 (PIXMAN_OP_CLEAR,
				  r->src, NULL, r->u.composite.dst,
				  spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
				  0, 0,
				  r->composite->unbounded.x, y,
				  r->composite->unbounded.width, h);
	r->u.composite.mask_y = y + h;
	return CAIRO_STATUS_SUCCESS;
    }
66
    if (y != r->u.composite.mask_y) {
	pixman_image_composite32 (PIXMAN_OP_CLEAR,
				  r->src, NULL, r->u.composite.dst,
				  spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
				  0, 0,
				  r->composite->unbounded.x, r->u.composite.mask_y,
				  r->composite->unbounded.width, y - r->u.composite.mask_y);
    }
66
    if (spans[0].x != r->composite->unbounded.x) {
	    pixman_image_composite32 (PIXMAN_OP_CLEAR,
				      r->src, NULL, r->u.composite.dst,
				      spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
				      0, 0,
				      r->composite->unbounded.x, y,
				      spans[0].x - r->composite->unbounded.x, h);
    }
    do {
66
	int op = spans[0].coverage ? r->op : PIXMAN_OP_CLEAR;
66
	pixman_image_composite32 (op,
				  r->src, NULL, r->u.composite.dst,
66
				  spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
				  0, 0,
66
				  spans[0].x, y,
66
				  spans[1].x - spans[0].x, h);
66
	spans++;
66
    } while (--num_spans > 1);
66
    if (spans[0].x != r->composite->unbounded.x + r->composite->unbounded.width) {
12
	    pixman_image_composite32 (PIXMAN_OP_CLEAR,
				      r->src, NULL, r->u.composite.dst,
12
				      spans[0].x + r->u.composite.src_x,  y + r->u.composite.src_y,
				      0, 0,
12
				      spans[0].x, y,
12
				      r->composite->unbounded.x + r->composite->unbounded.width - spans[0].x, h);
    }
66
    r->u.composite.mask_y = y + h;
66
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
6
_mono_finish_unbounded_spans (void *abstract_renderer)
{
6
    cairo_image_span_renderer_t *r = abstract_renderer;
6
    if (r->u.composite.mask_y < r->composite->unbounded.y + r->composite->unbounded.height) {
3
	pixman_image_composite32 (PIXMAN_OP_CLEAR,
				  r->src, NULL, r->u.composite.dst,
3
				  r->composite->unbounded.x + r->u.composite.src_x,  r->u.composite.mask_y + r->u.composite.src_y,
				  0, 0,
3
				  r->composite->unbounded.x, r->u.composite.mask_y,
3
				  r->composite->unbounded.width,
3
				  r->composite->unbounded.y + r->composite->unbounded.height - r->u.composite.mask_y);
    }
6
    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
182654
mono_renderer_init (cairo_image_span_renderer_t	*r,
		    const cairo_composite_rectangles_t *composite,
		    cairo_antialias_t			 antialias,
		    cairo_bool_t			 needs_clip)
{
182654
    cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
182654
    if (antialias != CAIRO_ANTIALIAS_NONE)
181868
	return CAIRO_INT_STATUS_UNSUPPORTED;
786
    if (!_cairo_pattern_is_opaque_solid (&composite->mask_pattern.base))
3
	return CAIRO_INT_STATUS_UNSUPPORTED;
783
    r->base.render_rows = NULL;
783
    if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
	const cairo_color_t *color;
780
	color = &composite->source_pattern.solid.color;
780
	if (composite->op == CAIRO_OPERATOR_CLEAR)
	    color = CAIRO_COLOR_TRANSPARENT;
780
	if (fill_reduces_to_source (composite->op, color, dst, &r->u.fill.pixel)) {
	    /* Use plain C for the fill operations as the span length is
	     * typically small, too small to payback the startup overheads of
	     * using SSE2 etc.
	     */
771
	    switch (PIXMAN_FORMAT_BPP(dst->pixman_format)) {
	    case 8: r->base.render_rows = _fill8_spans; break;
257
	    case 16: r->base.render_rows = _fill16_spans; break;
514
	    case 32: r->base.render_rows = _fill32_spans; break;
	    default: break;
	    }
771
	    r->u.fill.data = dst->data;
771
	    r->u.fill.stride = dst->stride;
	}
3
    } else if ((composite->op == CAIRO_OPERATOR_SOURCE ||
3
		(composite->op == CAIRO_OPERATOR_OVER &&
3
		 (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) &&
2
	       composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
2
	       composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE &&
2
	       to_image_surface(composite->source_pattern.surface.surface)->format == dst->format)
    {
1
       cairo_image_surface_t *src =
	   to_image_surface(composite->source_pattern.surface.surface);
       int tx, ty;
1
	if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix,
						 &tx, &ty) &&
	    composite->bounded.x + tx >= 0 &&
	    composite->bounded.y + ty >= 0 &&
	    composite->bounded.x + composite->bounded.width +  tx <= src->width &&
	    composite->bounded.y + composite->bounded.height + ty <= src->height) {
	    r->u.blit.stride = dst->stride;
	    r->u.blit.data = dst->data;
	    r->u.blit.src_stride = src->stride;
	    r->u.blit.src_data = src->data + src->stride * ty + tx * 4;
	    r->base.render_rows = _blit_spans;
	}
    }
783
    if (r->base.render_rows == NULL) {
12
	r->src = _pixman_image_for_pattern (dst, &composite->source_pattern.base, FALSE,
					    &composite->unbounded,
					    &composite->source_sample_area,
					    &r->u.composite.src_x, &r->u.composite.src_y);
12
	if (unlikely (r->src == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
12
	r->u.composite.dst = to_pixman_image (composite->surface);
12
	r->op = _pixman_operator (composite->op);
12
	if (composite->is_bounded == 0) {
6
	    r->base.render_rows = _mono_unbounded_spans;
6
	    r->base.finish = _mono_finish_unbounded_spans;
6
	    r->u.composite.mask_y = composite->unbounded.y;
	} else
6
	    r->base.render_rows = _mono_spans;
    }
783
    r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
783
    return CAIRO_INT_STATUS_SUCCESS;
}
#define ONE_HALF 0x7f
#define RB_MASK 0x00ff00ff
#define RB_ONE_HALF 0x007f007f
#define RB_MASK_PLUS_ONE 0x01000100
#define G_SHIFT 8
static inline uint32_t
12651680
mul8x2_8 (uint32_t a, uint8_t b)
{
12651680
    uint32_t t = (a & RB_MASK) * b + RB_ONE_HALF;
12651680
    return ((t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT) & RB_MASK;
}
static inline uint32_t
6325840
add8x2_8x2 (uint32_t a, uint32_t b)
{
6325840
    uint32_t t = a + b;
6325840
    t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK);
6325840
    return t & RB_MASK;
}
static inline uint8_t
114870
mul8_8 (uint8_t a, uint8_t b)
{
114870
    uint16_t t = a * (uint16_t)b + ONE_HALF;
114870
    return ((t >> G_SHIFT) + t) >> G_SHIFT;
}
static inline uint32_t
3162920
lerp8x4 (uint32_t src, uint8_t a, uint32_t dst)
{
3162920
    return (add8x2_8x2 (mul8x2_8 (src, a),
6325840
			mul8x2_8 (dst, ~a)) |
3162920
	    add8x2_8x2 (mul8x2_8 (src >> G_SHIFT, a),
3162920
			mul8x2_8 (dst >> G_SHIFT, ~a)) << G_SHIFT);
}
static cairo_status_t
11097
_fill_a8_lerp_opaque_spans (void *abstract_renderer, int y, int h,
			    const cairo_half_open_span_t *spans, unsigned num_spans)
{
11097
    cairo_image_span_renderer_t *r = abstract_renderer;
11097
    if (num_spans == 0)
3
	return CAIRO_STATUS_SUCCESS;
11094
    if (likely(h == 1)) {
10827
	uint8_t *d = r->u.fill.data + r->u.fill.stride*y;
	do {
33417
	    uint8_t a = spans[0].coverage;
33417
	    if (a) {
31923
		int len = spans[1].x - spans[0].x;
31923
		if (a == 0xff) {
10107
		    memset(d + spans[0].x, r->u.fill.pixel, len);
		} else {
21816
		    uint8_t s = mul8_8(a, r->u.fill.pixel);
21816
		    uint8_t *dst = d + spans[0].x;
21816
		    a = ~a;
49278
		    while (len-- > 0) {
27462
			uint8_t t = mul8_8(*dst, a);
27462
			*dst++ = t + s;
		    }
		}
	    }
33417
	    spans++;
33417
	} while (--num_spans > 1);
    } else {
	do {
657
	    uint8_t a = spans[0].coverage;
657
	    if (a) {
621
		int yy = y, hh = h;
621
		if (a == 0xff) {
		    do {
3516
			int len = spans[1].x - spans[0].x;
3516
			uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
3516
			memset(d, r->u.fill.pixel, len);
3516
			yy++;
3516
		    } while (--hh);
		} else {
390
		    uint8_t s = mul8_8(a, r->u.fill.pixel);
390
		    a = ~a;
		    do {
4278
			int len = spans[1].x - spans[0].x;
4278
			uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
8556
			while (len-- > 0) {
4278
			    uint8_t t = mul8_8(*d, a);
4278
			    *d++ = t + s;
			}
4278
			yy++;
4278
		    } while (--hh);
		}
	    }
657
	    spans++;
657
	} while (--num_spans > 1);
    }
11094
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
175510
_fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h,
				const cairo_half_open_span_t *spans, unsigned num_spans)
{
175510
    cairo_image_span_renderer_t *r = abstract_renderer;
175510
    if (num_spans == 0)
492
	return CAIRO_STATUS_SUCCESS;
175018
    if (likely(h == 1)) {
	do {
3182919
	    uint8_t a = spans[0].coverage;
3182919
	    if (a) {
2757294
		int len = spans[1].x - spans[0].x;
2757294
		uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
2757294
		if (a == 0xff) {
279095
		    if (len > 31) {
41762
			pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
41762
				     spans[0].x, y, len, 1, r->u.fill.pixel);
		    } else {
237333
			uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
1838654
			while (len-- > 0)
1601321
			    *d++ = r->u.fill.pixel;
		    }
5528565
		} else while (len-- > 0) {
3050366
		    *d = lerp8x4 (r->u.fill.pixel, a, *d);
3050366
		    d++;
		}
	    }
3182919
	    spans++;
3182919
	} while (--num_spans > 1);
    } else {
	do {
16686
	    uint8_t a = spans[0].coverage;
16686
	    if (a) {
13077
		if (a == 0xff) {
4892
		    if (spans[1].x - spans[0].x > 16) {
532
			pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
532
				     spans[0].x, y, spans[1].x - spans[0].x, h,
				     r->u.fill.pixel);
		    } else {
4360
			int yy = y, hh = h;
			do {
19018
			    int len = spans[1].x - spans[0].x;
19018
			    uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
115155
			    while (len-- > 0)
96137
				*d++ = r->u.fill.pixel;
19018
			    yy++;
19018
			} while (--hh);
		    }
		} else {
8185
		    int yy = y, hh = h;
		    do {
30566
			int len = spans[1].x - spans[0].x;
30566
			uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
62178
			while (len-- > 0) {
31612
			    *d = lerp8x4 (r->u.fill.pixel, a, *d);
31612
			    d++;
			}
30566
			yy++;
30566
		    } while (--hh);
		}
	    }
16686
	    spans++;
16686
	} while (--num_spans > 1);
    }
175018
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_fill_a8_lerp_spans (void *abstract_renderer, int y, int h,
		     const cairo_half_open_span_t *spans, unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
    if (likely(h == 1)) {
	do {
	    uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
	    if (a) {
		int len = spans[1].x - spans[0].x;
		uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
		uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
		uint16_t ia = ~a;
		while (len-- > 0) {
		    uint16_t t = *d*ia + p;
		    *d++ = (t + (t>>8)) >> 8;
		}
	    }
	    spans++;
	} while (--num_spans > 1);
    } else {
	do {
	    uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
	    if (a) {
		int yy = y, hh = h;
		uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
		uint16_t ia = ~a;
		do {
		    int len = spans[1].x - spans[0].x;
		    uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x;
		    while (len-- > 0) {
			uint16_t t = *d*ia + p;
			*d++ = (t + (t>>8)) >> 8;
		    }
		    yy++;
		} while (--hh);
	    }
	    spans++;
	} while (--num_spans > 1);
    }
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
1040
_fill_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
			 const cairo_half_open_span_t *spans, unsigned num_spans)
{
1040
    cairo_image_span_renderer_t *r = abstract_renderer;
1040
    if (num_spans == 0)
8
	return CAIRO_STATUS_SUCCESS;
1032
    if (likely(h == 1)) {
	do {
29492
	    uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
29492
	    if (a) {
23810
		int len = spans[1].x - spans[0].x;
23810
		uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
89006
		while (len-- > 0) {
65196
		    *d = lerp8x4 (r->u.fill.pixel, a, *d);
65196
		    d++;
		}
	    }
29492
	    spans++;
29492
	} while (--num_spans > 1);
    } else {
	do {
7920
	    uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
7920
	    if (a) {
4760
		int yy = y, hh = h;
		do {
9758
		    int len = spans[1].x - spans[0].x;
9758
		    uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4);
24190
		    while (len-- > 0) {
14432
			*d = lerp8x4 (r->u.fill.pixel, a, *d);
14432
			d++;
		    }
9758
		    yy++;
9758
		} while (--hh);
	    }
7920
	    spans++;
7920
	} while (--num_spans > 1);
    }
1032
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
214
_blit_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
			 const cairo_half_open_span_t *spans, unsigned num_spans)
{
214
    cairo_image_span_renderer_t *r = abstract_renderer;
214
    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;
214
    if (likely(h == 1)) {
210
	uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
210
	uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
	do {
1767
	    uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
1767
	    if (a) {
1605
		uint32_t *s = (uint32_t*)src + spans[0].x;
1605
		uint32_t *d = (uint32_t*)dst + spans[0].x;
1605
		int len = spans[1].x - spans[0].x;
1605
		if (a == 0xff) {
354
		    if (len == 1)
13
			*d = *s;
		    else
341
			memcpy(d, s, len*4);
		} else {
2537
		    while (len-- > 0) {
1286
			*d = lerp8x4 (*s, a, *d);
1286
			s++, d++;
		    }
		}
	    }
1767
	    spans++;
1767
	} while (--num_spans > 1);
    } else {
	do {
6
	    uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
6
	    if (a) {
6
		int yy = y, hh = h;
		do {
58
		    uint32_t *s = (uint32_t *)(r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x * 4);
58
		    uint32_t *d = (uint32_t *)(r->u.blit.data + yy*r->u.blit.stride + spans[0].x * 4);
58
		    int len = spans[1].x - spans[0].x;
58
		    if (a == 0xff) {
30
			if (len == 1)
			    *d = *s;
			else
30
			    memcpy(d, s, len * 4);
		    } else {
56
			while (len-- > 0) {
28
			    *d = lerp8x4 (*s, a, *d);
28
			    s++, d++;
			}
		    }
58
		    yy++;
58
		} while (--hh);
	    }
6
	    spans++;
6
	} while (--num_spans > 1);
    }
214
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
311080
_inplace_spans (void *abstract_renderer,
		int y, int h,
		const cairo_half_open_span_t *spans,
		unsigned num_spans)
{
311080
    cairo_image_span_renderer_t *r = abstract_renderer;
    uint8_t *mask;
    int x0, x1;
311080
    if (num_spans == 0)
1232
	return CAIRO_STATUS_SUCCESS;
309848
    if (num_spans == 2 && spans[0].coverage == 0xff) {
49469
	pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst,
49469
				  spans[0].x + r->u.composite.src_x,
49469
				  y + r->u.composite.src_y,
				  0, 0,
49469
				  spans[0].x, y,
49469
				  spans[1].x - spans[0].x, h);
49469
	return CAIRO_STATUS_SUCCESS;
    }
260379
    mask = (uint8_t *)pixman_image_get_data (r->mask);
260379
    x1 = x0 = spans[0].x;
    do {
2424733
	int len = spans[1].x - spans[0].x;
2424733
	*mask++ = spans[0].coverage;
2424733
	if (len > 1) {
504805
	    if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
106290
		if (x1 != x0) {
98608
		    pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
98608
					      x0 + r->u.composite.src_x,
98608
					      y + r->u.composite.src_y,
					      0, 0,
					      x0, y,
					      x1 - x0, h);
		}
106290
		pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst,
106290
					  spans[0].x + r->u.composite.src_x,
106290
					  y + r->u.composite.src_y,
					  0, 0,
106290
					  spans[0].x, y,
					  len, h);
106290
		mask = (uint8_t *)pixman_image_get_data (r->mask);
106290
		x0 = spans[1].x;
398515
	    } else if (spans[0].coverage == 0x0 &&
193321
		       x1 - x0 > r->u.composite.run_length) {
77855
		pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
77855
					  x0 + r->u.composite.src_x,
77855
					  y + r->u.composite.src_y,
					  0, 0,
					  x0, y,
					  x1 - x0, h);
77855
		mask = (uint8_t *)pixman_image_get_data (r->mask);
77855
		x0 = spans[1].x;
	    }else {
320660
		memset (mask, spans[0].coverage, --len);
320660
		mask += len;
	    }
	}
2424733
	x1 = spans[1].x;
2424733
	spans++;
2424733
    } while (--num_spans > 1);
260379
    if (x1 != x0) {
255145
	pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
255145
				  x0 + r->u.composite.src_x,
255145
				  y + r->u.composite.src_y,
				  0, 0,
				  x0, y,
				  x1 - x0, h);
    }
260379
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
2139
_inplace_opacity_spans (void *abstract_renderer, int y, int h,
			const cairo_half_open_span_t *spans,
			unsigned num_spans)
{
2139
    cairo_image_span_renderer_t *r = abstract_renderer;
    uint8_t *mask;
    int x0, x1;
2139
    if (num_spans == 0)
87
	return CAIRO_STATUS_SUCCESS;
2052
    mask = (uint8_t *)pixman_image_get_data (r->mask);
2052
    x1 = x0 = spans[0].x;
    do {
3033
	int len = spans[1].x - spans[0].x;
3033
	uint8_t m = mul8_8(spans[0].coverage, r->bpp);
3033
	*mask++ = m;
3033
	if (len > 1) {
1446
	    if (m == 0 &&
		x1 - x0 > r->u.composite.run_length) {
		pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
					  x0 + r->u.composite.src_x,
					  y + r->u.composite.src_y,
					  0, 0,
					  x0, y,
					  x1 - x0, h);
		mask = (uint8_t *)pixman_image_get_data (r->mask);
		x0 = spans[1].x;
	    }else {
1446
		memset (mask, m, --len);
1446
		mask += len;
	    }
	}
3033
	x1 = spans[1].x;
3033
	spans++;
3033
    } while (--num_spans > 1);
2052
    if (x1 != x0) {
2052
	pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
2052
				  x0 + r->u.composite.src_x,
2052
				  y + r->u.composite.src_y,
				  0, 0,
				  x0, y,
				  x1 - x0, h);
    }
2052
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
589
_inplace_src_spans (void *abstract_renderer, int y, int h,
		    const cairo_half_open_span_t *spans,
		    unsigned num_spans)
{
589
    cairo_image_span_renderer_t *r = abstract_renderer;
589
    uint8_t *m, *base = (uint8_t*)pixman_image_get_data(r->mask);
    int x0;
589
    if (num_spans == 0)
1
	return CAIRO_STATUS_SUCCESS;
588
    x0 = spans[0].x;
588
    m = base;
    do {
54694
	int len = spans[1].x - spans[0].x;
54694
	if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
92
	    if (spans[0].x != x0) {
#if PIXMAN_HAS_OP_LERP
		pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
					  r->src, r->mask, r->u.composite.dst,
					  x0 + r->u.composite.src_x,
					  y + r->u.composite.src_y,
					  0, 0,
					  x0, y,
					  spans[0].x - x0, h);
#else
56
		pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
					  r->mask, NULL, r->u.composite.dst,
					  0, 0,
					  0, 0,
					  x0, y,
56
					  spans[0].x - x0, h);
56
		pixman_image_composite32 (PIXMAN_OP_ADD,
					  r->src, r->mask, r->u.composite.dst,
56
					  x0 + r->u.composite.src_x,
56
					  y + r->u.composite.src_y,
					  0, 0,
					  x0, y,
56
					  spans[0].x - x0, h);
#endif
	    }
92
	    pixman_image_composite32 (PIXMAN_OP_SRC,
				      r->src, NULL, r->u.composite.dst,
92
				      spans[0].x + r->u.composite.src_x,
92
				      y + r->u.composite.src_y,
				      0, 0,
92
				      spans[0].x, y,
92
				      spans[1].x - spans[0].x, h);
92
	    m = base;
92
	    x0 = spans[1].x;
54602
	} else if (spans[0].coverage == 0x0) {
2278
	    if (spans[0].x != x0) {
#if PIXMAN_HAS_OP_LERP
		pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
					  r->src, r->mask, r->u.composite.dst,
					  x0 + r->u.composite.src_x,
					  y + r->u.composite.src_y,
					  0, 0,
					  x0, y,
					  spans[0].x - x0, h);
#else
2154
		pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
					  r->mask, NULL, r->u.composite.dst,
					  0, 0,
					  0, 0,
					  x0, y,
2154
					  spans[0].x - x0, h);
2154
		pixman_image_composite32 (PIXMAN_OP_ADD,
					  r->src, r->mask, r->u.composite.dst,
2154
					  x0 + r->u.composite.src_x,
2154
					  y + r->u.composite.src_y,
					  0, 0,
					  x0, y,
2154
					  spans[0].x - x0, h);
#endif
	    }
2278
	    m = base;
2278
	    x0 = spans[1].x;
	} else {
52324
	    *m++ = spans[0].coverage;
52324
	    if (len > 1) {
3227
		memset (m, spans[0].coverage, --len);
3227
		m += len;
	    }
	}
54694
	spans++;
54694
    } while (--num_spans > 1);
588
    if (spans[0].x != x0) {
#if PIXMAN_HAS_OP_LERP
	pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
				  r->src, r->mask, r->u.composite.dst,
				  x0 + r->u.composite.src_x,
				  y + r->u.composite.src_y,
				  0, 0,
				  x0, y,
				  spans[0].x - x0, h);
#else
538
	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
				  r->mask, NULL, r->u.composite.dst,
				  0, 0,
				  0, 0,
				  x0, y,
538
				  spans[0].x - x0, h);
538
	pixman_image_composite32 (PIXMAN_OP_ADD,
				  r->src, r->mask, r->u.composite.dst,
538
				  x0 + r->u.composite.src_x,
538
				  y + r->u.composite.src_y,
				  0, 0,
				  x0, y,
538
				  spans[0].x - x0, h);
#endif
    }
588
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
520
_inplace_src_opacity_spans (void *abstract_renderer, int y, int h,
			    const cairo_half_open_span_t *spans,
			    unsigned num_spans)
{
520
    cairo_image_span_renderer_t *r = abstract_renderer;
    uint8_t *mask;
    int x0;
520
    if (num_spans == 0)
4
	return CAIRO_STATUS_SUCCESS;
516
    x0 = spans[0].x;
516
    mask = (uint8_t *)pixman_image_get_data (r->mask);
    do {
18706
	int len = spans[1].x - spans[0].x;
18706
	uint8_t m = mul8_8(spans[0].coverage, r->bpp);
18706
	if (m == 0) {
4421
	    if (spans[0].x != x0) {
#if PIXMAN_HAS_OP_LERP
		pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
					  r->src, r->mask, r->u.composite.dst,
					  x0 + r->u.composite.src_x,
					  y + r->u.composite.src_y,
					  0, 0,
					  x0, y,
					  spans[0].x - x0, h);
#else
4344
		pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
					  r->mask, NULL, r->u.composite.dst,
					  0, 0,
					  0, 0,
					  x0, y,
4344
					  spans[0].x - x0, h);
4344
		pixman_image_composite32 (PIXMAN_OP_ADD,
					  r->src, r->mask, r->u.composite.dst,
4344
					  x0 + r->u.composite.src_x,
4344
					  y + r->u.composite.src_y,
					  0, 0,
					  x0, y,
4344
					  spans[0].x - x0, h);
#endif
	    }
4421
	    mask = (uint8_t *)pixman_image_get_data (r->mask);
4421
	    x0 = spans[1].x;
	} else {
14285
	    *mask++ = m;
14285
	    if (len > 1) {
4859
		memset (mask, m, --len);
4859
		mask += len;
	    }
	}
18706
	spans++;
18706
    } while (--num_spans > 1);
516
    if (spans[0].x != x0) {
#if PIXMAN_HAS_OP_LERP
	pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
				  r->src, r->mask, r->u.composite.dst,
				  x0 + r->u.composite.src_x,
				  y + r->u.composite.src_y,
				  0, 0,
				  x0, y,
				  spans[0].x - x0, h);
#else
390
	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
				  r->mask, NULL, r->u.composite.dst,
				  0, 0,
				  0, 0,
				  x0, y,
390
				  spans[0].x - x0, h);
390
	pixman_image_composite32 (PIXMAN_OP_ADD,
				  r->src, r->mask, r->u.composite.dst,
390
				  x0 + r->u.composite.src_x,
390
				  y + r->u.composite.src_y,
				  0, 0,
				  x0, y,
390
				  spans[0].x - x0, h);
#endif
    }
516
    return CAIRO_STATUS_SUCCESS;
}
5
static void free_pixels (pixman_image_t *image, void *data)
{
5
	free (data);
5
}
static cairo_int_status_t
181871
inplace_renderer_init (cairo_image_span_renderer_t	*r,
		       const cairo_composite_rectangles_t *composite,
		       cairo_antialias_t		 antialias,
		       cairo_bool_t			 needs_clip)
{
181871
    cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
    uint8_t *buf;
181871
    if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
765
	return CAIRO_INT_STATUS_UNSUPPORTED;
181106
    r->base.render_rows = NULL;
181106
    r->bpp = composite->mask_pattern.solid.color.alpha_short >> 8;
181106
    if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
	const cairo_color_t *color;
179417
	color = &composite->source_pattern.solid.color;
179417
	if (composite->op == CAIRO_OPERATOR_CLEAR)
147
	    color = CAIRO_COLOR_TRANSPARENT;
179417
	if (fill_reduces_to_source (composite->op, color, dst, &r->u.fill.pixel)) {
	    /* Use plain C for the fill operations as the span length is
	     * typically small, too small to payback the startup overheads of
	     * using SSE2 etc.
	     */
35723
	    if (r->bpp == 0xff) {
35705
		switch (dst->format) {
5865
		case CAIRO_FORMAT_A8:
5865
		    r->base.render_rows = _fill_a8_lerp_opaque_spans;
5865
		    break;
23791
		case CAIRO_FORMAT_RGB24:
		case CAIRO_FORMAT_ARGB32:
23791
		    r->base.render_rows = _fill_xrgb32_lerp_opaque_spans;
23791
		    break;
6049
		case CAIRO_FORMAT_A1:
		case CAIRO_FORMAT_RGB16_565:
		case CAIRO_FORMAT_RGB30:
		case CAIRO_FORMAT_RGB96F:
		case CAIRO_FORMAT_RGBA128F:
		case CAIRO_FORMAT_INVALID:
6049
		default: break;
		}
	    } else {
18
		switch (dst->format) {
		case CAIRO_FORMAT_A8:
		    r->base.render_rows = _fill_a8_lerp_spans;
		    break;
12
		case CAIRO_FORMAT_RGB24:
		case CAIRO_FORMAT_ARGB32:
12
		    r->base.render_rows = _fill_xrgb32_lerp_spans;
12
		    break;
6
		case CAIRO_FORMAT_A1:
		case CAIRO_FORMAT_RGB16_565:
		case CAIRO_FORMAT_RGB30:
		case CAIRO_FORMAT_RGB96F:
		case CAIRO_FORMAT_RGBA128F:
		case CAIRO_FORMAT_INVALID:
6
		default: break;
		}
	    }
35723
	    r->u.fill.data = dst->data;
35723
	    r->u.fill.stride = dst->stride;
	}
1689
    } else if ((dst->format == CAIRO_FORMAT_ARGB32 || dst->format == CAIRO_FORMAT_RGB24) &&
1129
	       (composite->op == CAIRO_OPERATOR_SOURCE ||
1117
		(composite->op == CAIRO_OPERATOR_OVER &&
1115
		 (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) &&
594
	       composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
524
	       composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE &&
44
	       to_image_surface(composite->source_pattern.surface.surface)->format == dst->format)
    {
37
       cairo_image_surface_t *src =
	   to_image_surface(composite->source_pattern.surface.surface);
       int tx, ty;
37
	if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix,
12
						 &tx, &ty) &&
12
	    composite->bounded.x + tx >= 0 &&
10
	    composite->bounded.y + ty >= 0 &&
10
	    composite->bounded.x + composite->bounded.width + tx <= src->width &&
10
	    composite->bounded.y + composite->bounded.height + ty <= src->height) {
8
	    assert(PIXMAN_FORMAT_BPP(dst->pixman_format) == 32);
8
	    r->u.blit.stride = dst->stride;
8
	    r->u.blit.data = dst->data;
8
	    r->u.blit.src_stride = src->stride;
8
	    r->u.blit.src_data = src->data + src->stride * ty + tx * 4;
8
	    r->base.render_rows = _blit_xrgb32_lerp_spans;
	}
    }
181106
    if (r->base.render_rows == NULL) {
151430
	const cairo_pattern_t *src = &composite->source_pattern.base;
	unsigned int width;
151430
	if (composite->is_bounded == 0)
72
	    return CAIRO_INT_STATUS_UNSUPPORTED;
151358
	r->base.render_rows = r->bpp == 0xff ? _inplace_spans : _inplace_opacity_spans;
151358
	width = (composite->bounded.width + 3) & ~3;
151358
	r->u.composite.run_length = 8;
151358
	if (src->type == CAIRO_PATTERN_TYPE_LINEAR ||
151223
	    src->type == CAIRO_PATTERN_TYPE_RADIAL)
138
		r->u.composite.run_length = 256;
151358
	if (dst->base.is_clear &&
219
	    (composite->op == CAIRO_OPERATOR_SOURCE ||
217
	     composite->op == CAIRO_OPERATOR_OVER ||
4
	     composite->op == CAIRO_OPERATOR_ADD)) {
215
	    r->op = PIXMAN_OP_SRC;
151143
	} else if (composite->op == CAIRO_OPERATOR_SOURCE) {
38
	    r->base.render_rows = r->bpp == 0xff ? _inplace_src_spans : _inplace_src_opacity_spans;
38
	    r->u.composite.mask_y = r->composite->unbounded.y;
38
	    width = (composite->unbounded.width + 3) & ~3;
151105
	} else if (composite->op == CAIRO_OPERATOR_CLEAR) {
47
	    r->op = PIXMAN_OP_OUT_REVERSE;
47
	    src = NULL;
	} else {
151058
	    r->op = _pixman_operator (composite->op);
	}
151358
	r->src = _pixman_image_for_pattern (dst, src, FALSE,
					    &composite->bounded,
					    &composite->source_sample_area,
					    &r->u.composite.src_x, &r->u.composite.src_y);
151358
	if (unlikely (r->src == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	/* Create an effectively unbounded mask by repeating the single line */
151358
	buf = r->_buf;
151358
	if (width > SZ_BUF) {
5
	    buf = _cairo_malloc (width);
5
	    if (unlikely (buf == NULL)) {
		pixman_image_unref (r->src);
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    }
	}
302716
	r->mask = pixman_image_create_bits (PIXMAN_a8,
151358
					    width, composite->unbounded.height,
					    (uint32_t *)buf, 0);
151358
	if (unlikely (r->mask == NULL)) {
	    pixman_image_unref (r->src);
	    if (buf != r->_buf)
		free (buf);
	    return _cairo_error(CAIRO_STATUS_NO_MEMORY);
	}
151358
	if (buf != r->_buf)
5
	    pixman_image_set_destroy_function (r->mask, free_pixels, buf);
151358
	r->u.composite.dst = dst->pixman_image;
    }
181034
    return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
182654
span_renderer_init (cairo_abstract_span_renderer_t	*_r,
		    const cairo_composite_rectangles_t *composite,
		    cairo_antialias_t			 antialias,
		    cairo_bool_t			 needs_clip)
{
182654
    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
182654
    cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
182654
    const cairo_pattern_t *source = &composite->source_pattern.base;
182654
    cairo_operator_t op = composite->op;
    cairo_int_status_t status;
    TRACE ((stderr, "%s: antialias=%d, needs_clip=%d\n", __FUNCTION__,
	    antialias, needs_clip));
182654
    if (needs_clip)
	return CAIRO_INT_STATUS_UNSUPPORTED;
182654
    r->composite = composite;
182654
    r->mask = NULL;
182654
    r->src = NULL;
182654
    r->base.finish = NULL;
182654
    status = mono_renderer_init (r, composite, antialias, needs_clip);
182654
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
783
	return status;
181871
    status = inplace_renderer_init (r, composite, antialias, needs_clip);
181871
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
181034
	return status;
837
    r->bpp = 0;
837
    if (op == CAIRO_OPERATOR_CLEAR) {
#if PIXMAN_HAS_OP_LERP
	op = PIXMAN_OP_LERP_CLEAR;
#else
3
	source = &_cairo_pattern_white.base;
3
	op = PIXMAN_OP_OUT_REVERSE;
#endif
834
    } else if (dst->base.is_clear &&
24
	       (op == CAIRO_OPERATOR_SOURCE ||
		op == CAIRO_OPERATOR_OVER ||
		op == CAIRO_OPERATOR_ADD)) {
30
	op = PIXMAN_OP_SRC;
804
    } else if (op == CAIRO_OPERATOR_SOURCE) {
711
	if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
				      &composite->source_sample_area))
	{
693
	    op = PIXMAN_OP_OVER;
	}
	else
	{
#if PIXMAN_HAS_OP_LERP
	    op = PIXMAN_OP_LERP_SRC;
#else
18
	    return CAIRO_INT_STATUS_UNSUPPORTED;
#endif
	}
    } else {
93
	op = _pixman_operator (op);
    }
819
    r->op = op;
819
    r->src = _pixman_image_for_pattern (dst, source, FALSE,
					&composite->unbounded,
					&composite->source_sample_area,
					&r->u.mask.src_x, &r->u.mask.src_y);
819
    if (unlikely (r->src == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
819
    r->opacity = 1.0;
819
    if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
72
	r->opacity = composite->mask_pattern.solid.color.alpha;
    } else {
	pixman_image_t *mask;
	int mask_x, mask_y;
747
	mask = _pixman_image_for_pattern (dst,
					  &composite->mask_pattern.base,
					  TRUE,
					  &composite->unbounded,
					  &composite->mask_sample_area,
					  &mask_x, &mask_y);
747
	if (unlikely (mask == NULL))
747
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	/* XXX Component-alpha? */
747
	if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
	    _cairo_pattern_is_opaque (source, &composite->source_sample_area))
	{
	    pixman_image_unref (r->src);
	    r->src = mask;
	    r->u.mask.src_x = mask_x;
	    r->u.mask.src_y = mask_y;
	    mask = NULL;
	}
747
	if (mask) {
747
	    pixman_image_unref (mask);
747
	    return CAIRO_INT_STATUS_UNSUPPORTED;
	}
    }
72
    r->u.mask.extents = composite->unbounded;
72
    r->u.mask.stride = (r->u.mask.extents.width + 3) & ~3;
72
    if (r->u.mask.extents.height * r->u.mask.stride > SZ_BUF) {
	r->mask = pixman_image_create_bits (PIXMAN_a8,
					    r->u.mask.extents.width,
					    r->u.mask.extents.height,
					    NULL, 0);
	r->base.render_rows = _cairo_image_spans;
	r->base.finish = NULL;
    } else {
144
	r->mask = pixman_image_create_bits (PIXMAN_a8,
					    r->u.mask.extents.width,
					    r->u.mask.extents.height,
72
					    (uint32_t *)r->_buf, r->u.mask.stride);
72
	r->base.render_rows = _cairo_image_spans_and_zero;
72
	r->base.finish = _cairo_image_finish_spans_and_zero;
    }
72
    if (unlikely (r->mask == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
72
    r->u.mask.data = (uint8_t *) pixman_image_get_data (r->mask);
72
    r->u.mask.stride = pixman_image_get_stride (r->mask);
72
    r->u.mask.extents.height += r->u.mask.extents.y;
72
    return CAIRO_STATUS_SUCCESS;
}
static void
182654
span_renderer_fini (cairo_abstract_span_renderer_t *_r,
		    cairo_int_status_t status)
{
182654
    cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
    TRACE ((stderr, "%s\n", __FUNCTION__));
182654
    if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
181889
	if (r->base.finish)
78
	    r->base.finish (r);
    }
182654
    if (likely (status == CAIRO_INT_STATUS_SUCCESS && r->bpp == 0)) {
72
	const cairo_composite_rectangles_t *composite = r->composite;
72
	pixman_image_composite32 (r->op, r->src, r->mask,
72
				  to_pixman_image (composite->surface),
72
				  composite->unbounded.x + r->u.mask.src_x,
72
				  composite->unbounded.y + r->u.mask.src_y,
				  0, 0,
72
				  composite->unbounded.x,
72
				  composite->unbounded.y,
72
				  composite->unbounded.width,
72
				  composite->unbounded.height);
    }
182654
    if (r->src)
152189
	pixman_image_unref (r->src);
182654
    if (r->mask)
151430
	pixman_image_unref (r->mask);
182654
}
#endif
const cairo_compositor_t *
54564
_cairo_image_spans_compositor_get (void)
{
    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
    static cairo_spans_compositor_t spans;
    static cairo_compositor_t shape;
54564
    if (_cairo_atomic_init_once_enter(&once)) {
1742
	_cairo_shape_mask_compositor_init (&shape,
					   _cairo_image_traps_compositor_get());
1742
	shape.glyphs = NULL;
1742
	_cairo_spans_compositor_init (&spans, &shape);
1742
	spans.flags = 0;
#if PIXMAN_HAS_OP_LERP
	spans.flags |= CAIRO_SPANS_COMPOSITOR_HAS_LERP;
#endif
	//spans.acquire = acquire;
	//spans.release = release;
1742
	spans.fill_boxes = fill_boxes;
1742
	spans.draw_image_boxes = draw_image_boxes;
	//spans.copy_boxes = copy_boxes;
1742
	spans.pattern_to_surface = _cairo_image_source_create_for_pattern;
	//spans.check_composite_boxes = check_composite_boxes;
1742
	spans.composite_boxes = composite_boxes;
	//spans.check_span_renderer = check_span_renderer;
1742
	spans.renderer_init = span_renderer_init;
1742
	spans.renderer_fini = span_renderer_fini;
	_cairo_atomic_init_once_leave(&once);
    }
54564
    return &spans.base;
}