tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-xlib-display.c
1 /* Cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2007 Chris Wilson
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it either under the terms of the GNU Lesser General Public
7  * License version 2.1 as published by the Free Software Foundation
8  * (the "LGPL") or, at your option, under the terms of the Mozilla
9  * Public License Version 1.1 (the "MPL"). If you do not alter this
10  * notice, a recipient may use your version of this file under either
11  * the MPL or the LGPL.
12  *
13  * You should have received a copy of the LGPL along with this library
14  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16  * You should have received a copy of the MPL along with this library
17  * in the file COPYING-MPL-1.1
18  *
19  * The contents of this file are subject to the Mozilla Public License
20  * Version 1.1 (the "License"); you may not use this file except in
21  * compliance with the License. You may obtain a copy of the License at
22  * http://www.mozilla.org/MPL/
23  *
24  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26  * the specific language governing rights and limitations.
27  *
28  * The Original Code is the cairo graphics library.
29  *
30  * The Initial Developer of the Original Code is Chris Wilson.
31  *
32  * Contributor(s):
33  *      Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
34  */
35
36 #include "cairoint.h"
37
38 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
39
40 #include "cairo-xlib-private.h"
41 #include "cairo-xlib-xrender-private.h"
42 #include "cairo-freelist-private.h"
43 #include "cairo-error-private.h"
44 #include "cairo-list-inline.h"
45
46 #include <X11/Xlibint.h>        /* For XESetCloseDisplay */
47
48 typedef int (*cairo_xlib_error_func_t) (Display     *display,
49                                         XErrorEvent *event);
50
51 static cairo_xlib_display_t *_cairo_xlib_display_list;
52
53 static int
54 _noop_error_handler (Display     *display,
55                      XErrorEvent *event)
56 {
57     return False;               /* return value is ignored */
58 }
59
60 static void
61 _cairo_xlib_display_finish (void *abstract_display)
62 {
63     cairo_xlib_display_t *display = abstract_display;
64     Display *dpy = display->display;
65
66     _cairo_xlib_display_fini_shm (display);
67
68     if (! cairo_device_acquire (&display->base)) {
69         cairo_xlib_error_func_t old_handler;
70
71         /* protect the notifies from triggering XErrors */
72         XSync (dpy, False);
73         old_handler = XSetErrorHandler (_noop_error_handler);
74
75         while (! cairo_list_is_empty (&display->fonts)) {
76             _cairo_xlib_font_close (cairo_list_first_entry (&display->fonts,
77                                                             cairo_xlib_font_t,
78                                                             link));
79         }
80
81         while (! cairo_list_is_empty (&display->screens)) {
82             _cairo_xlib_screen_destroy (display,
83                                         cairo_list_first_entry (&display->screens,
84                                                                 cairo_xlib_screen_t,
85                                                                 link));
86         }
87
88         XSync (dpy, False);
89         XSetErrorHandler (old_handler);
90
91         cairo_device_release (&display->base);
92     }
93 }
94
95 static void
96 _cairo_xlib_display_destroy (void *abstract_display)
97 {
98     cairo_xlib_display_t *display = abstract_display;
99
100     free (display);
101 }
102
103 static int
104 _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
105 {
106     cairo_xlib_display_t *display, **prev, *next;
107
108     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
109     for (display = _cairo_xlib_display_list; display; display = display->next)
110         if (display->display == dpy)
111             break;
112     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
113     if (display == NULL)
114         return 0;
115
116     cairo_device_finish (&display->base);
117
118     /*
119      * Unhook from the global list
120      */
121     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
122     prev = &_cairo_xlib_display_list;
123     for (display = _cairo_xlib_display_list; display; display = next) {
124         next = display->next;
125         if (display->display == dpy) {
126             *prev = next;
127             break;
128         } else
129             prev = &display->next;
130     }
131     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
132
133     if (display) {
134         display->display = NULL; /* catch any later invalid access */
135         cairo_device_destroy (&display->base);
136     }
137     /* Return value in accordance with requirements of
138      * XESetCloseDisplay */
139     return 0;
140 }
141
142 static const cairo_device_backend_t _cairo_xlib_device_backend = {
143     CAIRO_DEVICE_TYPE_XLIB,
144
145     NULL,
146     NULL,
147
148     NULL, /* flush */
149     _cairo_xlib_display_finish,
150     _cairo_xlib_display_destroy,
151 };
152
153 static void _cairo_xlib_display_select_compositor (cairo_xlib_display_t *display)
154 {
155 #if 0
156     if (display->render_major > 0 || display->render_minor >= 4)
157         display->compositor = _cairo_xlib_traps_compositor_get ();
158     else if (display->render_major > 0 || display->render_minor >= 0)
159         display->compositor = _cairo_xlib_mask_compositor_get ();
160     else
161         display->compositor = _cairo_xlib_core_compositor_get ();
162 #else
163     display->compositor = _cairo_xlib_fallback_compositor_get ();
164 #endif
165 }
166
167 /**
168  * _cairo_xlib_device_create:
169  * @dpy: the display to create the device for
170  *
171  * Gets the device belonging to @dpy, or creates it if it doesn't exist yet.
172  *
173  * Returns: the device belonging to @dpy
174  **/
175 cairo_device_t *
176 _cairo_xlib_device_create (Display *dpy)
177 {
178     cairo_xlib_display_t *display;
179     cairo_xlib_display_t **prev;
180     cairo_device_t *device;
181     XExtCodes *codes;
182     const char *env;
183
184     CAIRO_MUTEX_INITIALIZE ();
185
186     /* There is an apparent deadlock between this mutex and the
187      * mutex for the display, but it's actually safe. For the
188      * app to call XCloseDisplay() while any other thread is
189      * inside this function would be an error in the logic
190      * app, and the CloseDisplay hook is the only other place we
191      * acquire this mutex.
192      */
193     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
194
195     for (prev = &_cairo_xlib_display_list; (display = *prev); prev = &(*prev)->next)
196     {
197         if (display->display == dpy) {
198             /*
199              * MRU the list
200              */
201             if (prev != &_cairo_xlib_display_list) {
202                 *prev = display->next;
203                 display->next = _cairo_xlib_display_list;
204                 _cairo_xlib_display_list = display;
205             }
206             device = cairo_device_reference (&display->base);
207             goto UNLOCK;
208         }
209     }
210
211     display = malloc (sizeof (cairo_xlib_display_t));
212     if (unlikely (display == NULL)) {
213         device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
214         goto UNLOCK;
215     }
216
217     _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
218
219     display->display = dpy;
220     cairo_list_init (&display->screens);
221     cairo_list_init (&display->fonts);
222     display->closed = FALSE;
223
224     /* Xlib calls out to the extension close_display hooks in LIFO
225      * order. So we have to ensure that all extensions that we depend
226      * on in our close_display hook are properly initialized before we
227      * add our hook. For now, that means Render, so we call into its
228      * QueryVersion function to ensure it gets initialized.
229      */
230     display->render_major = display->render_minor = -1;
231     XRenderQueryVersion (dpy, &display->render_major, &display->render_minor);
232     env = getenv ("CAIRO_DEBUG");
233     if (env != NULL && (env = strstr (env, "xrender-version=")) != NULL) {
234         int max_render_major, max_render_minor;
235
236         env += sizeof ("xrender-version=") - 1;
237         if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2)
238             max_render_major = max_render_minor = -1;
239
240         if (max_render_major < display->render_major ||
241             (max_render_major == display->render_major &&
242              max_render_minor < display->render_minor))
243         {
244             display->render_major = max_render_major;
245             display->render_minor = max_render_minor;
246         }
247     }
248
249     _cairo_xlib_display_select_compositor (display);
250
251     display->white = NULL;
252     memset (display->alpha, 0, sizeof (display->alpha));
253     memset (display->solid, 0, sizeof (display->solid));
254     memset (display->solid_cache, 0, sizeof (display->solid_cache));
255     memset (display->last_solid_cache, 0, sizeof (display->last_solid_cache));
256
257     memset (display->cached_xrender_formats, 0,
258             sizeof (display->cached_xrender_formats));
259
260     display->force_precision = -1;
261
262     _cairo_xlib_display_init_shm (display);
263
264     /* Prior to Render 0.10, there is no protocol support for gradients and
265      * we call function stubs instead, which would silently consume the drawing.
266      */
267 #if RENDER_MAJOR == 0 && RENDER_MINOR < 10
268     display->buggy_gradients = TRUE;
269 #else
270     display->buggy_gradients = FALSE;
271 #endif
272     display->buggy_pad_reflect = FALSE;
273     display->buggy_repeat = FALSE;
274
275     /* This buggy_repeat condition is very complicated because there
276      * are multiple X server code bases (with multiple versioning
277      * schemes within a code base), and multiple bugs.
278      *
279      * The X servers:
280      *
281      *    1. The Vendor=="XFree86" code base with release numbers such
282      *    as 4.7.0 (VendorRelease==40700000).
283      *
284      *    2. The Vendor=="X.Org" code base (a descendant of the
285      *    XFree86 code base). It originally had things like
286      *    VendorRelease==60700000 for release 6.7.0 but then changed
287      *    its versioning scheme so that, for example,
288      *    VendorRelease==10400000 for the 1.4.0 X server within the
289      *    X.Org 7.3 release.
290      *
291      * The bugs:
292      *
293      *    1. The original bug that led to the buggy_repeat
294      *    workaround. This was a bug that Owen Taylor investigated,
295      *    understood well, and characterized against carious X
296      *    servers. Confirmed X servers with this bug include:
297      *
298      *          "XFree86" <= 40500000
299      *          "X.Org" <= 60802000 (only with old numbering >= 60700000)
300      *
301      *    2. A separate bug resulting in a crash of the X server when
302      *    using cairo's extend-reflect test case, (which, surprisingly
303      *    enough was not passing RepeatReflect to the X server, but
304      *    instead using RepeatNormal in a workaround). Nobody to date
305      *    has understood the bug well, but it appears to be gone as of
306      *    the X.Org 1.4.0 server. This bug is coincidentally avoided
307      *    by using the same buggy_repeat workaround. Confirmed X
308      *    servers with this bug include:
309      *
310      *          "X.org" == 60900000 (old versioning scheme)
311      *          "X.org"  < 10400000 (new numbering scheme)
312      *
313      *    For the old-versioning-scheme X servers we don't know
314      *    exactly when second the bug started, but since bug 1 is
315      *    present through 6.8.2 and bug 2 is present in 6.9.0 it seems
316      *    safest to just blacklist all old-versioning-scheme X servers,
317      *    (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
318      */
319     if (_cairo_xlib_vendor_is_xorg (dpy)) {
320         if (VendorRelease (dpy) >= 60700000) {
321             if (VendorRelease (dpy) < 70000000)
322                 display->buggy_repeat = TRUE;
323
324             /* We know that gradients simply do not work in early Xorg servers */
325             if (VendorRelease (dpy) < 70200000)
326                 display->buggy_gradients = TRUE;
327
328             /* And the extended repeat modes were not fixed until much later */
329             display->buggy_pad_reflect = TRUE;
330         } else {
331             if (VendorRelease (dpy) < 10400000)
332                 display->buggy_repeat = TRUE;
333
334             /* Too many bugs in the early drivers */
335             if (VendorRelease (dpy) < 10699000)
336                 display->buggy_pad_reflect = TRUE;
337         }
338     } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
339         if (VendorRelease (dpy) <= 40500000)
340             display->buggy_repeat = TRUE;
341
342         display->buggy_gradients = TRUE;
343         display->buggy_pad_reflect = TRUE;
344     }
345
346     codes = XAddExtension (dpy);
347     if (unlikely (codes == NULL)) {
348         device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
349         free (display->shm);
350         free (display);
351         goto UNLOCK;
352     }
353
354     XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
355     cairo_device_reference (&display->base); /* add one for the CloseDisplay */
356
357     display->next = _cairo_xlib_display_list;
358     _cairo_xlib_display_list = display;
359
360     device = &display->base;
361
362 UNLOCK:
363     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
364     return device;
365 }
366
367 cairo_status_t
368 _cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **display)
369 {
370     cairo_status_t status;
371
372     status = cairo_device_acquire (device);
373     if (status)
374         return status;
375
376     *display = (cairo_xlib_display_t *) device;
377     return CAIRO_STATUS_SUCCESS;
378 }
379
380 XRenderPictFormat *
381 _cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t *display,
382                                                   pixman_format_code_t format)
383 {
384     Display *dpy = display->display;
385     XRenderPictFormat tmpl;
386     int mask;
387
388 #define MASK(x) ((1<<(x))-1)
389
390     tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
391     mask = PictFormatType | PictFormatDepth;
392
393     switch (PIXMAN_FORMAT_TYPE(format)) {
394     case PIXMAN_TYPE_ARGB:
395         tmpl.type = PictTypeDirect;
396
397         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
398         if (PIXMAN_FORMAT_A(format))
399             tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) +
400                                  PIXMAN_FORMAT_G(format) +
401                                  PIXMAN_FORMAT_B(format));
402
403         tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
404         tmpl.direct.red = (PIXMAN_FORMAT_G(format) +
405                            PIXMAN_FORMAT_B(format));
406
407         tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
408         tmpl.direct.green = PIXMAN_FORMAT_B(format);
409
410         tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
411         tmpl.direct.blue = 0;
412
413         mask |= PictFormatRed | PictFormatRedMask;
414         mask |= PictFormatGreen | PictFormatGreenMask;
415         mask |= PictFormatBlue | PictFormatBlueMask;
416         mask |= PictFormatAlpha | PictFormatAlphaMask;
417         break;
418
419     case PIXMAN_TYPE_ABGR:
420         tmpl.type = PictTypeDirect;
421
422         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
423         if (tmpl.direct.alphaMask)
424             tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) +
425                                  PIXMAN_FORMAT_G(format) +
426                                  PIXMAN_FORMAT_R(format));
427
428         tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
429         tmpl.direct.blue = (PIXMAN_FORMAT_G(format) +
430                             PIXMAN_FORMAT_R(format));
431
432         tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
433         tmpl.direct.green = PIXMAN_FORMAT_R(format);
434
435         tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
436         tmpl.direct.red = 0;
437
438         mask |= PictFormatRed | PictFormatRedMask;
439         mask |= PictFormatGreen | PictFormatGreenMask;
440         mask |= PictFormatBlue | PictFormatBlueMask;
441         mask |= PictFormatAlpha | PictFormatAlphaMask;
442         break;
443
444     case PIXMAN_TYPE_BGRA:
445         tmpl.type = PictTypeDirect;
446
447         tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
448         tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format));
449
450         tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
451         tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
452                              PIXMAN_FORMAT_G(format));
453
454         tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
455         tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
456                            PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format));
457
458         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
459         tmpl.direct.alpha = 0;
460
461         mask |= PictFormatRed | PictFormatRedMask;
462         mask |= PictFormatGreen | PictFormatGreenMask;
463         mask |= PictFormatBlue | PictFormatBlueMask;
464         mask |= PictFormatAlpha | PictFormatAlphaMask;
465         break;
466
467     case PIXMAN_TYPE_A:
468         tmpl.type = PictTypeDirect;
469
470         tmpl.direct.alpha = 0;
471         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
472
473         mask |= PictFormatAlpha | PictFormatAlphaMask;
474         break;
475
476     case PIXMAN_TYPE_COLOR:
477     case PIXMAN_TYPE_GRAY:
478         /* XXX Find matching visual/colormap */
479         tmpl.type = PictTypeIndexed;
480         //tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid;
481         //mask |= PictFormatColormap;
482         return NULL;
483     }
484 #undef MASK
485
486     /* XXX caching? */
487     return XRenderFindFormat(dpy, mask, &tmpl, 1);
488 }
489
490 XRenderPictFormat *
491 _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t    *display,
492                                         cairo_format_t           format)
493 {
494     XRenderPictFormat *xrender_format;
495
496 #if ! ATOMIC_OP_NEEDS_MEMORY_BARRIER
497     xrender_format = display->cached_xrender_formats[format];
498     if (likely (xrender_format != NULL))
499         return xrender_format;
500 #endif
501
502     xrender_format = display->cached_xrender_formats[format];
503     if (xrender_format == NULL) {
504         int pict_format = PictStandardNUM;
505
506         switch (format) {
507         case CAIRO_FORMAT_A1:
508             pict_format = PictStandardA1; break;
509         case CAIRO_FORMAT_A8:
510             pict_format = PictStandardA8; break;
511         case CAIRO_FORMAT_RGB24:
512             pict_format = PictStandardRGB24; break;
513         case CAIRO_FORMAT_RGB16_565:
514             xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
515                                                                                PIXMAN_r5g6b5);
516             break;
517         case CAIRO_FORMAT_RGB30:
518             xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
519                                                                                PIXMAN_x2r10g10b10);
520             break;
521         case CAIRO_FORMAT_INVALID:
522         default:
523             ASSERT_NOT_REACHED;
524         case CAIRO_FORMAT_ARGB32:
525             pict_format = PictStandardARGB32; break;
526         }
527         if (pict_format != PictStandardNUM)
528             xrender_format =
529                 XRenderFindStandardFormat (display->display, pict_format);
530         display->cached_xrender_formats[format] = xrender_format;
531     }
532
533     return xrender_format;
534 }
535
536 cairo_xlib_screen_t *
537 _cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
538                                 Screen *screen)
539 {
540     cairo_xlib_screen_t *info;
541
542     cairo_list_foreach_entry (info, cairo_xlib_screen_t, &display->screens, link) {
543         if (info->screen == screen) {
544             if (display->screens.next != &info->link)
545                 cairo_list_move (&info->link, &display->screens);
546             return info;
547         }
548     }
549
550     return NULL;
551 }
552
553 cairo_bool_t
554 _cairo_xlib_display_has_repeat (cairo_device_t *device)
555 {
556     return ! ((cairo_xlib_display_t *) device)->buggy_repeat;
557 }
558
559 cairo_bool_t
560 _cairo_xlib_display_has_reflect (cairo_device_t *device)
561 {
562     return ! ((cairo_xlib_display_t *) device)->buggy_pad_reflect;
563 }
564
565 cairo_bool_t
566 _cairo_xlib_display_has_gradients (cairo_device_t *device)
567 {
568     return ! ((cairo_xlib_display_t *) device)->buggy_gradients;
569 }
570
571 /**
572  * cairo_xlib_device_debug_cap_xrender_version:
573  * @device: a #cairo_device_t for the Xlib backend
574  * @major_version: major version to restrict to
575  * @minor_version: minor version to restrict to
576  *
577  * Restricts all future Xlib surfaces for this devices to the specified version
578  * of the RENDER extension. This function exists solely for debugging purpose.
579  * It let's you find out how cairo would behave with an older version of
580  * the RENDER extension.
581  *
582  * Use the special values -1 and -1 for disabling the RENDER extension.
583  *
584  * Since: 1.12
585  **/
586 void
587 cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device,
588                                              int major_version,
589                                              int minor_version)
590 {
591     cairo_xlib_display_t *display = (cairo_xlib_display_t *) device;
592
593     if (device == NULL || device->status)
594         return;
595
596     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB)
597         return;
598
599     if (major_version < display->render_major ||
600         (major_version == display->render_major &&
601          minor_version < display->render_minor))
602     {
603         display->render_major = major_version;
604         display->render_minor = minor_version;
605     }
606
607     _cairo_xlib_display_select_compositor (display);
608 }
609
610 /**
611  * cairo_xlib_device_debug_set_precision:
612  * @device: a #cairo_device_t for the Xlib backend
613  * @precision: the precision to use
614  *
615  * Render supports two modes of precision when rendering trapezoids. Set
616  * the precision to the desired mode.
617  *
618  * Since: 1.12
619  **/
620 void
621 cairo_xlib_device_debug_set_precision (cairo_device_t *device,
622                                        int precision)
623 {
624     if (device == NULL || device->status)
625         return;
626     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
627         cairo_status_t status;
628
629         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
630         (void) status;
631         return;
632     }
633
634     ((cairo_xlib_display_t *) device)->force_precision = precision;
635 }
636
637 /**
638  * cairo_xlib_device_debug_get_precision:
639  * @device: a #cairo_device_t for the Xlib backend
640  *
641  * Get the Xrender precision mode.
642  *
643  * Returns: the render precision mode
644  *
645  * Since: 1.12
646  **/
647 int
648 cairo_xlib_device_debug_get_precision (cairo_device_t *device)
649 {
650     if (device == NULL || device->status)
651         return -1;
652     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
653         cairo_status_t status;
654
655         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
656         (void) status;
657         return -1;
658     }
659
660     return ((cairo_xlib_display_t *) device)->force_precision;
661 }
662
663 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */