Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.     display->display = NULL; /* catch any later invalid access */
  134.     cairo_device_destroy (&display->base);
  135.  
  136.     /* Return value in accordance with requirements of
  137.      * XESetCloseDisplay */
  138.     return 0;
  139. }
  140.  
  141. static const cairo_device_backend_t _cairo_xlib_device_backend = {
  142.     CAIRO_DEVICE_TYPE_XLIB,
  143.  
  144.     NULL,
  145.     NULL,
  146.  
  147.     NULL, /* flush */
  148.     _cairo_xlib_display_finish,
  149.     _cairo_xlib_display_destroy,
  150. };
  151.  
  152. static void _cairo_xlib_display_select_compositor (cairo_xlib_display_t *display)
  153. {
  154. #if 1
  155.     if (display->render_major > 0 || display->render_minor >= 4)
  156.         display->compositor = _cairo_xlib_traps_compositor_get ();
  157.     else if (display->render_major > 0 || display->render_minor >= 0)
  158.         display->compositor = _cairo_xlib_mask_compositor_get ();
  159.     else
  160.         display->compositor = _cairo_xlib_core_compositor_get ();
  161. #else
  162.     display->compositor = _cairo_xlib_fallback_compositor_get ();
  163. #endif
  164. }
  165.  
  166. /**
  167.  * _cairo_xlib_device_create:
  168.  * @dpy: the display to create the device for
  169.  *
  170.  * Gets the device belonging to @dpy, or creates it if it doesn't exist yet.
  171.  *
  172.  * Returns: the device belonging to @dpy
  173.  **/
  174. cairo_device_t *
  175. _cairo_xlib_device_create (Display *dpy)
  176. {
  177.     cairo_xlib_display_t *display;
  178.     cairo_xlib_display_t **prev;
  179.     cairo_device_t *device;
  180.     XExtCodes *codes;
  181.     const char *env;
  182.  
  183.     CAIRO_MUTEX_INITIALIZE ();
  184.  
  185.     /* There is an apparent deadlock between this mutex and the
  186.      * mutex for the display, but it's actually safe. For the
  187.      * app to call XCloseDisplay() while any other thread is
  188.      * inside this function would be an error in the logic
  189.      * app, and the CloseDisplay hook is the only other place we
  190.      * acquire this mutex.
  191.      */
  192.     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
  193.  
  194.     for (prev = &_cairo_xlib_display_list; (display = *prev); prev = &(*prev)->next)
  195.     {
  196.         if (display->display == dpy) {
  197.             /*
  198.              * MRU the list
  199.              */
  200.             if (prev != &_cairo_xlib_display_list) {
  201.                 *prev = display->next;
  202.                 display->next = _cairo_xlib_display_list;
  203.                 _cairo_xlib_display_list = display;
  204.             }
  205.             device = cairo_device_reference (&display->base);
  206.             goto UNLOCK;
  207.         }
  208.     }
  209.  
  210.     display = malloc (sizeof (cairo_xlib_display_t));
  211.     if (unlikely (display == NULL)) {
  212.         device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
  213.         goto UNLOCK;
  214.     }
  215.  
  216.     _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
  217.  
  218.     display->display = dpy;
  219.     cairo_list_init (&display->screens);
  220.     cairo_list_init (&display->fonts);
  221.     display->closed = FALSE;
  222.  
  223.     /* Xlib calls out to the extension close_display hooks in LIFO
  224.      * order. So we have to ensure that all extensions that we depend
  225.      * on in our close_display hook are properly initialized before we
  226.      * add our hook. For now, that means Render, so we call into its
  227.      * QueryVersion function to ensure it gets initialized.
  228.      */
  229.     display->render_major = display->render_minor = -1;
  230.     XRenderQueryVersion (dpy, &display->render_major, &display->render_minor);
  231.     env = getenv ("CAIRO_DEBUG");
  232.     if (env != NULL && (env = strstr (env, "xrender-version=")) != NULL) {
  233.         int max_render_major, max_render_minor;
  234.  
  235.         env += sizeof ("xrender-version=") - 1;
  236.         if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2)
  237.             max_render_major = max_render_minor = -1;
  238.  
  239.         if (max_render_major < display->render_major ||
  240.             (max_render_major == display->render_major &&
  241.              max_render_minor < display->render_minor))
  242.         {
  243.             display->render_major = max_render_major;
  244.             display->render_minor = max_render_minor;
  245.         }
  246.     }
  247.  
  248.     _cairo_xlib_display_select_compositor (display);
  249.  
  250.     display->white = NULL;
  251.     memset (display->alpha, 0, sizeof (display->alpha));
  252.     memset (display->solid, 0, sizeof (display->solid));
  253.     memset (display->solid_cache, 0, sizeof (display->solid_cache));
  254.     memset (display->last_solid_cache, 0, sizeof (display->last_solid_cache));
  255.  
  256.     memset (display->cached_xrender_formats, 0,
  257.             sizeof (display->cached_xrender_formats));
  258.  
  259.     display->force_precision = -1;
  260.  
  261.     _cairo_xlib_display_init_shm (display);
  262.  
  263.     /* Prior to Render 0.10, there is no protocol support for gradients and
  264.      * we call function stubs instead, which would silently consume the drawing.
  265.      */
  266. #if RENDER_MAJOR == 0 && RENDER_MINOR < 10
  267.     display->buggy_gradients = TRUE;
  268. #else
  269.     display->buggy_gradients = FALSE;
  270. #endif
  271.     display->buggy_pad_reflect = FALSE;
  272.     display->buggy_repeat = FALSE;
  273.  
  274.     /* This buggy_repeat condition is very complicated because there
  275.      * are multiple X server code bases (with multiple versioning
  276.      * schemes within a code base), and multiple bugs.
  277.      *
  278.      * The X servers:
  279.      *
  280.      *    1. The Vendor=="XFree86" code base with release numbers such
  281.      *    as 4.7.0 (VendorRelease==40700000).
  282.      *
  283.      *    2. The Vendor=="X.Org" code base (a descendant of the
  284.      *    XFree86 code base). It originally had things like
  285.      *    VendorRelease==60700000 for release 6.7.0 but then changed
  286.      *    its versioning scheme so that, for example,
  287.      *    VendorRelease==10400000 for the 1.4.0 X server within the
  288.      *    X.Org 7.3 release.
  289.      *
  290.      * The bugs:
  291.      *
  292.      *    1. The original bug that led to the buggy_repeat
  293.      *    workaround. This was a bug that Owen Taylor investigated,
  294.      *    understood well, and characterized against carious X
  295.      *    servers. Confirmed X servers with this bug include:
  296.      *
  297.      *          "XFree86" <= 40500000
  298.      *          "X.Org" <= 60802000 (only with old numbering >= 60700000)
  299.      *
  300.      *    2. A separate bug resulting in a crash of the X server when
  301.      *    using cairo's extend-reflect test case, (which, surprisingly
  302.      *    enough was not passing RepeatReflect to the X server, but
  303.      *    instead using RepeatNormal in a workaround). Nobody to date
  304.      *    has understood the bug well, but it appears to be gone as of
  305.      *    the X.Org 1.4.0 server. This bug is coincidentally avoided
  306.      *    by using the same buggy_repeat workaround. Confirmed X
  307.      *    servers with this bug include:
  308.      *
  309.      *          "X.org" == 60900000 (old versioning scheme)
  310.      *          "X.org"  < 10400000 (new numbering scheme)
  311.      *
  312.      *    For the old-versioning-scheme X servers we don't know
  313.      *    exactly when second the bug started, but since bug 1 is
  314.      *    present through 6.8.2 and bug 2 is present in 6.9.0 it seems
  315.      *    safest to just blacklist all old-versioning-scheme X servers,
  316.      *    (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
  317.      */
  318.     if (_cairo_xlib_vendor_is_xorg (dpy)) {
  319.         if (VendorRelease (dpy) >= 60700000) {
  320.             if (VendorRelease (dpy) < 70000000)
  321.                 display->buggy_repeat = TRUE;
  322.  
  323.             /* We know that gradients simply do not work in early Xorg servers */
  324.             if (VendorRelease (dpy) < 70200000)
  325.                 display->buggy_gradients = TRUE;
  326.  
  327.             /* And the extended repeat modes were not fixed until much later */
  328.             display->buggy_pad_reflect = TRUE;
  329.         } else {
  330.             if (VendorRelease (dpy) < 10400000)
  331.                 display->buggy_repeat = TRUE;
  332.  
  333.             /* Too many bugs in the early drivers */
  334.             if (VendorRelease (dpy) < 10699000)
  335.                 display->buggy_pad_reflect = TRUE;
  336.         }
  337.     } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
  338.         if (VendorRelease (dpy) <= 40500000)
  339.             display->buggy_repeat = TRUE;
  340.  
  341.         display->buggy_gradients = TRUE;
  342.         display->buggy_pad_reflect = TRUE;
  343.     }
  344.  
  345.     codes = XAddExtension (dpy);
  346.     if (unlikely (codes == NULL)) {
  347.         device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
  348.         free (display);
  349.         goto UNLOCK;
  350.     }
  351.  
  352.     XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
  353.     cairo_device_reference (&display->base); /* add one for the CloseDisplay */
  354.  
  355.     display->next = _cairo_xlib_display_list;
  356.     _cairo_xlib_display_list = display;
  357.  
  358.     device = &display->base;
  359.  
  360. UNLOCK:
  361.     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
  362.     return device;
  363. }
  364.  
  365. cairo_status_t
  366. _cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **display)
  367. {
  368.     cairo_status_t status;
  369.  
  370.     status = cairo_device_acquire (device);
  371.     if (status)
  372.         return status;
  373.  
  374.     *display = (cairo_xlib_display_t *) device;
  375.     return CAIRO_STATUS_SUCCESS;
  376. }
  377.  
  378. XRenderPictFormat *
  379. _cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t *display,
  380.                                                   pixman_format_code_t format)
  381. {
  382.     Display *dpy = display->display;
  383.     XRenderPictFormat tmpl;
  384.     int mask;
  385.  
  386. #define MASK(x) ((1<<(x))-1)
  387.  
  388.     tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
  389.     mask = PictFormatType | PictFormatDepth;
  390.  
  391.     switch (PIXMAN_FORMAT_TYPE(format)) {
  392.     case PIXMAN_TYPE_ARGB:
  393.         tmpl.type = PictTypeDirect;
  394.  
  395.         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
  396.         if (PIXMAN_FORMAT_A(format))
  397.             tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) +
  398.                                  PIXMAN_FORMAT_G(format) +
  399.                                  PIXMAN_FORMAT_B(format));
  400.  
  401.         tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
  402.         tmpl.direct.red = (PIXMAN_FORMAT_G(format) +
  403.                            PIXMAN_FORMAT_B(format));
  404.  
  405.         tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
  406.         tmpl.direct.green = PIXMAN_FORMAT_B(format);
  407.  
  408.         tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
  409.         tmpl.direct.blue = 0;
  410.  
  411.         mask |= PictFormatRed | PictFormatRedMask;
  412.         mask |= PictFormatGreen | PictFormatGreenMask;
  413.         mask |= PictFormatBlue | PictFormatBlueMask;
  414.         mask |= PictFormatAlpha | PictFormatAlphaMask;
  415.         break;
  416.  
  417.     case PIXMAN_TYPE_ABGR:
  418.         tmpl.type = PictTypeDirect;
  419.  
  420.         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
  421.         if (tmpl.direct.alphaMask)
  422.             tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) +
  423.                                  PIXMAN_FORMAT_G(format) +
  424.                                  PIXMAN_FORMAT_R(format));
  425.  
  426.         tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
  427.         tmpl.direct.blue = (PIXMAN_FORMAT_G(format) +
  428.                             PIXMAN_FORMAT_R(format));
  429.  
  430.         tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
  431.         tmpl.direct.green = PIXMAN_FORMAT_R(format);
  432.  
  433.         tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
  434.         tmpl.direct.red = 0;
  435.  
  436.         mask |= PictFormatRed | PictFormatRedMask;
  437.         mask |= PictFormatGreen | PictFormatGreenMask;
  438.         mask |= PictFormatBlue | PictFormatBlueMask;
  439.         mask |= PictFormatAlpha | PictFormatAlphaMask;
  440.         break;
  441.  
  442.     case PIXMAN_TYPE_BGRA:
  443.         tmpl.type = PictTypeDirect;
  444.  
  445.         tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
  446.         tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format));
  447.  
  448.         tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
  449.         tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
  450.                              PIXMAN_FORMAT_G(format));
  451.  
  452.         tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
  453.         tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
  454.                            PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format));
  455.  
  456.         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
  457.         tmpl.direct.alpha = 0;
  458.  
  459.         mask |= PictFormatRed | PictFormatRedMask;
  460.         mask |= PictFormatGreen | PictFormatGreenMask;
  461.         mask |= PictFormatBlue | PictFormatBlueMask;
  462.         mask |= PictFormatAlpha | PictFormatAlphaMask;
  463.         break;
  464.  
  465.     case PIXMAN_TYPE_A:
  466.         tmpl.type = PictTypeDirect;
  467.  
  468.         tmpl.direct.alpha = 0;
  469.         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
  470.  
  471.         mask |= PictFormatAlpha | PictFormatAlphaMask;
  472.         break;
  473.  
  474.     case PIXMAN_TYPE_COLOR:
  475.     case PIXMAN_TYPE_GRAY:
  476.         /* XXX Find matching visual/colormap */
  477.         tmpl.type = PictTypeIndexed;
  478.         //tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid;
  479.         //mask |= PictFormatColormap;
  480.         return NULL;
  481.     }
  482. #undef MASK
  483.  
  484.     /* XXX caching? */
  485.     return XRenderFindFormat(dpy, mask, &tmpl, 0);
  486. }
  487.  
  488. XRenderPictFormat *
  489. _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t    *display,
  490.                                         cairo_format_t           format)
  491. {
  492.     XRenderPictFormat *xrender_format;
  493.  
  494. #if ! ATOMIC_OP_NEEDS_MEMORY_BARRIER
  495.     xrender_format = display->cached_xrender_formats[format];
  496.     if (likely (xrender_format != NULL))
  497.         return xrender_format;
  498. #endif
  499.  
  500.     xrender_format = display->cached_xrender_formats[format];
  501.     if (xrender_format == NULL) {
  502.         int pict_format = PictStandardNUM;
  503.  
  504.         switch (format) {
  505.         case CAIRO_FORMAT_A1:
  506.             pict_format = PictStandardA1; break;
  507.         case CAIRO_FORMAT_A8:
  508.             pict_format = PictStandardA8; break;
  509.         case CAIRO_FORMAT_RGB24:
  510.             pict_format = PictStandardRGB24; break;
  511.         case CAIRO_FORMAT_RGB16_565:
  512.             xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
  513.                                                                                PIXMAN_r5g6b5);
  514.             break;
  515.         case CAIRO_FORMAT_RGB30:
  516.             xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
  517.                                                                                PIXMAN_x2r10g10b10);
  518.             break;
  519.         case CAIRO_FORMAT_INVALID:
  520.         default:
  521.             ASSERT_NOT_REACHED;
  522.         case CAIRO_FORMAT_ARGB32:
  523.             pict_format = PictStandardARGB32; break;
  524.         }
  525.         if (pict_format != PictStandardNUM)
  526.             xrender_format =
  527.                 XRenderFindStandardFormat (display->display, pict_format);
  528.         display->cached_xrender_formats[format] = xrender_format;
  529.     }
  530.  
  531.     return xrender_format;
  532. }
  533.  
  534. cairo_xlib_screen_t *
  535. _cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
  536.                                 Screen *screen)
  537. {
  538.     cairo_xlib_screen_t *info;
  539.  
  540.     cairo_list_foreach_entry (info, cairo_xlib_screen_t, &display->screens, link) {
  541.         if (info->screen == screen) {
  542.             if (display->screens.next != &info->link)
  543.                 cairo_list_move (&info->link, &display->screens);
  544.             return info;
  545.         }
  546.     }
  547.  
  548.     return NULL;
  549. }
  550.  
  551. cairo_bool_t
  552. _cairo_xlib_display_has_repeat (cairo_device_t *device)
  553. {
  554.     return ! ((cairo_xlib_display_t *) device)->buggy_repeat;
  555. }
  556.  
  557. cairo_bool_t
  558. _cairo_xlib_display_has_reflect (cairo_device_t *device)
  559. {
  560.     return ! ((cairo_xlib_display_t *) device)->buggy_pad_reflect;
  561. }
  562.  
  563. cairo_bool_t
  564. _cairo_xlib_display_has_gradients (cairo_device_t *device)
  565. {
  566.     return ! ((cairo_xlib_display_t *) device)->buggy_gradients;
  567. }
  568.  
  569. /**
  570.  * cairo_xlib_device_debug_cap_xrender_version:
  571.  * @device: a #cairo_device_t for the Xlib backend
  572.  * @major_version: major version to restrict to
  573.  * @minor_version: minor version to restrict to
  574.  *
  575.  * Restricts all future Xlib surfaces for this devices to the specified version
  576.  * of the RENDER extension. This function exists solely for debugging purpose.
  577.  * It let's you find out how cairo would behave with an older version of
  578.  * the RENDER extension.
  579.  *
  580.  * Use the special values -1 and -1 for disabling the RENDER extension.
  581.  *
  582.  * Since: 1.12
  583.  **/
  584. void
  585. cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device,
  586.                                              int major_version,
  587.                                              int minor_version)
  588. {
  589.     cairo_xlib_display_t *display = (cairo_xlib_display_t *) device;
  590.  
  591.     if (device == NULL || device->status)
  592.         return;
  593.  
  594.     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB)
  595.         return;
  596.  
  597.     if (major_version < display->render_major ||
  598.         (major_version == display->render_major &&
  599.          minor_version < display->render_minor))
  600.     {
  601.         display->render_major = major_version;
  602.         display->render_minor = minor_version;
  603.     }
  604.  
  605.     _cairo_xlib_display_select_compositor (display);
  606. }
  607.  
  608. /**
  609.  * cairo_xlib_device_debug_set_precision:
  610.  * @device: a #cairo_device_t for the Xlib backend
  611.  * @precision: the precision to use
  612.  *
  613.  * Render supports two modes of precision when rendering trapezoids. Set
  614.  * the precision to the desired mode.
  615.  *
  616.  * Since: 1.12
  617.  **/
  618. void
  619. cairo_xlib_device_debug_set_precision (cairo_device_t *device,
  620.                                        int precision)
  621. {
  622.     if (device == NULL || device->status)
  623.         return;
  624.     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
  625.         cairo_status_t status;
  626.  
  627.         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
  628.         (void) status;
  629.         return;
  630.     }
  631.  
  632.     ((cairo_xlib_display_t *) device)->force_precision = precision;
  633. }
  634.  
  635. /**
  636.  * cairo_xlib_device_debug_get_precision:
  637.  * @device: a #cairo_device_t for the Xlib backend
  638.  *
  639.  * Get the Xrender precision mode.
  640.  *
  641.  * Returns: the render precision mode
  642.  *
  643.  * Since: 1.12
  644.  **/
  645. int
  646. cairo_xlib_device_debug_get_precision (cairo_device_t *device)
  647. {
  648.     if (device == NULL || device->status)
  649.         return -1;
  650.     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
  651.         cairo_status_t status;
  652.  
  653.         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
  654.         (void) status;
  655.         return -1;
  656.     }
  657.  
  658.     return ((cairo_xlib_display_t *) device)->force_precision;
  659. }
  660.  
  661. #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */
  662.