Back to index

lightning-sunbird  0.9+nobinonly
cairo-xcb-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  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it either under the terms of the GNU Lesser General Public
00007  * License version 2.1 as published by the Free Software Foundation
00008  * (the "LGPL") or, at your option, under the terms of the Mozilla
00009  * Public License Version 1.1 (the "MPL"). If you do not alter this
00010  * notice, a recipient may use your version of this file under either
00011  * the MPL or the LGPL.
00012  *
00013  * You should have received a copy of the LGPL along with this library
00014  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016  * You should have received a copy of the MPL along with this library
00017  * in the file COPYING-MPL-1.1
00018  *
00019  * The contents of this file are subject to the Mozilla Public License
00020  * Version 1.1 (the "License"); you may not use this file except in
00021  * compliance with the License. You may obtain a copy of the License at
00022  * http://www.mozilla.org/MPL/
00023  *
00024  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00025  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00026  * the specific language governing rights and limitations.
00027  *
00028  * The Original Code is the cairo graphics library.
00029  *
00030  * The Initial Developer of the Original Code is University of Southern
00031  * California.
00032  *
00033  * Contributor(s):
00034  *     Carl D. Worth <cworth@cworth.org>
00035  */
00036 
00037 #include "cairoint.h"
00038 #include "cairo-xcb.h"
00039 #include "cairo-xcb-xrender.h"
00040 
00041 #define AllPlanes               ((unsigned long)~0L)
00042 
00043 static XCBRenderPICTFORMAT
00044 format_from_visual(XCBConnection *c, XCBVISUALID visual)
00045 {
00046     static const XCBRenderPICTFORMAT nil = { 0 };
00047     XCBRenderQueryPictFormatsRep *r;
00048     XCBRenderPICTSCREENIter si;
00049     XCBRenderPICTDEPTHIter di;
00050     XCBRenderPICTVISUALIter vi;
00051 
00052     r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
00053     if(!r)
00054        return nil;
00055 
00056     for(si = XCBRenderQueryPictFormatsScreensIter(r); si.rem; XCBRenderPICTSCREENNext(&si))
00057        for(di = XCBRenderPICTSCREENDepthsIter(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
00058            for(vi = XCBRenderPICTDEPTHVisualsIter(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
00059               if(vi.data->visual.id == visual.id)
00060               {
00061                   XCBRenderPICTFORMAT ret = vi.data->format;
00062                   free(r);
00063                   return ret;
00064               }
00065 
00066     return nil;
00067 }
00068 
00069 /* XXX: Why is this ridiculously complex compared to the equivalent
00070  * function in cairo-xlib-surface.c */
00071 static XCBRenderPICTFORMINFO
00072 _format_from_cairo(XCBConnection *c, cairo_format_t fmt)
00073 {
00074     XCBRenderPICTFORMINFO ret = {{ 0 }};
00075     struct tmpl_t {
00076        XCBRenderDIRECTFORMAT direct;
00077        CARD8 depth;
00078     };
00079     static const struct tmpl_t templates[] = {
00080        /* CAIRO_FORMAT_ARGB32 */
00081        {
00082            {
00083               16, 0xff,
00084               8,  0xff,
00085               0,  0xff,
00086               24, 0xff
00087            },
00088            32
00089        },
00090        /* CAIRO_FORMAT_RGB24 */
00091        {
00092            {
00093               16, 0xff,
00094               8,  0xff,
00095               0,  0xff,
00096               0,  0x00
00097            },
00098            24
00099        },
00100        /* CAIRO_FORMAT_A8 */
00101        {
00102            {
00103               0,  0x00,
00104               0,  0x00,
00105               0,  0x00,
00106               0,  0xff
00107            },
00108            8
00109        },
00110        /* CAIRO_FORMAT_A1 */
00111        {
00112            {
00113               0,  0x00,
00114               0,  0x00,
00115               0,  0x00,
00116               0,  0x01
00117            },
00118            1
00119        },
00120     };
00121     const struct tmpl_t *tmpl;
00122     XCBRenderQueryPictFormatsRep *r;
00123     XCBRenderPICTFORMINFOIter fi;
00124 
00125     if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates)))
00126        return ret;
00127     tmpl = templates + fmt;
00128 
00129     r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
00130     if(!r)
00131        return ret;
00132 
00133     for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
00134     {
00135        const XCBRenderDIRECTFORMAT *t, *f;
00136        if(fi.data->type != XCBRenderPictTypeDirect)
00137            continue;
00138        if(fi.data->depth != tmpl->depth)
00139            continue;
00140        t = &tmpl->direct;
00141        f = &fi.data->direct;
00142        if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift))
00143            continue;
00144        if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift))
00145            continue;
00146        if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift))
00147            continue;
00148        if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
00149            continue;
00150 
00151        ret = *fi.data;
00152     }
00153 
00154     free(r);
00155     return ret;
00156 }
00157 
00158 /*
00159  * Instead of taking two round trips for each blending request,
00160  * assume that if a particular drawable fails GetImage that it will
00161  * fail for a "while"; use temporary pixmaps to avoid the errors
00162  */
00163 
00164 #define CAIRO_ASSUME_PIXMAP 20
00165 
00166 typedef struct cairo_xcb_surface {
00167     cairo_surface_t base;
00168 
00169     XCBConnection *dpy;
00170     XCBGCONTEXT gc;
00171     XCBDRAWABLE drawable;
00172     int owns_pixmap;
00173     XCBVISUALTYPE *visual;
00174 
00175     int use_pixmap;
00176 
00177     int render_major;
00178     int render_minor;
00179 
00180     int width;
00181     int height;
00182     int depth;
00183 
00184     XCBRenderPICTURE picture;
00185     XCBRenderPICTFORMINFO format;
00186     int has_format;
00187 } cairo_xcb_surface_t;
00188 
00189 #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor)   \
00190        (((surface)->render_major > major) ||                   \
00191         (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
00192 
00193 #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface)              CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
00194 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface)            CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
00195 
00196 #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface)              CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
00197 #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface)             CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
00198 
00199 #define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface)                    CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
00200 #define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface)                    CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
00201 
00202 #define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface)           CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
00203 #define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface)            CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
00204 #define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface)                    CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
00205 #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface)               CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
00206 
00207 #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface)    CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
00208 #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)       CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
00209 
00210 static void
00211 _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);
00212 
00213 static int
00214 _CAIRO_FORMAT_DEPTH (cairo_format_t format)
00215 {
00216     switch (format) {
00217     case CAIRO_FORMAT_A1:
00218        return 1;
00219     case CAIRO_FORMAT_A8:
00220        return 8;
00221     case CAIRO_FORMAT_RGB24:
00222        return 24;
00223     case CAIRO_FORMAT_ARGB32:
00224     default:
00225        return 32;
00226     }
00227 }
00228 
00229 static cairo_surface_t *
00230 _cairo_xcb_surface_create_similar (void                 *abstract_src,
00231                                cairo_content_t   content,
00232                                int               width,
00233                                int               height)
00234 {
00235     cairo_xcb_surface_t *src = abstract_src;
00236     XCBConnection *dpy = src->dpy;
00237     XCBDRAWABLE d;
00238     cairo_xcb_surface_t *surface;
00239     cairo_format_t format = _cairo_format_from_content (content);
00240     XCBRenderPICTFORMINFO xrender_format = _format_from_cairo (dpy, format);
00241 
00242     /* As a good first approximation, if the display doesn't have COMPOSITE,
00243      * we're better off using image surfaces for all temporary operations
00244      */
00245     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) {
00246        return cairo_image_surface_create (format, width, height);
00247     }
00248 
00249     d.pixmap = XCBPIXMAPNew (dpy);
00250     XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
00251                    d.pixmap, src->drawable,
00252                    width <= 0 ? 1 : width,
00253                    height <= 0 ? 1 : height);
00254     
00255     surface = (cairo_xcb_surface_t *)
00256        cairo_xcb_surface_create_with_xrender_format (dpy, d,
00257                                                 &xrender_format,
00258                                                 width, height);
00259     if (surface->base.status) {
00260        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00261        return (cairo_surface_t*) &_cairo_surface_nil;
00262     }
00263 
00264     surface->owns_pixmap = TRUE;
00265 
00266     return &surface->base;
00267 }
00268 
00269 static cairo_status_t
00270 _cairo_xcb_surface_finish (void *abstract_surface)
00271 {
00272     cairo_xcb_surface_t *surface = abstract_surface;
00273     if (surface->picture.xid)
00274        XCBRenderFreePicture (surface->dpy, surface->picture);
00275 
00276     if (surface->owns_pixmap)
00277        XCBFreePixmap (surface->dpy, surface->drawable.pixmap);
00278 
00279     if (surface->gc.xid)
00280        XCBFreeGC (surface->dpy, surface->gc);
00281 
00282     surface->dpy = NULL;
00283 
00284     return CAIRO_STATUS_SUCCESS;
00285 }
00286 
00287 static int
00288 _bits_per_pixel(XCBConnection *c, int depth)
00289 {
00290     XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c));
00291     XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c));
00292 
00293     for(; fmt != fmtend; ++fmt)
00294        if(fmt->depth == depth)
00295            return fmt->bits_per_pixel;
00296 
00297     if(depth <= 4)
00298        return 4;
00299     if(depth <= 8)
00300        return 8;
00301     if(depth <= 16)
00302        return 16;
00303     return 32;
00304 }
00305 
00306 static int
00307 _bytes_per_line(XCBConnection *c, int width, int bpp)
00308 {
00309     int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
00310     return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
00311 }
00312 
00313 static cairo_bool_t
00314 _CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
00315 {
00316     switch (masks->bpp) {
00317     case 32:
00318        if (masks->alpha_mask == 0xff000000 &&
00319            masks->red_mask == 0x00ff0000 &&
00320            masks->green_mask == 0x0000ff00 &&
00321            masks->blue_mask == 0x000000ff)
00322        {
00323            *format = CAIRO_FORMAT_ARGB32;
00324            return 1;
00325        }
00326        if (masks->alpha_mask == 0x00000000 &&
00327            masks->red_mask == 0x00ff0000 &&
00328            masks->green_mask == 0x0000ff00 &&
00329            masks->blue_mask == 0x000000ff)
00330        {
00331            *format = CAIRO_FORMAT_RGB24;
00332            return 1;
00333        }
00334        break;
00335     case 8:
00336        if (masks->alpha_mask == 0xff)
00337        {
00338            *format = CAIRO_FORMAT_A8;
00339            return 1;
00340        }
00341        break;
00342     case 1:
00343        if (masks->alpha_mask == 0x1)
00344        {
00345            *format = CAIRO_FORMAT_A1;
00346            return 1;
00347        }
00348        break;
00349     }
00350     return 0;
00351 }
00352 
00353 static cairo_status_t
00354 _get_image_surface (cairo_xcb_surface_t    *surface,
00355                   cairo_rectangle_t      *interest_rect,
00356                   cairo_image_surface_t **image_out,
00357                   cairo_rectangle_t      *image_rect)
00358 {
00359     cairo_image_surface_t *image;
00360     XCBGetImageRep *imagerep;
00361     int bpp, bytes_per_line;
00362     int x1, y1, x2, y2;
00363     unsigned char *data;
00364     cairo_format_t format;
00365     cairo_format_masks_t masks;
00366 
00367     x1 = 0;
00368     y1 = 0;
00369     x2 = surface->width;
00370     y2 = surface->height;
00371 
00372     if (interest_rect) {
00373        cairo_rectangle_t rect;
00374 
00375        rect.x = interest_rect->x;
00376        rect.y = interest_rect->y;
00377        rect.width = interest_rect->width;
00378        rect.height = interest_rect->height;
00379     
00380        if (rect.x > x1)
00381            x1 = rect.x;
00382        if (rect.y > y1)
00383            y1 = rect.y;
00384        if (rect.x + rect.width < x2)
00385            x2 = rect.x + rect.width;
00386        if (rect.y + rect.height < y2)
00387            y2 = rect.y + rect.height;
00388 
00389        if (x1 >= x2 || y1 >= y2) {
00390            *image_out = NULL;
00391            return CAIRO_STATUS_SUCCESS;
00392        }
00393     }
00394 
00395     if (image_rect) {
00396        image_rect->x = x1;
00397        image_rect->y = y1;
00398        image_rect->width = x2 - x1;
00399        image_rect->height = y2 - y1;
00400     }
00401 
00402     /* XXX: This should try to use the XShm extension if available */
00403 
00404     if (surface->use_pixmap == 0)
00405     {
00406        XCBGenericError *error;
00407        imagerep = XCBGetImageReply(surface->dpy,
00408                                 XCBGetImage(surface->dpy, ZPixmap,
00409                                           surface->drawable,
00410                                           x1, y1,
00411                                           x2 - x1, y2 - y1,
00412                                           AllPlanes), &error);
00413 
00414        /* If we get an error, the surface must have been a window,
00415         * so retry with the safe code path.
00416         */
00417        if (error)
00418            surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
00419     }
00420     else
00421     {
00422        surface->use_pixmap--;
00423        imagerep = NULL;
00424     }
00425 
00426     if (!imagerep)
00427     {
00428        /* XCBGetImage from a window is dangerous because it can
00429         * produce errors if the window is unmapped or partially
00430         * outside the screen. We could check for errors and
00431         * retry, but to keep things simple, we just create a
00432         * temporary pixmap
00433         */
00434        XCBDRAWABLE drawable;
00435        drawable.pixmap = XCBPIXMAPNew (surface->dpy);
00436        XCBCreatePixmap (surface->dpy,
00437                       surface->depth,
00438                       drawable.pixmap,
00439                       surface->drawable,
00440                       x2 - x1, y2 - y1);
00441        _cairo_xcb_surface_ensure_gc (surface);
00442 
00443        XCBCopyArea (surface->dpy, surface->drawable, drawable, surface->gc,
00444                    x1, y1, 0, 0, x2 - x1, y2 - y1);
00445 
00446        imagerep = XCBGetImageReply(surface->dpy,
00447                                 XCBGetImage(surface->dpy, ZPixmap,
00448                                           drawable,
00449                                           x1, y1,
00450                                           x2 - x1, y2 - y1,
00451                                           AllPlanes), 0);
00452        XCBFreePixmap (surface->dpy, drawable.pixmap);
00453 
00454     }
00455     if (!imagerep)
00456        return CAIRO_STATUS_NO_MEMORY;
00457 
00458     bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
00459     bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);
00460 
00461     data = malloc (bytes_per_line * surface->height);
00462     if (data == NULL) {
00463        free (imagerep);
00464        return CAIRO_STATUS_NO_MEMORY;
00465     }
00466 
00467     memcpy (data, XCBGetImageData (imagerep), bytes_per_line * surface->height);
00468     free (imagerep);
00469 
00470     /*
00471      * Compute the pixel format masks from either an XCBVISUALTYPE or
00472      * a XCBRenderPCTFORMINFO, failing we assume the drawable is an
00473      * alpha-only pixmap as it could only have been created that way
00474      * through the cairo_xlib_surface_create_for_bitmap function.
00475      */
00476     if (surface->visual) {
00477        masks.bpp = bpp;
00478        masks.alpha_mask = 0;
00479        masks.red_mask = surface->visual->red_mask;
00480        masks.green_mask = surface->visual->green_mask;
00481        masks.blue_mask = surface->visual->blue_mask;
00482     } else if (surface->has_format) {
00483        masks.bpp = bpp;
00484        masks.red_mask = (unsigned long)surface->format.direct.red_mask << surface->format.direct.red_shift;
00485        masks.green_mask = (unsigned long)surface->format.direct.green_mask << surface->format.direct.green_shift;
00486        masks.blue_mask = (unsigned long)surface->format.direct.blue_mask << surface->format.direct.blue_shift;
00487        masks.alpha_mask = (unsigned long)surface->format.direct.alpha_mask << surface->format.direct.alpha_shift;
00488     } else {
00489        masks.bpp = bpp;
00490        masks.red_mask = 0;
00491        masks.green_mask = 0;
00492        masks.blue_mask = 0;
00493        if (surface->depth < 32)
00494            masks.alpha_mask = (1 << surface->depth) - 1;
00495        else
00496            masks.alpha_mask = 0xffffffff;
00497     }
00498 
00499     /*
00500      * Prefer to use a standard pixman format instead of the
00501      * general masks case.
00502      */
00503     if (_CAIRO_MASK_FORMAT (&masks, &format)) {
00504        image = (cairo_image_surface_t *)
00505            cairo_image_surface_create_for_data (data,
00506                                            format,
00507                                            x2 - x1, 
00508                                            y2 - y1,
00509                                            bytes_per_line);
00510        if (image->base.status)
00511            goto FAIL;
00512     } else {
00513        /*
00514         * XXX This can't work.  We must convert the data to one of the
00515         * supported pixman formats.  Pixman needs another function
00516         * which takes data in an arbitrary format and converts it
00517         * to something supported by that library.
00518         */
00519        image = (cairo_image_surface_t *)
00520            _cairo_image_surface_create_with_masks (data,
00521                                               &masks,
00522                                               x2 - x1,
00523                                               y2 - y1,
00524                                               bytes_per_line);
00525        if (image->base.status)
00526            goto FAIL;
00527     }
00528 
00529     /* Let the surface take ownership of the data */
00530     _cairo_image_surface_assume_ownership_of_data (image);
00531 
00532     *image_out = image;
00533     return CAIRO_STATUS_SUCCESS;
00534 
00535  FAIL:
00536     free (data);
00537     return CAIRO_STATUS_NO_MEMORY;
00538 }
00539 
00540 static void
00541 _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
00542 {
00543     if (surface->gc.xid)
00544        return;
00545 
00546     surface->gc = XCBGCONTEXTNew(surface->dpy);
00547     XCBCreateGC (surface->dpy, surface->gc, surface->drawable, 0, 0);
00548 }
00549 
00550 static cairo_status_t
00551 _draw_image_surface (cairo_xcb_surface_t    *surface,
00552                    cairo_image_surface_t  *image,
00553                    int                    dst_x,
00554                    int                    dst_y)
00555 {
00556     int bpp, data_len;
00557 
00558     _cairo_xcb_surface_ensure_gc (surface);
00559     bpp = _bits_per_pixel(surface->dpy, image->depth);
00560     data_len = _bytes_per_line(surface->dpy, image->width, bpp) * image->height;
00561     XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
00562              image->width,
00563              image->height,
00564              dst_x, dst_y,
00565              /* left_pad */ 0, image->depth, 
00566              data_len, image->data);
00567 
00568     return CAIRO_STATUS_SUCCESS;
00569 }
00570 
00571 static cairo_status_t
00572 _cairo_xcb_surface_acquire_source_image (void                    *abstract_surface,
00573                                     cairo_image_surface_t  **image_out,
00574                                     void                   **image_extra)
00575 {
00576     cairo_xcb_surface_t *surface = abstract_surface;
00577     cairo_image_surface_t *image;
00578     cairo_status_t status;
00579 
00580     status = _get_image_surface (surface, NULL, &image, NULL);
00581     if (status)
00582        return status;
00583 
00584     *image_out = image;
00585     *image_extra = NULL;
00586 
00587     return CAIRO_STATUS_SUCCESS;
00588 }
00589 
00590 static void
00591 _cairo_xcb_surface_release_source_image (void                   *abstract_surface,
00592                                     cairo_image_surface_t  *image,
00593                                     void                   *image_extra)
00594 {
00595     cairo_surface_destroy (&image->base);
00596 }
00597 
00598 static cairo_status_t
00599 _cairo_xcb_surface_acquire_dest_image (void                    *abstract_surface,
00600                                    cairo_rectangle_t       *interest_rect,
00601                                    cairo_image_surface_t  **image_out,
00602                                    cairo_rectangle_t       *image_rect_out,
00603                                    void                   **image_extra)
00604 {
00605     cairo_xcb_surface_t *surface = abstract_surface;
00606     cairo_image_surface_t *image;
00607     cairo_status_t status;
00608 
00609     status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
00610     if (status)
00611        return status;
00612 
00613     *image_out = image;
00614     *image_extra = NULL;
00615 
00616     return CAIRO_STATUS_SUCCESS;
00617 }
00618 
00619 static void
00620 _cairo_xcb_surface_release_dest_image (void                   *abstract_surface,
00621                                    cairo_rectangle_t      *interest_rect,
00622                                    cairo_image_surface_t  *image,
00623                                    cairo_rectangle_t      *image_rect,
00624                                    void                   *image_extra)
00625 {
00626     cairo_xcb_surface_t *surface = abstract_surface;
00627 
00628     /* ignore errors */
00629     _draw_image_surface (surface, image, image_rect->x, image_rect->y);
00630 
00631     cairo_surface_destroy (&image->base);
00632 }
00633 
00634 static cairo_status_t
00635 _cairo_xcb_surface_clone_similar (void                  *abstract_surface,
00636                               cairo_surface_t    *src,
00637                               cairo_surface_t     **clone_out)
00638 {
00639     cairo_xcb_surface_t *surface = abstract_surface;
00640     cairo_xcb_surface_t *clone;
00641 
00642     if (src->backend == surface->base.backend ) {
00643        cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
00644 
00645        if (xcb_src->dpy == surface->dpy) {
00646            *clone_out = cairo_surface_reference (src);
00647            
00648            return CAIRO_STATUS_SUCCESS;
00649        }
00650     } else if (_cairo_surface_is_image (src)) {
00651        cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
00652        cairo_content_t content = _cairo_content_from_format (image_src->format);
00653 
00654        if (surface->base.status)
00655            return surface->base.status;
00656     
00657        clone = (cairo_xcb_surface_t *)
00658            _cairo_xcb_surface_create_similar (surface, content,
00659                                           image_src->width, image_src->height);
00660        if (clone->base.status)
00661            return CAIRO_STATUS_NO_MEMORY;
00662        
00663        _draw_image_surface (clone, image_src, 0, 0);
00664        
00665        *clone_out = &clone->base;
00666 
00667        return CAIRO_STATUS_SUCCESS;
00668     }
00669     
00670     return CAIRO_INT_STATUS_UNSUPPORTED;
00671 }
00672 
00673 static cairo_status_t
00674 _cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
00675                             cairo_matrix_t          *matrix)
00676 {
00677     XCBRenderTRANSFORM xtransform;
00678 
00679     if (!surface->picture.xid)
00680        return CAIRO_STATUS_SUCCESS;
00681 
00682     xtransform.matrix11 = _cairo_fixed_from_double (matrix->xx);
00683     xtransform.matrix12 = _cairo_fixed_from_double (matrix->xy);
00684     xtransform.matrix13 = _cairo_fixed_from_double (matrix->x0);
00685 
00686     xtransform.matrix21 = _cairo_fixed_from_double (matrix->yx);
00687     xtransform.matrix22 = _cairo_fixed_from_double (matrix->yy);
00688     xtransform.matrix23 = _cairo_fixed_from_double (matrix->y0);
00689 
00690     xtransform.matrix31 = 0;
00691     xtransform.matrix32 = 0;
00692     xtransform.matrix33 = _cairo_fixed_from_double (1);
00693 
00694     if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
00695     {
00696        static const XCBRenderTRANSFORM identity = {
00697            1 << 16, 0x00000, 0x00000,
00698            0x00000, 1 << 16, 0x00000,
00699            0x00000, 0x00000, 1 << 16
00700        };
00701 
00702        if (memcmp (&xtransform, &identity, sizeof (XCBRenderTRANSFORM)) == 0)
00703            return CAIRO_STATUS_SUCCESS;
00704        
00705        return CAIRO_INT_STATUS_UNSUPPORTED;
00706     }
00707     
00708     XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
00709 
00710     return CAIRO_STATUS_SUCCESS;
00711 }
00712 
00713 static cairo_status_t
00714 _cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
00715                             cairo_filter_t          filter)
00716 {
00717     char *render_filter;
00718 
00719     if (!surface->picture.xid)
00720        return CAIRO_STATUS_SUCCESS;
00721     
00722     if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
00723     {
00724        if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
00725            return CAIRO_STATUS_SUCCESS;
00726        
00727        return CAIRO_INT_STATUS_UNSUPPORTED;
00728     }
00729     
00730     switch (filter) {
00731     case CAIRO_FILTER_FAST:
00732        render_filter = "fast";
00733        break;
00734     case CAIRO_FILTER_GOOD:
00735        render_filter = "good";
00736        break;
00737     case CAIRO_FILTER_BEST:
00738        render_filter = "best";
00739        break;
00740     case CAIRO_FILTER_NEAREST:
00741        render_filter = "nearest";
00742        break;
00743     case CAIRO_FILTER_BILINEAR:
00744        render_filter = "bilinear";
00745        break;
00746     default:
00747        render_filter = "best";
00748        break;
00749     }
00750 
00751     XCBRenderSetPictureFilter(surface->dpy, surface->picture,
00752                           strlen(render_filter), render_filter, 0, NULL);
00753 
00754     return CAIRO_STATUS_SUCCESS;
00755 }
00756 
00757 static cairo_status_t
00758 _cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
00759 {
00760     CARD32 mask = XCBRenderCPRepeat;
00761     CARD32 pa[] = { repeat };
00762 
00763     if (!surface->picture.xid)
00764        return CAIRO_STATUS_SUCCESS;
00765 
00766     XCBRenderChangePicture (surface->dpy, surface->picture, mask, pa);
00767 
00768     return CAIRO_STATUS_SUCCESS;
00769 }
00770 
00771 static cairo_int_status_t
00772 _cairo_xcb_surface_set_attributes (cairo_xcb_surface_t        *surface,
00773                                cairo_surface_attributes_t *attributes)
00774 {
00775     cairo_int_status_t status;
00776 
00777     status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
00778     if (status)
00779        return status;
00780     
00781     switch (attributes->extend) {
00782     case CAIRO_EXTEND_NONE:
00783        _cairo_xcb_surface_set_repeat (surface, 0);
00784        break;
00785     case CAIRO_EXTEND_REPEAT:
00786        _cairo_xcb_surface_set_repeat (surface, 1);
00787        break;
00788     case CAIRO_EXTEND_REFLECT:
00789        return CAIRO_INT_STATUS_UNSUPPORTED;
00790     }
00791 
00792     status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
00793     if (status)
00794        return status;
00795 
00796     return CAIRO_STATUS_SUCCESS;
00797 }
00798 
00799 static int
00800 _render_operator (cairo_operator_t operator)
00801 {
00802     switch (operator) {
00803     case CAIRO_OPERATOR_CLEAR:
00804        return XCBRenderPictOpClear;
00805     case CAIRO_OPERATOR_SOURCE:
00806        return XCBRenderPictOpSrc;
00807     case CAIRO_OPERATOR_DEST:
00808        return XCBRenderPictOpDst;
00809     case CAIRO_OPERATOR_OVER:
00810        return XCBRenderPictOpOver;
00811     case CAIRO_OPERATOR_DEST_OVER:
00812        return XCBRenderPictOpOverReverse;
00813     case CAIRO_OPERATOR_IN:
00814        return XCBRenderPictOpIn;
00815     case CAIRO_OPERATOR_DEST_IN:
00816        return XCBRenderPictOpInReverse;
00817     case CAIRO_OPERATOR_OUT:
00818        return XCBRenderPictOpOut;
00819     case CAIRO_OPERATOR_DEST_OUT:
00820        return XCBRenderPictOpOutReverse;
00821     case CAIRO_OPERATOR_ATOP:
00822        return XCBRenderPictOpAtop;
00823     case CAIRO_OPERATOR_DEST_ATOP:
00824        return XCBRenderPictOpAtopReverse;
00825     case CAIRO_OPERATOR_XOR:
00826        return XCBRenderPictOpXor;
00827     case CAIRO_OPERATOR_ADD:
00828        return XCBRenderPictOpAdd;
00829     case CAIRO_OPERATOR_SATURATE:
00830        return XCBRenderPictOpSaturate;
00831     default:
00832        return XCBRenderPictOpOver;
00833     }
00834 }
00835 
00836 static cairo_int_status_t
00837 _cairo_xcb_surface_composite (cairo_operator_t          operator,
00838                            cairo_pattern_t              *src_pattern,
00839                            cairo_pattern_t              *mask_pattern,
00840                            void                  *abstract_dst,
00841                            int                   src_x,
00842                            int                   src_y,
00843                            int                   mask_x,
00844                            int                   mask_y,
00845                            int                   dst_x,
00846                            int                   dst_y,
00847                            unsigned int          width,
00848                            unsigned int          height)
00849 {
00850     cairo_surface_attributes_t     src_attr, mask_attr;
00851     cairo_xcb_surface_t            *dst = abstract_dst;
00852     cairo_xcb_surface_t            *src;
00853     cairo_xcb_surface_t            *mask;
00854     cairo_int_status_t             status;
00855 
00856     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
00857        return CAIRO_INT_STATUS_UNSUPPORTED;
00858 
00859     status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
00860                                          &dst->base,
00861                                          src_x, src_y,
00862                                          mask_x, mask_y,
00863                                          width, height,
00864                                          (cairo_surface_t **) &src,
00865                                          (cairo_surface_t **) &mask,
00866                                          &src_attr, &mask_attr);
00867     if (status)
00868        return status;
00869     
00870     status = _cairo_xcb_surface_set_attributes (src, &src_attr);
00871     if (status == CAIRO_STATUS_SUCCESS)
00872     {
00873        if (mask)
00874        {
00875            status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
00876            if (status == CAIRO_STATUS_SUCCESS)
00877               XCBRenderComposite (dst->dpy,
00878                                 _render_operator (operator),
00879                                 src->picture,
00880                                 mask->picture,
00881                                 dst->picture,
00882                                 src_x + src_attr.x_offset,
00883                                 src_y + src_attr.y_offset,
00884                                 mask_x + mask_attr.x_offset,
00885                                 mask_y + mask_attr.y_offset,
00886                                 dst_x, dst_y,
00887                                 width, height);
00888        }
00889        else
00890        {
00891            static XCBRenderPICTURE maskpict = { 0 };
00892            
00893            XCBRenderComposite (dst->dpy,
00894                             _render_operator (operator),
00895                             src->picture,
00896                             maskpict,
00897                             dst->picture,
00898                             src_x + src_attr.x_offset,
00899                             src_y + src_attr.y_offset,
00900                             0, 0,
00901                             dst_x, dst_y,
00902                             width, height);
00903        }
00904     }
00905 
00906     if (mask)
00907        _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
00908     
00909     _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
00910 
00911     return status;
00912 }
00913 
00914 static cairo_int_status_t
00915 _cairo_xcb_surface_fill_rectangles (void                *abstract_surface,
00916                                  cairo_operator_t              operator,
00917                                  const cairo_color_t    *color,
00918                                  cairo_rectangle_t             *rects,
00919                                  int                    num_rects)
00920 {
00921     cairo_xcb_surface_t *surface = abstract_surface;
00922     XCBRenderCOLOR render_color;
00923 
00924     if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
00925        return CAIRO_INT_STATUS_UNSUPPORTED;
00926 
00927     render_color.red   = color->red_short;
00928     render_color.green = color->green_short;
00929     render_color.blue  = color->blue_short;
00930     render_color.alpha = color->alpha_short;
00931 
00932     /* XXX: This XCBRECTANGLE cast is evil... it needs to go away somehow. */
00933     XCBRenderFillRectangles (surface->dpy,
00934                         _render_operator (operator),
00935                         surface->picture,
00936                         render_color, num_rects, (XCBRECTANGLE *) rects);
00937 
00938     return CAIRO_STATUS_SUCCESS;
00939 }
00940 
00941 static cairo_int_status_t
00942 _cairo_xcb_surface_composite_trapezoids (cairo_operator_t      operator,
00943                                     cairo_pattern_t     *pattern,
00944                                     void                *abstract_dst,
00945                                     cairo_antialias_t   antialias,
00946                                     int                 src_x,
00947                                     int                 src_y,
00948                                     int                 dst_x,
00949                                     int                 dst_y,
00950                                     unsigned int        width,
00951                                     unsigned int        height,
00952                                     cairo_trapezoid_t   *traps,
00953                                     int                 num_traps)
00954 {
00955     cairo_surface_attributes_t     attributes;
00956     cairo_xcb_surface_t            *dst = abstract_dst;
00957     cairo_xcb_surface_t            *src;
00958     cairo_int_status_t             status;
00959     int                            render_reference_x, render_reference_y;
00960     int                            render_src_x, render_src_y;
00961     XCBRenderPICTFORMINFO   render_format;
00962 
00963     if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
00964        return CAIRO_INT_STATUS_UNSUPPORTED;
00965     
00966     status = _cairo_pattern_acquire_surface (pattern, &dst->base,
00967                                         src_x, src_y, width, height,
00968                                         (cairo_surface_t **) &src,
00969                                         &attributes);
00970     if (status)
00971        return status;
00972     
00973     if (traps[0].left.p1.y < traps[0].left.p2.y) {
00974        render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
00975        render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
00976     } else {
00977        render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
00978        render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
00979     }
00980 
00981     render_src_x = src_x + render_reference_x - dst_x;
00982     render_src_y = src_y + render_reference_y - dst_y;
00983 
00984     switch (antialias) {
00985     case CAIRO_ANTIALIAS_NONE:
00986        render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A1);
00987        break;
00988     default:
00989        render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A8);
00990        break;
00991     }
00992 
00993     /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
00994     /* XXX: _format_from_cairo is slow. should cache something. */
00995     status = _cairo_xcb_surface_set_attributes (src, &attributes);
00996     if (status == CAIRO_STATUS_SUCCESS)
00997        XCBRenderTrapezoids (dst->dpy,
00998                           _render_operator (operator),
00999                           src->picture, dst->picture,
01000                           render_format.id,
01001                           render_src_x + attributes.x_offset, 
01002                           render_src_y + attributes.y_offset,
01003                           num_traps, (XCBRenderTRAP *) traps);
01004 
01005     _cairo_pattern_release_surface (pattern, &src->base, &attributes);
01006 
01007     return status;
01008 }
01009 
01010 static cairo_int_status_t
01011 _cairo_xcb_surface_get_extents (void               *abstract_surface,
01012                             cairo_rectangle_t *rectangle)
01013 {
01014     cairo_xcb_surface_t *surface = abstract_surface;
01015 
01016     rectangle->x = 0;
01017     rectangle->y = 0;
01018 
01019     rectangle->width  = surface->width;
01020     rectangle->height = surface->height;
01021 
01022     return CAIRO_STATUS_SUCCESS;
01023 }
01024 
01025 static const cairo_surface_backend_t cairo_xcb_surface_backend = {
01026     _cairo_xcb_surface_create_similar,
01027     _cairo_xcb_surface_finish,
01028     _cairo_xcb_surface_acquire_source_image,
01029     _cairo_xcb_surface_release_source_image,
01030     _cairo_xcb_surface_acquire_dest_image,
01031     _cairo_xcb_surface_release_dest_image,
01032     _cairo_xcb_surface_clone_similar,
01033     _cairo_xcb_surface_composite,
01034     _cairo_xcb_surface_fill_rectangles,
01035     _cairo_xcb_surface_composite_trapezoids,
01036     NULL, /* copy_page */
01037     NULL, /* show_page */
01038     NULL, /* _cairo_xcb_surface_set_clip_region */
01039     NULL, /* intersect_clip_path */
01040     _cairo_xcb_surface_get_extents,
01041     NULL /* show_glyphs */
01042 };
01043 
01052 static cairo_bool_t
01053 _cairo_surface_is_xcb (cairo_surface_t *surface)
01054 {
01055     return surface->backend == &cairo_xcb_surface_backend;
01056 }
01057 
01058 static void
01059 query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
01060 {
01061     XCBRenderQueryVersionRep *r;
01062 
01063     surface->render_major = -1;
01064     surface->render_minor = -1;
01065 
01066     if (!XCBRenderInit(c))
01067        return;
01068 
01069     r = XCBRenderQueryVersionReply(c, XCBRenderQueryVersion(c, 0, 6), 0);
01070     if (!r)
01071        return;
01072 
01073     surface->render_major = r->major_version;
01074     surface->render_minor = r->minor_version;
01075     free(r);
01076 }
01077 
01078 static cairo_surface_t *
01079 _cairo_xcb_surface_create_internal (XCBConnection            *dpy,
01080                                 XCBDRAWABLE                   drawable,
01081                                 XCBVISUALTYPE         *visual,
01082                                 XCBRenderPICTFORMINFO    *format,
01083                                 int                           width,
01084                                 int                           height,
01085                                 int                           depth)
01086 {
01087     cairo_xcb_surface_t *surface;
01088 
01089     surface = malloc (sizeof (cairo_xcb_surface_t));
01090     if (surface == NULL) {
01091        _cairo_error (CAIRO_STATUS_NO_MEMORY);
01092        return (cairo_surface_t*) &_cairo_surface_nil;
01093     }
01094 
01095     _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend);
01096 
01097     surface->dpy = dpy;
01098 
01099     surface->gc.xid = 0;
01100     surface->drawable = drawable;
01101     surface->owns_pixmap = FALSE;
01102     surface->visual = visual;
01103     if (format) {
01104        surface->format = *format;
01105        surface->has_format = 1;
01106     } else {
01107        surface->format.id.xid = 0;
01108        surface->has_format = 0;
01109     }
01110     surface->use_pixmap = 0;
01111     surface->width = width;
01112     surface->height = height;
01113     surface->depth = depth;
01114 
01115     if (format) {
01116        surface->depth = format->depth;
01117     } else if (visual) {
01118        XCBSCREENIter roots;
01119        XCBDEPTHIter depths;
01120        XCBVISUALTYPEIter visuals;
01121 
01122        /* This is ugly, but we have to walk over all visuals
01123         * for the display to find the depth.
01124         */
01125         roots = XCBConnSetupSuccessRepRootsIter(XCBGetSetup(surface->dpy));
01126         for(; roots.rem; XCBSCREENNext(&roots))
01127         {
01128            depths = XCBSCREENAllowedDepthsIter(roots.data);
01129            for(; depths.rem; XCBDEPTHNext(&depths))
01130            {
01131               visuals = XCBDEPTHVisualsIter(depths.data);
01132               for(; visuals.rem; XCBVISUALTYPENext(&visuals))
01133               {
01134                   if(visuals.data->visual_id.id == visual->visual_id.id)
01135                   {
01136                      surface->depth = depths.data->depth;
01137                      goto found;
01138                   }
01139               }
01140            }
01141         }
01142     found:
01143        ;
01144     }
01145 
01146     query_render_version(dpy, surface);
01147 
01148     surface->picture.xid = 0;
01149 
01150     if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
01151     {
01152        XCBRenderPICTFORMAT pict_format = {0};
01153        XCBRenderPICTFORMINFO format_info;
01154 
01155        surface->picture = XCBRenderPICTURENew(dpy);
01156 
01157        if (!format) {
01158            if (visual) {
01159               pict_format = format_from_visual (dpy, visual->visual_id);
01160            } else if (depth == 1) {
01161               format_info = _format_from_cairo (dpy, CAIRO_FORMAT_A1);
01162               pict_format = format_info.id;
01163            }
01164            XCBRenderCreatePicture (dpy, surface->picture, drawable,
01165                                 pict_format, 0, NULL);
01166        } else {
01167            XCBRenderCreatePicture (dpy, surface->picture, drawable,
01168                                 format->id, 0, NULL);
01169        }
01170     }
01171 
01172     return (cairo_surface_t *) surface;
01173 }
01174 
01195 cairo_surface_t *
01196 cairo_xcb_surface_create (XCBConnection *c,
01197                        XCBDRAWABLE  drawable,
01198                        XCBVISUALTYPE *visual,
01199                        int          width,
01200                        int          height)
01201 {
01202     return _cairo_xcb_surface_create_internal (c, drawable,
01203                                           visual, NULL,
01204                                           width, height, 0);
01205 }
01206 
01219 cairo_surface_t *
01220 cairo_xcb_surface_create_for_bitmap (XCBConnection     *c,
01221                                  XCBPIXMAP              bitmap,
01222                                  int             width,
01223                                  int             height)
01224 {
01225     XCBDRAWABLE drawable;
01226     drawable.pixmap = bitmap;
01227     return _cairo_xcb_surface_create_internal (c, drawable,
01228                                           NULL, NULL,
01229                                           width, height, 1);
01230 }
01231 
01251 cairo_surface_t *
01252 cairo_xcb_surface_create_with_xrender_format (XCBConnection        *c,
01253                                          XCBDRAWABLE         drawable,
01254                                          XCBRenderPICTFORMINFO *format,
01255                                          int                 width,
01256                                          int                 height)
01257 {
01258     return _cairo_xcb_surface_create_internal (c, drawable,
01259                                           NULL, format,
01260                                           width, height, 0);
01261 }
01262 
01279 void
01280 cairo_xcb_surface_set_size (cairo_surface_t *surface,
01281                          int              width,
01282                          int              height)
01283 {
01284     cairo_xcb_surface_t *xcb_surface = (cairo_xcb_surface_t *)surface;
01285 
01286     /* XXX: How do we want to handle this error case? */
01287     if (! _cairo_surface_is_xcb (surface))
01288        return;
01289 
01290     xcb_surface->width = width;
01291     xcb_surface->height = height;
01292 }
01293