Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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 
38
 *	Behdad Esfahbod 
39
 *	Chris Wilson 
40
 *	Karl Tomlinson , 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
check_composite (const cairo_composite_rectangles_t *extents)
60
{
61
    cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
62
 
63
    if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
64
	return CAIRO_INT_STATUS_UNSUPPORTED;
65
 
66
    return CAIRO_STATUS_SUCCESS;
67
}
68
 
69
static cairo_int_status_t
70
acquire (void *abstract_dst)
71
{
72
    cairo_xlib_surface_t *dst = abstract_dst;
73
    cairo_int_status_t status;
74
 
75
    status = _cairo_xlib_display_acquire (dst->base.device, &dst->display);
76
    if (unlikely (status))
77
        return status;
78
 
79
    dst->dpy = dst->display->display;
80
    return CAIRO_STATUS_SUCCESS;
81
}
82
 
83
static cairo_int_status_t
84
release (void *abstract_dst)
85
{
86
    cairo_xlib_surface_t *dst = abstract_dst;
87
 
88
    cairo_device_release (&dst->display->base);
89
    dst->dpy = NULL;
90
 
91
    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 (sizeof (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
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
    cairo_xlib_surface_t *dst = _dst;
392
    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
    if (! _cairo_xlib_surface_same_screen  (dst, src))
400
	return CAIRO_INT_STATUS_UNSUPPORTED;
401
 
402
    if (dst->depth != src->depth)
403
	return CAIRO_INT_STATUS_UNSUPPORTED;
404
 
405
    status = acquire (dst);
406
    if (unlikely (status))
407
	return status;
408
 
409
    status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
410
    if (unlikely (status)) {
411
	release (dst);
412
	return status;
413
    }
414
 
415
    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
	if (! src->owns_pixmap) {
421
	    XGCValues gcv;
422
 
423
	    gcv.subwindow_mode = IncludeInferiors;
424
	    XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
425
	}
426
	d = src->drawable;
427
    }
428
 
429
    if (boxes->num_boxes == 1) {
430
	int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
431
	int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
432
	int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
433
	int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
434
 
435
	XCopyArea (dst->dpy, d, dst->drawable, gc,
436
		   x1 + dx, y1 + dy,
437
		   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
    if (src->fallback && src->shm->damage->dirty) {
504
	_cairo_xlib_shm_surface_mark_active (src->shm);
505
    } else if (! src->owns_pixmap) {
506
	XGCValues gcv;
507
 
508
	gcv.subwindow_mode = ClipByChildren;
509
	XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
510
    }
511
 
512
    _cairo_xlib_surface_put_gc (dst->display, dst, gc);
513
    release (dst);
514
    return CAIRO_STATUS_SUCCESS;
515
}
516
 
517
static int
518
_render_operator (cairo_operator_t op)
519
{
520
    switch (op) {
521
    case CAIRO_OPERATOR_CLEAR:
522
	return PictOpClear;
523
 
524
    case CAIRO_OPERATOR_SOURCE:
525
	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
fill_reduces_to_source (cairo_operator_t op,
592
			const cairo_color_t *color,
593
			cairo_xlib_surface_t *dst)
594
{
595
    if (dst->base.is_clear || CAIRO_COLOR_IS_OPAQUE (color)) {
596
	if (op == CAIRO_OPERATOR_OVER)
597
	    return TRUE;
598
	if (op == CAIRO_OPERATOR_ADD)
599
	    return (dst->base.content & CAIRO_CONTENT_COLOR) == 0;
600
    }
601
 
602
    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
fill_boxes (void		*abstract_surface,
677
	    cairo_operator_t	 op,
678
	    const cairo_color_t	*color,
679
	    cairo_boxes_t	*boxes)
680
{
681
    cairo_xlib_surface_t *dst = abstract_surface;
682
    XRenderColor render_color;
683
 
684
    if (fill_reduces_to_source (op, color, dst))
685
	op = CAIRO_OPERATOR_SOURCE;
686
 
687
    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
    render_color.red   = color->red_short;
697
    render_color.green = color->green_short;
698
    render_color.blue  = color->blue_short;
699
    render_color.alpha = color->alpha_short;
700
 
701
    _cairo_xlib_surface_ensure_picture (dst);
702
    if (boxes->num_boxes == 1) {
703
	int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
704
	int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
705
	int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
706
	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
	XRenderFillRectangle (dst->dpy,
712
			      _render_operator (op),
713
			      dst->picture,
714
			      &render_color,
715
			      x1, y1,
716
			      x2 - x1, y2 - y1);
717
    } else {
718
	XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
719
	XRectangle *xrects = stack_xrects;
720
	struct _cairo_boxes_chunk *chunk;
721
	int i, j;
722
 
723
	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
	j = 0;
730
	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
731
	    for (i = 0; i < chunk->count; i++) {
732
		int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
733
		int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
734
		int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
735
		int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
736
 
737
		xrects[j].x = x1;
738
		xrects[j].y = y1;
739
		xrects[j].width  = x2 - x1;
740
		xrects[j].height = y2 - y1;
741
		j++;
742
	    }
743
	}
744
 
745
	XRenderFillRectangles (dst->dpy,
746
			       _render_operator (op),
747
			       dst->picture,
748
			       &render_color, xrects, j);
749
 
750
	if (xrects != stack_xrects)
751
	    free (xrects);
752
    }
753
 
754
    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 (status)
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 (&display->base);
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 = malloc (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);
1000
    priv->font = font;
1001
    cairo_list_add (&priv->link, &display->fonts);
1002
 
1003
    for (i = 0; i < NUM_GLYPHSETS; i++) {
1004
	cairo_xlib_font_glyphset_t *info = &priv->glyphset[i];
1005
	switch (i) {
1006
	case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break;
1007
	case GLYPHSET_INDEX_A8:     info->format = CAIRO_FORMAT_A8;     break;
1008
	case GLYPHSET_INDEX_A1:     info->format = CAIRO_FORMAT_A1;     break;
1009
	default:                    ASSERT_NOT_REACHED;                          break;
1010
	}
1011
	info->xrender_format = NULL;
1012
	info->glyphset = None;
1013
	info->to_free.count = 0;
1014
    }
1015
 
1016
    return priv;
1017
}
1018
 
1019
static int
1020
_cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
1021
{
1022
    if (format == CAIRO_FORMAT_A8)
1023
        return GLYPHSET_INDEX_A8;
1024
    if (format == CAIRO_FORMAT_A1)
1025
        return GLYPHSET_INDEX_A1;
1026
 
1027
    assert (format == CAIRO_FORMAT_ARGB32);
1028
    return GLYPHSET_INDEX_ARGB32;
1029
}
1030
 
1031
static inline cairo_xlib_font_t *
1032
_cairo_xlib_font_get (const cairo_xlib_display_t *display,
1033
		      cairo_scaled_font_t *font)
1034
{
1035
    return (cairo_xlib_font_t *)_cairo_scaled_font_find_private (font, display);
1036
}
1037
 
1038
typedef struct {
1039
    cairo_scaled_glyph_private_t base;
1040
 
1041
 
1042
    cairo_xlib_font_glyphset_t *glyphset;
1043
} cairo_xlib_glyph_private_t;
1044
 
1045
static void
1046
_cairo_xlib_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
1047
			cairo_scaled_glyph_t *glyph,
1048
			cairo_scaled_font_t  *font)
1049
{
1050
    cairo_xlib_glyph_private_t *priv = (cairo_xlib_glyph_private_t *)glyph_private;
1051
 
1052
    if (! font->finished) {
1053
	cairo_xlib_font_t *font_private;
1054
	struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
1055
	cairo_xlib_font_glyphset_t *info;
1056
 
1057
	font_private = _cairo_xlib_font_get (glyph_private->key, font);
1058
	assert (font_private);
1059
 
1060
	info = priv->glyphset;
1061
	to_free = &info->to_free;
1062
	if (to_free->count == ARRAY_LENGTH (to_free->indices)) {
1063
	    cairo_xlib_display_t *display;
1064
 
1065
	    if (_cairo_xlib_display_acquire (font_private->device,
1066
					     &display) == CAIRO_STATUS_SUCCESS) {
1067
		XRenderFreeGlyphs (display->display,
1068
				   info->glyphset,
1069
				   to_free->indices,
1070
				   to_free->count);
1071
		cairo_device_release (&display->base);
1072
	    }
1073
 
1074
	    to_free->count = 0;
1075
	}
1076
 
1077
	to_free->indices[to_free->count++] =
1078
	    _cairo_scaled_glyph_index (glyph);
1079
    }
1080
 
1081
    cairo_list_del (&glyph_private->link);
1082
    free (glyph_private);
1083
}
1084
 
1085
static cairo_status_t
1086
_cairo_xlib_glyph_attach (cairo_xlib_display_t	*display,
1087
			  cairo_scaled_glyph_t	*glyph,
1088
			  cairo_xlib_font_glyphset_t *info)
1089
{
1090
    cairo_xlib_glyph_private_t *priv;
1091
 
1092
    priv = malloc (sizeof (*priv));
1093
    if (unlikely (priv == NULL))
1094
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1095
 
1096
    _cairo_scaled_glyph_attach_private (glyph, &priv->base, display,
1097
					_cairo_xlib_glyph_fini);
1098
    priv->glyphset = info;
1099
 
1100
    glyph->dev_private = info;
1101
    glyph->dev_private_key = display;
1102
    return CAIRO_STATUS_SUCCESS;
1103
}
1104
 
1105
static cairo_xlib_font_glyphset_t *
1106
_cairo_xlib_font_get_glyphset_info_for_format (cairo_xlib_display_t *display,
1107
					       cairo_scaled_font_t *font,
1108
					       cairo_format_t       format)
1109
{
1110
    cairo_xlib_font_t *priv;
1111
    cairo_xlib_font_glyphset_t *info;
1112
    int glyphset_index;
1113
 
1114
    glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
1115
 
1116
    priv = _cairo_xlib_font_get (display, font);
1117
    if (priv == NULL) {
1118
	priv = _cairo_xlib_font_create (display, font);
1119
	if (priv == NULL)
1120
	    return NULL;
1121
    }
1122
 
1123
    info = &priv->glyphset[glyphset_index];
1124
    if (info->glyphset == None) {
1125
	info->xrender_format =
1126
	    _cairo_xlib_display_get_xrender_format (display, info->format);
1127
	info->glyphset = XRenderCreateGlyphSet (display->display,
1128
						info->xrender_format);
1129
    }
1130
 
1131
    return info;
1132
}
1133
 
1134
static cairo_bool_t
1135
has_pending_free_glyph (cairo_xlib_font_glyphset_t *info,
1136
			unsigned long glyph_index)
1137
{
1138
    struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
1139
    int i;
1140
 
1141
    to_free = &info->to_free;
1142
    for (i = 0; i < to_free->count; i++) {
1143
	if (to_free->indices[i] == glyph_index) {
1144
	    to_free->count--;
1145
	    memmove (&to_free->indices[i],
1146
		     &to_free->indices[i+1],
1147
		     (to_free->count - i) * sizeof (to_free->indices[0]));
1148
	    return TRUE;
1149
	}
1150
    }
1151
 
1152
    return FALSE;
1153
}
1154
 
1155
static cairo_xlib_font_glyphset_t *
1156
find_pending_free_glyph (cairo_xlib_display_t *display,
1157
			 cairo_scaled_font_t *font,
1158
			 unsigned long glyph_index,
1159
			 cairo_image_surface_t *surface)
1160
{
1161
    cairo_xlib_font_t *priv;
1162
    int i;
1163
 
1164
    priv = _cairo_xlib_font_get (display, font);
1165
    if (priv == NULL)
1166
	return NULL;
1167
 
1168
    if (surface != NULL) {
1169
	i = _cairo_xlib_get_glyphset_index_for_format (surface->format);
1170
	if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
1171
	    return &priv->glyphset[i];
1172
    } else {
1173
	for (i = 0; i < NUM_GLYPHSETS; i++) {
1174
	    if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
1175
		return &priv->glyphset[i];
1176
	}
1177
    }
1178
 
1179
    return NULL;
1180
}
1181
 
1182
static cairo_status_t
1183
_cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
1184
			       cairo_scaled_font_t   *font,
1185
			       cairo_scaled_glyph_t **pscaled_glyph)
1186
{
1187
    XGlyphInfo glyph_info;
1188
    unsigned long glyph_index;
1189
    unsigned char *data;
1190
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1191
    cairo_scaled_glyph_t *glyph = *pscaled_glyph;
1192
    cairo_image_surface_t *glyph_surface = glyph->surface;
1193
    cairo_bool_t already_had_glyph_surface;
1194
    cairo_xlib_font_glyphset_t *info;
1195
 
1196
    glyph_index = _cairo_scaled_glyph_index (glyph);
1197
 
1198
    /* check to see if we have a pending XRenderFreeGlyph for this glyph */
1199
    info = find_pending_free_glyph (display, font, glyph_index, glyph_surface);
1200
    if (info != NULL)
1201
	return _cairo_xlib_glyph_attach (display, glyph, info);
1202
 
1203
    if (glyph_surface == NULL) {
1204
	status = _cairo_scaled_glyph_lookup (font,
1205
					     glyph_index,
1206
					     CAIRO_SCALED_GLYPH_INFO_METRICS |
1207
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
1208
					     pscaled_glyph);
1209
	if (unlikely (status))
1210
	    return status;
1211
 
1212
	glyph = *pscaled_glyph;
1213
	glyph_surface = glyph->surface;
1214
	already_had_glyph_surface = FALSE;
1215
    } else {
1216
	already_had_glyph_surface = TRUE;
1217
    }
1218
 
1219
    info = _cairo_xlib_font_get_glyphset_info_for_format (display, font,
1220
							  glyph_surface->format);
1221
 
1222
#if 0
1223
    /* If the glyph surface has zero height or width, we create
1224
     * a clear 1x1 surface, to avoid various X server bugs.
1225
     */
1226
    if (glyph_surface->width == 0 || glyph_surface->height == 0) {
1227
	cairo_surface_t *tmp_surface;
1228
 
1229
	tmp_surface = cairo_image_surface_create (info->format, 1, 1);
1230
	status = tmp_surface->status;
1231
	if (unlikely (status))
1232
	    goto BAIL;
1233
 
1234
	tmp_surface->device_transform = glyph_surface->base.device_transform;
1235
	tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
1236
 
1237
	glyph_surface = (cairo_image_surface_t *) tmp_surface;
1238
    }
1239
#endif
1240
 
1241
    /* If the glyph format does not match the font format, then we
1242
     * create a temporary surface for the glyph image with the font's
1243
     * format.
1244
     */
1245
    if (glyph_surface->format != info->format) {
1246
	cairo_surface_pattern_t pattern;
1247
	cairo_surface_t *tmp_surface;
1248
 
1249
	tmp_surface = cairo_image_surface_create (info->format,
1250
						  glyph_surface->width,
1251
						  glyph_surface->height);
1252
	status = tmp_surface->status;
1253
	if (unlikely (status))
1254
	    goto BAIL;
1255
 
1256
	tmp_surface->device_transform = glyph_surface->base.device_transform;
1257
	tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
1258
 
1259
	_cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
1260
	status = _cairo_surface_paint (tmp_surface,
1261
				       CAIRO_OPERATOR_SOURCE, &pattern.base,
1262
				       NULL);
1263
	_cairo_pattern_fini (&pattern.base);
1264
 
1265
	glyph_surface = (cairo_image_surface_t *) tmp_surface;
1266
 
1267
	if (unlikely (status))
1268
	    goto BAIL;
1269
    }
1270
 
1271
    /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
1272
    glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
1273
    glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
1274
    glyph_info.width = glyph_surface->width;
1275
    glyph_info.height = glyph_surface->height;
1276
    glyph_info.xOff = glyph->x_advance;
1277
    glyph_info.yOff = glyph->y_advance;
1278
 
1279
    data = glyph_surface->data;
1280
 
1281
    /* flip formats around */
1282
    switch (_cairo_xlib_get_glyphset_index_for_format (glyph->surface->format)) {
1283
    case GLYPHSET_INDEX_A1:
1284
	/* local bitmaps are always stored with bit == byte */
1285
	if (_cairo_is_little_endian() != (BitmapBitOrder (display->display) == LSBFirst)) {
1286
	    int		    c = glyph_surface->stride * glyph_surface->height;
1287
	    unsigned char   *d;
1288
	    unsigned char   *new, *n;
1289
 
1290
	    new = malloc (c);
1291
	    if (!new) {
1292
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1293
		goto BAIL;
1294
	    }
1295
	    n = new;
1296
	    d = data;
1297
	    do {
1298
		char	b = *d++;
1299
		b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
1300
		b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
1301
		b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
1302
		*n++ = b;
1303
	    } while (--c);
1304
	    data = new;
1305
	}
1306
	break;
1307
    case GLYPHSET_INDEX_A8:
1308
	break;
1309
    case GLYPHSET_INDEX_ARGB32:
1310
	if (_cairo_is_little_endian() != (ImageByteOrder (display->display) == LSBFirst)) {
1311
	    unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
1312
	    const uint32_t *d;
1313
	    uint32_t *new, *n;
1314
 
1315
	    new = malloc (4 * c);
1316
	    if (unlikely (new == NULL)) {
1317
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1318
		goto BAIL;
1319
	    }
1320
	    n = new;
1321
	    d = (uint32_t *) data;
1322
	    do {
1323
		*n++ = bswap_32 (*d);
1324
		d++;
1325
	    } while (--c);
1326
	    data = (uint8_t *) new;
1327
	}
1328
	break;
1329
    default:
1330
	ASSERT_NOT_REACHED;
1331
	break;
1332
    }
1333
    /* XXX assume X server wants pixman padding. Xft assumes this as well */
1334
 
1335
    XRenderAddGlyphs (display->display, info->glyphset,
1336
		      &glyph_index, &glyph_info, 1,
1337
		      (char *) data,
1338
		      glyph_surface->stride * glyph_surface->height);
1339
 
1340
    if (data != glyph_surface->data)
1341
	free (data);
1342
 
1343
    status = _cairo_xlib_glyph_attach (display, glyph, info);
1344
 
1345
 BAIL:
1346
    if (glyph_surface != glyph->surface)
1347
	cairo_surface_destroy (&glyph_surface->base);
1348
 
1349
    /* if the scaled glyph didn't already have a surface attached
1350
     * to it, release the created surface now that we have it
1351
     * uploaded to the X server.  If the surface has already been
1352
     * there (eg. because image backend requested it), leave it in
1353
     * the cache
1354
     */
1355
    if (!already_had_glyph_surface)
1356
	_cairo_scaled_glyph_set_surface (glyph, font, NULL);
1357
 
1358
    return status;
1359
}
1360
 
1361
typedef void (*cairo_xrender_composite_text_func_t)
1362
	      (Display                      *dpy,
1363
	       int                          op,
1364
	       Picture                      src,
1365
	       Picture                      dst,
1366
	       _Xconst XRenderPictFormat    *maskFormat,
1367
	       int                          xSrc,
1368
	       int                          ySrc,
1369
	       int                          xDst,
1370
	       int                          yDst,
1371
	       _Xconst XGlyphElt8           *elts,
1372
	       int                          nelt);
1373
 
1374
/* Build a struct of the same size of #cairo_glyph_t that can be used both as
1375
 * an input glyph with double coordinates, and as "working" glyph with
1376
 * integer from-current-point offsets. */
1377
typedef union {
1378
    cairo_glyph_t d;
1379
    unsigned long index;
1380
    struct {
1381
        unsigned long index;
1382
        int x;
1383
        int y;
1384
    } i;
1385
} cairo_xlib_glyph_t;
1386
 
1387
/* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
1388
COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
1389
 
1390
/* Start a new element for the first glyph,
1391
 * or for any glyph that has unexpected position,
1392
 * or if current element has too many glyphs
1393
 * (Xrender limits each element to 252 glyphs, we limit them to 128)
1394
 *
1395
 * These same conditions need to be mirrored between
1396
 * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
1397
 */
1398
#define _start_new_glyph_elt(count, glyph) \
1399
    (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
1400
 
1401
static cairo_status_t
1402
_emit_glyphs_chunk (cairo_xlib_display_t *display,
1403
                    cairo_xlib_surface_t *dst,
1404
		    int dst_x, int dst_y,
1405
		    cairo_xlib_glyph_t *glyphs,
1406
		    int num_glyphs,
1407
		    cairo_scaled_font_t *font,
1408
		    cairo_bool_t use_mask,
1409
		    cairo_operator_t op,
1410
		    cairo_xlib_source_t *src,
1411
		    int src_x, int src_y,
1412
		    /* info for this chunk */
1413
		    int num_elts,
1414
		    int width,
1415
		    cairo_xlib_font_glyphset_t *info)
1416
{
1417
    /* Which XRenderCompositeText function to use */
1418
    cairo_xrender_composite_text_func_t composite_text_func;
1419
    int size;
1420
 
1421
    /* Element buffer stuff */
1422
    XGlyphElt8 *elts;
1423
    XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
1424
 
1425
    /* Reuse the input glyph array for output char generation */
1426
    char *char8 = (char *) glyphs;
1427
    unsigned short *char16 = (unsigned short *) glyphs;
1428
    unsigned int *char32 = (unsigned int *) glyphs;
1429
 
1430
    int i;
1431
    int nelt; /* Element index */
1432
    int n; /* Num output glyphs in current element */
1433
    int j; /* Num output glyphs so far */
1434
 
1435
    switch (width) {
1436
    case 1:
1437
	/* don't cast the 8-variant, to catch possible mismatches */
1438
	composite_text_func = XRenderCompositeText8;
1439
	size = sizeof (char);
1440
	break;
1441
    case 2:
1442
	composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
1443
	size = sizeof (unsigned short);
1444
	break;
1445
    default:
1446
    case 4:
1447
	composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
1448
	size = sizeof (unsigned int);
1449
    }
1450
 
1451
    /* Allocate element array */
1452
    if (num_elts <= ARRAY_LENGTH (stack_elts)) {
1453
      elts = stack_elts;
1454
    } else {
1455
      elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
1456
      if (unlikely (elts == NULL))
1457
	  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1458
    }
1459
 
1460
    /* Fill them in */
1461
    nelt = 0;
1462
    n = 0;
1463
    j = 0;
1464
    for (i = 0; i < num_glyphs; i++) {
1465
      /* Start a new element for first output glyph,
1466
       * or for any glyph that has unexpected position,
1467
       * or if current element has too many glyphs.
1468
       *
1469
       * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
1470
       */
1471
      if (_start_new_glyph_elt (j, &glyphs[i])) {
1472
	  if (j) {
1473
	      elts[nelt].nchars = n;
1474
	      nelt++;
1475
	      n = 0;
1476
	  }
1477
	  elts[nelt].chars = char8 + size * j;
1478
	  elts[nelt].glyphset = info->glyphset;
1479
	  elts[nelt].xOff = glyphs[i].i.x;
1480
	  elts[nelt].yOff = glyphs[i].i.y;
1481
      }
1482
 
1483
      switch (width) {
1484
      case 1: char8 [j] = (char)           glyphs[i].index; break;
1485
      case 2: char16[j] = (unsigned short) glyphs[i].index; break;
1486
      default:
1487
      case 4: char32[j] = (unsigned int)   glyphs[i].index; break;
1488
      }
1489
 
1490
      n++;
1491
      j++;
1492
    }
1493
 
1494
    if (n) {
1495
	elts[nelt].nchars = n;
1496
	nelt++;
1497
    }
1498
 
1499
    /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
1500
     * expected number of xGlyphElts.  */
1501
    assert (nelt == num_elts);
1502
 
1503
    composite_text_func (display->display, op,
1504
			 src->picture,
1505
			 dst->picture,
1506
			 use_mask ? info->xrender_format : NULL,
1507
			 src_x + elts[0].xOff + dst_x,
1508
			 src_y + elts[0].yOff + dst_y,
1509
			 elts[0].xOff, elts[0].yOff,
1510
			 (XGlyphElt8 *) elts, nelt);
1511
 
1512
    if (elts != stack_elts)
1513
      free (elts);
1514
 
1515
    return CAIRO_STATUS_SUCCESS;
1516
}
1517
 
1518
static cairo_int_status_t
1519
check_composite_glyphs (const cairo_composite_rectangles_t *extents,
1520
			cairo_scaled_font_t *font,
1521
			cairo_glyph_t *glyphs,
1522
			int *num_glyphs)
1523
{
1524
    cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface;
1525
    cairo_xlib_display_t *display = dst->display;
1526
    int max_request_size, size;
1527
 
1528
    TRACE ((stderr, "%s\n", __FUNCTION__));
1529
 
1530
    if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
1531
	return CAIRO_INT_STATUS_UNSUPPORTED;
1532
 
1533
    /* The glyph coordinates must be representable in an int16_t.
1534
     * When possible, they will be expressed as an offset from the
1535
     * previous glyph, otherwise they will be an offset from the
1536
     * surface origin. If we can't guarantee this to be possible,
1537
     * fallback.
1538
     */
1539
    if (extents->bounded.x + extents->bounded.width > INT16_MAX ||
1540
	extents->bounded.y + extents->bounded.height> INT16_MAX ||
1541
	extents->bounded.x < INT16_MIN ||
1542
	extents->bounded.y < INT16_MIN)
1543
    {
1544
	return CAIRO_INT_STATUS_UNSUPPORTED;
1545
    }
1546
 
1547
    /* Approximate the size of the largest glyph and fallback if we can not
1548
     * upload it to the xserver.
1549
     */
1550
    size = ceil (font->max_scale);
1551
    size = 4 * size * size;
1552
    max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display)
1553
			: XMaxRequestSize (display->display)) * 4 -
1554
	sz_xRenderAddGlyphsReq -
1555
	sz_xGlyphInfo          -
1556
	8;
1557
    if (size >= max_request_size)
1558
	return CAIRO_INT_STATUS_UNSUPPORTED;
1559
 
1560
    return CAIRO_STATUS_SUCCESS;
1561
}
1562
 
1563
/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
1564
 * enough room for padding */
1565
#define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
1566
 
1567
static cairo_int_status_t
1568
composite_glyphs (void				*surface,
1569
		  cairo_operator_t		 op,
1570
		  cairo_surface_t		*_src,
1571
		  int				 src_x,
1572
		  int				 src_y,
1573
		  int				 dst_x,
1574
		  int				 dst_y,
1575
		  cairo_composite_glyphs_info_t *info)
1576
{
1577
    cairo_xlib_surface_t *dst = surface;
1578
    cairo_xlib_glyph_t *glyphs = (cairo_xlib_glyph_t *)info->glyphs;
1579
    cairo_xlib_source_t *src = (cairo_xlib_source_t *)_src;
1580
    cairo_xlib_display_t *display = dst->display;
1581
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1582
    cairo_scaled_glyph_t *glyph;
1583
    cairo_fixed_t x = dst_x, y = dst_y;
1584
    cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info;
1585
 
1586
    unsigned long max_index = 0;
1587
    int width = 1;
1588
    int num_elts = 0;
1589
    int num_out_glyphs = 0;
1590
    int num_glyphs = info->num_glyphs;
1591
 
1592
    int max_request_size = XMaxRequestSize (display->display) * 4
1593
			 - MAX (sz_xRenderCompositeGlyphs8Req,
1594
				MAX(sz_xRenderCompositeGlyphs16Req,
1595
				    sz_xRenderCompositeGlyphs32Req));
1596
    int request_size = 0;
1597
    int i;
1598
 
1599
    op = _render_operator (op),
1600
    _cairo_xlib_surface_ensure_picture (dst);
1601
    for (i = 0; i < num_glyphs; i++) {
1602
	int this_x, this_y;
1603
	int old_width;
1604
 
1605
	status = _cairo_scaled_glyph_lookup (info->font,
1606
					     glyphs[i].index,
1607
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
1608
					     &glyph);
1609
	if (unlikely (status))
1610
	    return status;
1611
 
1612
	this_x = _cairo_lround (glyphs[i].d.x);
1613
	this_y = _cairo_lround (glyphs[i].d.y);
1614
 
1615
	/* Send unsent glyphs to the server */
1616
	if (glyph->dev_private_key != display) {
1617
	    status = _cairo_xlib_surface_add_glyph (display, info->font, &glyph);
1618
	    if (unlikely (status))
1619
		return status;
1620
	}
1621
 
1622
	this_glyphset_info = glyph->dev_private;
1623
	if (!glyphset)
1624
	    glyphset = this_glyphset_info;
1625
 
1626
	/* The invariant here is that we can always flush the glyphs
1627
	 * accumulated before this one, using old_width, and they
1628
	 * would fit in the request.
1629
	 */
1630
	old_width = width;
1631
 
1632
	/* Update max glyph index */
1633
	if (glyphs[i].index > max_index) {
1634
	    max_index = glyphs[i].index;
1635
	    if (max_index >= 65536)
1636
	      width = 4;
1637
	    else if (max_index >= 256)
1638
	      width = 2;
1639
	    if (width != old_width)
1640
	      request_size += (width - old_width) * num_out_glyphs;
1641
	}
1642
 
1643
	/* If we will pass the max request size by adding this glyph,
1644
	 * flush current glyphs.  Note that we account for a
1645
	 * possible element being added below.
1646
	 *
1647
	 * Also flush if changing glyphsets, as Xrender limits one mask
1648
	 * format per request, so we can either break up, or use a
1649
	 * wide-enough mask format.  We do the former.  One reason to
1650
	 * prefer the latter is the fact that Xserver ADDs all glyphs
1651
	 * to the mask first, and then composes that to final surface,
1652
	 * though it's not a big deal.
1653
	 *
1654
	 * If the glyph has a coordinate which cannot be represented
1655
	 * as a 16-bit offset from the previous glyph, flush the
1656
	 * current chunk. The current glyph will be the first one in
1657
	 * the next chunk, thus its coordinates will be an offset from
1658
	 * the destination origin. This offset is guaranteed to be
1659
	 * representable as 16-bit offset (otherwise we would have
1660
	 * fallen back).
1661
	 */
1662
	if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
1663
	    this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
1664
	    this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
1665
	    (this_glyphset_info != glyphset)) {
1666
	    status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
1667
					 glyphs, i, info->font, info->use_mask,
1668
					 op, src, src_x, src_y,
1669
					 num_elts, old_width, glyphset);
1670
	    if (unlikely (status))
1671
		return status;
1672
 
1673
	    glyphs += i;
1674
	    num_glyphs -= i;
1675
	    i = 0;
1676
	    max_index = glyphs[i].index;
1677
	    width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
1678
	    request_size = 0;
1679
	    num_elts = 0;
1680
	    num_out_glyphs = 0;
1681
	    x = y = 0;
1682
	    glyphset = this_glyphset_info;
1683
	}
1684
 
1685
	/* Convert absolute glyph position to relative-to-current-point
1686
	 * position */
1687
	glyphs[i].i.x = this_x - x;
1688
	glyphs[i].i.y = this_y - y;
1689
 
1690
	/* Start a new element for the first glyph,
1691
	 * or for any glyph that has unexpected position,
1692
	 * or if current element has too many glyphs.
1693
	 *
1694
	 * These same conditions are mirrored in _emit_glyphs_chunk().
1695
	 */
1696
      if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
1697
	    num_elts++;
1698
	    request_size += _cairo_sz_xGlyphElt;
1699
	}
1700
 
1701
	/* adjust current-position */
1702
	x = this_x + glyph->x_advance;
1703
	y = this_y + glyph->y_advance;
1704
 
1705
	num_out_glyphs++;
1706
	request_size += width;
1707
    }
1708
 
1709
    if (num_elts) {
1710
	status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
1711
				     glyphs, i, info->font, info->use_mask,
1712
				     op, src, src_x, src_y,
1713
				     num_elts, width, glyphset);
1714
    }
1715
 
1716
    return status;
1717
}
1718
 
1719
const cairo_compositor_t *
1720
_cairo_xlib_mask_compositor_get (void)
1721
{
1722
    static cairo_mask_compositor_t compositor;
1723
 
1724
    if (compositor.base.delegate == NULL) {
1725
	_cairo_mask_compositor_init (&compositor,
1726
				     _cairo_xlib_fallback_compositor_get ());
1727
 
1728
	compositor.acquire = acquire;
1729
	compositor.release = release;
1730
	compositor.set_clip_region = set_clip_region;
1731
	compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
1732
	compositor.draw_image_boxes = draw_image_boxes;
1733
	compositor.fill_rectangles = fill_rectangles;
1734
	compositor.fill_boxes = fill_boxes;
1735
	compositor.copy_boxes = copy_boxes;
1736
	compositor.check_composite = check_composite;
1737
	compositor.composite = composite;
1738
	//compositor.check_composite_boxes = check_composite_boxes;
1739
	compositor.composite_boxes = composite_boxes;
1740
	compositor.check_composite_glyphs = check_composite_glyphs;
1741
	compositor.composite_glyphs = composite_glyphs;
1742
    }
1743
 
1744
    return &compositor.base;
1745
}
1746
 
