[cairo-commit] 2 commits - src/cairo-xlib-private.h src/cairo-xlib-screen.c src/cairo-xlib-surface.c src/cairo-xlib-surface-private.h test/clip-image.c test/clip-image.ref.png test/Makefile.am test/Makefile.sources

Chris Wilson ickle at kemper.freedesktop.org
Tue Sep 1 16:38:10 PDT 2009


 src/cairo-xlib-private.h         |   12 --
 src/cairo-xlib-screen.c          |   50 +++------
 src/cairo-xlib-surface-private.h |    2 
 src/cairo-xlib-surface.c         |  197 ++++++++++++++++++---------------------
 test/Makefile.am                 |    1 
 test/Makefile.sources            |    1 
 test/clip-image.c                |   94 ++++++++++++++++++
 test/clip-image.ref.png          |binary
 8 files changed, 212 insertions(+), 145 deletions(-)

New commits:
commit 59c4fe93ee30c8182ae1a29267b9c08602e2f6c5
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Sep 2 00:34:37 2009 +0100

    [xlib] Eliminate GC clipping
    
    Eradicate the use of clipping with GC. By never using clipping, we never
    have to worry about retrieving a dirty clip from the GC cache.

diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index e92bb94..33601e8 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -85,7 +85,7 @@ struct _cairo_xlib_screen {
     cairo_font_options_t font_options;
 
     GC gc[4];
-    int gc_depths; /* 4 x uint8_t, high bit == needs reset */
+    int gc_depths; /* 4 x uint8_t */
 
     cairo_array_t visuals;
 };
@@ -171,15 +171,13 @@ _cairo_xlib_screen_close_display (cairo_xlib_screen_t *info);
 
 cairo_private GC
 _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
-			   unsigned int depth,
-			   Drawable drawable,
-			   unsigned int *need_reset);
+			   int depth,
+			   Drawable drawable);
 
 cairo_private void
 _cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info,
-			   unsigned int depth,
-			   GC gc,
-			   cairo_bool_t reset_clip);
+			   int depth,
+			   GC gc);
 
 cairo_private cairo_font_options_t *
 _cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info);
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index 38e64af..800c6d2 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -380,9 +380,8 @@ _cairo_xlib_screen_get (Display *dpy,
 #if HAS_ATOMIC_OPS
 GC
 _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
-			   unsigned int depth,
-			   Drawable drawable,
-			   unsigned int *dirty)
+			   int depth,
+			   Drawable drawable)
 {
     XGCValues gcv;
     int i, new, old;
@@ -394,13 +393,13 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
 	if (old == 0)
 	    break;
 
-	if (((old >> 0) & 0x7f) == depth)
+	if (((old >> 0) & 0xff) == depth)
 	    i = 0;
-	else if (((old >> 8) & 0x7f) == depth)
+	else if (((old >> 8) & 0xff) == depth)
 	    i = 1;
-	else if (((old >> 16) & 0x7f) == depth)
+	else if (((old >> 16) & 0xff) == depth)
 	    i = 2;
-	else if (((old >> 24) & 0x7f) == depth)
+	else if (((old >> 24) & 0xff) == depth)
 	    i = 3;
 	else
 	    break;
@@ -411,10 +410,6 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
 
     if (likely (gc != NULL)) {
 	(void) _cairo_atomic_ptr_cmpxchg (&info->gc[i], gc, NULL);
-
-	if (old & 0x80 << (8 * i))
-	    *dirty |= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
-
 	return gc;
     }
 
@@ -426,25 +421,23 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
 
 void
 _cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info,
-			   unsigned int depth,
-			   GC gc,
-			   cairo_bool_t reset_clip)
+			   int depth,
+			   GC gc)
 {
     int i, old, new;
 
-    depth |= reset_clip ? 0x80 : 0;
     do {
 	do {
 	    i = -1;
 	    old = info->gc_depths;
 
-	    if (((old >> 0) & 0x7f) == 0)
+	    if (((old >> 0) & 0xff) == 0)
 		i = 0;
-	    else if (((old >> 8) & 0x7f) == 0)
+	    else if (((old >> 8) & 0xff) == 0)
 		i = 1;
-	    else if (((old >> 16) & 0x7f) == 0)
+	    else if (((old >> 16) & 0xff) == 0)
 		i = 2;
-	    else if (((old >> 24) & 0x7f) == 0)
+	    else if (((old >> 24) & 0xff) == 0)
 		i = 3;
 	    else
 		goto out;
@@ -468,19 +461,15 @@ out:
 #else
 GC
 _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
-			   unsigned int depth,
-			   Drawable drawable,
-			   unsigned int *dirty)
+			   int depth,
+			   Drawable drawable)
 {
     GC gc = NULL;
     int i;
 
     CAIRO_MUTEX_LOCK (info->mutex);
     for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
-	if (((info->gc_depths >> (8*i)) & 0x7f) == depth) {
-	    if (info->gc_depths & 0x80 << (8*i))
-		*dirty |= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
-
+	if (((info->gc_depths >> (8*i)) & 0xff) == depth) {
 	    info->gc_depths &= ~(0xff << (8*i));
 	    gc = info->gc[i];
 	    break;
@@ -502,17 +491,14 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
 
 void
 _cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info,
-			   unsigned int depth,
-			   GC gc,
-			   cairo_bool_t reset_clip)
+			   int depth,
+			   GC gc)
 {
     int i;
 
-    depth |= reset_clip ? 0x80 : 0;
-
     CAIRO_MUTEX_LOCK (info->mutex);
     for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
-	if (((info->gc_depths >> (8*i)) & 0x7f) == 0)
+	if (((info->gc_depths >> (8*i)) & 0xff) == 0)
 	    break;
     }
 
diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h
index b3cbe04..f821569 100644
--- a/src/cairo-xlib-surface-private.h
+++ b/src/cairo-xlib-surface-private.h
@@ -49,7 +49,6 @@ struct _cairo_xlib_surface {
     cairo_xlib_screen_t *screen;
     cairo_xlib_hook_t close_display_hook;
 
-    GC gc;
     Drawable drawable;
     cairo_bool_t owns_pixmap;
     Visual *visual;
@@ -88,7 +87,6 @@ struct _cairo_xlib_surface {
     Picture dst_picture, src_picture;
 
     unsigned int clip_dirty;
-    cairo_bool_t gc_has_clip_rects;
     XRectangle embedded_clip_rects[8];
     XRectangle *clip_rects;
     int num_clip_rects;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index b53f4de..1de6a97 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -83,11 +83,10 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t	*screen,
 				     int			depth);
 
 static cairo_status_t
-_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface,
-			       cairo_bool_t set_clip);
+_cairo_xlib_surface_get_gc (cairo_xlib_surface_t *surface, GC *gc);
 
 static void
-_cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface);
+_cairo_xlib_surface_put_gc (cairo_xlib_surface_t *surface, GC gc);
 
 static void
 _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface);
@@ -380,14 +379,6 @@ _cairo_xlib_surface_finish (void *abstract_surface)
 	    XRenderFreePicture (surface->dpy, surface->src_picture);
     }
 
-    if (surface->gc != NULL) {
-	_cairo_xlib_screen_put_gc (surface->screen,
-				   surface->depth,
-				   surface->gc,
-				   surface->gc_has_clip_rects);
-	surface->gc = NULL;
-    }
-
     if (surface->clip_rects != surface->embedded_clip_rects)
 	free (surface->clip_rects);
 
@@ -742,8 +733,9 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 	 * temporary pixmap
 	 */
 	Pixmap pixmap;
+	GC gc;
 
-	status = _cairo_xlib_surface_ensure_gc (surface, FALSE);
+	status = _cairo_xlib_surface_get_gc (surface, &gc);
 	if (unlikely (status))
 	    return status;
 
@@ -752,7 +744,7 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 				extents.width, extents.height,
 				surface->depth);
 	if (pixmap) {
-	    XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,
+	    XCopyArea (surface->dpy, surface->drawable, pixmap, gc,
 		       extents.x, extents.y,
 		       extents.width, extents.height,
 		       0, 0);
@@ -766,10 +758,10 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 	    XFreePixmap (surface->dpy, pixmap);
 	}
 
+	_cairo_xlib_surface_put_gc (surface, gc);
+
 	if (ximage == NULL)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	_cairo_xlib_surface_maybe_put_gc (surface);
     }
 
     _swap_ximage_to_native (ximage);
@@ -947,21 +939,6 @@ _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface)
 }
 
 static void
-_cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface)
-{
-    surface->gc_has_clip_rects = surface->clip_region != NULL;
-    if (surface->clip_region != NULL) {
-	XSetClipRectangles(surface->dpy, surface->gc,
-			   0, 0,
-			   surface->clip_rects,
-			   surface->num_clip_rects, YXSorted);
-    } else
-	XSetClipMask (surface->dpy, surface->gc, None);
-
-    surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
-}
-
-static void
 _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t    *surface)
 {
     if (!surface->dst_picture) {
@@ -976,49 +953,23 @@ _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t    *surface)
 }
 
 static cairo_status_t
-_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface,
-			       cairo_bool_t set_clip)
+_cairo_xlib_surface_get_gc (cairo_xlib_surface_t *surface, GC *gc)
 {
-
-    if (surface->gc == NULL) {
-	surface->gc = _cairo_xlib_screen_get_gc (surface->screen,
-						 surface->depth,
-						 surface->drawable,
-						 &surface->clip_dirty);
-	if (unlikely (surface->gc == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	surface->gc_has_clip_rects =
-	    surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
-    }
-
-    if (set_clip) {
-	if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC)
-	    _cairo_xlib_surface_set_gc_clip_rects (surface);
-    } else {
-	if (surface->gc_has_clip_rects) {
-	    surface->gc_has_clip_rects = FALSE;
-	    XSetClipMask (surface->dpy, surface->gc, None);
-
-	    surface->clip_dirty |= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
-	}
-    }
+    *gc = _cairo_xlib_screen_get_gc (surface->screen,
+				     surface->depth,
+				     surface->drawable);
+    if (unlikely (*gc == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
-_cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface)
+_cairo_xlib_surface_put_gc (cairo_xlib_surface_t *surface, GC gc)
 {
-    /* return the GC back to the common pool if clean */
-    if (surface->gc_has_clip_rects)
-	return;
-
     _cairo_xlib_screen_put_gc (surface->screen,
 			       surface->depth,
-			       surface->gc,
-			       FALSE);
-    surface->gc = NULL;
+			       gc);
 }
 
 static cairo_status_t
@@ -1036,6 +987,7 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
     int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
     cairo_status_t status;
     cairo_bool_t own_data;
+    GC gc;
 
     _pixman_format_to_masks (image->pixman_format, &image_masks);
 
@@ -1173,16 +1125,15 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 	}
     }
 
-    /* XXX set clip? */
-    status = _cairo_xlib_surface_ensure_gc (surface, FALSE);
+    status = _cairo_xlib_surface_get_gc (surface, &gc);
     if (unlikely (status))
 	goto BAIL;
 
-    XPutImage (surface->dpy, surface->drawable, surface->gc,
+    XPutImage (surface->dpy, surface->drawable, gc,
 	       &ximage, src_x, src_y, dst_x, dst_y,
 	       width, height);
 
-    _cairo_xlib_surface_maybe_put_gc (surface);
+    _cairo_xlib_surface_put_gc (surface, gc);
 
   BAIL:
     if (own_data)
@@ -2136,6 +2087,7 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
     cairo_bool_t		is_integer_translation;
     cairo_bool_t		needs_alpha_composite;
     cairo_content_t		src_content;
+    GC				gc;
 
     if (mask_pattern != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
 	return UNSUPPORTED ("no support for masks");
@@ -2183,10 +2135,6 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 	goto BAIL;
     }
 
-    status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
-    if (unlikely (status))
-	goto BAIL;
-
     switch (operation)
     {
     case DO_RENDER:
@@ -2196,6 +2144,10 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 	if (unlikely (status))
 	    goto BAIL;
 
+	status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
+	if (unlikely (status))
+	    goto BAIL;
+
 	_cairo_xlib_surface_ensure_dst_picture (dst);
 	if (mask) {
 	    status = _cairo_xlib_surface_set_attributes (mask, &mask_attr,
@@ -2231,7 +2183,7 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 	break;
 
     case DO_XCOPYAREA:
-	status = _cairo_xlib_surface_ensure_gc (dst, TRUE);
+	status = _cairo_xlib_surface_get_gc (dst, &gc);
 	if (unlikely (status))
 	    goto BAIL;
 
@@ -2240,16 +2192,38 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 	/* This is a pre-condition for DO_XCOPYAREA. */
 	assert (is_integer_translation);
 
-	XCopyArea (dst->dpy,
-		   src->drawable,
-		   dst->drawable,
-		   dst->gc,
-		   src_x + src_attr.x_offset + itx,
-		   src_y + src_attr.y_offset + ity,
-		   width, height,
-		   dst_x, dst_y);
+	if (clip_region == NULL) {
+	    XCopyArea (dst->dpy,
+		       src->drawable,
+		       dst->drawable,
+		       gc,
+		       src_x + src_attr.x_offset + itx,
+		       src_y + src_attr.y_offset + ity,
+		       width, height,
+		       dst_x, dst_y);
+	} else {
+	    int n, num_rects;
+
+	    src_x += src_attr.x_offset + itx - dst_x;
+	    src_y += src_attr.y_offset + ity - dst_y;
+
+	    num_rects = cairo_region_num_rectangles (clip_region);
+	    for (n = 0; n < num_rects; n++) {
+		cairo_rectangle_int_t rect;
+
+		cairo_region_get_rectangle (clip_region, n, &rect);
+		XCopyArea (dst->dpy,
+			   src->drawable,
+			   dst->drawable,
+			   gc,
+			   rect.x + src_x,
+			   rect.y + src_y,
+			   rect.width, rect.height,
+			   rect.x, rect.y);
+	    }
+	}
 
-	_cairo_xlib_surface_maybe_put_gc (dst);
+	_cairo_xlib_surface_put_gc (dst, gc);
 	break;
 
     case DO_XTILE:
@@ -2261,23 +2235,42 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 	 * _recategorize_composite_operation.
 	 */
 
-	status = _cairo_xlib_surface_ensure_gc (dst, TRUE);
+	status = _cairo_xlib_surface_get_gc (dst, &gc);
 	if (unlikely (status))
 	    goto BAIL;
+
 	is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
 								       &itx, &ity);
 	/* This is a pre-condition for DO_XTILE. */
 	assert (is_integer_translation);
 
-	XSetTSOrigin (dst->dpy, dst->gc,
+	XSetTSOrigin (dst->dpy, gc,
 		      - (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
-	XSetTile (dst->dpy, dst->gc, src->drawable);
-	XSetFillStyle (dst->dpy, dst->gc, FillTiled);
+	XSetTile (dst->dpy, gc, src->drawable);
+	XSetFillStyle (dst->dpy, gc, FillTiled);
+
+	if (clip_region == NULL) {
+	    XFillRectangle (dst->dpy, dst->drawable, gc,
+			    dst_x, dst_y, width, height);
+	} else {
+	    int n, num_rects;
 
-	XFillRectangle (dst->dpy, dst->drawable, dst->gc,
-			dst_x, dst_y, width, height);
+	    src_x += src_attr.x_offset + itx;
+	    src_y += src_attr.y_offset + ity;
 
-	_cairo_xlib_surface_maybe_put_gc (dst);
+	    num_rects = cairo_region_num_rectangles (clip_region);
+	    for (n = 0; n < num_rects; n++) {
+		cairo_rectangle_int_t rect;
+
+		cairo_region_get_rectangle (clip_region, n, &rect);
+		rect.x -= dst_x;
+		rect.y -= dst_y;
+		XFillRectangle (dst->dpy, dst->drawable, gc,
+				rect.x, rect.y, rect.width, rect.height);
+	    }
+	}
+
+	_cairo_xlib_surface_put_gc (dst, gc);
 	break;
 
     case DO_UNSUPPORTED:
@@ -2316,11 +2309,12 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
     cairo_solid_pattern_t solid;
     cairo_surface_t *solid_surface = NULL;
     cairo_surface_attributes_t attrs;
+    GC gc;
     int i;
 
     _cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR);
 
-    status = _cairo_xlib_surface_ensure_gc (surface, FALSE);
+    status = _cairo_xlib_surface_get_gc (surface, &gc);
     if (unlikely (status))
         return status;
 
@@ -2332,25 +2326,27 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
 					     CAIRO_PATTERN_ACQUIRE_NONE,
 					     &solid_surface,
 					     &attrs);
-    if (unlikely (status))
-        return status;
+    if (unlikely (status)) {
+	_cairo_xlib_surface_put_gc (surface, gc);
+	return status;
+    }
 
     assert (_cairo_surface_is_xlib (solid_surface));
 
-    XSetTSOrigin (surface->dpy, surface->gc,
+    XSetTSOrigin (surface->dpy, gc,
 		  - (surface->base.device_transform.x0 + attrs.x_offset),
 		  - (surface->base.device_transform.y0 + attrs.y_offset));
-    XSetTile (surface->dpy, surface->gc,
+    XSetTile (surface->dpy, gc,
 	      ((cairo_xlib_surface_t *) solid_surface)->drawable);
-    XSetFillStyle (surface->dpy, surface->gc, FillTiled);
+    XSetFillStyle (surface->dpy, gc, FillTiled);
 
     for (i = 0; i < num_rects; i++) {
-	XFillRectangle (surface->dpy, surface->drawable, surface->gc,
+	XFillRectangle (surface->dpy, surface->drawable, gc,
 			rects[i].x, rects[i].y,
 			rects[i].width, rects[i].height);
     }
 
-    _cairo_xlib_surface_maybe_put_gc (surface);
+    _cairo_xlib_surface_put_gc (surface, gc);
 
     _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs);
 
@@ -2859,11 +2855,6 @@ _cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data)
 	surface->drawable = None;
 	surface->owns_pixmap = FALSE;
     }
-
-    if (surface->gc != NULL) {
-	XFreeGC (dpy, surface->gc);
-	surface->gc = NULL;
-    }
 }
 
 static cairo_surface_t *
@@ -2947,7 +2938,6 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t	*screen,
     surface->screen = _cairo_xlib_screen_reference (screen);
     surface->display = screen->display;
 
-    surface->gc = NULL;
     surface->drawable = drawable;
     surface->owns_pixmap = FALSE;
     surface->use_pixmap = 0;
@@ -2979,7 +2969,6 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t	*screen,
     surface->xtransform = identity;
 
     surface->clip_region = NULL;
-    surface->gc_has_clip_rects = FALSE;
     surface->clip_rects = surface->embedded_clip_rects;
     surface->num_clip_rects = 0;
     surface->clip_dirty = 0;
commit 075fc5666abe006c434bf7ec28d2d4f0226a1d3a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Sep 2 00:33:22 2009 +0100

    [test] Add clip-image
    
    Exercise the XCopyArea() paths under clipping - whilst modifying that code
    I noticed that it was not being exercised by the test suite.

diff --git a/test/Makefile.am b/test/Makefile.am
index 4ac776f..aaa520d 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -177,6 +177,7 @@ REFERENCE_IMAGES = \
 	clip-fill-rule.rgb24.ref.png \
 	clip-fill-rule.test-paginated.rgb24.ref.png \
 	clip-fill-rule.xlib.rgb24.ref.png \
+	clip-image.ref.png \
 	clip-nesting.pdf.argb32.ref.png \
 	clip-nesting.ps2.argb32.ref.png \
 	clip-nesting.ps2.rgb24.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index c4f2516..3dbdd55 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -18,6 +18,7 @@ test_sources = \
 	clip-fill.c					\
 	clip-fill-rule.c				\
 	clip-fill-rule-pixel-aligned.c			\
+	clip-image.c					\
 	clip-nesting.c					\
 	clip-operator.c					\
 	clip-push-group.c				\
diff --git a/test/clip-image.c b/test/clip-image.c
new file mode 100644
index 0000000..e3c8809
--- /dev/null
+++ b/test/clip-image.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2009 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#define WIDTH 20
+#define HEIGHT 20
+
+static const char *png_filename = "romedalen.png";
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    const cairo_test_context_t *ctx = cairo_test_get_context (cr);
+    cairo_surface_t *image;
+
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+
+    image = cairo_test_create_surface_from_png (ctx, png_filename);
+    cairo_set_source_surface (cr, image, 0, 0);
+
+    /* simple clip */
+    cairo_save (cr);
+    cairo_rectangle (cr, 2, 2, 16, 16);
+    cairo_clip (cr);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    cairo_translate (cr, WIDTH, 0);
+
+    /* unaligned clip */
+    cairo_save (cr);
+    cairo_rectangle (cr, 2.5, 2.5, 15, 15);
+    cairo_clip (cr);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    cairo_translate (cr, -WIDTH, HEIGHT);
+
+    /* aligned-clip */
+    cairo_save (cr);
+    cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+    cairo_rectangle (cr, 0, 0, 20, 20);
+    cairo_rectangle (cr, 3, 3, 10, 10);
+    cairo_rectangle (cr, 7, 7, 10, 10);
+    cairo_clip (cr);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    cairo_translate (cr, WIDTH, 0);
+
+    /* force a clip-mask */
+    cairo_save (cr);
+    cairo_arc (cr, 10, 10, 10, 0, 2 * M_PI);
+    cairo_new_sub_path (cr);
+    cairo_arc_negative (cr, 10, 10, 5, 2 * M_PI, 0);
+    cairo_new_sub_path (cr);
+    cairo_arc (cr, 10, 10, 2, 0, 2 * M_PI);
+    cairo_clip (cr);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (clip_image,
+	    "Tests painting an image through complex clips.",
+	    "clip, paint", /* keywords */
+	    NULL, /* requirements */
+	    2 * WIDTH, 2 * HEIGHT,
+	    NULL, draw)
diff --git a/test/clip-image.ref.png b/test/clip-image.ref.png
new file mode 100644
index 0000000..b038f2a
Binary files /dev/null and b/test/clip-image.ref.png differ


More information about the cairo-commit mailing list