1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2002 University of Southern California
5
 * Copyright © 2005 Red Hat, Inc.
6
 * Copyright © 2011 Intel Corporation
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it either under the terms of the GNU Lesser General Public
10
 * License version 2.1 as published by the Free Software Foundation
11
 * (the "LGPL") or, at your option, under the terms of the Mozilla
12
 * Public License Version 1.1 (the "MPL"). If you do not alter this
13
 * notice, a recipient may use your version of this file under either
14
 * the MPL or the LGPL.
15
 *
16
 * You should have received a copy of the LGPL along with this library
17
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19
 * You should have received a copy of the MPL along with this library
20
 * in the file COPYING-MPL-1.1
21
 *
22
 * The contents of this file are subject to the Mozilla Public License
23
 * Version 1.1 (the "License"); you may not use this file except in
24
 * compliance with the License. You may obtain a copy of the License at
25
 * http://www.mozilla.org/MPL/
26
 *
27
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29
 * the specific language governing rights and limitations.
30
 *
31
 * The Original Code is the cairo graphics library.
32
 *
33
 * The Initial Developer of the Original Code is University of Southern
34
 * California.
35
 *
36
 * Contributor(s):
37
 *	Carl D. Worth <cworth@cworth.org>
38
 *	Behdad Esfahbod <behdad@behdad.org>
39
 *	Chris Wilson <chris@chris-wilson.co.uk>
40
 *	Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
41
 */
42

            
43
#include "cairoint.h"
44

            
45
#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
46

            
47
#include "cairo-xlib-private.h"
48

            
49
#include "cairo-compositor-private.h"
50
#include "cairo-damage-private.h"
51
#include "cairo-image-surface-private.h"
52
#include "cairo-list-inline.h"
53
#include "cairo-pattern-private.h"
54
#include "cairo-pixman-private.h"
55
#include "cairo-traps-private.h"
56
#include "cairo-tristrip-private.h"
57

            
58
static cairo_int_status_t
59
33
check_composite (const cairo_composite_rectangles_t *extents)
60
{
61
33
    cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
62

            
63
33
    if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
64
	return CAIRO_INT_STATUS_UNSUPPORTED;
65

            
66
33
    return CAIRO_STATUS_SUCCESS;
67
}
68

            
69
static cairo_int_status_t
70
33
acquire (void *abstract_dst)
71
{
72
33
    cairo_xlib_surface_t *dst = abstract_dst;
73
    cairo_int_status_t status;
74

            
75
33
    status = _cairo_xlib_display_acquire (dst->base.device, &dst->display);
76
33
    if (unlikely (status))
77
        return status;
78

            
79
33
    dst->dpy = dst->display->display;
80
33
    return CAIRO_STATUS_SUCCESS;
81
}
82

            
83
static cairo_int_status_t
84
33
release (void *abstract_dst)
85
{
86
33
    cairo_xlib_surface_t *dst = abstract_dst;
87

            
88
33
    cairo_device_release (&dst->display->base);
89
33
    dst->dpy = NULL;
90

            
91
33
    return CAIRO_STATUS_SUCCESS;
92
}
93

            
94
static cairo_int_status_t
95
set_clip_region (void *_surface,
96
		 cairo_region_t *region)
97
{
98
    cairo_xlib_surface_t *surface = _surface;
99

            
100
    _cairo_xlib_surface_ensure_picture (surface);
101

            
102
    if (region != NULL) {
103
	XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
104
	XRectangle *rects = stack_rects;
105
	int n_rects, i;
106

            
107
	n_rects = cairo_region_num_rectangles (region);
108
	if (n_rects > ARRAY_LENGTH (stack_rects)) {
109
	    rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
110
	    if (unlikely (rects == NULL))
111
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
112
	}
113
	for (i = 0; i < n_rects; i++) {
114
	    cairo_rectangle_int_t rect;
115

            
116
	    cairo_region_get_rectangle (region, i, &rect);
117

            
118
	    rects[i].x = rect.x;
119
	    rects[i].y = rect.y;
120
	    rects[i].width  = rect.width;
121
	    rects[i].height = rect.height;
122
	}
123
	XRenderSetPictureClipRectangles (surface->dpy,
124
					 surface->picture,
125
					 0, 0,
126
					 rects, n_rects);
127
	if (rects != stack_rects)
128
	    free (rects);
129
    } else {
130
	XRenderPictureAttributes pa;
131
	pa.clip_mask = None;
132
	XRenderChangePicture (surface->dpy,
133
			      surface->picture,
134
			      CPClipMask, &pa);
135
    }
136

            
137
    return CAIRO_STATUS_SUCCESS;
138
}
139

            
140
static cairo_int_status_t
141
copy_image_boxes (void *_dst,
142
		  cairo_image_surface_t *image,
143
		  cairo_boxes_t *boxes,
144
		  int dx, int dy)
145
{
146
    cairo_xlib_surface_t *dst = _dst;
147
    struct _cairo_boxes_chunk *chunk;
148
    cairo_int_status_t status;
149
    Pixmap src;
150
    GC gc;
151
    int i, j;
152

            
153
    assert (image->depth == dst->depth);
154

            
155
    status = acquire (dst);
156
    if (unlikely (status))
157
	return status;
158

            
159
    status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
160
    if (unlikely (status)) {
161
	release (dst);
162
	return status;
163
    }
164

            
165
    src = _cairo_xlib_shm_surface_get_pixmap (&image->base);
166
    if (boxes->num_boxes == 1) {
167
	int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
168
	int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
169
	int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
170
	int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
171

            
172
	_cairo_xlib_shm_surface_mark_active (&image->base);
173
	XCopyArea (dst->dpy, src, dst->drawable, gc,
174
		   x1 + dx, y1 + dy,
175
		   x2 - x1, y2 - y1,
176
		   x1,      y1);
177
    } else {
178
	XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
179
	XRectangle *rects = stack_rects;
180

            
181
	if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
182
	    rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
183
	    if (unlikely (rects == NULL))
184
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
185
	}
186

            
187
	j = 0;
188
	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
189
	    for (i = 0; i < chunk->count; i++) {
190
		int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
191
		int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
192
		int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
193
		int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
194

            
195
		if (x2 > x1 && y2 > y1) {
196
		    rects[j].x = x1;
197
		    rects[j].y = y1;
198
		    rects[j].width  = x2 - x1;
199
		    rects[j].height = y2 - y1;
200
		    j++;
201
		}
202
	    }
203
	}
204

            
205
	XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
206
	_cairo_xlib_shm_surface_mark_active (&image->base);
207
	XCopyArea (dst->dpy, src, dst->drawable, gc,
208
		   0, 0, image->width, image->height, -dx, -dy);
209
	XSetClipMask (dst->dpy, gc, None);
210

            
211
	if (rects != stack_rects)
212
	    free (rects);
213
    }
214

            
215
    _cairo_xlib_surface_put_gc (dst->display, dst, gc);
216
    release (dst);
217
    return CAIRO_STATUS_SUCCESS;
218
}
219

            
220
static cairo_bool_t
221
boxes_cover_surface (cairo_boxes_t *boxes,
222
		     cairo_xlib_surface_t *surface)
223
{
224
    cairo_box_t *b;
225

            
226
    if (boxes->num_boxes != 1)
227
	    return FALSE;
228

            
229
    b = &boxes->chunks.base[0];
230

            
231
    if (_cairo_fixed_integer_part (b->p1.x) > 0 ||
232
	_cairo_fixed_integer_part (b->p1.y) > 0)
233
	return FALSE;
234

            
235
    if (_cairo_fixed_integer_part (b->p2.x) < surface->width ||
236
	_cairo_fixed_integer_part (b->p2.y) < surface->height)
237
	return FALSE;
238

            
239
    return TRUE;
240
}
241

            
242
static cairo_int_status_t
243
draw_image_boxes (void *_dst,
244
		  cairo_image_surface_t *image,
245
		  cairo_boxes_t *boxes,
246
		  int dx, int dy)
247
{
248
    cairo_xlib_surface_t *dst = _dst;
249
    struct _cairo_boxes_chunk *chunk;
250
    cairo_image_surface_t *shm = NULL;
251
    cairo_int_status_t status;
252
    int i;
253

            
254
    if (image->base.device == dst->base.device) {
255
	if (image->depth != dst->depth)
256
	    return CAIRO_INT_STATUS_UNSUPPORTED;
257

            
258
	if (_cairo_xlib_shm_surface_get_pixmap (&image->base))
259
	    return copy_image_boxes (dst, image, boxes, dx, dy);
260

            
261
	goto draw_image_boxes;
262
    }
263

            
264
    if (boxes_cover_surface (boxes, dst))
265
	shm = (cairo_image_surface_t *) _cairo_xlib_surface_get_shm (dst, TRUE);
266
    if (shm) {
267
	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
268
	    for (i = 0; i < chunk->count; i++) {
269
		cairo_box_t *b = &chunk->base[i];
270
		cairo_rectangle_int_t r;
271

            
272
		r.x = _cairo_fixed_integer_part (b->p1.x);
273
		r.y = _cairo_fixed_integer_part (b->p1.y);
274
		r.width = _cairo_fixed_integer_part (b->p2.x) - r.x;
275
		r.height = _cairo_fixed_integer_part (b->p2.y) - r.y;
276

            
277
		if (shm->pixman_format != image->pixman_format ||
278
		    ! pixman_blt ((uint32_t *)image->data, (uint32_t *)shm->data,
279
				  image->stride / sizeof (uint32_t),
280
				  shm->stride / sizeof (uint32_t),
281
				  PIXMAN_FORMAT_BPP (image->pixman_format),
282
				  PIXMAN_FORMAT_BPP (shm->pixman_format),
283
				  r.x + dx, r.y + dy,
284
				  r.x, r.y,
285
				  r.width, r.height))
286
		{
287
		    pixman_image_composite32 (PIXMAN_OP_SRC,
288
					      image->pixman_image, NULL, shm->pixman_image,
289
					      r.x + dx, r.y + dy,
290
					      0, 0,
291
					      r.x, r.y,
292
					      r.width, r.height);
293
		}
294

            
295
		shm->base.damage =
296
		    _cairo_damage_add_rectangle (shm->base.damage, &r);
297
	    }
298
	}
299
	dst->base.is_clear = FALSE;
300
	dst->fallback++;
301
	dst->base.serial++;
302
	return CAIRO_INT_STATUS_NOTHING_TO_DO;
303
    }
304

            
305
    if (image->depth == dst->depth &&
306
	((cairo_xlib_display_t *)dst->display)->shm) {
307
	cairo_box_t extents;
308
	cairo_rectangle_int_t r;
309

            
310
	_cairo_boxes_extents (boxes, &extents);
311
	_cairo_box_round_to_rectangle (&extents, &r);
312

            
313
	shm = (cairo_image_surface_t *)
314
	    _cairo_xlib_surface_create_shm (dst, image->pixman_format,
315
					    r.width, r.height);
316
	if (shm) {
317
	    int tx = -r.x, ty = -r.y;
318

            
319
	    assert (shm->pixman_format == image->pixman_format);
320
	    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
321
		for (i = 0; i < chunk->count; i++) {
322
		    cairo_box_t *b = &chunk->base[i];
323

            
324
		    r.x = _cairo_fixed_integer_part (b->p1.x);
325
		    r.y = _cairo_fixed_integer_part (b->p1.y);
326
		    r.width  = _cairo_fixed_integer_part (b->p2.x) - r.x;
327
		    r.height = _cairo_fixed_integer_part (b->p2.y) - r.y;
328

            
329
		    if (! pixman_blt ((uint32_t *)image->data, (uint32_t *)shm->data,
330
				      image->stride / sizeof (uint32_t),
331
				      shm->stride / sizeof (uint32_t),
332
				      PIXMAN_FORMAT_BPP (image->pixman_format),
333
				      PIXMAN_FORMAT_BPP (shm->pixman_format),
334
				      r.x + dx, r.y + dy,
335
				      r.x + tx, r.y + ty,
336
				      r.width, r.height))
337
		    {
338
			pixman_image_composite32 (PIXMAN_OP_SRC,
339
						  image->pixman_image, NULL, shm->pixman_image,
340
						  r.x + dx, r.y + dy,
341
						  0, 0,
342
						  r.x + tx, r.y + ty,
343
						  r.width, r.height);
344
		    }
345
		}
346
	    }
347

            
348
	    dx = tx;
349
	    dy = ty;
350
	    image = shm;
351

            
352
	    if (_cairo_xlib_shm_surface_get_pixmap (&image->base)) {
353
		status = copy_image_boxes (dst, image, boxes, dx, dy);
354
		if (status != CAIRO_INT_STATUS_UNSUPPORTED)
355
		    goto out;
356
	    }
357
	}
358
    }
359

            
360
draw_image_boxes:
361
    status = CAIRO_STATUS_SUCCESS;
362
    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
363
	for (i = 0; i < chunk->count; i++) {
364
	    cairo_box_t *b = &chunk->base[i];
365
	    int x1 = _cairo_fixed_integer_part (b->p1.x);
366
	    int y1 = _cairo_fixed_integer_part (b->p1.y);
367
	    int x2 = _cairo_fixed_integer_part (b->p2.x);
368
	    int y2 = _cairo_fixed_integer_part (b->p2.y);
369
	    if (_cairo_xlib_surface_draw_image (dst, image,
370
						x1 + dx, y1 + dy,
371
						x2 - x1, y2 - y1,
372
						x1, y1)) {
373
		status = CAIRO_INT_STATUS_UNSUPPORTED;
374
		goto out;
375
	    }
376
	}
377
    }
378

            
379
out:
380
    cairo_surface_destroy (&shm->base);
381
    return status;
382
}
383

            
384
static cairo_int_status_t
385
3
copy_boxes (void *_dst,
386
	    cairo_surface_t *_src,
387
	    cairo_boxes_t *boxes,
388
	    const cairo_rectangle_int_t *extents,
389
	    int dx, int dy)
390
{
391
3
    cairo_xlib_surface_t *dst = _dst;
392
3
    cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)_src;
393
    struct _cairo_boxes_chunk *chunk;
394
    cairo_int_status_t status;
395
    GC gc;
396
    Drawable d;
397
    int i, j;
398

            
399
3
    if (! _cairo_xlib_surface_same_screen  (dst, src))
400
	return CAIRO_INT_STATUS_UNSUPPORTED;
401

            
402
3
    if (dst->depth != src->depth)
403
	return CAIRO_INT_STATUS_UNSUPPORTED;
404

            
405
3
    status = acquire (dst);
406
3
    if (unlikely (status))
407
	return status;
408

            
409
3
    status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
410
3
    if (unlikely (status)) {
411
	release (dst);
412
	return status;
413
    }
414

            
415
3
    if (src->fallback && src->shm->damage->dirty) {
416
	assert (src != dst);
417
	d = _cairo_xlib_shm_surface_get_pixmap (src->shm);
418
	assert (d != 0);
419
    } else {
420
3
	if (! src->owns_pixmap) {
421
	    XGCValues gcv;
422

            
423
3
	    gcv.subwindow_mode = IncludeInferiors;
424
3
	    XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
425
	}
426
3
	d = src->drawable;
427
    }
428

            
429
3
    if (boxes->num_boxes == 1) {
430
3
	int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
431
3
	int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
432
3
	int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
433
3
	int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
434

            
435
3
	XCopyArea (dst->dpy, d, dst->drawable, gc,
436
		   x1 + dx, y1 + dy,
437
3
		   x2 - x1, y2 - y1,
438
		   x1,      y1);
439
    } else {
440
	/* We can only have a single control for subwindow_mode on the
441
	 * GC. If we have a Window destination, we need to set ClipByChildren,
442
	 * but if we have a Window source, we need IncludeInferiors. If we have
443
	 * both a Window destination and source, we must fallback. There is
444
	 * no convenient way to detect if a drawable is a Pixmap or Window,
445
	 * therefore we can only rely on those surfaces that we created
446
	 * ourselves to be Pixmaps, and treat everything else as a potential
447
	 * Window.
448
	 */
449
	if (src == dst || (!src->owns_pixmap && !dst->owns_pixmap)) {
450
	    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
451
		for (i = 0; i < chunk->count; i++) {
452
		    int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
453
		    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
454
		    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
455
		    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
456
		    XCopyArea (dst->dpy, d, dst->drawable, gc,
457
			       x1 + dx, y1 + dy,
458
			       x2 - x1, y2 - y1,
459
			       x1,      y1);
460
		}
461
	    }
462
	} else {
463
	    XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
464
	    XRectangle *rects = stack_rects;
465

            
466
	    if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
467
		rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
468
		if (unlikely (rects == NULL))
469
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
470
	    }
471

            
472
	    j = 0;
473
	    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
474
		for (i = 0; i < chunk->count; i++) {
475
		    int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
476
		    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
477
		    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
478
		    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
479

            
480
		    rects[j].x = x1;
481
		    rects[j].y = y1;
482
		    rects[j].width  = x2 - x1;
483
		    rects[j].height = y2 - y1;
484
		    j++;
485
		}
486
	    }
487
	    assert (j == boxes->num_boxes);
488

            
489
	    XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
490

            
491
	    XCopyArea (dst->dpy, d, dst->drawable, gc,
492
		       extents->x + dx, extents->y + dy,
493
		       extents->width,  extents->height,
494
		       extents->x,      extents->y);
495

            
496
	    XSetClipMask (dst->dpy, gc, None);
497

            
498
	    if (rects != stack_rects)
499
		free (rects);
500
	}
501
    }
502

            
503
3
    if (src->fallback && src->shm->damage->dirty) {
504
	_cairo_xlib_shm_surface_mark_active (src->shm);
505
3
    } else if (! src->owns_pixmap) {
506
	XGCValues gcv;
507

            
508
3
	gcv.subwindow_mode = ClipByChildren;
509
3
	XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
510
    }
511

            
512
3
    _cairo_xlib_surface_put_gc (dst->display, dst, gc);
513
3
    release (dst);
514
3
    return CAIRO_STATUS_SUCCESS;
515
}
516

            
517
static int
518
30
_render_operator (cairo_operator_t op)
519
{
520
30
    switch (op) {
521
6
    case CAIRO_OPERATOR_CLEAR:
522
6
	return PictOpClear;
523

            
524
24
    case CAIRO_OPERATOR_SOURCE:
525
24
	return PictOpSrc;
526
    case CAIRO_OPERATOR_OVER:
527
	return PictOpOver;
528
    case CAIRO_OPERATOR_IN:
529
	return PictOpIn;
530
    case CAIRO_OPERATOR_OUT:
531
	return PictOpOut;
532
    case CAIRO_OPERATOR_ATOP:
533
	return PictOpAtop;
534

            
535
    case CAIRO_OPERATOR_DEST:
536
	return PictOpDst;
537
    case CAIRO_OPERATOR_DEST_OVER:
538
	return PictOpOverReverse;
539
    case CAIRO_OPERATOR_DEST_IN:
540
	return PictOpInReverse;
541
    case CAIRO_OPERATOR_DEST_OUT:
542
	return PictOpOutReverse;
543
    case CAIRO_OPERATOR_DEST_ATOP:
544
	return PictOpAtopReverse;
545

            
546
    case CAIRO_OPERATOR_XOR:
547
	return PictOpXor;
548
    case CAIRO_OPERATOR_ADD:
549
	return PictOpAdd;
550
    case CAIRO_OPERATOR_SATURATE:
551
	return PictOpSaturate;
552

            
553
    case CAIRO_OPERATOR_MULTIPLY:
554
	return PictOpMultiply;
555
    case CAIRO_OPERATOR_SCREEN:
556
	return PictOpScreen;
557
    case CAIRO_OPERATOR_OVERLAY:
558
	return PictOpOverlay;
559
    case CAIRO_OPERATOR_DARKEN:
560
	return PictOpDarken;
561
    case CAIRO_OPERATOR_LIGHTEN:
562
	return PictOpLighten;
563
    case CAIRO_OPERATOR_COLOR_DODGE:
564
	return PictOpColorDodge;
565
    case CAIRO_OPERATOR_COLOR_BURN:
566
	return PictOpColorBurn;
567
    case CAIRO_OPERATOR_HARD_LIGHT:
568
	return PictOpHardLight;
569
    case CAIRO_OPERATOR_SOFT_LIGHT:
570
	return PictOpSoftLight;
571
    case CAIRO_OPERATOR_DIFFERENCE:
572
	return PictOpDifference;
573
    case CAIRO_OPERATOR_EXCLUSION:
574
	return PictOpExclusion;
575
    case CAIRO_OPERATOR_HSL_HUE:
576
	return PictOpHSLHue;
577
    case CAIRO_OPERATOR_HSL_SATURATION:
578
	return PictOpHSLSaturation;
579
    case CAIRO_OPERATOR_HSL_COLOR:
580
	return PictOpHSLColor;
581
    case CAIRO_OPERATOR_HSL_LUMINOSITY:
582
	return PictOpHSLLuminosity;
583

            
584
    default:
585
	ASSERT_NOT_REACHED;
586
	return PictOpOver;
587
    }
588
}
589

            
590
static cairo_bool_t
591
30
fill_reduces_to_source (cairo_operator_t op,
592
			const cairo_color_t *color,
593
			cairo_xlib_surface_t *dst)
594
{
595
30
    if (dst->base.is_clear || CAIRO_COLOR_IS_OPAQUE (color)) {
596
12
	if (op == CAIRO_OPERATOR_OVER)
597
	    return TRUE;
598
12
	if (op == CAIRO_OPERATOR_ADD)
599
	    return (dst->base.content & CAIRO_CONTENT_COLOR) == 0;
600
    }
601

            
602
30
    return FALSE;
603
}
604

            
605
static cairo_int_status_t
606
fill_rectangles (void				*abstract_surface,
607
		 cairo_operator_t		 op,
608
		 const cairo_color_t		*color,
609
		 cairo_rectangle_int_t		*rects,
610
		 int				 num_rects)
611
{
612
    cairo_xlib_surface_t *dst = abstract_surface;
613
    XRenderColor render_color;
614
    int i;
615

            
616
    //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
617

            
618
    if (fill_reduces_to_source (op, color, dst))
619
	op = CAIRO_OPERATOR_SOURCE;
620

            
621
    if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
622
	cairo_int_status_t status;
623

            
624
	status = CAIRO_INT_STATUS_UNSUPPORTED;
625
	if (op == CAIRO_OPERATOR_SOURCE)
626
	    status = _cairo_xlib_core_fill_rectangles (dst, color, num_rects, rects);
627
	return status;
628
    }
629

            
630
    render_color.red   = color->red_short;
631
    render_color.green = color->green_short;
632
    render_color.blue  = color->blue_short;
633
    render_color.alpha = color->alpha_short;
634

            
635
    _cairo_xlib_surface_ensure_picture (dst);
636
    if (num_rects == 1) {
637
	/* Take advantage of the protocol compaction that libXrender performs
638
	 * to amalgamate sequences of XRenderFillRectangle().
639
	 */
640
	XRenderFillRectangle (dst->dpy,
641
			      _render_operator (op),
642
			      dst->picture,
643
			      &render_color,
644
			      rects->x, rects->y,
645
			      rects->width, rects->height);
646
    } else {
647
	XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
648
	XRectangle *xrects = stack_xrects;
649

            
650
	if (num_rects > ARRAY_LENGTH (stack_xrects)) {
651
	    xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
652
	    if (unlikely (xrects == NULL))
653
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
654
	}
655

            
656
	for (i = 0; i < num_rects; i++) {
657
	    xrects[i].x = rects[i].x;
658
	    xrects[i].y = rects[i].y;
659
	    xrects[i].width  = rects[i].width;
660
	    xrects[i].height = rects[i].height;
661
	}
662

            
663
	XRenderFillRectangles (dst->dpy,
664
			       _render_operator (op),
665
			       dst->picture,
666
			       &render_color, xrects, num_rects);
667

            
668
	if (xrects != stack_xrects)
669
	    free (xrects);
670
    }
671

            
672
    return CAIRO_STATUS_SUCCESS;
673
}
674

            
675
static cairo_int_status_t
676
30
fill_boxes (void		*abstract_surface,
677
	    cairo_operator_t	 op,
678
	    const cairo_color_t	*color,
679
	    cairo_boxes_t	*boxes)
680
{
681
30
    cairo_xlib_surface_t *dst = abstract_surface;
682
    XRenderColor render_color;
683

            
684
30
    if (fill_reduces_to_source (op, color, dst))
685
	op = CAIRO_OPERATOR_SOURCE;
686

            
687
30
    if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
688
	cairo_int_status_t status;
689

            
690
	status = CAIRO_INT_STATUS_UNSUPPORTED;
691
	if (op == CAIRO_OPERATOR_SOURCE)
692
	    status = _cairo_xlib_core_fill_boxes (dst, color, boxes);
693
	return status;
694
    }
