LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-xlib-surface.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1965 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 96 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             :  *
       7             :  * This library is free software; you can redistribute it and/or
       8             :  * modify it either under the terms of the GNU Lesser General Public
       9             :  * License version 2.1 as published by the Free Software Foundation
      10             :  * (the "LGPL") or, at your option, under the terms of the Mozilla
      11             :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      12             :  * notice, a recipient may use your version of this file under either
      13             :  * the MPL or the LGPL.
      14             :  *
      15             :  * You should have received a copy of the LGPL along with this library
      16             :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      18             :  * You should have received a copy of the MPL along with this library
      19             :  * in the file COPYING-MPL-1.1
      20             :  *
      21             :  * The contents of this file are subject to the Mozilla Public License
      22             :  * Version 1.1 (the "License"); you may not use this file except in
      23             :  * compliance with the License. You may obtain a copy of the License at
      24             :  * http://www.mozilla.org/MPL/
      25             :  *
      26             :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      27             :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      28             :  * the specific language governing rights and limitations.
      29             :  *
      30             :  * The Original Code is the cairo graphics library.
      31             :  *
      32             :  * The Initial Developer of the Original Code is University of Southern
      33             :  * California.
      34             :  *
      35             :  * Contributor(s):
      36             :  *      Carl D. Worth <cworth@cworth.org>
      37             :  *      Behdad Esfahbod <behdad@behdad.org>
      38             :  *      Chris Wilson <chris@chris-wilson.co.uk>
      39             :  *      Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
      40             :  */
      41             : 
      42             : /* Heed well the words of Owen Taylor:
      43             :  * "Any patch that works around a render bug, or claims to, without a
      44             :  * specific reference to the bug filed in bugzilla.freedesktop.org will
      45             :  * never pass approval."
      46             :  */
      47             : 
      48             : #include "cairoint.h"
      49             : 
      50             : #include "cairo-xlib-private.h"
      51             : #include "cairo-xlib-surface-private.h"
      52             : #include "cairo-clip-private.h"
      53             : #include "cairo-error-private.h"
      54             : #include "cairo-scaled-font-private.h"
      55             : #include "cairo-surface-snapshot-private.h"
      56             : #include "cairo-surface-subsurface-private.h"
      57             : #include "cairo-region-private.h"
      58             : #include "cairo-xlib-xrender-private.h"
      59             : 
      60             : #include <X11/Xutil.h> /* for XDestroyImage */
      61             : #include <X11/Xlibint.h> /* for access to XDisplay's innards */
      62             : 
      63             : #define XLIB_COORD_MAX 32767
      64             : 
      65             : #define DEBUG 0
      66             : 
      67             : #if DEBUG
      68             : #define UNSUPPORTED(reason) \
      69             :     fprintf (stderr, \
      70             :              "cairo-xlib: hit unsupported operation %s(), line %d: %s\n", \
      71             :              __FUNCTION__, __LINE__, reason), \
      72             :     CAIRO_INT_STATUS_UNSUPPORTED
      73             : #else
      74             : #define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
      75             : #endif
      76             : 
      77             : #if DEBUG
      78             : static void CAIRO_PRINTF_FORMAT (2, 3)
      79             : _x_bread_crumb (Display *dpy,
      80             :                 const char *fmt,
      81             :                 ...)
      82             : {
      83             :     xReq *req;
      84             :     char buf[2048];
      85             :     unsigned int len, len_dwords;
      86             :     va_list ap;
      87             : 
      88             :     va_start (ap, fmt);
      89             :     len = vsnprintf (buf, sizeof (buf), fmt, ap);
      90             :     va_end (ap);
      91             : 
      92             :     buf[len++] = '\0';
      93             :     while (len & 3)
      94             :         buf[len++] = '\0';
      95             : 
      96             :     LockDisplay (dpy);
      97             :     GetEmptyReq (NoOperation, req);
      98             : 
      99             :     len_dwords = len >> 2;
     100             :     SetReqLen (req, len_dwords, len_dwords);
     101             :     Data (dpy, buf, len);
     102             : 
     103             :     UnlockDisplay (dpy);
     104             :     SyncHandle ();
     105             : }
     106             : #define X_DEBUG(x) _x_bread_crumb x
     107             : #else
     108             : #define X_DEBUG(x)
     109             : #endif
     110             : 
     111             : /**
     112             :  * SECTION:cairo-xlib
     113             :  * @Title: XLib Surfaces
     114             :  * @Short_Description: X Window System rendering using XLib
     115             :  * @See_Also: #cairo_surface_t
     116             :  *
     117             :  * The XLib surface is used to render cairo graphics to X Window System
     118             :  * windows and pixmaps using the XLib library.
     119             :  *
     120             :  * Note that the XLib surface automatically takes advantage of X render extension
     121             :  * if it is available.
     122             :  */
     123             : 
     124             : /**
     125             :  * CAIRO_HAS_XLIB_SURFACE:
     126             :  *
     127             :  * Defined if the Xlib surface backend is available.
     128             :  * This macro can be used to conditionally compile backend-specific code.
     129             :  */
     130             : 
     131             : /**
     132             :  * SECTION:cairo-xlib-xrender
     133             :  * @Title: XLib/XRender Backend
     134             :  * @Short_Description: X Window System rendering using XLib and the X Render extension
     135             :  * @See_Also: #cairo_surface_t
     136             :  *
     137             :  * The XLib surface is used to render cairo graphics to X Window System
     138             :  * windows and pixmaps using the XLib and Xrender libraries.
     139             :  *
     140             :  * Note that the XLib surface automatically takes advantage of X Render extension
     141             :  * if it is available.
     142             :  */
     143             : 
     144             : /**
     145             :  * CAIRO_HAS_XLIB_XRENDER_SURFACE:
     146             :  *
     147             :  * Defined if the XLib/XRender surface functions are available.
     148             :  * This macro can be used to conditionally compile backend-specific code.
     149             :  */
     150             : 
     151             : /* Xlib doesn't define a typedef, so define one ourselves */
     152             : typedef int (*cairo_xlib_error_func_t) (Display     *display,
     153             :                                         XErrorEvent *event);
     154             : 
     155             : static cairo_surface_t *
     156             : _cairo_xlib_surface_create_internal (cairo_xlib_screen_t        *screen,
     157             :                                      Drawable                   drawable,
     158             :                                      Visual                    *visual,
     159             :                                      XRenderPictFormat         *xrender_format,
     160             :                                      int                        width,
     161             :                                      int                        height,
     162             :                                      int                        depth);
     163             : 
     164             : static cairo_bool_t
     165             : _cairo_surface_is_xlib (cairo_surface_t *surface);
     166             : 
     167             : static cairo_bool_t
     168             : _native_byte_order_lsb (void);
     169             : 
     170             : static cairo_int_status_t
     171             : _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
     172             :                                  cairo_operator_t     op,
     173             :                                  const cairo_pattern_t  *src_pattern,
     174             :                                  cairo_glyph_t       *glyphs,
     175             :                                  int                  num_glyphs,
     176             :                                  cairo_scaled_font_t *scaled_font,
     177             :                                  cairo_clip_t        *clip,
     178             :                                  int                 *remaining_glyphs);
     179             : 
     180             : /*
     181             :  * Instead of taking two round trips for each blending request,
     182             :  * assume that if a particular drawable fails GetImage that it will
     183             :  * fail for a "while"; use temporary pixmaps to avoid the errors
     184             :  */
     185             : 
     186             : #define CAIRO_ASSUME_PIXMAP     20
     187             : 
     188             : static const XTransform identity = { {
     189             :     { 1 << 16, 0x00000, 0x00000 },
     190             :     { 0x00000, 1 << 16, 0x00000 },
     191             :     { 0x00000, 0x00000, 1 << 16 },
     192             : } };
     193             : 
     194             : #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor)    \
     195             :         (((surface)->render_major > major) ||                     \
     196             :          (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
     197             : 
     198             : #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface)                CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
     199             : #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface)             CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
     200             : #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface)        CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
     201             : 
     202             : #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface)               CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
     203             : 
     204             : #define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface)                      CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
     205             : #define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface)                      CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
     206             : 
     207             : #define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface)            CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
     208             : #define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface)             CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
     209             : #define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface)                      CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
     210             : #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface)                        CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
     211             : 
     212             : #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface)     CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
     213             : #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)       CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
     214             : 
     215             : #define CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT(surface)       CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
     216             : #define CAIRO_SURFACE_RENDER_HAS_GRADIENTS(surface)     CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
     217             : 
     218             : #define CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 11)
     219             : 
     220             : #define CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR(surface, op)     \
     221             :      ((op) <= CAIRO_OPERATOR_SATURATE ||                     \
     222             :       (CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS(surface) &&       \
     223             :        (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY))
     224             : 
     225             : static Visual *
     226           0 : _visual_for_xrender_format(Screen *screen,
     227             :                            XRenderPictFormat *xrender_format)
     228             : {
     229             :     int d, v;
     230             : 
     231             :     /* XXX Consider searching through the list of known cairo_visual_t for
     232             :      * the reverse mapping.
     233             :      */
     234             : 
     235           0 :     for (d = 0; d < screen->ndepths; d++) {
     236           0 :         Depth *d_info = &screen->depths[d];
     237             : 
     238           0 :         if (d_info->depth != xrender_format->depth)
     239           0 :             continue;
     240             : 
     241           0 :         for (v = 0; v < d_info->nvisuals; v++) {
     242           0 :             Visual *visual = &d_info->visuals[v];
     243             : 
     244           0 :             switch (visual->class) {
     245             :             case TrueColor:
     246           0 :                 if (xrender_format->type != PictTypeDirect)
     247           0 :                     continue;
     248           0 :                 break;
     249             : 
     250             :             case DirectColor:
     251             :                 /* Prefer TrueColor to DirectColor.
     252             :                  * (XRenderFindVisualFormat considers both TrueColor and DirectColor
     253             :                  * Visuals to match the same PictFormat.)
     254             :                  */
     255           0 :                 continue;
     256             : 
     257             :             case StaticGray:
     258             :             case GrayScale:
     259             :             case StaticColor:
     260             :             case PseudoColor:
     261           0 :                 if (xrender_format->type != PictTypeIndexed)
     262           0 :                     continue;
     263           0 :                 break;
     264             :             }
     265             : 
     266           0 :             if (xrender_format ==
     267           0 :                 XRenderFindVisualFormat (DisplayOfScreen(screen), visual))
     268           0 :                 return visual;
     269             :         }
     270             :     }
     271             : 
     272           0 :     return NULL;
     273             : }
     274             : 
     275             : static cairo_status_t
     276           0 : _cairo_xlib_surface_set_clip_region (cairo_xlib_surface_t *surface,
     277             :                                      cairo_region_t *region)
     278             : {
     279           0 :     cairo_bool_t had_clip_rects = surface->clip_region != NULL;
     280             : 
     281           0 :     if (had_clip_rects == FALSE && region == NULL)
     282           0 :         return CAIRO_STATUS_SUCCESS;
     283             : 
     284           0 :     if (surface->clip_region == region)
     285           0 :         return CAIRO_STATUS_SUCCESS;
     286             : 
     287           0 :     if (cairo_region_equal (surface->clip_region, region))
     288           0 :         return CAIRO_STATUS_SUCCESS;
     289             : 
     290           0 :     cairo_region_destroy (surface->clip_region);
     291           0 :     surface->clip_region = cairo_region_reference (region);
     292             : 
     293           0 :     if (surface->clip_rects != surface->embedded_clip_rects) {
     294           0 :         free (surface->clip_rects);
     295           0 :         surface->clip_rects = surface->embedded_clip_rects;
     296             :     }
     297           0 :     surface->num_clip_rects = 0;
     298             : 
     299           0 :     if (region != NULL) {
     300           0 :         XRectangle *rects = NULL;
     301             :         int n_rects, i;
     302             : 
     303           0 :         n_rects = cairo_region_num_rectangles (region);
     304           0 :         if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) {
     305           0 :             rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
     306           0 :             if (unlikely (rects == NULL))
     307           0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     308             :         } else {
     309           0 :             rects = surface->embedded_clip_rects;
     310             :         }
     311             : 
     312           0 :         for (i = 0; i < n_rects; i++) {
     313             :             cairo_rectangle_int_t rect;
     314             : 
     315           0 :             cairo_region_get_rectangle (region, i, &rect);
     316             : 
     317           0 :             rects[i].x = rect.x;
     318           0 :             rects[i].y = rect.y;
     319           0 :             rects[i].width = rect.width;
     320           0 :             rects[i].height = rect.height;
     321             :         }
     322             : 
     323           0 :         surface->clip_rects = rects;
     324           0 :         surface->num_clip_rects = n_rects;
     325             :     }
     326             : 
     327           0 :     surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL;
     328           0 :     return CAIRO_STATUS_SUCCESS;
     329             : }
     330             : 
     331             : static cairo_content_t
     332           0 : _xrender_format_to_content (XRenderPictFormat *xrender_format)
     333             : {
     334             :     cairo_bool_t xrender_format_has_alpha;
     335             :     cairo_bool_t xrender_format_has_color;
     336             : 
     337             :     /* This only happens when using a non-Render server. Let's punt
     338             :      * and say there's no alpha here. */
     339           0 :     if (xrender_format == NULL)
     340           0 :         return CAIRO_CONTENT_COLOR;
     341             : 
     342           0 :     xrender_format_has_alpha = (xrender_format->direct.alphaMask != 0);
     343           0 :     xrender_format_has_color = (xrender_format->direct.redMask   != 0 ||
     344           0 :                                 xrender_format->direct.greenMask != 0 ||
     345           0 :                                 xrender_format->direct.blueMask  != 0);
     346             : 
     347           0 :     if (xrender_format_has_alpha)
     348           0 :         if (xrender_format_has_color)
     349           0 :             return CAIRO_CONTENT_COLOR_ALPHA;
     350             :         else
     351           0 :             return CAIRO_CONTENT_ALPHA;
     352             :     else
     353           0 :         return CAIRO_CONTENT_COLOR;
     354             : }
     355             : 
     356             : static cairo_surface_t *
     357           0 : _cairo_xlib_surface_create_similar (void               *abstract_src,
     358             :                                     cairo_content_t     content,
     359             :                                     int                 width,
     360             :                                     int                 height)
     361             : {
     362           0 :     cairo_xlib_surface_t *src = abstract_src;
     363             :     XRenderPictFormat *xrender_format;
     364             :     cairo_xlib_surface_t *surface;
     365             :     cairo_xlib_display_t *display;
     366             :     Pixmap pix;
     367             : 
     368           0 :     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
     369           0 :         return NULL;
     370             : 
     371           0 :     if (! CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (src))
     372           0 :         return NULL;
     373             : 
     374           0 :     if (_cairo_xlib_display_acquire (src->base.device, &display))
     375           0 :         return NULL;
     376             : 
     377             :     /* If we never found an XRenderFormat or if it isn't compatible
     378             :      * with the content being requested, then we fallback to just
     379             :      * constructing a cairo_format_t instead, (which will fairly
     380             :      * arbitrarily pick a visual/depth for the similar surface.
     381             :      */
     382           0 :     xrender_format = src->xrender_format;
     383           0 :     if ((xrender_format != NULL &&
     384           0 :         _xrender_format_to_content (xrender_format) == content) ||
     385             :         (xrender_format =
     386           0 :          _cairo_xlib_display_get_xrender_format (display,
     387             :                                                  _cairo_format_from_content (content))))
     388           0 :     {
     389             :         Visual *visual;
     390             : 
     391             :         /* We've got a compatible XRenderFormat now, which means the
     392             :          * similar surface will match the existing surface as closely in
     393             :          * visual/depth etc. as possible. */
     394           0 :         pix = XCreatePixmap (display->display, src->drawable,
     395           0 :                              width <= 0 ? 1 : width, height <= 0 ? 1 : height,
     396           0 :                              xrender_format->depth);
     397             : 
     398           0 :         if (xrender_format == src->xrender_format)
     399           0 :             visual = src->visual;
     400             :         else
     401           0 :             visual = _visual_for_xrender_format(src->screen->screen,
     402             :                                                 xrender_format);
     403             : 
     404           0 :         surface = (cairo_xlib_surface_t *)
     405           0 :                   _cairo_xlib_surface_create_internal (src->screen, pix,
     406             :                                                        visual,
     407             :                                                        xrender_format,
     408             :                                                        width, height,
     409             :                                                        xrender_format->depth);
     410             :     }
     411             :     else
     412             :     {
     413             : #ifdef DEBUG_FORCE_FALLBACKS
     414             :         Screen *screen = src->screen->screen;
     415             :         int depth;
     416             : 
     417             :         /* No compatabile XRenderFormat, see if we can make an ordinary pixmap,
     418             :          * so that we can still accelerate blits with XCopyArea(). */
     419             :         if (content != CAIRO_CONTENT_COLOR) {
     420             :             cairo_device_release (&display->base);
     421             :             return NULL;
     422             :         }
     423             : 
     424             :         depth = DefaultDepthOfScreen (screen);
     425             : 
     426             :         pix = XCreatePixmap (display->display, RootWindowOfScreen (screen),
     427             :                              width <= 0 ? 1 : width, height <= 0 ? 1 : height,
     428             :                              depth);
     429             : 
     430             :         surface = (cairo_xlib_surface_t *)
     431             :                   _cairo_xlib_surface_create_internal (src->screen, pix,
     432             :                                                        DefaultVisualOfScreen (screen),
     433             :                                                        NULL,
     434             :                                                        width, height, depth);
     435             : #else
     436             :         /* No compatabile XRenderFormat, just say no. */
     437           0 :         cairo_device_release (&display->base);
     438           0 :         return NULL;
     439             : #endif
     440             :     }
     441             : 
     442           0 :     if (unlikely (surface->base.status)) {
     443           0 :         XFreePixmap (display->display, pix);
     444           0 :         cairo_device_release (&display->base);
     445           0 :         return &surface->base;
     446             :     }
     447             : 
     448           0 :     surface->owns_pixmap = TRUE;
     449             : 
     450           0 :     cairo_device_release (&display->base);
     451             : 
     452           0 :     return &surface->base;
     453             : }
     454             : 
     455             : static cairo_status_t
     456           0 : _cairo_xlib_surface_finish (void *abstract_surface)
     457             : {
     458           0 :     cairo_xlib_surface_t *surface = abstract_surface;
     459             :     cairo_status_t        status;
     460             :     cairo_xlib_display_t *display;
     461             : 
     462             :     X_DEBUG ((display->display, "finish (drawable=%x)", (unsigned int) surface->drawable));
     463             : 
     464           0 :     status = _cairo_xlib_display_acquire (surface->base.device, &display);
     465           0 :     if (unlikely (status))
     466           0 :         return status;
     467             : 
     468           0 :     if (surface->owns_pixmap) {
     469             :         cairo_status_t status2;
     470             : 
     471           0 :         if (surface->dst_picture != None) {
     472           0 :             status2 = _cairo_xlib_display_queue_resource (display,
     473             :                                                           XRenderFreePicture,
     474             :                                                           surface->dst_picture);
     475           0 :             if (status == CAIRO_STATUS_SUCCESS)
     476           0 :                 status = status2;
     477             :         }
     478             : 
     479           0 :         if (surface->src_picture != None) {
     480           0 :             status2 = _cairo_xlib_display_queue_resource (display,
     481             :                                                           XRenderFreePicture,
     482             :                                                           surface->src_picture);
     483           0 :             if (status == CAIRO_STATUS_SUCCESS)
     484           0 :                 status = status2;
     485             :         }
     486             : 
     487           0 :         status2 = _cairo_xlib_display_queue_resource (display,
     488             :                                            (cairo_xlib_notify_resource_func) XFreePixmap,
     489             :                                            surface->drawable);
     490           0 :         if (status == CAIRO_STATUS_SUCCESS)
     491           0 :             status = status2;
     492             :     } else {
     493           0 :         if (surface->dst_picture != None)
     494           0 :             XRenderFreePicture (display->display, surface->dst_picture);
     495             : 
     496           0 :         if (surface->src_picture != None)
     497           0 :             XRenderFreePicture (display->display, surface->src_picture);
     498             :     }
     499             : 
     500           0 :     if (surface->clip_rects != surface->embedded_clip_rects)
     501           0 :         free (surface->clip_rects);
     502             : 
     503           0 :     if (display->display != NULL)
     504           0 :         _cairo_xlib_remove_close_display_hook (display,
     505             :                                                &surface->close_display_hook);
     506             : 
     507           0 :     cairo_device_release (&display->base);
     508             : 
     509           0 :     cairo_region_destroy (surface->clip_region);
     510             : 
     511           0 :     return status;
     512             : }
     513             : 
     514             : static cairo_status_t
     515           0 : _cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
     516             :                             cairo_xlib_surface_t *surface,
     517             :                             GC                   *gc)
     518             : {
     519           0 :     *gc = _cairo_xlib_screen_get_gc (display,
     520             :                                      surface->screen,
     521             :                                      surface->depth,
     522             :                                      surface->drawable);
     523           0 :     if (unlikely (*gc == NULL))
     524           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     525             : 
     526           0 :     return CAIRO_STATUS_SUCCESS;
     527             : }
     528             : 
     529             : static void
     530           0 : _cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
     531             :                             cairo_xlib_surface_t *surface,
     532             :                             GC                    gc)
     533             : {
     534           0 :     _cairo_xlib_screen_put_gc (display,
     535             :                                surface->screen,
     536             :                                surface->depth,
     537             :                                gc);
     538           0 : }
     539             : 
     540             : static int
     541           0 : _noop_error_handler (Display     *display,
     542             :                      XErrorEvent *event)
     543             : {
     544           0 :     return False;               /* return value is ignored */
     545             : }
     546             : 
     547             : static void
     548           0 : _swap_ximage_2bytes (XImage *ximage)
     549             : {
     550             :     int i, j;
     551           0 :     char *line = ximage->data;
     552             : 
     553           0 :     for (j = ximage->height; j; j--) {
     554           0 :         uint16_t *p = (uint16_t *) line;
     555           0 :         for (i = ximage->width; i; i--) {
     556           0 :             *p = bswap_16 (*p);
     557           0 :             p++;
     558             :         }
     559             : 
     560           0 :         line += ximage->bytes_per_line;
     561             :     }
     562           0 : }
     563             : 
     564             : static void
     565           0 : _swap_ximage_3bytes (XImage *ximage)
     566             : {
     567             :     int i, j;
     568           0 :     char *line = ximage->data;
     569             : 
     570           0 :     for (j = ximage->height; j; j--) {
     571           0 :         uint8_t *p = (uint8_t *) line;
     572           0 :         for (i = ximage->width; i; i--) {
     573             :             uint8_t tmp;
     574           0 :             tmp = p[2];
     575           0 :             p[2] = p[0];
     576           0 :             p[0] = tmp;
     577           0 :             p += 3;
     578             :         }
     579             : 
     580           0 :         line += ximage->bytes_per_line;
     581             :     }
     582           0 : }
     583             : 
     584             : static void
     585           0 : _swap_ximage_4bytes (XImage *ximage)
     586             : {
     587             :     int i, j;
     588           0 :     char *line = ximage->data;
     589             : 
     590           0 :     for (j = ximage->height; j; j--) {
     591           0 :         uint32_t *p = (uint32_t *) line;
     592           0 :         for (i = ximage->width; i; i--) {
     593           0 :             *p = bswap_32 (*p);
     594           0 :             p++;
     595             :         }
     596             : 
     597           0 :         line += ximage->bytes_per_line;
     598             :     }
     599           0 : }
     600             : 
     601             : static void
     602           0 : _swap_ximage_nibbles (XImage *ximage)
     603             : {
     604             :     int i, j;
     605           0 :     char *line = ximage->data;
     606             : 
     607           0 :     for (j = ximage->height; j; j--) {
     608           0 :         uint8_t *p = (uint8_t *) line;
     609           0 :         for (i = (ximage->width + 1) / 2; i; i--) {
     610           0 :             *p = ((*p >> 4) & 0xf) | ((*p << 4) & ~0xf);
     611           0 :             p++;
     612             :         }
     613             : 
     614           0 :         line += ximage->bytes_per_line;
     615             :     }
     616           0 : }
     617             : 
     618             : static void
     619           0 : _swap_ximage_bits (XImage *ximage)
     620             : {
     621             :     int i, j;
     622           0 :     char *line = ximage->data;
     623           0 :     int unit = ximage->bitmap_unit;
     624           0 :     int line_bytes = ((ximage->width + unit - 1) & ~(unit - 1)) / 8;
     625             : 
     626           0 :     for (j = ximage->height; j; j--) {
     627           0 :         char *p = line;
     628             : 
     629           0 :         for (i = line_bytes; i; i--) {
     630           0 :             char b = *p;
     631           0 :             b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
     632           0 :             b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
     633           0 :             b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
     634           0 :             *p = b;
     635             : 
     636           0 :             p++;
     637             :         }
     638             : 
     639           0 :         line += ximage->bytes_per_line;
     640             :     }
     641           0 : }
     642             : 
     643             : static void
     644           0 : _swap_ximage_to_native (XImage *ximage)
     645             : {
     646           0 :     int unit_bytes = 0;
     647           0 :     int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
     648             : 
     649           0 :     if (ximage->bits_per_pixel == 1 &&
     650           0 :         ximage->bitmap_bit_order != native_byte_order)
     651             :     {
     652           0 :         _swap_ximage_bits (ximage);
     653           0 :         if (ximage->bitmap_bit_order == ximage->byte_order)
     654           0 :             return;
     655             :     }
     656             : 
     657           0 :     if (ximage->byte_order == native_byte_order)
     658           0 :         return;
     659             : 
     660           0 :     switch (ximage->bits_per_pixel) {
     661             :     case 1:
     662           0 :         unit_bytes = ximage->bitmap_unit / 8;
     663           0 :         break;
     664             :     case 4:
     665           0 :         _swap_ximage_nibbles (ximage);
     666             :         /* fall-through */
     667             :     case 8:
     668             :     case 16:
     669             :     case 20:
     670             :     case 24:
     671             :     case 28:
     672             :     case 30:
     673             :     case 32:
     674           0 :         unit_bytes = (ximage->bits_per_pixel + 7) / 8;
     675           0 :         break;
     676             :     default:
     677             :         /* This could be hit on some rare but possible cases. */
     678           0 :         ASSERT_NOT_REACHED;
     679             :     }
     680             : 
     681           0 :     switch (unit_bytes) {
     682             :     case 1:
     683           0 :         break;
     684             :     case 2:
     685           0 :         _swap_ximage_2bytes (ximage);
     686           0 :         break;
     687             :     case 3:
     688           0 :         _swap_ximage_3bytes (ximage);
     689           0 :         break;
     690             :     case 4:
     691           0 :         _swap_ximage_4bytes (ximage);
     692           0 :         break;
     693             :     default:
     694           0 :         ASSERT_NOT_REACHED;
     695             :     }
     696             : }
     697             : 
     698             : 
     699             : /* Given a mask, (with a single sequence of contiguous 1 bits), return
     700             :  * the number of 1 bits in 'width' and the number of 0 bits to its
     701             :  * right in 'shift'. */
     702             : static void
     703           0 : _characterize_field (uint32_t mask, int *width, int *shift)
     704             : {
     705           0 :     *width = _cairo_popcount (mask);
     706             :     /* The final '& 31' is to force a 0 mask to result in 0 shift. */
     707           0 :     *shift = _cairo_popcount ((mask - 1) & ~mask) & 31;
     708           0 : }
     709             : 
     710             : 
     711             : /* Convert a field of 'width' bits to 'new_width' bits with correct
     712             :  * rounding. */
     713             : static inline uint32_t
     714           0 : _resize_field (uint32_t field, int width, int new_width)
     715             : {
     716           0 :     if (width == 0)
     717           0 :         return 0;
     718             : 
     719           0 :     if (width >= new_width) {
     720           0 :         return field >> (width - new_width);
     721             :     } else {
     722           0 :         uint32_t result = field << (new_width - width);
     723             : 
     724           0 :         while (width < new_width) {
     725           0 :             result |= result >> width;
     726           0 :             width <<= 1;
     727             :         }
     728           0 :         return result;
     729             :     }
     730             : }
     731             : 
     732             : static inline uint32_t
     733           0 : _adjust_field (uint32_t field, int adjustment)
     734             : {
     735           0 :     return MIN (255, MAX(0, (int)field + adjustment));
     736             : }
     737             : 
     738             : /* Given a shifted field value, (described by 'width' and 'shift),
     739             :  * resize it 8-bits and return that value.
     740             :  *
     741             :  * Note that the original field value must not have any non-field bits
     742             :  * set.
     743             :  */
     744             : static inline uint32_t
     745           0 : _field_to_8 (uint32_t field, int width, int shift)
     746             : {
     747           0 :     return _resize_field (field >> shift, width, 8);
     748             : }
     749             : 
     750             : static inline uint32_t
     751           0 : _field_to_8_undither (uint32_t field, int width, int shift,
     752             :                       int dither_adjustment)
     753             : {
     754           0 :     return _adjust_field (_field_to_8 (field, width, shift), - dither_adjustment>>width);
     755             : }
     756             : 
     757             : /* Given an 8-bit value, convert it to a field of 'width', shift it up
     758             :  *  to 'shift, and return it. */
     759             : static inline uint32_t
     760           0 : _field_from_8 (uint32_t field, int width, int shift)
     761             : {
     762           0 :     return _resize_field (field, 8, width) << shift;
     763             : }
     764             : 
     765             : static inline uint32_t
     766           0 : _field_from_8_dither (uint32_t field, int width, int shift,
     767             :                       int8_t dither_adjustment)
     768             : {
     769           0 :     return _field_from_8 (_adjust_field (field, dither_adjustment>>width), width, shift);
     770             : }
     771             : 
     772             : static inline uint32_t
     773           0 : _pseudocolor_from_rgb888_dither (cairo_xlib_visual_info_t *visual_info,
     774             :                                  uint32_t r, uint32_t g, uint32_t b,
     775             :                                  int8_t dither_adjustment)
     776             : {
     777           0 :     if (r == g && g == b) {
     778           0 :         dither_adjustment /= RAMP_SIZE;
     779           0 :         return visual_info->gray8_to_pseudocolor[_adjust_field (r, dither_adjustment)];
     780             :     } else {
     781           0 :         dither_adjustment = visual_info->dither8_to_cube[dither_adjustment+128];
     782           0 :         return visual_info->cube_to_pseudocolor[visual_info->field8_to_cube[_adjust_field (r, dither_adjustment)]]
     783           0 :                                                [visual_info->field8_to_cube[_adjust_field (g, dither_adjustment)]]
     784           0 :                                                [visual_info->field8_to_cube[_adjust_field (b, dither_adjustment)]];
     785             :     }
     786             : }
     787             : 
     788             : static inline uint32_t
     789           0 : _pseudocolor_to_rgb888 (cairo_xlib_visual_info_t *visual_info,
     790             :                         uint32_t pixel)
     791             : {
     792             :     uint32_t r, g, b;
     793           0 :     pixel &= 0xff;
     794           0 :     r = visual_info->colors[pixel].r;
     795           0 :     g = visual_info->colors[pixel].g;
     796           0 :     b = visual_info->colors[pixel].b;
     797           0 :     return (r << 16) |
     798           0 :            (g <<  8) |
     799             :            (b      );
     800             : }
     801             : 
     802             : 
     803             : /* should range from -128 to 127 */
     804             : #define X 16
     805             : static const int8_t dither_pattern[4][4] = {
     806             :     {-8*X, +0*X, -6*X, +2*X},
     807             :     {+4*X, -4*X, +6*X, -2*X},
     808             :     {-5*X, +4*X, -7*X, +1*X},
     809             :     {+7*X, -1*X, +5*X, -3*X}
     810             : };
     811             : #undef X
     812             : 
     813             : 
     814             : static cairo_status_t
     815           0 : _get_image_surface (cairo_xlib_surface_t    *surface,
     816             :                     cairo_rectangle_int_t   *interest_rect,
     817             :                     cairo_image_surface_t  **image_out,
     818             :                     cairo_rectangle_int_t   *image_rect)
     819             : {
     820             :     cairo_int_status_t status;
     821           0 :     cairo_image_surface_t *image = NULL;
     822             :     XImage *ximage;
     823             :     cairo_rectangle_int_t extents;
     824             :     pixman_format_code_t pixman_format;
     825             :     cairo_format_masks_t xlib_masks;
     826             :     cairo_xlib_display_t *display;
     827             : 
     828           0 :     extents.x = 0;
     829           0 :     extents.y = 0;
     830           0 :     extents.width  = surface->width;
     831           0 :     extents.height = surface->height;
     832             : 
     833           0 :     if (interest_rect) {
     834           0 :         if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
     835           0 :             *image_out = NULL;
     836           0 :             return CAIRO_STATUS_SUCCESS;
     837             :         }
     838             :     }
     839             : 
     840           0 :     status = _cairo_xlib_display_acquire (surface->base.device, &display);
     841           0 :     if (status)
     842           0 :         return status;
     843             : 
     844           0 :     if (image_rect)
     845           0 :         *image_rect = extents;
     846             : 
     847             :     /* XXX: This should try to use the XShm extension if available */
     848             : 
     849           0 :     if (surface->use_pixmap == 0)
     850             :     {
     851             :         cairo_xlib_error_func_t old_handler;
     852             : 
     853           0 :         old_handler = XSetErrorHandler (_noop_error_handler);
     854             : 
     855           0 :         ximage = XGetImage (display->display,
     856             :                             surface->drawable,
     857             :                             extents.x, extents.y,
     858           0 :                             extents.width, extents.height,
     859             :                             AllPlanes, ZPixmap);
     860             : 
     861           0 :         XSetErrorHandler (old_handler);
     862             : 
     863             :         /* If we get an error, the surface must have been a window,
     864             :          * so retry with the safe code path.
     865             :          */
     866           0 :         if (!ximage)
     867           0 :             surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
     868             :     }
     869             :     else
     870             :     {
     871           0 :         surface->use_pixmap--;
     872           0 :         ximage = NULL;
     873             :     }
     874             : 
     875           0 :     if (ximage == NULL) {
     876             :         /* XGetImage from a window is dangerous because it can
     877             :          * produce errors if the window is unmapped or partially
     878             :          * outside the screen. We could check for errors and
     879             :          * retry, but to keep things simple, we just create a
     880             :          * temporary pixmap
     881             :          */
     882             :         Pixmap pixmap;
     883             :         GC gc;
     884             : 
     885           0 :         status = _cairo_xlib_surface_get_gc (display, surface, &gc);
     886           0 :         if (unlikely (status))
     887           0 :             goto BAIL;
     888             : 
     889           0 :         pixmap = XCreatePixmap (display->display,
     890             :                                 surface->drawable,
     891           0 :                                 extents.width <= 0 ? 1 : extents.width,
     892           0 :                                 extents.height <= 0 ? 1 : extents.height,
     893           0 :                                 surface->depth);
     894           0 :         if (pixmap) {
     895           0 :             XCopyArea (display->display, surface->drawable, pixmap, gc,
     896             :                        extents.x, extents.y,
     897           0 :                        extents.width, extents.height,
     898             :                        0, 0);
     899             : 
     900           0 :             ximage = XGetImage (display->display,
     901             :                                 pixmap,
     902             :                                 0, 0,
     903           0 :                                 extents.width <= 0 ? 1 : extents.width,
     904           0 :                                 extents.height <= 0 ? 1 : extents.height,
     905             :                                 AllPlanes, ZPixmap);
     906             : 
     907           0 :             XFreePixmap (display->display, pixmap);
     908             :         }
     909             : 
     910           0 :         _cairo_xlib_surface_put_gc (display, surface, gc);
     911             : 
     912           0 :         if (ximage == NULL) {
     913           0 :             status =  _cairo_error (CAIRO_STATUS_NO_MEMORY);
     914           0 :             goto BAIL;
     915             :         }
     916             :     }
     917             : 
     918           0 :     _swap_ximage_to_native (ximage);
     919             : 
     920           0 :     xlib_masks.bpp = ximage->bits_per_pixel;
     921           0 :     xlib_masks.alpha_mask = surface->a_mask;
     922           0 :     xlib_masks.red_mask = surface->r_mask;
     923           0 :     xlib_masks.green_mask = surface->g_mask;
     924           0 :     xlib_masks.blue_mask = surface->b_mask;
     925             : 
     926             :     /* We can't use pixman to simply write to image if:
     927             :      *   (a) the pixels are not appropriately aligned,
     928             :      *   (b) pixman does not the pixel format, or
     929             :      *   (c) if the image is palettized and we need to convert.
     930             :      */
     931           0 :     if (ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 &&
     932           0 :         _pixman_format_from_masks (&xlib_masks, &pixman_format) &&
     933           0 :         (surface->visual == NULL || surface->visual->class == TrueColor))
     934             :     {
     935           0 :         image = (cairo_image_surface_t*)
     936           0 :             _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
     937             :                                                             pixman_format,
     938             :                                                             ximage->width,
     939             :                                                             ximage->height,
     940             :                                                             ximage->bytes_per_line);
     941           0 :         status = image->base.status;
     942           0 :         if (unlikely (status))
     943           0 :             goto BAIL;
     944             : 
     945             :         /* Let the surface take ownership of the data */
     946           0 :         _cairo_image_surface_assume_ownership_of_data (image);
     947           0 :         ximage->data = NULL;
     948             :     } else {
     949             :         /* The visual we are dealing with is not supported by the
     950             :          * standard pixman formats. So we must first convert the data
     951             :          * to a supported format. */
     952             : 
     953             :         cairo_format_t format;
     954             :         unsigned char *data;
     955             :         uint32_t *row;
     956             :         uint32_t in_pixel, out_pixel;
     957             :         unsigned int rowstride;
     958           0 :         uint32_t a_mask=0, r_mask=0, g_mask=0, b_mask=0;
     959           0 :         int a_width=0, r_width=0, g_width=0, b_width=0;
     960           0 :         int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
     961             :         int x, y, x0, y0, x_off, y_off;
     962           0 :         cairo_xlib_visual_info_t *visual_info = NULL;
     963             : 
     964           0 :         if (surface->visual == NULL || surface->visual->class == TrueColor) {
     965             :             cairo_bool_t has_alpha;
     966             :             cairo_bool_t has_color;
     967             : 
     968           0 :             has_alpha =  surface->a_mask;
     969           0 :             has_color = (surface->r_mask ||
     970           0 :                          surface->g_mask ||
     971           0 :                          surface->b_mask);
     972             : 
     973           0 :             if (has_color) {
     974           0 :                 if (has_alpha) {
     975           0 :                     format = CAIRO_FORMAT_ARGB32;
     976             :                 } else {
     977           0 :                     format = CAIRO_FORMAT_RGB24;
     978             :                 }
     979             :             } else {
     980             :                 /* XXX: Using CAIRO_FORMAT_A8 here would be more
     981             :                  * efficient, but would require slightly different code in
     982             :                  * the image conversion to put the alpha channel values
     983             :                  * into the right place. */
     984           0 :                 format = CAIRO_FORMAT_ARGB32;
     985             :             }
     986             : 
     987           0 :             a_mask = surface->a_mask;
     988           0 :             r_mask = surface->r_mask;
     989           0 :             g_mask = surface->g_mask;
     990           0 :             b_mask = surface->b_mask;
     991             : 
     992           0 :             _characterize_field (a_mask, &a_width, &a_shift);
     993           0 :             _characterize_field (r_mask, &r_width, &r_shift);
     994           0 :             _characterize_field (g_mask, &g_width, &g_shift);
     995           0 :             _characterize_field (b_mask, &b_width, &b_shift);
     996             : 
     997             :         } else {
     998           0 :             format = CAIRO_FORMAT_RGB24;
     999             : 
    1000           0 :             status = _cairo_xlib_screen_get_visual_info (display,
    1001             :                                                          surface->screen,
    1002             :                                                          surface->visual,
    1003             :                                                          &visual_info);
    1004           0 :             if (unlikely (status))
    1005           0 :                 goto BAIL;
    1006             :         }
    1007             : 
    1008           0 :         image = (cairo_image_surface_t *) cairo_image_surface_create
    1009             :             (format, ximage->width, ximage->height);
    1010           0 :         status = image->base.status;
    1011           0 :         if (unlikely (status))
    1012           0 :             goto BAIL;
    1013             : 
    1014           0 :         data = cairo_image_surface_get_data (&image->base);
    1015           0 :         rowstride = cairo_image_surface_get_stride (&image->base) >> 2;
    1016           0 :         row = (uint32_t *) data;
    1017           0 :         x0 = extents.x + surface->base.device_transform.x0;
    1018           0 :         y0 = extents.y + surface->base.device_transform.y0;
    1019           0 :         for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
    1020           0 :              y < ximage->height;
    1021           0 :              y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) {
    1022           0 :             const int8_t *dither_row = dither_pattern[y_off];
    1023           0 :             for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
    1024           0 :                  x < ximage->width;
    1025           0 :                  x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0])) {
    1026           0 :                 int dither_adjustment = dither_row[x_off];
    1027             : 
    1028           0 :                 in_pixel = XGetPixel (ximage, x, y);
    1029           0 :                 if (visual_info == NULL) {
    1030           0 :                     out_pixel = (
    1031           0 :                         _field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 |
    1032           0 :                         _field_to_8_undither (in_pixel & r_mask, r_width, r_shift, dither_adjustment) << 16 |
    1033           0 :                         _field_to_8_undither (in_pixel & g_mask, g_width, g_shift, dither_adjustment) << 8 |
    1034           0 :                         _field_to_8_undither (in_pixel & b_mask, b_width, b_shift, dither_adjustment));
    1035             :                 } else {
    1036             :                     /* Undithering pseudocolor does not look better */
    1037           0 :                     out_pixel = _pseudocolor_to_rgb888 (visual_info, in_pixel);
    1038             :                 }
    1039           0 :                 row[x] = out_pixel;
    1040             :             }
    1041           0 :             row += rowstride;
    1042             :         }
    1043           0 :         cairo_surface_mark_dirty (&image->base);
    1044             :     }
    1045             : 
    1046             :  BAIL:
    1047           0 :     if (ximage)
    1048           0 :         XDestroyImage (ximage);
    1049             : 
    1050           0 :     cairo_device_release (&display->base);
    1051             : 
    1052           0 :     if (unlikely (status)) {
    1053           0 :         if (image) {
    1054           0 :             cairo_surface_destroy (&image->base);
    1055           0 :             image = NULL;
    1056             :         }
    1057             :     }
    1058           0 :     *image_out = image;
    1059           0 :     return status;
    1060             : }
    1061             : 
    1062             : static void
    1063           0 : _cairo_xlib_surface_ensure_src_picture (cairo_xlib_display_t *display,
    1064             :                                         cairo_xlib_surface_t *surface)
    1065             : {
    1066           0 :     if (!surface->src_picture) {
    1067             :         XRenderPictureAttributes pa;
    1068           0 :         int mask = 0;
    1069             : 
    1070           0 :         pa.subwindow_mode = IncludeInferiors;
    1071           0 :         mask |= CPSubwindowMode;
    1072             : 
    1073           0 :         surface->src_picture = XRenderCreatePicture (display->display,
    1074             :                                                      surface->drawable,
    1075           0 :                                                      surface->xrender_format,
    1076             :                                                      mask, &pa);
    1077             :     }
    1078           0 : }
    1079             : 
    1080             : static void
    1081           0 : _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_display_t *display,
    1082             :                                             cairo_xlib_surface_t *surface)
    1083             : {
    1084           0 :     if (surface->clip_region != NULL) {
    1085           0 :         XRenderSetPictureClipRectangles (display->display, surface->dst_picture,
    1086             :                                          0, 0,
    1087           0 :                                          surface->clip_rects,
    1088             :                                          surface->num_clip_rects);
    1089             :     } else {
    1090             :         XRenderPictureAttributes pa;
    1091           0 :         pa.clip_mask = None;
    1092           0 :         XRenderChangePicture (display->display, surface->dst_picture,
    1093             :                               CPClipMask, &pa);
    1094             :     }
    1095             : 
    1096           0 :     surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE;
    1097           0 : }
    1098             : 
    1099             : static void
    1100           0 : _cairo_xlib_surface_set_precision (cairo_xlib_display_t *display,
    1101             :                                    cairo_xlib_surface_t *surface,
    1102             :                                    cairo_antialias_t     antialias)
    1103             : {
    1104             :     int precision;
    1105             : 
    1106           0 :     switch (antialias) {
    1107             :     case CAIRO_ANTIALIAS_DEFAULT:
    1108             :     case CAIRO_ANTIALIAS_GRAY:
    1109           0 :         precision = PolyModeImprecise;
    1110           0 :         break;
    1111             :     case CAIRO_ANTIALIAS_NONE:
    1112             :     case CAIRO_ANTIALIAS_SUBPIXEL:
    1113           0 :         precision = PolyModePrecise;
    1114           0 :         break;
    1115             :     }
    1116             : 
    1117             :     /* NVidia's driver version 190.42 is much slower when using PolyModeInprecise */
    1118           0 :     precision = PolyModePrecise;
    1119             : 
    1120           0 :     if (surface->precision != precision) {
    1121             :         XRenderPictureAttributes pa;
    1122             : 
    1123           0 :         pa.poly_mode = precision;
    1124           0 :         XRenderChangePicture (display->display, surface->dst_picture,
    1125             :                               CPPolyMode, &pa);
    1126             : 
    1127           0 :         surface->precision = precision;
    1128             :     }
    1129           0 : }
    1130             : 
    1131             : static void
    1132           0 : _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_display_t    *display,
    1133             :                                         cairo_xlib_surface_t    *surface)
    1134             : {
    1135           0 :     if (!surface->dst_picture) {
    1136           0 :         surface->dst_picture = XRenderCreatePicture (display->display,
    1137             :                                                      surface->drawable,
    1138           0 :                                                      surface->xrender_format,
    1139             :                                                      0, NULL);
    1140             :     }
    1141             : 
    1142           0 :     if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE)
    1143           0 :         _cairo_xlib_surface_set_picture_clip_rects (display, surface);
    1144           0 : }
    1145             : 
    1146             : static cairo_status_t
    1147           0 : _draw_image_surface (cairo_xlib_surface_t   *surface,
    1148             :                      cairo_image_surface_t  *image,
    1149             :                      int                    src_x,
    1150             :                      int                    src_y,
    1151             :                      int                    width,
    1152             :                      int                    height,
    1153             :                      int                    dst_x,
    1154             :                      int                    dst_y)
    1155             : {
    1156             :     cairo_xlib_display_t *display;
    1157             :     XImage ximage;
    1158             :     cairo_format_masks_t image_masks;
    1159           0 :     int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
    1160           0 :     pixman_image_t *pixman_image = NULL;
    1161             :     cairo_status_t status;
    1162             :     cairo_bool_t own_data;
    1163             :     GC gc;
    1164             : 
    1165           0 :     ximage.width = image->width;
    1166           0 :     ximage.height = image->height;
    1167           0 :     ximage.format = ZPixmap;
    1168           0 :     ximage.byte_order = native_byte_order;
    1169           0 :     ximage.bitmap_unit = 32;    /* always for libpixman */
    1170           0 :     ximage.bitmap_bit_order = native_byte_order;
    1171           0 :     ximage.bitmap_pad = 32;     /* always for libpixman */
    1172           0 :     ximage.depth = surface->depth;
    1173           0 :     ximage.red_mask = surface->r_mask;
    1174           0 :     ximage.green_mask = surface->g_mask;
    1175           0 :     ximage.blue_mask = surface->b_mask;
    1176           0 :     ximage.xoffset = 0;
    1177             : 
    1178           0 :     status = _cairo_xlib_display_acquire (surface->base.device, &display);
    1179           0 :     if (unlikely (status))
    1180           0 :         return status;
    1181             : 
    1182           0 :     if (!_pixman_format_to_masks (image->pixman_format, &image_masks))
    1183             :     {
    1184             :         pixman_format_code_t intermediate_format;
    1185             :         int ret;
    1186             : 
    1187           0 :         image_masks.alpha_mask = surface->a_mask;
    1188           0 :         image_masks.red_mask   = surface->r_mask;
    1189           0 :         image_masks.green_mask = surface->g_mask;
    1190           0 :         image_masks.blue_mask  = surface->b_mask;
    1191           0 :         image_masks.bpp        = surface->depth;
    1192           0 :         ret = _pixman_format_from_masks (&image_masks, &intermediate_format);
    1193           0 :         assert (ret);
    1194             : 
    1195           0 :         own_data = FALSE;
    1196             : 
    1197           0 :         pixman_image = pixman_image_create_bits (intermediate_format,
    1198             :                                                  image->width,
    1199             :                                                  image->height,
    1200             :                                                  NULL,
    1201             :                                                  0);
    1202           0 :         if (pixman_image == NULL) {
    1203           0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1204           0 :             goto BAIL;
    1205             :         }
    1206             : 
    1207           0 :         pixman_image_composite32 (PIXMAN_OP_SRC,
    1208             :                                   image->pixman_image,
    1209             :                                   NULL,
    1210             :                                   pixman_image,
    1211             :                                   0, 0,
    1212             :                                   0, 0,
    1213             :                                   0, 0,
    1214             :                                   image->width, image->height);
    1215             : 
    1216           0 :         ximage.bits_per_pixel = image_masks.bpp;
    1217           0 :         ximage.data = (char *) pixman_image_get_data (pixman_image);
    1218           0 :         ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
    1219             : 
    1220           0 :         ret = XInitImage (&ximage);
    1221           0 :         assert (ret != 0);
    1222             :     }
    1223           0 :     else if ((image_masks.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
    1224           0 :              (image_masks.red_mask   == surface->r_mask || surface->r_mask == 0) &&
    1225           0 :              (image_masks.green_mask == surface->g_mask || surface->g_mask == 0) &&
    1226           0 :              (image_masks.blue_mask  == surface->b_mask || surface->b_mask == 0))
    1227           0 :     {
    1228             :         int ret;
    1229             : 
    1230           0 :         ximage.bits_per_pixel = image_masks.bpp;
    1231           0 :         ximage.bytes_per_line = image->stride;
    1232           0 :         ximage.data = (char *)image->data;
    1233           0 :         own_data = FALSE;
    1234             : 
    1235           0 :         ret = XInitImage (&ximage);
    1236           0 :         assert (ret != 0);
    1237             :     }
    1238             :     else
    1239             :     {
    1240             :         unsigned int stride, rowstride;
    1241             :         int x, y, x0, y0, x_off, y_off;
    1242             :         uint32_t in_pixel, out_pixel, *row;
    1243           0 :         int i_a_width=0, i_r_width=0, i_g_width=0, i_b_width=0;
    1244           0 :         int i_a_shift=0, i_r_shift=0, i_g_shift=0, i_b_shift=0;
    1245           0 :         int o_a_width=0, o_r_width=0, o_g_width=0, o_b_width=0;
    1246           0 :         int o_a_shift=0, o_r_shift=0, o_g_shift=0, o_b_shift=0;
    1247           0 :         cairo_xlib_visual_info_t *visual_info = NULL;
    1248             :         cairo_bool_t true_color;
    1249             :         int ret;
    1250             : 
    1251           0 :         if (surface->depth > 16)
    1252           0 :             ximage.bits_per_pixel = 32;
    1253           0 :         else if (surface->depth > 8)
    1254           0 :             ximage.bits_per_pixel = 16;
    1255           0 :         else if (surface->depth > 1)
    1256           0 :             ximage.bits_per_pixel = 8;
    1257             :         else
    1258           0 :             ximage.bits_per_pixel = 1;
    1259           0 :         stride = CAIRO_STRIDE_FOR_WIDTH_BPP (ximage.width,
    1260             :                                              ximage.bits_per_pixel);
    1261           0 :         ximage.bytes_per_line = stride;
    1262           0 :         ximage.data = _cairo_malloc_ab (stride, ximage.height);
    1263           0 :         if (unlikely (ximage.data == NULL)) {
    1264           0 :             own_data = FALSE;
    1265           0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1266           0 :             goto BAIL;
    1267             :         }
    1268             : 
    1269           0 :         own_data = TRUE;
    1270             : 
    1271           0 :         ret = XInitImage (&ximage);
    1272           0 :         assert (ret != 0);
    1273             : 
    1274           0 :         _characterize_field (image_masks.alpha_mask, &i_a_width, &i_a_shift);
    1275           0 :         _characterize_field (image_masks.red_mask  , &i_r_width, &i_r_shift);
    1276           0 :         _characterize_field (image_masks.green_mask, &i_g_width, &i_g_shift);
    1277           0 :         _characterize_field (image_masks.blue_mask , &i_b_width, &i_b_shift);
    1278             : 
    1279           0 :         true_color = surface->visual == NULL ||
    1280           0 :                      surface->visual->class == TrueColor;
    1281           0 :         if (true_color) {
    1282           0 :             _characterize_field (surface->a_mask, &o_a_width, &o_a_shift);
    1283           0 :             _characterize_field (surface->r_mask, &o_r_width, &o_r_shift);
    1284           0 :             _characterize_field (surface->g_mask, &o_g_width, &o_g_shift);
    1285           0 :             _characterize_field (surface->b_mask, &o_b_width, &o_b_shift);
    1286             :         } else {
    1287           0 :             status = _cairo_xlib_screen_get_visual_info (display,
    1288             :                                                          surface->screen,
    1289             :                                                          surface->visual,
    1290             :                                                          &visual_info);
    1291           0 :             if (unlikely (status))
    1292           0 :                 goto BAIL;
    1293             :         }
    1294             : 
    1295           0 :         rowstride = image->stride >> 2;
    1296           0 :         row = (uint32_t *) image->data;
    1297           0 :         x0 = dst_x + surface->base.device_transform.x0;
    1298           0 :         y0 = dst_y + surface->base.device_transform.y0;
    1299           0 :         for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
    1300           0 :              y < ximage.height;
    1301           0 :              y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern))
    1302             :         {
    1303           0 :             const int8_t *dither_row = dither_pattern[y_off];
    1304             : 
    1305           0 :             for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
    1306           0 :                  x < ximage.width;
    1307           0 :                  x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0]))
    1308             :             {
    1309           0 :                 int dither_adjustment = dither_row[x_off];
    1310             :                 int a, r, g, b;
    1311             : 
    1312           0 :                 if (image_masks.bpp == 1)
    1313           0 :                     in_pixel = !! (((uint8_t*)row)[x/8] & (1 << (x & 7)));
    1314           0 :                 else if (image_masks.bpp <= 8)
    1315           0 :                     in_pixel = ((uint8_t*)row)[x];
    1316           0 :                 else if (image_masks.bpp <= 16)
    1317           0 :                     in_pixel = ((uint16_t*)row)[x];
    1318           0 :                 else if (image_masks.bpp <= 24)
    1319             : #ifdef WORDS_BIGENDIAN
    1320             :                     in_pixel = ((uint8_t*)row)[3 * x]     << 16 |
    1321             :                                ((uint8_t*)row)[3 * x + 1] << 8  |
    1322             :                                ((uint8_t*)row)[3 * x + 2];
    1323             : #else
    1324           0 :                     in_pixel = ((uint8_t*)row)[3 * x]           |
    1325           0 :                                ((uint8_t*)row)[3 * x + 1] << 8  |
    1326           0 :                                ((uint8_t*)row)[3 * x + 2] << 16;
    1327             : #endif
    1328             :                 else
    1329           0 :                     in_pixel = row[x];
    1330             : 
    1331             :                 /* If the incoming image has no alpha channel, then the input
    1332             :                  * is opaque and the output should have the maximum alpha value.
    1333             :                  * For all other channels, their absence implies 0.
    1334             :                  */
    1335           0 :                 if (image_masks.alpha_mask == 0x0)
    1336           0 :                     a = 0xff;
    1337             :                 else
    1338           0 :                     a = _field_to_8 (in_pixel & image_masks.alpha_mask, i_a_width, i_a_shift);
    1339           0 :                 r = _field_to_8 (in_pixel & image_masks.red_mask  , i_r_width, i_r_shift);
    1340           0 :                 g = _field_to_8 (in_pixel & image_masks.green_mask, i_g_width, i_g_shift);
    1341           0 :                 b = _field_to_8 (in_pixel & image_masks.blue_mask , i_b_width, i_b_shift);
    1342             : 
    1343           0 :                 if (true_color) {
    1344           0 :                     out_pixel = _field_from_8        (a, o_a_width, o_a_shift) |
    1345           0 :                                 _field_from_8_dither (r, o_r_width, o_r_shift, dither_adjustment) |
    1346           0 :                                 _field_from_8_dither (g, o_g_width, o_g_shift, dither_adjustment) |
    1347           0 :                                 _field_from_8_dither (b, o_b_width, o_b_shift, dither_adjustment);
    1348             :                 } else {
    1349           0 :                     out_pixel = _pseudocolor_from_rgb888_dither (visual_info, r, g, b, dither_adjustment);
    1350             :                 }
    1351             : 
    1352           0 :                 XPutPixel (&ximage, x, y, out_pixel);
    1353             :             }
    1354             : 
    1355           0 :             row += rowstride;
    1356             :         }
    1357             :     }
    1358             : 
    1359           0 :     status = _cairo_xlib_surface_get_gc (display, surface, &gc);
    1360           0 :     if (unlikely (status))
    1361           0 :         goto BAIL;
    1362             : 
    1363           0 :     XPutImage (display->display, surface->drawable, gc,
    1364             :                &ximage, src_x, src_y, dst_x, dst_y,
    1365             :                width, height);
    1366             : 
    1367           0 :     _cairo_xlib_surface_put_gc (display, surface, gc);
    1368             : 
    1369             :   BAIL:
    1370             : 
    1371           0 :     cairo_device_release (&display->base);
    1372             : 
    1373           0 :     if (own_data)
    1374           0 :         free (ximage.data);
    1375           0 :     if (pixman_image)
    1376           0 :         pixman_image_unref (pixman_image);
    1377             : 
    1378           0 :     return CAIRO_STATUS_SUCCESS;
    1379             : }
    1380             : 
    1381             : static cairo_status_t
    1382           0 : _cairo_xlib_surface_acquire_source_image (void                    *abstract_surface,
    1383             :                                           cairo_image_surface_t  **image_out,
    1384             :                                           void                   **image_extra)
    1385             : {
    1386           0 :     cairo_xlib_surface_t *surface = abstract_surface;
    1387             :     cairo_image_surface_t *image;
    1388             :     cairo_status_t status;
    1389             : 
    1390           0 :     status = _get_image_surface (surface, NULL, &image, NULL);
    1391           0 :     if (unlikely (status))
    1392           0 :         return status;
    1393             : 
    1394           0 :     *image_out = image;
    1395           0 :     *image_extra = NULL;
    1396             : 
    1397           0 :     return CAIRO_STATUS_SUCCESS;
    1398             : }
    1399             : 
    1400             : static cairo_surface_t *
    1401           0 : _cairo_xlib_surface_snapshot (void *abstract_surface)
    1402             : {
    1403           0 :     cairo_xlib_surface_t *surface = abstract_surface;
    1404             :     cairo_image_surface_t *image;
    1405             :     cairo_status_t status;
    1406             : 
    1407           0 :     status = _get_image_surface (surface, NULL, &image, NULL);
    1408           0 :     if (unlikely (status))
    1409           0 :         return _cairo_surface_create_in_error (status);
    1410             : 
    1411           0 :     return &image->base;
    1412             : }
    1413             : 
    1414             : static void
    1415           0 : _cairo_xlib_surface_release_source_image (void                   *abstract_surface,
    1416             :                                           cairo_image_surface_t  *image,
    1417             :                                           void                   *image_extra)
    1418             : {
    1419           0 :     cairo_surface_destroy (&image->base);
    1420           0 : }
    1421             : 
    1422             : static cairo_status_t
    1423           0 : _cairo_xlib_surface_acquire_dest_image (void                    *abstract_surface,
    1424             :                                         cairo_rectangle_int_t   *interest_rect,
    1425             :                                         cairo_image_surface_t  **image_out,
    1426             :                                         cairo_rectangle_int_t   *image_rect_out,
    1427             :                                         void                   **image_extra)
    1428             : {
    1429           0 :     cairo_xlib_surface_t *surface = abstract_surface;
    1430             :     cairo_image_surface_t *image;
    1431             :     cairo_status_t status;
    1432             : 
    1433           0 :     status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
    1434           0 :     if (unlikely (status))
    1435           0 :         return status;
    1436             : 
    1437           0 :     *image_out = image;
    1438           0 :     *image_extra = NULL;
    1439             : 
    1440           0 :     return CAIRO_STATUS_SUCCESS;
    1441             : }
    1442             : 
    1443             : static void
    1444           0 : _cairo_xlib_surface_release_dest_image (void                    *abstract_surface,
    1445             :                                         cairo_rectangle_int_t   *interest_rect,
    1446             :                                         cairo_image_surface_t   *image,
    1447             :                                         cairo_rectangle_int_t   *image_rect,
    1448             :                                         void                    *image_extra)
    1449             : {
    1450           0 :     cairo_xlib_surface_t *surface = abstract_surface;
    1451             :     cairo_status_t status;
    1452             : 
    1453           0 :     status = _draw_image_surface (surface, image,
    1454             :                                   0, 0, image->width, image->height,
    1455             :                                   image_rect->x, image_rect->y);
    1456           0 :     status = _cairo_surface_set_error (&surface->base, status);
    1457             : 
    1458           0 :     cairo_surface_destroy (&image->base);
    1459           0 : }
    1460             : 
    1461             : /*
    1462             :  * Return whether two xlib surfaces share the same
    1463             :  * screen.  Both core and Render drawing require this
    1464             :  * when using multiple drawables in an operation.
    1465             :  */
    1466             : static inline cairo_bool_t
    1467           0 : _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
    1468             :                                  cairo_xlib_surface_t *src)
    1469             : {
    1470           0 :     return dst->screen == src->screen;
    1471             : }
    1472             : 
    1473             : static cairo_status_t
    1474           0 : _cairo_xlib_surface_clone_similar (void                 *abstract_surface,
    1475             :                                    cairo_surface_t      *src,
    1476             :                                    int                   src_x,
    1477             :                                    int                   src_y,
    1478             :                                    int                   width,
    1479             :                                    int                   height,
    1480             :                                    int                  *clone_offset_x,
    1481             :                                    int                  *clone_offset_y,
    1482             :                                    cairo_surface_t     **clone_out)
    1483             : {
    1484           0 :     cairo_xlib_surface_t *surface = abstract_surface;
    1485             :     cairo_xlib_surface_t *clone;
    1486             :     cairo_status_t status;
    1487             : 
    1488           0 :     if (src->backend == surface->base.backend ) {
    1489           0 :         cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
    1490             : 
    1491           0 :         if (_cairo_xlib_surface_same_screen (surface, xlib_src)) {
    1492           0 :             *clone_offset_x = 0;
    1493           0 :             *clone_offset_y = 0;
    1494           0 :             *clone_out = cairo_surface_reference (src);
    1495             : 
    1496           0 :             return CAIRO_STATUS_SUCCESS;
    1497             :         }
    1498           0 :     } else if (_cairo_surface_is_image (src)) {
    1499           0 :         cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
    1500             : 
    1501           0 :         if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
    1502           0 :             return UNSUPPORTED ("roi too large for xlib");
    1503             : 
    1504           0 :         clone = (cairo_xlib_surface_t *)
    1505           0 :             _cairo_xlib_surface_create_similar (surface,
    1506             :                                                 image_src->base.content,
    1507             :                                                 width, height);
    1508           0 :         if (clone == NULL)
    1509           0 :             return UNSUPPORTED ("unhandled image format, no similar surface");
    1510             : 
    1511           0 :         if (unlikely (clone->base.status))
    1512           0 :             return clone->base.status;
    1513             : 
    1514           0 :         status = _draw_image_surface (clone, image_src,
    1515             :                                       src_x, src_y,
    1516             :                                       width, height,
    1517             :                                       0, 0);
    1518           0 :         if (unlikely (status)) {
    1519           0 :             cairo_surface_destroy (&clone->base);
    1520           0 :             return status;
    1521             :         }
    1522             : 
    1523           0 :         *clone_offset_x = src_x;
    1524           0 :         *clone_offset_y = src_y;
    1525           0 :         *clone_out = &clone->base;
    1526             : 
    1527           0 :         return CAIRO_STATUS_SUCCESS;
    1528             :     }
    1529             : 
    1530           0 :     return CAIRO_INT_STATUS_UNSUPPORTED;
    1531             : }
    1532             : 
    1533             : static cairo_surface_t *
    1534           0 : _cairo_xlib_surface_create_solid_pattern_surface (void                  *abstract_surface,
    1535             :                                                   const cairo_solid_pattern_t *solid_pattern)
    1536             : {
    1537             :     /* This function's only responsibility is to create a proper surface
    1538             :      * for when XRender is not available.  The proper surface is a xlib
    1539             :      * surface (as opposed to image surface which is what create_similar
    1540             :      * returns in those cases) and the size of the dithering pattern, not
    1541             :      * 1x1.  This surface can then be used in
    1542             :      * _cairo_xlib_surface_solid_fill_rectangles() to do dithered "solid"
    1543             :      * fills using core protocol */
    1544             : 
    1545           0 :     cairo_xlib_surface_t *other = abstract_surface;
    1546             :     cairo_image_surface_t *image;
    1547           0 :     cairo_xlib_surface_t *surface = NULL;
    1548           0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
    1549             :     cairo_xlib_display_t *display;
    1550             : 
    1551           0 :     int width = ARRAY_LENGTH (dither_pattern[0]);
    1552           0 :     int height = ARRAY_LENGTH (dither_pattern);
    1553             : 
    1554           0 :     Pixmap pixmap = None;
    1555             : 
    1556           0 :     if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other))
    1557           0 :         return NULL;
    1558             : 
    1559           0 :     image = (cairo_image_surface_t *)
    1560           0 :         _cairo_image_surface_create_with_content (_cairo_color_get_content (&solid_pattern->color),
    1561             :                                                   width, height);
    1562           0 :     status = image->base.status;
    1563           0 :     if (unlikely (status))
    1564           0 :         goto BAIL;
    1565             : 
    1566           0 :     status = _cairo_xlib_display_acquire (other->base.device, &display);
    1567           0 :     if (unlikely (status))
    1568           0 :         goto BAIL;
    1569             : 
    1570           0 :     pixmap = XCreatePixmap (display->display,
    1571             :                             other->drawable,
    1572             :                             width, height,
    1573           0 :                             other->depth);
    1574           0 :     cairo_device_release (&display->base);
    1575             : 
    1576           0 :     surface = (cairo_xlib_surface_t *)
    1577           0 :               _cairo_xlib_surface_create_internal (other->screen,
    1578             :                                                    pixmap,
    1579             :                                                    other->visual,
    1580             :                                                    other->xrender_format,
    1581             :                                                    width, height,
    1582             :                                                    other->depth);
    1583           0 :     status = surface->base.status;
    1584           0 :     if (unlikely (status))
    1585           0 :         goto BAIL;
    1586             : 
    1587           0 :     status = _cairo_surface_paint (&image->base,
    1588             :                                    CAIRO_OPERATOR_SOURCE,
    1589             :                                    &solid_pattern->base,
    1590             :                                    NULL);
    1591           0 :     if (unlikely (status))
    1592           0 :         goto BAIL;
    1593             : 
    1594           0 :     status = _draw_image_surface (surface, image,
    1595             :                                   0, 0,
    1596             :                                   width, height,
    1597             :                                   0, 0);
    1598           0 :     if (unlikely (status))
    1599           0 :         goto BAIL;
    1600             : 
    1601             :   BAIL:
    1602           0 :     cairo_surface_destroy (&image->base);
    1603             : 
    1604           0 :     if (status) {
    1605           0 :         if (pixmap != None) {
    1606           0 :             if (!_cairo_xlib_display_acquire (other->base.device, &display)) {
    1607           0 :               XFreePixmap (display->display, pixmap);
    1608           0 :               cairo_device_release (&display->base);
    1609             :             }
    1610             :         }
    1611           0 :         cairo_surface_destroy (&surface->base);
    1612             : 
    1613           0 :         return _cairo_surface_create_in_error (status);
    1614             :     }
    1615             : 
    1616           0 :     surface->owns_pixmap = TRUE;
    1617           0 :     return &surface->base;
    1618             : }
    1619             : 
    1620             : static cairo_bool_t
    1621           0 : _cairo_xlib_surface_can_repaint_solid_pattern_surface (void *abstract_surface,
    1622             :                                                        const cairo_solid_pattern_t *solid_pattern)
    1623             : {
    1624           0 :     cairo_xlib_surface_t *other = abstract_surface;
    1625           0 :     return CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other);
    1626             : }
    1627             : 
    1628             : static cairo_status_t
    1629           0 : _cairo_xlib_surface_set_matrix (cairo_xlib_display_t *display,
    1630             :                                 cairo_xlib_surface_t *surface,
    1631             :                                 const cairo_matrix_t *matrix,
    1632             :                                 double                xc,
    1633             :                                 double                yc)
    1634             : {
    1635             :     XTransform xtransform;
    1636             : 
    1637             :     /* Casting between pixman_transform_t and XTransform is safe because
    1638             :      * they happen to be the exact same type.
    1639             :      */
    1640           0 :     _cairo_matrix_to_pixman_matrix (matrix,
    1641             :                                     (pixman_transform_t *) &xtransform,
    1642             :                                     xc, yc);
    1643             : 
    1644           0 :     if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0)
    1645           0 :         return CAIRO_STATUS_SUCCESS;
    1646             : 
    1647           0 :     if (! CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
    1648           0 :         return UNSUPPORTED ("XRender does not support picture transforms");
    1649             : 
    1650           0 :     XRenderSetPictureTransform (display->display, surface->src_picture, &xtransform);
    1651           0 :     surface->xtransform = xtransform;
    1652             : 
    1653           0 :     return CAIRO_STATUS_SUCCESS;
    1654             : }
    1655             : 
    1656             : static cairo_status_t
    1657           0 : _cairo_xlib_surface_set_filter (cairo_xlib_display_t *display,
    1658             :                                 cairo_xlib_surface_t *surface,
    1659             :                                 cairo_filter_t       filter)
    1660             : {
    1661             :     const char *render_filter;
    1662             : 
    1663           0 :     if (surface->filter == filter)
    1664           0 :         return CAIRO_STATUS_SUCCESS;
    1665             : 
    1666           0 :     if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) {
    1667           0 :         if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
    1668           0 :             return CAIRO_STATUS_SUCCESS;
    1669             : 
    1670           0 :         return UNSUPPORTED ("XRender does not support filter");
    1671             :     }
    1672             : 
    1673           0 :     switch (filter) {
    1674             :     case CAIRO_FILTER_FAST:
    1675           0 :         render_filter = FilterFast;
    1676           0 :         break;
    1677             :     case CAIRO_FILTER_GOOD:
    1678           0 :         render_filter = FilterGood;
    1679           0 :         break;
    1680             :     case CAIRO_FILTER_BEST:
    1681           0 :         render_filter = FilterBest;
    1682           0 :         break;
    1683             :     case CAIRO_FILTER_NEAREST:
    1684           0 :         render_filter = FilterNearest;
    1685           0 :         break;
    1686             :     case CAIRO_FILTER_BILINEAR:
    1687           0 :         render_filter = FilterBilinear;
    1688           0 :         break;
    1689             :     case CAIRO_FILTER_GAUSSIAN:
    1690             :         /* XXX: The GAUSSIAN value has no implementation in cairo
    1691             :          * whatsoever, so it was really a mistake to have it in the
    1692             :          * API. We could fix this by officially deprecating it, or
    1693             :          * else inventing semantics and providing an actual
    1694             :          * implementation for it. */
    1695             :     default:
    1696           0 :         render_filter = FilterBest;
    1697           0 :         break;
    1698             :     }
    1699             : 
    1700           0 :     XRenderSetPictureFilter (display->display, surface->src_picture,
    1701             :                              (char *) render_filter, NULL, 0);
    1702           0 :     surface->filter = filter;
    1703             : 
    1704           0 :     return CAIRO_STATUS_SUCCESS;
    1705             : }
    1706             : 
    1707             : static cairo_status_t
    1708           0 : _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t    *surface,
    1709             :                                 cairo_extend_t           extend,
    1710             :                                 unsigned long           *mask,
    1711             :                                 XRenderPictureAttributes *pa)
    1712             : {
    1713             :     int repeat;
    1714             : 
    1715           0 :     if (surface->extend == extend)
    1716           0 :         return CAIRO_STATUS_SUCCESS;
    1717             : 
    1718           0 :     switch (extend) {
    1719             :     case CAIRO_EXTEND_NONE:
    1720           0 :         repeat = RepeatNone;
    1721           0 :         break;
    1722             :     case CAIRO_EXTEND_REPEAT:
    1723           0 :         repeat = RepeatNormal;
    1724           0 :         break;
    1725             :     case CAIRO_EXTEND_REFLECT:
    1726           0 :         if (surface->buggy_pad_reflect)
    1727           0 :             return UNSUPPORTED ("buggy reflect");
    1728             : 
    1729           0 :         repeat = RepeatReflect;
    1730           0 :         break;
    1731             :     case CAIRO_EXTEND_PAD:
    1732           0 :         if (surface->buggy_pad_reflect)
    1733           0 :             return UNSUPPORTED ("buggy pad");
    1734             : 
    1735           0 :         repeat = RepeatPad;
    1736           0 :         break;
    1737             :     default:
    1738           0 :         ASSERT_NOT_REACHED;
    1739           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1740             :     }
    1741             : 
    1742           0 :     *mask |= CPRepeat;
    1743           0 :     pa->repeat = repeat;
    1744             : 
    1745           0 :     surface->extend = extend;
    1746           0 :     return CAIRO_STATUS_SUCCESS;
    1747             : }
    1748             : 
    1749             : static cairo_status_t
    1750           0 : _cairo_xlib_surface_set_component_alpha (cairo_xlib_surface_t *surface,
    1751             :                                          cairo_bool_t           ca,
    1752             :                                          unsigned long          *mask,
    1753             :                                          XRenderPictureAttributes *pa)
    1754             : {
    1755           0 :     if (surface->has_component_alpha == ca)
    1756           0 :         return CAIRO_STATUS_SUCCESS;
    1757             : 
    1758           0 :     *mask |= CPComponentAlpha;
    1759           0 :     pa->component_alpha = ca;
    1760             : 
    1761           0 :     surface->has_component_alpha = ca;
    1762           0 :     return CAIRO_STATUS_SUCCESS;
    1763             : }
    1764             : 
    1765             : static cairo_int_status_t
    1766           0 : _cairo_xlib_surface_set_attributes (cairo_xlib_display_t             *display,
    1767             :                                     cairo_xlib_surface_t             *surface,
    1768             :                                     const cairo_surface_attributes_t *attributes,
    1769             :                                     double                            xc,
    1770             :                                     double                            yc)
    1771             : {
    1772             :     cairo_int_status_t status;
    1773             :     XRenderPictureAttributes pa;
    1774           0 :     unsigned long mask = 0;
    1775             : 
    1776           0 :     _cairo_xlib_surface_ensure_src_picture (display, surface);
    1777             : 
    1778           0 :     status = _cairo_xlib_surface_set_matrix (display, surface,
    1779             :                                              &attributes->matrix, xc, yc);
    1780           0 :     if (unlikely (status))
    1781           0 :         return status;
    1782             : 
    1783           0 :     status = _cairo_xlib_surface_set_repeat (surface, attributes->extend,
    1784             :                                              &mask, &pa);
    1785           0 :     if (unlikely (status))
    1786           0 :         return status;
    1787             : 
    1788           0 :     status = _cairo_xlib_surface_set_component_alpha (surface,
    1789             :                                                       attributes->has_component_alpha,
    1790             :                                                       &mask, &pa);
    1791           0 :     if (unlikely (status))
    1792           0 :         return status;
    1793             : 
    1794           0 :     status = _cairo_xlib_surface_set_filter (display, surface, attributes->filter);
    1795           0 :     if (unlikely (status))
    1796           0 :         return status;
    1797             : 
    1798           0 :     if (mask)
    1799           0 :         XRenderChangePicture (display->display, surface->src_picture, mask, &pa);
    1800             : 
    1801           0 :     return CAIRO_STATUS_SUCCESS;
    1802             : }
    1803             : 
    1804             : /* Checks whether we can can directly draw from src to dst with
    1805             :  * the core protocol: either with CopyArea or using src as a
    1806             :  * a tile in a GC.
    1807             :  */
    1808             : static cairo_bool_t
    1809           0 : _surfaces_compatible (cairo_xlib_surface_t *dst,
    1810             :                       cairo_xlib_surface_t *src)
    1811             : {
    1812             :     /* same screen */
    1813           0 :     if (! _cairo_xlib_surface_same_screen (dst, src))
    1814           0 :         return FALSE;
    1815             : 
    1816             :     /* same depth (for core) */
    1817           0 :     if (src->depth != dst->depth)
    1818           0 :         return FALSE;
    1819             : 
    1820             :     /* if Render is supported, match picture formats */
    1821           0 :     if (src->xrender_format != dst->xrender_format)
    1822           0 :         return FALSE;
    1823           0 :     else if (src->xrender_format != NULL)
    1824           0 :         return TRUE;
    1825             : 
    1826             :     /* Without Render, match visuals instead */
    1827           0 :     if (src->visual == dst->visual)
    1828           0 :         return TRUE;
    1829             : 
    1830           0 :     return FALSE;
    1831             : }
    1832             : 
    1833             : static cairo_bool_t
    1834           0 : _surface_has_alpha (cairo_xlib_surface_t *surface)
    1835             : {
    1836           0 :     if (surface->xrender_format) {
    1837           0 :         if (surface->xrender_format->type == PictTypeDirect &&
    1838           0 :             surface->xrender_format->direct.alphaMask != 0)
    1839           0 :             return TRUE;
    1840             :         else
    1841           0 :             return FALSE;
    1842             :     } else {
    1843             :         /* In the no-render case, we never have alpha */
    1844           0 :         return FALSE;
    1845             :     }
    1846             : }
    1847             : 
    1848             : /* Returns true if the given operator and alpha combination requires alpha
    1849             :  * compositing to complete on source and destination surfaces with the same
    1850             :  * format.  i.e. if a simple bitwise copy is not appropriate.
    1851             :  */
    1852             : static cairo_bool_t
    1853           0 : _operator_needs_alpha_composite (cairo_operator_t op,
    1854             :                                  cairo_bool_t     surfaces_have_alpha)
    1855             : {
    1856           0 :     if (op == CAIRO_OPERATOR_SOURCE)
    1857           0 :         return FALSE;
    1858             : 
    1859           0 :     if (op == CAIRO_OPERATOR_OVER ||
    1860           0 :         op == CAIRO_OPERATOR_IN ||
    1861             :         op == CAIRO_OPERATOR_ATOP)
    1862           0 :         return surfaces_have_alpha;
    1863             : 
    1864           0 :     return TRUE;
    1865             : }
    1866             : 
    1867             : /* There is a bug in most older X servers with compositing using a
    1868             :  * untransformed repeating source pattern when the source is in off-screen
    1869             :  * video memory, and another with repeated transformed images using a
    1870             :  * general transform matrix. When these bugs could be triggered, we need a
    1871             :  * fallback: in the common case where we have no transformation and the
    1872             :  * source and destination have the same format/visual, we can do the
    1873             :  * operation using the core protocol for the first bug, otherwise, we need
    1874             :  * a software fallback.
    1875             :  *
    1876             :  * We can also often optimize a compositing operation by calling XCopyArea
    1877             :  * for some common cases where there is no alpha compositing to be done.
    1878             :  * We figure that out here as well.
    1879             :  */
    1880             : typedef enum {
    1881             :     DO_RENDER,          /* use render */
    1882             :     DO_XCOPYAREA,       /* core protocol XCopyArea optimization/fallback */
    1883             :     DO_XTILE,           /* core protocol XSetTile optimization/fallback */
    1884             :     DO_UNSUPPORTED      /* software fallback */
    1885             : } composite_operation_t;
    1886             : 
    1887             : /* Initial check for the render bugs; we need to recheck for the
    1888             :  * offscreen-memory bug after we turn patterns into surfaces, since that
    1889             :  * may introduce a repeating pattern for gradient patterns.  We don't need
    1890             :  * to check for the repeat+transform bug because gradient surfaces aren't
    1891             :  * transformed.
    1892             :  *
    1893             :  * All we do here is reject cases where we *know* are going to
    1894             :  * hit the bug and won't be able to use a core protocol fallback.
    1895             :  */
    1896             : static composite_operation_t
    1897           0 : _categorize_composite_operation (cairo_xlib_surface_t *dst,
    1898             :                                  cairo_operator_t      op,
    1899             :                                  const cairo_pattern_t *src_pattern,
    1900             :                                  cairo_bool_t          have_mask)
    1901             : 
    1902             : {
    1903           0 :     if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (dst, op))
    1904           0 :         return DO_UNSUPPORTED;
    1905             : 
    1906           0 :     if (! dst->buggy_repeat)
    1907           0 :         return DO_RENDER;
    1908             : 
    1909           0 :     if (src_pattern->type != CAIRO_PATTERN_TYPE_SOLID &&
    1910           0 :         src_pattern->extend == CAIRO_EXTEND_REPEAT)
    1911             :     {
    1912             :         /* Check for the bug with repeat patterns nad general transforms. */
    1913           0 :         if (! _cairo_matrix_is_integer_translation (&src_pattern->matrix,
    1914             :                                                     NULL, NULL))
    1915             :         {
    1916           0 :             return DO_UNSUPPORTED;
    1917             :         }
    1918             : 
    1919           0 :         if (have_mask ||
    1920           0 :             !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
    1921             :         {
    1922           0 :             return DO_UNSUPPORTED;
    1923             :         }
    1924             : 
    1925           0 :         if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
    1926           0 :             cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) src_pattern;
    1927             : 
    1928             :             /* This is the case where we have the bug involving
    1929             :              * untransformed repeating source patterns with off-screen
    1930             :              * video memory; reject some cases where a core protocol
    1931             :              * fallback is impossible.
    1932             :              */
    1933           0 :             if (_cairo_surface_is_xlib (surface_pattern->surface)) {
    1934           0 :                 cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) surface_pattern->surface;
    1935             : 
    1936           0 :                 if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
    1937           0 :                     return DO_UNSUPPORTED;
    1938             : 
    1939             :                 /* If these are on the same screen but otherwise incompatible,
    1940             :                  * make a copy as core drawing can't cross depths and doesn't
    1941             :                  * work right across visuals of the same depth
    1942             :                  */
    1943           0 :                 if (_cairo_xlib_surface_same_screen (dst, src) &&
    1944           0 :                     !_surfaces_compatible (dst, src))
    1945             :                 {
    1946           0 :                     return DO_UNSUPPORTED;
    1947             :                 }
    1948             :             }
    1949             :         }
    1950             :     }
    1951             : 
    1952           0 :     return DO_RENDER;
    1953             : }
    1954             : 
    1955             : /* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
    1956             :  * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
    1957             :  * did to turn gradients into a pattern, but most of the time we can handle
    1958             :  * that case with core protocol fallback.
    1959             :  *
    1960             :  * Also check here if we can just use XCopyArea, instead of going through
    1961             :  * Render.
    1962             :  */
    1963             : static composite_operation_t
    1964           0 : _recategorize_composite_operation (cairo_xlib_surface_t       *dst,
    1965             :                                    cairo_operator_t            op,
    1966             :                                    cairo_xlib_surface_t       *src,
    1967             :                                    cairo_surface_attributes_t *src_attr,
    1968             :                                    cairo_bool_t                have_mask)
    1969             : {
    1970             :     /* Can we use the core protocol? */
    1971           0 :     if (! have_mask &&
    1972           0 :         _surfaces_compatible (src, dst) &&
    1973           0 :         _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
    1974           0 :         ! _operator_needs_alpha_composite (op, _surface_has_alpha (dst)))
    1975             :     {
    1976           0 :         if (src_attr->extend == CAIRO_EXTEND_NONE)
    1977           0 :             return DO_XCOPYAREA;
    1978             : 
    1979           0 :         if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT)
    1980           0 :             return DO_XTILE;
    1981             :     }
    1982             : 
    1983           0 :     if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT &&
    1984           0 :             (src->width != 1 || src->height != 1))
    1985           0 :         return DO_UNSUPPORTED;
    1986             : 
    1987           0 :     if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
    1988           0 :         return DO_UNSUPPORTED;
    1989             : 
    1990           0 :     if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
    1991           0 :         return DO_UNSUPPORTED;
    1992             : 
    1993           0 :     return DO_RENDER;
    1994             : }
    1995             : 
    1996             : static int
    1997           0 : _render_operator (cairo_operator_t op)
    1998             : {
    1999           0 :     switch (op) {
    2000             :     case CAIRO_OPERATOR_CLEAR:
    2001           0 :         return PictOpClear;
    2002             : 
    2003             :     case CAIRO_OPERATOR_SOURCE:
    2004           0 :         return PictOpSrc;
    2005             :     case CAIRO_OPERATOR_OVER:
    2006           0 :         return PictOpOver;
    2007             :     case CAIRO_OPERATOR_IN:
    2008           0 :         return PictOpIn;
    2009             :     case CAIRO_OPERATOR_OUT:
    2010           0 :         return PictOpOut;
    2011             :     case CAIRO_OPERATOR_ATOP:
    2012           0 :         return PictOpAtop;
    2013             : 
    2014             :     case CAIRO_OPERATOR_DEST:
    2015           0 :         return PictOpDst;
    2016             :     case CAIRO_OPERATOR_DEST_OVER:
    2017           0 :         return PictOpOverReverse;
    2018             :     case CAIRO_OPERATOR_DEST_IN:
    2019           0 :         return PictOpInReverse;
    2020             :     case CAIRO_OPERATOR_DEST_OUT:
    2021           0 :         return PictOpOutReverse;
    2022             :     case CAIRO_OPERATOR_DEST_ATOP:
    2023           0 :         return PictOpAtopReverse;
    2024             : 
    2025             :     case CAIRO_OPERATOR_XOR:
    2026           0 :         return PictOpXor;
    2027             :     case CAIRO_OPERATOR_ADD:
    2028           0 :         return PictOpAdd;
    2029             :     case CAIRO_OPERATOR_SATURATE:
    2030           0 :         return PictOpSaturate;
    2031             : 
    2032             :     case CAIRO_OPERATOR_MULTIPLY:
    2033           0 :         return PictOpMultiply;
    2034             :     case CAIRO_OPERATOR_SCREEN:
    2035           0 :         return PictOpScreen;
    2036             :     case CAIRO_OPERATOR_OVERLAY:
    2037           0 :         return PictOpOverlay;
    2038             :     case CAIRO_OPERATOR_DARKEN:
    2039           0 :         return PictOpDarken;
    2040             :     case CAIRO_OPERATOR_LIGHTEN:
    2041           0 :         return PictOpLighten;
    2042             :     case CAIRO_OPERATOR_COLOR_DODGE:
    2043           0 :         return PictOpColorDodge;
    2044             :     case CAIRO_OPERATOR_COLOR_BURN:
    2045           0 :         return PictOpColorBurn;
    2046             :     case CAIRO_OPERATOR_HARD_LIGHT:
    2047           0 :         return PictOpHardLight;
    2048             :     case CAIRO_OPERATOR_SOFT_LIGHT:
    2049           0 :         return PictOpSoftLight;
    2050             :     case CAIRO_OPERATOR_DIFFERENCE:
    2051           0 :         return PictOpDifference;
    2052             :     case CAIRO_OPERATOR_EXCLUSION:
    2053           0 :         return PictOpExclusion;
    2054             :     case CAIRO_OPERATOR_HSL_HUE:
    2055           0 :         return PictOpHSLHue;
    2056             :     case CAIRO_OPERATOR_HSL_SATURATION:
    2057           0 :         return PictOpHSLSaturation;
    2058             :     case CAIRO_OPERATOR_HSL_COLOR:
    2059           0 :         return PictOpHSLColor;
    2060             :     case CAIRO_OPERATOR_HSL_LUMINOSITY:
    2061           0 :         return PictOpHSLLuminosity;
    2062             : 
    2063             :     default:
    2064           0 :         ASSERT_NOT_REACHED;
    2065           0 :         return PictOpOver;
    2066             :     }
    2067             : }
    2068             : 
    2069             : static cairo_int_status_t
    2070           0 : _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
    2071             :                                              cairo_xlib_surface_t *dst,
    2072             :                                              const cairo_pattern_t *pattern,
    2073             :                                              int x, int y,
    2074             :                                              int width, int height,
    2075             :                                              cairo_xlib_surface_t **surface_out,
    2076             :                                              cairo_surface_attributes_t *attributes)
    2077             : {
    2078           0 :     switch (pattern->type) {
    2079             :     case CAIRO_PATTERN_TYPE_LINEAR:
    2080             :     case CAIRO_PATTERN_TYPE_RADIAL:
    2081             :         {
    2082           0 :             cairo_gradient_pattern_t *gradient =
    2083             :                 (cairo_gradient_pattern_t *) pattern;
    2084           0 :             cairo_matrix_t matrix = pattern->matrix;
    2085             :             cairo_xlib_surface_t *surface;
    2086             :             char buf[CAIRO_STACK_BUFFER_SIZE];
    2087             :             XFixed *stops;
    2088             :             XRenderColor *colors;
    2089             :             XRenderPictFormat *format;
    2090             :             Picture picture;
    2091             :             unsigned int i;
    2092             : 
    2093           0 :             if (dst->buggy_gradients)
    2094           0 :                 break;
    2095             : 
    2096           0 :             if (gradient->n_stops < 2) /* becomes a solid */
    2097           0 :                 break;
    2098             : 
    2099           0 :             if (gradient->n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
    2100             :             {
    2101           0 :                 stops = (XFixed *) buf;
    2102             :             }
    2103             :             else
    2104             :             {
    2105           0 :                 stops =
    2106           0 :                     _cairo_malloc_ab (gradient->n_stops,
    2107             :                                       sizeof (XFixed) + sizeof (XRenderColor));
    2108           0 :                 if (unlikely (stops == NULL))
    2109           0 :                     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2110             :             }
    2111             : 
    2112           0 :             colors = (XRenderColor *) (stops + gradient->n_stops);
    2113           0 :             for (i = 0; i < gradient->n_stops; i++) {
    2114           0 :                 stops[i] =
    2115           0 :                     _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
    2116             : 
    2117           0 :                 colors[i].red   = gradient->stops[i].color.red_short;
    2118           0 :                 colors[i].green = gradient->stops[i].color.green_short;
    2119           0 :                 colors[i].blue  = gradient->stops[i].color.blue_short;
    2120           0 :                 colors[i].alpha = gradient->stops[i].color.alpha_short;
    2121             :             }
    2122             : 
    2123             : #if 0
    2124             :             /* For some weird reason the X server is sometimes getting
    2125             :              * CreateGradient requests with bad length. So far I've only seen
    2126             :              * XRenderCreateLinearGradient request with 4 stops sometime end up
    2127             :              * with length field matching 0 stops at the server side. I've
    2128             :              * looked at the libXrender code and I can't see anything that
    2129             :              * could cause this behavior. However, for some reason having a
    2130             :              * XSync call here seems to avoid the issue so I'll keep it here
    2131             :              * until it's solved.
    2132             :              */
    2133             :             XSync (display->display, False);
    2134             : #endif
    2135             : 
    2136           0 :             if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
    2137           0 :                 cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
    2138             :                 XLinearGradient grad;
    2139             : 
    2140             :                 cairo_fixed_t xdim, ydim;
    2141             : 
    2142           0 :                 xdim = linear->p2.x - linear->p1.x;
    2143           0 :                 ydim = linear->p2.y - linear->p1.y;
    2144             : 
    2145             :                 /*
    2146             :                  * Transform the matrix to avoid overflow when converting between
    2147             :                  * cairo_fixed_t and pixman_fixed_t (without incurring performance
    2148             :                  * loss when the transformation is unnecessary).
    2149             :                  *
    2150             :                  * XXX: Consider converting out-of-range co-ordinates and transforms.
    2151             :                  * Having a function to compute the required transformation to
    2152             :                  * "normalize" a given bounding box would be generally useful -
    2153             :                  * cf linear patterns, gradient patterns, surface patterns...
    2154             :                  */
    2155             : #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
    2156           0 :                 if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
    2157           0 :                     _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
    2158           0 :                 {
    2159             :                     double sf;
    2160             : 
    2161           0 :                     if (xdim > ydim)
    2162           0 :                         sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
    2163             :                     else
    2164           0 :                         sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
    2165             : 
    2166           0 :                     grad.p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
    2167           0 :                     grad.p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
    2168           0 :                     grad.p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
    2169           0 :                     grad.p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
    2170             : 
    2171           0 :                     cairo_matrix_scale (&matrix, sf, sf);
    2172             :                 }
    2173             :                 else
    2174             :                 {
    2175           0 :                     grad.p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
    2176           0 :                     grad.p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
    2177           0 :                     grad.p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
    2178           0 :                     grad.p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
    2179             :                 }
    2180             : 
    2181           0 :                 picture = XRenderCreateLinearGradient (display->display, &grad,
    2182             :                                                        stops, colors,
    2183           0 :                                                        gradient->n_stops);
    2184             :             } else {
    2185           0 :                 cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
    2186             :                 XRadialGradient grad;
    2187             : 
    2188           0 :                 grad.inner.x = _cairo_fixed_to_16_16 (radial->c1.x);
    2189           0 :                 grad.inner.y = _cairo_fixed_to_16_16 (radial->c1.y);
    2190           0 :                 grad.inner.radius = _cairo_fixed_to_16_16 (radial->r1);
    2191             : 
    2192           0 :                 grad.outer.x = _cairo_fixed_to_16_16 (radial->c2.x);
    2193           0 :                 grad.outer.y = _cairo_fixed_to_16_16 (radial->c2.y);
    2194           0 :                 grad.outer.radius = _cairo_fixed_to_16_16 (radial->r2);
    2195             : 
    2196           0 :                 picture = XRenderCreateRadialGradient (display->display, &grad,
    2197             :                                                        stops, colors,
    2198           0 :                                                        gradient->n_stops);
    2199             : 
    2200             :             }
    2201             : 
    2202           0 :             if (stops != (XFixed *) buf)
    2203           0 :                 free (stops);
    2204             : 
    2205           0 :             if (unlikely (picture == None))
    2206           0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2207             : 
    2208             :             /* Wrap the remote Picture in an xlib surface. */
    2209           0 :             format = _cairo_xlib_display_get_xrender_format (display,
    2210             :                                                              CAIRO_FORMAT_ARGB32);
    2211             : 
    2212           0 :             surface = (cairo_xlib_surface_t *)
    2213           0 :                 _cairo_xlib_surface_create_internal (dst->screen, None,
    2214             :                                                      NULL, format,
    2215             :                                                      /* what could possibly go wrong? */
    2216             :                                                      XLIB_COORD_MAX, XLIB_COORD_MAX, 32);
    2217           0 :             if (unlikely (surface->base.status)) {
    2218           0 :                 XRenderFreePicture (display->display, picture);
    2219           0 :                 return surface->base.status;
    2220             :             }
    2221             : 
    2222           0 :             surface->src_picture = picture;
    2223             : 
    2224           0 :             attributes->matrix   = matrix;
    2225           0 :             attributes->extend   = pattern->extend;
    2226           0 :             attributes->filter   = CAIRO_FILTER_NEAREST;
    2227           0 :             attributes->x_offset = 0;
    2228           0 :             attributes->y_offset = 0;
    2229           0 :             attributes->has_component_alpha = FALSE;
    2230             : 
    2231           0 :             *surface_out = surface;
    2232           0 :             return CAIRO_STATUS_SUCCESS;
    2233             :         }
    2234             :     default:
    2235           0 :         ASSERT_NOT_REACHED;
    2236             :     case CAIRO_PATTERN_TYPE_SOLID:
    2237             :     case CAIRO_PATTERN_TYPE_SURFACE:
    2238           0 :         break;
    2239             :     }
    2240             : 
    2241           0 :     return _cairo_pattern_acquire_surface (pattern, &dst->base,
    2242             :                                            x, y, width, height,
    2243           0 :                                            dst->buggy_pad_reflect ?
    2244             :                                            CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
    2245             :                                            CAIRO_PATTERN_ACQUIRE_NONE,
    2246             :                                            (cairo_surface_t **) surface_out,
    2247             :                                            attributes);
    2248             : }
    2249             : 
    2250             : static cairo_int_status_t
    2251           0 : _cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_display_t       *display,
    2252             :                                               cairo_xlib_surface_t       *dst,
    2253             :                                               const cairo_pattern_t      *src,
    2254             :                                               const cairo_pattern_t      *mask,
    2255             :                                               int                        src_x,
    2256             :                                               int                        src_y,
    2257             :                                               int                        mask_x,
    2258             :                                               int                        mask_y,
    2259             :                                               unsigned int               width,
    2260             :                                               unsigned int               height,
    2261             :                                               cairo_xlib_surface_t       **src_out,
    2262             :                                               cairo_xlib_surface_t       **mask_out,
    2263             :                                               cairo_surface_attributes_t *src_attr,
    2264             :                                               cairo_surface_attributes_t *mask_attr)
    2265             : {
    2266           0 :     if (! dst->buggy_gradients &&
    2267           0 :         (src->type == CAIRO_PATTERN_TYPE_LINEAR               ||
    2268           0 :          src->type == CAIRO_PATTERN_TYPE_RADIAL               ||
    2269           0 :          (mask && (mask->type == CAIRO_PATTERN_TYPE_LINEAR ||
    2270           0 :                    mask->type == CAIRO_PATTERN_TYPE_RADIAL))))
    2271             :     {
    2272             :         cairo_int_status_t status;
    2273             : 
    2274           0 :         status = _cairo_xlib_surface_acquire_pattern_surface (display,
    2275             :                                                               dst, src,
    2276             :                                                               src_x, src_y,
    2277             :                                                               width, height,
    2278             :                                                               src_out,
    2279             :                                                               src_attr);
    2280           0 :         if (unlikely (status))
    2281           0 :             return status;
    2282             : 
    2283           0 :         if (mask) {
    2284           0 :             status = _cairo_xlib_surface_acquire_pattern_surface (display,
    2285             :                                                                   dst, mask,
    2286             :                                                                   mask_x,
    2287             :                                                                   mask_y,
    2288             :                                                                   width,
    2289             :                                                                   height,
    2290             :                                                                   mask_out,
    2291             :                                                                   mask_attr);
    2292           0 :             if (unlikely (status)) {
    2293           0 :                 _cairo_pattern_release_surface (src, &(*src_out)->base,
    2294             :                                                 src_attr);
    2295           0 :                 return status;
    2296             :             }
    2297             :         } else {
    2298           0 :             *mask_out = NULL;
    2299             :         }
    2300             : 
    2301           0 :         return CAIRO_STATUS_SUCCESS;
    2302             :     }
    2303             : 
    2304           0 :     return _cairo_pattern_acquire_surfaces (src, mask,
    2305             :                                             &dst->base,
    2306             :                                             src_x, src_y,
    2307             :                                             mask_x, mask_y,
    2308             :                                             width, height,
    2309           0 :                                             dst->buggy_pad_reflect ?
    2310             :                                             CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
    2311             :                                             CAIRO_PATTERN_ACQUIRE_NONE,
    2312             :                                             (cairo_surface_t **) src_out,
    2313             :                                             (cairo_surface_t **) mask_out,
    2314             :                                             src_attr, mask_attr);
    2315             : }
    2316             : 
    2317             : static cairo_int_status_t
    2318           0 : _cairo_xlib_surface_upload(cairo_xlib_surface_t *surface,
    2319             :                            cairo_operator_t op,
    2320             :                            const cairo_pattern_t *pattern,
    2321             :                            int src_x, int src_y,
    2322             :                            int dst_x, int dst_y,
    2323             :                            unsigned int width,
    2324             :                            unsigned int height,
    2325             :                            cairo_region_t *clip_region)
    2326             : {
    2327             :     cairo_image_surface_t *image;
    2328             :     cairo_rectangle_int_t extents;
    2329             :     cairo_status_t status;
    2330             :     int tx, ty;
    2331             : 
    2332           0 :     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
    2333           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2334             : 
    2335           0 :     image = (cairo_image_surface_t *) ((cairo_surface_pattern_t *) pattern)->surface;
    2336           0 :     if (image->base.type != CAIRO_SURFACE_TYPE_IMAGE)
    2337           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2338             : 
    2339           0 :     if (! (op == CAIRO_OPERATOR_SOURCE ||
    2340           0 :            (op == CAIRO_OPERATOR_OVER &&
    2341           0 :             (image->base.content & CAIRO_CONTENT_ALPHA) == 0)))
    2342           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2343             : 
    2344           0 :     if (image->base.backend->type != CAIRO_SURFACE_TYPE_IMAGE) {
    2345           0 :         if (image->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
    2346           0 :             image = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) image)->target;
    2347           0 :             extents.x = extents.y = 0;
    2348           0 :             extents.width = image->width;
    2349           0 :             extents.height = image->height;
    2350           0 :         } else if (image->base.backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
    2351           0 :             cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) image;
    2352           0 :             image = (cairo_image_surface_t *) sub->target;
    2353           0 :             src_x += sub->extents.x;
    2354           0 :             src_y += sub->extents.y;
    2355           0 :             extents = sub->extents;
    2356             :         } else {
    2357           0 :             return CAIRO_INT_STATUS_UNSUPPORTED;
    2358             :         }
    2359             :     } else {
    2360           0 :         extents.x = extents.y = 0;
    2361           0 :         extents.width = image->width;
    2362           0 :         extents.height = image->height;
    2363             :     }
    2364             : 
    2365           0 :     if (image->format == CAIRO_FORMAT_INVALID)
    2366           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2367           0 :     if (image->depth != surface->depth)
    2368           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2369             : 
    2370           0 :     if (! _cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty))
    2371           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2372             : 
    2373           0 :     src_x += tx;
    2374           0 :     src_y += ty;
    2375             : 
    2376             :     /* XXX for EXTEND_NONE perform unbounded fixups? */
    2377           0 :     if (src_x < extents.x ||
    2378           0 :         src_y < extents.y ||
    2379           0 :         src_x + width  > (unsigned) extents.width ||
    2380           0 :         src_y + height > (unsigned) extents.height)
    2381             :     {
    2382           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2383             :     }
    2384             : 
    2385           0 :     status = cairo_device_acquire (surface->base.device);
    2386           0 :     if (unlikely (status))
    2387           0 :         return status;
    2388             : 
    2389           0 :     if (clip_region != NULL) {
    2390             :         int n, num_rect;
    2391             : 
    2392           0 :         src_x -= dst_x;
    2393           0 :         src_y -= dst_y;
    2394             : 
    2395           0 :         num_rect = cairo_region_num_rectangles (clip_region);
    2396           0 :         for (n = 0; n < num_rect; n++) {
    2397             :             cairo_rectangle_int_t rect;
    2398             : 
    2399           0 :             cairo_region_get_rectangle (clip_region, n, &rect);
    2400           0 :             status = _draw_image_surface (surface, image,
    2401           0 :                                           rect.x + src_x, rect.y + src_y,
    2402             :                                           rect.width, rect.height,
    2403             :                                           rect.x, rect.y);
    2404           0 :             if (unlikely (status))
    2405           0 :                 break;
    2406             :         }
    2407             :     } else {
    2408           0 :         status = _draw_image_surface (surface, image,
    2409             :                                       src_x, src_y,
    2410             :                                       width, height,
    2411             :                                       dst_x, dst_y);
    2412             :     }
    2413             : 
    2414           0 :     cairo_device_release (surface->base.device);
    2415             : 
    2416           0 :     return status;
    2417             : }
    2418             : 
    2419             : static cairo_int_status_t
    2420           0 : _cairo_xlib_surface_composite (cairo_operator_t         op,
    2421             :                                const cairo_pattern_t    *src_pattern,
    2422             :                                const cairo_pattern_t    *mask_pattern,
    2423             :                                void                     *abstract_dst,
    2424             :                                int                      src_x,
    2425             :                                int                      src_y,
    2426             :                                int                      mask_x,
    2427             :                                int                      mask_y,
    2428             :                                int                      dst_x,
    2429             :                                int                      dst_y,
    2430             :                                unsigned int             width,
    2431             :                                unsigned int             height,
    2432             :                                cairo_region_t           *clip_region)
    2433             : {
    2434             :     cairo_surface_attributes_t  src_attr, mask_attr;
    2435           0 :     cairo_xlib_surface_t        *dst = abstract_dst;
    2436             :     cairo_xlib_surface_t        *src;
    2437             :     cairo_xlib_surface_t        *mask;
    2438             :     cairo_xlib_display_t        *display;
    2439             :     cairo_int_status_t          status;
    2440             :     composite_operation_t       operation;
    2441             :     int                         itx, ity;
    2442             :     cairo_bool_t                is_integer_translation;
    2443             :     GC                          gc;
    2444             : 
    2445           0 :     if (mask_pattern != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
    2446           0 :         return UNSUPPORTED ("no support for masks");
    2447             : 
    2448           0 :     operation = _categorize_composite_operation (dst, op, src_pattern,
    2449             :                                                  mask_pattern != NULL);
    2450           0 :     if (operation == DO_UNSUPPORTED)
    2451           0 :         return UNSUPPORTED ("unsupported operation");
    2452             : 
    2453             :     X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
    2454             : 
    2455           0 :     if (mask_pattern == NULL) {
    2456             :         /* Can we do a simple upload in-place? */
    2457           0 :         status = _cairo_xlib_surface_upload(dst, op, src_pattern,
    2458             :                                             src_x, src_y,
    2459             :                                             dst_x, dst_y,
    2460             :                                             width, height,
    2461             :                                             clip_region);
    2462           0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    2463           0 :             return status;
    2464             :     }
    2465             : 
    2466           0 :     status = _cairo_xlib_display_acquire (dst-> base.device, &display);
    2467           0 :     if (unlikely (status))
    2468           0 :         return status;
    2469             : 
    2470           0 :     status =
    2471           0 :         _cairo_xlib_surface_acquire_pattern_surfaces (display, dst,
    2472             :                                                       src_pattern, mask_pattern,
    2473             :                                                       src_x, src_y,
    2474             :                                                       mask_x, mask_y,
    2475             :                                                       width, height,
    2476             :                                                       &src, &mask,
    2477             :                                                       &src_attr, &mask_attr);
    2478           0 :     if (unlikely (status))
    2479           0 :         goto BAIL0;
    2480             : 
    2481             :     /* check for fallback surfaces that we cannot handle ... */
    2482           0 :     assert (_cairo_surface_is_xlib (&src->base));
    2483           0 :     assert (mask == NULL || _cairo_surface_is_xlib (&mask->base));
    2484             : 
    2485           0 :     if (mask != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (mask)) {
    2486           0 :         status = UNSUPPORTED ("unsupported mask");
    2487           0 :         goto BAIL;
    2488             :     }
    2489             : 
    2490           0 :     operation = _recategorize_composite_operation (dst, op, src, &src_attr,
    2491             :                                                    mask_pattern != NULL);
    2492           0 :     if (operation == DO_UNSUPPORTED) {
    2493           0 :         status = UNSUPPORTED ("unsupported operation");
    2494           0 :         goto BAIL;
    2495             :     }
    2496             : 
    2497           0 :     switch (operation)
    2498             :     {
    2499             :     case DO_RENDER:
    2500           0 :         status = _cairo_xlib_surface_set_attributes (display,
    2501             :                                                      src, &src_attr,
    2502           0 :                                                      dst_x + width / 2.,
    2503           0 :                                                      dst_y + height / 2.);
    2504           0 :         if (unlikely (status))
    2505           0 :             goto BAIL;
    2506             : 
    2507           0 :         status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
    2508           0 :         if (unlikely (status))
    2509           0 :             goto BAIL;
    2510             : 
    2511           0 :         _cairo_xlib_surface_ensure_dst_picture (display, dst);
    2512           0 :         if (mask) {
    2513           0 :             status = _cairo_xlib_surface_set_attributes (display,
    2514             :                                                          mask, &mask_attr,
    2515           0 :                                                          dst_x + width / 2.,
    2516           0 :                                                          dst_y + height/ 2.);
    2517           0 :             if (unlikely (status))
    2518           0 :                 goto BAIL;
    2519             : 
    2520           0 :             XRenderComposite (display->display,
    2521             :                               _render_operator (op),
    2522           0 :                               src->src_picture,
    2523           0 :                               mask->src_picture,
    2524             :                               dst->dst_picture,
    2525           0 :                               src_x + src_attr.x_offset,
    2526           0 :                               src_y + src_attr.y_offset,
    2527           0 :                               mask_x + mask_attr.x_offset,
    2528           0 :                               mask_y + mask_attr.y_offset,
    2529             :                               dst_x, dst_y,
    2530             :                               width, height);
    2531             :         } else {
    2532           0 :             XRenderComposite (display->display,
    2533             :                               _render_operator (op),
    2534           0 :                               src->src_picture,
    2535             :                               0,
    2536             :                               dst->dst_picture,
    2537           0 :                               src_x + src_attr.x_offset,
    2538           0 :                               src_y + src_attr.y_offset,
    2539             :                               0, 0,
    2540             :                               dst_x, dst_y,
    2541             :                               width, height);
    2542             :         }
    2543             : 
    2544           0 :         break;
    2545             : 
    2546             :     case DO_XCOPYAREA:
    2547           0 :         status = _cairo_xlib_surface_get_gc (display, dst, &gc);
    2548           0 :         if (unlikely (status))
    2549           0 :             goto BAIL;
    2550             : 
    2551           0 :         is_integer_translation =
    2552             :             _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
    2553             :         /* This is a pre-condition for DO_XCOPYAREA. */
    2554           0 :         assert (is_integer_translation);
    2555             : 
    2556           0 :         if (clip_region == NULL) {
    2557           0 :             XCopyArea (display->display, src->drawable, dst->drawable, gc,
    2558           0 :                        src_x + src_attr.x_offset + itx,
    2559           0 :                        src_y + src_attr.y_offset + ity,
    2560             :                        width, height,
    2561             :                        dst_x, dst_y);
    2562             :         } else {
    2563             :             int n, num_rects, x, y;
    2564             : 
    2565           0 :             x = src_x + src_attr.x_offset + itx - dst_x;
    2566           0 :             y = src_y + src_attr.y_offset + ity - dst_y;
    2567             : 
    2568           0 :             num_rects = cairo_region_num_rectangles (clip_region);
    2569           0 :             for (n = 0; n < num_rects; n++) {
    2570             :                 cairo_rectangle_int_t rect;
    2571             : 
    2572           0 :                 cairo_region_get_rectangle (clip_region, n, &rect);
    2573           0 :                 XCopyArea (display->display, src->drawable, dst->drawable, gc,
    2574           0 :                            rect.x + x, rect.y + y,
    2575           0 :                            rect.width, rect.height,
    2576             :                            rect.x, rect.y);
    2577             :             }
    2578             :         }
    2579             : 
    2580           0 :         _cairo_xlib_surface_put_gc (display, dst, gc);
    2581           0 :         break;
    2582             : 
    2583             :     case DO_XTILE:
    2584             :         /* This case is only used for bug fallbacks, though we also use it for
    2585             :          * the case where we don't have the RENDER extension, by forcing
    2586             :          * buggy_repeat to TRUE.
    2587             :          *
    2588             :          * We've checked that we have a repeating unscaled source in
    2589             :          * _recategorize_composite_operation.
    2590             :          */
    2591             : 
    2592           0 :         status = _cairo_xlib_surface_get_gc (display, dst, &gc);
    2593           0 :         if (unlikely (status))
    2594           0 :             goto BAIL;
    2595             : 
    2596           0 :         is_integer_translation =
    2597             :             _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
    2598             :         /* This is a pre-condition for DO_XTILE. */
    2599           0 :         assert (is_integer_translation);
    2600             : 
    2601           0 :         XSetTSOrigin (display->display, gc,
    2602           0 :                       - (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
    2603           0 :         XSetTile (display->display, gc, src->drawable);
    2604             : 
    2605           0 :         if (clip_region == NULL) {
    2606           0 :             XFillRectangle (display->display, dst->drawable, gc,
    2607             :                             dst_x, dst_y, width, height);
    2608             :         } else {
    2609             :             int n, num_rects;
    2610             : 
    2611           0 :             num_rects = cairo_region_num_rectangles (clip_region);
    2612           0 :             for (n = 0; n < num_rects; n++) {
    2613             :                 cairo_rectangle_int_t rect;
    2614             : 
    2615           0 :                 cairo_region_get_rectangle (clip_region, n, &rect);
    2616           0 :                 XFillRectangle (display->display, dst->drawable, gc,
    2617           0 :                                 rect.x, rect.y, rect.width, rect.height);
    2618             :             }
    2619             :         }
    2620             : 
    2621           0 :         _cairo_xlib_surface_put_gc (display, dst, gc);
    2622           0 :         break;
    2623             : 
    2624             :     case DO_UNSUPPORTED:
    2625             :     default:
    2626           0 :         ASSERT_NOT_REACHED;
    2627             :     }
    2628             : 
    2629           0 :     if (!_cairo_operator_bounded_by_source (op))
    2630           0 :       status = _cairo_surface_composite_fixup_unbounded (&dst->base,
    2631           0 :                                                          &src_attr, src->width, src->height,
    2632           0 :                                                          mask ? &mask_attr : NULL,
    2633           0 :                                                          mask ? mask->width : 0,
    2634           0 :                                                          mask ? mask->height : 0,
    2635             :                                                          src_x, src_y,
    2636             :                                                          mask_x, mask_y,
    2637             :                                                          dst_x, dst_y, width, height,
    2638             :                                                          clip_region);
    2639             : 
    2640             :  BAIL:
    2641           0 :     if (mask)
    2642           0 :         _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
    2643             : 
    2644           0 :     _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
    2645             : 
    2646             :  BAIL0:
    2647           0 :     cairo_device_release (&display->base);
    2648             : 
    2649           0 :     return status;
    2650             : }
    2651             : 
    2652             : /* XXX move this out of core and into acquire_pattern_surface() above. */
    2653             : static cairo_int_status_t
    2654           0 : _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
    2655             :                                            const cairo_color_t     *color,
    2656             :                                            cairo_rectangle_int_t   *rects,
    2657             :                                            int                     num_rects)
    2658             : {
    2659             :     cairo_status_t status;
    2660             :     cairo_solid_pattern_t solid;
    2661           0 :     cairo_surface_t *solid_surface = NULL;
    2662             :     cairo_surface_attributes_t attrs;
    2663             :     cairo_xlib_display_t *display;
    2664             :     GC gc;
    2665             :     int i;
    2666             : 
    2667           0 :     _cairo_pattern_init_solid (&solid, color);
    2668             : 
    2669           0 :     status = _cairo_xlib_display_acquire (surface->base.device, &display);
    2670           0 :     if (unlikely (status))
    2671           0 :         return status;
    2672             : 
    2673           0 :     status = _cairo_xlib_surface_get_gc (display, surface, &gc);
    2674           0 :     if (unlikely (status))
    2675           0 :         return status;
    2676             : 
    2677             :     X_DEBUG ((display->display, "solid_fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
    2678             : 
    2679           0 :     status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
    2680             :                                              0, 0,
    2681             :                                              ARRAY_LENGTH (dither_pattern[0]),
    2682             :                                              ARRAY_LENGTH (dither_pattern),
    2683             :                                              CAIRO_PATTERN_ACQUIRE_NONE,
    2684             :                                              &solid_surface,
    2685             :                                              &attrs);
    2686           0 :     if (unlikely (status)) {
    2687           0 :         _cairo_xlib_surface_put_gc (display, surface, gc);
    2688           0 :         cairo_device_release (&display->base);
    2689           0 :         return status;
    2690             :     }
    2691             : 
    2692           0 :     assert (_cairo_surface_is_xlib (solid_surface));
    2693             : 
    2694           0 :     XSetTSOrigin (display->display, gc,
    2695           0 :                   - (surface->base.device_transform.x0 + attrs.x_offset),
    2696           0 :                   - (surface->base.device_transform.y0 + attrs.y_offset));
    2697           0 :     XSetTile (display->display, gc,
    2698           0 :               ((cairo_xlib_surface_t *) solid_surface)->drawable);
    2699             : 
    2700           0 :     for (i = 0; i < num_rects; i++) {
    2701           0 :         XFillRectangle (display->display, surface->drawable, gc,
    2702           0 :                         rects[i].x, rects[i].y,
    2703           0 :                         rects[i].width, rects[i].height);
    2704             :     }
    2705             : 
    2706           0 :     _cairo_xlib_surface_put_gc (display, surface, gc);
    2707             : 
    2708           0 :     _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs);
    2709             :     
    2710           0 :     cairo_device_release (&display->base);
    2711             : 
    2712           0 :     return CAIRO_STATUS_SUCCESS;
    2713             : }
    2714             : 
    2715             : static cairo_int_status_t
    2716           0 : _cairo_xlib_surface_fill_rectangles (void                    *abstract_surface,
    2717             :                                      cairo_operator_t         op,
    2718             :                                      const cairo_color_t     *color,
    2719             :                                      cairo_rectangle_int_t   *rects,
    2720             :                                      int                      num_rects)
    2721             : {
    2722           0 :     cairo_xlib_surface_t *surface = abstract_surface;
    2723             :     cairo_xlib_display_t *display;
    2724             :     XRenderColor render_color;
    2725             :     cairo_status_t status;
    2726             :     int i;
    2727             : 
    2728           0 :     if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (surface, op))
    2729           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    2730             : 
    2731           0 :     if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
    2732           0 :         if (op == CAIRO_OPERATOR_CLEAR ||
    2733           0 :             ((op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER) &&
    2734           0 :              CAIRO_COLOR_IS_OPAQUE (color)))
    2735             :         {
    2736           0 :             return _cairo_xlib_surface_solid_fill_rectangles (surface, color,
    2737             :                                                               rects, num_rects);
    2738             :         }
    2739             : 
    2740           0 :         return UNSUPPORTED ("no support for FillRectangles with this op");
    2741             :     }
    2742             : 
    2743           0 :     status = _cairo_xlib_display_acquire (surface->base.device, &display);
    2744           0 :     if (unlikely (status))
    2745           0 :         return status;
    2746             : 
    2747             :     X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
    2748             : 
    2749           0 :     render_color.red   = color->red_short;
    2750           0 :     render_color.green = color->green_short;
    2751           0 :     render_color.blue  = color->blue_short;
    2752           0 :     render_color.alpha = color->alpha_short;
    2753             : 
    2754           0 :     status = _cairo_xlib_surface_set_clip_region (surface, NULL);
    2755           0 :     assert (status == CAIRO_STATUS_SUCCESS);
    2756             : 
    2757           0 :     _cairo_xlib_surface_ensure_dst_picture (display, surface);
    2758           0 :     if (num_rects == 1) {
    2759             :         /* Take advantage of the protocol compaction that libXrender performs
    2760             :          * to amalgamate sequences of XRenderFillRectangle().
    2761             :          */
    2762           0 :         XRenderFillRectangle (display->display,
    2763             :                               _render_operator (op),
    2764             :                               surface->dst_picture,
    2765             :                               &render_color,
    2766             :                               rects->x,
    2767             :                               rects->y,
    2768           0 :                               rects->width,
    2769           0 :                               rects->height);
    2770             :     } else {
    2771             :         XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
    2772           0 :         XRectangle *xrects = static_xrects;
    2773             : 
    2774           0 :         if (num_rects > ARRAY_LENGTH (static_xrects)) {
    2775           0 :             xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
    2776           0 :             if (unlikely (xrects == NULL)) {
    2777           0 :                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2778           0 :                 goto BAIL;
    2779             :             }
    2780             :         }
    2781             : 
    2782           0 :         for (i = 0; i < num_rects; i++) {
    2783           0 :             xrects[i].x = rects[i].x;
    2784           0 :             xrects[i].y = rects[i].y;
    2785           0 :             xrects[i].width = rects[i].width;
    2786           0 :             xrects[i].height = rects[i].height;
    2787             :         }
    2788             : 
    2789           0 :         XRenderFillRectangles (display->display,
    2790             :                                _render_operator (op),
    2791             :                                surface->dst_picture,
    2792             :                                &render_color, xrects, num_rects);
    2793             : 
    2794           0 :         if (xrects != static_xrects)
    2795           0 :             free (xrects);
    2796             :     }
    2797             : 
    2798             : BAIL:
    2799           0 :     cairo_device_release (&display->base);
    2800           0 :     return status;
    2801             : }
    2802             : 
    2803             : #define CAIRO_FIXED_16_16_MIN -32768
    2804             : #define CAIRO_FIXED_16_16_MAX 32767
    2805             : 
    2806             : static cairo_bool_t
    2807           0 : _line_exceeds_16_16 (const cairo_line_t *line)
    2808             : {
    2809             :     return
    2810           0 :         line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
    2811           0 :         line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
    2812           0 :         line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
    2813           0 :         line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
    2814           0 :         line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
    2815           0 :         line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
    2816           0 :         line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
    2817           0 :         line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX);
    2818             : }
    2819             : 
    2820             : static void
    2821           0 : _project_line_x_onto_16_16 (const cairo_line_t *line,
    2822             :                             cairo_fixed_t top,
    2823             :                             cairo_fixed_t bottom,
    2824             :                             XLineFixed *out)
    2825             : {
    2826             :     cairo_point_double_t p1, p2;
    2827             :     double m;
    2828             : 
    2829           0 :     p1.x = _cairo_fixed_to_double (line->p1.x);
    2830           0 :     p1.y = _cairo_fixed_to_double (line->p1.y);
    2831             : 
    2832           0 :     p2.x = _cairo_fixed_to_double (line->p2.x);
    2833           0 :     p2.y = _cairo_fixed_to_double (line->p2.y);
    2834             : 
    2835           0 :     m = (p2.x - p1.x) / (p2.y - p1.y);
    2836           0 :     out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
    2837           0 :     out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
    2838           0 : }
    2839             : 
    2840             : static cairo_int_status_t
    2841           0 : _cairo_xlib_surface_composite_trapezoids (cairo_operator_t      op,
    2842             :                                           const cairo_pattern_t *pattern,
    2843             :                                           void                  *abstract_dst,
    2844             :                                           cairo_antialias_t     antialias,
    2845             :                                           int                   src_x,
    2846             :                                           int                   src_y,
    2847             :                                           int                   dst_x,
    2848             :                                           int                   dst_y,
    2849             :                                           unsigned int          width,
    2850             :                                           unsigned int          height,
    2851             :                                           cairo_trapezoid_t     *traps,
    2852             :                                           int                   num_traps,
    2853             :                                           cairo_region_t        *clip_region)
    2854             : {
    2855             :     cairo_surface_attributes_t  attributes;
    2856           0 :     cairo_xlib_surface_t        *dst = abstract_dst;
    2857             :     cairo_xlib_surface_t        *src;
    2858             :     cairo_xlib_display_t        *display;
    2859             :     cairo_int_status_t          status;
    2860             :     composite_operation_t       operation;
    2861             :     int                         render_reference_x, render_reference_y;
    2862             :     int                         render_src_x, render_src_y;
    2863             :     XRenderPictFormat           *pict_format;
    2864             :     XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
    2865           0 :     XTrapezoid *xtraps = xtraps_stack;
    2866             :     int i;
    2867             : 
    2868           0 :     if (! CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
    2869           0 :         return UNSUPPORTED ("XRender does not support CompositeTrapezoids");
    2870             : 
    2871           0 :     operation = _categorize_composite_operation (dst, op, pattern, TRUE);
    2872           0 :     if (operation == DO_UNSUPPORTED)
    2873           0 :         return UNSUPPORTED ("unsupported operation");
    2874             : 
    2875           0 :     status = _cairo_xlib_display_acquire (dst->base.device, &display);
    2876           0 :     if (unlikely (status))
    2877           0 :         return status;
    2878             : 
    2879             :     X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
    2880             : 
    2881           0 :     status = _cairo_xlib_surface_acquire_pattern_surface (display,
    2882             :                                                           dst,
    2883             :                                                           pattern,
    2884             :                                                           src_x, src_y,
    2885             :                                                           width, height,
    2886             :                                                           &src, &attributes);
    2887           0 :     if (unlikely (status))
    2888           0 :         goto BAIL0;
    2889             : 
    2890           0 :     operation = _recategorize_composite_operation (dst, op, src,
    2891             :                                                    &attributes, TRUE);
    2892           0 :     if (operation == DO_UNSUPPORTED) {
    2893           0 :         status = UNSUPPORTED ("unsupported operation");
    2894           0 :         goto BAIL;
    2895             :     }
    2896             : 
    2897           0 :     switch (antialias) {
    2898             :     case CAIRO_ANTIALIAS_NONE:
    2899           0 :         pict_format =
    2900           0 :             _cairo_xlib_display_get_xrender_format (display,
    2901             :                                                     CAIRO_FORMAT_A1);
    2902           0 :         break;
    2903             :     case CAIRO_ANTIALIAS_GRAY:
    2904             :     case CAIRO_ANTIALIAS_SUBPIXEL:
    2905             :     case CAIRO_ANTIALIAS_DEFAULT:
    2906             :     default:
    2907           0 :         pict_format =
    2908           0 :             _cairo_xlib_display_get_xrender_format (display,
    2909             :                                                     CAIRO_FORMAT_A8);
    2910           0 :         break;
    2911             :     }
    2912             : 
    2913           0 :     status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
    2914           0 :     if (unlikely (status))
    2915           0 :         goto BAIL;
    2916             : 
    2917           0 :     _cairo_xlib_surface_ensure_dst_picture (display, dst);
    2918           0 :     _cairo_xlib_surface_set_precision (display, dst, antialias);
    2919             : 
    2920           0 :     status = _cairo_xlib_surface_set_attributes (display,
    2921             :                                                  src, &attributes,
    2922           0 :                                                  dst_x + width / 2.,
    2923           0 :                                                  dst_y + height / 2.);
    2924           0 :     if (unlikely (status))
    2925           0 :         goto BAIL;
    2926             : 
    2927           0 :     if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
    2928           0 :         xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
    2929           0 :         if (unlikely (xtraps == NULL)) {
    2930           0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    2931           0 :             goto BAIL;
    2932             :         }
    2933             :     }
    2934             : 
    2935           0 :     for (i = 0; i < num_traps; i++) {
    2936             :         /* top/bottom will be clamped to surface bounds */
    2937           0 :         xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
    2938           0 :         xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
    2939             : 
    2940             :         /* However, all the other coordinates will have been left untouched so
    2941             :          * as not to introduce numerical error. Recompute them if they
    2942             :          * exceed the 16.16 limits.
    2943             :          */
    2944           0 :         if (unlikely (_line_exceeds_16_16 (&traps[i].left))) {
    2945           0 :             _project_line_x_onto_16_16 (&traps[i].left,
    2946           0 :                                         traps[i].top,
    2947           0 :                                         traps[i].bottom,
    2948           0 :                                         &xtraps[i].left);
    2949           0 :             xtraps[i].left.p1.y = xtraps[i].top;
    2950           0 :             xtraps[i].left.p2.y = xtraps[i].bottom;
    2951             :         } else {
    2952           0 :             xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
    2953           0 :             xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
    2954           0 :             xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
    2955           0 :             xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
    2956             :         }
    2957             : 
    2958           0 :         if (unlikely (_line_exceeds_16_16 (&traps[i].right))) {
    2959           0 :             _project_line_x_onto_16_16 (&traps[i].right,
    2960           0 :                                         traps[i].top,
    2961           0 :                                         traps[i].bottom,
    2962           0 :                                         &xtraps[i].right);
    2963           0 :             xtraps[i].right.p1.y = xtraps[i].top;
    2964           0 :             xtraps[i].right.p2.y = xtraps[i].bottom;
    2965             :         } else {
    2966           0 :             xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
    2967           0 :             xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
    2968           0 :             xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
    2969           0 :             xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
    2970             :         }
    2971             :     }
    2972             : 
    2973           0 :     if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
    2974           0 :         render_reference_x = _cairo_fixed_16_16_floor (xtraps[0].left.p1.x);
    2975           0 :         render_reference_y = _cairo_fixed_16_16_floor (xtraps[0].left.p1.y);
    2976             :     } else {
    2977           0 :         render_reference_x = _cairo_fixed_16_16_floor (xtraps[0].left.p2.x);
    2978           0 :         render_reference_y = _cairo_fixed_16_16_floor (xtraps[0].left.p2.y);
    2979             :     }
    2980             : 
    2981           0 :     render_src_x = src_x + render_reference_x - dst_x;
    2982           0 :     render_src_y = src_y + render_reference_y - dst_y;
    2983             : 
    2984           0 :     XRenderCompositeTrapezoids (display->display,
    2985             :                                 _render_operator (op),
    2986           0 :                                 src->src_picture, dst->dst_picture,
    2987             :                                 pict_format,
    2988           0 :                                 render_src_x + attributes.x_offset,
    2989           0 :                                 render_src_y + attributes.y_offset,
    2990             :                                 xtraps, num_traps);
    2991             : 
    2992           0 :     if (xtraps != xtraps_stack)
    2993           0 :         free (xtraps);
    2994             : 
    2995           0 :     if (! _cairo_operator_bounded_by_mask (op)) {
    2996             :         cairo_traps_t _traps;
    2997             :         cairo_box_t box;
    2998             :         cairo_rectangle_int_t extents;
    2999             : 
    3000             :         /* XRenderCompositeTrapezoids() creates a mask only large enough for the
    3001             :          * trapezoids themselves, but if the operator is unbounded, then we need
    3002             :          * to actually composite all the way out to the bounds.
    3003             :          */
    3004             :         /* XXX: update the interface to pass composite rects */
    3005           0 :         _traps.traps = traps;
    3006           0 :         _traps.num_traps = num_traps;
    3007           0 :         _cairo_traps_extents (&_traps, &box);
    3008           0 :         _cairo_box_round_to_rectangle (&box, &extents);
    3009             : 
    3010           0 :         status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
    3011             :                                                                  &attributes,
    3012           0 :                                                                  src->width, src->height,
    3013             :                                                                  extents.width, extents.height,
    3014             :                                                                  src_x, src_y,
    3015           0 :                                                                  -extents.x + dst_x, -extents.y + dst_y,
    3016             :                                                                  dst_x, dst_y,
    3017             :                                                                  width, height,
    3018             :                                                                  clip_region);
    3019             :     }
    3020             : 
    3021             :  BAIL:
    3022           0 :     _cairo_pattern_release_surface (pattern, &src->base, &attributes);
    3023             :  BAIL0:
    3024           0 :     cairo_device_release (&display->base);
    3025             : 
    3026           0 :     return status;
    3027             : }
    3028             : 
    3029             : static cairo_bool_t
    3030           0 : _cairo_xlib_surface_get_extents (void                    *abstract_surface,
    3031             :                                  cairo_rectangle_int_t   *rectangle)
    3032             : {
    3033           0 :     cairo_xlib_surface_t *surface = abstract_surface;
    3034             : 
    3035           0 :     rectangle->x = 0;
    3036           0 :     rectangle->y = 0;
    3037             : 
    3038           0 :     rectangle->width  = surface->width;
    3039           0 :     rectangle->height = surface->height;
    3040             : 
    3041           0 :     return TRUE;
    3042             : }
    3043             : 
    3044             : static void
    3045           0 : _cairo_xlib_surface_get_font_options (void                  *abstract_surface,
    3046             :                                       cairo_font_options_t  *options)
    3047             : {
    3048           0 :     cairo_xlib_surface_t *surface = abstract_surface;
    3049             : 
    3050           0 :     *options = *_cairo_xlib_screen_get_font_options (surface->screen);
    3051           0 : }
    3052             : 
    3053             : static void
    3054             : _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
    3055             : 
    3056             : static void
    3057             : _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
    3058             :                                        cairo_scaled_font_t  *scaled_font);
    3059             : 
    3060             : static cairo_bool_t
    3061           0 : _cairo_xlib_surface_is_similar (void            *surface_a,
    3062             :                                 void            *surface_b)
    3063             : {
    3064           0 :     return _cairo_xlib_surface_same_screen (surface_a, surface_b);
    3065             : }
    3066             : 
    3067             : static const cairo_surface_backend_t cairo_xlib_surface_backend = {
    3068             :     CAIRO_SURFACE_TYPE_XLIB,
    3069             :     _cairo_xlib_surface_create_similar,
    3070             :     _cairo_xlib_surface_finish,
    3071             :     _cairo_xlib_surface_acquire_source_image,
    3072             :     _cairo_xlib_surface_release_source_image,
    3073             :     _cairo_xlib_surface_acquire_dest_image,
    3074             :     _cairo_xlib_surface_release_dest_image,
    3075             :     _cairo_xlib_surface_clone_similar,
    3076             :     _cairo_xlib_surface_composite,
    3077             :     _cairo_xlib_surface_fill_rectangles,
    3078             :     _cairo_xlib_surface_composite_trapezoids,
    3079             :     NULL, /* create_span_renderer */
    3080             :     NULL, /* check_span_renderer */
    3081             :     NULL, /* copy_page */
    3082             :     NULL, /* show_page */
    3083             :     _cairo_xlib_surface_get_extents,
    3084             :     NULL, /* old_show_glyphs */
    3085             :     _cairo_xlib_surface_get_font_options,
    3086             :     NULL, /* flush */
    3087             :     NULL, /* mark_dirty_rectangle */
    3088             :     _cairo_xlib_surface_scaled_font_fini,
    3089             :     _cairo_xlib_surface_scaled_glyph_fini,
    3090             : 
    3091             :     NULL, /* paint */
    3092             :     NULL, /* mask */
    3093             :     NULL, /* stroke */
    3094             :     NULL, /* fill */
    3095             :     _cairo_xlib_surface_show_glyphs,
    3096             : 
    3097             :     _cairo_xlib_surface_snapshot,
    3098             :     _cairo_xlib_surface_is_similar,
    3099             : 
    3100             :     NULL, /* fill_stroke */
    3101             : 
    3102             :     _cairo_xlib_surface_create_solid_pattern_surface,
    3103             :     _cairo_xlib_surface_can_repaint_solid_pattern_surface
    3104             : };
    3105             : 
    3106             : /**
    3107             :  * _cairo_surface_is_xlib:
    3108             :  * @surface: a #cairo_surface_t
    3109             :  *
    3110             :  * Checks if a surface is a #cairo_xlib_surface_t
    3111             :  *
    3112             :  * Return value: True if the surface is an xlib surface
    3113             :  **/
    3114             : static cairo_bool_t
    3115           0 : _cairo_surface_is_xlib (cairo_surface_t *surface)
    3116             : {
    3117           0 :     return surface->backend == &cairo_xlib_surface_backend;
    3118             : }
    3119             : 
    3120             : /* callback from CloseDisplay */
    3121             : static void
    3122           0 : _cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data)
    3123             : {
    3124           0 :     cairo_xlib_surface_t *surface = cairo_container_of (data,
    3125             :                                                         cairo_xlib_surface_t,
    3126             :                                                         close_display_hook);
    3127             :     Display *dpy;
    3128             : 
    3129           0 :     dpy = display->display;
    3130             : 
    3131             :     X_DEBUG ((dpy, "detach (drawable=%x)", (unsigned int) surface->drawable));
    3132             : 
    3133           0 :     if (surface->dst_picture != None) {
    3134           0 :         XRenderFreePicture (dpy, surface->dst_picture);
    3135           0 :         surface->dst_picture = None;
    3136             :     }
    3137             : 
    3138           0 :     if (surface->src_picture != None) {
    3139           0 :         XRenderFreePicture (dpy, surface->src_picture);
    3140           0 :         surface->src_picture = None;
    3141             :     }
    3142             : 
    3143           0 :     if (surface->owns_pixmap) {
    3144           0 :         XFreePixmap (dpy, surface->drawable);
    3145           0 :         surface->drawable = None;
    3146           0 :         surface->owns_pixmap = FALSE;
    3147             :     }
    3148           0 : }
    3149             : 
    3150             : static cairo_surface_t *
    3151           0 : _cairo_xlib_surface_create_internal (cairo_xlib_screen_t        *screen,
    3152             :                                      Drawable                    drawable,
    3153             :                                      Visual                     *visual,
    3154             :                                      XRenderPictFormat          *xrender_format,
    3155             :                                      int                         width,
    3156             :                                      int                         height,
    3157             :                                      int                         depth)
    3158             : {
    3159             :     cairo_xlib_surface_t *surface;
    3160             :     cairo_xlib_display_t *display;
    3161             :     cairo_status_t status;
    3162             : 
    3163           0 :     if (depth == 0) {
    3164           0 :         if (xrender_format) {
    3165           0 :             depth = xrender_format->depth;
    3166             : 
    3167             :             /* XXX find matching visual for core/dithering fallbacks? */
    3168           0 :         } else if (visual) {
    3169           0 :             Screen *scr = screen->screen;
    3170             : 
    3171           0 :             if (visual == DefaultVisualOfScreen (scr)) {
    3172           0 :                 depth = DefaultDepthOfScreen (scr);
    3173             :             } else  {
    3174             :                 int j, k;
    3175             : 
    3176             :                 /* This is ugly, but we have to walk over all visuals
    3177             :                  * for the display to find the correct depth.
    3178             :                  */
    3179           0 :                 depth = 0;
    3180           0 :                 for (j = 0; j < scr->ndepths; j++) {
    3181           0 :                     Depth *d = &scr->depths[j];
    3182           0 :                     for (k = 0; k < d->nvisuals; k++) {
    3183           0 :                         if (&d->visuals[k] == visual) {
    3184           0 :                             depth = d->depth;
    3185           0 :                             goto found;
    3186             :                         }
    3187             :                     }
    3188             :                 }
    3189             :             }
    3190             :         }
    3191             : 
    3192           0 :         if (depth == 0)
    3193           0 :             return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
    3194             : 
    3195             : found:
    3196             :         ;
    3197             :     }
    3198             : 
    3199           0 :     surface = malloc (sizeof (cairo_xlib_surface_t));
    3200           0 :     if (unlikely (surface == NULL))
    3201           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
    3202             : 
    3203           0 :     status = _cairo_xlib_display_acquire (screen->device, &display);
    3204           0 :     if (unlikely (status)) {
    3205           0 :         free (surface);
    3206           0 :         return _cairo_surface_create_in_error (_cairo_error (status));
    3207             :     }
    3208             : 
    3209           0 :     _cairo_xlib_display_get_xrender_version (display,
    3210             :                                              &surface->render_major,
    3211             :                                              &surface->render_minor);
    3212           0 :     if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
    3213           0 :         if (!xrender_format) {
    3214           0 :             if (visual) {
    3215           0 :                 xrender_format = XRenderFindVisualFormat (display->display, visual);
    3216           0 :             } else if (depth == 1) {
    3217           0 :                 xrender_format =
    3218           0 :                     _cairo_xlib_display_get_xrender_format (display,
    3219             :                                                             CAIRO_FORMAT_A1);
    3220             :             }
    3221             :         }
    3222             :     } else {
    3223             :         /* we cannot use XRender for this surface, so ensure we don't try */
    3224           0 :         surface->render_major = -1;
    3225           0 :         surface->render_minor = -1;
    3226             :     }
    3227             : 
    3228             :     /* initialize and hook into the CloseDisplay callback */
    3229           0 :     surface->close_display_hook.func = _cairo_xlib_surface_detach_display;
    3230           0 :     _cairo_xlib_add_close_display_hook (display,
    3231             :                                         &surface->close_display_hook);
    3232             : 
    3233           0 :     cairo_device_release (&display->base);
    3234             : 
    3235           0 :     _cairo_surface_init (&surface->base,
    3236             :                          &cairo_xlib_surface_backend,
    3237             :                          screen->device,
    3238             :                          _xrender_format_to_content (xrender_format));
    3239             : 
    3240           0 :     surface->screen = screen;
    3241             : 
    3242           0 :     surface->drawable = drawable;
    3243           0 :     surface->owns_pixmap = FALSE;
    3244           0 :     surface->use_pixmap = 0;
    3245           0 :     surface->width = width;
    3246           0 :     surface->height = height;
    3247             : 
    3248           0 :     surface->buggy_repeat = ! _cairo_xlib_display_has_repeat (screen->device);
    3249           0 :     if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
    3250             :         /* so we can use the XTile fallback */
    3251           0 :         surface->buggy_repeat = TRUE;
    3252             :     }
    3253             : 
    3254           0 :     surface->buggy_pad_reflect = ! _cairo_xlib_display_has_reflect (screen->device);
    3255           0 :     if (! CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT (surface))
    3256           0 :         surface->buggy_pad_reflect = TRUE;
    3257             : 
    3258           0 :     surface->buggy_gradients = ! _cairo_xlib_display_has_gradients (screen->device);
    3259           0 :     if (! CAIRO_SURFACE_RENDER_HAS_GRADIENTS (surface))
    3260           0 :         surface->buggy_gradients = TRUE;
    3261             : 
    3262           0 :     surface->dst_picture = None;
    3263           0 :     surface->src_picture = None;
    3264             : 
    3265           0 :     surface->visual = visual;
    3266           0 :     surface->xrender_format = xrender_format;
    3267           0 :     surface->depth = depth;
    3268           0 :     surface->filter = CAIRO_FILTER_NEAREST;
    3269           0 :     surface->extend = CAIRO_EXTEND_NONE;
    3270           0 :     surface->has_component_alpha = FALSE;
    3271           0 :     surface->precision = PolyModePrecise;
    3272           0 :     surface->xtransform = identity;
    3273             : 
    3274           0 :     surface->clip_region = NULL;
    3275           0 :     surface->clip_rects = surface->embedded_clip_rects;
    3276           0 :     surface->num_clip_rects = 0;
    3277           0 :     surface->clip_dirty = 0;
    3278             : 
    3279             :     /*
    3280             :      * Compute the pixel format masks from either a XrenderFormat or
    3281             :      * else from a visual; failing that we assume the drawable is an
    3282             :      * alpha-only pixmap as it could only have been created that way
    3283             :      * through the cairo_xlib_surface_create_for_bitmap function.
    3284             :      */
    3285           0 :     if (xrender_format) {
    3286           0 :         surface->a_mask = (unsigned long)
    3287           0 :             surface->xrender_format->direct.alphaMask
    3288           0 :             << surface->xrender_format->direct.alpha;
    3289           0 :         surface->r_mask = (unsigned long)
    3290           0 :             surface->xrender_format->direct.redMask
    3291           0 :             << surface->xrender_format->direct.red;
    3292           0 :         surface->g_mask = (unsigned long)
    3293           0 :             surface->xrender_format->direct.greenMask
    3294           0 :             << surface->xrender_format->direct.green;
    3295           0 :         surface->b_mask = (unsigned long)
    3296           0 :             surface->xrender_format->direct.blueMask
    3297           0 :             << surface->xrender_format->direct.blue;
    3298           0 :     } else if (visual) {
    3299           0 :         surface->a_mask = 0;
    3300           0 :         surface->r_mask = visual->red_mask;
    3301           0 :         surface->g_mask = visual->green_mask;
    3302           0 :         surface->b_mask = visual->blue_mask;
    3303             :     } else {
    3304           0 :         if (depth < 32)
    3305           0 :             surface->a_mask = (1 << depth) - 1;
    3306             :         else
    3307           0 :             surface->a_mask = 0xffffffff;
    3308           0 :         surface->r_mask = 0;
    3309           0 :         surface->g_mask = 0;
    3310           0 :         surface->b_mask = 0;
    3311             :     }
    3312             : 
    3313           0 :     return &surface->base;
    3314             : }
    3315             : 
    3316             : static Screen *
    3317           0 : _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
    3318             : {
    3319             :     int s, d, v;
    3320             : 
    3321           0 :     for (s = 0; s < ScreenCount (dpy); s++) {
    3322             :         Screen *screen;
    3323             : 
    3324           0 :         screen = ScreenOfDisplay (dpy, s);
    3325           0 :         if (visual == DefaultVisualOfScreen (screen))
    3326           0 :             return screen;
    3327             : 
    3328           0 :         for (d = 0; d < screen->ndepths; d++) {
    3329             :             Depth  *depth;
    3330             : 
    3331           0 :             depth = &screen->depths[d];
    3332           0 :             for (v = 0; v < depth->nvisuals; v++)
    3333           0 :                 if (visual == &depth->visuals[v])
    3334           0 :                     return screen;
    3335             :         }
    3336             :     }
    3337             : 
    3338           0 :     return NULL;
    3339             : }
    3340             : 
    3341             : /**
    3342             :  * cairo_xlib_surface_create:
    3343             :  * @dpy: an X Display
    3344             :  * @drawable: an X Drawable, (a Pixmap or a Window)
    3345             :  * @visual: the visual to use for drawing to @drawable. The depth
    3346             :  *          of the visual must match the depth of the drawable.
    3347             :  *          Currently, only TrueColor visuals are fully supported.
    3348             :  * @width: the current width of @drawable.
    3349             :  * @height: the current height of @drawable.
    3350             :  *
    3351             :  * Creates an Xlib surface that draws to the given drawable.
    3352             :  * The way that colors are represented in the drawable is specified
    3353             :  * by the provided visual.
    3354             :  *
    3355             :  * Note: If @drawable is a Window, then the function
    3356             :  * cairo_xlib_surface_set_size() must be called whenever the size of the
    3357             :  * window changes.
    3358             :  *
    3359             :  * When @drawable is a Window containing child windows then drawing to
    3360             :  * the created surface will be clipped by those child windows.  When
    3361             :  * the created surface is used as a source, the contents of the
    3362             :  * children will be included.
    3363             :  *
    3364             :  * Return value: the newly created surface
    3365             :  **/
    3366             : cairo_surface_t *
    3367           0 : cairo_xlib_surface_create (Display     *dpy,
    3368             :                            Drawable     drawable,
    3369             :                            Visual      *visual,
    3370             :                            int          width,
    3371             :                            int          height)
    3372             : {
    3373             :     Screen *scr;
    3374             :     cairo_xlib_screen_t *screen;
    3375             :     cairo_status_t status;
    3376             : 
    3377           0 :     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
    3378             :         /* you're lying, and you know it! */
    3379           0 :         return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
    3380             :     }
    3381             : 
    3382           0 :     scr = _cairo_xlib_screen_from_visual (dpy, visual);
    3383           0 :     if (scr == NULL)
    3384           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
    3385             : 
    3386           0 :     status = _cairo_xlib_screen_get (dpy, scr, &screen);
    3387           0 :     if (unlikely (status))
    3388           0 :         return _cairo_surface_create_in_error (status);
    3389             : 
    3390             :     X_DEBUG ((dpy, "create (drawable=%x)", (unsigned int) drawable));
    3391             : 
    3392           0 :     return _cairo_xlib_surface_create_internal (screen, drawable,
    3393             :                                                 visual, NULL,
    3394             :                                                 width, height, 0);
    3395             : }
    3396             : 
    3397             : /**
    3398             :  * cairo_xlib_surface_create_for_bitmap:
    3399             :  * @dpy: an X Display
    3400             :  * @bitmap: an X Drawable, (a depth-1 Pixmap)
    3401             :  * @screen: the X Screen associated with @bitmap
    3402             :  * @width: the current width of @bitmap.
    3403             :  * @height: the current height of @bitmap.
    3404             :  *
    3405             :  * Creates an Xlib surface that draws to the given bitmap.
    3406             :  * This will be drawn to as a %CAIRO_FORMAT_A1 object.
    3407             :  *
    3408             :  * Return value: the newly created surface
    3409             :  **/
    3410             : cairo_surface_t *
    3411           0 : cairo_xlib_surface_create_for_bitmap (Display  *dpy,
    3412             :                                       Pixmap    bitmap,
    3413             :                                       Screen   *scr,
    3414             :                                       int       width,
    3415             :                                       int       height)
    3416             : {
    3417             :     cairo_xlib_screen_t *screen;
    3418             :     cairo_status_t status;
    3419             : 
    3420           0 :     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
    3421           0 :         return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
    3422             : 
    3423           0 :     status = _cairo_xlib_screen_get (dpy, scr, &screen);
    3424           0 :     if (unlikely (status))
    3425           0 :         return _cairo_surface_create_in_error (status);
    3426             : 
    3427             :     X_DEBUG ((dpy, "create_for_bitmap (drawable=%x)", (unsigned int) bitmap));
    3428             : 
    3429           0 :     return _cairo_xlib_surface_create_internal (screen, bitmap,
    3430             :                                                 NULL, NULL,
    3431             :                                                 width, height, 1);
    3432             : }
    3433             : 
    3434             : #if CAIRO_HAS_XLIB_XRENDER_SURFACE
    3435             : /**
    3436             :  * cairo_xlib_surface_create_with_xrender_format:
    3437             :  * @dpy: an X Display
    3438             :  * @drawable: an X Drawable, (a Pixmap or a Window)
    3439             :  * @screen: the X Screen associated with @drawable
    3440             :  * @format: the picture format to use for drawing to @drawable. The depth
    3441             :  *          of @format must match the depth of the drawable.
    3442             :  * @width: the current width of @drawable.
    3443             :  * @height: the current height of @drawable.
    3444             :  *
    3445             :  * Creates an Xlib surface that draws to the given drawable.
    3446             :  * The way that colors are represented in the drawable is specified
    3447             :  * by the provided picture format.
    3448             :  *
    3449             :  * Note: If @drawable is a Window, then the function
    3450             :  * cairo_xlib_surface_set_size() must be called whenever the size of the
    3451             :  * window changes.
    3452             :  *
    3453             :  * Return value: the newly created surface
    3454             :  **/
    3455             : cairo_surface_t *
    3456           0 : cairo_xlib_surface_create_with_xrender_format (Display              *dpy,
    3457             :                                                Drawable             drawable,
    3458             :                                                Screen               *scr,
    3459             :                                                XRenderPictFormat    *format,
    3460             :                                                int                  width,
    3461             :                                                int                  height)
    3462             : {
    3463             :     cairo_xlib_screen_t *screen;
    3464             :     cairo_status_t status;
    3465             : 
    3466           0 :     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
    3467           0 :         return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
    3468             : 
    3469           0 :     status = _cairo_xlib_screen_get (dpy, scr, &screen);
    3470           0 :     if (unlikely (status))
    3471           0 :         return _cairo_surface_create_in_error (status);
    3472             : 
    3473             :     X_DEBUG ((dpy, "create_with_xrender_format (drawable=%x)", (unsigned int) drawable));
    3474             : 
    3475           0 :     return _cairo_xlib_surface_create_internal (screen, drawable,
    3476             :                                                 _visual_for_xrender_format (scr, format),
    3477             :                                                 format, width, height, 0);
    3478             : }
    3479             : 
    3480             : /**
    3481             :  * cairo_xlib_surface_get_xrender_format:
    3482             :  * @surface: an xlib surface
    3483             :  *
    3484             :  * Gets the X Render picture format that @surface uses for rendering with the
    3485             :  * X Render extension. If the surface was created by
    3486             :  * cairo_xlib_surface_create_with_xrender_format() originally, the return
    3487             :  * value is the format passed to that constructor.
    3488             :  *
    3489             :  * Return value: the XRenderPictFormat* associated with @surface,
    3490             :  * or %NULL if the surface is not an xlib surface
    3491             :  * or if the X Render extension is not available.
    3492             :  *
    3493             :  * Since: 1.6
    3494             :  **/
    3495             : XRenderPictFormat *
    3496           0 : cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
    3497             : {
    3498           0 :     cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface;
    3499             : 
    3500             :     /* Throw an error for a non-xlib surface */
    3501           0 :     if (! _cairo_surface_is_xlib (surface)) {
    3502           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    3503           0 :         return NULL;
    3504             :     }
    3505             : 
    3506           0 :     return xlib_surface->xrender_format;
    3507             : }
    3508             : #endif
    3509             : 
    3510             : /**
    3511             :  * cairo_xlib_surface_set_size:
    3512             :  * @surface: a #cairo_surface_t for the XLib backend
    3513             :  * @width: the new width of the surface
    3514             :  * @height: the new height of the surface
    3515             :  *
    3516             :  * Informs cairo of the new size of the X Drawable underlying the
    3517             :  * surface. For a surface created for a Window (rather than a Pixmap),
    3518             :  * this function must be called each time the size of the window
    3519             :  * changes. (For a subwindow, you are normally resizing the window
    3520             :  * yourself, but for a toplevel window, it is necessary to listen for
    3521             :  * ConfigureNotify events.)
    3522             :  *
    3523             :  * A Pixmap can never change size, so it is never necessary to call
    3524             :  * this function on a surface created for a Pixmap.
    3525             :  **/
    3526             : void
    3527           0 : cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
    3528             :                              int              width,
    3529             :                              int              height)
    3530             : {
    3531           0 :     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
    3532             :     cairo_status_t status;
    3533             : 
    3534           0 :     if (unlikely (abstract_surface->status))
    3535           0 :         return;
    3536           0 :     if (unlikely (abstract_surface->finished)) {
    3537           0 :         status = _cairo_surface_set_error (abstract_surface,
    3538             :                                            _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
    3539           0 :         return;
    3540             :     }
    3541             : 
    3542           0 :     if (! _cairo_surface_is_xlib (abstract_surface)) {
    3543           0 :         status = _cairo_surface_set_error (abstract_surface,
    3544             :                                            _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
    3545           0 :         return;
    3546             :     }
    3547             : 
    3548           0 :     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
    3549           0 :         status = _cairo_surface_set_error (abstract_surface,
    3550             :                                            _cairo_error (CAIRO_STATUS_INVALID_SIZE));
    3551           0 :         return;
    3552             :     }
    3553             : 
    3554           0 :     surface->width = width;
    3555           0 :     surface->height = height;
    3556             : }
    3557             : /**
    3558             :  * cairo_xlib_surface_set_drawable:
    3559             :  * @surface: a #cairo_surface_t for the XLib backend
    3560             :  * @drawable: the new drawable for the surface
    3561             :  * @width: the width of the new drawable
    3562             :  * @height: the height of the new drawable
    3563             :  *
    3564             :  * Informs cairo of a new X Drawable underlying the
    3565             :  * surface. The drawable must match the display, screen
    3566             :  * and format of the existing drawable or the application
    3567             :  * will get X protocol errors and will probably terminate.
    3568             :  * No checks are done by this function to ensure this
    3569             :  * compatibility.
    3570             :  **/
    3571             : void
    3572           0 : cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
    3573             :                                  Drawable           drawable,
    3574             :                                  int                width,
    3575             :                                  int                height)
    3576             : {
    3577           0 :     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *)abstract_surface;
    3578             :     cairo_status_t status;
    3579             : 
    3580           0 :     if (unlikely (abstract_surface->status))
    3581           0 :         return;
    3582           0 :     if (unlikely (abstract_surface->finished)) {
    3583           0 :         status = _cairo_surface_set_error (abstract_surface,
    3584             :                                            _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
    3585           0 :         return;
    3586             :     }
    3587             : 
    3588           0 :     if (! _cairo_surface_is_xlib (abstract_surface)) {
    3589           0 :         status = _cairo_surface_set_error (abstract_surface,
    3590             :                                            _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
    3591           0 :         return;
    3592             :     }
    3593             : 
    3594           0 :     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
    3595           0 :         status = _cairo_surface_set_error (abstract_surface,
    3596             :                                            _cairo_error (CAIRO_STATUS_INVALID_SIZE));
    3597           0 :         return;
    3598             :     }
    3599             : 
    3600             :     /* XXX: and what about this case? */
    3601           0 :     if (surface->owns_pixmap)
    3602           0 :         return;
    3603             : 
    3604           0 :     if (surface->drawable != drawable) {
    3605             :         cairo_xlib_display_t *display;
    3606             : 
    3607           0 :         status = _cairo_xlib_display_acquire (surface->base.device, &display);
    3608           0 :         if (unlikely (status))
    3609           0 :             return;
    3610             : 
    3611             :         X_DEBUG ((display->display, "set_drawable (drawable=%x)", (unsigned int) drawable));
    3612             : 
    3613           0 :         if (surface->dst_picture != None) {
    3614           0 :             status = _cairo_xlib_display_queue_resource (
    3615             :                                                   display,
    3616             :                                                   XRenderFreePicture,
    3617             :                                                   surface->dst_picture);
    3618           0 :             if (unlikely (status)) {
    3619           0 :                 status = _cairo_surface_set_error (&surface->base, status);
    3620           0 :                 return;
    3621             :             }
    3622             : 
    3623           0 :             surface->dst_picture = None;
    3624             :         }
    3625             : 
    3626           0 :         if (surface->src_picture != None) {
    3627           0 :             status = _cairo_xlib_display_queue_resource (
    3628             :                                                   display,
    3629             :                                                   XRenderFreePicture,
    3630             :                                                   surface->src_picture);
    3631           0 :             if (unlikely (status)) {
    3632           0 :                 status = _cairo_surface_set_error (&surface->base, status);
    3633           0 :                 return;
    3634             :             }
    3635             : 
    3636           0 :             surface->src_picture = None;
    3637             :         }
    3638             : 
    3639           0 :         cairo_device_release (&display->base);
    3640             : 
    3641           0 :         surface->drawable = drawable;
    3642             :     }
    3643           0 :     surface->width = width;
    3644           0 :     surface->height = height;
    3645             : }
    3646             : 
    3647             : /**
    3648             :  * cairo_xlib_surface_get_display:
    3649             :  * @surface: a #cairo_xlib_surface_t
    3650             :  *
    3651             :  * Get the X Display for the underlying X Drawable.
    3652             :  *
    3653             :  * Return value: the display.
    3654             :  *
    3655             :  * Since: 1.2
    3656             :  **/
    3657             : Display *
    3658           0 : cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
    3659             : {
    3660           0 :     if (! _cairo_surface_is_xlib (abstract_surface)) {
    3661           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    3662           0 :         return NULL;
    3663             :     }
    3664             : 
    3665           0 :     return ((cairo_xlib_display_t *) abstract_surface->device)->display;
    3666             : }
    3667             : 
    3668             : /**
    3669             :  * cairo_xlib_surface_get_drawable:
    3670             :  * @surface: a #cairo_xlib_surface_t
    3671             :  *
    3672             :  * Get the underlying X Drawable used for the surface.
    3673             :  *
    3674             :  * Return value: the drawable.
    3675             :  *
    3676             :  * Since: 1.2
    3677             :  **/
    3678             : Drawable
    3679           0 : cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
    3680             : {
    3681           0 :     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
    3682             : 
    3683           0 :     if (! _cairo_surface_is_xlib (abstract_surface)) {
    3684           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    3685           0 :         return 0;
    3686             :     }
    3687             : 
    3688           0 :     return surface->drawable;
    3689             : }
    3690             : 
    3691             : /**
    3692             :  * cairo_xlib_surface_get_screen:
    3693             :  * @surface: a #cairo_xlib_surface_t
    3694             :  *
    3695             :  * Get the X Screen for the underlying X Drawable.
    3696             :  *
    3697             :  * Return value: the screen.
    3698             :  *
    3699             :  * Since: 1.2
    3700             :  **/
    3701             : Screen *
    3702           0 : cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
    3703             : {
    3704           0 :     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
    3705             : 
    3706           0 :     if (! _cairo_surface_is_xlib (abstract_surface)) {
    3707           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    3708           0 :         return NULL;
    3709             :     }
    3710             : 
    3711           0 :     return surface->screen->screen;
    3712             : }
    3713             : 
    3714             : /**
    3715             :  * cairo_xlib_surface_get_visual:
    3716             :  * @surface: a #cairo_xlib_surface_t
    3717             :  *
    3718             :  * Gets the X Visual associated with @surface, suitable for use with the
    3719             :  * underlying X Drawable.  If @surface was created by
    3720             :  * cairo_xlib_surface_create(), the return value is the Visual passed to that
    3721             :  * constructor.
    3722             :  *
    3723             :  * Return value: the Visual or %NULL if there is no appropriate Visual for
    3724             :  * @surface.
    3725             :  *
    3726             :  * Since: 1.2
    3727             :  **/
    3728             : Visual *
    3729           0 : cairo_xlib_surface_get_visual (cairo_surface_t *surface)
    3730             : {
    3731           0 :     cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface;
    3732             : 
    3733           0 :     if (! _cairo_surface_is_xlib (surface)) {
    3734           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    3735           0 :         return NULL;
    3736             :     }
    3737             : 
    3738           0 :     return xlib_surface->visual;
    3739             : }
    3740             : 
    3741             : /**
    3742             :  * cairo_xlib_surface_get_depth:
    3743             :  * @surface: a #cairo_xlib_surface_t
    3744             :  *
    3745             :  * Get the number of bits used to represent each pixel value.
    3746             :  *
    3747             :  * Return value: the depth of the surface in bits.
    3748             :  *
    3749             :  * Since: 1.2
    3750             :  **/
    3751             : int
    3752           0 : cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
    3753             : {
    3754           0 :     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
    3755             : 
    3756           0 :     if (! _cairo_surface_is_xlib (abstract_surface)) {
    3757           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    3758           0 :         return 0;
    3759             :     }
    3760             : 
    3761           0 :     return surface->depth;
    3762             : }
    3763             : 
    3764             : /**
    3765             :  * cairo_xlib_surface_get_width:
    3766             :  * @surface: a #cairo_xlib_surface_t
    3767             :  *
    3768             :  * Get the width of the X Drawable underlying the surface in pixels.
    3769             :  *
    3770             :  * Return value: the width of the surface in pixels.
    3771             :  *
    3772             :  * Since: 1.2
    3773             :  **/
    3774             : int
    3775           0 : cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
    3776             : {
    3777           0 :     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
    3778             : 
    3779           0 :     if (! _cairo_surface_is_xlib (abstract_surface)) {
    3780           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    3781           0 :         return 0;
    3782             :     }
    3783             : 
    3784           0 :     return surface->width;
    3785             : }
    3786             : 
    3787             : /**
    3788             :  * cairo_xlib_surface_get_height:
    3789             :  * @surface: a #cairo_xlib_surface_t
    3790             :  *
    3791             :  * Get the height of the X Drawable underlying the surface in pixels.
    3792             :  *
    3793             :  * Return value: the height of the surface in pixels.
    3794             :  *
    3795             :  * Since: 1.2
    3796             :  **/
    3797             : int
    3798           0 : cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
    3799             : {
    3800           0 :     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
    3801             : 
    3802           0 :     if (! _cairo_surface_is_xlib (abstract_surface)) {
    3803           0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    3804           0 :         return 0;
    3805             :     }
    3806             : 
    3807           0 :     return surface->height;
    3808             : }
    3809             : 
    3810             : enum {
    3811             :     GLYPHSET_INDEX_ARGB32,
    3812             :     GLYPHSET_INDEX_A8,
    3813             :     GLYPHSET_INDEX_A1,
    3814             :     NUM_GLYPHSETS
    3815             : };
    3816             : 
    3817             : typedef struct _cairo_xlib_font_glyphset_free_glyphs {
    3818             :     GlyphSet            glyphset;
    3819             :     int                 glyph_count;
    3820             :     unsigned long       glyph_indices[128];
    3821             : } cairo_xlib_font_glyphset_free_glyphs_t;
    3822             : 
    3823             : typedef struct _cairo_xlib_font_glyphset_info {
    3824             :     GlyphSet            glyphset;
    3825             :     cairo_format_t      format;
    3826             :     XRenderPictFormat   *xrender_format;
    3827             :     cairo_xlib_font_glyphset_free_glyphs_t *pending_free_glyphs;
    3828             : } cairo_xlib_font_glyphset_info_t;
    3829             : 
    3830             : typedef struct _cairo_xlib_surface_font_private {
    3831             :     cairo_scaled_font_t             *scaled_font;
    3832             :     cairo_scaled_font_t         *grayscale_font;
    3833             :     cairo_xlib_hook_t                close_display_hook;
    3834             :     cairo_device_t                  *device;
    3835             :     cairo_xlib_font_glyphset_info_t  glyphset_info[NUM_GLYPHSETS];
    3836             : } cairo_xlib_surface_font_private_t;
    3837             : 
    3838             : /* callback from CloseDisplay */
    3839             : static void
    3840           0 : _cairo_xlib_surface_remove_scaled_font (cairo_xlib_display_t    *display,
    3841             :                                         void                    *data)
    3842             : {
    3843             :     cairo_xlib_surface_font_private_t   *font_private;
    3844             :     cairo_scaled_font_t                 *scaled_font;
    3845             : 
    3846           0 :     font_private = cairo_container_of (data,
    3847             :                                        cairo_xlib_surface_font_private_t,
    3848             :                                        close_display_hook);
    3849           0 :     scaled_font = font_private->scaled_font;
    3850             : 
    3851           0 :     CAIRO_MUTEX_LOCK (scaled_font->mutex);
    3852           0 :     font_private = scaled_font->surface_private;
    3853           0 :     scaled_font->surface_private = NULL;
    3854             : 
    3855           0 :     _cairo_scaled_font_reset_cache (scaled_font);
    3856           0 :     CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
    3857             : 
    3858           0 :     if (font_private != NULL) {
    3859             :         int i;
    3860             : 
    3861           0 :         if (font_private->grayscale_font) {
    3862           0 :             cairo_scaled_font_destroy (font_private->grayscale_font);
    3863             :         }
    3864             : 
    3865           0 :         for (i = 0; i < NUM_GLYPHSETS; i++) {
    3866             :             cairo_xlib_font_glyphset_info_t *glyphset_info;
    3867             : 
    3868           0 :             glyphset_info = &font_private->glyphset_info[i];
    3869           0 :             if (glyphset_info->glyphset)
    3870           0 :                 XRenderFreeGlyphSet (display->display, glyphset_info->glyphset);
    3871             : 
    3872           0 :             if (glyphset_info->pending_free_glyphs != NULL)
    3873           0 :                 free (glyphset_info->pending_free_glyphs);
    3874             :         }
    3875             : 
    3876           0 :         cairo_device_destroy (font_private->device);
    3877           0 :         free (font_private);
    3878             :     }
    3879           0 : }
    3880             : 
    3881             : static cairo_status_t
    3882           0 : _cairo_xlib_surface_font_init (cairo_xlib_display_t *display,
    3883             :                                cairo_scaled_font_t  *scaled_font)
    3884             : {
    3885             :     cairo_xlib_surface_font_private_t   *font_private;
    3886             :     int i;
    3887             : 
    3888           0 :     font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
    3889           0 :     if (unlikely (font_private == NULL))
    3890           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    3891             : 
    3892           0 :     font_private->scaled_font = scaled_font;
    3893           0 :     font_private->grayscale_font = NULL;
    3894           0 :     font_private->device = cairo_device_reference (&display->base);
    3895             : 
    3896             :     /* initialize and hook into the CloseDisplay callback */
    3897           0 :     font_private->close_display_hook.func =
    3898             :         _cairo_xlib_surface_remove_scaled_font;
    3899           0 :     _cairo_xlib_add_close_display_hook (display,
    3900             :                                         &font_private->close_display_hook);
    3901             : 
    3902             : 
    3903           0 :     for (i = 0; i < NUM_GLYPHSETS; i++) {
    3904           0 :         cairo_xlib_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
    3905           0 :         switch (i) {
    3906           0 :         case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
    3907           0 :         case GLYPHSET_INDEX_A8:     glyphset_info->format = CAIRO_FORMAT_A8;     break;
    3908           0 :         case GLYPHSET_INDEX_A1:     glyphset_info->format = CAIRO_FORMAT_A1;     break;
    3909           0 :         default:                    ASSERT_NOT_REACHED;                          break;
    3910             :         }
    3911           0 :         glyphset_info->xrender_format = NULL;
    3912           0 :         glyphset_info->glyphset = None;
    3913           0 :         glyphset_info->pending_free_glyphs = NULL;
    3914             :     }
    3915             : 
    3916           0 :     scaled_font->surface_private = font_private;
    3917           0 :     scaled_font->surface_backend = &cairo_xlib_surface_backend;
    3918             : 
    3919           0 :     return CAIRO_STATUS_SUCCESS;
    3920             : }
    3921             : 
    3922             : static void
    3923           0 : _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
    3924             : {
    3925             :     cairo_xlib_surface_font_private_t *font_private;
    3926             :     cairo_status_t status;
    3927             : 
    3928           0 :     font_private = scaled_font->surface_private;
    3929           0 :     if (font_private != NULL) {
    3930             :         cairo_xlib_display_t *display;
    3931             :         int i;
    3932             : 
    3933           0 :         if (font_private->grayscale_font) {
    3934           0 :             cairo_scaled_font_destroy (font_private->grayscale_font);
    3935             :         }
    3936           0 :         status = _cairo_xlib_display_acquire (font_private->device, &display);
    3937           0 :         if (status)
    3938           0 :             goto BAIL;
    3939             : 
    3940           0 :         _cairo_xlib_remove_close_display_hook (display,
    3941             :                                                &font_private->close_display_hook);
    3942             : 
    3943           0 :         for (i = 0; i < NUM_GLYPHSETS; i++) {
    3944             :             cairo_xlib_font_glyphset_info_t *glyphset_info;
    3945             : 
    3946           0 :             glyphset_info = &font_private->glyphset_info[i];
    3947             : 
    3948           0 :             if (glyphset_info->pending_free_glyphs != NULL)
    3949           0 :                 free (glyphset_info->pending_free_glyphs);
    3950             : 
    3951           0 :             if (glyphset_info->glyphset) {
    3952           0 :                 status = _cairo_xlib_display_queue_resource (display,
    3953             :                                                              XRenderFreeGlyphSet,
    3954             :                                                              glyphset_info->glyphset);
    3955             :                 (void) status; /* XXX cannot propagate failure */
    3956             :             }
    3957             :         }
    3958             : 
    3959           0 :         cairo_device_release (&display->base);
    3960             : BAIL:
    3961           0 :         cairo_device_destroy (&display->base);
    3962           0 :         free (font_private);
    3963             :     }
    3964           0 : }
    3965             : 
    3966             : static void
    3967           0 : _cairo_xlib_render_free_glyphs (Display *dpy,
    3968             :                                 cairo_xlib_font_glyphset_free_glyphs_t *to_free)
    3969             : {
    3970           0 :     XRenderFreeGlyphs (dpy,
    3971             :                        to_free->glyphset,
    3972           0 :                        to_free->glyph_indices,
    3973             :                        to_free->glyph_count);
    3974           0 : }
    3975             : 
    3976             : static cairo_xlib_font_glyphset_info_t *
    3977           0 : _cairo_xlib_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t            *scaled_glyph)
    3978             : {
    3979           0 :     return scaled_glyph->surface_private;
    3980             : }
    3981             : 
    3982             : static void
    3983           0 : _cairo_xlib_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t            *scaled_glyph,
    3984             :                                             cairo_xlib_font_glyphset_info_t *glyphset_info)
    3985             : {
    3986           0 :     scaled_glyph->surface_private = glyphset_info;
    3987           0 : }
    3988             : 
    3989             : static void
    3990           0 : _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
    3991             :                                        cairo_scaled_font_t  *scaled_font)
    3992             : {
    3993             :     cairo_xlib_surface_font_private_t   *font_private;
    3994             :     cairo_xlib_font_glyphset_info_t *glyphset_info;
    3995             : 
    3996           0 :     if (scaled_font->finished)
    3997           0 :         return;
    3998             : 
    3999           0 :     font_private = scaled_font->surface_private;
    4000           0 :     glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
    4001           0 :     if (font_private != NULL && glyphset_info != NULL) {
    4002             :         cairo_xlib_font_glyphset_free_glyphs_t *to_free;
    4003             :         cairo_status_t status;
    4004             : 
    4005           0 :         to_free = glyphset_info->pending_free_glyphs;
    4006           0 :         if (to_free != NULL &&
    4007           0 :             to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
    4008             :         {
    4009             :             cairo_xlib_display_t *display;
    4010             : 
    4011           0 :             status = _cairo_xlib_display_acquire (font_private->device, &display);
    4012           0 :             if (status == CAIRO_STATUS_SUCCESS) {
    4013           0 :                 status = _cairo_xlib_display_queue_work (display,
    4014             :                         (cairo_xlib_notify_func) _cairo_xlib_render_free_glyphs,
    4015             :                         to_free,
    4016             :                         free);
    4017           0 :                 cairo_device_release (&display->base);
    4018             :             }
    4019             :             /* XXX cannot propagate failure */
    4020           0 :             if (unlikely (status))
    4021           0 :                 free (to_free);
    4022             : 
    4023           0 :             to_free = glyphset_info->pending_free_glyphs = NULL;
    4024             :         }
    4025             : 
    4026           0 :         if (to_free == NULL) {
    4027           0 :             to_free = malloc (sizeof (cairo_xlib_font_glyphset_free_glyphs_t));
    4028           0 :             if (unlikely (to_free == NULL)) {
    4029           0 :                 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
    4030           0 :                 return; /* XXX cannot propagate failure */
    4031             :             }
    4032             : 
    4033           0 :             to_free->glyphset = glyphset_info->glyphset;
    4034           0 :             to_free->glyph_count = 0;
    4035           0 :             glyphset_info->pending_free_glyphs = to_free;
    4036             :         }
    4037             : 
    4038           0 :         to_free->glyph_indices[to_free->glyph_count++] =
    4039           0 :             _cairo_scaled_glyph_index (scaled_glyph);
    4040             :     }
    4041             : }
    4042             : 
    4043             : static cairo_bool_t
    4044           0 : _native_byte_order_lsb (void)
    4045             : {
    4046           0 :     int x = 1;
    4047             : 
    4048           0 :     return *((char *) &x) == 1;
    4049             : }
    4050             : 
    4051             : static int
    4052           0 : _cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
    4053             : {
    4054           0 :     if (format == CAIRO_FORMAT_A8)
    4055           0 :         return GLYPHSET_INDEX_A8;
    4056           0 :     if (format == CAIRO_FORMAT_A1)
    4057           0 :         return GLYPHSET_INDEX_A1;
    4058             : 
    4059           0 :     assert (format == CAIRO_FORMAT_ARGB32);
    4060           0 :     return GLYPHSET_INDEX_ARGB32;
    4061             : }
    4062             : 
    4063             : static cairo_xlib_font_glyphset_info_t *
    4064           0 : _cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
    4065             :                                                       cairo_format_t       format)
    4066             : {
    4067             :     cairo_xlib_surface_font_private_t *font_private;
    4068             :     cairo_xlib_font_glyphset_info_t *glyphset_info;
    4069             :     int glyphset_index;
    4070             : 
    4071           0 :     glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
    4072           0 :     font_private = scaled_font->surface_private;
    4073           0 :     glyphset_info = &font_private->glyphset_info[glyphset_index];
    4074           0 :     if (glyphset_info->glyphset == None) {
    4075             :         cairo_xlib_display_t *display;
    4076             :         
    4077           0 :         if (_cairo_xlib_display_acquire (font_private->device, &display))
    4078           0 :             return NULL;
    4079             : 
    4080           0 :         glyphset_info->xrender_format =
    4081           0 :             _cairo_xlib_display_get_xrender_format (display,
    4082             :                                                     glyphset_info->format);
    4083           0 :         glyphset_info->glyphset = XRenderCreateGlyphSet (display->display,
    4084           0 :                                                          glyphset_info->xrender_format);
    4085             : 
    4086           0 :         cairo_device_release (&display->base);
    4087             :     }
    4088             : 
    4089           0 :     return glyphset_info;
    4090             : }
    4091             : 
    4092             : static cairo_bool_t
    4093           0 : _cairo_xlib_glyphset_info_has_pending_free_glyph (
    4094             :                                 cairo_xlib_font_glyphset_info_t *glyphset_info,
    4095             :                                 unsigned long glyph_index)
    4096             : {
    4097           0 :     if (glyphset_info->pending_free_glyphs != NULL) {
    4098             :         cairo_xlib_font_glyphset_free_glyphs_t *to_free;
    4099             :         int i;
    4100             : 
    4101           0 :         to_free = glyphset_info->pending_free_glyphs;
    4102           0 :         for (i = 0; i < to_free->glyph_count; i++) {
    4103           0 :             if (to_free->glyph_indices[i] == glyph_index) {
    4104           0 :                 to_free->glyph_count--;
    4105           0 :                 memmove (&to_free->glyph_indices[i],
    4106           0 :                          &to_free->glyph_indices[i+1],
    4107           0 :                          (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
    4108           0 :                 return TRUE;
    4109             :             }
    4110             :         }
    4111             :     }
    4112             : 
    4113           0 :     return FALSE;
    4114             : }
    4115             : 
    4116             : static cairo_xlib_font_glyphset_info_t *
    4117           0 : _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (
    4118             :                                                cairo_scaled_font_t *scaled_font,
    4119             :                                                unsigned long glyph_index,
    4120             :                                                cairo_image_surface_t *surface)
    4121             : {
    4122             :     cairo_xlib_surface_font_private_t *font_private;
    4123             :     int i;
    4124             : 
    4125           0 :     font_private = scaled_font->surface_private;
    4126           0 :     if (font_private == NULL)
    4127           0 :         return NULL;
    4128             : 
    4129           0 :     if (surface != NULL) {
    4130           0 :         i = _cairo_xlib_get_glyphset_index_for_format (surface->format);
    4131           0 :         if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
    4132             :                                                 &font_private->glyphset_info[i],
    4133             :                                                 glyph_index))
    4134             :         {
    4135           0 :             return &font_private->glyphset_info[i];
    4136             :         }
    4137             :     } else {
    4138           0 :         for (i = 0; i < NUM_GLYPHSETS; i++) {
    4139           0 :             if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
    4140             :                                                 &font_private->glyphset_info[i],
    4141             :                                                 glyph_index))
    4142             :             {
    4143           0 :                 return &font_private->glyphset_info[i];
    4144             :             }
    4145             :         }
    4146             :     }
    4147             : 
    4148           0 :     return NULL;
    4149             : }
    4150             : 
    4151             : static cairo_status_t
    4152           0 : _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
    4153             :                                cairo_scaled_font_t   *scaled_font,
    4154             :                                cairo_scaled_glyph_t **pscaled_glyph)
    4155             : {
    4156             :     XGlyphInfo glyph_info;
    4157             :     unsigned long glyph_index;
    4158             :     unsigned char *data;
    4159           0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
    4160           0 :     cairo_scaled_glyph_t *scaled_glyph = *pscaled_glyph;
    4161           0 :     cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
    4162             :     cairo_bool_t already_had_glyph_surface;
    4163             :     cairo_xlib_font_glyphset_info_t *glyphset_info;
    4164             : 
    4165           0 :     glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
    4166             : 
    4167             :     /* check to see if we have a pending XRenderFreeGlyph for this glyph */
    4168           0 :     glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
    4169           0 :     if (glyphset_info != NULL) {
    4170           0 :         _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
    4171           0 :         return CAIRO_STATUS_SUCCESS;
    4172             :     }
    4173             : 
    4174           0 :     if (!glyph_surface) {
    4175           0 :         status = _cairo_scaled_glyph_lookup (scaled_font,
    4176             :                                              glyph_index,
    4177             :                                              CAIRO_SCALED_GLYPH_INFO_METRICS |
    4178             :                                              CAIRO_SCALED_GLYPH_INFO_SURFACE,
    4179             :                                              pscaled_glyph);
    4180           0 :         if (unlikely (status))
    4181           0 :             return status;
    4182             : 
    4183           0 :         scaled_glyph = *pscaled_glyph;
    4184           0 :         glyph_surface = scaled_glyph->surface;
    4185           0 :         already_had_glyph_surface = FALSE;
    4186             :     } else {
    4187           0 :         already_had_glyph_surface = TRUE;
    4188             :     }
    4189             : 
    4190           0 :     if (scaled_font->surface_private == NULL) {
    4191           0 :         status = _cairo_xlib_surface_font_init (display, scaled_font);
    4192           0 :         if (unlikely (status))
    4193           0 :             return status;
    4194             :     }
    4195             : 
    4196           0 :     glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_format (scaled_font,
    4197             :                                                                           glyph_surface->format);
    4198             : 
    4199             :     /* XRenderAddGlyph does not handle a glyph surface larger than the extended maximum XRequest size.  */
    4200             :     {
    4201           0 :         int len = cairo_format_stride_for_width (glyphset_info->format, glyph_surface->width) * glyph_surface->height;
    4202           0 :         int max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display)
    4203           0 :                                                                            : XMaxRequestSize (display->display)) * 4 -
    4204             :                                sz_xRenderAddGlyphsReq -
    4205           0 :                                sz_xGlyphInfo          -
    4206             :                                8;
    4207           0 :         if (len >= max_request_size)
    4208           0 :             return UNSUPPORTED ("glyph too large for XRequest");
    4209             :     }
    4210             : 
    4211             :     /* If the glyph surface has zero height or width, we create
    4212             :      * a clear 1x1 surface, to avoid various X server bugs.
    4213             :      */
    4214           0 :     if (glyph_surface->width == 0 || glyph_surface->height == 0) {
    4215             :         cairo_surface_t *tmp_surface;
    4216             : 
    4217           0 :         tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
    4218           0 :         status = tmp_surface->status;
    4219           0 :         if (unlikely (status))
    4220           0 :             goto BAIL;
    4221             : 
    4222           0 :         tmp_surface->device_transform = glyph_surface->base.device_transform;
    4223           0 :         tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
    4224             : 
    4225           0 :         glyph_surface = (cairo_image_surface_t *) tmp_surface;
    4226             :     }
    4227             : 
    4228             :     /* If the glyph format does not match the font format, then we
    4229             :      * create a temporary surface for the glyph image with the font's
    4230             :      * format.
    4231             :      */
    4232           0 :     if (glyph_surface->format != glyphset_info->format) {
    4233             :         cairo_surface_pattern_t pattern;
    4234             :         cairo_surface_t *tmp_surface;
    4235             : 
    4236           0 :         tmp_surface = cairo_image_surface_create (glyphset_info->format,
    4237             :                                                   glyph_surface->width,
    4238             :                                                   glyph_surface->height);
    4239           0 :         status = tmp_surface->status;
    4240           0 :         if (unlikely (status))
    4241           0 :             goto BAIL;
    4242             : 
    4243           0 :         tmp_surface->device_transform = glyph_surface->base.device_transform;
    4244           0 :         tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
    4245             : 
    4246           0 :         _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
    4247           0 :         status = _cairo_surface_paint (tmp_surface,
    4248             :                                        CAIRO_OPERATOR_SOURCE, &pattern.base,
    4249             :                                        NULL);
    4250           0 :         _cairo_pattern_fini (&pattern.base);
    4251             : 
    4252           0 :         glyph_surface = (cairo_image_surface_t *) tmp_surface;
    4253             : 
    4254           0 :         if (unlikely (status))
    4255           0 :             goto BAIL;
    4256             :     }
    4257             : 
    4258             :     /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
    4259           0 :     glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
    4260           0 :     glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
    4261           0 :     glyph_info.width = glyph_surface->width;
    4262           0 :     glyph_info.height = glyph_surface->height;
    4263           0 :     glyph_info.xOff = scaled_glyph->x_advance;
    4264           0 :     glyph_info.yOff = scaled_glyph->y_advance;
    4265             : 
    4266           0 :     data = glyph_surface->data;
    4267             : 
    4268             :     /* flip formats around */
    4269           0 :     switch (_cairo_xlib_get_glyphset_index_for_format (scaled_glyph->surface->format)) {
    4270             :     case GLYPHSET_INDEX_A1:
    4271             :         /* local bitmaps are always stored with bit == byte */
    4272           0 :         if (_native_byte_order_lsb() != (BitmapBitOrder (display->display) == LSBFirst)) {
    4273           0 :             int             c = glyph_surface->stride * glyph_surface->height;
    4274             :             unsigned char   *d;
    4275             :             unsigned char   *new, *n;
    4276             : 
    4277           0 :             new = malloc (c);
    4278           0 :             if (!new) {
    4279           0 :                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4280           0 :                 goto BAIL;
    4281             :             }
    4282           0 :             n = new;
    4283           0 :             d = data;
    4284             :             do {
    4285           0 :                 char    b = *d++;
    4286           0 :                 b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
    4287           0 :                 b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
    4288           0 :                 b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
    4289           0 :                 *n++ = b;
    4290           0 :             } while (--c);
    4291           0 :             data = new;
    4292             :         }
    4293           0 :         break;
    4294             :     case GLYPHSET_INDEX_A8:
    4295           0 :         break;
    4296             :     case GLYPHSET_INDEX_ARGB32:
    4297           0 :         if (_native_byte_order_lsb() != (ImageByteOrder (display->display) == LSBFirst)) {
    4298           0 :             unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
    4299             :             const uint32_t *d;
    4300             :             uint32_t *new, *n;
    4301             : 
    4302           0 :             new = malloc (4 * c);
    4303           0 :             if (unlikely (new == NULL)) {
    4304           0 :                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4305           0 :                 goto BAIL;
    4306             :             }
    4307           0 :             n = new;
    4308           0 :             d = (uint32_t *) data;
    4309             :             do {
    4310           0 :                 *n++ = bswap_32 (*d);
    4311           0 :                 d++;
    4312           0 :             } while (--c);
    4313           0 :             data = (uint8_t *) new;
    4314             :         }
    4315           0 :         break;
    4316             :     default:
    4317           0 :         ASSERT_NOT_REACHED;
    4318           0 :         break;
    4319             :     }
    4320             :     /* XXX assume X server wants pixman padding. Xft assumes this as well */
    4321             : 
    4322           0 :     struct _XDisplay *dpy = (struct _XDisplay *) display->display;
    4323           0 :     int req_length = sz_xRenderAddGlyphsReq + 4;
    4324           0 :     if (req_length & 3)
    4325           0 :         req_length += 4 - (req_length & 3);
    4326           0 :     if (dpy->bufptr + req_length > dpy->bufmax)
    4327           0 :         XFlush (display->display);
    4328             : 
    4329           0 :     XRenderAddGlyphs (display->display, glyphset_info->glyphset,
    4330             :                       &glyph_index, &glyph_info, 1,
    4331             :                       (char *) data,
    4332           0 :                       glyph_surface->stride * glyph_surface->height);
    4333             : 
    4334           0 :     if (data != glyph_surface->data)
    4335           0 :         free (data);
    4336             : 
    4337           0 :     _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
    4338             : 
    4339             :  BAIL:
    4340           0 :     if (glyph_surface != scaled_glyph->surface)
    4341           0 :         cairo_surface_destroy (&glyph_surface->base);
    4342             : 
    4343             :     /* if the scaled glyph didn't already have a surface attached
    4344             :      * to it, release the created surface now that we have it
    4345             :      * uploaded to the X server.  If the surface has already been
    4346             :      * there (eg. because image backend requested it), leave it in
    4347             :      * the cache
    4348             :      */
    4349           0 :     if (!already_had_glyph_surface)
    4350           0 :         _cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
    4351             : 
    4352           0 :     return status;
    4353             : }
    4354             : 
    4355             : typedef void (*cairo_xrender_composite_text_func_t)
    4356             :               (Display                      *dpy,
    4357             :                int                          op,
    4358             :                Picture                      src,
    4359             :                Picture                      dst,
    4360             :                _Xconst XRenderPictFormat    *maskFormat,
    4361             :                int                          xSrc,
    4362             :                int                          ySrc,
    4363             :                int                          xDst,
    4364             :                int                          yDst,
    4365             :                _Xconst XGlyphElt8           *elts,
    4366             :                int                          nelt);
    4367             : 
    4368             : /* Build a struct of the same size of #cairo_glyph_t that can be used both as
    4369             :  * an input glyph with double coordinates, and as "working" glyph with
    4370             :  * integer from-current-point offsets. */
    4371             : typedef union {
    4372             :     cairo_glyph_t d;
    4373             :     unsigned long index;
    4374             :     struct {
    4375             :         unsigned long index;
    4376             :         int x;
    4377             :         int y;
    4378             :     } i;
    4379             : } cairo_xlib_glyph_t;
    4380             : 
    4381             : /* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
    4382             : COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
    4383             : 
    4384             : /* Start a new element for the first glyph,
    4385             :  * or for any glyph that has unexpected position,
    4386             :  * or if current element has too many glyphs
    4387             :  * (Xrender limits each element to 252 glyphs, we limit them to 128)
    4388             :  *
    4389             :  * These same conditions need to be mirrored between
    4390             :  * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
    4391             :  */
    4392             : #define _start_new_glyph_elt(count, glyph) \
    4393             :     (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
    4394             : 
    4395             : static cairo_status_t
    4396           0 : _emit_glyphs_chunk (cairo_xlib_display_t *display,
    4397             :                     cairo_xlib_surface_t *dst,
    4398             :                     cairo_xlib_glyph_t *glyphs,
    4399             :                     int num_glyphs,
    4400             :                     cairo_scaled_font_t *scaled_font,
    4401             :                     cairo_operator_t op,
    4402             :                     cairo_xlib_surface_t *src,
    4403             :                     cairo_surface_attributes_t *attributes,
    4404             :                     /* info for this chunk */
    4405             :                     int num_elts,
    4406             :                     int width,
    4407             :                     cairo_xlib_font_glyphset_info_t *glyphset_info)
    4408             : {
    4409             :     /* Which XRenderCompositeText function to use */
    4410             :     cairo_xrender_composite_text_func_t composite_text_func;
    4411             :     int size;
    4412             : 
    4413             :     /* Element buffer stuff */
    4414             :     XGlyphElt8 *elts;
    4415             :     XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
    4416             : 
    4417             :     /* Reuse the input glyph array for output char generation */
    4418           0 :     char *char8 = (char *) glyphs;
    4419           0 :     unsigned short *char16 = (unsigned short *) glyphs;
    4420           0 :     unsigned int *char32 = (unsigned int *) glyphs;
    4421             : 
    4422             :     int i;
    4423             :     int nelt; /* Element index */
    4424             :     int n; /* Num output glyphs in current element */
    4425             :     int j; /* Num output glyphs so far */
    4426             : 
    4427           0 :     switch (width) {
    4428             :     case 1:
    4429             :         /* don't cast the 8-variant, to catch possible mismatches */
    4430           0 :         composite_text_func = XRenderCompositeText8;
    4431           0 :         size = sizeof (char);
    4432           0 :         break;
    4433             :     case 2:
    4434           0 :         composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
    4435           0 :         size = sizeof (unsigned short);
    4436           0 :         break;
    4437             :     default:
    4438             :     case 4:
    4439           0 :         composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
    4440           0 :         size = sizeof (unsigned int);
    4441             :     }
    4442             : 
    4443             :     /* Allocate element array */
    4444           0 :     if (num_elts <= ARRAY_LENGTH (stack_elts)) {
    4445           0 :       elts = stack_elts;
    4446             :     } else {
    4447           0 :       elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
    4448           0 :       if (unlikely (elts == NULL))
    4449           0 :           return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    4450             :     }
    4451             : 
    4452             :     /* Fill them in */
    4453           0 :     nelt = 0;
    4454           0 :     n = 0;
    4455           0 :     j = 0;
    4456           0 :     for (i = 0; i < num_glyphs; i++) {
    4457             : 
    4458             :       /* Start a new element for first output glyph,
    4459             :        * or for any glyph that has unexpected position,
    4460             :        * or if current element has too many glyphs.
    4461             :        *
    4462             :        * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
    4463             :        */
    4464           0 :       if (_start_new_glyph_elt (j, &glyphs[i])) {
    4465           0 :           if (j) {
    4466           0 :             elts[nelt].nchars = n;
    4467           0 :             nelt++;
    4468           0 :             n = 0;
    4469             :           }
    4470           0 :           elts[nelt].chars = char8 + size * j;
    4471           0 :           elts[nelt].glyphset = glyphset_info->glyphset;
    4472           0 :           elts[nelt].xOff = glyphs[i].i.x;
    4473           0 :           elts[nelt].yOff = glyphs[i].i.y;
    4474             :       }
    4475             : 
    4476           0 :       switch (width) {
    4477           0 :       case 1: char8 [j] = (char)           glyphs[i].index; break;
    4478           0 :       case 2: char16[j] = (unsigned short) glyphs[i].index; break;
    4479             :       default:
    4480           0 :       case 4: char32[j] = (unsigned int)   glyphs[i].index; break;
    4481             :       }
    4482             : 
    4483           0 :       n++;
    4484           0 :       j++;
    4485             :     }
    4486             : 
    4487           0 :     if (n) {
    4488           0 :         elts[nelt].nchars = n;
    4489           0 :         nelt++;
    4490             :     }
    4491             : 
    4492             :     /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
    4493             :      * expected number of xGlyphElts.  */
    4494           0 :     assert (nelt == num_elts);
    4495             : 
    4496           0 :     composite_text_func (display->display,
    4497             :                          _render_operator (op),
    4498             :                          src->src_picture,
    4499             :                          dst->dst_picture,
    4500           0 :                          glyphset_info->xrender_format,
    4501           0 :                          attributes->x_offset + elts[0].xOff,
    4502           0 :                          attributes->y_offset + elts[0].yOff,
    4503             :                          elts[0].xOff, elts[0].yOff,
    4504             :                          (XGlyphElt8 *) elts, nelt);
    4505             : 
    4506           0 :     if (elts != stack_elts)
    4507           0 :       free (elts);
    4508             : 
    4509           0 :     return CAIRO_STATUS_SUCCESS;
    4510             : }
    4511             : 
    4512             : 
    4513             : /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
    4514             :  * enough room for padding */
    4515             : #define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
    4516             : 
    4517             : static cairo_status_t
    4518           0 : _cairo_xlib_surface_emit_glyphs (cairo_xlib_display_t *display,
    4519             :                                  cairo_xlib_surface_t *dst,
    4520             :                                  cairo_xlib_glyph_t *glyphs,
    4521             :                                  int num_glyphs,
    4522             :                                  cairo_scaled_font_t *scaled_font,
    4523             :                                  cairo_operator_t op,
    4524             :                                  cairo_xlib_surface_t *src,
    4525             :                                  cairo_surface_attributes_t *attributes,
    4526             :                                  int *remaining_glyphs)
    4527             : {
    4528             :     int i;
    4529           0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
    4530             :     cairo_scaled_glyph_t *scaled_glyph;
    4531           0 :     cairo_fixed_t x = 0, y = 0;
    4532           0 :     cairo_xlib_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
    4533             : 
    4534           0 :     unsigned long max_index = 0;
    4535           0 :     int width = 1;
    4536           0 :     int num_elts = 0;
    4537           0 :     int num_out_glyphs = 0;
    4538             : 
    4539           0 :     int max_request_size = XMaxRequestSize (display->display) * 4
    4540           0 :                          - MAX (sz_xRenderCompositeGlyphs8Req,
    4541             :                                 MAX(sz_xRenderCompositeGlyphs16Req,
    4542             :                                     sz_xRenderCompositeGlyphs32Req));
    4543           0 :     int request_size = 0;
    4544             : 
    4545           0 :     _cairo_xlib_surface_ensure_dst_picture (display, dst);
    4546             : 
    4547           0 :     for (i = 0; i < num_glyphs; i++) {
    4548             :         int this_x, this_y;
    4549             :         int old_width;
    4550             : 
    4551           0 :         status = _cairo_scaled_glyph_lookup (scaled_font,
    4552           0 :                                              glyphs[i].index,
    4553             :                                              CAIRO_SCALED_GLYPH_INFO_METRICS,
    4554             :                                              &scaled_glyph);
    4555           0 :         if (unlikely (status))
    4556           0 :             return status;
    4557             : 
    4558           0 :         this_x = _cairo_lround (glyphs[i].d.x);
    4559           0 :         this_y = _cairo_lround (glyphs[i].d.y);
    4560             : 
    4561             :         /* Glyph skipping:
    4562             :          *
    4563             :          * We skip any glyphs that have troublesome coordinates.  We want
    4564             :          * to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in
    4565             :          * a signed 16bit integer, otherwise it will overflow in the render
    4566             :          * protocol.
    4567             :          * To ensure this, we'll make sure that (glyph2.x - glyph1.x) fits in
    4568             :          * a signed 15bit integer.  The trivial option would be to allow
    4569             :          * coordinates -8192..8192, but that's kinda dull.  It probably will
    4570             :          * take a decade or so to get monitors 8192x4096 or something.  A
    4571             :          * negative value of -8192 on the other hand, is absolutely useless.
    4572             :          * Note that we do want to allow some negative positions.  The glyph
    4573             :          * may start off the screen but part of it make it to the screen.
    4574             :          * Anyway, we will allow positions in the range -4096..122887.  That
    4575             :          * will buy us a few more years before this stops working.
    4576             :          *
    4577             :          * Update: upon seeing weird glyphs, we just return and let fallback
    4578             :          * code do the job.
    4579             :          */
    4580           0 :         if (((this_x+4096)|(this_y+4096))&~0x3fffu)
    4581           0 :             break;
    4582             : 
    4583             :         /* Send unsent glyphs to the server */
    4584           0 :         if (_cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) {
    4585           0 :             status = _cairo_xlib_surface_add_glyph (display,
    4586             :                                                     scaled_font,
    4587             :                                                     &scaled_glyph);
    4588           0 :             if (unlikely (status)) {
    4589           0 :                 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
    4590             :                     /* Break so we flush glyphs so far and let fallback code
    4591             :                      * handle the rest */
    4592           0 :                     break;
    4593             : 
    4594           0 :                 return status;
    4595             :             }
    4596             :         }
    4597             : 
    4598           0 :         this_glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
    4599           0 :         if (!glyphset_info)
    4600           0 :             glyphset_info = this_glyphset_info;
    4601             : 
    4602             :         /* The invariant here is that we can always flush the glyphs
    4603             :          * accumulated before this one, using old_width, and they
    4604             :          * would fit in the request.
    4605             :          */
    4606           0 :         old_width = width;
    4607             : 
    4608             :         /* Update max glyph index */
    4609           0 :         if (glyphs[i].index > max_index) {
    4610           0 :             max_index = glyphs[i].index;
    4611           0 :             if (max_index >= 65536)
    4612           0 :               width = 4;
    4613           0 :             else if (max_index >= 256)
    4614           0 :               width = 2;
    4615           0 :             if (width != old_width)
    4616           0 :               request_size += (width - old_width) * num_out_glyphs;
    4617             :         }
    4618             : 
    4619             :         /* If we will pass the max request size by adding this glyph,
    4620             :          * flush current glyphs.  Note that we account for a
    4621             :          * possible element being added below.
    4622             :          *
    4623             :          * Also flush if changing glyphsets, as Xrender limits one mask
    4624             :          * format per request, so we can either break up, or use a
    4625             :          * wide-enough mask format.  We do the former.  One reason to
    4626             :          * prefer the latter is the fact that Xserver ADDs all glyphs
    4627             :          * to the mask first, and then composes that to final surface,
    4628             :          * though it's not a big deal.
    4629             :          */
    4630           0 :         if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
    4631             :             (this_glyphset_info != glyphset_info)) {
    4632           0 :             status = _emit_glyphs_chunk (display, dst, glyphs, i,
    4633             :                                          scaled_font, op, src, attributes,
    4634             :                                          num_elts, old_width, glyphset_info);
    4635           0 :             if (unlikely (status))
    4636           0 :                 return status;
    4637             : 
    4638           0 :             glyphs += i;
    4639           0 :             num_glyphs -= i;
    4640           0 :             i = 0;
    4641           0 :             max_index = glyphs[i].index;
    4642           0 :             width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
    4643           0 :             request_size = 0;
    4644           0 :             num_elts = 0;
    4645           0 :             num_out_glyphs = 0;
    4646           0 :             x = y = 0;
    4647           0 :             glyphset_info = this_glyphset_info;
    4648             :         }
    4649             : 
    4650             :         /* Convert absolute glyph position to relative-to-current-point
    4651             :          * position */
    4652           0 :         glyphs[i].i.x = this_x - x;
    4653           0 :         glyphs[i].i.y = this_y - y;
    4654             : 
    4655             :         /* Start a new element for the first glyph,
    4656             :          * or for any glyph that has unexpected position,
    4657             :          * or if current element has too many glyphs.
    4658             :          *
    4659             :          * These same conditions are mirrored in _emit_glyphs_chunk().
    4660             :          */
    4661           0 :       if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
    4662           0 :             num_elts++;
    4663           0 :             request_size += _cairo_sz_xGlyphElt;
    4664             :         }
    4665             : 
    4666             :         /* adjust current-position */
    4667           0 :         x = this_x + scaled_glyph->x_advance;
    4668           0 :         y = this_y + scaled_glyph->y_advance;
    4669             : 
    4670           0 :         num_out_glyphs++;
    4671           0 :         request_size += width;
    4672             :     }
    4673             : 
    4674           0 :     if (num_elts) {
    4675           0 :         status = _emit_glyphs_chunk (display, dst, glyphs, i,
    4676             :                                      scaled_font, op, src, attributes,
    4677             :                                      num_elts, width, glyphset_info);
    4678             :     }
    4679             : 
    4680           0 :     *remaining_glyphs = num_glyphs - i;
    4681           0 :     if (*remaining_glyphs != 0 && status == CAIRO_STATUS_SUCCESS)
    4682           0 :         status = CAIRO_INT_STATUS_UNSUPPORTED;
    4683             : 
    4684           0 :     return status;
    4685             : }
    4686             : 
    4687             : static cairo_bool_t
    4688           0 : _cairo_xlib_surface_owns_font (cairo_xlib_surface_t *dst,
    4689             :                                cairo_scaled_font_t *scaled_font)
    4690             : {
    4691             :     cairo_xlib_surface_font_private_t *font_private;
    4692             : 
    4693           0 :     font_private = scaled_font->surface_private;
    4694           0 :     if ((scaled_font->surface_backend != NULL &&
    4695           0 :          scaled_font->surface_backend != &cairo_xlib_surface_backend) ||
    4696           0 :         (font_private != NULL && font_private->device != dst->base.device))
    4697             :     {
    4698           0 :         return FALSE;
    4699             :     }
    4700             : 
    4701           0 :     return TRUE;
    4702             : }
    4703             : 
    4704             : /* Gets a grayscale version of scaled_font. The grayscale version is cached
    4705             :  * in our surface_private data.
    4706             :  */
    4707             : static cairo_scaled_font_t *
    4708           0 : _cairo_xlib_get_grayscale_font (cairo_xlib_display_t *display,
    4709             :                                 cairo_scaled_font_t *scaled_font)
    4710             : {
    4711           0 :     cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
    4712             :     cairo_bool_t needs_font;
    4713             : 
    4714           0 :     if (font_private == NULL) {
    4715           0 :         cairo_status_t status = _cairo_xlib_surface_font_init (display, scaled_font);
    4716           0 :         if (unlikely (status))
    4717           0 :             return _cairo_scaled_font_create_in_error (status);
    4718           0 :         font_private = scaled_font->surface_private;
    4719             :     }
    4720             : 
    4721           0 :     CAIRO_MUTEX_LOCK (scaled_font->mutex);
    4722           0 :     needs_font = !font_private->grayscale_font;
    4723           0 :     CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
    4724             : 
    4725           0 :     if (needs_font) {
    4726             :         cairo_font_options_t options;
    4727             :         cairo_scaled_font_t *new_font;
    4728             : 
    4729           0 :         options = scaled_font->options;
    4730           0 :         options.antialias = CAIRO_ANTIALIAS_GRAY;
    4731           0 :         new_font = cairo_scaled_font_create (scaled_font->font_face,
    4732           0 :                                              &scaled_font->font_matrix,
    4733           0 :                                              &scaled_font->ctm, &options);
    4734             : 
    4735           0 :         CAIRO_MUTEX_LOCK (scaled_font->mutex);
    4736           0 :         if (!font_private->grayscale_font) {
    4737           0 :             font_private->grayscale_font = new_font;
    4738           0 :             new_font = NULL;
    4739             :         }
    4740           0 :         CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
    4741             : 
    4742           0 :         if (new_font) {
    4743           0 :             cairo_scaled_font_destroy (new_font);
    4744             :         }
    4745             :     }
    4746             : 
    4747           0 :     return font_private->grayscale_font;
    4748             : }
    4749             : 
    4750             : static cairo_int_status_t
    4751           0 : _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
    4752             :                                  cairo_operator_t     op,
    4753             :                                  const cairo_pattern_t *src_pattern,
    4754             :                                  cairo_glyph_t       *glyphs,
    4755             :                                  int                  num_glyphs,
    4756             :                                  cairo_scaled_font_t *scaled_font,
    4757             :                                  cairo_clip_t        *clip,
    4758             :                                  int                 *remaining_glyphs)
    4759             : {
    4760           0 :     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
    4761           0 :     cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst;
    4762             :     composite_operation_t operation;
    4763             :     cairo_surface_attributes_t attributes;
    4764           0 :     cairo_xlib_surface_t *src = NULL;
    4765           0 :     cairo_region_t *clip_region = NULL;
    4766             :     cairo_xlib_display_t *display;
    4767             : 
    4768           0 :     if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst))
    4769           0 :         return UNSUPPORTED ("XRender does not support CompositeText");
    4770             : 
    4771             :     /* Just let unbounded operators go through the fallback code
    4772             :      * instead of trying to do the fixups here */
    4773           0 :     if (! _cairo_operator_bounded_by_mask (op))
    4774           0 :         return UNSUPPORTED ("unsupported unbounded op");
    4775             : 
    4776             :     /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
    4777             :      * the solid source seems to be multiplied by the glyph mask, and
    4778             :      * then the entire thing is copied to the destination surface,
    4779             :      * including the fully transparent "background" of the rectangular
    4780             :      * glyph surface. */
    4781           0 :     if (op == CAIRO_OPERATOR_SOURCE &&
    4782           0 :         ! CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
    4783             :     {
    4784           0 :         return UNSUPPORTED ("known bug in Render");
    4785             :     }
    4786             : 
    4787             :     /* We can only use our code if we either have no clip or
    4788             :      * have a real native clip region set.  If we're using
    4789             :      * fallback clip masking, we have to go through the full
    4790             :      * fallback path.
    4791             :      */
    4792           0 :     if (clip != NULL) {
    4793           0 :         status = _cairo_clip_get_region (clip, &clip_region);
    4794           0 :         assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
    4795           0 :         if (status)
    4796           0 :             return status;
    4797             :     }
    4798             : 
    4799           0 :     operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
    4800           0 :     if (operation == DO_UNSUPPORTED)
    4801           0 :         return UNSUPPORTED ("unsupported op");
    4802             : 
    4803           0 :     if (! _cairo_xlib_surface_owns_font (dst, scaled_font))
    4804           0 :         return UNSUPPORTED ("unowned font");
    4805             : 
    4806             : 
    4807           0 :     status = _cairo_xlib_display_acquire (dst->base.device, &display);
    4808           0 :     if (unlikely (status))
    4809           0 :         return status;
    4810             : 
    4811           0 :     if (!dst->base.permit_subpixel_antialiasing &&
    4812           0 :         scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL) {
    4813           0 :         scaled_font = _cairo_xlib_get_grayscale_font (display, scaled_font);
    4814             :     }
    4815             : 
    4816             :     X_DEBUG ((display->display, "show_glyphs (dst=%x)", (unsigned int) dst->drawable));
    4817             : 
    4818           0 :     if (clip_region != NULL &&
    4819           0 :         cairo_region_num_rectangles (clip_region) == 1)
    4820             :     {
    4821             :         cairo_rectangle_int_t glyph_extents;
    4822             :         cairo_rectangle_int_t clip_extents;
    4823             : 
    4824             :         /* Can we do without the clip?
    4825             :          * Around 50% of the time the clip is redundant (firefox).
    4826             :          */
    4827           0 :         _cairo_scaled_font_glyph_approximate_extents (scaled_font,
    4828             :                                                       glyphs, num_glyphs,
    4829             :                                                       &glyph_extents);
    4830             : 
    4831           0 :         cairo_region_get_extents(clip_region, &clip_extents);
    4832           0 :         if (clip_extents.x <= glyph_extents.x &&
    4833           0 :             clip_extents.y <= glyph_extents.y &&
    4834           0 :             clip_extents.x + clip_extents.width  >= glyph_extents.x + glyph_extents.width &&
    4835           0 :             clip_extents.y + clip_extents.height >= glyph_extents.y + glyph_extents.height)
    4836             :         {
    4837           0 :             clip_region = NULL;
    4838             :         }
    4839             :     }
    4840             : 
    4841           0 :     status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
    4842           0 :     if (unlikely (status))
    4843           0 :         goto BAIL0;
    4844             : 
    4845             :     /* After passing all those tests, we're now committed to rendering
    4846             :      * these glyphs or to fail trying. We first upload any glyphs to
    4847             :      * the X server that it doesn't have already, then we draw
    4848             :      * them.
    4849             :      */
    4850             : 
    4851             :     /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
    4852             :      * the mask (the glyphs).  This code below was executed as a side effect
    4853             :      * of going through the _clip_and_composite fallback code for old_show_glyphs,
    4854             :      * so PictOpClear was never used with CompositeText before.
    4855             :      */
    4856           0 :     if (op == CAIRO_OPERATOR_CLEAR) {
    4857           0 :         src_pattern = &_cairo_pattern_white.base;
    4858           0 :         op = CAIRO_OPERATOR_DEST_OUT;
    4859             :     }
    4860             : 
    4861           0 :     if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
    4862           0 :         status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
    4863             :                                                  0, 0, 1, 1,
    4864             :                                                  CAIRO_PATTERN_ACQUIRE_NONE,
    4865             :                                                  (cairo_surface_t **) &src,
    4866             :                                                  &attributes);
    4867           0 :         if (unlikely (status))
    4868           0 :             goto BAIL0;
    4869             :     } else {
    4870             :         cairo_rectangle_int_t glyph_extents;
    4871             : 
    4872           0 :         status = _cairo_scaled_font_glyph_device_extents (scaled_font,
    4873             :                                                           glyphs,
    4874             :                                                           num_glyphs,
    4875             :                                                           &glyph_extents,
    4876             :                                                           NULL);
    4877           0 :         if (unlikely (status))
    4878           0 :             goto BAIL0;
    4879             : 
    4880           0 :         if (clip != NULL) {
    4881           0 :             if (! _cairo_rectangle_intersect (&glyph_extents,
    4882             :                                               _cairo_clip_get_extents (clip)))
    4883             :             {
    4884           0 :                 goto BAIL0;
    4885             :             }
    4886             :         }
    4887             : 
    4888           0 :         status = _cairo_xlib_surface_acquire_pattern_surface (display,
    4889             :                                                               dst, src_pattern,
    4890             :                                                               glyph_extents.x,
    4891             :                                                               glyph_extents.y,
    4892             :                                                               glyph_extents.width,
    4893             :                                                               glyph_extents.height,
    4894             :                                                               &src, &attributes);
    4895           0 :         if (unlikely (status))
    4896           0 :             goto BAIL0;
    4897             :     }
    4898             : 
    4899           0 :     operation = _recategorize_composite_operation (dst, op, src,
    4900             :                                                    &attributes, TRUE);
    4901           0 :     if (operation == DO_UNSUPPORTED) {
    4902           0 :         status = UNSUPPORTED ("unsupported op");
    4903           0 :         goto BAIL1;
    4904             :     }
    4905             : 
    4906           0 :     status = _cairo_xlib_surface_set_attributes (display, src, &attributes, 0, 0);
    4907           0 :     if (unlikely (status))
    4908           0 :         goto BAIL1;
    4909             : 
    4910           0 :     _cairo_scaled_font_freeze_cache (scaled_font);
    4911           0 :     if (_cairo_xlib_surface_owns_font (dst, scaled_font)) {
    4912           0 :         status = _cairo_xlib_surface_emit_glyphs (display,
    4913             :                                                   dst,
    4914             :                                                   (cairo_xlib_glyph_t *) glyphs,
    4915             :                                                   num_glyphs,
    4916             :                                                   scaled_font,
    4917             :                                                   op,
    4918             :                                                   src,
    4919             :                                                   &attributes,
    4920             :                                                   remaining_glyphs);
    4921             :     } else {
    4922           0 :         status = UNSUPPORTED ("unowned font");
    4923             :     }
    4924           0 :     _cairo_scaled_font_thaw_cache (scaled_font);
    4925             : 
    4926             :   BAIL1:
    4927           0 :     if (src)
    4928           0 :         _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
    4929             :   BAIL0:
    4930           0 :     cairo_device_release (&display->base);
    4931             : 
    4932           0 :     return status;
    4933             : }

Generated by: LCOV version 1.13