diff options
author | Carl Worth <cworth@cworth.org> | 2005-05-17 06:11:32 +0000 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2005-05-17 06:11:32 +0000 |
commit | 30d7ede3dfdc256180e4447debd0be6d69c699b7 (patch) | |
tree | 7d3a3b0156e1c594c2549c26ebf2a4e8d7cc74b3 | |
parent | f67f5003df306de40416f24bc652fc4630cf5808 (diff) |
Update cairo-xcb.h to provide the same style of interface as cairo-xlib.h.
Update to match new cairo_xcb_surface_t create functions.
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/cairo-xcb-surface.c | 410 | ||||
-rw-r--r-- | src/cairo-xcb-xrender.h | 62 | ||||
-rw-r--r-- | src/cairo-xcb.h | 21 | ||||
-rw-r--r-- | test/cairo-test.c | 115 |
6 files changed, 427 insertions, 197 deletions
@@ -1,5 +1,19 @@ 2005-05-17 Carl Worth <cworth@cworth.org> + * src/Makefile.am: + * src/cairo-xcb.h: + * src/cairo-xcb-xrender.h: + * src/cairo-xcb-surface.c: + (cairo_xcb_surface_create), + (cairo_xcb_surface_create_for_bitmap), + (cairo_xcb_surface_create_with_xrender_format): Update cairo-xcb.h + to provide the same style of interface as cairo-xlib.h. + + * test/cairo-test.c: Update to match new cairo_xcb_surface_t + create functions. + +2005-05-17 Carl Worth <cworth@cworth.org> + * src/cairo-xlib-surface.c (_get_image_surface): Avoid shifting 32-bit quanity by 32 bits, which is undefined behavior. diff --git a/src/Makefile.am b/src/Makefile.am index 30cf00e42..58ca5a0b9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,7 @@ libcairo_quartz_sources = cairo-quartz-surface.c endif if CAIRO_HAS_XCB_SURFACE -libcairo_xcb_headers = cairo-xcb.h +libcairo_xcb_headers = cairo-xcb.h cairo-xcb-xrender.h libcairo_xcb_sources = cairo-xcb-surface.c endif diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index f826bc65d..e77e3dc3c 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -36,6 +36,7 @@ #include "cairoint.h" #include "cairo-xcb.h" +#include "cairo-xcb-xrender.h" #define AllPlanes ((unsigned long)~0L) @@ -65,10 +66,12 @@ format_from_visual(XCBConnection *c, XCBVISUALID visual) return nil; } -static XCBRenderPICTFORMAT -format_from_cairo(XCBConnection *c, cairo_format_t fmt) +/* XXX: Why is this ridiculously complex compared to the equivalent + * function in cairo-xlib-surface.c */ +static XCBRenderPICTFORMINFO +_format_from_cairo(XCBConnection *c, cairo_format_t fmt) { - XCBRenderPICTFORMAT ret = { 0 }; + XCBRenderPICTFORMINFO ret = {{ 0 }}; struct tmpl_t { XCBRenderDIRECTFORMAT direct; CARD8 depth; @@ -145,17 +148,20 @@ format_from_cairo(XCBConnection *c, cairo_format_t fmt) if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift)) continue; - ret = fi.data->id; + ret = *fi.data; } free(r); return ret; } -typedef enum { - CAIRO_XCB_PIXMAP, - CAIRO_XCB_WINDOW -} cairo_xcb_drawable_type_t; +/* + * Instead of taking two round trips for each blending request, + * assume that if a particular drawable fails GetImage that it will + * fail for a "while"; use temporary pixmaps to avoid the errors + */ + +#define CAIRO_ASSUME_PIXMAP 20 typedef struct cairo_xcb_surface { cairo_surface_t base; @@ -165,17 +171,19 @@ typedef struct cairo_xcb_surface { XCBDRAWABLE drawable; int owns_pixmap; XCBVISUALTYPE *visual; - cairo_format_t format; + + int use_pixmap; int render_major; int render_minor; - cairo_xcb_drawable_type_t type; int width; int height; int depth; XCBRenderPICTURE picture; + XCBRenderPICTFORMINFO format; + int has_format; } cairo_xcb_surface_t; #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \ @@ -229,6 +237,7 @@ _cairo_xcb_surface_create_similar (void *abstract_src, XCBConnection *dpy = src->dpy; XCBDRAWABLE d; cairo_xcb_surface_t *surface; + XCBRenderPICTFORMINFO xrender_format = _format_from_cairo (dpy, format); /* As a good first approximation, if the display doesn't have COMPOSITE, * we're better off using image surfaces for all temporary operations @@ -240,11 +249,13 @@ _cairo_xcb_surface_create_similar (void *abstract_src, d.pixmap = XCBPIXMAPNew (dpy); XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format), d.pixmap, src->drawable, - width, height); + width <= 0 ? 1 : width, + height <= 0 ? 1 : height); surface = (cairo_xcb_surface_t *) - cairo_xcb_surface_create_for_pixmap (dpy, d.pixmap, format); - cairo_xcb_surface_set_size (&surface->base, width, height); + cairo_xcb_surface_create_with_xrender_format (dpy, d, + &xrender_format, + width, height); surface->owns_pixmap = TRUE; @@ -269,43 +280,6 @@ _cairo_xcb_surface_finish (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_xcb_surface_get_size (cairo_xcb_surface_t *surface, - int *width, - int *height) -{ - XCBGetGeometryRep *geomrep; - - if (surface->width >= 0 && surface->height >= 0) { - *width = surface->width; - *height = surface->height; - return CAIRO_STATUS_SUCCESS; - } - - geomrep = XCBGetGeometryReply(surface->dpy, - XCBGetGeometry(surface->dpy, surface->drawable), - 0); - /* XXX: I haven't looked closely at XCB yet to know why this might - * fail. */ - if(!geomrep) - return CAIRO_STATUS_NO_MEMORY; - - /* The size of a pixmap can't change, so we store - * the information to avoid having to get it again - */ - if (surface->type == CAIRO_XCB_PIXMAP) { - surface->width = geomrep->width; - surface->height = geomrep->height; - } - - *width = geomrep->width; - *height = geomrep->height; - - free(geomrep); - - return CAIRO_STATUS_SUCCESS; -} - static int _bits_per_pixel(XCBConnection *c, int depth) { @@ -332,25 +306,64 @@ _bytes_per_line(XCBConnection *c, int width, int bpp) return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3; } +static cairo_bool_t +_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format) +{ + switch (masks->bpp) { + case 32: + if (masks->alpha_mask == 0xff000000 && + masks->red_mask == 0x00ff0000 && + masks->green_mask == 0x0000ff00 && + masks->blue_mask == 0x000000ff) + { + *format = CAIRO_FORMAT_ARGB32; + return 1; + } + if (masks->alpha_mask == 0x00000000 && + masks->red_mask == 0x00ff0000 && + masks->green_mask == 0x0000ff00 && + masks->blue_mask == 0x000000ff) + { + *format = CAIRO_FORMAT_RGB24; + return 1; + } + break; + case 8: + if (masks->alpha_mask == 0xff) + { + *format = CAIRO_FORMAT_A8; + return 1; + } + break; + case 1: + if (masks->alpha_mask == 0x1) + { + *format = CAIRO_FORMAT_A1; + return 1; + } + break; + } + return 0; +} + static cairo_status_t _get_image_surface (cairo_xcb_surface_t *surface, cairo_rectangle_t *interest_rect, cairo_image_surface_t **image_out, cairo_rectangle_t *image_rect) { - cairo_status_t status; cairo_image_surface_t *image; XCBGetImageRep *imagerep; int bpp, bytes_per_line; int x1, y1, x2, y2; unsigned char *data; + cairo_format_t format; + cairo_format_masks_t masks; x1 = 0; y1 = 0; - - status = _cairo_xcb_surface_get_size (surface, &x2, &y2); - if (status) - return status; + x2 = surface->width; + y2 = surface->height; if (interest_rect) { cairo_rectangle_t rect; @@ -384,8 +397,30 @@ _get_image_surface (cairo_xcb_surface_t *surface, /* XXX: This should try to use the XShm extension if available */ - if (surface->type == CAIRO_XCB_WINDOW) { + if (surface->use_pixmap == 0) + { + XCBGenericError *error; + imagerep = XCBGetImageReply(surface->dpy, + XCBGetImage(surface->dpy, ZPixmap, + surface->drawable, + x1, y1, + x2 - x1, y2 - y1, + AllPlanes), &error); + + /* If we get an error, the surface must have been a window, + * so retry with the safe code path. + */ + if (error) + surface->use_pixmap = CAIRO_ASSUME_PIXMAP; + } + else + { + surface->use_pixmap--; + imagerep = NULL; + } + if (!imagerep) + { /* XCBGetImage from a window is dangerous because it can * produce errors if the window is unmapped or partially * outside the screen. We could check for errors and @@ -412,14 +447,9 @@ _get_image_surface (cairo_xcb_surface_t *surface, AllPlanes), 0); XCBFreePixmap (surface->dpy, drawable.pixmap); - } else { - imagerep = XCBGetImageReply(surface->dpy, - XCBGetImage(surface->dpy, ZPixmap, - surface->drawable, - x1, y1, - x2 - x1, y2 - y1, - AllPlanes), 0); } + if (!imagerep) + return CAIRO_STATUS_NO_MEMORY; bpp = _bits_per_pixel(surface->dpy, imagerep->depth); bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp); @@ -434,10 +464,6 @@ _get_image_surface (cairo_xcb_surface_t *surface, free (imagerep); if (surface->visual) { - cairo_format_masks_t masks; - - /* XXX: Add support here for pictures with external alpha? */ - masks.bpp = bpp; masks.alpha_mask = 0; masks.red_mask = surface->visual->red_mask; @@ -449,13 +475,40 @@ _get_image_surface (cairo_xcb_surface_t *surface, x2 - x1, y2 - y1, bytes_per_line); + } else if (surface->has_format) { + masks.bpp = bpp; + masks.red_mask = surface->format.direct.red_mask << surface->format.direct.red_shift; + masks.green_mask = surface->format.direct.green_mask << surface->format.direct.green_shift; + masks.blue_mask = surface->format.direct.blue_mask << surface->format.direct.blue_shift; + masks.alpha_mask = surface->format.direct.alpha_mask << surface->format.direct.alpha_shift; } else { + masks.bpp = bpp; + masks.red_mask = 0; + masks.green_mask = 0; + masks.blue_mask = 0; + if (surface->depth == 32) + masks.alpha_mask = 0xffffffff; + else + masks.alpha_mask = (1 << surface->depth) - 1; + } + + if (_CAIRO_MASK_FORMAT (&masks, &format)) { image = (cairo_image_surface_t *) cairo_image_surface_create_for_data (data, - surface->format, + format, x2 - x1, y2 - y1, bytes_per_line); + } else { + /* XXX This can't work. We must convert the data to one of the + * supported pixman formats + */ + image = _cairo_image_surface_create_with_masks (data, + &masks, + x2 - x1, + y2 - y1, + bytes_per_line); + } /* Let the surface take ownership of the data */ @@ -879,6 +932,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, cairo_int_status_t status; int render_reference_x, render_reference_y; int render_src_x, render_src_y; + XCBRenderPICTFORMINFO render_format; if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -902,13 +956,14 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, render_src_y = src_y + render_reference_y - dst_y; /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ - /* XXX: format_from_cairo is slow. should cache something. */ + /* XXX: _format_from_cairo is slow. should cache something. */ + render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), status = _cairo_xcb_surface_set_attributes (src, &attributes); if (CAIRO_OK (status)) XCBRenderTrapezoids (dst->dpy, _render_operator (operator), src->picture, dst->picture, - format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), + render_format.id, render_src_x + attributes.x_offset, render_src_y + attributes.y_offset, num_traps, (XCBRenderTRAP *) traps); @@ -931,14 +986,10 @@ _cairo_xcb_surface_get_extents (void *abstract_surface, cairo_rectangle_t *rectangle) { cairo_xcb_surface_t *surface = abstract_surface; - int width, height; rectangle->x = 0; rectangle->y = 0; - _cairo_xcb_surface_get_size (surface, - &width, &height); - rectangle->width = surface->width; rectangle->height = surface->height; @@ -1000,9 +1051,11 @@ query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface) static cairo_surface_t * _cairo_xcb_surface_create_internal (XCBConnection *dpy, XCBDRAWABLE drawable, - cairo_xcb_drawable_type_t type, XCBVISUALTYPE *visual, - cairo_format_t format) + XCBRenderPICTFORMINFO *format, + int width, + int height, + int depth) { cairo_xcb_surface_t *surface; @@ -1012,23 +1065,31 @@ _cairo_xcb_surface_create_internal (XCBConnection *dpy, _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend); - surface->type = type; - surface->dpy = dpy; surface->gc.xid = 0; surface->drawable = drawable; surface->owns_pixmap = FALSE; - surface->width = -1; - surface->height = -1; - - if (visual) { + surface->visual = visual; + if (format) { + surface->format = *format; + surface->has_format = 1; + } else { + surface->format.id.xid = 0; + surface->has_format = 0; + } + surface->use_pixmap = 0; + surface->width = width; + surface->height = height; + surface->depth = depth; + + if (format) { + surface->depth = format->depth; + } else if (visual) { XCBSCREENIter roots; XCBDEPTHIter depths; XCBVISUALTYPEIter visuals; - surface->format = (cairo_format_t)-1; - /* This is ugly, but we have to walk over all visuals * for the display to find the depth. */ @@ -1050,124 +1111,128 @@ _cairo_xcb_surface_create_internal (XCBConnection *dpy, } } found: - - surface->visual = visual; - - } else { - surface->format = format; - surface->depth = _CAIRO_FORMAT_DEPTH (format); - surface->visual = NULL; + ; } query_render_version(dpy, surface); + surface->picture.xid = 0; + if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) { - XCBRenderPICTFORMAT fmt; - if(visual) - fmt = format_from_visual (dpy, visual->visual_id); - else - fmt = format_from_cairo (dpy, format); - surface->picture = XCBRenderPICTURENew(dpy); - XCBRenderCreatePicture (dpy, surface->picture, drawable, - fmt, 0, NULL); + XCBRenderPICTFORMINFO render_format; + if (!format) { + if (visual) { + /* XXX: This case is currently broken. How to fix ? + render_format = format_from_visual (dpy, visual->visual_id); + format = &render_format; + */ + } else if (depth == 1) { + render_format = _format_from_cairo (dpy, CAIRO_FORMAT_A1); + format = &render_format; + } + } + + if (format) { + surface->picture = XCBRenderPICTURENew(dpy); + XCBRenderCreatePicture (dpy, surface->picture, drawable, + format->id, 0, NULL); + } } - else - surface->picture.xid = 0; return (cairo_surface_t *) surface; } /** - * cairo_xcb_surface_create_for_pixmap: - * @dpy: an XCB connection - * @pixmap: an XCB pixmap - * @format: a standard cairo pixel data format. The depth (number of - * of bits used) for the format must match the depth of - * @pixmap. - * - * Creates an XCB surface that draws to the given pixmap. - * The way that colors are represented in the pixmap is specified - * by giving one of cairo's standard pixel data formats. + * cairo_xcb_surface_create: + * @c: an XCB connection + * @drawable: an XCB drawable + * @visual: the visual to use for drawing to @drawable. The depth + * of the visual must match the depth of the drawable. + * Currently, only TrueColor visuals are fully supported. + * @width: the current width of @drawable. + * @height: the current height of @drawable. + * + * Creates an XCB surface that draws to the given drawable. + * The way that colors are represented in the drawable is specified + * by the provided visual. * - * For maximum efficiency, if you know the size of the pixmap, - * you should call cairo_xcb_surface_set_size(). + * NOTE: If @drawable is a window, then the function + * cairo_xcb_surface_set_size must be called whenever the size of the + * window changes. * * Return value: the newly created surface **/ cairo_surface_t * -cairo_xcb_surface_create_for_pixmap (XCBConnection *dpy, - XCBPIXMAP pixmap, - cairo_format_t format) +cairo_xcb_surface_create (XCBConnection *c, + XCBDRAWABLE drawable, + XCBVISUALTYPE *visual, + int width, + int height) { - XCBDRAWABLE drawable; - drawable.pixmap = pixmap; - return _cairo_xcb_surface_create_internal (dpy, drawable, - CAIRO_XCB_PIXMAP, - NULL, format); + return _cairo_xcb_surface_create_internal (c, drawable, + visual, NULL, + width, height, 0); } /** - * cairo_xcb_surface_create_for_pixmap_with_visual: - * @dpy: an XCB connection - * @pixmap: an XCB pixmap - * @visual: the visual to use for drawing to @pixmap. The depth - * of the visual must match the depth of the pixmap. - * Currently, only TrueColor visuals are fully supported. - * - * Creates an XCB surface that draws to the given pixmap. - * The way that colors are represented in the pixmap is specified - * by an XCB visual. - * - * Normally, you would use this function instead of - * cairo_xcb_surface_create_for_pixmap() when you double-buffering by - * using cairo to draw to pixmap and then XCopyArea() to copy the - * results to a window. In that case, @visual is the visual of the - * window. + * cairo_xcb_surface_create_for_bitmap: + * @c: an XCB connection + * @bitmap: an XCB drawable (a depth-1 pixmap) + * @width: the current width of @bitmap + * @height: the current height of @bitmap + * + * Creates an XCB surface that draws to the given bitmap. + * This will be drawn to as a CAIRO_FORMAT_A1 object. * - * For maximum efficiency, if you know the size of the pixmap, - * you should call cairo_xcb_surface_set_size(). + * NOTE: If @drawable is a Window, then the function + * cairo_xlib_surface_set_size must be called whenever the size of the + * window changes. * * Return value: the newly created surface **/ cairo_surface_t * -cairo_xcb_surface_create_for_pixmap_with_visual (XCBConnection *dpy, - XCBPIXMAP pixmap, - XCBVISUALTYPE *visual) +cairo_xcb_surface_create_for_bitmap (XCBConnection *c, + XCBPIXMAP bitmap, + int width, + int height) { XCBDRAWABLE drawable; - drawable.pixmap = pixmap; - return _cairo_xcb_surface_create_internal (dpy, drawable, - CAIRO_XCB_PIXMAP, - visual, - (cairo_format_t)-1); + drawable.pixmap = bitmap; + return _cairo_xcb_surface_create_internal (c, drawable, + NULL, NULL, + width, height, 1); } /** - * cairo_xcb_surface_create_for_window_with_visual: - * @dpy: an XCB connection - * @window: an XCB window - * @visual: the visual of @window. Currently, only TrueColor visuals - * are fully supported. + * cairo_xcb_surface_create_with_xrender_format: + * @c: an XCB connection + * @drawable: an XCB drawable + * @format: the picture format to use for drawing to @drawable. The + * depth of @format mush match the depth of the drawable. + * @width: the current width of @drawable + * @height: the current height of @drawable * - * Creates a new XCB backend surface that draws to the given window. + * Creates an XCB surface that draws to the given drawable. + * The way that colors are represented in the drawable is specified + * by the provided picture format. * - * For maximum efficiency, you should use cairo_xcb_surface_set_size() - * to inform cairo of the size of the window. + * NOTE: If @drawable is a Window, then the function + * cairo_xlib_surface_set_size must be called whenever the size of the + * window changes. * * Return value: the newly created surface. **/ cairo_surface_t * -cairo_xcb_surface_create_for_window_with_visual (XCBConnection *dpy, - XCBWINDOW window, - XCBVISUALTYPE *visual) +cairo_xcb_surface_create_with_xrender_format (XCBConnection *c, + XCBDRAWABLE drawable, + XCBRenderPICTFORMINFO *format, + int width, + int height) { - XCBDRAWABLE drawable; - drawable.window = window; - return _cairo_xcb_surface_create_internal (dpy, drawable, - CAIRO_XCB_WINDOW, - visual, - (cairo_format_t)-1); + return _cairo_xcb_surface_create_internal (c, drawable, + NULL, format, + width, height, 0); } /** @@ -1176,16 +1241,15 @@ cairo_xcb_surface_create_for_window_with_visual (XCBConnection *dpy, * @width: the new width of the surface * @height: the new height of the surface * - * Informs cairo of the size of the X drawable underlying the - * surface. This allows cairo to avoid querying the server for the - * size, which can be a significant performance bottleneck. + * Informs cairo of the new size of the XCB drawable underlying the + * surface. For a surface created for a window (rather than a pixmap), + * this function must be called each time the size of the window + * changes. (For a subwindow, you are normally resizing the window + * yourself, but for a toplevel window, it is necessary to listen for + * ConfigureNotify events.) * - * For a surface created for a pixmap, it is only necessary to call - * this function once, since pixmaps have a fixed size. For a surface - * created for a window, you should call this function each time the - * window changes size. (For a subwindow, you are normally resizing - * the window yourself, but for a top-level window, it is necessary - * to listen for ConfigureNotify events.) + * A pixmap can never change size, so it is never necessary to call + * this function on a surface created for a pixmap. **/ void cairo_xcb_surface_set_size (cairo_surface_t *surface, diff --git a/src/cairo-xcb-xrender.h b/src/cairo-xcb-xrender.h new file mode 100644 index 000000000..ef4baa991 --- /dev/null +++ b/src/cairo-xcb-xrender.h @@ -0,0 +1,62 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + */ + +#ifndef CAIRO_XCB_XRENDER_H +#define CAIRO_XCB_XRENDER_H + +#include <cairo.h> + +#if CAIRO_HAS_XCB_SURFACE + +#include <X11/XCB/xcb.h> +#include <X11/XCB/render.h> + +CAIRO_BEGIN_DECLS + +cairo_surface_t * +cairo_xcb_surface_create_with_xrender_format (XCBConnection *c, + XCBDRAWABLE drawable, + XCBRenderPICTFORMINFO *format, + int width, + int height); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_XCB_SURFACE */ +# error Cairo was not compiled with support for the xcb backend +#endif /* CAIRO_HAS_XCB_SURFACE */ + +#endif /* CAIRO_XCB_XRENDER_H */ diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h index abc11cf54..57a7aebd1 100644 --- a/src/cairo-xcb.h +++ b/src/cairo-xcb.h @@ -42,24 +42,21 @@ #if CAIRO_HAS_XCB_SURFACE #include <X11/XCB/xcb.h> -#include <X11/XCB/render.h> CAIRO_BEGIN_DECLS cairo_surface_t * -cairo_xcb_surface_create_for_pixmap (XCBConnection *c, - XCBPIXMAP pixmap, - cairo_format_t format); +cairo_xcb_surface_create (XCBConnection *c, + XCBDRAWABLE pixmap, + XCBVISUALTYPE *visual, + int width, + int height); cairo_surface_t * -cairo_xcb_surface_create_for_pixmap_with_visual (XCBConnection *c, - XCBPIXMAP pixmap, - XCBVISUALTYPE *visual); - -cairo_surface_t * -cairo_xcb_surface_create_for_window_with_visual (XCBConnection *c, - XCBWINDOW window, - XCBVISUALTYPE *visual); +cairo_xcb_surface_create_for_bitmap (XCBConnection *c, + XCBPIXMAP bitmap, + int width, + int height); void cairo_xcb_surface_set_size (cairo_surface_t *surface, diff --git a/test/cairo-test.c b/test/cairo-test.c index 45b6c550c..d8ce6800f 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -193,13 +193,102 @@ cleanup_win32 (void *closure) #endif #if CAIRO_HAS_XCB_SURFACE -#include "cairo-xcb.h" +#include "cairo-xcb-xrender.h" typedef struct _xcb_target_closure { XCBConnection *c; - XCBPIXMAP pixmap; + XCBDRAWABLE drawable; } xcb_target_closure_t; +/* XXX: This is a nasty hack. Something like this should be in XCB's + * bindings for Render, not here in this test. */ +static XCBRenderPICTFORMINFO +_format_from_cairo(XCBConnection *c, cairo_format_t fmt) +{ + XCBRenderPICTFORMINFO ret = {{ 0 }}; + struct tmpl_t { + XCBRenderDIRECTFORMAT direct; + CARD8 depth; + }; + static const struct tmpl_t templates[] = { + /* CAIRO_FORMAT_ARGB32 */ + { + { + 16, 0xff, + 8, 0xff, + 0, 0xff, + 24, 0xff + }, + 32 + }, + /* CAIRO_FORMAT_RGB24 */ + { + { + 16, 0xff, + 8, 0xff, + 0, 0xff, + 0, 0x00 + }, + 24 + }, + /* CAIRO_FORMAT_A8 */ + { + { + 0, 0x00, + 0, 0x00, + 0, 0x00, + 0, 0xff + }, + 8 + }, + /* CAIRO_FORMAT_A1 */ + { + { + 0, 0x00, + 0, 0x00, + 0, 0x00, + 0, 0x01 + }, + 1 + }, + }; + const struct tmpl_t *tmpl; + XCBRenderQueryPictFormatsRep *r; + XCBRenderPICTFORMINFOIter fi; + + if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates))) + return ret; + tmpl = templates + fmt; + + r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0); + if(!r) + return ret; + + for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi)) + { + const XCBRenderDIRECTFORMAT *t, *f; + if(fi.data->type != XCBRenderPictTypeDirect) + continue; + if(fi.data->depth != tmpl->depth) + continue; + t = &tmpl->direct; + f = &fi.data->direct; + if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift)) + continue; + if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift)) + continue; + if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift)) + continue; + if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift)) + continue; + + ret = *fi.data; + } + + free(r); + return ret; +} + static cairo_surface_t * create_xcb_surface (int width, int height, void **closure) { @@ -207,6 +296,7 @@ create_xcb_surface (int width, int height, void **closure) xcb_target_closure_t *xtc; cairo_surface_t *surface; XCBConnection *c; + XCBRenderPICTFORMINFO render_format; *closure = xtc = xmalloc (sizeof (xcb_target_closure_t)); @@ -216,24 +306,27 @@ create_xcb_surface (int width, int height, void **closure) height = 1; xtc->c = c = XCBConnectBasic(); - root = XCBConnSetupSuccessRepRootsIter(XCBGetSetup(c)).data; - if (c == NULL) { cairo_test_log ("Failed to connect to X server through XCB\n"); return NULL; } - xtc->pixmap = XCBPIXMAPNew (c); - /* XXX: What in the world is the drawable argument to XCBCreatePixmap ? */ + root = XCBConnSetupSuccessRepRootsIter(XCBGetSetup(c)).data; + + xtc->drawable.pixmap = XCBPIXMAPNew (c); { XCBDRAWABLE root_drawable; root_drawable.window = root->root; - XCBCreatePixmap (c, 32, xtc->pixmap, root_drawable, width, height); + XCBCreatePixmap (c, 32, xtc->drawable.pixmap, root_drawable, + width, height); } - surface = cairo_xcb_surface_create_for_pixmap (c, xtc->pixmap, - CAIRO_FORMAT_ARGB32); - cairo_xcb_surface_set_size (surface, width, height); + render_format = _format_from_cairo (c, CAIRO_FORMAT_ARGB32); + if (render_format.id.xid == 0) + return NULL; + surface = cairo_xcb_surface_create_with_xrender_format (c, xtc->drawable, + &render_format, + width, height); return surface; } @@ -243,7 +336,7 @@ cleanup_xcb (void *closure) { xcb_target_closure_t *xtc = closure; - XCBFreePixmap (xtc->c, xtc->pixmap); + XCBFreePixmap (xtc->c, xtc->drawable.pixmap); XCBDisconnect (xtc->c); } #endif |