mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-09 06:08:02 +02:00
xlib: Set IncludeInferiors when using CopyArea
cairo-xlib semantics state that we copy the contents of a Window's children when we use a Window as a source in a cairo operation. This requires that we set the IncludeInferiors SubwindowMode on the GC. However, we can only set one SubwindowMode for an operation and our semantics are that drawing performed by cairo onto a Window are clipped by its children (the ClipByChildren SubwindowMode). Therefore if we have to copy between two Window, we can not use CopyArea. Furthermore, we cannot tell if an external Drawable is a Window or a Pixmap, therefore we treat all foriegn Drawables as Window. Failure here means falling back to a render path, where we can independently control the subwindow mode on the source and destination, or to a GetImage/PutImage if the xserver does not support render. Reported-by: Benjamin Otte <otte@redhat.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
d95172858b
commit
b454db4b13
2 changed files with 58 additions and 5 deletions
|
|
@ -359,18 +359,30 @@ copy_boxes (cairo_xlib_surface_t *dst,
|
|||
if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
/* XXX subsurface */
|
||||
|
||||
pattern = (const cairo_surface_pattern_t *) source;
|
||||
if (pattern->surface->type != CAIRO_SURFACE_TYPE_XLIB)
|
||||
if (pattern->surface->backend->type != CAIRO_SURFACE_TYPE_XLIB)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
src = (cairo_xlib_surface_t *) pattern->surface;
|
||||
if (src->depth != dst->depth)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (! _cairo_xlib_surface_same_screen (dst, src))
|
||||
/* We can only have a single control for subwindow_mode on the
|
||||
* GC. If we have a Window destination, we need to set ClipByChildren,
|
||||
* but if we have a Window source, we need IncludeInferiors. If we have
|
||||
* both a Window destination and source, we must fallback. There is
|
||||
* no convenient way to detect if a drawable is a Pixmap or Window,
|
||||
* therefore we can only rely on those surfaces that we created
|
||||
* ourselves to be Pixmaps, and treat everything else as a potential
|
||||
* Window.
|
||||
*/
|
||||
if (! src->owns_pixmap && ! dst->owns_pixmap)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
/* XXX subsurface */
|
||||
if (! _cairo_xlib_surface_same_screen (dst, src))
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (! _cairo_matrix_is_integer_translation (&source->matrix,
|
||||
&cb.tx, &cb.ty))
|
||||
|
|
@ -390,12 +402,27 @@ copy_boxes (cairo_xlib_surface_t *dst,
|
|||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
if (! src->owns_pixmap) {
|
||||
XGCValues gcv;
|
||||
|
||||
gcv.subwindow_mode = IncludeInferiors;
|
||||
XChangeGC (dst->display->display, cb.gc, GCSubwindowMode, &gcv);
|
||||
}
|
||||
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
if (! _cairo_boxes_for_each_box (boxes, copy_box, &cb))
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (! src->owns_pixmap) {
|
||||
XGCValues gcv;
|
||||
|
||||
gcv.subwindow_mode = ClipByChildren;
|
||||
XChangeGC (dst->display->display, cb.gc, GCSubwindowMode, &gcv);
|
||||
}
|
||||
|
||||
_cairo_xlib_surface_put_gc (dst->display, dst, cb.gc);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
|
|
|
|||
|
|
@ -164,6 +164,18 @@ copy_boxes (void *_dst,
|
|||
GC gc;
|
||||
int i, j;
|
||||
|
||||
/* We can only have a single control for subwindow_mode on the
|
||||
* GC. If we have a Window destination, we need to set ClipByChildren,
|
||||
* but if we have a Window source, we need IncludeInferiors. If we have
|
||||
* both a Window destination and source, we must fallback. There is
|
||||
* no convenient way to detect if a drawable is a Pixmap or Window,
|
||||
* therefore we can only rely on those surfaces that we created
|
||||
* ourselves to be Pixmaps, and treat everything else as a potential
|
||||
* Window.
|
||||
*/
|
||||
if (! src->owns_pixmap && ! dst->owns_pixmap)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (! _cairo_xlib_surface_same_screen (dst, src))
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
|
|
@ -180,6 +192,13 @@ copy_boxes (void *_dst,
|
|||
return status;
|
||||
}
|
||||
|
||||
if (! src->owns_pixmap) {
|
||||
XGCValues gcv;
|
||||
|
||||
gcv.subwindow_mode = IncludeInferiors;
|
||||
XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
|
||||
}
|
||||
|
||||
if (boxes->num_boxes == 1) {
|
||||
int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
|
||||
int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
|
||||
|
|
@ -230,6 +249,13 @@ copy_boxes (void *_dst,
|
|||
free (rects);
|
||||
}
|
||||
|
||||
if (! src->owns_pixmap) {
|
||||
XGCValues gcv;
|
||||
|
||||
gcv.subwindow_mode = ClipByChildren;
|
||||
XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
|
||||
}
|
||||
|
||||
_cairo_xlib_surface_put_gc (dst->display, dst, gc);
|
||||
release (dst);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue