[cairo-commit] 6 commits - AUTHORS boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate.h boilerplate/cairo-boilerplate-pdf.c src/cairo.c src/cairo-xlib-surface.c test/cairo-test-trace.c test/.gitignore test/group-clip.c test/group-clip.ref.png test/Makefile.am test/Makefile.sources

Chris Wilson ickle at kemper.freedesktop.org
Fri Jun 19 11:19:09 PDT 2009


 AUTHORS                             |    1 
 boilerplate/cairo-boilerplate-pdf.c |    2 
 boilerplate/cairo-boilerplate.c     |  254 +++++++++++++++++++-----------------
 boilerplate/cairo-boilerplate.h     |    5 
 src/cairo-xlib-surface.c            |    9 -
 src/cairo.c                         |   10 +
 test/.gitignore                     |    1 
 test/Makefile.am                    |    7 
 test/Makefile.sources               |    1 
 test/cairo-test-trace.c             |  229 ++++++++++++++++++++++++++------
 test/group-clip.c                   |   57 ++++++++
 test/group-clip.ref.png             |binary
 12 files changed, 415 insertions(+), 161 deletions(-)

New commits:
commit 3bad3efaa2fa00275c1d27c95ccbf1fcdfdfef3e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jun 19 19:09:03 2009 +0100

    [test] Add cairo-test-trace to .gitignore

diff --git a/test/.gitignore b/test/.gitignore
index 867db42..b34bc64 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -12,6 +12,7 @@ any2ppm
 .any2ppm.pid
 .any2ppm.errors
 cairo-test-constructors.c
+cairo-test-trace
 cairo-test-suite
 pdf2png
 ps2png
commit 62dc0ae46c26652da9a76b851bab594020020115
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jun 19 19:03:17 2009 +0100

    [cairo] Offset the current path when pushing/popping groups.
    
    We need to translate the path in order to compensate for the device offset
    applied to the group surface when pushing and popping. (The path is
    transformed to device space on creation, and so needs recomputing for the
    new device.)

diff --git a/src/cairo.c b/src/cairo.c
index 5f26d6f..c462e42 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -530,6 +530,11 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
                                      parent_surface->device_transform.x0 - extents.x,
                                      parent_surface->device_transform.y0 - extents.y);
 
+    /* If we have a current path, we need to adjust it to compensate for
+     * the device offset just applied. */
+    _cairo_path_fixed_transform (cr->path,
+				 &group_surface->device_transform);
+
     /* create a new gstate for the redirect */
     cairo_save (cr);
     if (cr->status)
@@ -613,6 +618,11 @@ cairo_pop_group (cairo_t *cr)
 	cairo_pattern_set_matrix (group_pattern, &group_matrix);
     }
 
+    /* If we have a current path, we need to adjust it to compensate for
+     * the device offset just removed. */
+    _cairo_path_fixed_transform (cr->path,
+				 &group_surface->device_transform_inverse);
+
 done:
     cairo_surface_destroy (group_surface);
 
commit 851c8839622619779c9169299e3efccd108d0395
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jun 19 19:00:39 2009 +0100

    [test] Add group-clip
    
    Larry Ewing found an ancient and nasty bug whereby a path was not
    corrected whilst pushing and popping groups.

diff --git a/AUTHORS b/AUTHORS
index 7f7b0d1..39a3179 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -23,6 +23,7 @@ John Ellson <ellson at research.att.com> First font/glyph extents functions
 Michael Emmel <mike.emmel at gmail.com> DirectFB backend
 Miklós Erdélyi <erdelyim at gmail.com> Fix typo leading to a crash
 Behdad Esfahbod <behdad at behdad.org> Huge piles of bug fixes, improvements, and general maintenance
+Larry Ewing <lewing at novell.com> Test case for group-clip
 Brian Ewins <Brian.Ewins at gmail.com> ATSUI maintenance (first success at making it really work)
 Bertram Felgenhauer <int-e at gmx.de> Fixes for subtle arithmetic errors
 Damian Frank <damian.frank at gmail.com> Build system improvements for win32
diff --git a/test/Makefile.am b/test/Makefile.am
index ff4d588..a2275a4 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -500,6 +500,7 @@ REFERENCE_IMAGES = \
 	gradient-constant-alpha.rgb24.ref.png \
 	gradient-zero-stops.ref.png \
 	gradient-zero-stops.rgb24.ref.png \
+	group-clip.ref.png \
 	group-paint.ref.png \
 	huge-linear.ps3.ref.png \
 	huge-linear.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 4604b1f..64c6d04 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -79,6 +79,7 @@ test_sources = \
 	gradient-alpha.c				\
 	gradient-constant-alpha.c			\
 	gradient-zero-stops.c				\
+	group-clip.c					\
 	group-paint.c					\
 	huge-linear.c					\
 	huge-radial.c					\
diff --git a/test/group-clip.c b/test/group-clip.c
new file mode 100644
index 0000000..b99d861
--- /dev/null
+++ b/test/group-clip.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright © Chris Wilson, 2008
+ *
+ * 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. Red Hat, Inc. 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.
+ *
+ * Authors: Chris Wilson <chris at chris-wilson.co.uk>
+ *          Larry Ewing <lewing at novell.com>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+
+    cairo_rectangle (cr, 25, 25, width, height);
+    cairo_clip_preserve (cr);
+    cairo_push_group (cr);
+    cairo_set_source_rgb (cr, 0, 0, 1);
+    cairo_fill (cr);
+    cairo_rectangle (cr, 0, 0, width, height);
+    cairo_pop_group_to_source (cr);
+    cairo_paint (cr);
+
+    cairo_reset_clip (cr);
+    cairo_clip_preserve (cr);
+    cairo_set_source_rgba (cr, 1, 0, 0, .5);
+    cairo_paint (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (group_clip,
+	    "test preserving paths across groups",
+	    "group", /* keywords */
+	    NULL, /* requirements */
+	    40 + 25, 40 + 25,
+	    NULL, draw)
diff --git a/test/group-clip.ref.png b/test/group-clip.ref.png
new file mode 100644
index 0000000..7b8a753
Binary files /dev/null and b/test/group-clip.ref.png differ
commit 0a34abace781976b92287dd07daa2b41e168c4f6
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jun 19 18:40:43 2009 +0100

    [test] Experiment with reference targets
    
    Specify another boilerplate target to use as the reference for this
    target. We then use this in cairo-test-trace in preference to using the
    image surface. Still not perfect, though the framework is improving.

diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 0a9ab62..50a28f8 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -279,86 +279,86 @@ static const cairo_boilerplate_target_t targets[] =
      * for tolerance. There shouldn't ever be anything that is out of
      * our control here. */
     {
-	"image", "image", NULL,
+	"image", "image", NULL, NULL,
 	CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_image_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_image_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png
     },
     {
-	"image", "image", NULL,
+	"image", "image", NULL, NULL,
 	CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_image_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_image_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png
     },
 #ifdef CAIRO_HAS_TEST_SURFACES
     {
-	"test-fallback", "image", NULL,
+	"test-fallback", "image", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
 	CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_test_fallback_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_test_fallback_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png
     },
     {
-	"test-fallback", "image", NULL,
+	"test-fallback", "image", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
 	CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_test_fallback_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_test_fallback_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png
     },
     {
-	"test-fallback16", "image", NULL,
+	"test-fallback16", "image", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
 	CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_test_fallback16_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_test_fallback16_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png
     },
     {
-	"test-fallback16", "image", NULL,
+	"test-fallback16", "image", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
 	CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_test_fallback16_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_test_fallback16_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png
     },
     {
-	"test-meta", "image", NULL,
+	"test-meta", "image", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
 	CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_test_meta_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_test_meta_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	NULL, NULL,
 	FALSE, TRUE
     },
     {
-	"test-meta", "image", NULL,
+	"test-meta", "image", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
 	CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_test_meta_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_test_meta_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	NULL, NULL,
 	FALSE, TRUE
     },
     {
-	"test-paginated", "image", NULL,
+	"test-paginated", "image", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
 	CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_test_paginated_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_test_paginated_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_test_paginated_get_image_surface,
 	_cairo_boilerplate_test_paginated_surface_write_to_png,
 	_cairo_boilerplate_test_paginated_cleanup,
@@ -366,11 +366,11 @@ static const cairo_boilerplate_target_t targets[] =
 	FALSE, TRUE,
     },
     {
-	"test-paginated", "image", NULL,
+	"test-paginated", "image", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
 	CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_test_paginated_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_test_paginated_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_test_paginated_get_image_surface,
 	_cairo_boilerplate_test_paginated_surface_write_to_png,
 	_cairo_boilerplate_test_paginated_cleanup,
@@ -378,31 +378,32 @@ static const cairo_boilerplate_target_t targets[] =
 	FALSE, TRUE
     },
     {
-	"null", "image", NULL,
+	"null", "image", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_NULL,
 	CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_test_null_create_surface, NULL,
-	NULL, NULL, NULL,
+	_cairo_boilerplate_test_null_create_surface,
 	NULL, NULL,
+	NULL, NULL, NULL,
+	NULL,
 	TRUE, FALSE
     },
 #endif
 #ifdef CAIRO_HAS_GLITZ_SURFACE
 #if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
     {
-	"glitz-glx", "glitz", NULL,
+	"glitz-glx", "glitz", NULL, NULL,
 	CAIRO_SURFACE_TYPE_GLITZ,CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_glitz_glx_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_glitz_glx_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_glitz_glx_cleanup
     },
     {
-	"glitz-glx", "glitz", NULL,
+	"glitz-glx", "glitz", NULL, NULL,
 	CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_glitz_glx_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_glitz_glx_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_glitz_glx_cleanup
@@ -410,19 +411,19 @@ static const cairo_boilerplate_target_t targets[] =
 #endif
 #if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
     {
-	"glitz-agl", "glitz", NULL,
+	"glitz-agl", "glitz", NULL, NULL,
 	CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_glitz_agl_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_glitz_agl_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_glitz_agl_cleanup
     },
     {
-	"glitz-agl", "glitz", NULL,
+	"glitz-agl", "glitz", NULL, NULL,
 	CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_glitz_agl_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_glitz_agl_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_glitz_agl_cleanup
@@ -430,19 +431,19 @@ static const cairo_boilerplate_target_t targets[] =
 #endif
 #if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE
     {
-	"glitz-wgl", "glitz", NULL,
+	"glitz-wgl", "glitz", NULL, NULL,
 	CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_glitz_wgl_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_glitz_wgl_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_glitz_wgl_cleanup
     },
     {
-	"glitz-wgl", "glitz", NULL,
+	"glitz-wgl", "glitz", NULL, NULL,
 	CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_glitz_wgl_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_glitz_wgl_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_glitz_wgl_cleanup
@@ -451,19 +452,19 @@ static const cairo_boilerplate_target_t targets[] =
 #endif /* CAIRO_HAS_GLITZ_SURFACE */
 #if CAIRO_HAS_QT_SURFACE
     {
-	"qt", "qt", NULL,
+	"qt", "qt", NULL, NULL,
 	CAIRO_SURFACE_TYPE_QT, CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_qt_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_qt_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_qt_cleanup
     },
     {
-	"qt", "qt", NULL,
+	"qt", "qt", NULL, NULL,
 	CAIRO_SURFACE_TYPE_QT, CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_qt_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_qt_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_qt_cleanup
@@ -471,19 +472,19 @@ static const cairo_boilerplate_target_t targets[] =
 #endif
 #if CAIRO_HAS_QUARTZ_SURFACE
     {
-	"quartz", "quartz", NULL,
+	"quartz", "quartz", NULL, NULL,
 	CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_quartz_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_quartz_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_quartz_cleanup
     },
     {
-	"quartz", "quartz", NULL,
+	"quartz", "quartz", NULL, NULL,
 	CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_quartz_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_quartz_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_quartz_cleanup
@@ -491,10 +492,10 @@ static const cairo_boilerplate_target_t targets[] =
 #endif
 #if CAIRO_HAS_WIN32_SURFACE
     {
-	"win32", "win32", NULL,
+	"win32", "win32", NULL, NULL,
 	CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_win32_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_win32_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png
     },
@@ -502,30 +503,30 @@ static const cairo_boilerplate_target_t targets[] =
      * ARGB images it just chains to the image backend
      */
     {
-	"win32", "win32", NULL,
+	"win32", "win32", NULL, NULL,
 	CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_win32_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_win32_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png
     },
 #if CAIRO_CAN_TEST_WIN32_PRINTING_SURFACE
     {
-	"win32-printing", "win32", ".ps",
+	"win32-printing", "win32", ".ps", NULL,
 	CAIRO_SURFACE_TYPE_WIN32_PRINTING,
 	CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
-	_cairo_boilerplate_win32_printing_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_win32_printing_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_win32_printing_get_image_surface,
 	_cairo_boilerplate_win32_printing_surface_write_to_png,
 	_cairo_boilerplate_win32_printing_cleanup,
 	NULL, TRUE, TRUE
     },
     {
-	"win32-printing", "win32", ".ps",
+	"win32-printing", "win32", ".ps", NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_win32_printing_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_win32_printing_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_win32_printing_get_image_surface,
 	_cairo_boilerplate_win32_printing_surface_write_to_png,
 	_cairo_boilerplate_win32_printing_cleanup,
@@ -537,10 +538,10 @@ static const cairo_boilerplate_target_t targets[] =
     /* Acceleration architectures may make the results differ by a
      * bit, so we set the error tolerance to 1. */
     {
-	"xcb", "xcb", NULL,
+	"xcb", "xcb", NULL, NULL,
 	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
-	_cairo_boilerplate_xcb_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_xcb_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_xcb_cleanup,
@@ -551,19 +552,20 @@ static const cairo_boilerplate_target_t targets[] =
     /* Acceleration architectures may make the results differ by a
      * bit, so we set the error tolerance to 1. */
     {
-	"xlib", "xlib", NULL,
+	"xlib", "xlib", NULL, "xlib-fallback",
 	CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA, 1,
-	_cairo_boilerplate_xlib_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_xlib_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_xlib_cleanup,
 	_cairo_boilerplate_xlib_synchronize
     },
     {
-	"xlib", "xlib", NULL, CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
-	_cairo_boilerplate_xlib_create_surface, NULL,
-	NULL,
+	"xlib", "xlib", NULL, "xlib-fallback",
+	CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
+	_cairo_boilerplate_xlib_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_xlib_cleanup,
@@ -574,10 +576,10 @@ static const cairo_boilerplate_target_t targets[] =
     /* This is a fallback surface which uses xlib fallbacks instead of
      * the Render extension. */
     {
-	"xlib-fallback", "xlib", NULL,
+	"xlib-fallback", "xlib", NULL, NULL,
 	CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
-	_cairo_boilerplate_xlib_fallback_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_xlib_fallback_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_xlib_cleanup,
@@ -586,7 +588,7 @@ static const cairo_boilerplate_target_t targets[] =
 #endif
 #if CAIRO_HAS_PS_SURFACE && CAIRO_CAN_TEST_PS_SURFACE
     {
-	"ps2", "ps", ".ps",
+	"ps2", "ps", ".ps", NULL,
 	CAIRO_SURFACE_TYPE_PS,
 	CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
 	_cairo_boilerplate_ps2_create_surface,
@@ -598,7 +600,7 @@ static const cairo_boilerplate_target_t targets[] =
 	NULL, TRUE, TRUE
     },
     {
-	"ps2", "ps", ".ps",
+	"ps2", "ps", ".ps", NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
 	_cairo_boilerplate_ps2_create_surface,
 	_cairo_boilerplate_ps_force_fallbacks,
@@ -609,7 +611,7 @@ static const cairo_boilerplate_target_t targets[] =
 	NULL, TRUE, TRUE
     },
     {
-	"ps3", "ps", ".ps",
+	"ps3", "ps", ".ps", NULL,
 	CAIRO_SURFACE_TYPE_PS,
 	CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
 	_cairo_boilerplate_ps3_create_surface,
@@ -621,7 +623,7 @@ static const cairo_boilerplate_target_t targets[] =
 	NULL, TRUE, TRUE
     },
     {
-	"ps3", "ps", ".ps",
+	"ps3", "ps", ".ps", NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
 	_cairo_boilerplate_ps3_create_surface,
 	_cairo_boilerplate_ps_force_fallbacks,
@@ -634,7 +636,7 @@ static const cairo_boilerplate_target_t targets[] =
 #endif
 #if CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE
     {
-	"pdf", "pdf", ".pdf",
+	"pdf", "pdf", ".pdf", NULL,
 	CAIRO_SURFACE_TYPE_PDF,
 	CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
 	_cairo_boilerplate_pdf_create_surface,
@@ -646,7 +648,7 @@ static const cairo_boilerplate_target_t targets[] =
 	NULL, TRUE, TRUE
     },
     {
-	"pdf", "pdf", ".pdf",
+	"pdf", "pdf", ".pdf", NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
 	_cairo_boilerplate_pdf_create_surface,
 	_cairo_boilerplate_pdf_force_fallbacks,
@@ -659,7 +661,7 @@ static const cairo_boilerplate_target_t targets[] =
 #endif
 #if CAIRO_HAS_SCRIPT_SURFACE
     {
-	"script", "script", ".cs",
+	"script", "script", ".cs", NULL,
 	CAIRO_SURFACE_TYPE_SCRIPT, CAIRO_CONTENT_COLOR_ALPHA, 0,
 	_cairo_boilerplate_script_create_surface,
 	NULL,
@@ -677,7 +679,7 @@ static const cairo_boilerplate_target_t targets[] =
      * tests. XXX: I'd still like to chase these down at some point.
      * For now just set the svg error tolerance to 1. */
     {
-	"svg11", "svg", NULL,
+	"svg11", "svg", NULL, NULL,
 	CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1,
 	_cairo_boilerplate_svg11_create_surface,
 	_cairo_boilerplate_svg_force_fallbacks,
@@ -688,7 +690,7 @@ static const cairo_boilerplate_target_t targets[] =
 	NULL, TRUE, TRUE
     },
     {
-	"svg11", "svg", NULL,
+	"svg11", "svg", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
 	_cairo_boilerplate_svg11_create_surface,
 	_cairo_boilerplate_svg_force_fallbacks,
@@ -699,7 +701,7 @@ static const cairo_boilerplate_target_t targets[] =
 	NULL, TRUE, TRUE
     },
     {
-	"svg12", "svg", NULL,
+	"svg12", "svg", NULL, NULL,
 	CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1,
 	_cairo_boilerplate_svg12_create_surface,
 	_cairo_boilerplate_svg_force_fallbacks,
@@ -710,7 +712,7 @@ static const cairo_boilerplate_target_t targets[] =
 	NULL, TRUE, TRUE
     },
     {
-	"svg12", "svg", NULL,
+	"svg12", "svg", NULL, NULL,
 	CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
 	_cairo_boilerplate_svg12_create_surface,
 	_cairo_boilerplate_svg_force_fallbacks,
@@ -726,28 +728,28 @@ static const cairo_boilerplate_target_t targets[] =
      * is related to the fact that it doesn't use premultiplied alpha...
      * Just ignore the small difference. */
     {
-	"beos", "beos", NULL,
+	"beos", "beos", NULL, NULL,
 	CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR, 1,
-	_cairo_boilerplate_beos_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_beos_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_beos_cleanup
     },
     {
-	"beos-bitmap", "beos", NULL,
+	"beos-bitmap", "beos", NULL, NULL,
 	CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR, 1,
-	_cairo_boilerplate_beos_create_surface_for_bitmap, NULL,
-	NULL,
+	_cairo_boilerplate_beos_create_surface_for_bitmap,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_beos_cleanup_bitmap
     },
     {
-	"beos-bitmap", "beos", NULL,
+	"beos-bitmap", "beos", NULL, NULL,
 	CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR_ALPHA, 1,
-	_cairo_boilerplate_beos_create_surface_for_bitmap, NULL,
-	NULL,
+	_cairo_boilerplate_beos_create_surface_for_bitmap,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_beos_cleanup_bitmap
@@ -756,19 +758,19 @@ static const cairo_boilerplate_target_t targets[] =
 
 #if CAIRO_HAS_DIRECTFB_SURFACE
     {
-	"directfb", "directfb", NULL,
+	"directfb", "directfb", NULL, NULL,
 	CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR, 0,
-	_cairo_boilerplate_directfb_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_directfb_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_directfb_cleanup
     },
     {
-	"directfb-bitmap", "directfb", NULL,
+	"directfb-bitmap", "directfb", NULL, NULL,
 	CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR_ALPHA, 0,
-	_cairo_boilerplate_directfb_create_surface, NULL,
-	NULL,
+	_cairo_boilerplate_directfb_create_surface,
+	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_directfb_cleanup
@@ -899,6 +901,32 @@ cairo_boilerplate_get_image_target (cairo_content_t content)
     return NULL;
 }
 
+const cairo_boilerplate_target_t *
+cairo_boilerplate_get_target_by_name (const char *name,
+				      cairo_content_t content)
+{
+    int num_targets, i;
+
+    num_targets = sizeof (targets) / sizeof (targets[0]);
+
+    /* first return an exact match */
+    for (i = 0; i < num_targets; i++) {
+	if (strcmp (targets[i].name, name) == 0 &&
+	    targets[i].content == content)
+	{
+	    return &targets[i];
+	}
+    }
+
+    /* otherwise just return a match that may differ in content */
+    for (i = 0; i < num_targets; i++) {
+	if (strcmp (targets[i].name, name) == 0)
+	    return &targets[i];
+    }
+
+    return NULL;
+}
+
 void
 cairo_boilerplate_free_targets (const cairo_boilerplate_target_t **targets)
 {
diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h
index aa96ab7..99dc5ce 100644
--- a/boilerplate/cairo-boilerplate.h
+++ b/boilerplate/cairo-boilerplate.h
@@ -152,6 +152,7 @@ typedef struct _cairo_boilerplate_target
     const char					*name;
     const char					*basename;
     const char					*file_extension;
+    const char                                  *reference_target;
     cairo_surface_type_t			 expected_type;
     cairo_content_t				 content;
     unsigned int				 error_tolerance;
@@ -169,6 +170,10 @@ typedef struct _cairo_boilerplate_target
 const cairo_boilerplate_target_t *
 cairo_boilerplate_get_image_target (cairo_content_t content);
 
+const cairo_boilerplate_target_t *
+cairo_boilerplate_get_target_by_name (const char *name,
+				      cairo_content_t content);
+
 const cairo_boilerplate_target_t **
 cairo_boilerplate_get_targets (int *num_targets, cairo_bool_t *limited_targets);
 
diff --git a/test/Makefile.am b/test/Makefile.am
index 91ae578..ff4d588 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -100,14 +100,18 @@ endif
 if HAVE_SHM
 EXTRA_PROGRAMS += cairo-test-trace
 cairo_test_trace_SOURCES =		\
-	cairo-test-trace.c
+	cairo-test-trace.c		\
+	buffer-diff.c			\
+	buffer-diff.h
 cairo_test_trace_LDADD =		\
+	$(top_builddir)/test/pdiff/libpdiff.la 			\
 	$(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
         $(top_builddir)/boilerplate/libcairoboilerplate.la	\
 	$(top_builddir)/src/libcairo.la 			\
 	$(CAIRO_LDADD) \
 	$(SHM_LIBS)
 cairo_test_trace_DEPENDENCIES = \
+	$(top_builddir)/test/pdiff/libpdiff.la 			\
 	$(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
         $(top_builddir)/boilerplate/libcairoboilerplate.la	\
 	$(top_builddir)/src/libcairo.la
diff --git a/test/cairo-test-trace.c b/test/cairo-test-trace.c
index 1db4439..5bf058e 100644
--- a/test/cairo-test-trace.c
+++ b/test/cairo-test-trace.c
@@ -55,6 +55,7 @@
 #define _GNU_SOURCE 1	/* getline() */
 
 #include "cairo-test.h"
+#include "buffer-diff.h"
 
 #include "cairo-boilerplate-getopt.h"
 #include <cairo-script-interpreter.h>
@@ -82,7 +83,7 @@
 #include <fontconfig/fontconfig.h>
 #endif
 
-#define DATA_SIZE (64 << 20)
+#define DATA_SIZE (256 << 20)
 #define SHM_PATH_XXX "/shmem-cairo-trace"
 
 typedef struct _test_runner {
@@ -106,9 +107,12 @@ typedef struct _test_runner_thread {
     pid_t pid;
     int sk;
 
-    struct context_list {
-	struct context_list *next;
+    cairo_script_interpreter_t *csi;
+    struct context_closure {
+	struct context_closure *next;
 	unsigned long id;
+	unsigned long start_line;
+	unsigned long end_line;
 	cairo_t *context;
 	cairo_surface_t *surface;
     } *contexts;
@@ -121,12 +125,19 @@ struct slave {
     int fd;
     unsigned long image_serial;
     unsigned long image_ready;
+    unsigned long start_line;
+    unsigned long end_line;
     cairo_surface_t *image;
+    cairo_surface_t *difference;
+    buffer_diff_result_t result;
     const cairo_boilerplate_target_t *target;
+    const struct slave *reference;
 };
 
 struct request_image {
     unsigned long id;
+    unsigned long start_line;
+    unsigned long end_line;
     cairo_format_t format;
     int width;
     int height;
@@ -212,11 +223,16 @@ format_for_content (cairo_content_t content)
 
 static void *
 request_image (test_runner_thread_t *thread,
-	       unsigned long id,
+	       struct context_closure *closure,
 	       cairo_format_t format,
 	       int width, int height, int stride)
 {
-    struct request_image rq = { id, format, width, height, stride };
+    const struct request_image rq = {
+	closure->id,
+	closure->start_line,
+	closure->end_line,
+	format, width, height, stride
+    };
     size_t offset = -1;
 
     writen (thread->sk, &rq, sizeof (rq));
@@ -229,9 +245,9 @@ request_image (test_runner_thread_t *thread,
 
 static void
 push_surface (test_runner_thread_t *thread,
-	      cairo_surface_t *source,
-	      unsigned long id)
+	      struct context_closure *closure)
 {
+    cairo_surface_t *source = closure->surface;
     cairo_surface_t *image;
     cairo_format_t format = (cairo_format_t) -1;
     cairo_t *cr;
@@ -271,7 +287,7 @@ push_surface (test_runner_thread_t *thread,
 
     stride = cairo_format_stride_for_width (format, width);
 
-    data = request_image (thread, id, format, width, height, stride);
+    data = request_image (thread, closure, format, width, height, stride);
     if (data == NULL)
 	exit (-1);
 
@@ -288,12 +304,12 @@ push_surface (test_runner_thread_t *thread,
     cairo_destroy (cr);
 
     /* signal completion */
-    writen (thread->sk, &id, sizeof (id));
+    writen (thread->sk, &closure->id, sizeof (closure->id));
 
     /* wait for image check */
     serial = 0;
     readn (thread->sk, &serial, sizeof (serial));
-    if (serial != id)
+    if (serial != closure->id)
 	exit (-1);
 }
 
@@ -324,10 +340,12 @@ static cairo_t *
 _context_create (void *closure, cairo_surface_t *surface)
 {
     test_runner_thread_t *thread = closure;
-    struct context_list *l;
+    struct context_closure *l;
 
     l = xmalloc (sizeof (*l));
     l->next = thread->contexts;
+    l->start_line = cairo_script_interpreter_get_line_number (thread->csi);
+    l->end_line = l->start_line;
     l->context = cairo_create (surface);
     l->surface = cairo_surface_reference (surface);
     l->id = ++thread->context_id;
@@ -342,17 +360,19 @@ static void
 _context_destroy (void *closure, void *ptr)
 {
     test_runner_thread_t *thread = closure;
-    struct context_list *l, **prev = &thread->contexts;
+    struct context_closure *l, **prev = &thread->contexts;
 
     while ((l = *prev) != NULL) {
 	if (l->context == ptr) {
+	    l->end_line =
+		cairo_script_interpreter_get_line_number (thread->csi);
 	    if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) {
-		push_surface (thread, l->surface, l->id);
+		push_surface (thread, l);
             } else {
-		fprintf (stderr, "%s: error during replay: %s!\n",
+		fprintf (stderr, "%s: error during replay, line %lu: %s!\n",
 			 thread->target->name,
-			 cairo_status_to_string (cairo_surface_status
-						 (l->surface)));
+			 l->end_line,
+			 cairo_status_to_string (cairo_surface_status (l->surface)));
 		exit (1);
 	    }
 
@@ -375,15 +395,14 @@ execute (test_runner_thread_t    *thread,
 	.context_create = _context_create,
 	.context_destroy = _context_destroy,
     };
-    cairo_script_interpreter_t *csi;
 
-    csi = cairo_script_interpreter_create ();
-    cairo_script_interpreter_install_hooks (csi, &hooks);
+    thread->csi = cairo_script_interpreter_create ();
+    cairo_script_interpreter_install_hooks (thread->csi, &hooks);
 
-    cairo_script_interpreter_run (csi, trace);
+    cairo_script_interpreter_run (thread->csi, trace);
 
-    cairo_script_interpreter_finish (csi);
-    if (cairo_script_interpreter_destroy (csi))
+    cairo_script_interpreter_finish (thread->csi);
+    if (cairo_script_interpreter_destroy (thread->csi))
 	exit (1);
 }
 
@@ -463,7 +482,7 @@ spawn_target (const char *socket_path,
     thread.context_id = 0;
 
     thread.surface = target->create_surface (NULL,
-					     CAIRO_CONTENT_COLOR_ALPHA,
+					     target->content,
 					     1, 1,
 					     1, 1,
 					     CAIRO_BOILERPLATE_MODE_TEST,
@@ -491,10 +510,12 @@ spawn_target (const char *socket_path,
 
 /* XXX imagediff - is the extra expense worth it? */
 static cairo_bool_t
-matching_images (cairo_surface_t *a, cairo_surface_t *b)
+matches_reference (struct slave *slave)
 {
-    if (a == NULL || b == NULL)
-	return FALSE;
+    cairo_surface_t *a, *b;
+
+    a = slave->image;
+    b = slave->reference->image;
 
     if (cairo_surface_status (a) || cairo_surface_status (b))
 	return FALSE;
@@ -514,10 +535,46 @@ matching_images (cairo_surface_t *a, cairo_surface_t *b)
     if (cairo_image_surface_get_stride (a) != cairo_image_surface_get_stride (b))
 	return FALSE;
 
-    return memcmp (cairo_image_surface_get_data (a),
-		   cairo_image_surface_get_data (b),
-		   cairo_image_surface_get_stride (a) *
-		   cairo_image_surface_get_stride (b));
+    if (FALSE && cairo_surface_get_content (a) & CAIRO_CONTENT_COLOR) {
+	cairo_surface_t *diff;
+	int width, height, stride, size;
+	unsigned char *data;
+	cairo_status_t status;
+
+	width = cairo_image_surface_get_width (a);
+	height = cairo_image_surface_get_height (a);
+	stride = cairo_image_surface_get_stride (a);
+	size = height * stride * 4;
+	data = malloc (size);
+	if (data == NULL)
+	    return FALSE;
+
+	diff = cairo_image_surface_create_for_data (data,
+						    cairo_image_surface_get_format (a),
+						    width, height, stride);
+	cairo_surface_set_user_data (diff, (cairo_user_data_key_t *) diff,
+				     data, free);
+
+	status = image_diff (NULL, a, b, diff, &slave->result);
+	if (status) {
+	    cairo_surface_destroy (diff);
+	    return FALSE;
+	}
+
+	if (slave->result.pixels_changed &&
+	    slave->result.max_diff > slave->target->error_tolerance) {
+	    slave->difference = diff;
+	    return FALSE;
+	} else {
+	    cairo_surface_destroy (diff);
+	    return TRUE;
+	}
+    } else {
+	return memcmp (cairo_image_surface_get_data (a),
+		       cairo_image_surface_get_data (b),
+		       cairo_image_surface_get_stride (a) *
+		       cairo_image_surface_get_stride (b));
+    }
 }
 
 static cairo_bool_t
@@ -528,7 +585,10 @@ check_images (struct slave *slaves, int num_slaves)
     for (n = 1; n < num_slaves; n++) {
 	assert (slaves[n].image_ready == slaves[0].image_ready);
 
-	if (! matching_images (slaves[n].image, slaves[0].image))
+	if (slaves[n].reference == NULL)
+	    continue;
+
+	if (! matches_reference (&slaves[n]))
 	    return FALSE;
     }
 
@@ -546,6 +606,13 @@ write_images (const char *trace, struct slave *slave, int num_slaves)
 		       trace, slave->target->name);
 	    cairo_surface_write_to_png (slave->image, filename);
 	    free (filename);
+
+	    if (slave->difference) {
+		xasprintf (&filename, "%s-%s-diff.png",
+			   trace, slave->target->name);
+		cairo_surface_write_to_png (slave->difference, filename);
+		free (filename);
+	    }
 	}
 
 	slave++;
@@ -561,6 +628,8 @@ allocate_image_for_slave (uint8_t *base, size_t offset, struct slave *slave)
 
     readn (slave->fd, &rq, sizeof (rq));
     slave->image_serial = rq.id;
+    slave->start_line = rq.start_line;
+    slave->end_line = rq.end_line;
 
     size = rq.height * rq.stride;
     size = (size + 127) & -128;
@@ -576,12 +645,19 @@ allocate_image_for_slave (uint8_t *base, size_t offset, struct slave *slave)
     return offset;
 }
 
+struct error_info {
+    unsigned long context_id;
+    unsigned long start_line;
+    unsigned long end_line;
+};
+
 static cairo_bool_t
 test_run (void *base,
 	  int sk,
 	  const char *trace,
 	  struct slave *slaves,
-	  int num_slaves)
+	  int num_slaves,
+	  struct error_info *error)
 {
     struct pollfd *pfd;
     int npfd, cnt, n, i;
@@ -672,6 +748,10 @@ test_run (void *base,
 
 	if (completion == num_slaves) {
 	    if (! check_images (slaves, num_slaves)) {
+		error->context_id = slaves[0].image_serial;
+		error->start_line = slaves[0].start_line;
+		error->end_line = slaves[0].end_line;
+
 		write_images (trace, slaves, num_slaves);
 		goto out;
 	    }
@@ -710,6 +790,9 @@ out:
 	cairo_surface_destroy (slaves[n].image);
 	slaves[n].image = NULL;
 
+	cairo_surface_destroy (slaves[n].difference);
+	slaves[n].difference = NULL;
+
 	slaves[n].image_serial = 0;
 	slaves[n].image_ready = 0;
 	ret = FALSE;
@@ -744,16 +827,17 @@ target_is_measurable (const cairo_boilerplate_target_t *target)
     case CAIRO_SURFACE_TYPE_XCB:
     case CAIRO_SURFACE_TYPE_GLITZ:
     case CAIRO_SURFACE_TYPE_QUARTZ:
+    case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE:
     case CAIRO_SURFACE_TYPE_WIN32:
     case CAIRO_SURFACE_TYPE_BEOS:
     case CAIRO_SURFACE_TYPE_DIRECTFB:
-#if CAIRO_VERSION > CAIRO_VERSION_ENCODE(1,1,2)
     case CAIRO_SURFACE_TYPE_OS2:
-#endif
+    case CAIRO_SURFACE_TYPE_QT:
 	return TRUE;
 
     case CAIRO_SURFACE_TYPE_PDF:
     case CAIRO_SURFACE_TYPE_PS:
+    case CAIRO_SURFACE_TYPE_SCRIPT:
     case CAIRO_SURFACE_TYPE_SVG:
     case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
     default:
@@ -814,7 +898,10 @@ server_shm (const char *shm_path)
 }
 
 static cairo_bool_t
-_test_trace (test_runner_t *test, const char *trace, const char *name)
+_test_trace (test_runner_t *test,
+	     const char *trace,
+	     const char *name,
+	     struct error_info *error)
 {
     const char *shm_path = SHM_PATH_XXX;
     const cairo_boilerplate_target_t *target, *image;
@@ -851,21 +938,51 @@ _test_trace (test_runner_t *test, const char *trace, const char *name)
     assert (image != NULL);
 
     /* spawn slave processes to run the trace */
-    s = slaves = xcalloc (test->num_targets + 1, sizeof (struct slave));
+    s = slaves = xcalloc (2*test->num_targets + 1, sizeof (struct slave));
     s->pid = spawn_target (socket_path, shm_path, image, trace);
     if (s->pid < 0)
 	goto cleanup;
     s->target = image;
+    s->reference = NULL;
     s->fd = -1;
     s++;
 
     for (i = 0; i < test->num_targets; i++) {
 	pid_t slave;
+	const cairo_boilerplate_target_t *reference;
+	struct slave *master;
 
 	target = test->targets[i];
 	if (target == image || ! target_is_measurable (target))
 	    continue;
 
+	/* find a matching slave to use as a reference for this target */
+	if (target->reference_target != NULL) {
+	    reference =
+		cairo_boilerplate_get_target_by_name (target->reference_target,
+						      target->content);
+	    assert (reference != NULL);
+	} else {
+	    reference = image;
+	}
+	for (master = slaves; master < s; master++) {
+	    if (master->target == reference)
+		break;
+	}
+
+	if (master == s) {
+	    /* no match found, spawn a slave to render the reference image */
+	    slave = spawn_target (socket_path, shm_path, reference, trace);
+	    if (slave < 0)
+		continue;
+
+	    s->pid = slave;
+	    s->target = reference;
+	    s->fd = -1;
+	    s->reference = NULL;
+	    s++;
+	}
+
 	slave = spawn_target (socket_path, shm_path, target, trace);
 	if (slave < 0)
 	    continue;
@@ -873,6 +990,7 @@ _test_trace (test_runner_t *test, const char *trace, const char *name)
 	s->pid = slave;
 	s->target = target;
 	s->fd = -1;
+	s->reference = master;
 	s++;
     }
     num_slaves = s - slaves;
@@ -886,7 +1004,7 @@ _test_trace (test_runner_t *test, const char *trace, const char *name)
 	fprintf (stderr, "Unable to mmap shared memory\n");
 	goto cleanup;
     }
-    ret = test_run (base, sk, name, slaves, num_slaves);
+    ret = test_run (base, sk, name, slaves, num_slaves, error);
     munmap (base, DATA_SIZE);
 
 cleanup:
@@ -927,13 +1045,25 @@ test_trace (test_runner_t *test, const char *trace)
     if (test->list_only) {
 	printf ("%s\n", name);
     } else {
+	struct error_info error = {0};
 	cairo_bool_t ret;
 
 	printf ("%s: ", name);
 	fflush (stdout);
 
-	ret = _test_trace (test, trace, name);
-	printf ("%s\n", ret ? "PASS" : "FAIL");
+	ret = _test_trace (test, trace, name, &error);
+	if (ret) {
+	    printf ("PASS\n");
+	} else {
+	    if (error.context_id) {
+		printf ("FAIL (context %lu, lines [%lu, %lu])\n",
+			error.context_id,
+			error.start_line,
+			error.end_line);
+	    } else {
+		printf ("FAIL\n");
+	    }
+	}
     }
 
     free (trace_cpy);
@@ -1258,3 +1388,24 @@ main (int argc, char *argv[])
 
     return 0;
 }
+
+void
+cairo_test_logv (const cairo_test_context_t *ctx,
+		 const char *fmt, va_list va)
+{
+#if 0
+    vfprintf (stderr, fmt, va);
+#endif
+}
+
+void
+cairo_test_log (const cairo_test_context_t *ctx, const char *fmt, ...)
+{
+#if 0
+    va_list va;
+
+    va_start (va, fmt);
+    vfprintf (stderr, fmt, va);
+    va_end (va);
+#endif
+}
commit cec8579348fb39ca879285bebfb1ee65cbae502d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jun 19 16:09:26 2009 +0100

    [xlib] Remove redundant code to query a xrender_format from a visual
    
    We always query an xrender_format for a Visual upon surface creation, so
    checking again in create_similar() is redundant. (It also interferes with
    disabling XRender...)

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index b68e6ed..99da0d5 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -210,7 +210,7 @@ _cairo_xlib_surface_create_similar (void	       *abstract_src,
 				    int			height)
 {
     cairo_xlib_surface_t *src = abstract_src;
-    XRenderPictFormat *xrender_format = src->xrender_format;
+    XRenderPictFormat *xrender_format;
     cairo_xlib_surface_t *surface;
     Pixmap pix;
 
@@ -219,17 +219,12 @@ _cairo_xlib_surface_create_similar (void	       *abstract_src,
 
     _cairo_xlib_display_notify (src->display);
 
-    /* Start by examining the surface's XRenderFormat, or if it
-     * doesn't have one, then look one up through its visual (in the
-     * case of a bitmap, it won't even have that). */
-    if (xrender_format == NULL && src->visual != NULL)
-        xrender_format = XRenderFindVisualFormat (src->dpy, src->visual);
-
     /* If we never found an XRenderFormat or if it isn't compatible
      * with the content being requested, then we fallback to just
      * constructing a cairo_format_t instead, (which will fairly
      * arbitrarily pick a visual/depth for the similar surface.
      */
+    xrender_format = src->xrender_format;
     if (xrender_format == NULL ||
 	_xrender_format_to_content (xrender_format) != content)
     {
commit dd842a2bed1568000c9727fc35d4683db349e506
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jun 19 14:59:59 2009 +0100

    [boilerplate] Missing static on pdf user data key.

diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c
index 7e5e162..c3289f8 100644
--- a/boilerplate/cairo-boilerplate-pdf.c
+++ b/boilerplate/cairo-boilerplate-pdf.c
@@ -36,7 +36,7 @@
 #include <signal.h>
 #endif
 
-cairo_user_data_key_t pdf_closure_key;
+static const cairo_user_data_key_t pdf_closure_key;
 
 typedef struct _pdf_target_closure
 {


More information about the cairo-commit mailing list