Imported Upstream version 1.12.14
[platform/upstream/cairo.git] / src / cairo-xlib-core-compositor.c
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2002 University of Southern California
5  * Copyright © 2005 Red Hat, Inc.
6  * Copyright © 2011 Intel Corporation
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it either under the terms of the GNU Lesser General Public
10  * License version 2.1 as published by the Free Software Foundation
11  * (the "LGPL") or, at your option, under the terms of the Mozilla
12  * Public License Version 1.1 (the "MPL"). If you do not alter this
13  * notice, a recipient may use your version of this file under either
14  * the MPL or the LGPL.
15  *
16  * You should have received a copy of the LGPL along with this library
17  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19  * You should have received a copy of the MPL along with this library
20  * in the file COPYING-MPL-1.1
21  *
22  * The contents of this file are subject to the Mozilla Public License
23  * Version 1.1 (the "License"); you may not use this file except in
24  * compliance with the License. You may obtain a copy of the License at
25  * http://www.mozilla.org/MPL/
26  *
27  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29  * the specific language governing rights and limitations.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is University of Southern
34  * California.
35  *
36  * Contributor(s):
37  *      Carl D. Worth <cworth@cworth.org>
38  *      Behdad Esfahbod <behdad@behdad.org>
39  *      Chris Wilson <chris@chris-wilson.co.uk>
40  *      Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
41  */
42
43 /* The original X drawing API was very restrictive in what it could handle,
44  * pixel-aligned fill/blits are all that map into Cairo's drawing model.
45  */
46
47 #include "cairoint.h"
48
49 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
50
51 #include "cairo-xlib-private.h"
52 #include "cairo-xlib-surface-private.h"
53
54 #include "cairo-boxes-private.h"
55 #include "cairo-clip-inline.h"
56 #include "cairo-compositor-private.h"
57 #include "cairo-image-surface-private.h"
58 #include "cairo-pattern-private.h"
59 #include "cairo-region-private.h"
60 #include "cairo-surface-offset-private.h"
61
62 /* the low-level interface */
63
64 static cairo_int_status_t
65 acquire (void *abstract_dst)
66 {
67     cairo_xlib_surface_t *dst = abstract_dst;
68     return _cairo_xlib_display_acquire (dst->base.device, &dst->display);
69 }
70
71 static cairo_int_status_t
72 release (void *abstract_dst)
73 {
74     cairo_xlib_surface_t *dst = abstract_dst;
75
76     cairo_device_release (&dst->display->base);
77     dst->display = NULL;
78
79     return CAIRO_STATUS_SUCCESS;
80 }
81
82 struct _fill_box {
83     Display *dpy;
84     Drawable drawable;
85     GC gc;
86     //cairo_surface_t *dither = NULL;
87 };
88
89 static cairo_bool_t fill_box (cairo_box_t *box, void *closure)
90 {
91     struct _fill_box *data = closure;
92     int x = _cairo_fixed_integer_part (box->p1.x);
93     int y = _cairo_fixed_integer_part (box->p1.y);
94     int width  = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
95     int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
96
97     XFillRectangle (data->dpy, data->drawable, data->gc, x, y, width, height);
98     return TRUE;
99 }
100
101 static void
102 _characterize_field (uint32_t mask, int *width, int *shift)
103 {
104     *width = _cairo_popcount (mask);
105     /* The final '& 31' is to force a 0 mask to result in 0 shift. */
106     *shift = _cairo_popcount ((mask - 1) & ~mask) & 31;
107 }
108
109 static uint32_t
110 color_to_pixel (cairo_xlib_surface_t    *dst,
111                 const cairo_color_t     *color)
112 {
113     uint32_t rgba = 0;
114     int width, shift;
115
116     _characterize_field (dst->a_mask, &width, &shift);
117     rgba |= color->alpha_short >> (16 - width) << shift;
118
119     _characterize_field (dst->r_mask, &width, &shift);
120     rgba |= color->red_short >> (16 - width) << shift;
121
122     _characterize_field (dst->g_mask, &width, &shift);
123     rgba |= color->green_short >> (16 - width) << shift;
124
125     _characterize_field (dst->b_mask, &width, &shift);
126     rgba |= color->blue_short >> (16 - width) << shift;
127
128     return rgba;
129 }
130
131 static cairo_int_status_t
132 _fill_box_init (struct _fill_box *fb,
133                 cairo_xlib_surface_t *dst,
134                 const cairo_color_t *color)
135 {
136     cairo_int_status_t status;
137
138     status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb->gc);
139     if (unlikely (status))
140         return status;
141
142     fb->dpy = dst->display->display;
143     fb->drawable = dst->drawable;
144
145     if (dst->visual && dst->visual->class != TrueColor && 0) {
146 #if 0
147         cairo_solid_pattern_t solid;
148         cairo_surface_attributes_t attrs;
149
150         _cairo_pattern_init_solid (&solid, color);
151         status = _cairo_pattern_acquire_surface (&solid.base, &dst->base,
152                                                  0, 0,
153                                                  ARRAY_LENGTH (dither_pattern[0]),
154                                                  ARRAY_LENGTH (dither_pattern),
155                                                  CAIRO_PATTERN_ACQUIRE_NONE,
156                                                  &dither,
157                                                  &attrs);
158         if (unlikely (status)) {
159             _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
160             return status;
161         }
162
163         XSetTSOrigin (fb->dpy, fb->gc,
164                       - (dst->base.device_transform.x0 + attrs.x_offset),
165                       - (dst->base.device_transform.y0 + attrs.y_offset));
166         XSetTile (fb->dpy, fb->gc, ((cairo_xlib_surface_t *) dither)->drawable);
167 #endif
168     } else {
169         XGCValues gcv;
170
171         gcv.foreground = color_to_pixel (dst, color);
172         gcv.fill_style = FillSolid;
173
174         XChangeGC (fb->dpy, fb->gc, GCFillStyle | GCForeground, &gcv);
175     }
176
177     return CAIRO_INT_STATUS_SUCCESS;
178 }
179
180 static void
181 _fill_box_fini (struct _fill_box *fb,
182                 cairo_xlib_surface_t *dst)
183 {
184     _cairo_xlib_surface_put_gc (dst->display, dst, fb->gc);
185     //cairo_surface_destroy (fb->dither);
186 }
187
188 cairo_int_status_t
189 _cairo_xlib_core_fill_boxes (cairo_xlib_surface_t    *dst,
190                              const cairo_color_t     *color,
191                              cairo_boxes_t          *boxes)
192 {
193     cairo_int_status_t status;
194     struct _fill_box fb;
195
196     status = _fill_box_init (&fb, dst, color);
197     if (unlikely (status))
198         return status;
199
200     _cairo_boxes_for_each_box (boxes, fill_box, &fb);
201
202     _fill_box_fini (&fb, dst);
203     return CAIRO_STATUS_SUCCESS;
204 }
205
206 cairo_int_status_t
207 _cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t    *dst,
208                                   const cairo_color_t     *color,
209                                   int num_rects,
210                                   cairo_rectangle_int_t *rects)
211 {
212     cairo_int_status_t status;
213     struct _fill_box fb;
214     int i;
215
216     status = _fill_box_init (&fb, dst, color);
217     if (unlikely (status))
218         return status;
219
220     for (i = 0; i < num_rects; i++)
221         XFillRectangle (fb.dpy, fb.drawable, fb.gc,
222                         rects[i].x, rects[i].y,
223                         rects[i].width, rects[i].height);
224
225     _fill_box_fini (&fb, dst);
226     return CAIRO_STATUS_SUCCESS;
227 }
228
229 struct _fallback_box {
230     cairo_xlib_surface_t        *dst;
231     cairo_format_t               format;
232     const cairo_pattern_t       *pattern;
233 };
234
235 static cairo_bool_t fallback_box (cairo_box_t *box, void *closure)
236 {
237     struct _fallback_box *data = closure;
238     int x = _cairo_fixed_integer_part (box->p1.x);
239     int y = _cairo_fixed_integer_part (box->p1.y);
240     int width  = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
241     int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
242     cairo_surface_t *image;
243     cairo_status_t status;
244
245     /* XXX for EXTEND_NONE and if the box is wholly outside we can just fill */
246
247     image = cairo_surface_create_similar_image (&data->dst->base, data->format,
248                                                 width, height);
249     status = _cairo_surface_offset_paint (image, x, y,
250                                           CAIRO_OPERATOR_SOURCE,
251                                           data->pattern, NULL);
252     if (status == CAIRO_STATUS_SUCCESS) {
253         status = _cairo_xlib_surface_draw_image (data->dst,
254                                                  (cairo_image_surface_t *)image,
255                                                  0, 0,
256                                                  width, height,
257                                                  x, y);
258     }
259     cairo_surface_destroy (image);
260
261     return status == CAIRO_STATUS_SUCCESS;
262 }
263
264 static cairo_int_status_t
265 fallback_boxes (cairo_xlib_surface_t    *dst,
266                 const cairo_pattern_t   *pattern,
267                 cairo_boxes_t           *boxes)
268 {
269     struct _fallback_box fb;
270
271     /* XXX create_similar_image using pixman_format? */
272     switch (dst->depth) {
273     case 8: fb.format = CAIRO_FORMAT_A8; break;
274     case 16: fb.format = CAIRO_FORMAT_RGB16_565; break;
275     case 24: fb.format = CAIRO_FORMAT_RGB24; break;
276     case 30: fb.format = CAIRO_FORMAT_RGB30; break;
277     case 32: fb.format = CAIRO_FORMAT_ARGB32; break;
278     default: return CAIRO_INT_STATUS_UNSUPPORTED;
279     }
280
281     fb.dst = dst;
282     fb.pattern = pattern;
283
284     if (! _cairo_boxes_for_each_box (boxes, fallback_box, &fb))
285         return CAIRO_INT_STATUS_UNSUPPORTED;
286
287     return CAIRO_STATUS_SUCCESS;
288 }
289
290 static cairo_int_status_t
291 render_boxes (cairo_xlib_surface_t      *dst,
292               const cairo_pattern_t     *pattern,
293               cairo_boxes_t             *boxes)
294 {
295     double pad;
296
297     if (_cairo_pattern_analyze_filter (pattern, &pad) != CAIRO_FILTER_NEAREST)
298         return fallback_boxes (dst, pattern, boxes);
299
300     switch (pattern->extend) {
301     default:
302     case CAIRO_EXTEND_NONE:
303     case CAIRO_EXTEND_REFLECT:
304     case CAIRO_EXTEND_PAD:
305         return fallback_boxes (dst, pattern, boxes);
306
307     case CAIRO_EXTEND_REPEAT: /* XXX Use tiling */
308         return fallback_boxes (dst, pattern, boxes);
309     }
310 }
311
312 /* the mid-level: converts boxes into drawing operations */
313
314 struct _box_data {
315     Display *dpy;
316     cairo_xlib_surface_t *dst;
317     cairo_surface_t *src;
318     GC gc;
319     int tx, ty;
320     int width, height;
321 };
322
323 static cairo_bool_t source_contains_box (cairo_box_t *box, void *closure)
324 {
325     struct _box_data *data = closure;
326
327     /* The box is pixel-aligned so the truncation is safe. */
328     return
329         _cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 &&
330         _cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 &&
331         _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width &&
332         _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height;
333 }
334
335 static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure)
336 {
337     const struct _box_data *iub = closure;
338     int x = _cairo_fixed_integer_part (box->p1.x);
339     int y = _cairo_fixed_integer_part (box->p1.y);
340     int width  = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
341     int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
342
343     return _cairo_xlib_surface_draw_image (iub->dst,
344                                            (cairo_image_surface_t *)iub->src,
345                                            x + iub->tx, y + iub->ty,
346                                            width, height,
347                                            x, y) == CAIRO_STATUS_SUCCESS;
348 }
349
350 static cairo_bool_t
351 surface_matches_image_format (cairo_xlib_surface_t *surface,
352                               cairo_image_surface_t *image)
353 {
354     cairo_format_masks_t format;
355
356     return (_pixman_format_to_masks (image->pixman_format, &format) &&
357             (format.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
358             (format.red_mask   == surface->r_mask || surface->r_mask == 0) &&
359             (format.green_mask == surface->g_mask || surface->g_mask == 0) &&
360             (format.blue_mask  == surface->b_mask || surface->b_mask == 0));
361 }
362
363 static cairo_status_t
364 upload_image_inplace (cairo_xlib_surface_t *dst,
365                       const cairo_pattern_t *source,
366                       cairo_boxes_t *boxes)
367 {
368     const cairo_surface_pattern_t *pattern;
369     struct _box_data iub;
370     cairo_image_surface_t *image;
371
372     if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
373         return CAIRO_INT_STATUS_UNSUPPORTED;
374
375     pattern = (const cairo_surface_pattern_t *) source;
376     if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE)
377         return CAIRO_INT_STATUS_UNSUPPORTED;
378
379     image = (cairo_image_surface_t *) pattern->surface;
380     if (image->format == CAIRO_FORMAT_INVALID)
381         return CAIRO_INT_STATUS_UNSUPPORTED;
382
383     if (image->depth != dst->depth)
384         return CAIRO_INT_STATUS_UNSUPPORTED;
385
386     if (! surface_matches_image_format (dst, image))
387         return CAIRO_INT_STATUS_UNSUPPORTED;
388
389     /* XXX subsurface */
390
391     if (! _cairo_matrix_is_integer_translation (&source->matrix,
392                                                 &iub.tx, &iub.ty))
393         return CAIRO_INT_STATUS_UNSUPPORTED;
394
395     iub.dst = dst;
396     iub.src = &image->base;
397     iub.width  = image->width;
398     iub.height = image->height;
399
400     /* First check that the data is entirely within the image */
401     if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &iub))
402         return CAIRO_INT_STATUS_UNSUPPORTED;
403
404     if (! _cairo_boxes_for_each_box (boxes, image_upload_box, &iub))
405         return CAIRO_INT_STATUS_UNSUPPORTED;
406
407     return CAIRO_STATUS_SUCCESS;
408 }
409
410 static cairo_bool_t copy_box (cairo_box_t *box, void *closure)
411 {
412     const struct _box_data *cb = closure;
413     int x = _cairo_fixed_integer_part (box->p1.x);
414     int y = _cairo_fixed_integer_part (box->p1.y);
415     int width  = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
416     int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
417
418     XCopyArea (cb->dpy,
419                ((cairo_xlib_surface_t *)cb->src)->drawable,
420                cb->dst->drawable,
421                cb->gc,
422                x + cb->tx, y + cb->ty,
423                width, height,
424                x, y);
425     return TRUE;
426 }
427
428 static cairo_status_t
429 copy_boxes (cairo_xlib_surface_t *dst,
430             const cairo_pattern_t *source,
431             cairo_boxes_t *boxes)
432 {
433     const cairo_surface_pattern_t *pattern;
434     struct _box_data cb;
435     cairo_xlib_surface_t *src;
436     cairo_status_t status;
437
438     if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
439         return CAIRO_INT_STATUS_UNSUPPORTED;
440
441     /* XXX subsurface */
442
443     pattern = (const cairo_surface_pattern_t *) source;
444     if (pattern->surface->backend->type != CAIRO_SURFACE_TYPE_XLIB)
445         return CAIRO_INT_STATUS_UNSUPPORTED;
446
447     src = (cairo_xlib_surface_t *) pattern->surface;
448     if (src->depth != dst->depth)
449         return CAIRO_INT_STATUS_UNSUPPORTED;
450
451     /* We can only have a single control for subwindow_mode on the
452      * GC. If we have a Window destination, we need to set ClipByChildren,
453      * but if we have a Window source, we need IncludeInferiors. If we have
454      * both a Window destination and source, we must fallback. There is
455      * no convenient way to detect if a drawable is a Pixmap or Window,
456      * therefore we can only rely on those surfaces that we created
457      * ourselves to be Pixmaps, and treat everything else as a potential
458      * Window.
459      */
460     if (! src->owns_pixmap && ! dst->owns_pixmap)
461         return CAIRO_INT_STATUS_UNSUPPORTED;
462
463     if (! _cairo_xlib_surface_same_screen (dst, src))
464         return CAIRO_INT_STATUS_UNSUPPORTED;
465
466     if (! _cairo_matrix_is_integer_translation (&source->matrix,
467                                                 &cb.tx, &cb.ty))
468         return CAIRO_INT_STATUS_UNSUPPORTED;
469
470     cb.dpy = dst->display->display;
471     cb.dst = dst;
472     cb.src = &src->base;
473     cb.width  = src->width;
474     cb.height = src->height;
475
476     /* First check that the data is entirely within the image */
477     if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
478         return CAIRO_INT_STATUS_UNSUPPORTED;
479
480     status = _cairo_xlib_surface_get_gc (dst->display, dst, &cb.gc);
481     if (unlikely (status))
482         return status;
483
484     if (! src->owns_pixmap) {
485         XGCValues gcv;
486
487         gcv.subwindow_mode = IncludeInferiors;
488         XChangeGC (dst->display->display, cb.gc, GCSubwindowMode, &gcv);
489     }
490
491     status = CAIRO_STATUS_SUCCESS;
492     if (! _cairo_boxes_for_each_box (boxes, copy_box, &cb))
493         status = CAIRO_INT_STATUS_UNSUPPORTED;
494
495     if (! src->owns_pixmap) {
496         XGCValues gcv;
497
498         gcv.subwindow_mode = ClipByChildren;
499         XChangeGC (dst->display->display, cb.gc, GCSubwindowMode, &gcv);
500     }
501
502     _cairo_xlib_surface_put_gc (dst->display, dst, cb.gc);
503
504     return status;
505 }
506
507 static cairo_status_t
508 draw_boxes (cairo_composite_rectangles_t *extents,
509             cairo_boxes_t *boxes)
510 {
511     cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface;
512     cairo_operator_t op = extents->op;
513     const cairo_pattern_t *src = &extents->source_pattern.base;
514     cairo_int_status_t status;
515
516     if (boxes->num_boxes == 0 && extents->is_bounded)
517         return CAIRO_STATUS_SUCCESS;
518
519     if (! boxes->is_pixel_aligned)
520         return CAIRO_INT_STATUS_UNSUPPORTED;
521
522     if (op == CAIRO_OPERATOR_CLEAR)
523         op = CAIRO_OPERATOR_SOURCE;
524
525     if (op == CAIRO_OPERATOR_OVER &&
526         _cairo_pattern_is_opaque (src, &extents->bounded))
527         op = CAIRO_OPERATOR_SOURCE;
528
529     if (dst->base.is_clear && op == CAIRO_OPERATOR_OVER)
530         op = CAIRO_OPERATOR_SOURCE;
531
532     if (op != CAIRO_OPERATOR_SOURCE)
533         return CAIRO_INT_STATUS_UNSUPPORTED;
534
535     status = acquire (dst);
536     if (unlikely (status))
537         return status;
538
539     if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
540         status = _cairo_xlib_core_fill_boxes
541             (dst, &((cairo_solid_pattern_t *) src)->color, boxes);
542     } else {
543         status = upload_image_inplace (dst, src, boxes);
544         if (status == CAIRO_INT_STATUS_UNSUPPORTED)
545             status = copy_boxes (dst, src, boxes);
546         if (status == CAIRO_INT_STATUS_UNSUPPORTED)
547             status = render_boxes (dst, src, boxes);
548     }
549
550     release (dst);
551
552     return status;
553 }
554
555 /* high-level compositor interface */
556
557 static cairo_int_status_t
558 _cairo_xlib_core_compositor_paint (const cairo_compositor_t     *compositor,
559                                    cairo_composite_rectangles_t *extents)
560 {
561     cairo_int_status_t status;
562
563     status = CAIRO_INT_STATUS_UNSUPPORTED;
564     if (_cairo_clip_is_region (extents->clip)) {
565         cairo_boxes_t boxes;
566
567          _cairo_clip_steal_boxes (extents->clip, &boxes);
568          status = draw_boxes (extents, &boxes);
569          _cairo_clip_unsteal_boxes (extents->clip, &boxes);
570     }
571
572     return status;
573 }
574
575 static cairo_int_status_t
576 _cairo_xlib_core_compositor_stroke (const cairo_compositor_t    *compositor,
577                                     cairo_composite_rectangles_t *extents,
578                                     const cairo_path_fixed_t    *path,
579                                     const cairo_stroke_style_t  *style,
580                                     const cairo_matrix_t        *ctm,
581                                     const cairo_matrix_t        *ctm_inverse,
582                                     double                       tolerance,
583                                     cairo_antialias_t            antialias)
584 {
585     cairo_int_status_t status;
586
587     status = CAIRO_INT_STATUS_UNSUPPORTED;
588     if (extents->clip->path == NULL &&
589         _cairo_path_fixed_stroke_is_rectilinear (path)) {
590         cairo_boxes_t boxes;
591
592         _cairo_boxes_init_with_clip (&boxes, extents->clip);
593         status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
594                                                                 style,
595                                                                 ctm,
596                                                                 antialias,
597                                                                 &boxes);
598         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
599             status = draw_boxes (extents, &boxes);
600         _cairo_boxes_fini (&boxes);
601     }
602
603     return status;
604 }
605
606 static cairo_int_status_t
607 _cairo_xlib_core_compositor_fill (const cairo_compositor_t      *compositor,
608                                   cairo_composite_rectangles_t  *extents,
609                                   const cairo_path_fixed_t      *path,
610                                   cairo_fill_rule_t              fill_rule,
611                                   double                         tolerance,
612                                   cairo_antialias_t              antialias)
613 {
614     cairo_int_status_t status;
615
616     status = CAIRO_INT_STATUS_UNSUPPORTED;
617     if (extents->clip->path == NULL &&
618         _cairo_path_fixed_fill_is_rectilinear (path)) {
619         cairo_boxes_t boxes;
620
621         _cairo_boxes_init_with_clip (&boxes, extents->clip);
622         status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
623                                                               fill_rule,
624                                                               antialias,
625                                                               &boxes);
626         if (likely (status == CAIRO_INT_STATUS_SUCCESS))
627             status = draw_boxes (extents, &boxes);
628         _cairo_boxes_fini (&boxes);
629     }
630
631     return status;
632 }
633
634 const cairo_compositor_t *
635 _cairo_xlib_core_compositor_get (void)
636 {
637     static cairo_compositor_t compositor;
638
639     if (compositor.delegate == NULL) {
640         compositor.delegate = _cairo_xlib_fallback_compositor_get ();
641
642         compositor.paint = _cairo_xlib_core_compositor_paint;
643         compositor.mask  = NULL;
644         compositor.fill  = _cairo_xlib_core_compositor_fill;
645         compositor.stroke = _cairo_xlib_core_compositor_stroke;
646         compositor.glyphs = NULL; /* XXX PolyGlyph? */
647     }
648
649     return &compositor;
650 }
651
652 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */