mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-01 04:28:03 +02:00
Rework occurrences of 'if (status == CAIRO_STATUS_SUCCESS)' to use 'if (status)' instead where trivial.
1267 lines
34 KiB
C
1267 lines
34 KiB
C
/* 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>
|
|
*/
|
|
|
|
#include "cairoint.h"
|
|
#include "cairo-xcb.h"
|
|
#include "cairo-xcb-xrender.h"
|
|
|
|
#define AllPlanes ((unsigned long)~0L)
|
|
|
|
static XCBRenderPICTFORMAT
|
|
format_from_visual(XCBConnection *c, XCBVISUALID visual)
|
|
{
|
|
static const XCBRenderPICTFORMAT nil = { 0 };
|
|
XCBRenderQueryPictFormatsRep *r;
|
|
XCBRenderPICTSCREENIter si;
|
|
XCBRenderPICTDEPTHIter di;
|
|
XCBRenderPICTVISUALIter vi;
|
|
|
|
r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
|
|
if(!r)
|
|
return nil;
|
|
|
|
for(si = XCBRenderQueryPictFormatsScreensIter(r); si.rem; XCBRenderPICTSCREENNext(&si))
|
|
for(di = XCBRenderPICTSCREENDepthsIter(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
|
|
for(vi = XCBRenderPICTDEPTHVisualsIter(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
|
|
if(vi.data->visual.id == visual.id)
|
|
{
|
|
XCBRenderPICTFORMAT ret = vi.data->format;
|
|
free(r);
|
|
return ret;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
|
|
XCBConnection *dpy;
|
|
XCBGCONTEXT gc;
|
|
XCBDRAWABLE drawable;
|
|
int owns_pixmap;
|
|
XCBVISUALTYPE *visual;
|
|
|
|
int use_pixmap;
|
|
|
|
int render_major;
|
|
int render_minor;
|
|
|
|
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) \
|
|
(((surface)->render_major > major) || \
|
|
(((surface)->render_major == major) && ((surface)->render_minor >= minor)))
|
|
|
|
#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
|
|
#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
|
|
|
|
#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
|
|
#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
|
|
|
|
#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
|
|
#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
|
|
|
|
#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
|
|
#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
|
|
#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
|
|
#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
|
|
|
|
#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
|
|
#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
|
|
|
|
static void
|
|
_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);
|
|
|
|
static int
|
|
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
|
|
{
|
|
switch (format) {
|
|
case CAIRO_FORMAT_A1:
|
|
return 1;
|
|
case CAIRO_FORMAT_A8:
|
|
return 8;
|
|
case CAIRO_FORMAT_RGB24:
|
|
return 24;
|
|
case CAIRO_FORMAT_ARGB32:
|
|
default:
|
|
return 32;
|
|
}
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
_cairo_xcb_surface_create_similar (void *abstract_src,
|
|
cairo_format_t format,
|
|
int drawable,
|
|
int width,
|
|
int height)
|
|
{
|
|
cairo_xcb_surface_t *src = 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
|
|
*/
|
|
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) {
|
|
return cairo_image_surface_create (format, width, height);
|
|
}
|
|
|
|
d.pixmap = XCBPIXMAPNew (dpy);
|
|
XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
|
|
d.pixmap, src->drawable,
|
|
width <= 0 ? 1 : width,
|
|
height <= 0 ? 1 : height);
|
|
|
|
surface = (cairo_xcb_surface_t *)
|
|
cairo_xcb_surface_create_with_xrender_format (dpy, d,
|
|
&xrender_format,
|
|
width, height);
|
|
|
|
surface->owns_pixmap = TRUE;
|
|
|
|
return &surface->base;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_cairo_xcb_surface_finish (void *abstract_surface)
|
|
{
|
|
cairo_xcb_surface_t *surface = abstract_surface;
|
|
if (surface->picture.xid)
|
|
XCBRenderFreePicture (surface->dpy, surface->picture);
|
|
|
|
if (surface->owns_pixmap)
|
|
XCBFreePixmap (surface->dpy, surface->drawable.pixmap);
|
|
|
|
if (surface->gc.xid)
|
|
XCBFreeGC (surface->dpy, surface->gc);
|
|
|
|
surface->dpy = NULL;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static int
|
|
_bits_per_pixel(XCBConnection *c, int depth)
|
|
{
|
|
XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c));
|
|
XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c));
|
|
|
|
for(; fmt != fmtend; ++fmt)
|
|
if(fmt->depth == depth)
|
|
return fmt->bits_per_pixel;
|
|
|
|
if(depth <= 4)
|
|
return 4;
|
|
if(depth <= 8)
|
|
return 8;
|
|
if(depth <= 16)
|
|
return 16;
|
|
return 32;
|
|
}
|
|
|
|
static int
|
|
_bytes_per_line(XCBConnection *c, int width, int bpp)
|
|
{
|
|
int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
|
|
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_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;
|
|
x2 = surface->width;
|
|
y2 = surface->height;
|
|
|
|
if (interest_rect) {
|
|
cairo_rectangle_t rect;
|
|
|
|
rect.x = interest_rect->x;
|
|
rect.y = interest_rect->y;
|
|
rect.width = interest_rect->width;
|
|
rect.height = interest_rect->width;
|
|
|
|
if (rect.x > x1)
|
|
x1 = rect.x;
|
|
if (rect.y > y1)
|
|
y1 = rect.y;
|
|
if (rect.x + rect.width < x2)
|
|
x2 = rect.x + rect.width;
|
|
if (rect.y + rect.height < y2)
|
|
y2 = rect.y + rect.height;
|
|
|
|
if (x1 >= x2 || y1 >= y2) {
|
|
*image_out = NULL;
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (image_rect) {
|
|
image_rect->x = x1;
|
|
image_rect->y = y1;
|
|
image_rect->width = x2 - x1;
|
|
image_rect->height = y2 - y1;
|
|
}
|
|
|
|
/* XXX: This should try to use the XShm extension if available */
|
|
|
|
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
|
|
* retry, but to keep things simple, we just create a
|
|
* temporary pixmap
|
|
*/
|
|
XCBDRAWABLE drawable;
|
|
drawable.pixmap = XCBPIXMAPNew (surface->dpy);
|
|
XCBCreatePixmap (surface->dpy,
|
|
surface->depth,
|
|
drawable.pixmap,
|
|
surface->drawable,
|
|
x2 - x1, y2 - y1);
|
|
_cairo_xcb_surface_ensure_gc (surface);
|
|
|
|
XCBCopyArea (surface->dpy, surface->drawable, drawable, surface->gc,
|
|
x1, y1, 0, 0, x2 - x1, y2 - y1);
|
|
|
|
imagerep = XCBGetImageReply(surface->dpy,
|
|
XCBGetImage(surface->dpy, ZPixmap,
|
|
drawable,
|
|
x1, y1,
|
|
x2 - x1, y2 - y1,
|
|
AllPlanes), 0);
|
|
XCBFreePixmap (surface->dpy, drawable.pixmap);
|
|
|
|
}
|
|
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);
|
|
|
|
data = malloc (bytes_per_line * surface->height);
|
|
if (data == NULL) {
|
|
free (imagerep);
|
|
return CAIRO_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
memcpy (data, XCBGetImageData (imagerep), bytes_per_line * surface->height);
|
|
free (imagerep);
|
|
|
|
/*
|
|
* Compute the pixel format masks from either an XCBVISUALTYPE or
|
|
* a XCBRenderPCTFORMINFO, failing we assume the drawable is an
|
|
* alpha-only pixmap as it could only have been created that way
|
|
* through the cairo_xlib_surface_create_for_bitmap function.
|
|
*/
|
|
if (surface->visual) {
|
|
masks.bpp = bpp;
|
|
masks.alpha_mask = 0;
|
|
masks.red_mask = surface->visual->red_mask;
|
|
masks.green_mask = surface->visual->green_mask;
|
|
masks.blue_mask = surface->visual->blue_mask;
|
|
} 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 = (1 << surface->depth) - 1;
|
|
else
|
|
masks.alpha_mask = 0xffffffff;
|
|
}
|
|
|
|
/*
|
|
* Prefer to use a standard pixman format instead of the
|
|
* general masks case.
|
|
*/
|
|
if (_CAIRO_MASK_FORMAT (&masks, &format)) {
|
|
image = (cairo_image_surface_t *)
|
|
cairo_image_surface_create_for_data (data,
|
|
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. Pixman needs another function
|
|
* which takes data in an arbitrary format and converts it
|
|
* to something supported by that library.
|
|
*/
|
|
image = _cairo_image_surface_create_with_masks (data,
|
|
&masks,
|
|
x2 - x1,
|
|
y2 - y1,
|
|
bytes_per_line);
|
|
|
|
}
|
|
|
|
/* Let the surface take ownership of the data */
|
|
_cairo_image_surface_assume_ownership_of_data (image);
|
|
|
|
_cairo_image_surface_set_repeat (image, surface->base.repeat);
|
|
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
|
|
|
|
*image_out = image;
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
|
|
{
|
|
if (surface->gc.xid)
|
|
return;
|
|
|
|
surface->gc = XCBGCONTEXTNew(surface->dpy);
|
|
XCBCreateGC (surface->dpy, surface->gc, surface->drawable, 0, 0);
|
|
}
|
|
|
|
static cairo_status_t
|
|
_draw_image_surface (cairo_xcb_surface_t *surface,
|
|
cairo_image_surface_t *image,
|
|
int dst_x,
|
|
int dst_y)
|
|
{
|
|
int bpp, data_len;
|
|
|
|
_cairo_xcb_surface_ensure_gc (surface);
|
|
bpp = _bits_per_pixel(surface->dpy, image->depth);
|
|
data_len = _bytes_per_line(surface->dpy, image->width, bpp) * image->height;
|
|
XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
|
|
image->width,
|
|
image->height,
|
|
dst_x, dst_y,
|
|
/* left_pad */ 0, image->depth,
|
|
data_len, image->data);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
|
|
cairo_image_surface_t **image_out,
|
|
void **image_extra)
|
|
{
|
|
cairo_xcb_surface_t *surface = abstract_surface;
|
|
cairo_image_surface_t *image;
|
|
cairo_status_t status;
|
|
|
|
status = _get_image_surface (surface, NULL, &image, NULL);
|
|
if (status)
|
|
return status;
|
|
|
|
*image_out = image;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
_cairo_xcb_surface_release_source_image (void *abstract_surface,
|
|
cairo_image_surface_t *image,
|
|
void *image_extra)
|
|
{
|
|
cairo_surface_destroy (&image->base);
|
|
}
|
|
|
|
static cairo_status_t
|
|
_cairo_xcb_surface_acquire_dest_image (void *abstract_surface,
|
|
cairo_rectangle_t *interest_rect,
|
|
cairo_image_surface_t **image_out,
|
|
cairo_rectangle_t *image_rect_out,
|
|
void **image_extra)
|
|
{
|
|
cairo_xcb_surface_t *surface = abstract_surface;
|
|
cairo_image_surface_t *image;
|
|
cairo_status_t status;
|
|
|
|
status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
|
|
if (status)
|
|
return status;
|
|
|
|
*image_out = image;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
_cairo_xcb_surface_release_dest_image (void *abstract_surface,
|
|
cairo_rectangle_t *interest_rect,
|
|
cairo_image_surface_t *image,
|
|
cairo_rectangle_t *image_rect,
|
|
void *image_extra)
|
|
{
|
|
cairo_xcb_surface_t *surface = abstract_surface;
|
|
|
|
/* ignore errors */
|
|
_draw_image_surface (surface, image, image_rect->x, image_rect->y);
|
|
|
|
cairo_surface_destroy (&image->base);
|
|
}
|
|
|
|
static cairo_status_t
|
|
_cairo_xcb_surface_clone_similar (void *abstract_surface,
|
|
cairo_surface_t *src,
|
|
cairo_surface_t **clone_out)
|
|
{
|
|
cairo_xcb_surface_t *surface = abstract_surface;
|
|
cairo_xcb_surface_t *clone;
|
|
|
|
if (src->backend == surface->base.backend ) {
|
|
cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
|
|
|
|
if (xcb_src->dpy == surface->dpy) {
|
|
*clone_out = src;
|
|
cairo_surface_reference (src);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
} else if (_cairo_surface_is_image (src)) {
|
|
cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
|
|
|
|
clone = (cairo_xcb_surface_t *)
|
|
_cairo_xcb_surface_create_similar (surface, image_src->format, 0,
|
|
image_src->width, image_src->height);
|
|
if (clone == NULL)
|
|
return CAIRO_STATUS_NO_MEMORY;
|
|
|
|
_draw_image_surface (clone, image_src, 0, 0);
|
|
|
|
*clone_out = &clone->base;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
|
|
cairo_matrix_t *matrix)
|
|
{
|
|
XCBRenderTRANSFORM xtransform;
|
|
|
|
if (!surface->picture.xid)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
xtransform.matrix11 = _cairo_fixed_from_double (matrix->xx);
|
|
xtransform.matrix12 = _cairo_fixed_from_double (matrix->xy);
|
|
xtransform.matrix13 = _cairo_fixed_from_double (matrix->x0);
|
|
|
|
xtransform.matrix21 = _cairo_fixed_from_double (matrix->yx);
|
|
xtransform.matrix22 = _cairo_fixed_from_double (matrix->yy);
|
|
xtransform.matrix23 = _cairo_fixed_from_double (matrix->y0);
|
|
|
|
xtransform.matrix31 = 0;
|
|
xtransform.matrix32 = 0;
|
|
xtransform.matrix33 = _cairo_fixed_from_double (1);
|
|
|
|
if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
|
|
{
|
|
static const XCBRenderTRANSFORM identity = {
|
|
1 << 16, 0x00000, 0x00000,
|
|
0x00000, 1 << 16, 0x00000,
|
|
0x00000, 0x00000, 1 << 16
|
|
};
|
|
|
|
if (memcmp (&xtransform, &identity, sizeof (XCBRenderTRANSFORM)) == 0)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
|
|
cairo_filter_t filter)
|
|
{
|
|
char *render_filter;
|
|
|
|
if (!surface->picture.xid)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
|
|
{
|
|
if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
switch (filter) {
|
|
case CAIRO_FILTER_FAST:
|
|
render_filter = "fast";
|
|
break;
|
|
case CAIRO_FILTER_GOOD:
|
|
render_filter = "good";
|
|
break;
|
|
case CAIRO_FILTER_BEST:
|
|
render_filter = "best";
|
|
break;
|
|
case CAIRO_FILTER_NEAREST:
|
|
render_filter = "nearest";
|
|
break;
|
|
case CAIRO_FILTER_BILINEAR:
|
|
render_filter = "bilinear";
|
|
break;
|
|
default:
|
|
render_filter = "best";
|
|
break;
|
|
}
|
|
|
|
XCBRenderSetPictureFilter(surface->dpy, surface->picture,
|
|
strlen(render_filter), render_filter, 0, NULL);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
|
|
{
|
|
CARD32 mask = XCBRenderCPRepeat;
|
|
CARD32 pa[] = { repeat };
|
|
|
|
if (!surface->picture.xid)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
XCBRenderChangePicture (surface->dpy, surface->picture, mask, pa);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
|
|
cairo_surface_attributes_t *attributes)
|
|
{
|
|
cairo_int_status_t status;
|
|
|
|
status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
|
|
if (status)
|
|
return status;
|
|
|
|
switch (attributes->extend) {
|
|
case CAIRO_EXTEND_NONE:
|
|
_cairo_xcb_surface_set_repeat (surface, 0);
|
|
break;
|
|
case CAIRO_EXTEND_REPEAT:
|
|
_cairo_xcb_surface_set_repeat (surface, 1);
|
|
break;
|
|
case CAIRO_EXTEND_REFLECT:
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
}
|
|
|
|
status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
|
|
if (status)
|
|
return status;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static int
|
|
_render_operator (cairo_operator_t operator)
|
|
{
|
|
switch (operator) {
|
|
case CAIRO_OPERATOR_CLEAR:
|
|
return XCBRenderPictOpClear;
|
|
case CAIRO_OPERATOR_SOURCE:
|
|
return XCBRenderPictOpSrc;
|
|
case CAIRO_OPERATOR_DEST:
|
|
return XCBRenderPictOpDst;
|
|
case CAIRO_OPERATOR_OVER:
|
|
return XCBRenderPictOpOver;
|
|
case CAIRO_OPERATOR_DEST_OVER:
|
|
return XCBRenderPictOpOverReverse;
|
|
case CAIRO_OPERATOR_IN:
|
|
return XCBRenderPictOpIn;
|
|
case CAIRO_OPERATOR_DEST_IN:
|
|
return XCBRenderPictOpInReverse;
|
|
case CAIRO_OPERATOR_OUT:
|
|
return XCBRenderPictOpOut;
|
|
case CAIRO_OPERATOR_DEST_OUT:
|
|
return XCBRenderPictOpOutReverse;
|
|
case CAIRO_OPERATOR_ATOP:
|
|
return XCBRenderPictOpAtop;
|
|
case CAIRO_OPERATOR_DEST_ATOP:
|
|
return XCBRenderPictOpAtopReverse;
|
|
case CAIRO_OPERATOR_XOR:
|
|
return XCBRenderPictOpXor;
|
|
case CAIRO_OPERATOR_ADD:
|
|
return XCBRenderPictOpAdd;
|
|
case CAIRO_OPERATOR_SATURATE:
|
|
return XCBRenderPictOpSaturate;
|
|
default:
|
|
return XCBRenderPictOpOver;
|
|
}
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_xcb_surface_composite (cairo_operator_t operator,
|
|
cairo_pattern_t *src_pattern,
|
|
cairo_pattern_t *mask_pattern,
|
|
void *abstract_dst,
|
|
int src_x,
|
|
int src_y,
|
|
int mask_x,
|
|
int mask_y,
|
|
int dst_x,
|
|
int dst_y,
|
|
unsigned int width,
|
|
unsigned int height)
|
|
{
|
|
cairo_surface_attributes_t src_attr, mask_attr;
|
|
cairo_xcb_surface_t *dst = abstract_dst;
|
|
cairo_xcb_surface_t *src;
|
|
cairo_xcb_surface_t *mask;
|
|
cairo_int_status_t status;
|
|
|
|
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
|
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
|
|
&dst->base,
|
|
src_x, src_y,
|
|
mask_x, mask_y,
|
|
width, height,
|
|
(cairo_surface_t **) &src,
|
|
(cairo_surface_t **) &mask,
|
|
&src_attr, &mask_attr);
|
|
if (status)
|
|
return status;
|
|
|
|
status = _cairo_xcb_surface_set_attributes (src, &src_attr);
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
{
|
|
if (mask)
|
|
{
|
|
status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
XCBRenderComposite (dst->dpy,
|
|
_render_operator (operator),
|
|
src->picture,
|
|
mask->picture,
|
|
dst->picture,
|
|
src_x + src_attr.x_offset,
|
|
src_y + src_attr.y_offset,
|
|
mask_x + mask_attr.x_offset,
|
|
mask_y + mask_attr.y_offset,
|
|
dst_x, dst_y,
|
|
width, height);
|
|
}
|
|
else
|
|
{
|
|
static XCBRenderPICTURE maskpict = { 0 };
|
|
|
|
XCBRenderComposite (dst->dpy,
|
|
_render_operator (operator),
|
|
src->picture,
|
|
maskpict,
|
|
dst->picture,
|
|
src_x + src_attr.x_offset,
|
|
src_y + src_attr.y_offset,
|
|
0, 0,
|
|
dst_x, dst_y,
|
|
width, height);
|
|
}
|
|
}
|
|
|
|
if (mask)
|
|
_cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
|
|
|
|
_cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
|
|
|
|
return status;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_xcb_surface_fill_rectangles (void *abstract_surface,
|
|
cairo_operator_t operator,
|
|
const cairo_color_t *color,
|
|
cairo_rectangle_t *rects,
|
|
int num_rects)
|
|
{
|
|
cairo_xcb_surface_t *surface = abstract_surface;
|
|
XCBRenderCOLOR render_color;
|
|
|
|
if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
|
render_color.red = color->red_short;
|
|
render_color.green = color->green_short;
|
|
render_color.blue = color->blue_short;
|
|
render_color.alpha = color->alpha_short;
|
|
|
|
/* XXX: This XCBRECTANGLE cast is evil... it needs to go away somehow. */
|
|
XCBRenderFillRectangles (surface->dpy,
|
|
_render_operator (operator),
|
|
surface->picture,
|
|
render_color, num_rects, (XCBRECTANGLE *) rects);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
|
|
cairo_pattern_t *pattern,
|
|
void *abstract_dst,
|
|
int src_x,
|
|
int src_y,
|
|
int dst_x,
|
|
int dst_y,
|
|
unsigned int width,
|
|
unsigned int height,
|
|
cairo_trapezoid_t *traps,
|
|
int num_traps)
|
|
{
|
|
cairo_surface_attributes_t attributes;
|
|
cairo_xcb_surface_t *dst = abstract_dst;
|
|
cairo_xcb_surface_t *src;
|
|
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;
|
|
|
|
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
|
|
src_x, src_y, width, height,
|
|
(cairo_surface_t **) &src,
|
|
&attributes);
|
|
if (status)
|
|
return status;
|
|
|
|
if (traps[0].left.p1.y < traps[0].left.p2.y) {
|
|
render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
|
|
render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
|
|
} else {
|
|
render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
|
|
render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
|
|
}
|
|
|
|
render_src_x = src_x + render_reference_x - dst_x;
|
|
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. */
|
|
render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
|
|
status = _cairo_xcb_surface_set_attributes (src, &attributes);
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
XCBRenderTrapezoids (dst->dpy,
|
|
_render_operator (operator),
|
|
src->picture, dst->picture,
|
|
render_format.id,
|
|
render_src_x + attributes.x_offset,
|
|
render_src_y + attributes.y_offset,
|
|
num_traps, (XCBRenderTRAP *) traps);
|
|
|
|
_cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
|
|
|
|
return status;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_xcb_surface_get_extents (void *abstract_surface,
|
|
cairo_rectangle_t *rectangle)
|
|
{
|
|
cairo_xcb_surface_t *surface = abstract_surface;
|
|
|
|
rectangle->x = 0;
|
|
rectangle->y = 0;
|
|
|
|
rectangle->width = surface->width;
|
|
rectangle->height = surface->height;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
|
|
_cairo_xcb_surface_create_similar,
|
|
_cairo_xcb_surface_finish,
|
|
_cairo_xcb_surface_acquire_source_image,
|
|
_cairo_xcb_surface_release_source_image,
|
|
_cairo_xcb_surface_acquire_dest_image,
|
|
_cairo_xcb_surface_release_dest_image,
|
|
_cairo_xcb_surface_clone_similar,
|
|
_cairo_xcb_surface_composite,
|
|
_cairo_xcb_surface_fill_rectangles,
|
|
_cairo_xcb_surface_composite_trapezoids,
|
|
NULL, /* copy_page */
|
|
NULL, /* show_page */
|
|
NULL, /* _cairo_xcb_surface_set_clip_region */
|
|
_cairo_xcb_surface_get_extents,
|
|
NULL /* show_glyphs */
|
|
};
|
|
|
|
/**
|
|
* _cairo_surface_is_xcb:
|
|
* @surface: a #cairo_surface_t
|
|
*
|
|
* Checks if a surface is a #cairo_xcb_surface_t
|
|
*
|
|
* Return value: True if the surface is an xcb surface
|
|
**/
|
|
static cairo_bool_t
|
|
_cairo_surface_is_xcb (cairo_surface_t *surface)
|
|
{
|
|
return surface->backend == &cairo_xcb_surface_backend;
|
|
}
|
|
|
|
static void
|
|
query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
|
|
{
|
|
XCBRenderQueryVersionRep *r;
|
|
|
|
surface->render_major = -1;
|
|
surface->render_minor = -1;
|
|
|
|
if (!XCBRenderInit(c))
|
|
return;
|
|
|
|
r = XCBRenderQueryVersionReply(c, XCBRenderQueryVersion(c, 0, 6), 0);
|
|
if (!r)
|
|
return;
|
|
|
|
surface->render_major = r->major_version;
|
|
surface->render_minor = r->minor_version;
|
|
free(r);
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
_cairo_xcb_surface_create_internal (XCBConnection *dpy,
|
|
XCBDRAWABLE drawable,
|
|
XCBVISUALTYPE *visual,
|
|
XCBRenderPICTFORMINFO *format,
|
|
int width,
|
|
int height,
|
|
int depth)
|
|
{
|
|
cairo_xcb_surface_t *surface;
|
|
|
|
surface = malloc (sizeof (cairo_xcb_surface_t));
|
|
if (surface == NULL)
|
|
return NULL;
|
|
|
|
_cairo_surface_init (&surface->base, &cairo_xcb_surface_backend);
|
|
|
|
surface->dpy = dpy;
|
|
|
|
surface->gc.xid = 0;
|
|
surface->drawable = drawable;
|
|
surface->owns_pixmap = FALSE;
|
|
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;
|
|
|
|
/* This is ugly, but we have to walk over all visuals
|
|
* for the display to find the depth.
|
|
*/
|
|
roots = XCBConnSetupSuccessRepRootsIter(XCBGetSetup(surface->dpy));
|
|
for(; roots.rem; XCBSCREENNext(&roots))
|
|
{
|
|
depths = XCBSCREENAllowedDepthsIter(roots.data);
|
|
for(; depths.rem; XCBDEPTHNext(&depths))
|
|
{
|
|
visuals = XCBDEPTHVisualsIter(depths.data);
|
|
for(; visuals.rem; XCBVISUALTYPENext(&visuals))
|
|
{
|
|
if(visuals.data->visual_id.id == visual->visual_id.id)
|
|
{
|
|
surface->depth = depths.data->depth;
|
|
goto found;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
found:
|
|
;
|
|
}
|
|
|
|
query_render_version(dpy, surface);
|
|
|
|
surface->picture.xid = 0;
|
|
|
|
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
|
|
{
|
|
XCBRenderPICTFORMAT pict_format = {0};
|
|
XCBRenderPICTFORMINFO format_info;
|
|
|
|
surface->picture = XCBRenderPICTURENew(dpy);
|
|
|
|
if (!format) {
|
|
if (visual) {
|
|
pict_format = format_from_visual (dpy, visual->visual_id);
|
|
} else if (depth == 1) {
|
|
format_info = _format_from_cairo (dpy, CAIRO_FORMAT_A1);
|
|
pict_format = format_info.id;
|
|
}
|
|
XCBRenderCreatePicture (dpy, surface->picture, drawable,
|
|
pict_format, 0, NULL);
|
|
} else {
|
|
XCBRenderCreatePicture (dpy, surface->picture, drawable,
|
|
format->id, 0, NULL);
|
|
}
|
|
}
|
|
|
|
return (cairo_surface_t *) surface;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* 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 (XCBConnection *c,
|
|
XCBDRAWABLE drawable,
|
|
XCBVISUALTYPE *visual,
|
|
int width,
|
|
int height)
|
|
{
|
|
return _cairo_xcb_surface_create_internal (c, drawable,
|
|
visual, NULL,
|
|
width, height, 0);
|
|
}
|
|
|
|
/**
|
|
* cairo_xcb_surface_create_for_bitmap:
|
|
* @c: an XCB connection
|
|
* @bitmap: an XCB Pixmap (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.
|
|
*
|
|
* Return value: the newly created surface
|
|
**/
|
|
cairo_surface_t *
|
|
cairo_xcb_surface_create_for_bitmap (XCBConnection *c,
|
|
XCBPIXMAP bitmap,
|
|
int width,
|
|
int height)
|
|
{
|
|
XCBDRAWABLE drawable;
|
|
drawable.pixmap = bitmap;
|
|
return _cairo_xcb_surface_create_internal (c, drawable,
|
|
NULL, NULL,
|
|
width, height, 1);
|
|
}
|
|
|
|
/**
|
|
* 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 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.
|
|
*
|
|
* 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_with_xrender_format (XCBConnection *c,
|
|
XCBDRAWABLE drawable,
|
|
XCBRenderPICTFORMINFO *format,
|
|
int width,
|
|
int height)
|
|
{
|
|
return _cairo_xcb_surface_create_internal (c, drawable,
|
|
NULL, format,
|
|
width, height, 0);
|
|
}
|
|
|
|
/**
|
|
* cairo_xcb_surface_set_size:
|
|
* @surface: a #cairo_surface_t for the XCB backend
|
|
* @width: the new width of the surface
|
|
* @height: the new height of the surface
|
|
*
|
|
* 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.)
|
|
*
|
|
* 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,
|
|
int width,
|
|
int height)
|
|
{
|
|
cairo_xcb_surface_t *xcb_surface = (cairo_xcb_surface_t *)surface;
|
|
|
|
/* XXX: How do we want to handle this error case? */
|
|
if (! _cairo_surface_is_xcb (surface))
|
|
return;
|
|
|
|
xcb_surface->width = width;
|
|
xcb_surface->height = height;
|
|
}
|
|
|