mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 06:28:01 +02:00
XCB: bring composite, trapezoids up-to-date with Xlib
Categorize & recategorize Distinguish DO_COPYAREA and DO_XTILE Create trapezoid mask Fixup unbounded
This commit is contained in:
parent
b1944e1672
commit
a34a4a2bd7
1 changed files with 242 additions and 28 deletions
|
|
@ -1112,10 +1112,17 @@ _cairo_xcb_surface_composite (cairo_operator_t op,
|
|||
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_operator_t op,
|
|||
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_operator_t op,
|
|||
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 *abstract_surface,
|
|||
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_operator_t op,
|
|||
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 (cairo_operator_t op,
|
|||
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 (cairo_operator_t op,
|
|||
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 (cairo_operator_t op,
|
|||
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)
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
BAIL:
|
||||
_cairo_pattern_release_surface (pattern, &src->base, &attributes);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue