[cairo-commit] src/cairo-xcb-surface.c
Ian Osgood
iano at kemper.freedesktop.org
Fri Oct 20 11:17:03 PDT 2006
src/cairo-xcb-surface.c | 268 +++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 241 insertions(+), 27 deletions(-)
New commits:
diff-tree a34a4a2bd745c07f0d6034acf066252ae55fbb81 (from b1944e1672ee6faa034dba4d8cf730886c35e848)
Author: Ian Osgood <iano at quirkster.com>
Date: Fri Oct 20 11:17:03 2006 -0700
XCB: bring composite, trapezoids up-to-date with Xlib
Categorize & recategorize
Distinguish DO_COPYAREA and DO_XTILE
Create trapezoid mask
Fixup unbounded
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 9e2d8d8..78fa9e0 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1112,10 +1112,17 @@ _cairo_xcb_surface_composite (cairo_oper
cairo_xcb_surface_t *src;
cairo_xcb_surface_t *mask;
cairo_int_status_t status;
+ composite_operation_t operation;
+ int itx, ity;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ operation = _categorize_composite_operation (dst, op, src_pattern,
+ mask_pattern != NULL);
+ if (operation == DO_UNSUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
&dst->base,
src_x, src_y,
@@ -1127,29 +1134,39 @@ _cairo_xcb_surface_composite (cairo_oper
if (status)
return status;
+ operation = _recategorize_composite_operation (dst, op, src, &src_attr,
+ mask_pattern != NULL);
+ if (operation == DO_UNSUPPORTED) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto BAIL;
+ }
+
status = _cairo_xcb_surface_set_attributes (src, &src_attr);
- if (status == CAIRO_STATUS_SUCCESS)
+ if (status)
+ goto BAIL;
+
+ switch (operation)
{
+ case DO_RENDER:
_cairo_xcb_surface_ensure_dst_picture (dst);
- if (mask)
- {
+ if (mask) {
status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
- if (status == CAIRO_STATUS_SUCCESS)
- xcb_render_composite (dst->dpy,
- _render_operator (op),
- src->src_picture,
- mask->src_picture,
- dst->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 xcb_render_picture_t maskpict = { 0 };
+ if (status)
+ goto BAIL;
+
+ xcb_render_composite (dst->dpy,
+ _render_operator (op),
+ src->src_picture,
+ mask->src_picture,
+ dst->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 xcb_render_picture_t maskpict = { XCB_NONE };
xcb_render_composite (dst->dpy,
_render_operator (op),
@@ -1162,8 +1179,63 @@ _cairo_xcb_surface_composite (cairo_oper
dst_x, dst_y,
width, height);
}
+ break;
+
+ case DO_XCOPYAREA:
+ _cairo_xcb_surface_ensure_gc (dst);
+ xcb_copy_area (dst->dpy,
+ src->drawable,
+ dst->drawable,
+ dst->gc,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ width, height,
+ dst_x, dst_y);
+ break;
+
+ case DO_XTILE:
+ /* This case is only used for bug fallbacks, though it is theoretically
+ * applicable to the case where we don't have the RENDER extension as
+ * well.
+ *
+ * We've checked that we have a repeating unscaled source in
+ * _recategorize_composite_operation.
+ */
+
+ _cairo_xcb_surface_ensure_gc (dst);
+ _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
+ {
+ uint32_t mask = XCB_GC_FILL_STYLE | XCB_GC_TILE
+ | XCB_GC_TILE_STIPPLE_ORIGIN_X
+ | XCB_GC_TILE_STIPPLE_ORIGIN_Y;
+ uint32_t values[] = {
+ XCB_FILL_STYLE_TILED, src->drawable,
+ - (itx + src_attr.x_offset),
+ - (ity + src_attr.y_offset)
+ };
+ xcb_rectangle_t rect = { dst_x, dst_y, width, height };
+
+ xcb_change_gc( dst->dpy, dst->gc, mask, values );
+ xcb_poly_fill_rectangle(dst->dpy, dst->drawable, dst->gc, 1, &rect);
+ }
+ break;
+
+ case DO_UNSUPPORTED:
+ default:
+ ASSERT_NOT_REACHED;
}
+ if (!_cairo_operator_bounded_by_source (op))
+ status = _cairo_surface_composite_fixup_unbounded (&dst->base,
+ &src_attr, src->width, src->height,
+ mask ? &mask_attr : NULL,
+ mask ? mask->width : 0,
+ mask ? mask->height : 0,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y, width, height);
+
+ BAIL:
if (mask)
_cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
@@ -1200,6 +1272,94 @@ _cairo_xcb_surface_fill_rectangles (void
return CAIRO_STATUS_SUCCESS;
}
+/* Creates an A8 picture of size @width x @height, initialized with @color
+ */
+static xcb_render_picture_t
+_create_a8_picture (cairo_xcb_surface_t *surface,
+ xcb_render_color_t *color,
+ int width,
+ int height,
+ cairo_bool_t repeat)
+{
+ uint32_t values[] = { TRUE };
+ unsigned long mask = repeat ? XCB_RENDER_CP_REPEAT : 0;
+
+ xcb_pixmap_t pixmap = xcb_generate_id (surface->dpy);
+ xcb_render_picture_t picture = xcb_generate_id (surface->dpy);
+
+ xcb_render_pictforminfo_t *format
+ = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8);
+ xcb_rectangle_t rect = { 0, 0, width, height };
+
+ xcb_create_pixmap (surface->dpy, pixmap, surface->drawable,
+ width <= 0 ? 1 : width,
+ height <= 0 ? 1 : height,
+ 8);
+ xcb_render_create_picture (surface->dpy, picture, pixmap, format->id, mask, values);
+ xcb_render_fill_rectangles (surface->dpy, XCB_RENDER_PICT_OP_SRC, picture, *color, 1, &rect);
+ xcb_free_pixmap (surface->dpy, pixmap);
+
+ return picture;
+}
+
+/* Creates a temporary mask for the trapezoids covering the area
+ * [@dst_x, @dst_y, @width, @height] of the destination surface.
+ */
+static xcb_render_picture_t
+_create_trapezoid_mask (cairo_xcb_surface_t *dst,
+ cairo_trapezoid_t *traps,
+ int num_traps,
+ int dst_x,
+ int dst_y,
+ int width,
+ int height,
+ xcb_render_pictforminfo_t *pict_format)
+{
+ xcb_render_color_t transparent = { 0, 0, 0, 0 };
+ xcb_render_color_t solid = { 0xffff, 0xffff, 0xffff, 0xffff };
+ xcb_render_picture_t mask_picture, solid_picture;
+ xcb_render_trapezoid_t *offset_traps;
+ int i;
+
+ /* This would be considerably simpler using XRenderAddTraps(), but since
+ * we are only using this in the unbounded-operator case, we stick with
+ * XRenderCompositeTrapezoids, which is available on older versions
+ * of RENDER rather than conditionalizing. We should still hit an
+ * optimization that avoids creating another intermediate surface on
+ * the servers that have XRenderAddTraps().
+ */
+ mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE);
+ solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE);
+
+ offset_traps = malloc (sizeof (xcb_render_trapezoid_t) * num_traps);
+ if (!offset_traps)
+ return XCB_NONE;
+
+ for (i = 0; i < num_traps; i++) {
+ offset_traps[i].top = traps[i].top - 0x10000 * dst_y;
+ offset_traps[i].bottom = traps[i].bottom - 0x10000 * dst_y;
+ offset_traps[i].left.p1.x = traps[i].left.p1.x - 0x10000 * dst_x;
+ offset_traps[i].left.p1.y = traps[i].left.p1.y - 0x10000 * dst_y;
+ offset_traps[i].left.p2.x = traps[i].left.p2.x - 0x10000 * dst_x;
+ offset_traps[i].left.p2.y = traps[i].left.p2.y - 0x10000 * dst_y;
+ offset_traps[i].right.p1.x = traps[i].right.p1.x - 0x10000 * dst_x;
+ offset_traps[i].right.p1.y = traps[i].right.p1.y - 0x10000 * dst_y;
+ offset_traps[i].right.p2.x = traps[i].right.p2.x - 0x10000 * dst_x;
+ offset_traps[i].right.p2.y = traps[i].right.p2.y - 0x10000 * dst_y;
+ }
+
+ xcb_render_trapezoids (dst->dpy, XCB_RENDER_PICT_OP_ADD,
+ solid_picture, mask_picture,
+ pict_format->id,
+ 0, 0,
+ num_traps, offset_traps);
+
+ xcb_render_free_picture (dst->dpy, solid_picture);
+ free (offset_traps);
+
+ return mask_picture;
+}
+
static cairo_int_status_t
_cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
cairo_pattern_t *pattern,
@@ -1218,6 +1378,7 @@ _cairo_xcb_surface_composite_trapezoids
cairo_xcb_surface_t *dst = abstract_dst;
cairo_xcb_surface_t *src;
cairo_int_status_t status;
+ composite_operation_t operation;
int render_reference_x, render_reference_y;
int render_src_x, render_src_y;
int cairo_format;
@@ -1226,6 +1387,10 @@ _cairo_xcb_surface_composite_trapezoids
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ operation = _categorize_composite_operation (dst, op, pattern, TRUE);
+ if (operation == DO_UNSUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
src_x, src_y, width, height,
(cairo_surface_t **) &src,
@@ -1233,6 +1398,12 @@ _cairo_xcb_surface_composite_trapezoids
if (status)
return status;
+ operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
+ if (operation == DO_UNSUPPORTED) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto BAIL;
+ }
+
switch (antialias) {
case CAIRO_ANTIALIAS_NONE:
cairo_format = CAIRO_FORMAT_A1;
@@ -1258,18 +1429,61 @@ _cairo_xcb_surface_composite_trapezoids
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. */
_cairo_xcb_surface_ensure_dst_picture (dst);
status = _cairo_xcb_surface_set_attributes (src, &attributes);
- if (status == CAIRO_STATUS_SUCCESS)
+ if (status)
+ goto BAIL;
+
+ if (!_cairo_operator_bounded_by_mask (op)) {
+ /* xcb_render_composite+trapezoids() creates a mask only large enough for the
+ * trapezoids themselves, but if the operator is unbounded, then we need
+ * to actually composite all the way out to the bounds, so we create
+ * the mask and composite ourselves. There actually would
+ * be benefit to doing this in all cases, since RENDER implementations
+ * will frequently create a too temporary big mask, ignoring destination
+ * bounds and clip. (xcb_render_add_traps() could be used to make creating
+ * the mask somewhat cheaper.)
+ */
+ xcb_render_picture_t mask_picture = _create_trapezoid_mask (dst, traps, num_traps,
+ dst_x, dst_y, width, height,
+ render_format);
+ if (!mask_picture) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL;
+ }
+
+ xcb_render_composite (dst->dpy,
+ _render_operator (op),
+ src->src_picture,
+ mask_picture,
+ dst->dst_picture,
+ src_x + attributes.x_offset,
+ src_y + attributes.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+
+ xcb_render_free_picture (dst->dpy, mask_picture);
+
+ status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
+ &attributes, src->width, src->height,
+ width, height,
+ src_x, src_y,
+ 0, 0,
+ dst_x, dst_y, width, height);
+
+ } else {
+ /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
xcb_render_trapezoids (dst->dpy,
- _render_operator (op),
- src->src_picture, dst->dst_picture,
- render_format->id,
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- num_traps, (xcb_render_trapezoid_t *) traps);
+ _render_operator (op),
+ src->src_picture, dst->dst_picture,
+ render_format->id,
+ render_src_x + attributes.x_offset,
+ render_src_y + attributes.y_offset,
+ num_traps, (xcb_render_trapezoid_t *) traps);
+ }
+ BAIL:
_cairo_pattern_release_surface (pattern, &src->base, &attributes);
return status;
More information about the cairo-commit
mailing list