[cairo-commit] src/cairo-xlib-core-compositor.c src/cairo-xlib-render-compositor.c

Chris Wilson ickle at kemper.freedesktop.org
Wed Feb 1 17:14:44 PST 2012


 src/cairo-xlib-core-compositor.c   |   37 ++++++++++++++++++++++++++++++++-----
 src/cairo-xlib-render-compositor.c |   26 ++++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 5 deletions(-)

New commits:
commit b454db4b138872121ac003d4ba953f44e1a1dc60
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Feb 2 01:07:27 2012 +0000

    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 at redhat.com>
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-xlib-core-compositor.c b/src/cairo-xlib-core-compositor.c
index 426a79c..f306640 100644
--- a/src/cairo-xlib-core-compositor.c
+++ b/src/cairo-xlib-core-compositor.c
@@ -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
diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c
index 6ee69e1..0faa557 100644
--- a/src/cairo-xlib-render-compositor.c
+++ b/src/cairo-xlib-render-compositor.c
@@ -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;


More information about the cairo-commit mailing list