1747
#define CAIRO_FIXED_16_16_MIN -32768
1748
#define CAIRO_FIXED_16_16_MAX 32767
1749
 
1750
static cairo_bool_t
1751
line_exceeds_16_16 (const cairo_line_t *line)
1752
{
1753
    return
1754
	line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1755
	line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
1756
	line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1757
	line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
1758
	line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1759
	line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
1760
	line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1761
	line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX);
1762
}
1763
 
1764
static void
1765
project_line_x_onto_16_16 (const cairo_line_t *line,
1766
			    cairo_fixed_t top,
1767
			    cairo_fixed_t bottom,
1768
			    XLineFixed *out)
1769
{
1770
    cairo_point_double_t p1, p2;
1771
    double m;
1772
 
1773
    p1.x = _cairo_fixed_to_double (line->p1.x);
1774
    p1.y = _cairo_fixed_to_double (line->p1.y);
1775
 
1776
    p2.x = _cairo_fixed_to_double (line->p2.x);
1777
    p2.y = _cairo_fixed_to_double (line->p2.y);
1778
 
1779
    m = (p2.x - p1.x) / (p2.y - p1.y);
1780
    out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
1781
    out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
1782
}
1783
#if 0
1784
static cairo_int_status_T
1785
check_composite_trapezoids ()
1786
{
1787
    operation = _categorize_composite_operation (dst, op, pattern, TRUE);
1788
    if (operation == DO_UNSUPPORTED)
1789
	return UNSUPPORTED ("unsupported operation");
1790
 
1791
    operation = _recategorize_composite_operation (dst, op, src,
1792
						   &attributes, TRUE);
1793
    if (operation == DO_UNSUPPORTED) {
1794
	status = UNSUPPORTED ("unsupported operation");
1795
	goto BAIL;
1796
    }
1797
 
1798
}
1799
#endif
1800
 
