Back to index

lightning-sunbird  0.9+nobinonly
cairo-xlib-surface.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2002 University of Southern California
00004  * Copyright © 2005 Red Hat, Inc.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it either under the terms of the GNU Lesser General Public
00008  * License version 2.1 as published by the Free Software Foundation
00009  * (the "LGPL") or, at your option, under the terms of the Mozilla
00010  * Public License Version 1.1 (the "MPL"). If you do not alter this
00011  * notice, a recipient may use your version of this file under either
00012  * the MPL or the LGPL.
00013  *
00014  * You should have received a copy of the LGPL along with this library
00015  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00017  * You should have received a copy of the MPL along with this library
00018  * in the file COPYING-MPL-1.1
00019  *
00020  * The contents of this file are subject to the Mozilla Public License
00021  * Version 1.1 (the "License"); you may not use this file except in
00022  * compliance with the License. You may obtain a copy of the License at
00023  * http://www.mozilla.org/MPL/
00024  *
00025  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00026  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00027  * the specific language governing rights and limitations.
00028  *
00029  * The Original Code is the cairo graphics library.
00030  *
00031  * The Initial Developer of the Original Code is University of Southern
00032  * California.
00033  *
00034  * Contributor(s):
00035  *     Carl D. Worth <cworth@cworth.org>
00036  */
00037 
00038 #include "cairoint.h"
00039 #include "cairo-xlib.h"
00040 #include "cairo-xlib-xrender.h"
00041 #include "cairo-xlib-test.h"
00042 #include "cairo-xlib-private.h"
00043 #include <X11/extensions/Xrender.h>
00044 
00045 /* Xlib doesn't define a typedef, so define one ourselves */
00046 typedef int (*cairo_xlib_error_func_t) (Display     *display,
00047                                    XErrorEvent *event);
00048 
00049 typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
00050 
00051 static void
00052 _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
00053 
00054 static void 
00055 _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface);
00056 
00057 static void 
00058 _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface);
00059 
00060 static cairo_bool_t
00061 _cairo_surface_is_xlib (cairo_surface_t *surface);
00062 
00063 static cairo_bool_t
00064 _native_byte_order_lsb (void);
00065 
00066 /*
00067  * Instead of taking two round trips for each blending request,
00068  * assume that if a particular drawable fails GetImage that it will
00069  * fail for a "while"; use temporary pixmaps to avoid the errors
00070  */
00071 
00072 #define CAIRO_ASSUME_PIXMAP 20
00073 
00074 struct _cairo_xlib_surface {
00075     cairo_surface_t base;
00076 
00077     Display *dpy;
00078     cairo_xlib_screen_info_t *screen_info;
00079   
00080     GC gc;
00081     Drawable drawable;
00082     Screen *screen;
00083     cairo_bool_t owns_pixmap;
00084     Visual *visual;
00085     
00086     int use_pixmap;
00087 
00088     int render_major;
00089     int render_minor;
00090 
00091     /* TRUE if the server has a bug with repeating pictures
00092      *
00093      *  https://bugs.freedesktop.org/show_bug.cgi?id=3566
00094      *
00095      * We can't test for this because it depends on whether the
00096      * picture is in video memory or not.
00097      *
00098      * We also use this variable as a guard against a second
00099      * independent bug with transformed repeating pictures:
00100      *
00101      * http://lists.freedesktop.org/archives/cairo/2004-September/001839.html
00102      *
00103      * Both are fixed in xorg >= 6.9 and hopefully in > 6.8.2, so
00104      * we can reuse the test for now.
00105      */ 
00106     cairo_bool_t buggy_repeat;
00107 
00108     int width;
00109     int height;
00110     int depth;
00111 
00112     Picture dst_picture, src_picture;
00113 
00114     cairo_bool_t have_clip_rects;
00115     XRectangle *clip_rects;
00116     int num_clip_rects;
00117 
00118     XRenderPictFormat *format;
00119 };
00120 
00121 #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor)   \
00122        (((surface)->render_major > major) ||                   \
00123         (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
00124 
00125 #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface)              CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
00126 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface)            CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
00127 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface)       CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
00128 
00129 
00130 #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface)              CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
00131 #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface)             CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
00132 
00133 #define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface)                    CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
00134 #define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface)                    CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
00135 
00136 #define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface)           CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
00137 #define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface)            CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
00138 #define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface)                    CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
00139 #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface)               CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
00140 
00141 #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface)    CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
00142 #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)       CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
00143 
00144 static cairo_bool_t cairo_xlib_render_disabled = FALSE;
00145 
00157 void
00158 cairo_test_xlib_disable_render (void)
00159 {
00160     cairo_xlib_render_disabled = TRUE;
00161 }
00162 
00163 static int
00164 _CAIRO_FORMAT_DEPTH (cairo_format_t format)
00165 {
00166     switch (format) {
00167     case CAIRO_FORMAT_A1:
00168        return 1;
00169     case CAIRO_FORMAT_A8:
00170        return 8;
00171     case CAIRO_FORMAT_RGB24:
00172        return 24;
00173     case CAIRO_FORMAT_ARGB32:
00174     default:
00175        return 32;
00176     }
00177 }
00178 
00179 static XRenderPictFormat *
00180 _CAIRO_FORMAT_XRENDER_FORMAT(Display *dpy, cairo_format_t format)
00181 {
00182     int       pict_format;
00183     switch (format) {
00184     case CAIRO_FORMAT_A1:
00185        pict_format = PictStandardA1; break;
00186     case CAIRO_FORMAT_A8:
00187        pict_format = PictStandardA8; break;
00188     case CAIRO_FORMAT_RGB24:
00189        pict_format = PictStandardRGB24; break;
00190     case CAIRO_FORMAT_ARGB32:
00191     default:
00192        pict_format = PictStandardARGB32; break;
00193     }
00194     return XRenderFindStandardFormat (dpy, pict_format);
00195 }
00196 
00197 static cairo_surface_t *
00198 _cairo_xlib_surface_create_similar (void         *abstract_src,
00199                                 cairo_content_t  content,
00200                                 int                     width,
00201                                 int                     height)
00202 {
00203     cairo_xlib_surface_t *src = abstract_src;
00204     Display *dpy = src->dpy;
00205     Pixmap pix;
00206     cairo_xlib_surface_t *surface;
00207     cairo_format_t format = _cairo_format_from_content (content);
00208     int depth = _CAIRO_FORMAT_DEPTH (format);
00209     XRenderPictFormat *xrender_format = _CAIRO_FORMAT_XRENDER_FORMAT (dpy, 
00210                                                               format);
00211 
00212     /* As a good first approximation, if the display doesn't have COMPOSITE,
00213      * we're better off using image surfaces for all temporary operations
00214      */
00215     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE(src)) {
00216        return cairo_image_surface_create (format, width, height);
00217     }
00218     
00219     pix = XCreatePixmap (dpy, RootWindowOfScreen (src->screen),
00220                       width <= 0 ? 1 : width, height <= 0 ? 1 : height,
00221                       depth);
00222     
00223     surface = (cairo_xlib_surface_t *)
00224        cairo_xlib_surface_create_with_xrender_format (dpy, pix, src->screen,
00225                                                  xrender_format,
00226                                                  width, height);
00227     if (surface->base.status) {
00228        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00229        return (cairo_surface_t*) &_cairo_surface_nil;
00230     }
00231                              
00232     surface->owns_pixmap = TRUE;
00233 
00234     return &surface->base;
00235 }
00236 
00237 static cairo_status_t
00238 _cairo_xlib_surface_finish (void *abstract_surface)
00239 {
00240     cairo_xlib_surface_t *surface = abstract_surface;
00241     if (surface->dst_picture)
00242        XRenderFreePicture (surface->dpy, surface->dst_picture);
00243     
00244     if (surface->src_picture)
00245        XRenderFreePicture (surface->dpy, surface->src_picture);
00246 
00247     if (surface->owns_pixmap)
00248        XFreePixmap (surface->dpy, surface->drawable);
00249 
00250     if (surface->gc)
00251        XFreeGC (surface->dpy, surface->gc);
00252 
00253     if (surface->clip_rects)
00254        free (surface->clip_rects);
00255 
00256     surface->dpy = NULL;
00257 
00258     return CAIRO_STATUS_SUCCESS;
00259 }
00260 
00261 static int
00262 _noop_error_handler (Display     *display,
00263                    XErrorEvent *event)
00264 {
00265     return False;           /* return value is ignored */
00266 }
00267 
00268 static cairo_bool_t
00269 _CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
00270 {
00271     switch (masks->bpp) {
00272     case 32:
00273        if (masks->alpha_mask == 0xff000000 &&
00274            masks->red_mask == 0x00ff0000 &&
00275            masks->green_mask == 0x0000ff00 &&
00276            masks->blue_mask == 0x000000ff)
00277        {
00278            *format = CAIRO_FORMAT_ARGB32;
00279            return True;
00280        }
00281        if (masks->alpha_mask == 0x00000000 &&
00282            masks->red_mask == 0x00ff0000 &&
00283            masks->green_mask == 0x0000ff00 &&
00284            masks->blue_mask == 0x000000ff)
00285        {
00286            *format = CAIRO_FORMAT_RGB24;
00287            return True;
00288        }
00289        break;
00290     case 8:
00291        if (masks->alpha_mask == 0xff)
00292        {
00293            *format = CAIRO_FORMAT_A8;
00294            return True;
00295        }
00296        break;
00297     case 1:
00298        if (masks->alpha_mask == 0x1)
00299        {
00300            *format = CAIRO_FORMAT_A1;
00301            return True;
00302        }
00303        break;
00304     }
00305     return False;
00306 }
00307 
00308 static void
00309 _swap_ximage_2bytes (XImage *ximage)
00310 {
00311     int i, j;
00312     char *line = ximage->data;
00313 
00314     for (j = ximage->height; j; j--) {
00315        uint16_t *p = (uint16_t *)line;
00316        for (i = ximage->width; i; i--) {
00317            *p = (((*p & 0x00ff) << 8) |
00318                 ((*p)          >> 8));
00319            p++;
00320        }
00321 
00322        line += ximage->bytes_per_line;
00323     }
00324 }
00325 
00326 static void
00327 _swap_ximage_4bytes (XImage *ximage)
00328 {
00329     int i, j;
00330     char *line = ximage->data;
00331 
00332     for (j = ximage->height; j; j--) {
00333        uint32_t *p = (uint32_t *)line;
00334        for (i = ximage->width; i; i--) {
00335            *p = (((*p & 0x000000ff) << 24) |
00336                 ((*p & 0x0000ff00) << 8) |
00337                 ((*p & 0x00ff0000) >> 8) |
00338                 ((*p)              >> 24));
00339            p++;
00340        }
00341 
00342        line += ximage->bytes_per_line;
00343     }
00344 }
00345 
00346 static void
00347 _swap_ximage_bits (XImage *ximage)
00348 {
00349     int i, j;
00350     char *line = ximage->data;
00351     int unit = ximage->bitmap_unit;
00352     int line_bytes = ((ximage->width + unit - 1) & ~(unit - 1)) / 8;
00353 
00354     for (j = ximage->height; j; j--) {
00355        char *p = line;
00356        
00357        for (i = line_bytes; i; i--) {
00358            char b = *p;
00359            b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
00360            b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
00361            b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
00362            *p = b;
00363            
00364            p++;
00365        }
00366 
00367        line += ximage->bytes_per_line;
00368     }
00369 }
00370 
00371 static void
00372 _swap_ximage_to_native (XImage *ximage)
00373 {
00374     int unit_bytes = 0;
00375     int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
00376 
00377     if (ximage->bits_per_pixel == 1 &&
00378        ximage->bitmap_bit_order != native_byte_order) {
00379        _swap_ximage_bits (ximage);
00380        if (ximage->bitmap_bit_order == ximage->byte_order)
00381            return;
00382     }
00383     
00384     if (ximage->byte_order == native_byte_order)
00385        return;
00386 
00387     switch (ximage->bits_per_pixel) {
00388     case 1:
00389        unit_bytes = ximage->bitmap_unit / 8;
00390        break;
00391     case 8:
00392     case 16:
00393     case 32:
00394        unit_bytes = ximage->bits_per_pixel / 8;
00395        break;
00396     default:
00397         /* This could be hit on some uncommon but possible cases,
00398         * such as bpp=4. These are cases that libpixman can't deal
00399         * with in any case.
00400         */
00401        ASSERT_NOT_REACHED;
00402     }
00403 
00404     switch (unit_bytes) {
00405     case 1:
00406        return;
00407     case 2:
00408        _swap_ximage_2bytes (ximage);
00409        break;
00410     case 4:
00411        _swap_ximage_4bytes (ximage);
00412        break;
00413     default:
00414        ASSERT_NOT_REACHED;
00415     }
00416 }
00417 
00418 static cairo_status_t
00419 _get_image_surface (cairo_xlib_surface_t   *surface,
00420                   cairo_rectangle_t      *interest_rect,
00421                   cairo_image_surface_t **image_out,
00422                   cairo_rectangle_t      *image_rect)
00423 {
00424     cairo_image_surface_t *image;
00425     XImage *ximage;
00426     int x1, y1, x2, y2;
00427     cairo_format_masks_t masks;
00428     cairo_format_t format;
00429 
00430     x1 = 0;
00431     y1 = 0;
00432     x2 = surface->width;
00433     y2 = surface->height;
00434 
00435     if (interest_rect) {
00436        cairo_rectangle_t rect;
00437        
00438        rect.x = interest_rect->x;
00439        rect.y = interest_rect->y;
00440        rect.width = interest_rect->width;
00441        rect.height = interest_rect->height;
00442     
00443        if (rect.x > x1)
00444            x1 = rect.x;
00445        if (rect.y > y1)
00446            y1 = rect.y;
00447        if (rect.x + rect.width < x2)
00448            x2 = rect.x + rect.width;
00449        if (rect.y + rect.height < y2)
00450            y2 = rect.y + rect.height;
00451 
00452        if (x1 >= x2 || y1 >= y2) {
00453            *image_out = NULL;
00454            return CAIRO_STATUS_SUCCESS;
00455        }
00456     }
00457 
00458     if (image_rect) {
00459        image_rect->x = x1;
00460        image_rect->y = y1;
00461        image_rect->width = x2 - x1;
00462        image_rect->height = y2 - y1;
00463     }
00464 
00465     /* XXX: This should try to use the XShm extension if available */
00466 
00467     if (surface->use_pixmap == 0)
00468     {
00469        cairo_xlib_error_func_t old_handler;
00470 
00471        old_handler = XSetErrorHandler (_noop_error_handler);
00472                                                  
00473        ximage = XGetImage (surface->dpy,
00474                          surface->drawable,
00475                          x1, y1,
00476                          x2 - x1, y2 - y1,
00477                          AllPlanes, ZPixmap);
00478 
00479        XSetErrorHandler (old_handler);
00480        
00481        /* If we get an error, the surface must have been a window,
00482         * so retry with the safe code path.
00483         */
00484        if (!ximage)
00485            surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
00486     }
00487     else
00488     {
00489        surface->use_pixmap--;
00490        ximage = NULL;
00491     }
00492     
00493     if (!ximage)
00494     {
00495 
00496        /* XGetImage from a window is dangerous because it can
00497         * produce errors if the window is unmapped or partially
00498         * outside the screen. We could check for errors and
00499         * retry, but to keep things simple, we just create a
00500         * temporary pixmap
00501         */
00502        Pixmap pixmap = XCreatePixmap (surface->dpy,
00503                                    surface->drawable,
00504                                    x2 - x1, y2 - y1,
00505                                    surface->depth);
00506        _cairo_xlib_surface_ensure_gc (surface);
00507 
00508        XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,
00509                  x1, y1, x2 - x1, y2 - y1, 0, 0);
00510        
00511        ximage = XGetImage (surface->dpy,
00512                          pixmap,
00513                          0, 0,
00514                          x2 - x1, y2 - y1,
00515                          AllPlanes, ZPixmap);
00516        
00517        XFreePixmap (surface->dpy, pixmap);
00518     }
00519     if (!ximage)
00520        return CAIRO_STATUS_NO_MEMORY;
00521 
00522     _swap_ximage_to_native (ximage);
00523                                    
00524     /*
00525      * Compute the pixel format masks from either a visual or a 
00526      * XRenderFormat, failing we assume the drawable is an
00527      * alpha-only pixmap as it could only have been created
00528      * that way through the cairo_xlib_surface_create_for_bitmap
00529      * function.
00530      */
00531     if (surface->visual) {
00532        masks.bpp = ximage->bits_per_pixel;
00533        masks.alpha_mask = 0;
00534        masks.red_mask = surface->visual->red_mask;
00535        masks.green_mask = surface->visual->green_mask;
00536        masks.blue_mask = surface->visual->blue_mask;
00537     } else if (surface->format) {
00538        masks.bpp = ximage->bits_per_pixel;
00539        masks.red_mask = (unsigned long)surface->format->direct.redMask << surface->format->direct.red;
00540        masks.green_mask = (unsigned long)surface->format->direct.greenMask << surface->format->direct.green;
00541        masks.blue_mask = (unsigned long)surface->format->direct.blueMask << surface->format->direct.blue;
00542        masks.alpha_mask = (unsigned long)surface->format->direct.alphaMask << surface->format->direct.alpha;
00543     } else {
00544        masks.bpp = ximage->bits_per_pixel;
00545        masks.red_mask = 0;
00546        masks.green_mask = 0;
00547        masks.blue_mask = 0;
00548        if (surface->depth < 32)
00549            masks.alpha_mask = (1 << surface->depth) - 1;
00550        else
00551            masks.alpha_mask = 0xffffffff;
00552     }
00553 
00554     /*
00555      * Prefer to use a standard pixman format instead of the
00556      * general masks case.
00557      */
00558     if (_CAIRO_MASK_FORMAT (&masks, &format))
00559     {
00560        image = (cairo_image_surface_t*)
00561            cairo_image_surface_create_for_data ((unsigned char *) ximage->data,
00562                                            format,
00563                                            ximage->width, 
00564                                            ximage->height,
00565                                            ximage->bytes_per_line);
00566        if (image->base.status)
00567            goto FAIL;
00568     }
00569     else
00570     {
00571        /* 
00572         * XXX This can't work.  We must convert the data to one of the 
00573         * supported pixman formats.  Pixman needs another function
00574         * which takes data in an arbitrary format and converts it
00575         * to something supported by that library.
00576         */
00577        image = (cairo_image_surface_t*)
00578            _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data,
00579                                               &masks,
00580                                               ximage->width, 
00581                                               ximage->height,
00582                                               ximage->bytes_per_line);
00583        if (image->base.status)
00584            goto FAIL;
00585     }
00586 
00587     /* Let the surface take ownership of the data */
00588     _cairo_image_surface_assume_ownership_of_data (image);
00589     ximage->data = NULL;
00590     XDestroyImage (ximage);
00591      
00592     *image_out = image;
00593     return CAIRO_STATUS_SUCCESS;
00594 
00595  FAIL:
00596     XDestroyImage (ximage);
00597     return CAIRO_STATUS_NO_MEMORY;
00598 }
00599 
00600 static void
00601 _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t    *surface)
00602 {
00603     if (!surface->src_picture)
00604        surface->src_picture = XRenderCreatePicture (surface->dpy, 
00605                                                surface->drawable, 
00606                                                surface->format,
00607                                                0, NULL);
00608 }
00609        
00610 static void
00611 _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface)
00612 {
00613     if (surface->have_clip_rects)
00614        XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture,
00615                                     0, 0,
00616                                     surface->clip_rects,
00617                                     surface->num_clip_rects);
00618 }
00619 
00620 static void
00621 _cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface)
00622 {
00623     if (surface->have_clip_rects)
00624        XSetClipRectangles(surface->dpy, surface->gc,
00625                         0, 0,
00626                         surface->clip_rects,
00627                         surface->num_clip_rects, YXSorted);
00628 }
00629     
00630 static void
00631 _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t    *surface)
00632 {
00633     if (!surface->dst_picture) {
00634        surface->dst_picture = XRenderCreatePicture (surface->dpy, 
00635                                                surface->drawable, 
00636                                                surface->format,
00637                                                0, NULL);
00638        _cairo_xlib_surface_set_picture_clip_rects (surface);
00639     }
00640        
00641 }
00642        
00643 static void
00644 _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
00645 {
00646     XGCValues gcv;
00647 
00648     if (surface->gc)
00649        return;
00650 
00651     gcv.graphics_exposures = False;
00652     surface->gc = XCreateGC (surface->dpy, surface->drawable,
00653                           GCGraphicsExposures, &gcv);
00654     _cairo_xlib_surface_set_gc_clip_rects (surface);
00655 }
00656 
00657 static cairo_status_t
00658 _draw_image_surface (cairo_xlib_surface_t   *surface,
00659                    cairo_image_surface_t  *image,
00660                    int                    dst_x,
00661                    int                    dst_y)
00662 {
00663     XImage ximage;
00664     int bpp, alpha, red, green, blue;
00665     int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
00666     
00667     pixman_format_get_masks (pixman_image_get_format (image->pixman_image),
00668                           &bpp, &alpha, &red, &green, &blue);
00669     
00670     ximage.width = image->width;
00671     ximage.height = image->height;
00672     ximage.format = ZPixmap;
00673     ximage.data = (char *)image->data;
00674     ximage.byte_order = native_byte_order;
00675     ximage.bitmap_unit = 32;       /* always for libpixman */
00676     ximage.bitmap_bit_order = native_byte_order;
00677     ximage.bitmap_pad = 32; /* always for libpixman */
00678     ximage.depth = image->depth;
00679     ximage.bytes_per_line = image->stride;
00680     ximage.bits_per_pixel = bpp;
00681     ximage.red_mask = red;
00682     ximage.green_mask = green;
00683     ximage.blue_mask = blue;
00684 
00685     XInitImage (&ximage);
00686     
00687     _cairo_xlib_surface_ensure_gc (surface);
00688     XPutImage(surface->dpy, surface->drawable, surface->gc,
00689              &ximage, 0, 0, dst_x, dst_y,
00690              image->width, image->height);
00691 
00692     return CAIRO_STATUS_SUCCESS;
00693 
00694 }
00695 
00696 static cairo_status_t
00697 _cairo_xlib_surface_acquire_source_image (void                    *abstract_surface,
00698                                      cairo_image_surface_t  **image_out,
00699                                      void                   **image_extra)
00700 {
00701     cairo_xlib_surface_t *surface = abstract_surface;
00702     cairo_image_surface_t *image;
00703     cairo_status_t status;
00704 
00705     status = _get_image_surface (surface, NULL, &image, NULL);
00706     if (status)
00707        return status;
00708 
00709     *image_out = image;
00710     *image_extra = NULL;
00711 
00712     return CAIRO_STATUS_SUCCESS;
00713 }
00714 
00715 static void
00716 _cairo_xlib_surface_release_source_image (void                   *abstract_surface,
00717                                      cairo_image_surface_t  *image,
00718                                      void                   *image_extra)
00719 {
00720     cairo_surface_destroy (&image->base);
00721 }
00722 
00723 static cairo_status_t
00724 _cairo_xlib_surface_acquire_dest_image (void                    *abstract_surface,
00725                                    cairo_rectangle_t       *interest_rect,
00726                                    cairo_image_surface_t  **image_out,
00727                                    cairo_rectangle_t       *image_rect_out,
00728                                    void                   **image_extra)
00729 {
00730     cairo_xlib_surface_t *surface = abstract_surface;
00731     cairo_image_surface_t *image;
00732     cairo_status_t status;
00733 
00734     status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
00735     if (status)
00736        return status;
00737 
00738     *image_out = image;
00739     *image_extra = NULL;
00740     
00741     return CAIRO_STATUS_SUCCESS;
00742 }
00743 
00744 static void
00745 _cairo_xlib_surface_release_dest_image (void                   *abstract_surface,
00746                                    cairo_rectangle_t      *interest_rect,
00747                                    cairo_image_surface_t  *image,
00748                                    cairo_rectangle_t      *image_rect,
00749                                    void                   *image_extra)
00750 {
00751     cairo_xlib_surface_t *surface = abstract_surface;
00752 
00753     /* ignore errors */
00754     _draw_image_surface (surface, image, image_rect->x, image_rect->y);
00755 
00756     cairo_surface_destroy (&image->base);
00757 }
00758 
00759 /*
00760  * Return whether two xlib surfaces share the same
00761  * screen.  Both core and Render drawing require this
00762  * when using multiple drawables in an operation.
00763  */
00764 static cairo_bool_t
00765 _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
00766                              cairo_xlib_surface_t *src)
00767 {
00768     return dst->dpy == src->dpy && dst->screen == src->screen;
00769 }
00770 
00771 static cairo_status_t
00772 _cairo_xlib_surface_clone_similar (void                 *abstract_surface,
00773                                cairo_surface_t   *src,
00774                                cairo_surface_t     **clone_out)
00775 {
00776     cairo_xlib_surface_t *surface = abstract_surface;
00777     cairo_xlib_surface_t *clone;
00778 
00779     if (src->backend == surface->base.backend ) {
00780        cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
00781 
00782        if (_cairo_xlib_surface_same_screen (surface, xlib_src)) {
00783            *clone_out = cairo_surface_reference (src);
00784            
00785            return CAIRO_STATUS_SUCCESS;
00786        }
00787     } else if (_cairo_surface_is_image (src)) {
00788        cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
00789        cairo_content_t content = _cairo_content_from_format (image_src->format);
00790     
00791        clone = (cairo_xlib_surface_t *)
00792            _cairo_xlib_surface_create_similar (surface, content,
00793                                           image_src->width, image_src->height);
00794        if (clone->base.status)
00795            return CAIRO_STATUS_NO_MEMORY;
00796        
00797        _draw_image_surface (clone, image_src, 0, 0);
00798        
00799        *clone_out = &clone->base;
00800 
00801        return CAIRO_STATUS_SUCCESS;
00802     }
00803     
00804     return CAIRO_INT_STATUS_UNSUPPORTED;
00805 }
00806 
00807 static cairo_status_t
00808 _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
00809                             cairo_matrix_t            *matrix)
00810 {
00811     XTransform xtransform;
00812 
00813     if (!surface->src_picture)
00814        return CAIRO_STATUS_SUCCESS;
00815     
00816     xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
00817     xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
00818     xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
00819 
00820     xtransform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
00821     xtransform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
00822     xtransform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
00823 
00824     xtransform.matrix[2][0] = 0;
00825     xtransform.matrix[2][1] = 0;
00826     xtransform.matrix[2][2] = _cairo_fixed_from_double (1);
00827 
00828     if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
00829     {
00830        static const XTransform identity = { {
00831            { 1 << 16, 0x00000, 0x00000 },
00832            { 0x00000, 1 << 16, 0x00000 },
00833            { 0x00000, 0x00000, 1 << 16 },
00834        } };
00835 
00836        if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
00837            return CAIRO_STATUS_SUCCESS;
00838        
00839        return CAIRO_INT_STATUS_UNSUPPORTED;
00840     }
00841 
00842     XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform);
00843 
00844     return CAIRO_STATUS_SUCCESS;
00845 }
00846 
00847 static cairo_status_t
00848 _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
00849                             cairo_filter_t            filter)
00850 {
00851     char *render_filter;
00852 
00853     if (!surface->src_picture)
00854        return CAIRO_STATUS_SUCCESS;
00855 
00856     if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
00857     {
00858        if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
00859            return CAIRO_STATUS_SUCCESS;
00860        
00861        return CAIRO_INT_STATUS_UNSUPPORTED;
00862     }
00863     
00864     switch (filter) {
00865     case CAIRO_FILTER_FAST:
00866        render_filter = FilterFast;
00867        break;
00868     case CAIRO_FILTER_GOOD:
00869        render_filter = FilterGood;
00870        break;
00871     case CAIRO_FILTER_BEST:
00872        render_filter = FilterBest;
00873        break;
00874     case CAIRO_FILTER_NEAREST:
00875        render_filter = FilterNearest;
00876        break;
00877     case CAIRO_FILTER_BILINEAR:
00878        render_filter = FilterBilinear;
00879        break;
00880     default:
00881        render_filter = FilterBest;
00882        break;
00883     }
00884 
00885     XRenderSetPictureFilter (surface->dpy, surface->src_picture,
00886                           render_filter, NULL, 0);
00887 
00888     return CAIRO_STATUS_SUCCESS;
00889 }
00890 
00891 static cairo_status_t
00892 _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
00893 {
00894     XRenderPictureAttributes pa;
00895     unsigned long         mask;
00896 
00897     if (!surface->src_picture)
00898        return CAIRO_STATUS_SUCCESS;
00899     
00900     mask = CPRepeat;
00901     pa.repeat = repeat;
00902 
00903     XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
00904 
00905     return CAIRO_STATUS_SUCCESS;
00906 }
00907 
00908 static cairo_int_status_t
00909 _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t         *surface,
00910                                    cairo_surface_attributes_t *attributes)
00911 {
00912     cairo_int_status_t status;
00913 
00914     _cairo_xlib_surface_ensure_src_picture (surface);
00915 
00916     status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix);
00917     if (status)
00918        return status;
00919     
00920     switch (attributes->extend) {
00921     case CAIRO_EXTEND_NONE:
00922        _cairo_xlib_surface_set_repeat (surface, 0);
00923        break;
00924     case CAIRO_EXTEND_REPEAT:
00925        _cairo_xlib_surface_set_repeat (surface, 1);
00926        break;
00927     case CAIRO_EXTEND_REFLECT:
00928        return CAIRO_INT_STATUS_UNSUPPORTED;
00929     }
00930 
00931     status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
00932     if (status)
00933        return status;
00934 
00935     return CAIRO_STATUS_SUCCESS;
00936 }
00937 
00938 /* Checks whether we can can directly draw from src to dst with
00939  * the core protocol: either with CopyArea or using src as a
00940  * a tile in a GC.
00941  */
00942 static cairo_bool_t
00943 _surfaces_compatible (cairo_xlib_surface_t *dst,
00944                     cairo_xlib_surface_t *src)
00945 {
00946     /* same screen */
00947     if (!_cairo_xlib_surface_same_screen (dst, src))
00948        return FALSE;
00949     
00950     /* same depth (for core) */
00951     if (src->depth != dst->depth)
00952        return FALSE;
00953 
00954     /* if Render is supported, match picture formats */
00955     if (src->format != NULL && src->format == dst->format)
00956        return TRUE;
00957     
00958     /* Without Render, match visuals instead */
00959     if (src->visual == dst->visual)
00960        return TRUE;
00961 
00962     return FALSE;
00963 }
00964 
00965 static cairo_bool_t
00966 _surface_has_alpha (cairo_xlib_surface_t *surface)
00967 {
00968     if (surface->format) {
00969        if (surface->format->type == PictTypeDirect &&
00970            surface->format->direct.alphaMask != 0)
00971            return TRUE;
00972        else
00973            return FALSE;
00974     } else {
00975        
00976        /* In the no-render case, we never have alpha */
00977        return FALSE;
00978     }
00979 }
00980 
00981 /* Returns true if the given operator and source-alpha combination
00982  * requires alpha compositing to complete.
00983  */
00984 static cairo_bool_t
00985 _operator_needs_alpha_composite (cairo_operator_t operator,
00986                              cairo_bool_t     surface_has_alpha)
00987 {
00988     if (operator == CAIRO_OPERATOR_SOURCE ||
00989        (!surface_has_alpha &&
00990         (operator == CAIRO_OPERATOR_OVER ||
00991          operator == CAIRO_OPERATOR_ATOP ||
00992          operator == CAIRO_OPERATOR_IN)))
00993        return FALSE;
00994 
00995     return TRUE;
00996 }
00997 
00998 /* There is a bug in most older X servers with compositing using a
00999  * untransformed repeating source pattern when the source is in off-screen
01000  * video memory, and another with repeated transformed images using a
01001  * general tranform matrix. When these bugs could be triggered, we need a
01002  * fallback: in the common case where we have no transformation and the
01003  * source and destination have the same format/visual, we can do the
01004  * operation using the core protocol for the first bug, otherwise, we need
01005  * a software fallback.
01006  *
01007  * We can also often optimize a compositing operation by calling XCopyArea
01008  * for some common cases where there is no alpha compositing to be done.
01009  * We figure that out here as well.
01010  */
01011 typedef enum {
01012     DO_RENDER,              /* use render */
01013     DO_XCOPYAREA,    /* core protocol XCopyArea optimization/fallback */
01014     DO_XTILE,        /* core protocol XSetTile optimization/fallback */
01015     DO_UNSUPPORTED   /* software fallback */
01016 } composite_operation_t;
01017 
01018 /* Initial check for the render bugs; we need to recheck for the
01019  * offscreen-memory bug after we turn patterns into surfaces, since that
01020  * may introduce a repeating pattern for gradient patterns.  We don't need
01021  * to check for the repeat+transform bug because gradient surfaces aren't
01022  * transformed.
01023  *
01024  * All we do here is reject cases where we *know* are going to
01025  * hit the bug and won't be able to use a core protocol fallback.
01026  */
01027 static composite_operation_t
01028 _categorize_composite_operation (cairo_xlib_surface_t *dst,
01029                              cairo_operator_t      operator,
01030                              cairo_pattern_t      *src_pattern,
01031                              cairo_bool_t        have_mask)
01032                            
01033 {
01034     if (!dst->buggy_repeat)
01035        return DO_RENDER;
01036 
01037     if (src_pattern->type == CAIRO_PATTERN_SURFACE)
01038     {
01039        cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
01040        
01041        if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
01042            src_pattern->extend == CAIRO_EXTEND_REPEAT)
01043        {
01044            /* This is the case where we have the bug involving
01045             * untransformed repeating source patterns with off-screen
01046             * video memory; reject some cases where a core protocol
01047             * fallback is impossible.
01048             */
01049            if (have_mask ||
01050               !(operator == CAIRO_OPERATOR_SOURCE || operator == CAIRO_OPERATOR_OVER))
01051               return DO_UNSUPPORTED;
01052 
01053            if (_cairo_surface_is_xlib (surface_pattern->surface)) {
01054               cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)surface_pattern->surface;
01055 
01056               if (operator == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
01057                   return DO_UNSUPPORTED;
01058               
01059               /* If these are on the same screen but otherwise incompatible,
01060                * make a copy as core drawing can't cross depths and doesn't
01061                * work rightacross visuals of the same depth
01062                */
01063               if (_cairo_xlib_surface_same_screen (dst, src) && 
01064                   !_surfaces_compatible (dst, src))
01065                   return DO_UNSUPPORTED;
01066            }
01067        }
01068 
01069        /* Check for the other bug involving repeat patterns with general
01070         * transforms. */
01071        if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
01072            src_pattern->extend == CAIRO_EXTEND_REPEAT)
01073            return DO_UNSUPPORTED;
01074     }
01075 
01076     return DO_RENDER;
01077 }
01078 
01079 /* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
01080  * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
01081  * did to turn gradients into a pattern, but most of the time we can handle
01082  * that case with core protocol fallback.
01083  *
01084  * Also check here if we can just use XCopyArea, instead of going through
01085  * Render.
01086  */
01087 static composite_operation_t
01088 _recategorize_composite_operation (cairo_xlib_surface_t       *dst,
01089                                cairo_operator_t         operator,
01090                                cairo_xlib_surface_t           *src,
01091                                cairo_surface_attributes_t *src_attr,
01092                                cairo_bool_t                    have_mask)
01093 {
01094     cairo_bool_t is_integer_translation =
01095        _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
01096     cairo_bool_t needs_alpha_composite =
01097        _operator_needs_alpha_composite (operator, _surface_has_alpha (src));
01098 
01099     if (!have_mask &&
01100        is_integer_translation &&
01101        src_attr->extend == CAIRO_EXTEND_NONE &&
01102        !needs_alpha_composite &&
01103        _surfaces_compatible(src, dst))
01104     {
01105        return DO_XCOPYAREA;
01106     }
01107 
01108     if (!dst->buggy_repeat)
01109        return DO_RENDER;
01110     
01111     if (is_integer_translation &&
01112        src_attr->extend == CAIRO_EXTEND_REPEAT &&
01113        (src->width != 1 || src->height != 1))
01114     {
01115        if (!have_mask &&
01116            !needs_alpha_composite &&
01117            _surfaces_compatible (dst, src))
01118        {
01119            return DO_XTILE;
01120        }
01121        
01122        return DO_UNSUPPORTED;
01123     }
01124     
01125     return DO_RENDER;
01126 }
01127 
01128 static int
01129 _render_operator (cairo_operator_t operator)
01130 {
01131     switch (operator) {
01132     case CAIRO_OPERATOR_CLEAR:
01133        return PictOpClear;
01134 
01135     case CAIRO_OPERATOR_SOURCE:
01136        return PictOpSrc;
01137     case CAIRO_OPERATOR_OVER:
01138        return PictOpOver;
01139     case CAIRO_OPERATOR_IN:
01140        return PictOpIn;
01141     case CAIRO_OPERATOR_OUT:
01142        return PictOpOut;
01143     case CAIRO_OPERATOR_ATOP:
01144        return PictOpAtop;
01145 
01146     case CAIRO_OPERATOR_DEST:
01147        return PictOpDst;
01148     case CAIRO_OPERATOR_DEST_OVER:
01149        return PictOpOverReverse;
01150     case CAIRO_OPERATOR_DEST_IN:
01151        return PictOpInReverse;
01152     case CAIRO_OPERATOR_DEST_OUT:
01153        return PictOpOutReverse;
01154     case CAIRO_OPERATOR_DEST_ATOP:
01155        return PictOpAtopReverse;
01156 
01157     case CAIRO_OPERATOR_XOR:
01158        return PictOpXor;
01159     case CAIRO_OPERATOR_ADD:
01160        return PictOpAdd;
01161     case CAIRO_OPERATOR_SATURATE:
01162        return PictOpSaturate;
01163     default:
01164        return PictOpOver;
01165     }
01166 }
01167 
01168 static cairo_int_status_t
01169 _cairo_xlib_surface_composite (cairo_operator_t         operator,
01170                             cairo_pattern_t             *src_pattern,
01171                             cairo_pattern_t             *mask_pattern,
01172                             void                 *abstract_dst,
01173                             int                  src_x,
01174                             int                  src_y,
01175                             int                  mask_x,
01176                             int                  mask_y,
01177                             int                  dst_x,
01178                             int                  dst_y,
01179                             unsigned int         width,
01180                             unsigned int         height)
01181 {
01182     cairo_surface_attributes_t     src_attr, mask_attr;
01183     cairo_xlib_surface_t    *dst = abstract_dst;
01184     cairo_xlib_surface_t    *src;
01185     cairo_xlib_surface_t    *mask;
01186     cairo_int_status_t             status;
01187     composite_operation_t       operation;
01188     int                            itx, ity;
01189 
01190     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
01191        return CAIRO_INT_STATUS_UNSUPPORTED;
01192 
01193     operation = _categorize_composite_operation (dst, operator, src_pattern,
01194                                            mask_pattern != NULL);
01195     if (operation == DO_UNSUPPORTED)
01196        return CAIRO_INT_STATUS_UNSUPPORTED;
01197     
01198     status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
01199                                          &dst->base,
01200                                          src_x, src_y,
01201                                          mask_x, mask_y,
01202                                          width, height,
01203                                          (cairo_surface_t **) &src,
01204                                          (cairo_surface_t **) &mask,
01205                                          &src_attr, &mask_attr);
01206     if (status)
01207        return status;
01208     
01209     operation = _recategorize_composite_operation (dst, operator, src, &src_attr,
01210                                              mask_pattern != NULL);
01211     if (operation == DO_UNSUPPORTED) {
01212        status = CAIRO_INT_STATUS_UNSUPPORTED;
01213        goto FAIL;
01214     }
01215        
01216     status = _cairo_xlib_surface_set_attributes (src, &src_attr);
01217     if (status)
01218        goto FAIL;
01219 
01220     switch (operation)
01221     {
01222     case DO_RENDER:
01223        _cairo_xlib_surface_ensure_dst_picture (dst);
01224        if (mask) {
01225            status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
01226            if (status)
01227               goto FAIL;
01228            
01229            XRenderComposite (dst->dpy,
01230                            _render_operator (operator),
01231                            src->src_picture,
01232                            mask->src_picture,
01233                            dst->dst_picture,
01234                            src_x + src_attr.x_offset,
01235                            src_y + src_attr.y_offset,
01236                            mask_x + mask_attr.x_offset,
01237                            mask_y + mask_attr.y_offset,
01238                            dst_x, dst_y,
01239                            width, height);
01240        } else {
01241            XRenderComposite (dst->dpy,
01242                            _render_operator (operator),
01243                            src->src_picture,
01244                            0,
01245                            dst->dst_picture,
01246                            src_x + src_attr.x_offset,
01247                            src_y + src_attr.y_offset,
01248                            0, 0,
01249                            dst_x, dst_y,
01250                            width, height);
01251        }
01252 
01253        break;
01254 
01255     case DO_XCOPYAREA:
01256        _cairo_xlib_surface_ensure_gc (dst);
01257        XCopyArea (dst->dpy,
01258                  src->drawable,
01259                  dst->drawable,
01260                  dst->gc,
01261                  src_x + src_attr.x_offset,
01262                  src_y + src_attr.y_offset,
01263                  width, height,
01264                  dst_x, dst_y);
01265        break;
01266 
01267     case DO_XTILE:
01268        /* This case is only used for bug fallbacks, though it is theoretically
01269         * applicable to the case where we don't have the RENDER extension as
01270         * well.
01271         *
01272         * We've checked that we have a repeating unscaled source in
01273         * _recategorize_composite_operation.
01274         */
01275 
01276        _cairo_xlib_surface_ensure_gc (dst);
01277        _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
01278 
01279        XSetTSOrigin (dst->dpy, dst->gc,
01280                     - (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
01281        XSetTile (dst->dpy, dst->gc, src->drawable);
01282        XSetFillStyle (dst->dpy, dst->gc, FillTiled);
01283 
01284        XFillRectangle (dst->dpy, dst->drawable, dst->gc,
01285                      dst_x, dst_y, width, height);
01286        break;
01287 
01288     default:
01289        ASSERT_NOT_REACHED;
01290     }
01291 
01292     if (!_cairo_operator_bounded (operator) ||
01293        operator == CAIRO_OPERATOR_SOURCE ||
01294        operator == CAIRO_OPERATOR_CLEAR)
01295       status = _cairo_surface_composite_fixup_unbounded (&dst->base,
01296                                                   &src_attr, src->width, src->height,
01297                                                   mask ? &mask_attr : NULL,
01298                                                   mask ? mask->width : 0,
01299                                                   mask ? mask->height : 0,
01300                                                   src_x, src_y,
01301                                                   mask_x, mask_y,
01302                                                   dst_x, dst_y, width, height);
01303     
01304  FAIL:
01305 
01306     if (mask)
01307        _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
01308     
01309     _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
01310 
01311     return status;
01312 }
01313 
01314 static cairo_int_status_t
01315 _cairo_xlib_surface_fill_rectangles (void               *abstract_surface,
01316                                  cairo_operator_t              operator,
01317                                  const cairo_color_t    *color,
01318                                  cairo_rectangle_t             *rects,
01319                                  int                    num_rects)
01320 {
01321     cairo_xlib_surface_t *surface = abstract_surface;
01322     XRenderColor render_color;
01323 
01324     if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
01325        return CAIRO_INT_STATUS_UNSUPPORTED;
01326 
01327     render_color.red   = color->red_short;
01328     render_color.green = color->green_short;
01329     render_color.blue  = color->blue_short;
01330     render_color.alpha = color->alpha_short;
01331 
01332     /* XXX: This XRectangle cast is evil... it needs to go away somehow. */
01333     _cairo_xlib_surface_ensure_dst_picture (surface);
01334     XRenderFillRectangles (surface->dpy,
01335                         _render_operator (operator),
01336                         surface->dst_picture,
01337                         &render_color, (XRectangle *) rects, num_rects);
01338 
01339     return CAIRO_STATUS_SUCCESS;
01340 }
01341 
01342 /* Creates an A8 picture of size @width x @height, initialized with @color
01343  */
01344 static Picture
01345 _create_a8_picture (cairo_xlib_surface_t *surface,
01346                   XRenderColor         *color,
01347                   int                   width,
01348                   int                   height,
01349                   cairo_bool_t          repeat)
01350 {
01351     XRenderPictureAttributes pa;
01352     unsigned long mask = 0;
01353 
01354     Pixmap pixmap = XCreatePixmap (surface->dpy, surface->drawable,
01355                                width <= 0 ? 1 : width,
01356                                height <= 0 ? 1 : height,
01357                                8);
01358     Picture picture;
01359 
01360     if (repeat) {
01361        pa.repeat = TRUE;
01362        mask = CPRepeat;
01363     }
01364     
01365     picture = XRenderCreatePicture (surface->dpy, pixmap,
01366                                 XRenderFindStandardFormat (surface->dpy, PictStandardA8),
01367                                 mask, &pa);
01368     XRenderFillRectangle (surface->dpy, PictOpSrc, picture, color,
01369                        0, 0, width, height);
01370     XFreePixmap (surface->dpy, pixmap);
01371     
01372     return picture;
01373 }
01374 
01375 /* Creates a temporary mask for the trapezoids covering the area
01376  * [@dst_x, @dst_y, @width, @height] of the destination surface.
01377  */
01378 static Picture
01379 _create_trapezoid_mask (cairo_xlib_surface_t *dst,
01380                      cairo_trapezoid_t    *traps,
01381                      int                   num_traps,
01382                      int                   dst_x,
01383                      int                   dst_y,
01384                      int                   width,
01385                      int                   height,
01386                      XRenderPictFormat     *pict_format)
01387 {
01388     XRenderColor transparent = { 0, 0, 0, 0 };
01389     XRenderColor solid = { 0xffff, 0xffff, 0xffff, 0xffff };
01390     Picture mask_picture, solid_picture;
01391     XTrapezoid *offset_traps;
01392     int i;
01393 
01394     /* This would be considerably simpler using XRenderAddTraps(), but since
01395      * we are only using this in the unbounded-operator case, we stick with
01396      * XRenderCompositeTrapezoids, which is available on older versions
01397      * of RENDER rather than conditionalizing. We should still hit an
01398      * optimization that avoids creating another intermediate surface on
01399      * the servers that have XRenderAddTraps().
01400      */
01401     mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE);
01402     solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE);
01403 
01404     offset_traps = malloc (sizeof (XTrapezoid) * num_traps);
01405     if (!offset_traps)
01406        return None;
01407 
01408     for (i = 0; i < num_traps; i++) {
01409        offset_traps[i].top = traps[i].top - 0x10000 * dst_y;
01410        offset_traps[i].bottom = traps[i].bottom - 0x10000 * dst_y;
01411        offset_traps[i].left.p1.x = traps[i].left.p1.x - 0x10000 * dst_x;
01412        offset_traps[i].left.p1.y = traps[i].left.p1.y - 0x10000 * dst_y;
01413        offset_traps[i].left.p2.x = traps[i].left.p2.x - 0x10000 * dst_x;
01414        offset_traps[i].left.p2.y = traps[i].left.p2.y - 0x10000 * dst_y;
01415        offset_traps[i].right.p1.x = traps[i].right.p1.x - 0x10000 * dst_x;
01416        offset_traps[i].right.p1.y = traps[i].right.p1.y - 0x10000 * dst_y;
01417        offset_traps[i].right.p2.x = traps[i].right.p2.x - 0x10000 * dst_x;
01418        offset_traps[i].right.p2.y = traps[i].right.p2.y - 0x10000 * dst_y;
01419     }
01420 
01421     XRenderCompositeTrapezoids (dst->dpy, PictOpAdd,
01422                             solid_picture, mask_picture,
01423                             pict_format,
01424                             0, 0,
01425                             offset_traps, num_traps);
01426     
01427     XRenderFreePicture (dst->dpy, solid_picture);
01428     free (offset_traps);
01429 
01430     return mask_picture;
01431 }
01432 
01433 static cairo_int_status_t
01434 _cairo_xlib_surface_composite_trapezoids (cairo_operator_t     operator,
01435                                      cairo_pattern_t    *pattern,
01436                                      void               *abstract_dst,
01437                                      cairo_antialias_t  antialias,
01438                                      int                src_x,
01439                                      int                src_y,
01440                                      int                dst_x,
01441                                      int                dst_y,
01442                                      unsigned int              width,
01443                                      unsigned int              height,
01444                                      cairo_trapezoid_t  *traps,
01445                                      int                num_traps)
01446 {
01447     cairo_surface_attributes_t     attributes;
01448     cairo_xlib_surface_t    *dst = abstract_dst;
01449     cairo_xlib_surface_t    *src;
01450     cairo_int_status_t             status;
01451     composite_operation_t       operation;
01452     int                            render_reference_x, render_reference_y;
01453     int                            render_src_x, render_src_y;
01454     XRenderPictFormat              *pict_format;
01455 
01456     if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
01457        return CAIRO_INT_STATUS_UNSUPPORTED;
01458 
01459     operation = _categorize_composite_operation (dst, operator, pattern, TRUE);
01460     if (operation == DO_UNSUPPORTED)
01461        return CAIRO_INT_STATUS_UNSUPPORTED;
01462     
01463     status = _cairo_pattern_acquire_surface (pattern, &dst->base,
01464                                         src_x, src_y, width, height,
01465                                         (cairo_surface_t **) &src,
01466                                         &attributes);
01467     if (status)
01468        return status;
01469 
01470     operation = _recategorize_composite_operation (dst, operator, src, &attributes, TRUE);
01471     if (operation == DO_UNSUPPORTED) {
01472        status = CAIRO_INT_STATUS_UNSUPPORTED;
01473        goto FAIL;
01474     }
01475 
01476     switch (antialias) {
01477     case CAIRO_ANTIALIAS_NONE:
01478        pict_format = XRenderFindStandardFormat (dst->dpy, PictStandardA1);
01479        break;
01480     default:
01481        pict_format = XRenderFindStandardFormat (dst->dpy, PictStandardA8);
01482        break;
01483     }
01484        
01485     if (traps[0].left.p1.y < traps[0].left.p2.y) {
01486        render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
01487        render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
01488     } else {
01489        render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
01490        render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
01491     }
01492 
01493     render_src_x = src_x + render_reference_x - dst_x;
01494     render_src_y = src_y + render_reference_y - dst_y;
01495 
01496     _cairo_xlib_surface_ensure_dst_picture (dst);
01497     status = _cairo_xlib_surface_set_attributes (src, &attributes);
01498     if (status)
01499        goto FAIL;
01500 
01501     if (!_cairo_operator_bounded (operator)) {
01502        /* XRenderCompositeTrapezoids() creates a mask only large enough for the
01503         * trapezoids themselves, but if the operator is unbounded, then we need
01504         * to actually composite all the way out to the bounds, so we create
01505         * the mask and composite ourselves. There actually would
01506         * be benefit to doing this in all cases, since RENDER implementations
01507         * will frequently create a too temporary big mask, ignoring destination
01508         * bounds and clip. (XRenderAddTraps() could be used to make creating
01509         * the mask somewhat cheaper.)
01510         */
01511        Picture mask_picture = _create_trapezoid_mask (dst, traps, num_traps,
01512                                                  dst_x, dst_y, width, height,
01513                                                  pict_format);
01514        if (!mask_picture) {
01515            status = CAIRO_STATUS_NO_MEMORY;
01516            goto FAIL;
01517        }
01518 
01519        XRenderComposite (dst->dpy,
01520                        _render_operator (operator),
01521                        src->src_picture,
01522                        mask_picture,
01523                        dst->dst_picture,
01524                        src_x + attributes.x_offset,
01525                        src_y + attributes.y_offset,
01526                        0, 0,
01527                        dst_x, dst_y,
01528                        width, height);
01529        
01530        XRenderFreePicture (dst->dpy, mask_picture);
01531        
01532        status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
01533                                                          &attributes, src->width, src->height,
01534                                                          width, height,
01535                                                          src_x, src_y,
01536                                                          0, 0,
01537                                                          dst_x, dst_y, width, height);
01538 
01539        
01540     } else {
01541        /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
01542        XRenderCompositeTrapezoids (dst->dpy,
01543                                 _render_operator (operator),
01544                                 src->src_picture, dst->dst_picture,
01545                                 pict_format,
01546                                 render_src_x + attributes.x_offset, 
01547                                 render_src_y + attributes.y_offset,
01548                                 (XTrapezoid *) traps, num_traps);
01549     }
01550 
01551  FAIL:
01552     _cairo_pattern_release_surface (pattern, &src->base, &attributes);
01553 
01554     return status;
01555 }
01556 
01557 static cairo_int_status_t
01558 _cairo_xlib_surface_set_clip_region (void              *abstract_surface,
01559                                  pixman_region16_t *region)
01560 {
01561     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
01562 
01563     if (surface->clip_rects) {
01564        free (surface->clip_rects);
01565        surface->clip_rects = NULL;
01566     }
01567 
01568     surface->have_clip_rects = FALSE;
01569     surface->num_clip_rects = 0;
01570 
01571     if (region == NULL) {
01572        if (surface->gc)
01573            XSetClipMask (surface->dpy, surface->gc, None);
01574        
01575        if (surface->format && surface->dst_picture) {
01576            XRenderPictureAttributes pa;
01577            pa.clip_mask = None;
01578            XRenderChangePicture (surface->dpy, surface->dst_picture,
01579                               CPClipMask, &pa);
01580        }
01581     } else {
01582        pixman_box16_t *boxes;
01583        XRectangle *rects = NULL;
01584        int n_boxes, i;
01585        
01586        n_boxes = pixman_region_num_rects (region);
01587        if (n_boxes > 0) {
01588            rects = malloc (sizeof(XRectangle) * n_boxes);
01589            if (rects == NULL)
01590               return CAIRO_STATUS_NO_MEMORY;
01591        } else {
01592            rects = NULL;
01593        }
01594 
01595        boxes = pixman_region_rects (region);
01596        
01597        for (i = 0; i < n_boxes; i++) {
01598            rects[i].x = boxes[i].x1;
01599            rects[i].y = boxes[i].y1;
01600            rects[i].width = boxes[i].x2 - boxes[i].x1;
01601            rects[i].height = boxes[i].y2 - boxes[i].y1;
01602        }
01603 
01604        surface->have_clip_rects = TRUE;
01605        surface->clip_rects = rects;
01606        surface->num_clip_rects = n_boxes;
01607 
01608        if (surface->gc)
01609            _cairo_xlib_surface_set_gc_clip_rects (surface);
01610 
01611        if (surface->dst_picture)
01612            _cairo_xlib_surface_set_picture_clip_rects (surface);
01613     }
01614     
01615     return CAIRO_STATUS_SUCCESS;
01616 }
01617 
01618 static cairo_int_status_t
01619 _cairo_xlib_surface_get_extents (void               *abstract_surface,
01620                              cairo_rectangle_t *rectangle)
01621 {
01622     cairo_xlib_surface_t *surface = abstract_surface;
01623 
01624     rectangle->x = 0;
01625     rectangle->y = 0;
01626 
01627     rectangle->width  = surface->width;
01628     rectangle->height = surface->height;
01629 
01630     return CAIRO_STATUS_SUCCESS;
01631 }
01632 
01633 static void
01634 _cairo_xlib_surface_get_font_options (void                  *abstract_surface,
01635                                   cairo_font_options_t  *options)
01636 {
01637     cairo_xlib_surface_t *surface = abstract_surface;
01638   
01639     *options = surface->screen_info->font_options;
01640     
01641     if (_surface_has_alpha (surface) && options->antialias == CAIRO_ANTIALIAS_SUBPIXEL)
01642        options->antialias = CAIRO_ANTIALIAS_GRAY;
01643 }
01644 
01645 static cairo_int_status_t
01646 _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t    *scaled_font,
01647                              cairo_operator_t       operator,
01648                              cairo_pattern_t     *pattern,
01649                              void                *abstract_surface,
01650                              int                    source_x,
01651                              int                    source_y,
01652                              int                 dest_x,
01653                              int                 dest_y,
01654                              unsigned int        width,
01655                              unsigned int        height,
01656                              const cairo_glyph_t    *glyphs,
01657                              int                    num_glyphs);
01658 
01659 static const cairo_surface_backend_t cairo_xlib_surface_backend = {
01660     _cairo_xlib_surface_create_similar,
01661     _cairo_xlib_surface_finish,
01662     _cairo_xlib_surface_acquire_source_image,
01663     _cairo_xlib_surface_release_source_image,
01664     _cairo_xlib_surface_acquire_dest_image,
01665     _cairo_xlib_surface_release_dest_image,
01666     _cairo_xlib_surface_clone_similar,
01667     _cairo_xlib_surface_composite,
01668     _cairo_xlib_surface_fill_rectangles,
01669     _cairo_xlib_surface_composite_trapezoids,
01670     NULL, /* copy_page */
01671     NULL, /* show_page */
01672     _cairo_xlib_surface_set_clip_region,
01673     NULL, /* intersect_clip_path */
01674     _cairo_xlib_surface_get_extents,
01675     _cairo_xlib_surface_show_glyphs,
01676     NULL, /* fill_path */
01677     _cairo_xlib_surface_get_font_options
01678 };
01679 
01688 static cairo_bool_t
01689 _cairo_surface_is_xlib (cairo_surface_t *surface)
01690 {
01691     return surface->backend == &cairo_xlib_surface_backend;
01692 }
01693 
01694 static cairo_surface_t *
01695 _cairo_xlib_surface_create_internal (Display                   *dpy,
01696                                  Drawable                drawable,
01697                                  Screen                 *screen,
01698                                  Visual                 *visual,
01699                                  XRenderPictFormat             *format,
01700                                  int                    width,
01701                                  int                    height,
01702                                  int                    depth)
01703 {
01704     cairo_xlib_surface_t *surface;
01705     cairo_xlib_screen_info_t *screen_info;
01706 
01707     screen_info = _cairo_xlib_screen_info_get (dpy, screen);
01708     if (screen_info == NULL) {
01709        _cairo_error (CAIRO_STATUS_NO_MEMORY);
01710        return (cairo_surface_t*) &_cairo_surface_nil;
01711     }
01712 
01713     surface = malloc (sizeof (cairo_xlib_surface_t));
01714     if (surface == NULL) {
01715        _cairo_error (CAIRO_STATUS_NO_MEMORY);
01716        return (cairo_surface_t*) &_cairo_surface_nil;
01717     }
01718 
01719     _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend);
01720 
01721     surface->dpy = dpy;
01722     surface->screen_info = screen_info;
01723 
01724     surface->gc = NULL;
01725     surface->drawable = drawable;
01726     surface->screen = screen;
01727     surface->owns_pixmap = FALSE;
01728     surface->use_pixmap = 0;
01729     surface->width = width;
01730     surface->height = height;
01731     
01732     if (format) {
01733        depth = format->depth;
01734     } else if (visual) {
01735        int j, k;
01736 
01737        /* This is ugly, but we have to walk over all visuals
01738         * for the display to find the depth.
01739         */
01740        for (j = 0; j < screen->ndepths; j++) {
01741            Depth *d = &screen->depths[j];
01742            for (k = 0; k < d->nvisuals; k++) {
01743               if (&d->visuals[k] == visual) {
01744                   depth = d->depth;
01745                   goto found;
01746               }
01747            }
01748        }
01749     found:
01750        ;
01751     }
01752 
01753     if (cairo_xlib_render_disabled ||
01754        ! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
01755        surface->render_major = -1;
01756        surface->render_minor = -1;
01757     }
01758 
01759     surface->buggy_repeat = FALSE;
01760     if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
01761        if (VendorRelease (dpy) <= 60802000)
01762            surface->buggy_repeat = TRUE;
01763     } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
01764        if (VendorRelease (dpy) <= 40500000)
01765            surface->buggy_repeat = TRUE;
01766     }
01767 
01768     surface->dst_picture = None;
01769     surface->src_picture = None;
01770 
01771     if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
01772        if (!format) {
01773            if (visual)
01774               format = XRenderFindVisualFormat (dpy, visual);
01775            else if (depth == 1)
01776               format = XRenderFindStandardFormat (dpy, PictStandardA1);
01777        }
01778     } else {
01779        format = NULL;
01780     }
01781 
01782     surface->visual = visual;
01783     surface->format = format;
01784     surface->depth = depth;
01785 
01786     surface->have_clip_rects = FALSE;
01787     surface->clip_rects = NULL;
01788     surface->num_clip_rects = 0;
01789 
01790     return (cairo_surface_t *) surface;
01791 }
01792 
01793 static Screen *
01794 _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
01795 {
01796     int           s;
01797     int           d;
01798     int           v;
01799     Screen *screen;
01800     Depth  *depth;
01801 
01802     for (s = 0; s < ScreenCount (dpy); s++) {
01803        screen = ScreenOfDisplay (dpy, s);
01804        if (visual == DefaultVisualOfScreen (screen))
01805            return screen;
01806        for (d = 0; d < screen->ndepths; d++) {
01807            depth = &screen->depths[d];
01808            for (v = 0; v < depth->nvisuals; v++)
01809               if (visual == &depth->visuals[v])
01810                   return screen;
01811        }
01812     }
01813     return NULL;
01814 }
01815 
01836 cairo_surface_t *
01837 cairo_xlib_surface_create (Display     *dpy,
01838                         Drawable   drawable,
01839                         Visual      *visual,
01840                         int        width,
01841                         int        height)
01842 {
01843     Screen *screen = _cairo_xlib_screen_from_visual (dpy, visual);
01844 
01845     if (screen == NULL) {
01846        _cairo_error (CAIRO_STATUS_INVALID_VISUAL);
01847        return (cairo_surface_t*) &_cairo_surface_nil;
01848     }
01849     
01850     return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
01851                                           visual, NULL, width, height, 0);
01852 }
01853 
01867 cairo_surface_t *
01868 cairo_xlib_surface_create_for_bitmap (Display  *dpy,
01869                                   Pixmap  bitmap,
01870                                   Screen   *screen,
01871                                   int     width,
01872                                   int     height)
01873 {
01874     return _cairo_xlib_surface_create_internal (dpy, bitmap, screen,
01875                                           NULL, NULL, width, height, 1);
01876 }
01877 
01898 cairo_surface_t *
01899 cairo_xlib_surface_create_with_xrender_format (Display             *dpy,
01900                                           Drawable                 drawable,
01901                                           Screen            *screen,
01902                                           XRenderPictFormat    *format,
01903                                           int               width,
01904                                           int               height)
01905 {
01906     return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
01907                                           NULL, format, width, height, 0);
01908 }
01909 
01926 void
01927 cairo_xlib_surface_set_size (cairo_surface_t *surface,
01928                           int              width,
01929                           int              height)
01930 {
01931     cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *)surface;
01932 
01933     /* XXX: How do we want to handle this error case? */
01934     if (! _cairo_surface_is_xlib (surface))
01935        return;
01936 
01937     xlib_surface->width = width;
01938     xlib_surface->height = height;
01939 }
01954 void
01955 cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
01956                              Drawable         drawable,
01957                              int              width,
01958                              int              height)
01959 {
01960     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *)abstract_surface;
01961 
01962     /* XXX: How do we want to handle this error case? */
01963     if (! _cairo_surface_is_xlib (abstract_surface))
01964        return;
01965 
01966     /* XXX: and what about this case? */
01967     if (surface->owns_pixmap)
01968        return;
01969     
01970     if (surface->drawable != drawable) {
01971        if (surface->dst_picture)
01972            XRenderFreePicture (surface->dpy, surface->dst_picture);
01973        
01974        if (surface->src_picture)
01975            XRenderFreePicture (surface->dpy, surface->src_picture);
01976     
01977        surface->dst_picture = None;
01978        surface->src_picture = None;
01979     
01980        surface->drawable = drawable;
01981     }
01982     surface->width = width;
01983     surface->height = height;
01984 }
01985 
01986 /* RENDER glyphset cache code */
01987 
01988 typedef struct glyphset_cache {
01989     cairo_cache_t base;
01990 
01991     Display *display;
01992     Glyph counter;
01993 
01994     XRenderPictFormat *a1_pict_format;
01995     GlyphSet a1_glyphset;
01996 
01997     XRenderPictFormat *a8_pict_format;
01998     GlyphSet a8_glyphset;
01999 
02000     XRenderPictFormat *argb32_pict_format;
02001     GlyphSet argb32_glyphset;
02002 
02003     struct glyphset_cache *next;
02004 } glyphset_cache_t;
02005 
02006 typedef struct {
02007     cairo_glyph_cache_key_t key;
02008     GlyphSet glyphset;
02009     Glyph glyph;
02010     cairo_glyph_size_t size;
02011 } glyphset_cache_entry_t;
02012 
02013 static Glyph
02014 _next_xlib_glyph (glyphset_cache_t *cache)
02015 {
02016     return ++(cache->counter);
02017 }
02018 
02019 static cairo_bool_t
02020 _native_byte_order_lsb (void)
02021 {
02022     int       x = 1;
02023 
02024     return *((char *) &x) == 1;
02025 }
02026 
02027 static cairo_status_t 
02028 _xlib_glyphset_cache_create_entry (void *abstract_cache,
02029                                void *abstract_key,
02030                                void **return_entry)
02031 {
02032     glyphset_cache_t *cache = abstract_cache;
02033     cairo_glyph_cache_key_t *key = abstract_key;
02034     glyphset_cache_entry_t *entry;
02035     XGlyphInfo glyph_info;
02036     unsigned char *data;
02037 
02038     cairo_status_t status;
02039 
02040     cairo_cache_t *im_cache;
02041     cairo_image_glyph_cache_entry_t *im;
02042 
02043     entry = malloc (sizeof (glyphset_cache_entry_t));
02044     _cairo_lock_global_image_glyph_cache ();
02045     im_cache = _cairo_get_global_image_glyph_cache ();
02046 
02047     if (cache == NULL || entry == NULL || im_cache == NULL) {
02048        _cairo_unlock_global_image_glyph_cache ();
02049        if (entry)
02050            free (entry);
02051        return CAIRO_STATUS_NO_MEMORY;
02052     }
02053 
02054     status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL);
02055     if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
02056        _cairo_unlock_global_image_glyph_cache ();
02057        free (entry);
02058        return CAIRO_STATUS_NO_MEMORY;
02059     }
02060 
02061     entry->key = *key;
02062     _cairo_unscaled_font_reference (entry->key.unscaled);
02063 
02064     if (!im->image) {
02065        entry->glyph = None;
02066        entry->glyphset = None;
02067        entry->key.base.memory = 0;
02068        entry->size.x = entry->size.y = entry->size.width = entry->size.height = 0;
02069        
02070        goto out;
02071     }
02072     
02073     entry->glyph = _next_xlib_glyph (cache);
02074 
02075     data = im->image->data;
02076 
02077     entry->size = im->size;
02078 
02079     glyph_info.width = im->size.width;
02080     glyph_info.height = im->size.height;
02081 
02082     /*
02083      *  Most of the font rendering system thinks of glyph tiles as having
02084      *  an origin at (0,0) and an x and y bounding box "offset" which
02085      *  extends possibly off into negative coordinates, like so:
02086      *
02087      *     
02088      *       (x,y) <-- probably negative numbers
02089      *         +----------------+
02090      *         |      .         |
02091      *         |      .         |
02092      *         |......(0,0)     |
02093      *         |                |
02094      *         |                |
02095      *         +----------------+
02096      *                  (width+x,height+y)
02097      *
02098      *  This is a postscript-y model, where each glyph has its own
02099      *  coordinate space, so it's what we expose in terms of metrics. It's
02100      *  apparantly what everyone's expecting. Everyone except the Render
02101      *  extension. Render wants to see a glyph tile starting at (0,0), with
02102      *  an origin offset inside, like this:
02103      *
02104      *       (0,0)
02105      *         +---------------+
02106      *         |      .        |
02107      *         |      .        |
02108      *         |......(x,y)    |
02109      *         |               |
02110      *         |               |
02111      *         +---------------+
02112      *                   (width,height)
02113      *
02114      *  Luckily, this is just the negation of the numbers we already have
02115      *  sitting around for x and y. 
02116      */
02117 
02118     glyph_info.x = -im->size.x;
02119     glyph_info.y = -im->size.y;
02120     glyph_info.xOff = 0;
02121     glyph_info.yOff = 0;
02122 
02123     switch (im->image->format) {
02124     case CAIRO_FORMAT_A1:
02125        /* local bitmaps are always stored with bit == byte */
02126        if (_native_byte_order_lsb() != 
02127            (BitmapBitOrder (cache->display) == LSBFirst)) 
02128        {
02129            int                  c = im->image->stride * im->size.height;
02130            unsigned char   *d;
02131            unsigned char   *new, *n;
02132            
02133            new = malloc (c);
02134            if (!new)
02135               return CAIRO_STATUS_NO_MEMORY;
02136            n = new;
02137            d = data;
02138            while (c--)
02139            {
02140               char   b = *d++;
02141               b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
02142               b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
02143               b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
02144               *n++ = b;
02145            }
02146            data = new;
02147        }
02148        entry->glyphset = cache->a1_glyphset;
02149        break;
02150     case CAIRO_FORMAT_A8:
02151        entry->glyphset = cache->a8_glyphset;
02152        break;
02153     case CAIRO_FORMAT_ARGB32:
02154        if (_native_byte_order_lsb() != 
02155            (ImageByteOrder (cache->display) == LSBFirst)) 
02156        {
02157            int                  c = im->image->stride * im->size.height;
02158            unsigned char   *d;
02159            unsigned char   *new, *n;
02160            
02161            new = malloc (c);
02162            if (!new)
02163               return CAIRO_STATUS_NO_MEMORY;
02164            n = new;
02165            d = data;
02166            while ((c -= 4) >= 0)
02167            {
02168               n[3] = d[0];
02169               n[2] = d[1];
02170               n[1] = d[2];
02171               n[0] = d[3];
02172               d += 4;
02173               n += 4;
02174            }
02175            data = new;
02176        }
02177        entry->glyphset = cache->argb32_glyphset;
02178        break;
02179     case CAIRO_FORMAT_RGB24:
02180     default:
02181        ASSERT_NOT_REACHED;
02182        break;
02183     }
02184     /* XXX assume X server wants pixman padding. Xft assumes this as well */
02185 
02186     XRenderAddGlyphs (cache->display, entry->glyphset,
02187                     &(entry->glyph), &(glyph_info), 1,
02188                     (char *) data,
02189                     im->image->stride * glyph_info.height);
02190 
02191     if (data != im->image->data)
02192        free (data);
02193     
02194     entry->key.base.memory = im->image->height * im->image->stride;
02195 
02196  out:
02197     *return_entry = entry;
02198     _cairo_unlock_global_image_glyph_cache ();
02199     
02200     return CAIRO_STATUS_SUCCESS;
02201 }
02202 
02203 static void 
02204 _xlib_glyphset_cache_destroy_cache (void *cache)
02205 {
02206     /* FIXME: will we ever release glyphset caches? */
02207 }
02208 
02209 static void 
02210 _xlib_glyphset_cache_destroy_entry (void *abstract_cache,
02211                                 void *abstract_entry)
02212 {
02213     glyphset_cache_t *cache = abstract_cache;
02214     glyphset_cache_entry_t *entry = abstract_entry;
02215 
02216     _cairo_unscaled_font_destroy (entry->key.unscaled);
02217     if (entry->glyph)
02218        XRenderFreeGlyphs (cache->display, entry->glyphset,
02219                         &(entry->glyph), 1);
02220     free (entry);    
02221 }
02222 
02223 static const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
02224     _cairo_glyph_cache_hash,
02225     _cairo_glyph_cache_keys_equal,
02226     _xlib_glyphset_cache_create_entry,
02227     _xlib_glyphset_cache_destroy_entry,
02228     _xlib_glyphset_cache_destroy_cache
02229 };
02230 
02231 CAIRO_MUTEX_DECLARE(_xlib_glyphset_caches_mutex);
02232 
02233 static glyphset_cache_t *
02234 _xlib_glyphset_caches = NULL;
02235 
02236 static void
02237 _lock_xlib_glyphset_caches (void)
02238 {
02239     CAIRO_MUTEX_LOCK(_xlib_glyphset_caches_mutex);
02240 }
02241 
02242 static void
02243 _unlock_xlib_glyphset_caches (glyphset_cache_t *cache)
02244 {
02245     if (cache) {
02246        _cairo_cache_shrink_to (&cache->base,
02247                             CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT);
02248     }
02249     CAIRO_MUTEX_UNLOCK(_xlib_glyphset_caches_mutex);
02250 }
02251 
02252 static glyphset_cache_t *
02253 _get_glyphset_cache (Display *d)
02254 {
02255     /* 
02256      * There should usually only be one, or a very small number, of
02257      * displays. So we just do a linear scan. 
02258      */
02259     glyphset_cache_t *cache;
02260 
02261     /* XXX: This is not thread-safe. Xft has example code to get
02262      * per-display data via Xlib extension mechanisms. */
02263     for (cache = _xlib_glyphset_caches; cache != NULL; cache = cache->next) {
02264        if (cache->display == d)
02265            return cache;
02266     }
02267 
02268     cache = malloc (sizeof (glyphset_cache_t));
02269     if (cache == NULL) 
02270        goto ERR;
02271 
02272     if (_cairo_cache_init (&cache->base,
02273                         &_xlib_glyphset_cache_backend, 0))
02274        goto FREE_GLYPHSET_CACHE;
02275 
02276     cache->display = d;
02277     cache->counter = 0;
02278 
02279     cache->a1_pict_format = XRenderFindStandardFormat (d, PictStandardA1);
02280     cache->a1_glyphset = XRenderCreateGlyphSet (d, cache->a1_pict_format);
02281 
02282     cache->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8);
02283     cache->a8_glyphset = XRenderCreateGlyphSet (d, cache->a8_pict_format);
02284 
02285     cache->argb32_pict_format = XRenderFindStandardFormat (d, PictStandardARGB32);
02286     cache->argb32_glyphset = XRenderCreateGlyphSet (d, cache->argb32_pict_format);;
02287     
02288     cache->next = _xlib_glyphset_caches;
02289     _xlib_glyphset_caches = cache;
02290 
02291     return cache;
02292     
02293  FREE_GLYPHSET_CACHE:
02294     free (cache);
02295     
02296  ERR:
02297     return NULL;
02298 }
02299 
02300 #define N_STACK_BUF 1024
02301 
02302 static XRenderPictFormat *
02303 _select_text_mask_format (glyphset_cache_t *cache,
02304                        cairo_bool_t           have_a1_glyphs,
02305                        cairo_bool_t           have_a8_glyphs,
02306                        cairo_bool_t           have_argb32_glyphs)
02307 {
02308     if (have_a8_glyphs)
02309        return cache->a8_pict_format;
02310 
02311     if (have_a1_glyphs && have_argb32_glyphs)
02312        return cache->a8_pict_format;
02313 
02314     if (have_a1_glyphs)
02315        return cache->a1_pict_format;
02316 
02317     if (have_argb32_glyphs)
02318        return cache->argb32_pict_format;
02319 
02320     /* when there are no glyphs to draw, just pick something */
02321     return cache->a8_pict_format;
02322 }
02323 
02324 static cairo_status_t
02325 _cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t    *scaled_font,
02326                                cairo_operator_t       operator,
02327                                glyphset_cache_t    *cache,
02328                                cairo_glyph_cache_key_t *key,
02329                                cairo_xlib_surface_t   *src,
02330                                cairo_xlib_surface_t   *self,
02331                                int                    source_x,
02332                                int                    source_y,
02333                                const cairo_glyph_t    *glyphs,
02334                                glyphset_cache_entry_t **entries,
02335                                int                    num_glyphs)
02336 {
02337     XGlyphElt32 *elts = NULL;
02338     XGlyphElt32 stack_elts [N_STACK_BUF];
02339 
02340     unsigned int *chars = NULL;
02341     unsigned int stack_chars [N_STACK_BUF];
02342 
02343     int i, count;    
02344     int thisX, thisY;
02345     int lastX = 0, lastY = 0;
02346 
02347     cairo_bool_t have_a1, have_a8, have_argb32;
02348     XRenderPictFormat *mask_format;
02349 
02350     /* Acquire arrays of suitable sizes. */
02351     if (num_glyphs < N_STACK_BUF) {
02352        elts = stack_elts;
02353        chars = stack_chars;
02354 
02355     } else {
02356        elts = malloc (num_glyphs * sizeof (XGlyphElt32));
02357        if (elts == NULL)
02358            goto FAIL;
02359 
02360        chars = malloc (num_glyphs * sizeof (unsigned int));
02361        if (chars == NULL)
02362            goto FREE_ELTS;
02363 
02364     }
02365 
02366     have_a1 = FALSE;
02367     have_a8 = FALSE;
02368     have_argb32 = FALSE;
02369     count = 0;
02370 
02371     for (i = 0; i < num_glyphs; ++i) {
02372        GlyphSet glyphset;
02373        
02374        if (!entries[i]->glyph)
02375            continue;
02376 
02377        glyphset = entries[i]->glyphset;
02378 
02379        if (glyphset == cache->a1_glyphset)
02380            have_a1 = TRUE;
02381        else if (glyphset == cache->a8_glyphset)
02382            have_a8 = TRUE;
02383        else if (glyphset == cache->argb32_glyphset)
02384            have_argb32 = TRUE;
02385 
02386        chars[count] = entries[i]->glyph;
02387        elts[count].chars = &(chars[count]);
02388        elts[count].nchars = 1;
02389        elts[count].glyphset = glyphset;
02390        thisX = (int) floor (glyphs[i].x + 0.5);
02391        thisY = (int) floor (glyphs[i].y + 0.5);
02392        elts[count].xOff = thisX - lastX;
02393        elts[count].yOff = thisY - lastY;
02394        lastX = thisX;
02395        lastY = thisY;
02396        count++;
02397     }
02398 
02399     mask_format = _select_text_mask_format (cache,
02400                                        have_a1, have_a8, have_argb32);
02401 
02402     XRenderCompositeText32 (self->dpy,
02403                          _render_operator (operator),
02404                          src->src_picture,
02405                          self->dst_picture,
02406                          mask_format,
02407                          source_x + elts[0].xOff, source_y + elts[0].yOff,
02408                          0, 0,
02409                          elts, count);
02410 
02411     if (num_glyphs >= N_STACK_BUF) {
02412        free (chars);
02413        free (elts); 
02414     }
02415     
02416     return CAIRO_STATUS_SUCCESS;
02417     
02418  FREE_ELTS:
02419     if (num_glyphs >= N_STACK_BUF)
02420        free (elts); 
02421 
02422  FAIL:
02423     return CAIRO_STATUS_NO_MEMORY;
02424 }
02425 
02426 
02427 static cairo_status_t
02428 _cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t    *scaled_font,
02429                                cairo_operator_t       operator,
02430                                glyphset_cache_t    *cache,
02431                                cairo_glyph_cache_key_t *key,
02432                                cairo_xlib_surface_t   *src,
02433                                cairo_xlib_surface_t   *self,
02434                                int                    source_x,
02435                                int                    source_y,
02436                                const cairo_glyph_t    *glyphs,
02437                                glyphset_cache_entry_t **entries,
02438                                int                    num_glyphs)
02439 {
02440     XGlyphElt16 *elts = NULL;
02441     XGlyphElt16 stack_elts [N_STACK_BUF];
02442 
02443     unsigned short *chars = NULL;
02444     unsigned short stack_chars [N_STACK_BUF];
02445 
02446     int i, count;
02447     int thisX, thisY;
02448     int lastX = 0, lastY = 0;
02449 
02450     cairo_bool_t have_a1, have_a8, have_argb32;
02451     XRenderPictFormat *mask_format;
02452 
02453     /* Acquire arrays of suitable sizes. */
02454     if (num_glyphs < N_STACK_BUF) {
02455        elts = stack_elts;
02456        chars = stack_chars;
02457 
02458     } else {
02459        elts = malloc (num_glyphs * sizeof (XGlyphElt16));
02460        if (elts == NULL)
02461            goto FAIL;
02462 
02463        chars = malloc (num_glyphs * sizeof (unsigned short));
02464        if (chars == NULL)
02465            goto FREE_ELTS;
02466 
02467     }
02468 
02469     have_a1 = FALSE;
02470     have_a8 = FALSE;
02471     have_argb32 = FALSE;
02472     count = 0;
02473 
02474     for (i = 0; i < num_glyphs; ++i) {
02475        GlyphSet glyphset;
02476        
02477        if (!entries[i]->glyph)
02478            continue;
02479 
02480        glyphset = entries[i]->glyphset;
02481 
02482        if (glyphset == cache->a1_glyphset)
02483            have_a1 = TRUE;
02484        else if (glyphset == cache->a8_glyphset)
02485            have_a8 = TRUE;
02486        else if (glyphset == cache->argb32_glyphset)
02487            have_argb32 = TRUE;
02488 
02489        chars[count] = entries[i]->glyph;
02490        elts[count].chars = &(chars[count]);
02491        elts[count].nchars = 1;
02492        elts[count].glyphset = glyphset;
02493        thisX = (int) floor (glyphs[i].x + 0.5);
02494        thisY = (int) floor (glyphs[i].y + 0.5);
02495        elts[count].xOff = thisX - lastX;
02496        elts[count].yOff = thisY - lastY;
02497        lastX = thisX;
02498        lastY = thisY;
02499        count++;
02500     }
02501 
02502     mask_format = _select_text_mask_format (cache,
02503                                        have_a1, have_a8, have_argb32);
02504 
02505     XRenderCompositeText16 (self->dpy,
02506                          _render_operator (operator),
02507                          src->src_picture,
02508                          self->dst_picture,
02509                          mask_format,
02510                          source_x + elts[0].xOff, source_y + elts[0].yOff,
02511                          0, 0,
02512                          elts, count);
02513 
02514     if (num_glyphs >= N_STACK_BUF) {
02515        free (chars);
02516        free (elts); 
02517     }
02518     
02519     return CAIRO_STATUS_SUCCESS;
02520 
02521  FREE_ELTS:
02522     if (num_glyphs >= N_STACK_BUF)
02523        free (elts); 
02524 
02525  FAIL:
02526     return CAIRO_STATUS_NO_MEMORY;
02527 }
02528 
02529 static cairo_status_t
02530 _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t    *scaled_font,
02531                               cairo_operator_t       operator,
02532                               glyphset_cache_t    *cache,
02533                               cairo_glyph_cache_key_t *key,
02534                               cairo_xlib_surface_t   *src,
02535                               cairo_xlib_surface_t   *self,
02536                               int                    source_x,
02537                               int                    source_y,
02538                               const cairo_glyph_t    *glyphs,
02539                               glyphset_cache_entry_t **entries,
02540                               int                    num_glyphs)
02541 {
02542     XGlyphElt8 *elts = NULL;
02543     XGlyphElt8 stack_elts [N_STACK_BUF];
02544 
02545     char *chars = NULL;
02546     char stack_chars [N_STACK_BUF];
02547 
02548     int i, count;
02549     int thisX, thisY;
02550     int lastX = 0, lastY = 0;
02551 
02552     cairo_bool_t have_a1, have_a8, have_argb32;
02553     XRenderPictFormat *mask_format;
02554 
02555     if (num_glyphs == 0)
02556        return CAIRO_STATUS_SUCCESS;
02557 
02558     /* Acquire arrays of suitable sizes. */
02559     if (num_glyphs < N_STACK_BUF) {
02560        elts = stack_elts;
02561        chars = stack_chars;
02562 
02563     } else {
02564        elts = malloc (num_glyphs * sizeof (XGlyphElt8));
02565        if (elts == NULL)
02566            goto FAIL;
02567 
02568        chars = malloc (num_glyphs * sizeof (char));
02569        if (chars == NULL)
02570            goto FREE_ELTS;
02571 
02572     }
02573 
02574     have_a1 = FALSE;
02575     have_a8 = FALSE;
02576     have_argb32 = FALSE;
02577     count = 0;
02578 
02579     for (i = 0; i < num_glyphs; ++i) {
02580        GlyphSet glyphset;
02581        
02582        if (!entries[i]->glyph)
02583            continue;
02584 
02585        glyphset = entries[i]->glyphset;
02586 
02587        if (glyphset == cache->a1_glyphset)
02588            have_a1 = TRUE;
02589        else if (glyphset == cache->a8_glyphset)
02590            have_a8 = TRUE;
02591        else if (glyphset == cache->argb32_glyphset)
02592            have_argb32 = TRUE;
02593 
02594        chars[count] = entries[i]->glyph;
02595        elts[count].chars = &(chars[count]);
02596        elts[count].nchars = 1;
02597        elts[count].glyphset = glyphset;
02598        thisX = (int) floor (glyphs[i].x + 0.5);
02599        thisY = (int) floor (glyphs[i].y + 0.5);
02600        elts[count].xOff = thisX - lastX;
02601        elts[count].yOff = thisY - lastY;
02602        lastX = thisX;
02603        lastY = thisY;
02604        count++;
02605     }
02606 
02607     mask_format = _select_text_mask_format (cache,
02608                                        have_a1, have_a8, have_argb32);
02609 
02610     XRenderCompositeText8 (self->dpy,
02611                         _render_operator (operator),
02612                         src->src_picture,
02613                         self->dst_picture,
02614                         mask_format,
02615                         source_x + elts[0].xOff, source_y + elts[0].yOff,
02616                         0, 0,
02617                         elts, count);
02618     
02619     if (num_glyphs >= N_STACK_BUF) {
02620        free (chars);
02621        free (elts); 
02622     }
02623     
02624     return CAIRO_STATUS_SUCCESS;
02625     
02626  FREE_ELTS:
02627     if (num_glyphs >= N_STACK_BUF)
02628        free (elts); 
02629 
02630  FAIL:
02631     return CAIRO_STATUS_NO_MEMORY;
02632 }
02633 
02634 /* Handles clearing the regions that are outside of the temporary
02635  * mask created by XRenderCompositeText[N] but should be affected
02636  * by an unbounded operator like CAIRO_OPERATOR_IN
02637  */
02638 static cairo_status_t
02639 _show_glyphs_fixup_unbounded (cairo_xlib_surface_t       *self,
02640                            cairo_surface_attributes_t *src_attr,
02641                            cairo_xlib_surface_t       *src,
02642                            const cairo_glyph_t        *glyphs,
02643                            glyphset_cache_entry_t    **entries,
02644                            int                         num_glyphs,
02645                            int                         src_x,
02646                            int                         src_y,
02647                            int                         dst_x,
02648                            int                         dst_y,
02649                            int                         width,
02650                            int                         height)
02651 {
02652     int x1 = INT_MAX;
02653     int x2 = INT_MIN;
02654     int y1 = INT_MAX;
02655     int y2 = INT_MIN;
02656     int i;
02657 
02658     /* Compute the size of the glyph mask as the bounding box
02659      * of all the glyphs.
02660      */
02661     for (i = 0; i < num_glyphs; ++i) {
02662        int thisX, thisY;
02663        
02664        if (entries[i] == NULL || !entries[i]->glyph) 
02665            continue;
02666        
02667        thisX = (int) floor (glyphs[i].x + 0.5);
02668        thisY = (int) floor (glyphs[i].y + 0.5);
02669        
02670        if (thisX + entries[i]->size.x < x1)
02671            x1 = thisX + entries[i]->size.x;
02672        if (thisX + entries[i]->size.x + entries[i]->size.width > x2)
02673            x2 = thisX + entries[i]->size.x + entries[i]->size.width;
02674        if (thisY + entries[i]->size.y < y1)
02675            y1 = thisY + entries[i]->size.y;
02676        if (thisY + entries[i]->size.y + entries[i]->size.height > y2)
02677            y2 = thisY + entries[i]->size.y + entries[i]->size.height;
02678     }
02679 
02680     if (x1 >= x2 || y1 >= y2)
02681        x1 = x2 = y1 = y2 = 0;
02682 
02683     return _cairo_surface_composite_shape_fixup_unbounded (&self->base,
02684                                                     src_attr, src->width, src->height,
02685                                                     x2 - x1, y2 - y1,
02686                                                     src_x, src_y,
02687                                                     dst_x - x1, dst_y - y1,
02688                                                     dst_x, dst_y, width, height);
02689 }
02690     
02691 static cairo_int_status_t
02692 _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t    *scaled_font,
02693                              cairo_operator_t       operator,
02694                              cairo_pattern_t        *pattern,
02695                              void                 *abstract_surface,
02696                              int                    source_x,
02697                              int                    source_y,
02698                              int                 dest_x,
02699                              int                 dest_y,
02700                              unsigned int        width,
02701                              unsigned int        height,
02702                              const cairo_glyph_t    *glyphs,
02703                              int                    num_glyphs)
02704 {
02705     cairo_surface_attributes_t     attributes;
02706     cairo_int_status_t             status;
02707     unsigned int elt_size;
02708     cairo_xlib_surface_t *self = abstract_surface;
02709     cairo_xlib_surface_t *src;
02710     glyphset_cache_t *cache;
02711     cairo_glyph_cache_key_t key;
02712     glyphset_cache_entry_t **entries;
02713     glyphset_cache_entry_t *stack_entries [N_STACK_BUF];
02714     composite_operation_t operation;
02715     int i;
02716 
02717     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self) || !self->format)
02718        return CAIRO_INT_STATUS_UNSUPPORTED;
02719 
02720     operation = _categorize_composite_operation (self, operator, pattern, TRUE);
02721     if (operation == DO_UNSUPPORTED)
02722        return CAIRO_INT_STATUS_UNSUPPORTED;
02723     
02724     status = _cairo_pattern_acquire_surface (pattern, &self->base,
02725                                         source_x, source_y, width, height,
02726                                         (cairo_surface_t **) &src,
02727                                         &attributes);
02728     if (status)
02729        return status;
02730 
02731     operation = _recategorize_composite_operation (self, operator, src, &attributes, TRUE);
02732     if (operation == DO_UNSUPPORTED) {
02733        status = CAIRO_INT_STATUS_UNSUPPORTED;
02734        goto FAIL;
02735     }
02736        
02737     status = _cairo_xlib_surface_set_attributes (src, &attributes);
02738     if (status)
02739        goto FAIL;
02740     
02741     /* Acquire an entry array of suitable size. */
02742     if (num_glyphs < N_STACK_BUF) {
02743        entries = stack_entries;
02744 
02745     } else {
02746        entries = malloc (num_glyphs * sizeof (glyphset_cache_entry_t *));
02747        if (entries == NULL)
02748            goto FAIL;
02749     }
02750 
02751     _lock_xlib_glyphset_caches ();
02752     cache = _get_glyphset_cache (self->dpy);
02753     if (cache == NULL)
02754        goto UNLOCK;
02755 
02756     /* Work out the index size to use. */
02757     elt_size = 8;
02758     status = _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
02759     if (status)
02760        goto UNLOCK;
02761 
02762     for (i = 0; i < num_glyphs; ++i) {
02763        key.index = glyphs[i].index;
02764        status = _cairo_cache_lookup (&cache->base, &key, (void **) (&entries[i]), NULL);
02765        if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL) 
02766            goto UNLOCK;
02767 
02768        if (elt_size == 8 && entries[i]->glyph > 0xff)
02769            elt_size = 16;
02770        if (elt_size == 16 && entries[i]->glyph > 0xffff) {
02771            elt_size = 32;
02772            break;
02773        }
02774     }
02775 
02776     /* Call the appropriate sub-function. */
02777 
02778     _cairo_xlib_surface_ensure_dst_picture (self);
02779     if (elt_size == 8)
02780     {
02781        status = _cairo_xlib_surface_show_glyphs8 (scaled_font, operator, cache, &key, src, self,
02782                                              source_x + attributes.x_offset - dest_x,
02783                                              source_y + attributes.y_offset - dest_y, 
02784                                              glyphs, entries, num_glyphs);
02785     }
02786     else if (elt_size == 16)
02787     {
02788        status = _cairo_xlib_surface_show_glyphs16 (scaled_font, operator, cache, &key, src, self,
02789                                               source_x + attributes.x_offset - dest_x,
02790                                               source_y + attributes.y_offset - dest_y, 
02791                                               glyphs, entries, num_glyphs);
02792     }
02793     else 
02794     {
02795        status = _cairo_xlib_surface_show_glyphs32 (scaled_font, operator, cache, &key, src, self,
02796                                               source_x + attributes.x_offset - dest_x,
02797                                               source_y + attributes.y_offset - dest_y, 
02798                                               glyphs, entries, num_glyphs);
02799     }
02800 
02801     if (status == CAIRO_STATUS_SUCCESS &&
02802        !_cairo_operator_bounded (operator))
02803        status = _show_glyphs_fixup_unbounded (self,
02804                                           &attributes, src,
02805                                           glyphs, entries, num_glyphs,
02806                                           source_x, source_y,
02807                                           dest_x, dest_y, width, height);
02808 
02809  UNLOCK:
02810     _unlock_xlib_glyphset_caches (cache);
02811 
02812     if (num_glyphs >= N_STACK_BUF)
02813        free (entries); 
02814 
02815  FAIL:
02816     _cairo_pattern_release_surface (pattern, &src->base, &attributes);
02817     
02818     return status;
02819 }
02820 
02821 static void
02822 _destroy_glyphset_cache_recurse (glyphset_cache_t *cache)
02823 {
02824     if (cache == NULL)
02825        return;
02826 
02827     _destroy_glyphset_cache_recurse (cache->next);
02828     _cairo_cache_destroy (&cache->base);
02829     free (cache);
02830 }
02831 
02832 void
02833 _cairo_xlib_surface_reset_static_data (void)
02834 {
02835     _lock_xlib_glyphset_caches ();
02836     _destroy_glyphset_cache_recurse (_xlib_glyphset_caches);
02837     _xlib_glyphset_caches = NULL;
02838     _unlock_xlib_glyphset_caches (NULL);
02839 }