LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-xlib-surface.c (source / functions) Found Hit Coverage
Test: app.info Lines: 1953 0 0.0 %
Date: 2012-06-02 Functions: 96 0 0.0 %

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

Generated by: LCOV version 1.7