1801
static cairo_int_status_t
1802
composite_traps (void			*abstract_dst,
1803
		 cairo_operator_t	op,
1804
		 cairo_surface_t	*abstract_src,
1805
		 int			src_x,
1806
		 int			src_y,
1807
		 int			dst_x,
1808
		 int			dst_y,
1809
		 const cairo_rectangle_int_t *extents,
1810
		 cairo_antialias_t	antialias,
1811
		 cairo_traps_t		*traps)
1812
{
1813
    cairo_xlib_surface_t	*dst = abstract_dst;
1814
    cairo_xlib_display_t        *display = dst->display;
1815
    cairo_xlib_source_t		*src = (cairo_xlib_source_t *)abstract_src;
1816
    XRenderPictFormat		*pict_format;
1817
    XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
1818
    XTrapezoid *xtraps = xtraps_stack;
1819
    int dx, dy;
1820
    int i;
1821
 
1822
    //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1823
 
1824
    if (dst->base.is_clear &&
1825
	(op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))
1826
    {
1827
	op = CAIRO_OPERATOR_SOURCE;
1828
    }
1829
 
1830
    pict_format =
1831
	_cairo_xlib_display_get_xrender_format (display,
1832
						antialias == CAIRO_ANTIALIAS_NONE ?  CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
1833
 
1834
    if (traps->num_traps > ARRAY_LENGTH (xtraps_stack)) {
1835
	xtraps = _cairo_malloc_ab (traps->num_traps, sizeof (XTrapezoid));
1836
	if (unlikely (xtraps == NULL))
1837
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1838
    }
1839
 
1840
    dx = -dst_x << 16;
1841
    dy = -dst_y << 16;
1842
    for (i = 0; i < traps->num_traps; i++) {
1843
	cairo_trapezoid_t *t = &traps->traps[i];
1844
 
1845
	/* top/bottom will be clamped to surface bounds */
1846
	xtraps[i].top = _cairo_fixed_to_16_16(t->top) + dy;
1847
	xtraps[i].bottom = _cairo_fixed_to_16_16(t->bottom) + dy;
1848
 
1849
	/* However, all the other coordinates will have been left untouched so
1850
	 * as not to introduce numerical error. Recompute them if they
1851
	 * exceed the 16.16 limits.
1852
	 */
1853
	if (unlikely (line_exceeds_16_16 (&t->left))) {
1854
	    project_line_x_onto_16_16 (&t->left, t->top, t->bottom,
1855
					&xtraps[i].left);
1856
	    xtraps[i].left.p1.x += dx;
1857
	    xtraps[i].left.p2.x += dx;
1858
	    xtraps[i].left.p1.y = xtraps[i].top;
1859
	    xtraps[i].left.p2.y = xtraps[i].bottom;
1860
	} else {
1861
	    xtraps[i].left.p1.x = _cairo_fixed_to_16_16(t->left.p1.x) + dx;
1862
	    xtraps[i].left.p1.y = _cairo_fixed_to_16_16(t->left.p1.y) + dy;
1863
	    xtraps[i].left.p2.x = _cairo_fixed_to_16_16(t->left.p2.x) + dx;
1864
	    xtraps[i].left.p2.y = _cairo_fixed_to_16_16(t->left.p2.y) + dy;
1865
	}
1866
 
1867
	if (unlikely (line_exceeds_16_16 (&t->right))) {
1868
	    project_line_x_onto_16_16 (&t->right, t->top, t->bottom,
1869
				       &xtraps[i].right);
1870
	    xtraps[i].right.p1.x += dx;
1871
	    xtraps[i].right.p2.x += dx;
1872
	    xtraps[i].right.p1.y = xtraps[i].top;
1873
	    xtraps[i].right.p2.y = xtraps[i].bottom;
1874
	} else {
1875
	    xtraps[i].right.p1.x = _cairo_fixed_to_16_16(t->right.p1.x) + dx;
1876
	    xtraps[i].right.p1.y = _cairo_fixed_to_16_16(t->right.p1.y) + dy;
1877
	    xtraps[i].right.p2.x = _cairo_fixed_to_16_16(t->right.p2.x) + dx;
1878
	    xtraps[i].right.p2.y = _cairo_fixed_to_16_16(t->right.p2.y) + dy;
1879
	}
1880
    }
1881
 
1882
    if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
1883
	src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p1.x);
1884
	src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p1.y);