695

            
696
30
    render_color.red   = color->red_short;
697
30
    render_color.green = color->green_short;
698
30
    render_color.blue  = color->blue_short;
699
30
    render_color.alpha = color->alpha_short;
700

            
701
30
    _cairo_xlib_surface_ensure_picture (dst);
702
30
    if (boxes->num_boxes == 1) {
703
18
	int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
704
18
	int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
705
18
	int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
706
18
	int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
707

            
708
	/* Take advantage of the protocol compaction that libXrender performs
709
	 * to amalgamate sequences of XRenderFillRectangle().
710
	 */
711
18
	XRenderFillRectangle (dst->dpy,
712
			      _render_operator (op),
713
			      dst->picture,
714
			      &render_color,
715
			      x1, y1,
716
18
			      x2 - x1, y2 - y1);
717
    } else {
718
	XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
719
12
	XRectangle *xrects = stack_xrects;
720
	struct _cairo_boxes_chunk *chunk;
721
	int i, j;
722

            
723
12
	if (boxes->num_boxes > ARRAY_LENGTH (stack_xrects)) {
724
	    xrects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
725
	    if (unlikely (xrects == NULL))
726
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
727
	}
728

            
729
12
	j = 0;
730
24
	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
731
36
	    for (i = 0; i < chunk->count; i++) {
732
24
		int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
733
24
		int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
734
24
		int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
735
24
		int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
736

            
737
24
		xrects[j].x = x1;
738
24
		xrects[j].y = y1;
739
24
		xrects[j].width  = x2 - x1;
740
24
		xrects[j].height = y2 - y1;
741
24
		j++;
742
	    }
743
	}
744

            
745
12
	XRenderFillRectangles (dst->dpy,
746
			       _render_operator (op),
747
			       dst->picture,
748
			       &render_color, xrects, j);
749

            
750
12
	if (xrects != stack_xrects)
751
	    free (xrects);
752
    }
753

            
754
30
    return CAIRO_STATUS_SUCCESS;
755
}
756

            
757
#if 0
758
check_composite ()
759
    operation = _categorize_composite_operation (dst, op, src_pattern,
760
						 mask_pattern != NULL);
761
    if (operation == DO_UNSUPPORTED)
762
	return UNSUPPORTED ("unsupported operation");
763

            
764
    //X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
765

            
766
    operation = _recategorize_composite_operation (dst, op, src, &src_attr,
767
						   mask_pattern != NULL);
768
    if (operation == DO_UNSUPPORTED) {
769
	status = UNSUPPORTED ("unsupported operation");
770
	goto BAIL;
771
    }
772
#endif
773

            
774
static cairo_int_status_t
775
composite (void *abstract_dst,
776
	   cairo_operator_t	op,
777
	   cairo_surface_t	*abstract_src,
778
	   cairo_surface_t	*abstract_mask,
779
	   int			src_x,
780
	   int			src_y,
781
	   int			mask_x,
782
	   int			mask_y,
783
	   int			dst_x,
784
	   int			dst_y,
785
	   unsigned int		width,
786
	   unsigned int		height)
787
{
788
    cairo_xlib_surface_t *dst = abstract_dst;
789
    cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
790

            
791
    op = _render_operator (op);
792

            
793
    _cairo_xlib_surface_ensure_picture (dst);
794
    if (abstract_mask) {
795
	cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
796

            
797
	XRenderComposite (dst->dpy, op,
798
			  src->picture, mask->picture, dst->picture,
799
			  src_x,  src_y,
800
			  mask_x, mask_y,
801
			  dst_x,  dst_y,
802
			  width,  height);
803
    } else {
804
	XRenderComposite (dst->dpy, op,
805
			  src->picture, 0, dst->picture,
806
			  src_x, src_y,
807
			  0, 0,
808
			  dst_x, dst_y,
809
			  width, height);
810
    }
811

            
812
    return CAIRO_STATUS_SUCCESS;
813
}
814

            
815
static cairo_int_status_t
816
lerp (void *abstract_dst,
817
      cairo_surface_t	*abstract_src,
818
      cairo_surface_t	*abstract_mask,
819
      int			src_x,
820
      int			src_y,
821
      int			mask_x,
822
      int			mask_y,
823
      int			dst_x,
824
      int			dst_y,
825
      unsigned int		width,
826
      unsigned int		height)
827
{
828
    cairo_xlib_surface_t *dst = abstract_dst;
829
    cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
830
    cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
831

            
832
    _cairo_xlib_surface_ensure_picture (dst);
833
    XRenderComposite (dst->dpy, PictOpOutReverse,
834
		      mask->picture, None, dst->picture,
835
		      mask_x, mask_y,
836
		      0,      0,
837
		      dst_x,  dst_y,
838
		      width,  height);
839
    XRenderComposite (dst->dpy, PictOpAdd,
840
		      src->picture, mask->picture, dst->picture,
841
		      src_x,  src_y,
842
		      mask_x, mask_y,
843
		      dst_x,  dst_y,
844
		      width,  height);
845

            
846
    return CAIRO_STATUS_SUCCESS;
847
}
848

            
849
static cairo_int_status_t
850
composite_boxes (void			*abstract_dst,
851
		 cairo_operator_t	 op,
852
		 cairo_surface_t	*abstract_src,
853
		 cairo_surface_t	*abstract_mask,
854
		 int			src_x,
855
		 int			src_y,
856
		 int			mask_x,
857
		 int			mask_y,
858
		 int			dst_x,
859
		 int			dst_y,
860
		 cairo_boxes_t		*boxes,
861
		 const cairo_rectangle_int_t  *extents)
862
{
863
    cairo_xlib_surface_t *dst = abstract_dst;
864
    Picture src = ((cairo_xlib_source_t *)abstract_src)->picture;
865
    Picture mask = abstract_mask ? ((cairo_xlib_source_t *)abstract_mask)->picture : 0;
866
    XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
867
    XRectangle *rects = stack_rects;
868
    struct _cairo_boxes_chunk *chunk;
869
    int i, j;
870

            
871
    op = _render_operator (op);
872
    _cairo_xlib_surface_ensure_picture (dst);
873
    if (boxes->num_boxes == 1) {
874
	int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
875
	int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
876
	int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
877
	int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
878

            
879
	XRenderComposite (dst->dpy, op,
880
			  src, mask, dst->picture,
881
			  x1 + src_x,	y1 + src_y,
882
			  x1 + mask_x,	y1 + mask_y,
883
			  x1 - dst_x,	y1 - dst_y,
884
			  x2 - x1,	y2 - y1);
885
	return CAIRO_STATUS_SUCCESS;
886
    }
887

            
888
    if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
889
	rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
890
	if (unlikely (rects == NULL))
891
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
892
    }
893

            
894
    j = 0;
895
    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
896
	for (i = 0; i < chunk->count; i++) {
897
	    int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
898
	    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
899
	    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
900
	    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
901

            
902
	    rects[j].x = x1 - dst_x;
903
	    rects[j].y = y1 - dst_y;
904
	    rects[j].width  = x2 - x1;
905
	    rects[j].height = y2 - y1;
906
	    j++;
907
	}
908
    }
909
    assert (j == boxes->num_boxes);
910

            
911
    XRenderSetPictureClipRectangles (dst->dpy,
912
				     dst->picture,
913
				     0, 0,
914
				     rects, j);
915
    if (rects != stack_rects)
916
	free (rects);
917

            
918
    XRenderComposite (dst->dpy, op,
919
		      src, mask, dst->picture,
920
		      extents->x + src_x,  extents->y + src_y,
921
		      extents->x + mask_x, extents->y + mask_y,
922
		      extents->x - dst_x,  extents->y - dst_y,
923
		      extents->width,      extents->height);
924

            
925
    set_clip_region (dst, NULL);
926

            
927
    return CAIRO_STATUS_SUCCESS;
