beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-xlib-render-compositor.c
blob8a1ec7bd731561fbcbfdff9f53823c54be0ca609
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
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
6 * Copyright © 2011 Intel Corporation
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.
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
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/
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.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
34 * California.
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
43 #include "cairoint.h"
45 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
47 #include "cairo-xlib-private.h"
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"
58 static cairo_int_status_t
59 check_composite (const cairo_composite_rectangles_t *extents)
61 cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
63 if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
64 return CAIRO_INT_STATUS_UNSUPPORTED;
66 return CAIRO_STATUS_SUCCESS;
69 static cairo_int_status_t
70 acquire (void *abstract_dst)
72 cairo_xlib_surface_t *dst = abstract_dst;
73 cairo_int_status_t status;
75 status = _cairo_xlib_display_acquire (dst->base.device, &dst->display);
76 if (unlikely (status))
77 return status;
79 dst->dpy = dst->display->display;
80 return CAIRO_STATUS_SUCCESS;
83 static cairo_int_status_t
84 release (void *abstract_dst)
86 cairo_xlib_surface_t *dst = abstract_dst;
88 cairo_device_release (&dst->display->base);
89 dst->dpy = NULL;
91 return CAIRO_STATUS_SUCCESS;
94 static cairo_int_status_t
95 set_clip_region (void *_surface,
96 cairo_region_t *region)
98 cairo_xlib_surface_t *surface = _surface;
100 _cairo_xlib_surface_ensure_picture (surface);
102 if (region != NULL) {
103 XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
104 XRectangle *rects = stack_rects;
105 int n_rects, i;
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);
113 for (i = 0; i < n_rects; i++) {
114 cairo_rectangle_int_t rect;
116 cairo_region_get_rectangle (region, i, &rect);
118 rects[i].x = rect.x;
119 rects[i].y = rect.y;
120 rects[i].width = rect.width;
121 rects[i].height = rect.height;
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);
137 return CAIRO_STATUS_SUCCESS;
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)
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;
153 assert (image->depth == dst->depth);
155 status = acquire (dst);
156 if (unlikely (status))
157 return status;
159 status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
160 if (unlikely (status)) {
161 release (dst);
162 return status;
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);
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;
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);
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);
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++;
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);
211 if (rects != stack_rects)
212 free (rects);
215 _cairo_xlib_surface_put_gc (dst->display, dst, gc);
216 release (dst);
217 return CAIRO_STATUS_SUCCESS;
220 static cairo_bool_t
221 boxes_cover_surface (cairo_boxes_t *boxes,
222 cairo_xlib_surface_t *surface)
224 cairo_box_t *b;
226 if (boxes->num_boxes != 1)
227 return FALSE;
229 b = &boxes->chunks.base[0];
231 if (_cairo_fixed_integer_part (b->p1.x) > 0 ||
232 _cairo_fixed_integer_part (b->p1.y) > 0)
233 return FALSE;
235 if (_cairo_fixed_integer_part (b->p2.x) < surface->width ||
236 _cairo_fixed_integer_part (b->p2.y) < surface->height)
237 return FALSE;
239 return TRUE;
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)
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;
254 if (image->base.device == dst->base.device) {
255 if (image->depth != dst->depth)
256 return CAIRO_INT_STATUS_UNSUPPORTED;
258 if (_cairo_xlib_shm_surface_get_pixmap (&image->base))
259 return copy_image_boxes (dst, image, boxes, dx, dy);
261 goto draw_image_boxes;
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;
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;
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))
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);
295 shm->base.damage =
296 _cairo_damage_add_rectangle (shm->base.damage, &r);
299 dst->base.is_clear = FALSE;
300 dst->fallback++;
301 dst->base.serial++;
302 return CAIRO_INT_STATUS_NOTHING_TO_DO;
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;
310 _cairo_boxes_extents (boxes, &extents);
311 _cairo_box_round_to_rectangle (&extents, &r);
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;
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];
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;
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))
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);
348 dx = tx;
349 dy = ty;
350 image = shm;
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;
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;
379 out:
380 cairo_surface_destroy (&shm->base);
381 return status;
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)
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;
399 if (! _cairo_xlib_surface_same_screen (dst, src))
400 return CAIRO_INT_STATUS_UNSUPPORTED;
402 if (dst->depth != src->depth)
403 return CAIRO_INT_STATUS_UNSUPPORTED;
405 status = acquire (dst);
406 if (unlikely (status))
407 return status;
409 status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
410 if (unlikely (status)) {
411 release (dst);
412 return status;
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;
423 gcv.subwindow_mode = IncludeInferiors;
424 XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
426 d = src->drawable;
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);
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.
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);
462 } else {
463 XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
464 XRectangle *rects = stack_rects;
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);
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);
480 rects[j].x = x1;
481 rects[j].y = y1;
482 rects[j].width = x2 - x1;
483 rects[j].height = y2 - y1;
484 j++;
487 assert (j == boxes->num_boxes);
489 XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
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);
496 XSetClipMask (dst->dpy, gc, None);
498 if (rects != stack_rects)
499 free (rects);
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;
508 gcv.subwindow_mode = ClipByChildren;
509 XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
512 _cairo_xlib_surface_put_gc (dst->display, dst, gc);
513 release (dst);
514 return CAIRO_STATUS_SUCCESS;
517 static int
518 _render_operator (cairo_operator_t op)
520 switch (op) {
521 case CAIRO_OPERATOR_CLEAR:
522 return PictOpClear;
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;
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;
546 case CAIRO_OPERATOR_XOR:
547 return PictOpXor;
548 case CAIRO_OPERATOR_ADD:
549 return PictOpAdd;
550 case CAIRO_OPERATOR_SATURATE:
551 return PictOpSaturate;
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;
584 default:
585 ASSERT_NOT_REACHED;
586 return PictOpOver;
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)
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;
602 return FALSE;
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)
612 cairo_xlib_surface_t *dst = abstract_surface;
613 XRenderColor render_color;
614 int i;
616 //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
618 if (fill_reduces_to_source (op, color, dst))
619 op = CAIRO_OPERATOR_SOURCE;
621 if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
622 cairo_int_status_t status;
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;
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;
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().
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;
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);
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;
663 XRenderFillRectangles (dst->dpy,
664 _render_operator (op),
665 dst->picture,
666 &render_color, xrects, num_rects);
668 if (xrects != stack_xrects)
669 free (xrects);
672 return CAIRO_STATUS_SUCCESS;
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)
681 cairo_xlib_surface_t *dst = abstract_surface;
682 XRenderColor render_color;
684 if (fill_reduces_to_source (op, color, dst))
685 op = CAIRO_OPERATOR_SOURCE;
687 if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
688 cairo_int_status_t status;
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;
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;
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);
708 /* Take advantage of the protocol compaction that libXrender performs
709 * to amalgamate sequences of XRenderFillRectangle().
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;
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);
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);
737 xrects[j].x = x1;
738 xrects[j].y = y1;
739 xrects[j].width = x2 - x1;
740 xrects[j].height = y2 - y1;
741 j++;
745 XRenderFillRectangles (dst->dpy,
746 _render_operator (op),
747 dst->picture,
748 &render_color, xrects, j);
750 if (xrects != stack_xrects)
751 free (xrects);
754 return CAIRO_STATUS_SUCCESS;
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");
764 //X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
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;
772 #endif
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)
788 cairo_xlib_surface_t *dst = abstract_dst;
789 cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
791 op = _render_operator (op);
793 _cairo_xlib_surface_ensure_picture (dst);
794 if (abstract_mask) {
795 cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
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);
812 return CAIRO_STATUS_SUCCESS;
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)
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;
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);
846 return CAIRO_STATUS_SUCCESS;
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)
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;
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);
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;
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);
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);
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++;
909 assert (j == boxes->num_boxes);
911 XRenderSetPictureClipRectangles (dst->dpy,
912 dst->picture,
913 0, 0,
914 rects, j);
915 if (rects != stack_rects)
916 free (rects);
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);
925 set_clip_region (dst, NULL);
927 return CAIRO_STATUS_SUCCESS;
930 /* font rendering */
932 void
933 _cairo_xlib_font_close (cairo_xlib_font_t *priv)
935 cairo_xlib_display_t *display = (cairo_xlib_display_t *)priv->base.key;
936 int i;
938 /* XXX All I really want is to do is zap my glyphs... */
939 _cairo_scaled_font_reset_cache (priv->font);
941 for (i = 0; i < NUM_GLYPHSETS; i++) {
942 cairo_xlib_font_glyphset_t *info;
944 info = &priv->glyphset[i];
945 if (info->glyphset)
946 XRenderFreeGlyphSet (display->display, info->glyphset);
949 /* XXX locking */
950 cairo_list_del (&priv->link);
951 cairo_list_del (&priv->base.link);
952 free (priv);
955 static void
956 _cairo_xlib_font_fini (cairo_scaled_font_private_t *abstract_private,
957 cairo_scaled_font_t *font)
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;
964 cairo_list_del (&priv->base.link);
965 cairo_list_del (&priv->link);
967 status = _cairo_xlib_display_acquire (priv->device, &display);
968 if (status)
969 goto BAIL;
971 for (i = 0; i < NUM_GLYPHSETS; i++) {
972 cairo_xlib_font_glyphset_t *info;
974 info = &priv->glyphset[i];
975 if (info->glyphset)
976 XRenderFreeGlyphSet (display->display, info->glyphset);
979 cairo_device_release (&display->base);
980 BAIL:
981 cairo_device_destroy (&display->base);
982 free (priv);
985 static cairo_xlib_font_t *
986 _cairo_xlib_font_create (cairo_xlib_display_t *display,
987 cairo_scaled_font_t *font)
989 cairo_xlib_font_t *priv;
990 int i;
992 priv = malloc (sizeof (cairo_xlib_font_t));
993 if (unlikely (priv == NULL))
994 return NULL;
996 _cairo_scaled_font_attach_private (font, &priv->base, display,
997 _cairo_xlib_font_fini);
999 priv->device = cairo_device_reference (&display->base);
1000 priv->font = font;
1001 cairo_list_add (&priv->link, &display->fonts);
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;
1011 info->xrender_format = NULL;
1012 info->glyphset = None;
1013 info->to_free.count = 0;
1016 return priv;
1019 static int
1020 _cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
1022 if (format == CAIRO_FORMAT_A8)
1023 return GLYPHSET_INDEX_A8;
1024 if (format == CAIRO_FORMAT_A1)
1025 return GLYPHSET_INDEX_A1;
1027 assert (format == CAIRO_FORMAT_ARGB32);
1028 return GLYPHSET_INDEX_ARGB32;
1031 static inline cairo_xlib_font_t *
1032 _cairo_xlib_font_get (const cairo_xlib_display_t *display,
1033 cairo_scaled_font_t *font)
1035 return (cairo_xlib_font_t *)_cairo_scaled_font_find_private (font, display);
1038 typedef struct {
1039 cairo_scaled_glyph_private_t base;
1042 cairo_xlib_font_glyphset_t *glyphset;
1043 } cairo_xlib_glyph_private_t;
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)
1050 cairo_xlib_glyph_private_t *priv = (cairo_xlib_glyph_private_t *)glyph_private;
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;
1057 font_private = _cairo_xlib_font_get (glyph_private->key, font);
1058 assert (font_private);
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;
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);
1074 to_free->count = 0;
1077 to_free->indices[to_free->count++] =
1078 _cairo_scaled_glyph_index (glyph);
1081 cairo_list_del (&glyph_private->link);
1082 free (glyph_private);
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)
1090 cairo_xlib_glyph_private_t *priv;
1092 priv = malloc (sizeof (*priv));
1093 if (unlikely (priv == NULL))
1094 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1096 _cairo_scaled_glyph_attach_private (glyph, &priv->base, display,
1097 _cairo_xlib_glyph_fini);
1098 priv->glyphset = info;
1100 glyph->dev_private = info;
1101 glyph->dev_private_key = display;
1102 return CAIRO_STATUS_SUCCESS;
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)
1110 cairo_xlib_font_t *priv;
1111 cairo_xlib_font_glyphset_t *info;
1112 int glyphset_index;
1114 glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
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;
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);
1131 return info;
1134 static cairo_bool_t
1135 has_pending_free_glyph (cairo_xlib_font_glyphset_t *info,
1136 unsigned long glyph_index)
1138 struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
1139 int i;
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;
1152 return FALSE;
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)
1161 cairo_xlib_font_t *priv;
1162 int i;
1164 priv = _cairo_xlib_font_get (display, font);
1165 if (priv == NULL)
1166 return NULL;
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];
1179 return NULL;
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)
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;
1196 glyph_index = _cairo_scaled_glyph_index (glyph);
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);
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;
1212 glyph = *pscaled_glyph;
1213 glyph_surface = glyph->surface;
1214 already_had_glyph_surface = FALSE;
1215 } else {
1216 already_had_glyph_surface = TRUE;
1219 info = _cairo_xlib_font_get_glyphset_info_for_format (display, font,
1220 glyph_surface->format);
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.
1226 if (glyph_surface->width == 0 || glyph_surface->height == 0) {
1227 cairo_surface_t *tmp_surface;
1229 tmp_surface = cairo_image_surface_create (info->format, 1, 1);
1230 status = tmp_surface->status;
1231 if (unlikely (status))
1232 goto BAIL;
1234 tmp_surface->device_transform = glyph_surface->base.device_transform;
1235 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
1237 glyph_surface = (cairo_image_surface_t *) tmp_surface;
1239 #endif
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.
1245 if (glyph_surface->format != info->format) {
1246 cairo_surface_pattern_t pattern;
1247 cairo_surface_t *tmp_surface;
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;
1256 tmp_surface->device_transform = glyph_surface->base.device_transform;
1257 tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
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);
1265 glyph_surface = (cairo_image_surface_t *) tmp_surface;
1267 if (unlikely (status))
1268 goto BAIL;
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;
1279 data = glyph_surface->data;
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;
1290 if (c == 0)
1291 break;
1293 new = malloc (c);
1294 if (!new) {
1295 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1296 goto BAIL;
1298 n = new;
1299 d = data;
1300 do {
1301 char b = *d++;
1302 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
1303 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
1304 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
1305 *n++ = b;
1306 } while (--c);
1307 data = new;
1309 break;
1310 case GLYPHSET_INDEX_A8:
1311 break;
1312 case GLYPHSET_INDEX_ARGB32:
1313 if (_cairo_is_little_endian() != (ImageByteOrder (display->display) == LSBFirst)) {
1314 unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
1315 const uint32_t *d;
1316 uint32_t *new, *n;
1318 if (c == 0)
1319 break;
1321 new = malloc (4 * c);
1322 if (unlikely (new == NULL)) {
1323 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1324 goto BAIL;
1326 n = new;
1327 d = (uint32_t *) data;
1328 do {
1329 *n++ = bswap_32 (*d);
1330 d++;
1331 } while (--c);
1332 data = (uint8_t *) new;
1334 break;
1335 default:
1336 ASSERT_NOT_REACHED;
1337 break;
1339 /* XXX assume X server wants pixman padding. Xft assumes this as well */
1341 XRenderAddGlyphs (display->display, info->glyphset,
1342 &glyph_index, &glyph_info, 1,
1343 (char *) data,
1344 glyph_surface->stride * glyph_surface->height);
1346 if (data != glyph_surface->data)
1347 free (data);
1349 status = _cairo_xlib_glyph_attach (display, glyph, info);
1351 BAIL:
1352 if (glyph_surface != glyph->surface)
1353 cairo_surface_destroy (&glyph_surface->base);
1355 /* if the scaled glyph didn't already have a surface attached
1356 * to it, release the created surface now that we have it
1357 * uploaded to the X server. If the surface has already been
1358 * there (eg. because image backend requested it), leave it in
1359 * the cache
1361 if (!already_had_glyph_surface)
1362 _cairo_scaled_glyph_set_surface (glyph, font, NULL);
1364 return status;
1367 typedef void (*cairo_xrender_composite_text_func_t)
1368 (Display *dpy,
1369 int op,
1370 Picture src,
1371 Picture dst,
1372 _Xconst XRenderPictFormat *maskFormat,
1373 int xSrc,
1374 int ySrc,
1375 int xDst,
1376 int yDst,
1377 _Xconst XGlyphElt8 *elts,
1378 int nelt);
1380 /* Build a struct of the same size of #cairo_glyph_t that can be used both as
1381 * an input glyph with double coordinates, and as "working" glyph with
1382 * integer from-current-point offsets. */
1383 typedef union {
1384 cairo_glyph_t d;
1385 unsigned long index;
1386 struct {
1387 unsigned long index;
1388 int x;
1389 int y;
1390 } i;
1391 } cairo_xlib_glyph_t;
1393 /* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
1394 COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
1396 /* Start a new element for the first glyph,
1397 * or for any glyph that has unexpected position,
1398 * or if current element has too many glyphs
1399 * (Xrender limits each element to 252 glyphs, we limit them to 128)
1401 * These same conditions need to be mirrored between
1402 * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
1404 #define _start_new_glyph_elt(count, glyph) \
1405 (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
1407 static cairo_status_t
1408 _emit_glyphs_chunk (cairo_xlib_display_t *display,
1409 cairo_xlib_surface_t *dst,
1410 int dst_x, int dst_y,
1411 cairo_xlib_glyph_t *glyphs,
1412 int num_glyphs,
1413 cairo_scaled_font_t *font,
1414 cairo_bool_t use_mask,
1415 cairo_operator_t op,
1416 cairo_xlib_source_t *src,
1417 int src_x, int src_y,
1418 /* info for this chunk */
1419 int num_elts,
1420 int width,
1421 cairo_xlib_font_glyphset_t *info)
1423 /* Which XRenderCompositeText function to use */
1424 cairo_xrender_composite_text_func_t composite_text_func;
1425 int size;
1427 /* Element buffer stuff */
1428 XGlyphElt8 *elts;
1429 XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
1431 /* Reuse the input glyph array for output char generation */
1432 char *char8 = (char *) glyphs;
1433 unsigned short *char16 = (unsigned short *) glyphs;
1434 unsigned int *char32 = (unsigned int *) glyphs;
1436 int i;
1437 int nelt; /* Element index */
1438 int n; /* Num output glyphs in current element */
1439 int j; /* Num output glyphs so far */
1441 switch (width) {
1442 case 1:
1443 /* don't cast the 8-variant, to catch possible mismatches */
1444 composite_text_func = XRenderCompositeText8;
1445 size = sizeof (char);
1446 break;
1447 case 2:
1448 composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
1449 size = sizeof (unsigned short);
1450 break;
1451 default:
1452 case 4:
1453 composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
1454 size = sizeof (unsigned int);
1457 /* Allocate element array */
1458 if (num_elts <= ARRAY_LENGTH (stack_elts)) {
1459 elts = stack_elts;
1460 } else {
1461 elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
1462 if (unlikely (elts == NULL))
1463 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1466 /* Fill them in */
1467 nelt = 0;
1468 n = 0;
1469 j = 0;
1470 for (i = 0; i < num_glyphs; i++) {
1471 /* Start a new element for first output glyph,
1472 * or for any glyph that has unexpected position,
1473 * or if current element has too many glyphs.
1475 * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
1477 if (_start_new_glyph_elt (j, &glyphs[i])) {
1478 if (j) {
1479 elts[nelt].nchars = n;
1480 nelt++;
1481 n = 0;
1483 elts[nelt].chars = char8 + size * j;
1484 elts[nelt].glyphset = info->glyphset;
1485 elts[nelt].xOff = glyphs[i].i.x;
1486 elts[nelt].yOff = glyphs[i].i.y;
1489 switch (width) {
1490 case 1: char8 [j] = (char) glyphs[i].index; break;
1491 case 2: char16[j] = (unsigned short) glyphs[i].index; break;
1492 default:
1493 case 4: char32[j] = (unsigned int) glyphs[i].index; break;
1496 n++;
1497 j++;
1500 if (n) {
1501 elts[nelt].nchars = n;
1502 nelt++;
1505 /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
1506 * expected number of xGlyphElts. */
1507 assert (nelt == num_elts);
1509 composite_text_func (display->display, op,
1510 src->picture,
1511 dst->picture,
1512 use_mask ? info->xrender_format : NULL,
1513 src_x + elts[0].xOff + dst_x,
1514 src_y + elts[0].yOff + dst_y,
1515 elts[0].xOff, elts[0].yOff,
1516 (XGlyphElt8 *) elts, nelt);
1518 if (elts != stack_elts)
1519 free (elts);
1521 return CAIRO_STATUS_SUCCESS;
1524 static cairo_int_status_t
1525 check_composite_glyphs (const cairo_composite_rectangles_t *extents,
1526 cairo_scaled_font_t *font,
1527 cairo_glyph_t *glyphs,
1528 int *num_glyphs)
1530 cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface;
1531 cairo_xlib_display_t *display = dst->display;
1532 int max_request_size, size;
1534 TRACE ((stderr, "%s\n", __FUNCTION__));
1536 if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
1537 return CAIRO_INT_STATUS_UNSUPPORTED;
1539 /* The glyph coordinates must be representable in an int16_t.
1540 * When possible, they will be expressed as an offset from the
1541 * previous glyph, otherwise they will be an offset from the
1542 * surface origin. If we can't guarantee this to be possible,
1543 * fallback.
1545 if (extents->bounded.x + extents->bounded.width > INT16_MAX ||
1546 extents->bounded.y + extents->bounded.height> INT16_MAX ||
1547 extents->bounded.x < INT16_MIN ||
1548 extents->bounded.y < INT16_MIN)
1550 return CAIRO_INT_STATUS_UNSUPPORTED;
1553 /* Approximate the size of the largest glyph and fallback if we can not
1554 * upload it to the xserver.
1556 size = ceil (font->max_scale);
1557 size = 4 * size * size;
1558 max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display)
1559 : XMaxRequestSize (display->display)) * 4 -
1560 sz_xRenderAddGlyphsReq -
1561 sz_xGlyphInfo -
1563 if (size >= max_request_size)
1564 return CAIRO_INT_STATUS_UNSUPPORTED;
1566 return CAIRO_STATUS_SUCCESS;
1569 /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
1570 * enough room for padding */
1571 #define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
1573 static cairo_int_status_t
1574 composite_glyphs (void *surface,
1575 cairo_operator_t op,
1576 cairo_surface_t *_src,
1577 int src_x,
1578 int src_y,
1579 int dst_x,
1580 int dst_y,
1581 cairo_composite_glyphs_info_t *info)
1583 cairo_xlib_surface_t *dst = surface;
1584 cairo_xlib_glyph_t *glyphs = (cairo_xlib_glyph_t *)info->glyphs;
1585 cairo_xlib_source_t *src = (cairo_xlib_source_t *)_src;
1586 cairo_xlib_display_t *display = dst->display;
1587 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1588 cairo_scaled_glyph_t *glyph;
1589 cairo_fixed_t x = dst_x, y = dst_y;
1590 cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info;
1592 unsigned long max_index = 0;
1593 int width = 1;
1594 int num_elts = 0;
1595 int num_out_glyphs = 0;
1596 int num_glyphs = info->num_glyphs;
1598 int max_request_size = XMaxRequestSize (display->display) * 4
1599 - MAX (sz_xRenderCompositeGlyphs8Req,
1600 MAX(sz_xRenderCompositeGlyphs16Req,
1601 sz_xRenderCompositeGlyphs32Req));
1602 int request_size = 0;
1603 int i;
1605 op = _render_operator (op),
1606 _cairo_xlib_surface_ensure_picture (dst);
1607 for (i = 0; i < num_glyphs; i++) {
1608 int this_x, this_y;
1609 int old_width;
1611 status = _cairo_scaled_glyph_lookup (info->font,
1612 glyphs[i].index,
1613 CAIRO_SCALED_GLYPH_INFO_METRICS,
1614 &glyph);
1615 if (unlikely (status))
1616 return status;
1618 this_x = _cairo_lround (glyphs[i].d.x);
1619 this_y = _cairo_lround (glyphs[i].d.y);
1621 /* Send unsent glyphs to the server */
1622 if (glyph->dev_private_key != display) {
1623 status = _cairo_xlib_surface_add_glyph (display, info->font, &glyph);
1624 if (unlikely (status))
1625 return status;
1628 this_glyphset_info = glyph->dev_private;
1629 if (!glyphset)
1630 glyphset = this_glyphset_info;
1632 /* The invariant here is that we can always flush the glyphs
1633 * accumulated before this one, using old_width, and they
1634 * would fit in the request.
1636 old_width = width;
1638 /* Update max glyph index */
1639 if (glyphs[i].index > max_index) {
1640 max_index = glyphs[i].index;
1641 if (max_index >= 65536)
1642 width = 4;
1643 else if (max_index >= 256)
1644 width = 2;
1645 if (width != old_width)
1646 request_size += (width - old_width) * num_out_glyphs;
1649 /* If we will pass the max request size by adding this glyph,
1650 * flush current glyphs. Note that we account for a
1651 * possible element being added below.
1653 * Also flush if changing glyphsets, as Xrender limits one mask
1654 * format per request, so we can either break up, or use a
1655 * wide-enough mask format. We do the former. One reason to
1656 * prefer the latter is the fact that Xserver ADDs all glyphs
1657 * to the mask first, and then composes that to final surface,
1658 * though it's not a big deal.
1660 * If the glyph has a coordinate which cannot be represented
1661 * as a 16-bit offset from the previous glyph, flush the
1662 * current chunk. The current glyph will be the first one in
1663 * the next chunk, thus its coordinates will be an offset from
1664 * the destination origin. This offset is guaranteed to be
1665 * representable as 16-bit offset (otherwise we would have
1666 * fallen back).
1668 if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
1669 this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
1670 this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
1671 (this_glyphset_info != glyphset)) {
1672 status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
1673 glyphs, i, info->font, info->use_mask,
1674 op, src, src_x, src_y,
1675 num_elts, old_width, glyphset);
1676 if (unlikely (status))
1677 return status;
1679 glyphs += i;
1680 num_glyphs -= i;
1681 i = 0;
1682 max_index = glyphs[i].index;
1683 width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
1684 request_size = 0;
1685 num_elts = 0;
1686 num_out_glyphs = 0;
1687 x = y = 0;
1688 glyphset = this_glyphset_info;
1691 /* Convert absolute glyph position to relative-to-current-point
1692 * position */
1693 glyphs[i].i.x = this_x - x;
1694 glyphs[i].i.y = this_y - y;
1696 /* Start a new element for the first glyph,
1697 * or for any glyph that has unexpected position,
1698 * or if current element has too many glyphs.
1700 * These same conditions are mirrored in _emit_glyphs_chunk().
1702 if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
1703 num_elts++;
1704 request_size += _cairo_sz_xGlyphElt;
1707 /* adjust current-position */
1708 x = this_x + glyph->x_advance;
1709 y = this_y + glyph->y_advance;
1711 num_out_glyphs++;
1712 request_size += width;
1715 if (num_elts) {
1716 status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
1717 glyphs, i, info->font, info->use_mask,
1718 op, src, src_x, src_y,
1719 num_elts, width, glyphset);
1722 return status;
1725 const cairo_compositor_t *
1726 _cairo_xlib_mask_compositor_get (void)
1728 static cairo_mask_compositor_t compositor;
1730 if (compositor.base.delegate == NULL) {
1731 _cairo_mask_compositor_init (&compositor,
1732 _cairo_xlib_fallback_compositor_get ());
1734 compositor.acquire = acquire;
1735 compositor.release = release;
1736 compositor.set_clip_region = set_clip_region;
1737 compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
1738 compositor.draw_image_boxes = draw_image_boxes;
1739 compositor.fill_rectangles = fill_rectangles;
1740 compositor.fill_boxes = fill_boxes;
1741 compositor.copy_boxes = copy_boxes;
1742 compositor.check_composite = check_composite;
1743 compositor.composite = composite;
1744 //compositor.check_composite_boxes = check_composite_boxes;
1745 compositor.composite_boxes = composite_boxes;
1746 compositor.check_composite_glyphs = check_composite_glyphs;
1747 compositor.composite_glyphs = composite_glyphs;
1750 return &compositor.base;
1753 #define CAIRO_FIXED_16_16_MIN -32768
1754 #define CAIRO_FIXED_16_16_MAX 32767
1756 static cairo_bool_t
1757 line_exceeds_16_16 (const cairo_line_t *line)
1759 return
1760 line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1761 line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
1762 line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1763 line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
1764 line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1765 line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
1766 line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
1767 line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX);
1770 static void
1771 project_line_x_onto_16_16 (const cairo_line_t *line,
1772 cairo_fixed_t top,
1773 cairo_fixed_t bottom,
1774 XLineFixed *out)
1776 cairo_point_double_t p1, p2;
1777 double m;
1779 p1.x = _cairo_fixed_to_double (line->p1.x);
1780 p1.y = _cairo_fixed_to_double (line->p1.y);
1782 p2.x = _cairo_fixed_to_double (line->p2.x);
1783 p2.y = _cairo_fixed_to_double (line->p2.y);
1785 m = (p2.x - p1.x) / (p2.y - p1.y);
1786 out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
1787 out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
1789 #if 0
1790 static cairo_int_status_T
1791 check_composite_trapezoids ()
1793 operation = _categorize_composite_operation (dst, op, pattern, TRUE);
1794 if (operation == DO_UNSUPPORTED)
1795 return UNSUPPORTED ("unsupported operation");
1797 operation = _recategorize_composite_operation (dst, op, src,
1798 &attributes, TRUE);
1799 if (operation == DO_UNSUPPORTED) {
1800 status = UNSUPPORTED ("unsupported operation");
1801 goto BAIL;
1805 #endif
1807 static cairo_int_status_t
1808 composite_traps (void *abstract_dst,
1809 cairo_operator_t op,
1810 cairo_surface_t *abstract_src,
1811 int src_x,
1812 int src_y,
1813 int dst_x,
1814 int dst_y,
1815 const cairo_rectangle_int_t *extents,
1816 cairo_antialias_t antialias,
1817 cairo_traps_t *traps)
1819 cairo_xlib_surface_t *dst = abstract_dst;
1820 cairo_xlib_display_t *display = dst->display;
1821 cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
1822 XRenderPictFormat *pict_format;
1823 XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
1824 XTrapezoid *xtraps = xtraps_stack;
1825 int dx, dy;
1826 int i;
1828 //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1830 if (dst->base.is_clear &&
1831 (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))
1833 op = CAIRO_OPERATOR_SOURCE;
1836 pict_format =
1837 _cairo_xlib_display_get_xrender_format (display,
1838 antialias == CAIRO_ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
1840 if (traps->num_traps > ARRAY_LENGTH (xtraps_stack)) {
1841 xtraps = _cairo_malloc_ab (traps->num_traps, sizeof (XTrapezoid));
1842 if (unlikely (xtraps == NULL))
1843 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1846 dx = -dst_x << 16;
1847 dy = -dst_y << 16;
1848 for (i = 0; i < traps->num_traps; i++) {
1849 cairo_trapezoid_t *t = &traps->traps[i];
1851 /* top/bottom will be clamped to surface bounds */
1852 xtraps[i].top = _cairo_fixed_to_16_16(t->top) + dy;
1853 xtraps[i].bottom = _cairo_fixed_to_16_16(t->bottom) + dy;
1855 /* However, all the other coordinates will have been left untouched so
1856 * as not to introduce numerical error. Recompute them if they
1857 * exceed the 16.16 limits.
1859 if (unlikely (line_exceeds_16_16 (&t->left))) {
1860 project_line_x_onto_16_16 (&t->left, t->top, t->bottom,
1861 &xtraps[i].left);
1862 xtraps[i].left.p1.x += dx;
1863 xtraps[i].left.p2.x += dx;
1864 xtraps[i].left.p1.y = xtraps[i].top;
1865 xtraps[i].left.p2.y = xtraps[i].bottom;
1866 } else {
1867 xtraps[i].left.p1.x = _cairo_fixed_to_16_16(t->left.p1.x) + dx;
1868 xtraps[i].left.p1.y = _cairo_fixed_to_16_16(t->left.p1.y) + dy;
1869 xtraps[i].left.p2.x = _cairo_fixed_to_16_16(t->left.p2.x) + dx;
1870 xtraps[i].left.p2.y = _cairo_fixed_to_16_16(t->left.p2.y) + dy;
1873 if (unlikely (line_exceeds_16_16 (&t->right))) {
1874 project_line_x_onto_16_16 (&t->right, t->top, t->bottom,
1875 &xtraps[i].right);
1876 xtraps[i].right.p1.x += dx;
1877 xtraps[i].right.p2.x += dx;
1878 xtraps[i].right.p1.y = xtraps[i].top;
1879 xtraps[i].right.p2.y = xtraps[i].bottom;
1880 } else {
1881 xtraps[i].right.p1.x = _cairo_fixed_to_16_16(t->right.p1.x) + dx;
1882 xtraps[i].right.p1.y = _cairo_fixed_to_16_16(t->right.p1.y) + dy;
1883 xtraps[i].right.p2.x = _cairo_fixed_to_16_16(t->right.p2.x) + dx;
1884 xtraps[i].right.p2.y = _cairo_fixed_to_16_16(t->right.p2.y) + dy;
1888 if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
1889 src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p1.x);
1890 src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p1.y);
1891 } else {
1892 src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p2.x);
1893 src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p2.y);
1895 src_x += dst_x;
1896 src_y += dst_y;
1898 _cairo_xlib_surface_ensure_picture (dst);
1899 _cairo_xlib_surface_set_precision (dst, antialias);
1900 XRenderCompositeTrapezoids (dst->dpy,
1901 _render_operator (op),
1902 src->picture, dst->picture,
1903 pict_format,
1904 src_x, src_y,
1905 xtraps, traps->num_traps);
1907 if (xtraps != xtraps_stack)
1908 free (xtraps);
1910 return CAIRO_STATUS_SUCCESS;
1913 static cairo_int_status_t
1914 composite_tristrip (void *abstract_dst,
1915 cairo_operator_t op,
1916 cairo_surface_t *abstract_src,
1917 int src_x,
1918 int src_y,
1919 int dst_x,
1920 int dst_y,
1921 const cairo_rectangle_int_t *extents,
1922 cairo_antialias_t antialias,
1923 cairo_tristrip_t *strip)
1925 cairo_xlib_surface_t *dst = abstract_dst;
1926 cairo_xlib_display_t *display = dst->display;
1927 cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
1928 XRenderPictFormat *pict_format;
1929 XPointFixed points_stack[CAIRO_STACK_ARRAY_LENGTH (XPointFixed)];
1930 XPointFixed *points = points_stack;
1931 int dx, dy;
1932 int i;
1934 //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
1936 pict_format =
1937 _cairo_xlib_display_get_xrender_format (display,
1938 antialias == CAIRO_ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
1940 if (strip->num_points > ARRAY_LENGTH (points_stack)) {
1941 points = _cairo_malloc_ab (strip->num_points, sizeof (XPointFixed));
1942 if (unlikely (points == NULL))
1943 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1946 dx = -dst_x << 16;
1947 dy = -dst_y << 16;
1948 for (i = 0; i < strip->num_points; i++) {
1949 cairo_point_t *p = &strip->points[i];
1951 points[i].x = _cairo_fixed_to_16_16(p->x) + dx;
1952 points[i].y = _cairo_fixed_to_16_16(p->y) + dy;
1955 src_x += _cairo_fixed_16_16_floor (points[0].x) + dst_x;
1956 src_y += _cairo_fixed_16_16_floor (points[0].y) + dst_y;
1958 _cairo_xlib_surface_ensure_picture (dst);
1959 _cairo_xlib_surface_set_precision (dst, antialias);
1960 XRenderCompositeTriStrip (dst->dpy,
1961 _render_operator (op),
1962 src->picture, dst->picture,
1963 pict_format,
1964 src_x, src_y,
1965 points, strip->num_points);
1967 if (points != points_stack)
1968 free (points);
1970 return CAIRO_STATUS_SUCCESS;
1973 const cairo_compositor_t *
1974 _cairo_xlib_traps_compositor_get (void)
1976 static cairo_traps_compositor_t compositor;
1978 if (compositor.base.delegate == NULL) {
1979 _cairo_traps_compositor_init (&compositor,
1980 _cairo_xlib_mask_compositor_get ());
1982 compositor.acquire = acquire;
1983 compositor.release = release;
1984 compositor.set_clip_region = set_clip_region;
1985 compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
1986 compositor.draw_image_boxes = draw_image_boxes;
1987 compositor.copy_boxes = copy_boxes;
1988 compositor.fill_boxes = fill_boxes;
1989 compositor.check_composite = check_composite;
1990 compositor.composite = composite;
1991 compositor.lerp = lerp;
1992 //compositor.check_composite_boxes = check_composite_boxes;
1993 compositor.composite_boxes = composite_boxes;
1994 //compositor.check_composite_traps = check_composite_traps;
1995 compositor.composite_traps = composite_traps;
1996 //compositor.check_composite_tristrip = check_composite_tristrip;
1997 compositor.composite_tristrip = composite_tristrip;
1998 compositor.check_composite_glyphs = check_composite_glyphs;
1999 compositor.composite_glyphs = composite_glyphs;
2002 return &compositor.base;
2005 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */