Update xcb backend

This commit is contained in:
David Reveman 2005-03-03 20:16:23 +00:00
parent f54f78525a
commit 4552898cfb
4 changed files with 626 additions and 288 deletions

View file

@ -1,5 +1,9 @@
2005-03-04 David Reveman <davidr@novell.com>
* configure.in: Enable xcb backend.
* src/cairo_xcb_surface.c: Update xcb backend.
* configure.in: Fixed variable assignments.
* src/cairo_glitz_surface.c: Add overall alpha acceleration

View file

@ -102,7 +102,7 @@ dnl ===========================================================================
AC_ARG_ENABLE(xcb,
[ --disable-xcb Disable cairo's XCB backend],
[use_xcb=$enableval], [use_xcb="no (temporarily disabled while code is out of sync)"])
[use_xcb=$enableval], [use_xcb=yes])
if test "x$use_xcb" = "xyes"; then
PKG_CHECK_MODULES(XCB, xcb, [use_xcb=yes], [
@ -229,7 +229,7 @@ dnl ===========================================================================
AC_ARG_ENABLE(glitz,
[ --disable-glitz Disable cairo's glitz backend],
[use_glitz=$enableval], [use_glitz="yes"])
[use_glitz=$enableval], [use_glitz=yes])
if test "x$use_glitz" = "xyes"; then
PKG_CHECK_MODULES(GLITZ, glitz >= 0.4.0, [

View file

@ -328,14 +328,17 @@ bytes_per_line(XCBConnection *c, int width, int bpp)
return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
}
static cairo_image_surface_t *
_cairo_xcb_surface_get_image (void *abstract_surface)
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_xcb_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
XCBGetGeometryRep *geomrep;
XCBGetImageRep *imagerep;
int bpp;
int x1, y1, x2, y2;
geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
if(!geomrep)
@ -345,11 +348,39 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
surface->height = geomrep->height;
free(geomrep);
x1 = 0;
y1 = 0;
x2 = surface->width;
y2 = surface->height;
if (interest_rect) {
if (interest_rect->x > x1)
x1 = interest_rect->x;
if (interest_rect->y > y1)
y1 = interest_rect->y;
if (interest_rect->x + interest_rect->width < x2)
x2 = interest_rect->x + interest_rect->width;
if (interest_rect->y + interest_rect->height < y2)
y2 = interest_rect->y + interest_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;
}
imagerep = XCBGetImageReply(surface->dpy,
XCBGetImage(surface->dpy, ZPixmap,
surface->drawable,
0, 0,
surface->width, surface->height,
x1, y1,
x2 - x1, y2 - y1,
AllPlanes), 0);
if(!imagerep)
return 0;
@ -369,15 +400,15 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
&masks,
surface->width,
surface->height,
x2 - x1,
y2 - y1,
bytes_per_line(surface->dpy, surface->width, bpp));
} else {
image = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
surface->format,
surface->width,
surface->height,
x2 - x1,
y2 - y1,
bytes_per_line(surface->dpy, surface->width, bpp));
}
@ -389,7 +420,8 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
return image;
*image_out = image;
return CAIRO_STATUS_SUCCESS;
}
static void
@ -403,10 +435,11 @@ _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
}
static cairo_status_t
_cairo_xcb_surface_set_image (void *abstract_surface,
cairo_image_surface_t *image)
_draw_image_surface (cairo_xcb_surface_t *surface,
cairo_image_surface_t *image,
int dst_x,
int dst_y)
{
cairo_xcb_surface_t *surface = abstract_surface;
int bpp, data_len;
_cairo_xcb_surface_ensure_gc (surface);
@ -415,7 +448,7 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
image->width,
image->height,
/* dst_x */ 0, /* dst_y */ 0,
dst_x, dst_y,
/* left_pad */ 0, image->depth,
data_len, image->data);
@ -423,9 +456,107 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
}
static cairo_status_t
_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
_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 == CAIRO_STATUS_SUCCESS) {
cairo_surface_set_filter (&image->base, surface->base.filter);
cairo_surface_set_matrix (&image->base, &surface->base.matrix);
cairo_surface_set_repeat (&image->base, surface->base.repeat);
*image_out = image;
}
return status;
}
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 == CAIRO_STATUS_SUCCESS)
*image_out = image;
return status;
}
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)
@ -443,27 +574,42 @@ _cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
xtransform.matrix32 = 0;
xtransform.matrix33 = _cairo_fixed_from_double (1);
if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
{
XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
} else {
/* XXX: Need support here if using an old RENDER without support
for SetPictureTransform */
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 (void *abstract_surface, cairo_filter_t filter)
_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
cairo_filter_t filter)
{
cairo_xcb_surface_t *surface = abstract_surface;
char *render_filter;
if (!(surface->picture.xid
&& CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
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";
@ -492,10 +638,8 @@ _cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
}
static cairo_status_t
_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
{
cairo_xcb_surface_t *surface = abstract_surface;
CARD32 mask = XCBRenderCPRepeat;
CARD32 pa[] = { repeat };
@ -507,33 +651,32 @@ _cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
return CAIRO_STATUS_SUCCESS;
}
static cairo_xcb_surface_t *
_cairo_xcb_surface_clone_similar (cairo_surface_t *src,
cairo_xcb_surface_t *template,
cairo_format_t format,
int depth)
static cairo_int_status_t
_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
cairo_surface_attributes_t *attributes)
{
cairo_xcb_surface_t *clone;
cairo_image_surface_t *src_image;
cairo_int_status_t status;
src_image = _cairo_surface_get_image (src);
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;
}
clone = (cairo_xcb_surface_t *)
_cairo_xcb_surface_create_similar (template, format, 0,
src_image->width,
src_image->height);
if (clone == NULL)
return NULL;
status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
if (status)
return status;
_cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src));
_cairo_xcb_surface_set_image (clone, src_image);
_cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix));
cairo_surface_destroy (&src_image->base);
return clone;
return CAIRO_STATUS_SUCCESS;
}
static int
@ -575,65 +718,80 @@ _render_operator (cairo_operator_t operator)
static cairo_int_status_t
_cairo_xcb_surface_composite (cairo_operator_t operator,
cairo_surface_t *generic_src,
cairo_surface_t *generic_mask,
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_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_xcb_surface_t *dst = abstract_dst;
cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask;
cairo_xcb_surface_t *src_clone = NULL;
cairo_xcb_surface_t *mask_clone = NULL;
XCBRenderPICTURE maskpict = { 0 };
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;
if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
CAIRO_FORMAT_ARGB32, 32);
if (!src_clone)
return CAIRO_INT_STATUS_UNSUPPORTED;
src = src_clone;
}
if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) {
mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst,
CAIRO_FORMAT_A8, 8);
if (!mask_clone)
return CAIRO_INT_STATUS_UNSUPPORTED;
mask = mask_clone;
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 (CAIRO_OK (status))
{
if (mask)
{
status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
if (CAIRO_OK (status))
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)
maskpict = mask->picture;
if (mask)
_cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
_cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
XCBRenderComposite (dst->dpy,
_render_operator (operator),
src->picture,
maskpict,
dst->picture,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
/* XXX: This is messed up. If I can xcb_surface_create, then I
should be able to xcb_surface_destroy. */
if (src_clone)
cairo_surface_destroy (&src_clone->base);
if (mask_clone)
cairo_surface_destroy (&mask_clone->base);
return CAIRO_STATUS_SUCCESS;
return status;
}
static cairo_int_status_t
@ -665,42 +823,60 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
cairo_surface_t *generic_src,
void *abstract_dst,
int xSrc,
int ySrc,
cairo_trapezoid_t *traps,
int num_traps)
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_xcb_surface_t *dst = abstract_dst;
cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
cairo_xcb_surface_t *src_clone = NULL;
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;
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
CAIRO_FORMAT_ARGB32, 32);
if (!src_clone)
return CAIRO_INT_STATUS_UNSUPPORTED;
src = src_clone;
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);
}
/* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */
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. */
XCBRenderTrapezoids (dst->dpy,
_render_operator (operator),
src->picture, dst->picture,
format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps);
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_src_x + attributes.x_offset,
render_src_y + attributes.y_offset,
num_traps, (XCBRenderTRAP *) traps);
/* XXX: This is messed up. If I can xcb_surface_create, then I
should be able to xcb_surface_destroy. */
if (src_clone)
cairo_surface_destroy (&src_clone->base);
_cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
return CAIRO_STATUS_SUCCESS;
return status;
}
static cairo_int_status_t
@ -723,30 +899,21 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_xcb_surface_create_pattern (void *abstract_surface,
cairo_pattern_t *pattern,
cairo_box_t *extents)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_destroy,
_cairo_xcb_surface_pixels_per_inch,
_cairo_xcb_surface_get_image,
_cairo_xcb_surface_set_image,
_cairo_xcb_surface_set_matrix,
_cairo_xcb_surface_set_filter,
_cairo_xcb_surface_set_repeat,
_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,
_cairo_xcb_surface_copy_page,
_cairo_xcb_surface_show_page,
_cairo_xcb_surface_set_clip_region,
_cairo_xcb_surface_create_pattern,
NULL /* show_glyphs */
};

View file

@ -328,14 +328,17 @@ bytes_per_line(XCBConnection *c, int width, int bpp)
return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
}
static cairo_image_surface_t *
_cairo_xcb_surface_get_image (void *abstract_surface)
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_xcb_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
XCBGetGeometryRep *geomrep;
XCBGetImageRep *imagerep;
int bpp;
int x1, y1, x2, y2;
geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
if(!geomrep)
@ -345,11 +348,39 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
surface->height = geomrep->height;
free(geomrep);
x1 = 0;
y1 = 0;
x2 = surface->width;
y2 = surface->height;
if (interest_rect) {
if (interest_rect->x > x1)
x1 = interest_rect->x;
if (interest_rect->y > y1)
y1 = interest_rect->y;
if (interest_rect->x + interest_rect->width < x2)
x2 = interest_rect->x + interest_rect->width;
if (interest_rect->y + interest_rect->height < y2)
y2 = interest_rect->y + interest_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;
}
imagerep = XCBGetImageReply(surface->dpy,
XCBGetImage(surface->dpy, ZPixmap,
surface->drawable,
0, 0,
surface->width, surface->height,
x1, y1,
x2 - x1, y2 - y1,
AllPlanes), 0);
if(!imagerep)
return 0;
@ -369,15 +400,15 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
&masks,
surface->width,
surface->height,
x2 - x1,
y2 - y1,
bytes_per_line(surface->dpy, surface->width, bpp));
} else {
image = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
surface->format,
surface->width,
surface->height,
x2 - x1,
y2 - y1,
bytes_per_line(surface->dpy, surface->width, bpp));
}
@ -389,7 +420,8 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
return image;
*image_out = image;
return CAIRO_STATUS_SUCCESS;
}
static void
@ -403,10 +435,11 @@ _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
}
static cairo_status_t
_cairo_xcb_surface_set_image (void *abstract_surface,
cairo_image_surface_t *image)
_draw_image_surface (cairo_xcb_surface_t *surface,
cairo_image_surface_t *image,
int dst_x,
int dst_y)
{
cairo_xcb_surface_t *surface = abstract_surface;
int bpp, data_len;
_cairo_xcb_surface_ensure_gc (surface);
@ -415,7 +448,7 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
image->width,
image->height,
/* dst_x */ 0, /* dst_y */ 0,
dst_x, dst_y,
/* left_pad */ 0, image->depth,
data_len, image->data);
@ -423,9 +456,107 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
}
static cairo_status_t
_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
_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 == CAIRO_STATUS_SUCCESS) {
cairo_surface_set_filter (&image->base, surface->base.filter);
cairo_surface_set_matrix (&image->base, &surface->base.matrix);
cairo_surface_set_repeat (&image->base, surface->base.repeat);
*image_out = image;
}
return status;
}
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 == CAIRO_STATUS_SUCCESS)
*image_out = image;
return status;
}
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)
@ -443,27 +574,42 @@ _cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
xtransform.matrix32 = 0;
xtransform.matrix33 = _cairo_fixed_from_double (1);
if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
{
XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
} else {
/* XXX: Need support here if using an old RENDER without support
for SetPictureTransform */
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 (void *abstract_surface, cairo_filter_t filter)
_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
cairo_filter_t filter)
{
cairo_xcb_surface_t *surface = abstract_surface;
char *render_filter;
if (!(surface->picture.xid
&& CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
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";
@ -492,10 +638,8 @@ _cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
}
static cairo_status_t
_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
{
cairo_xcb_surface_t *surface = abstract_surface;
CARD32 mask = XCBRenderCPRepeat;
CARD32 pa[] = { repeat };
@ -507,33 +651,32 @@ _cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
return CAIRO_STATUS_SUCCESS;
}
static cairo_xcb_surface_t *
_cairo_xcb_surface_clone_similar (cairo_surface_t *src,
cairo_xcb_surface_t *template,
cairo_format_t format,
int depth)
static cairo_int_status_t
_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
cairo_surface_attributes_t *attributes)
{
cairo_xcb_surface_t *clone;
cairo_image_surface_t *src_image;
cairo_int_status_t status;
src_image = _cairo_surface_get_image (src);
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;
}
clone = (cairo_xcb_surface_t *)
_cairo_xcb_surface_create_similar (template, format, 0,
src_image->width,
src_image->height);
if (clone == NULL)
return NULL;
status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
if (status)
return status;
_cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src));
_cairo_xcb_surface_set_image (clone, src_image);
_cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix));
cairo_surface_destroy (&src_image->base);
return clone;
return CAIRO_STATUS_SUCCESS;
}
static int
@ -575,65 +718,80 @@ _render_operator (cairo_operator_t operator)
static cairo_int_status_t
_cairo_xcb_surface_composite (cairo_operator_t operator,
cairo_surface_t *generic_src,
cairo_surface_t *generic_mask,
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_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_xcb_surface_t *dst = abstract_dst;
cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask;
cairo_xcb_surface_t *src_clone = NULL;
cairo_xcb_surface_t *mask_clone = NULL;
XCBRenderPICTURE maskpict = { 0 };
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;
if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
CAIRO_FORMAT_ARGB32, 32);
if (!src_clone)
return CAIRO_INT_STATUS_UNSUPPORTED;
src = src_clone;
}
if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) {
mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst,
CAIRO_FORMAT_A8, 8);
if (!mask_clone)
return CAIRO_INT_STATUS_UNSUPPORTED;
mask = mask_clone;
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 (CAIRO_OK (status))
{
if (mask)
{
status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
if (CAIRO_OK (status))
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)
maskpict = mask->picture;
if (mask)
_cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
_cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
XCBRenderComposite (dst->dpy,
_render_operator (operator),
src->picture,
maskpict,
dst->picture,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
/* XXX: This is messed up. If I can xcb_surface_create, then I
should be able to xcb_surface_destroy. */
if (src_clone)
cairo_surface_destroy (&src_clone->base);
if (mask_clone)
cairo_surface_destroy (&mask_clone->base);
return CAIRO_STATUS_SUCCESS;
return status;
}
static cairo_int_status_t
@ -665,42 +823,60 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
cairo_surface_t *generic_src,
void *abstract_dst,
int xSrc,
int ySrc,
cairo_trapezoid_t *traps,
int num_traps)
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_xcb_surface_t *dst = abstract_dst;
cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
cairo_xcb_surface_t *src_clone = NULL;
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;
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
CAIRO_FORMAT_ARGB32, 32);
if (!src_clone)
return CAIRO_INT_STATUS_UNSUPPORTED;
src = src_clone;
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);
}
/* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */
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. */
XCBRenderTrapezoids (dst->dpy,
_render_operator (operator),
src->picture, dst->picture,
format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps);
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_src_x + attributes.x_offset,
render_src_y + attributes.y_offset,
num_traps, (XCBRenderTRAP *) traps);
/* XXX: This is messed up. If I can xcb_surface_create, then I
should be able to xcb_surface_destroy. */
if (src_clone)
cairo_surface_destroy (&src_clone->base);
_cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
return CAIRO_STATUS_SUCCESS;
return status;
}
static cairo_int_status_t
@ -723,30 +899,21 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_xcb_surface_create_pattern (void *abstract_surface,
cairo_pattern_t *pattern,
cairo_box_t *extents)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_destroy,
_cairo_xcb_surface_pixels_per_inch,
_cairo_xcb_surface_get_image,
_cairo_xcb_surface_set_image,
_cairo_xcb_surface_set_matrix,
_cairo_xcb_surface_set_filter,
_cairo_xcb_surface_set_repeat,
_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,
_cairo_xcb_surface_copy_page,
_cairo_xcb_surface_show_page,
_cairo_xcb_surface_set_clip_region,
_cairo_xcb_surface_create_pattern,
NULL /* show_glyphs */
};