928
}
929

            
930
/* font rendering */
931

            
932
void
933
_cairo_xlib_font_close (cairo_xlib_font_t *priv)
934
{
935
    cairo_xlib_display_t *display = (cairo_xlib_display_t *)priv->base.key;
936
    int i;
937

            
938
    /* XXX All I really want is to do is zap my glyphs... */
939
    _cairo_scaled_font_reset_cache (priv->font);
940

            
941
    for (i = 0; i < NUM_GLYPHSETS; i++) {
942
	cairo_xlib_font_glyphset_t *info;
943

            
944
	info = &priv->glyphset[i];
945
	if (info->glyphset)
946
	    XRenderFreeGlyphSet (display->display, info->glyphset);
947
    }
948

            
949
    /* XXX locking */
950
    cairo_list_del (&priv->link);
951
    cairo_list_del (&priv->base.link);
952
    free (priv);
953
}
954

            
955
static void
956
_cairo_xlib_font_fini (cairo_scaled_font_private_t *abstract_private,
957
		       cairo_scaled_font_t *font)
958
{
959
    cairo_xlib_font_t *priv = (cairo_xlib_font_t *) abstract_private;
960
    cairo_status_t status;
961
    cairo_xlib_display_t *display;
962
    int i;
963

            
964
    cairo_list_del (&priv->base.link);
965
    cairo_list_del (&priv->link);
966

            
967
    status = _cairo_xlib_display_acquire (priv->device, &display);
968
    if (unlikely (status)) /* this should be impossible but leak just in case */
969
	goto BAIL;
970

            
971
    for (i = 0; i < NUM_GLYPHSETS; i++) {
972
	cairo_xlib_font_glyphset_t *info;
973

            
974
	info = &priv->glyphset[i];
975
	if (info->glyphset)
976
	    XRenderFreeGlyphSet (display->display, info->glyphset);
977
    }
978

            
979
    cairo_device_release (&display->base);
980
BAIL:
981
    cairo_device_destroy (priv->device);
982
    free (priv);
983
}
984

            
985
static cairo_xlib_font_t *
986
_cairo_xlib_font_create (cairo_xlib_display_t *display,
987
			 cairo_scaled_font_t  *font)
988
{
989
    cairo_xlib_font_t *priv;
990
    int i;
991

            
992
    priv = _cairo_calloc (sizeof (cairo_xlib_font_t));
993
    if (unlikely (priv == NULL))
994
	return NULL;
995

            
996
    _cairo_scaled_font_attach_private (font, &priv->base, display,
997
				       _cairo_xlib_font_fini);
998

            
999
    priv->device = cairo_device_reference (&display->base);
    priv->font = font;
    cairo_list_add (&priv->link, &display->fonts);
    for (i = 0; i < NUM_GLYPHSETS; i++) {
	cairo_xlib_font_glyphset_t *info = &priv->glyphset[i];
	switch (i) {
	case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break;
	case GLYPHSET_INDEX_A8:     info->format = CAIRO_FORMAT_A8;     break;
	case GLYPHSET_INDEX_A1:     info->format = CAIRO_FORMAT_A1;     break;
	default:                    ASSERT_NOT_REACHED;                          break;
	}
	info->xrender_format = NULL;
	info->glyphset = None;
	info->to_free.count = 0;
    }
    return priv;
}
static int
_cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
{
    if (format == CAIRO_FORMAT_A8)
        return GLYPHSET_INDEX_A8;
    if (format == CAIRO_FORMAT_A1)
        return GLYPHSET_INDEX_A1;
    assert (format == CAIRO_FORMAT_ARGB32);
    return GLYPHSET_INDEX_ARGB32;
}
static inline cairo_xlib_font_t *
_cairo_xlib_font_get (const cairo_xlib_display_t *display,
		      cairo_scaled_font_t *font)
{
    return (cairo_xlib_font_t *)_cairo_scaled_font_find_private (font, display);
}
typedef struct {
    cairo_scaled_glyph_private_t base;
    cairo_xlib_font_glyphset_t *glyphset;
} cairo_xlib_glyph_private_t;
static void
_cairo_xlib_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
			cairo_scaled_glyph_t *glyph,
			cairo_scaled_font_t  *font)
{
    cairo_xlib_glyph_private_t *priv = (cairo_xlib_glyph_private_t *)glyph_private;
    if (! font->finished) {
	cairo_xlib_font_t *font_private;
	struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
	cairo_xlib_font_glyphset_t *info;
	font_private = _cairo_xlib_font_get (glyph_private->key, font);
	assert (font_private);
	info = priv->glyphset;
	to_free = &info->to_free;
	if (to_free->count == ARRAY_LENGTH (to_free->indices)) {
	    cairo_xlib_display_t *display;
	    if (_cairo_xlib_display_acquire (font_private->device,
					     &display) == CAIRO_STATUS_SUCCESS) {
		XRenderFreeGlyphs (display->display,
				   info->glyphset,
				   to_free->indices,
				   to_free->count);
		cairo_device_release (&display->base);
	    }
	    to_free->count = 0;
	}
	to_free->indices[to_free->count++] = glyph->hash_entry.hash;
    }
    cairo_list_del (&glyph_private->link);
    free (glyph_private);
}
static cairo_status_t
_cairo_xlib_glyph_attach (cairo_xlib_display_t	*display,
			  cairo_scaled_glyph_t	*glyph,
			  cairo_xlib_font_glyphset_t *info)
{
    cairo_xlib_glyph_private_t *priv;
    priv = _cairo_calloc (sizeof (*priv));
    if (unlikely (priv == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    _cairo_scaled_glyph_attach_private (glyph, &priv->base, display,
					_cairo_xlib_glyph_fini);
    priv->glyphset = info;
    glyph->dev_private = info;
    glyph->dev_private_key = display;
    return CAIRO_STATUS_SUCCESS;
}
static cairo_xlib_font_glyphset_t *
_cairo_xlib_font_get_glyphset_info_for_format (cairo_xlib_display_t *display,
					       cairo_scaled_font_t *font,
					       cairo_format_t       format)
{
    cairo_xlib_font_t *priv;
    cairo_xlib_font_glyphset_t *info;
    int glyphset_index;
    glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
    priv = _cairo_xlib_font_get (display, font);
    if (priv == NULL) {
	priv = _cairo_xlib_font_create (display, font);
	if (priv == NULL)
	    return NULL;
    }
    info = &priv->glyphset[glyphset_index];
    if (info->glyphset == None) {
	info->xrender_format =
	    _cairo_xlib_display_get_xrender_format (display, info->format);
	info->glyphset = XRenderCreateGlyphSet (display->display,
						info->xrender_format);
    }
    return info;
}
static cairo_bool_t
has_pending_free_glyph (cairo_xlib_font_glyphset_t *info,
			unsigned long glyph_index)
{
    struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
    int i;
    to_free = &info->to_free;
    for (i = 0; i < to_free->count; i++) {
	if (to_free->indices[i] == glyph_index) {
	    to_free->count--;
	    memmove (&to_free->indices[i],
		     &to_free->indices[i+1],
		     (to_free->count - i) * sizeof (to_free->indices[0]));
	    return TRUE;
	}
    }
    return FALSE;
}
static cairo_xlib_font_glyphset_t *
find_pending_free_glyph (cairo_xlib_display_t *display,
			 cairo_scaled_font_t *font,
			 unsigned long glyph_index,
			 cairo_image_surface_t *surface)
{
    cairo_xlib_font_t *priv;
    int i;
    priv = _cairo_xlib_font_get (display, font);
    if (priv == NULL)
	return NULL;
    if (surface != NULL) {
	i = _cairo_xlib_get_glyphset_index_for_format (surface->format);
	if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
	    return &priv->glyphset[i];
    } else {
	for (i = 0; i < NUM_GLYPHSETS; i++) {
	    if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
		return &priv->glyphset[i];
	}
    }
    return NULL;
}
static cairo_status_t
_cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
			       cairo_scaled_font_t   *font,
			       cairo_scaled_glyph_t **pscaled_glyph)
{
    XGlyphInfo glyph_info;
    unsigned long glyph_index;
    unsigned char *data;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
    cairo_scaled_glyph_t *glyph = *pscaled_glyph;
    cairo_image_surface_t *glyph_surface = glyph->surface;
    cairo_bool_t already_had_glyph_surface;
    cairo_xlib_font_glyphset_t *info;
    glyph_index = glyph->hash_entry.hash;
    /* check to see if we have a pending XRenderFreeGlyph for this glyph */
    info = find_pending_free_glyph (display, font, glyph_index, glyph_surface);
    if (info != NULL)
	return _cairo_xlib_glyph_attach (display, glyph, info);
    if (glyph_surface == NULL) {
	status = _cairo_scaled_glyph_lookup (font,
					     glyph_index,
					     CAIRO_SCALED_GLYPH_INFO_METRICS |
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
                                             NULL, /* foreground color */
					     pscaled_glyph);
	if (unlikely (status))
	    return status;
	glyph = *pscaled_glyph;
	glyph_surface = glyph->surface;
	already_had_glyph_surface = FALSE;
    } else {
	already_had_glyph_surface = TRUE;
    }
    info = _cairo_xlib_font_get_glyphset_info_for_format (display, font,
							  glyph_surface->format);
#if 0
    /* If the glyph surface has zero height or width, we create
     * a clear 1x1 surface, to avoid various X server bugs.
     */
    if (glyph_surface->width == 0 || glyph_surface->height == 0) {
	cairo_surface_t *tmp_surface;
	tmp_surface = cairo_image_surface_create (info->format, 1, 1);
	status = tmp_surface->status;
	if (unlikely (status))
	    goto BAIL;
	tmp_surface->device_transform = glyph_surface->base.device_transform;
	tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
	glyph_surface = (cairo_image_surface_t *) tmp_surface;
    }
#endif
    /* If the glyph format does not match the font format, then we
     * create a temporary surface for the glyph image with the font's
     * format.
     */
    if (glyph_surface->format != info->format) {
	cairo_surface_pattern_t pattern;
	cairo_surface_t *tmp_surface;
	tmp_surface = cairo_image_surface_create (info->format,
						  glyph_surface->width,
						  glyph_surface->height);
	status = tmp_surface->status;
	if (unlikely (status))
	    goto BAIL;
	tmp_surface->device_transform = glyph_surface->base.device_transform;
	tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
	_cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
	status = _cairo_surface_paint (tmp_surface,
				       CAIRO_OPERATOR_SOURCE, &pattern.base,
				       NULL);
	_cairo_pattern_fini (&pattern.base);
	glyph_surface = (cairo_image_surface_t *) tmp_surface;
	if (unlikely (status))
	    goto BAIL;
    }
    /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
    glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
    glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
    glyph_info.width = glyph_surface->width;
    glyph_info.height = glyph_surface->height;
    glyph_info.xOff = glyph->x_advance;
    glyph_info.yOff = glyph->y_advance;
    data = glyph_surface->data;
    /* flip formats around */
    switch (_cairo_xlib_get_glyphset_index_for_format (glyph->surface->format)) {
    case GLYPHSET_INDEX_A1:
	/* local bitmaps are always stored with bit == byte */
	if (_cairo_is_little_endian() != (BitmapBitOrder (display->display) == LSBFirst)) {
	    int		    c = glyph_surface->stride * glyph_surface->height;
	    unsigned char   *d;
	    unsigned char   *new, *n;
	    if (c == 0)
		break;
	    new = _cairo_malloc (c);
	    if (!new) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto BAIL;
	    }
	    n = new;
	    d = data;
	    do {
		char	b = *d++;
		b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
		b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
		b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
		*n++ = b;
	    } while (--c);
	    data = new;
	}
	break;
    case GLYPHSET_INDEX_A8:
	break;
    case GLYPHSET_INDEX_ARGB32:
	if (_cairo_is_little_endian() != (ImageByteOrder (display->display) == LSBFirst)) {
	    unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
	    const uint32_t *d;
	    uint32_t *new, *n;
	    if (c == 0)
		break;
	    new = _cairo_malloc (4 * c);
	    if (unlikely (new == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto BAIL;
	    }
	    n = new;
	    d = (uint32_t *) data;
	    do {
		*n++ = bswap_32 (*d);
		d++;
	    } while (--c);
	    data = (uint8_t *) new;
	}
	break;
    default:
	ASSERT_NOT_REACHED;
	break;
    }
    /* XXX assume X server wants pixman padding. Xft assumes this as well */
    XRenderAddGlyphs (display->display, info->glyphset,
		      &glyph_index, &glyph_info, 1,
		      (char *) data,
		      glyph_surface->stride * glyph_surface->height);
    if (data != glyph_surface->data)
	free (data);
    status = _cairo_xlib_glyph_attach (display, glyph, info);
 BAIL:
    if (glyph_surface != glyph->surface)
	cairo_surface_destroy (&glyph_surface->base);
    /* if the scaled glyph didn't already have a surface attached
     * to it, release the created surface now that we have it
     * uploaded to the X server.  If the surface has already been
     * there (eg. because image backend requested it), leave it in
     * the cache
     */
    if (!already_had_glyph_surface)
	_cairo_scaled_glyph_set_surface (glyph, font, NULL);
    return status;
}
typedef void (*cairo_xrender_composite_text_func_t)
	      (Display                      *dpy,
	       int                          op,
	       Picture                      src,
	       Picture                      dst,
	       _Xconst XRenderPictFormat    *maskFormat,
	       int                          xSrc,
	       int                          ySrc,
	       int                          xDst,
	       int                          yDst,
	       _Xconst XGlyphElt8           *elts,
	       int                          nelt);
/* Build a struct of the same size of #cairo_glyph_t that can be used both as
 * an input glyph with double coordinates, and as "working" glyph with
 * integer from-current-point offsets. */
typedef union {
    cairo_glyph_t d;
    unsigned long index;
    struct {
        unsigned long index;
        int x;
        int y;
    } i;
} cairo_xlib_glyph_t;
/* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
/* Start a new element for the first glyph,
 * or for any glyph that has unexpected position,
 * or if current element has too many glyphs
 * (Xrender limits each element to 252 glyphs, we limit them to 128)
 *
 * These same conditions need to be mirrored between
 * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
 */
#define _start_new_glyph_elt(count, glyph) \
    (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
static cairo_status_t
_emit_glyphs_chunk (cairo_xlib_display_t *display,
                    cairo_xlib_surface_t *dst,
		    int dst_x, int dst_y,
		    cairo_xlib_glyph_t *glyphs,
		    int num_glyphs,
		    cairo_scaled_font_t *font,
		    cairo_bool_t use_mask,
		    cairo_operator_t op,
		    cairo_xlib_source_t *src,
		    int src_x, int src_y,
		    /* info for this chunk */
		    int num_elts,
		    int width,
		    cairo_xlib_font_glyphset_t *info)
{
    /* Which XRenderCompositeText function to use */
    cairo_xrender_composite_text_func_t composite_text_func;
    int size;
    /* Element buffer stuff */
    XGlyphElt8 *elts;
    XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
    /* Reuse the input glyph array for output char generation */
    char *char8 = (char *) glyphs;
    unsigned short *char16 = (unsigned short *) glyphs;
    unsigned int *char32 = (unsigned int *) glyphs;
    int i;
    int nelt; /* Element index */
    int n; /* Num output glyphs in current element */
    int j; /* Num output glyphs so far */
    switch (width) {
    case 1:
	/* don't cast the 8-variant, to catch possible mismatches */
	composite_text_func = XRenderCompositeText8;
	size = sizeof (char);
	break;
    case 2:
	composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
	size = sizeof (unsigned short);
	break;
    default:
    case 4:
	composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
	size = sizeof (unsigned int);
    }
    /* Allocate element array */
    if (num_elts <= ARRAY_LENGTH (stack_elts)) {
      elts = stack_elts;
    } else {
      elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
      if (unlikely (elts == NULL))
	  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }
    /* Fill them in */
    nelt = 0;
    n = 0;
    j = 0;
    for (i = 0; i < num_glyphs; i++) {
      /* Start a new element for first output glyph,
       * or for any glyph that has unexpected position,
       * or if current element has too many glyphs.
       *
       * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
       */
      if (_start_new_glyph_elt (j, &glyphs[i])) {
	  if (j) {
	      elts[nelt].nchars = n;
	      nelt++;
	      n = 0;
	  }
	  elts[nelt].chars = char8 + size * j;
	  elts[nelt].glyphset = info->glyphset;
	  elts[nelt].xOff = glyphs[i].i.x;
	  elts[nelt].yOff = glyphs[i].i.y;
      }
      switch (width) {
      case 1: char8 [j] = (char)           glyphs[i].index; break;
      case 2: char16[j] = (unsigned short) glyphs[i].index; break;
      default:
      case 4: char32[j] = (unsigned int)   glyphs[i].index; break;
      }
      n++;
      j++;
    }
    if (n) {
	elts[nelt].nchars = n;
	nelt++;
    }
    /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
     * expected number of xGlyphElts.  */
    assert (nelt == num_elts);
    composite_text_func (display->display, op,
			 src->picture,
			 dst->picture,
			 use_mask ? info->xrender_format : NULL,
			 src_x + elts[0].xOff + dst_x,
			 src_y + elts[0].yOff + dst_y,
			 elts[0].xOff, elts[0].yOff,
			 (XGlyphElt8 *) elts, nelt);
    if (elts != stack_elts)
      free (elts);
    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
check_composite_glyphs (const cairo_composite_rectangles_t *extents,
			cairo_scaled_font_t *font,
			cairo_glyph_t *glyphs,
			int *num_glyphs)
{
    cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface;
    cairo_xlib_display_t *display = dst->display;
    int max_request_size, size;
    TRACE ((stderr, "%s\n", __FUNCTION__));
    if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
	return CAIRO_INT_STATUS_UNSUPPORTED;
    /* The glyph coordinates must be representable in an int16_t.
     * When possible, they will be expressed as an offset from the
     * previous glyph, otherwise they will be an offset from the
     * surface origin. If we can't guarantee this to be possible,
     * fallback.
     */
    if (extents->bounded.x + extents->bounded.width > INT16_MAX ||
	extents->bounded.y + extents->bounded.height> INT16_MAX ||
	extents->bounded.x < INT16_MIN ||
	extents->bounded.y < INT16_MIN)
    {
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }
    /* Approximate the size of the largest glyph and fallback if we can not
     * upload it to the xserver.
     */
    size = ceil (font->max_scale);
    size = 4 * size * size;
    max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display)
			: XMaxRequestSize (display->display)) * 4 -
	sz_xRenderAddGlyphsReq -
	sz_xGlyphInfo          -
	8;
    if (size >= max_request_size)
	return CAIRO_INT_STATUS_UNSUPPORTED;
    return CAIRO_STATUS_SUCCESS;
}
/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
 * enough room for padding */
#define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
#define PHASE(x) ((int)(floor (4 * (x + 0.125)) - 4 * floor (x + 0.125)))
#define POSITION(x) ((int) floor (x + 0.125))
static cairo_int_status_t
composite_glyphs (void				*surface,
		  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_xlib_surface_t *dst = surface;
    cairo_xlib_glyph_t *glyphs = (cairo_xlib_glyph_t *)info->glyphs;
    cairo_xlib_source_t *src = (cairo_xlib_source_t *)_src;
    cairo_xlib_display_t *display = dst->display;
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
    cairo_scaled_glyph_t *glyph;
    cairo_fixed_t x = dst_x, y = dst_y;
    cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info;
    unsigned long max_index = 0;
    int width = 1;
    int num_elts = 0;
    int num_out_glyphs = 0;
    int num_glyphs = info->num_glyphs;
    int max_request_size = XMaxRequestSize (display->display) * 4
			 - MAX (sz_xRenderCompositeGlyphs8Req,
				MAX(sz_xRenderCompositeGlyphs16Req,
				    sz_xRenderCompositeGlyphs32Req));
    int request_size = 0;
    int i;
    op = _render_operator (op),
    _cairo_xlib_surface_ensure_picture (dst);
    for (i = 0; i < num_glyphs; i++) {
        unsigned long xphase, yphase;
	int this_x, this_y;
	int old_width;
        xphase = PHASE(glyphs[i].d.x);
        yphase = PHASE(glyphs[i].d.y);
        glyphs[i].index |= (xphase << 24) | (yphase << 26);
	status = _cairo_scaled_glyph_lookup (info->font,
					     glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
                                             NULL, /* foreground color */
					     &glyph);
	if (unlikely (status))
	    return status;
	this_x = POSITION (glyphs[i].d.x);
	this_y = POSITION (glyphs[i].d.y);
	/* Send unsent glyphs to the server */
	if (glyph->dev_private_key != display) {
	    status = _cairo_xlib_surface_add_glyph (display, info->font, &glyph);
	    if (unlikely (status))
		return status;
	}
	this_glyphset_info = glyph->dev_private;
	if (!glyphset)
	    glyphset = this_glyphset_info;
	/* The invariant here is that we can always flush the glyphs
	 * accumulated before this one, using old_width, and they
	 * would fit in the request.
	 */
	old_width = width;
	/* Update max glyph index */
	if (glyphs[i].index > max_index) {
	    max_index = glyphs[i].index;
	    if (max_index >= 65536)
	      width = 4;
	    else if (max_index >= 256)
	      width = 2;
	    if (width != old_width)
	      request_size += (width - old_width) * num_out_glyphs;
	}
	/* If we will pass the max request size by adding this glyph,
	 * flush current glyphs.  Note that we account for a
	 * possible element being added below.
	 *
	 * Also flush if changing glyphsets, as Xrender limits one mask
	 * format per request, so we can either break up, or use a
	 * wide-enough mask format.  We do the former.  One reason to
	 * prefer the latter is the fact that Xserver ADDs all glyphs
	 * to the mask first, and then composes that to final surface,
	 * though it's not a big deal.
	 *
	 * If the glyph has a coordinate which cannot be represented
	 * as a 16-bit offset from the previous glyph, flush the
	 * current chunk. The current glyph will be the first one in
	 * the next chunk, thus its coordinates will be an offset from
	 * the destination origin. This offset is guaranteed to be
	 * representable as 16-bit offset (otherwise we would have
	 * fallen back).
	 */
	if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
	    this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
	    this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
	    (this_glyphset_info != glyphset)) {
	    status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
					 glyphs, i, info->font, info->use_mask,
					 op, src, src_x, src_y,
					 num_elts, old_width, glyphset);
	    if (unlikely (status))
		return status;
	    glyphs += i;
	    num_glyphs -= i;
	    i = 0;
	    max_index = glyphs[i].index;
	    width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
	    request_size = 0;
	    num_elts = 0;
	    num_out_glyphs = 0;
	    x = y = 0;
	    glyphset = this_glyphset_info;
	}
	/* Convert absolute glyph position to relative-to-current-point
	 * position */
	glyphs[i].i.x = this_x - x;
	glyphs[i].i.y = this_y - y;
	/* Start a new element for the first glyph,
	 * or for any glyph that has unexpected position,
	 * or if current element has too many glyphs.
	 *
	 * These same conditions are mirrored in _emit_glyphs_chunk().
	 */
      if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
	    num_elts++;
	    request_size += _cairo_sz_xGlyphElt;
	}
	/* adjust current-position */
	x = this_x + glyph->x_advance;
	y = this_y + glyph->y_advance;
	num_out_glyphs++;
	request_size += width;
    }
    if (num_elts) {
	status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
				     glyphs, i, info->font, info->use_mask,
				     op, src, src_x, src_y,
				     num_elts, width, glyphset);
    }
    return status;
}
const cairo_compositor_t *
4
_cairo_xlib_mask_compositor_get (void)
{
    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
    static cairo_mask_compositor_t compositor;
4
    if (_cairo_atomic_init_once_enter(&once)) {
4
	_cairo_mask_compositor_init (&compositor,
				     _cairo_xlib_fallback_compositor_get ());
4
	compositor.acquire = acquire;
4
	compositor.release = release;
4
	compositor.set_clip_region = set_clip_region;
4
	compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
4
	compositor.draw_image_boxes = draw_image_boxes;
4
	compositor.fill_rectangles = fill_rectangles;
4
	compositor.fill_boxes = fill_boxes;
4
	compositor.copy_boxes = copy_boxes;
4
	compositor.check_composite = check_composite;
4
	compositor.composite = composite;
	//compositor.check_composite_boxes = check_composite_boxes;
4
	compositor.composite_boxes = composite_boxes;
4
	compositor.check_composite_glyphs = check_composite_glyphs;
4
	compositor.composite_glyphs = composite_glyphs;
	_cairo_atomic_init_once_leave(&once);
    }
4
    return &compositor.base;
}
#define CAIRO_FIXED_16_16_MIN -32768
#define CAIRO_FIXED_16_16_MAX 32767
static cairo_bool_t
line_exceeds_16_16 (const cairo_line_t *line)
{
    return
	line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
	line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
	line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
	line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
	line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
	line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
	line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
	line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX);
}
static void
project_line_x_onto_16_16 (const cairo_line_t *line,
			    cairo_fixed_t top,
			    cairo_fixed_t bottom,
			    XLineFixed *out)
{
    cairo_point_double_t p1, p2;
    double m;
    p1.x = _cairo_fixed_to_double (line->p1.x);
    p1.y = _cairo_fixed_to_double (line->p1.y);
    p2.x = _cairo_fixed_to_double (line->p2.x);
    p2.y = _cairo_fixed_to_double (line->p2.y);
    m = (p2.x - p1.x) / (p2.y - p1.y);
    out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
    out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
}
#if 0
static cairo_int_status_T
check_composite_trapezoids ()
{
    operation = _categorize_composite_operation (dst, op, pattern, TRUE);
    if (operation == DO_UNSUPPORTED)
	return UNSUPPORTED ("unsupported operation");
    operation = _recategorize_composite_operation (dst, op, src,
						   &attributes, TRUE);
    if (operation == DO_UNSUPPORTED) {
	status = UNSUPPORTED ("unsupported operation");
	goto BAIL;
    }
}
#endif
static cairo_int_status_t
composite_traps (void			*abstract_dst,
		 cairo_operator_t	op,
		 cairo_surface_t	*abstract_src,
		 int			src_x,
		 int			src_y,
		 int			dst_x,
		 int			dst_y,
		 const cairo_rectangle_int_t *extents,
		 cairo_antialias_t	antialias,
		 cairo_traps_t		*traps)
{
    cairo_xlib_surface_t	*dst = abstract_dst;
    cairo_xlib_display_t        *display = dst->display;
    cairo_xlib_source_t		*src = (cairo_xlib_source_t *)abstract_src;
    XRenderPictFormat		*pict_format;
    XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
    XTrapezoid *xtraps = xtraps_stack;
    int dx, dy;
    int i;
    //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
    if (traps->num_traps == 0)
	return CAIRO_STATUS_SUCCESS;
    if (dst->base.is_clear &&
	(op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))
    {
	op = CAIRO_OPERATOR_SOURCE;
    }
    pict_format =
	_cairo_xlib_display_get_xrender_format (display,
						antialias == CAIRO_ANTIALIAS_NONE ?  CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
    if (traps->num_traps > ARRAY_LENGTH (xtraps_stack)) {
	xtraps = _cairo_malloc_ab (traps->num_traps, sizeof (XTrapezoid));
	if (unlikely (xtraps == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }
    dx = -dst_x << 16;
    dy = -dst_y << 16;
    for (i = 0; i < traps->num_traps; i++) {
	cairo_trapezoid_t *t = &traps->traps[i];
	/* top/bottom will be clamped to surface bounds */
	xtraps[i].top = _cairo_fixed_to_16_16(t->top) + dy;
	xtraps[i].bottom = _cairo_fixed_to_16_16(t->bottom) + dy;
	/* However, all the other coordinates will have been left untouched so
	 * as not to introduce numerical error. Recompute them if they
	 * exceed the 16.16 limits.
	 */
	if (unlikely (line_exceeds_16_16 (&t->left))) {
	    project_line_x_onto_16_16 (&t->left, t->top, t->bottom,
					&xtraps[i].left);
	    xtraps[i].left.p1.x += dx;
	    xtraps[i].left.p2.x += dx;
	    xtraps[i].left.p1.y = xtraps[i].top;
	    xtraps[i].left.p2.y = xtraps[i].bottom;
	} else {
	    xtraps[i].left.p1.x = _cairo_fixed_to_16_16(t->left.p1.x) + dx;
	    xtraps[i].left.p1.y = _cairo_fixed_to_16_16(t->left.p1.y) + dy;
	    xtraps[i].left.p2.x = _cairo_fixed_to_16_16(t->left.p2.x) + dx;
	    xtraps[i].left.p2.y = _cairo_fixed_to_16_16(t->left.p2.y) + dy;
	}
	if (unlikely (line_exceeds_16_16 (&t->right))) {
	    project_line_x_onto_16_16 (&t->right, t->top, t->bottom,
				       &xtraps[i].right);
	    xtraps[i].right.p1.x += dx;
	    xtraps[i].right.p2.x += dx;
	    xtraps[i].right.p1.y = xtraps[i].top;
	    xtraps[i].right.p2.y = xtraps[i].bottom;
	} else {
	    xtraps[i].right.p1.x = _cairo_fixed_to_16_16(t->right.p1.x) + dx;
	    xtraps[i].right.p1.y = _cairo_fixed_to_16_16(t->right.p1.y) + dy;
	    xtraps[i].right.p2.x = _cairo_fixed_to_16_16(t->right.p2.x) + dx;
	    xtraps[i].right.p2.y = _cairo_fixed_to_16_16(t->right.p2.y) + dy;
	}
    }
    if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
	src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p1.x);
	src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p1.y);
    } else {
	src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p2.x);
	src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p2.y);
    }
    src_x += dst_x;
    src_y += dst_y;
    _cairo_xlib_surface_ensure_picture (dst);
    _cairo_xlib_surface_set_precision (dst, antialias);
    XRenderCompositeTrapezoids (dst->dpy,
				_render_operator (op),
				src->picture, dst->picture,
				pict_format,
				src_x, src_y,
				xtraps, traps->num_traps);
    if (xtraps != xtraps_stack)
	free (xtraps);
    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
composite_tristrip (void		*abstract_dst,
		    cairo_operator_t	op,
		    cairo_surface_t	*abstract_src,
		    int			src_x,
		    int			src_y,
		    int			dst_x,
		    int			dst_y,
		    const cairo_rectangle_int_t *extents,
		    cairo_antialias_t	antialias,
		    cairo_tristrip_t	*strip)
{
    cairo_xlib_surface_t	*dst = abstract_dst;
    cairo_xlib_display_t        *display = dst->display;
    cairo_xlib_source_t		*src = (cairo_xlib_source_t *)abstract_src;
    XRenderPictFormat		*pict_format;
    XPointFixed points_stack[CAIRO_STACK_ARRAY_LENGTH (XPointFixed)];
    XPointFixed *points = points_stack;
    int dx, dy;
    int i;
    //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
    pict_format =
	_cairo_xlib_display_get_xrender_format (display,
						antialias == CAIRO_ANTIALIAS_NONE ?  CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
    if (strip->num_points > ARRAY_LENGTH (points_stack)) {
	points = _cairo_malloc_ab (strip->num_points, sizeof (XPointFixed));
	if (unlikely (points == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }
    dx = -dst_x << 16;
    dy = -dst_y << 16;
    for (i = 0; i < strip->num_points; i++) {
	cairo_point_t *p = &strip->points[i];
	points[i].x = _cairo_fixed_to_16_16(p->x) + dx;
	points[i].y = _cairo_fixed_to_16_16(p->y) + dy;
    }
    src_x += _cairo_fixed_16_16_floor (points[0].x) + dst_x;
    src_y += _cairo_fixed_16_16_floor (points[0].y) + dst_y;
    _cairo_xlib_surface_ensure_picture (dst);
    _cairo_xlib_surface_set_precision (dst, antialias);
    XRenderCompositeTriStrip (dst->dpy,
			      _render_operator (op),
			      src->picture, dst->picture,
			      pict_format,
			      src_x, src_y,
			      points, strip->num_points);
    if (points != points_stack)
	free (points);
    return CAIRO_STATUS_SUCCESS;
}
const cairo_compositor_t *
4
_cairo_xlib_traps_compositor_get (void)
{
    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
    static cairo_traps_compositor_t compositor;
4
    if (_cairo_atomic_init_once_enter(&once)) {
4
	_cairo_traps_compositor_init (&compositor,
				      _cairo_xlib_mask_compositor_get ());
4
	compositor.acquire = acquire;
4
	compositor.release = release;
4
	compositor.set_clip_region = set_clip_region;
4
	compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
4
	compositor.draw_image_boxes = draw_image_boxes;
4
	compositor.copy_boxes = copy_boxes;
4
	compositor.fill_boxes = fill_boxes;
4
	compositor.check_composite = check_composite;
4
	compositor.composite = composite;
4
	compositor.lerp = lerp;
	//compositor.check_composite_boxes = check_composite_boxes;
4
	compositor.composite_boxes = composite_boxes;
	//compositor.check_composite_traps = check_composite_traps;
4
	compositor.composite_traps = composite_traps;
	//compositor.check_composite_tristrip = check_composite_tristrip;
4
	compositor.composite_tristrip = composite_tristrip;
4
	compositor.check_composite_glyphs = check_composite_glyphs;
4
	compositor.composite_glyphs = composite_glyphs;
	_cairo_atomic_init_once_leave(&once);
    }
4
    return &compositor.base;
}
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */