[cairo-commit] 3 commits - src/cairo-mask-compositor.c src/cairo-xlib-core-compositor.c src/cairo-xlib-private.h src/cairo-xlib-render-compositor.c src/cairo-xlib-source.c

Chris Wilson ickle at kemper.freedesktop.org
Sun Jan 13 10:40:28 PST 2013


 src/cairo-mask-compositor.c        |   65 ++++++++++++++++++++++--------
 src/cairo-xlib-core-compositor.c   |   79 ++++++++++++++++++++++++++++---------
 src/cairo-xlib-private.h           |   15 ++++++-
 src/cairo-xlib-render-compositor.c |   30 +++++++++++---
 src/cairo-xlib-source.c            |   70 ++++++++++++++++++++++++++++----
 5 files changed, 205 insertions(+), 54 deletions(-)

New commits:
commit fd34f420ec3ba02eb39f22f6551705ab23ebfc28
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jan 13 18:16:17 2013 +0000

    compositor: Pass back the internal failure
    
    In order to pass back a CAIRO_INT_STATUS_UNSUPPORTED, we need to use the
    internal error surface creation functions as they do not assert on
    private error codes.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-mask-compositor.c b/src/cairo-mask-compositor.c
index 0b36bea..d0be144 100644
--- a/src/cairo-mask-compositor.c
+++ b/src/cairo-mask-compositor.c
@@ -172,7 +172,7 @@ create_composite_mask (const cairo_mask_compositor_t *compositor,
     status = compositor->acquire (surface);
     if (unlikely (status)) {
 	cairo_surface_destroy (surface);
-	return _cairo_surface_create_in_error (status);
+	return _cairo_int_surface_create_in_error (status);
     }
 
     if (!surface->is_clear) {
@@ -239,7 +239,7 @@ error:
     compositor->release (surface);
     if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
 	cairo_surface_destroy (surface);
-	surface = _cairo_surface_create_in_error (status);
+	surface = _cairo_int_surface_create_in_error (status);
     }
     return surface;
 }
commit 14c32ee1cf6bfcaeb07d50a80b6d5a388a1f2885
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jan 13 18:11:31 2013 +0000

    compositor: Convert image surface into backend source
    
    Before passing a surface to the backend composite functions, they expect
    them to be a native source. The copy'n'paste code for the mask
    compositor forgot to perform the conversion upon the clip surfaces,
    which originally were native to the backend and are now images.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-mask-compositor.c b/src/cairo-mask-compositor.c
index b4bc2be..0b36bea 100644
--- a/src/cairo-mask-compositor.c
+++ b/src/cairo-mask-compositor.c
@@ -298,6 +298,38 @@ clip_and_composite_with_mask (const cairo_mask_compositor_t *compositor,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_surface_t *
+get_clip_source (const cairo_mask_compositor_t *compositor,
+		 cairo_clip_t *clip,
+		 cairo_surface_t *dst,
+		 const cairo_rectangle_int_t *bounds,
+		 int *out_x, int *out_y)
+{
+    cairo_surface_pattern_t pattern;
+    cairo_rectangle_int_t r;
+    cairo_surface_t *surface;
+
+    surface = _cairo_clip_get_image (clip, dst, bounds);
+    if (unlikely (surface->status))
+	return surface;
+
+    _cairo_pattern_init_for_surface (&pattern, surface);
+    pattern.base.filter = CAIRO_FILTER_NEAREST;
+    cairo_surface_destroy (surface);
+
+    r.x = r.y = 0;
+    r.width  = bounds->width;
+    r.height = bounds->height;
+
+    surface = compositor->pattern_to_surface (dst, &pattern.base, TRUE,
+					      &r, &r, out_x, out_y);
+    _cairo_pattern_fini (&pattern.base);
+
+    *out_x += -bounds->x;
+    *out_y += -bounds->y;
+    return surface;
+}
+
 /* Handles compositing with a clip surface when we have to do the operation
  * in two pieces and combine them together.
  */
@@ -312,6 +344,7 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
     cairo_surface_t *dst = extents->surface;
     cairo_surface_t *tmp, *clip;
     cairo_status_t status;
+    int clip_x, clip_y;
 
     tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
 						 extents->bounded.width,
@@ -332,20 +365,22 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
     if (unlikely (status))
 	goto cleanup;
 
-    clip = _cairo_clip_get_image (extents->clip, dst, &extents->bounded);
+    clip = get_clip_source (compositor,
+			    extents->clip, dst, &extents->bounded,
+			    &clip_x, &clip_y);
     if (unlikely ((status = clip->status)))
 	goto cleanup;
 
     if (dst->is_clear) {
 	compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
 			       0, 0,
-			       0, 0,
+			       clip_x, clip_y,
 			       extents->bounded.x,      extents->bounded.y,
 			       extents->bounded.width,  extents->bounded.height);
     } else {
 	/* Punch the clip out of the destination */
 	compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, clip, NULL,
-			       0, 0,
+			       clip_x, clip_y,
 			       0, 0,
 			       extents->bounded.x,     extents->bounded.y,
 			       extents->bounded.width, extents->bounded.height);
@@ -353,7 +388,7 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
 	/* Now add the two results together */
 	compositor->composite (dst, CAIRO_OPERATOR_ADD, tmp, clip,
 			       0, 0,
-			       0, 0,
+			       clip_x, clip_y,
 			       extents->bounded.x,     extents->bounded.y,
 			       extents->bounded.width, extents->bounded.height);
     }
@@ -515,17 +550,15 @@ fixup_unbounded_with_mask (const cairo_mask_compositor_t *compositor,
 			   cairo_surface_t *dst,
 			   const cairo_composite_rectangles_t *extents)
 {
-    cairo_clip_t *clip = extents->clip;
     cairo_surface_t *mask;
     int mask_x, mask_y;
 
-    mask = _cairo_clip_get_image (clip, dst, &extents->unbounded);
+    mask = get_clip_source (compositor,
+			    extents->clip, dst, &extents->unbounded,
+			    &mask_x, &mask_y);
     if (unlikely (mask->status))
 	return mask->status;
 
-    mask_x = -extents->unbounded.x;
-    mask_y = -extents->unbounded.y;
-
     /* top */
     if (extents->bounded.y != extents->unbounded.y) {
 	int x = extents->unbounded.x;
@@ -870,8 +903,9 @@ composite_boxes (const cairo_mask_compositor_t *compositor,
 	int mask_x = 0, mask_y = 0;
 
 	if (need_clip_mask) {
-	    mask = _cairo_clip_get_image (extents->clip, dst,
-					  &extents->bounded);
+	    mask = get_clip_source (compositor,
+				    extents->clip, dst, &extents->bounded,
+				    &mask_x, &mask_y);
 	    if (unlikely (mask->status))
 		return mask->status;
 
@@ -879,9 +913,6 @@ composite_boxes (const cairo_mask_compositor_t *compositor,
 		source = NULL;
 		op = CAIRO_OPERATOR_DEST_OUT;
 	    }
-
-	    mask_x = -extents->bounded.x;
-	    mask_y = -extents->bounded.y;
 	}
 
 	if (source || mask == NULL) {
@@ -1220,7 +1251,7 @@ _cairo_mask_compositor_mask (const cairo_compositor_t *_compositor,
 
     if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
 	extents->clip->path == NULL &&
-	! _cairo_clip_is_region (extents->clip)) {
+	_cairo_clip_is_region (extents->clip)) {
 	status = clip_and_composite (compositor,
 				     composite_opacity_boxes,
 				     composite_opacity_boxes,
commit 7012334ebb424b619312e1fa397cc3b8a3ffd770
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jan 13 17:20:24 2013 +0000

    xlib: Handle lack of XRenderFillRectangles
    
    Remember to check for a supported render version before making a
    FillRectangle request, and fallback to the core protocol where possible
    instead.
    
    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 aaa71d5..9398079 100644
--- a/src/cairo-xlib-core-compositor.c
+++ b/src/cairo-xlib-core-compositor.c
@@ -83,6 +83,7 @@ struct _fill_box {
     Display *dpy;
     Drawable drawable;
     GC gc;
+    //cairo_surface_t *dither = NULL;
 };
 
 static cairo_bool_t fill_box (cairo_box_t *box, void *closure)
@@ -128,27 +129,25 @@ color_to_pixel (cairo_xlib_surface_t    *dst,
 }
 
 static cairo_int_status_t
-fill_boxes (cairo_xlib_surface_t    *dst,
-	    const cairo_color_t     *color,
-	    cairo_boxes_t	    *boxes)
+_fill_box_init (struct _fill_box *fb,
+		cairo_xlib_surface_t *dst,
+		const cairo_color_t *color)
 {
-    cairo_surface_t *dither = NULL;
-    cairo_status_t status;
-    struct _fill_box fb;
+    cairo_int_status_t status;
 
-    status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb.gc);
+    status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb->gc);
     if (unlikely (status))
         return status;
 
-    fb.dpy = dst->display->display;
-    fb.drawable = dst->drawable;
+    fb->dpy = dst->display->display;
+    fb->drawable = dst->drawable;
 
     if (dst->visual && dst->visual->class != TrueColor && 0) {
+#if 0
 	cairo_solid_pattern_t solid;
 	cairo_surface_attributes_t attrs;
 
 	_cairo_pattern_init_solid (&solid, color);
-#if 0
 	status = _cairo_pattern_acquire_surface (&solid.base, &dst->base,
 						 0, 0,
 						 ARRAY_LENGTH (dither_pattern[0]),
@@ -160,27 +159,70 @@ fill_boxes (cairo_xlib_surface_t    *dst,
 	    _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
 	    return status;
 	}
-#endif
 
-	XSetTSOrigin (fb.dpy, fb.gc,
+	XSetTSOrigin (fb->dpy, fb->gc,
 		      - (dst->base.device_transform.x0 + attrs.x_offset),
 		      - (dst->base.device_transform.y0 + attrs.y_offset));
-	XSetTile (fb.dpy, fb.gc, ((cairo_xlib_surface_t *) dither)->drawable);
+	XSetTile (fb->dpy, fb->gc, ((cairo_xlib_surface_t *) dither)->drawable);
+#endif
     } else {
 	XGCValues gcv;
 
 	gcv.foreground = color_to_pixel (dst, color);
 	gcv.fill_style = FillSolid;
 
-	XChangeGC (fb.dpy, fb.gc, GCFillStyle | GCForeground, &gcv);
+	XChangeGC (fb->dpy, fb->gc, GCFillStyle | GCForeground, &gcv);
     }
 
+    return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static void
+_fill_box_fini (struct _fill_box *fb,
+		cairo_xlib_surface_t *dst)
+{
+    _cairo_xlib_surface_put_gc (dst->display, dst, fb->gc);
+    //cairo_surface_destroy (fb->dither);
+}
+
+cairo_int_status_t
+_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t    *dst,
+			     const cairo_color_t     *color,
+			     cairo_boxes_t	    *boxes)
+{
+    cairo_int_status_t status;
+    struct _fill_box fb;
+
+    status = _fill_box_init (&fb, dst, color);
+    if (unlikely (status))
+        return status;
+
     _cairo_boxes_for_each_box (boxes, fill_box, &fb);
 
-    _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
+    _fill_box_fini (&fb, dst);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t    *dst,
+				  const cairo_color_t     *color,
+				  int num_rects,
+				  cairo_rectangle_int_t *rects)
+{
+    cairo_int_status_t status;
+    struct _fill_box fb;
+    int i;
+
+    status = _fill_box_init (&fb, dst, color);
+    if (unlikely (status))
+        return status;
 
-    cairo_surface_destroy (dither);
+    for (i = 0; i < num_rects; i++)
+	XFillRectangle (fb.dpy, fb.drawable, fb.gc,
+			rects[i].x, rects[i].y,
+			rects[i].width, rects[i].height);
 
+    _fill_box_fini (&fb, dst);
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -495,9 +537,8 @@ draw_boxes (cairo_composite_rectangles_t *extents,
 	return status;
 
     if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
-	status = fill_boxes (dst,
-			     &((cairo_solid_pattern_t *) src)->color,
-			     boxes);
+	status = _cairo_xlib_core_fill_boxes
+	    (dst, &((cairo_solid_pattern_t *) src)->color, boxes);
     } else {
 	status = upload_image_inplace (dst, src, boxes);
 	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 000798a..4fd725f 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -171,6 +171,7 @@ struct _cairo_xlib_surface {
     cairo_surface_t base;
 
     Picture picture;
+    Drawable drawable;
 
     const cairo_compositor_t *compositor;
     cairo_surface_t *shm;
@@ -181,7 +182,6 @@ struct _cairo_xlib_surface {
     cairo_list_t link;
 
     Display *dpy; /* only valid between acquire/release */
-    Drawable drawable;
     cairo_bool_t owns_pixmap;
     Visual *visual;
 
@@ -203,6 +203,7 @@ struct _cairo_xlib_surface {
 	cairo_surface_t base;
 
 	Picture picture;
+	Pixmap pixmap;
 	Display *dpy;
 
 	unsigned int filter:3;
@@ -395,6 +396,17 @@ _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
     return dst->screen == src->screen;
 }
 
+cairo_private cairo_int_status_t
+_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t    *dst,
+			     const cairo_color_t     *color,
+			     cairo_boxes_t	    *boxes);
+
+cairo_private cairo_int_status_t
+_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t    *dst,
+				  const cairo_color_t     *color,
+				  int num_rects,
+				  cairo_rectangle_int_t *rects);
+
 static inline void
 _cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
                             cairo_xlib_surface_t *surface,
@@ -453,5 +465,4 @@ _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface);
 cairo_private pixman_format_code_t
 _pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface);
 
-
 #endif /* CAIRO_XLIB_PRIVATE_H */
diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c
index a5f750e..3540d1f 100644
--- a/src/cairo-xlib-render-compositor.c
+++ b/src/cairo-xlib-render-compositor.c
@@ -608,14 +608,23 @@ fill_rectangles (void				*abstract_surface,
 
     //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
 
+    if (fill_reduces_to_source (op, color, dst))
+	op = CAIRO_OPERATOR_SOURCE;
+
+    if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+	cairo_int_status_t status;
+
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	if (op == CAIRO_OPERATOR_SOURCE)
+	    status = _cairo_xlib_core_fill_rectangles (dst, color, num_rects, rects);
+	return status;
+    }
+
     render_color.red   = color->red_short;
     render_color.green = color->green_short;
     render_color.blue  = color->blue_short;
     render_color.alpha = color->alpha_short;
 
-    if (fill_reduces_to_source (op, color, dst))
-	op = CAIRO_OPERATOR_SOURCE;
-
     _cairo_xlib_surface_ensure_picture (dst);
     if (num_rects == 1) {
 	/* Take advantage of the protocol compaction that libXrender performs
@@ -665,14 +674,23 @@ fill_boxes (void		*abstract_surface,
     cairo_xlib_surface_t *dst = abstract_surface;
     XRenderColor render_color;
 
+    if (fill_reduces_to_source (op, color, dst))
+	op = CAIRO_OPERATOR_SOURCE;
+
+    if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+	cairo_int_status_t status;
+
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	if (op == CAIRO_OPERATOR_SOURCE)
+	    status = _cairo_xlib_core_fill_boxes (dst, color, boxes);
+	return status;
+    }
+
     render_color.red   = color->red_short;
     render_color.green = color->green_short;
     render_color.blue  = color->blue_short;
     render_color.alpha = color->alpha_short;
 
-    if (fill_reduces_to_source (op, color, dst))
-	op = CAIRO_OPERATOR_SOURCE;
-
     _cairo_xlib_surface_ensure_picture (dst);
     if (boxes->num_boxes == 1) {
 	int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index 0689d82..d0d6c0e 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -71,6 +71,8 @@ _cairo_xlib_source_finish (void *abstract_surface)
     cairo_xlib_source_t *source = abstract_surface;
 
     XRenderFreePicture (source->dpy, source->picture);
+    if (source->pixmap)
+	    XFreePixmap (source->dpy, source->pixmap);
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -86,6 +88,8 @@ _cairo_xlib_proxy_finish (void *abstract_surface)
     cairo_xlib_proxy_t *proxy = abstract_surface;
 
     XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
+    if (proxy->source.pixmap)
+	    XFreePixmap (proxy->source.dpy, proxy->source.pixmap);
     _cairo_xlib_shm_surface_mark_active (proxy->owner);
     cairo_surface_destroy (proxy->owner);
     return CAIRO_STATUS_SUCCESS;
@@ -98,7 +102,7 @@ static const cairo_surface_backend_t cairo_xlib_proxy_backend = {
 };
 
 static cairo_surface_t *
-source (cairo_xlib_surface_t *dst, Picture picture)
+source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap)
 {
     cairo_xlib_source_t *source;
 
@@ -108,6 +112,8 @@ source (cairo_xlib_surface_t *dst, Picture picture)
     source = malloc (sizeof (cairo_image_surface_t));
     if (unlikely (source == NULL)) {
 	XRenderFreePicture (dst->display->display, picture);
+	if (pixmap)
+		XFreePixmap (dst->display->display, pixmap);
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     }
 
@@ -118,6 +124,7 @@ source (cairo_xlib_surface_t *dst, Picture picture)
 
     /* The source exists only within an operation */
     source->picture = picture;
+    source->pixmap = pixmap;
     source->dpy = dst->display->display;
 
     return &source->base;
@@ -433,22 +440,65 @@ gradient_source (cairo_xlib_surface_t *dst,
 	return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
     }
 
-    return source (dst, picture);
+    return source (dst, picture, None);
 }
 
 static cairo_surface_t *
 color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
 {
-    XRenderColor xrender_color;
+    Display *dpy = dst->display->display;
+    XRenderColor xcolor;
+    Picture picture;
+    Pixmap pixmap = None;
+
+    xcolor.red   = color->red_short;
+    xcolor.green = color->green_short;
+    xcolor.blue  = color->blue_short;
+    xcolor.alpha = color->alpha_short;
+
+    if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
+	picture = XRenderCreateSolidFill (dpy, &xcolor);
+    } else {
+	XRenderPictureAttributes pa;
+	int mask = 0;
+
+	pa.repeat = RepeatNormal;
+	mask |= CPRepeat;
 
-    xrender_color.red   = color->red_short;
-    xrender_color.green = color->green_short;
-    xrender_color.blue  = color->blue_short;
-    xrender_color.alpha = color->alpha_short;
+	pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32);
+	picture = XRenderCreatePicture (dpy, pixmap,
+					_cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32),
+					mask, &pa);
+
+	if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+	    XRectangle r = { 0, 0, 1, 1};
+	    XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1);
+	} else {
+	    XGCValues gcv;
+	    GC gc;
+
+	    gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen,
+					    32, pixmap);
+	    if (unlikely (gc == NULL)) {
+		XFreePixmap (dpy, pixmap);
+		return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+	    }
+
+	    gcv.foreground = 0;
+	    gcv.foreground |= color->alpha_short >> 8 << 24;
+	    gcv.foreground |= color->red_short   >> 8 << 16;
+	    gcv.foreground |= color->green_short >> 8 << 8;
+	    gcv.foreground |= color->blue_short  >> 8 << 0;
+	    gcv.fill_style = FillSolid;
+
+	    XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv);
+	    XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1);
+
+	    _cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc);
+	}
+    }
 
-    return source (dst,
-		   XRenderCreateSolidFill (dst->display->display,
-					   &xrender_color));
+    return source (dst, picture, pixmap);
 }
 
 static cairo_surface_t *


More information about the cairo-commit mailing list