1885
    } else {
1886
	src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p2.x);
1887
	src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p2.y);
1888
    }
1889
    src_x += dst_x;
1890
    src_y += dst_y;
1891
 
1892
    _cairo_xlib_surface_ensure_picture (dst);
1893
    _cairo_xlib_surface_set_precision (dst, antialias);
1894
    XRenderCompositeTrapezoids (dst->dpy,
1895
				_render_operator (op),
1896
				src->picture, dst->picture,
1897
				pict_format,
1898
				src_x, src_y,
1899
				xtraps, traps->num_traps);
1900
 
1901
    if (xtraps != xtraps_stack)
1902
	free (xtraps);
1903
 
1904
    return CAIRO_STATUS_SUCCESS;
1905
}
1906
 
1907
static cairo_int_status_t
1908
composite_tristrip (void		*abstract_dst,
1909
		    cairo_operator_t	op,
1910
		    cairo_surface_t	*abstract_src,
1911
		    int			src_x,
1912
		    int			src_y,
1913
		    int			dst_x,
1914
		    int			dst_y,
1915
		    const cairo_rectangle_int_t *extents,
1916
		    cairo_antialias_t	antialias,
1917
		    cairo_tristrip_t	*strip)
1918
{
1919
    cairo_xlib_surface_t	*dst = abstract_dst;
1920
    cairo_xlib_display_t        *display = dst->display;
1921
    cairo_xlib_source_t		*src = (cairo_xlib_source_t *)abstract_src;
1922
    XRenderPictFormat		*pict_format;
1923
    XPointFixed points_stack[CAIRO_STACK_ARRAY_LENGTH (XPointFixed)];
1924
    XPointFixed *points = points_stack;
1925
    int dx, dy;
1926
    int i;
1927
 
1928
    //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1929
 
1930
    pict_format =
1931
	_cairo_xlib_display_get_xrender_format (display,
1932
						antialias == CAIRO_ANTIALIAS_NONE ?  CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
1933
 
1934
    if (strip->num_points > ARRAY_LENGTH (points_stack)) {
1935
	points = _cairo_malloc_ab (strip->num_points, sizeof (XPointFixed));
1936
	if (unlikely (points == NULL))
1937
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1938
    }
1939
 
1940
    dx = -dst_x << 16;
1941
    dy = -dst_y << 16;
1942
    for (i = 0; i < strip->num_points; i++) {
1943
	cairo_point_t *p = &strip->points[i];
1944
 
1945
	points[i].x = _cairo_fixed_to_16_16(p->x) + dx;
1946
	points[i].y = _cairo_fixed_to_16_16(p->y) + dy;
1947
    }
1948
 
1949
    src_x += _cairo_fixed_16_16_floor (points[0].x) + dst_x;
1950
    src_y += _cairo_fixed_16_16_floor (points[0].y) + dst_y;
1951
 
1952
    _cairo_xlib_surface_ensure_picture (dst);
1953
    _cairo_xlib_surface_set_precision (dst, antialias);
1954
    XRenderCompositeTriStrip (dst->dpy,
1955
			      _render_operator (op),
1956
			      src->picture, dst->picture,
1957
			      pict_format,
1958
			      src_x, src_y,
1959
			      points, strip->num_points);
1960
 
1961
    if (points != points_stack)
1962
	free (points);
1963
 
1964
    return CAIRO_STATUS_SUCCESS;
1965
}
1966
 
1967
const cairo_compositor_t *
1968
_cairo_xlib_traps_compositor_get (void)
1969
{
1970
    static cairo_traps_compositor_t compositor;
1971
 
1972
    if (compositor.base.delegate == NULL) {
1973
	_cairo_traps_compositor_init (&compositor,
1974
				      _cairo_xlib_mask_compositor_get ());
1975
 
1976
	compositor.acquire = acquire;
1977
	compositor.release = release;
1978
	compositor.set_clip_region = set_clip_region;
1979
	compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
1980
	compositor.draw_image_boxes = draw_image_boxes;
1981
	compositor.copy_boxes = copy_boxes;
1982
	compositor.fill_boxes = fill_boxes;
1983
	compositor.check_composite = check_composite;
1984
	compositor.composite = composite;
1985
	compositor.lerp = lerp;
1986
	//compositor.check_composite_boxes = check_composite_boxes;
1987
	compositor.composite_boxes = composite_boxes;
1988
	//compositor.check_composite_traps = check_composite_traps;
1989
	compositor.composite_traps = composite_traps;
1990
	//compositor.check_composite_tristrip = check_composite_tristrip;
1991
	compositor.composite_tristrip = composite_tristrip;
1992
	compositor.check_composite_glyphs = check_composite_glyphs;
1993
	compositor.composite_glyphs = composite_glyphs;
1994
    }
1995
 
1996
    return &compositor.base;
1997
}
1998
 
1999
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */