[cairo-commit] 3 commits - boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate.h boilerplate/cairo-boilerplate-pdf.c boilerplate/cairo-boilerplate-pdf-private.h boilerplate/cairo-boilerplate-ps.c boilerplate/cairo-boilerplate-ps-private.h boilerplate/cairo-boilerplate-svg.c boilerplate/cairo-boilerplate-svg-private.h boilerplate/cairo-boilerplate-win32-printing.c boilerplate/xmalloc.c boilerplate/xmalloc.h configure.in src/cairo-png.c src/cairo-ps-surface.c src/cairo-ps-surface-private.h test/buffer-diff.c test/buffer-diff.h test/cairo-test.c test/.gitignore test/imagediff.c test/Makefile.am test/README

Chris Wilson ickle at kemper.freedesktop.org
Wed Aug 20 15:59:43 PDT 2008


 boilerplate/cairo-boilerplate-pdf-private.h    |    7 
 boilerplate/cairo-boilerplate-pdf.c            |   18 -
 boilerplate/cairo-boilerplate-ps-private.h     |    3 
 boilerplate/cairo-boilerplate-ps.c             |   35 ++
 boilerplate/cairo-boilerplate-svg-private.h    |    7 
 boilerplate/cairo-boilerplate-svg.c            |   17 -
 boilerplate/cairo-boilerplate-win32-printing.c |    2 
 boilerplate/cairo-boilerplate.c                |  105 +++++---
 boilerplate/cairo-boilerplate.h                |    5 
 boilerplate/xmalloc.c                          |   14 +
 boilerplate/xmalloc.h                          |    4 
 configure.in                                   |    2 
 src/cairo-png.c                                |    9 
 src/cairo-ps-surface-private.h                 |    2 
 src/cairo-ps-surface.c                         |   10 
 test/.gitignore                                |    7 
 test/Makefile.am                               |   10 
 test/README                                    |    6 
 test/buffer-diff.c                             |  295 -------------------------
 test/buffer-diff.h                             |   36 ---
 test/cairo-test.c                              |  186 +++++++++++++--
 test/imagediff.c                               |  217 ++++++++++++++++++
 22 files changed, 561 insertions(+), 436 deletions(-)

New commits:
commit b9287e6669fde571a9f0cb57462cb3815fbd8d27
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Aug 20 19:44:30 2008 +0100

    [test] Cache last output and compare next time.
    
    Compare the current output against a previous run to determine if there
    has been any change since last time, and only run through imagediff if
    there has been. For the vector surfaces, we can check the vector output
    first and potentially skip the rasterisation. On my machine this reduces
    the time for a second run from 6 minutes to 2m30s. As most of the time,
    most test output will remain unchanged, so this seems to be a big win. On
    unix systems, hard linking is used to reduce the amount of storage space
    required - others will see about a three-fold increase in the amount of
    disk used.  The directory continues to be a stress test for file selectors.
    
    In order to reduce the changes between runs, the current time is no longer
    written to the PNG files (justified by that it only exists as a debugging
    aid) and the boilerplate tweaks the PS surface so that the creation date
    is fixed. To fully realise the benefits here, we need to strip the
    creation time from all the reference images...
    
    The biggest problem with using the caches is that different runs of the
    test suite can go through different code paths, introducing potential
    Heisenbergs. If you suspect that caching is interfering with the test
    results, use 'make -C test clean-caches check'.

diff --git a/boilerplate/cairo-boilerplate-pdf-private.h b/boilerplate/cairo-boilerplate-pdf-private.h
index 69f8da3..981fa8d 100644
--- a/boilerplate/cairo-boilerplate-pdf-private.h
+++ b/boilerplate/cairo-boilerplate-pdf-private.h
@@ -38,8 +38,8 @@ _cairo_boilerplate_pdf_create_surface (const char		 *name,
 				       int                        id,
 				       void			**closure);
 
-void
-_cairo_boilerplate_pdf_cleanup (void *closure);
+cairo_status_t
+_cairo_boilerplate_pdf_finish_surface (cairo_surface_t		*surface);
 
 cairo_status_t
 _cairo_boilerplate_pdf_surface_write_to_png (cairo_surface_t *surface, const char *filename);
@@ -49,4 +49,7 @@ _cairo_boilerplate_pdf_get_image_surface (cairo_surface_t *surface,
 					  int width,
 					  int height);
 
+void
+_cairo_boilerplate_pdf_cleanup (void *closure);
+
 #endif
diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c
index b0d9571..fb7d1aa 100644
--- a/boilerplate/cairo-boilerplate-pdf.c
+++ b/boilerplate/cairo-boilerplate-pdf.c
@@ -74,6 +74,7 @@ _cairo_boilerplate_pdf_create_surface (const char		 *name,
     ptc->height = height;
 
     xasprintf (&ptc->filename, "%s-out.pdf", name);
+    xunlink (ptc->filename);
 
     surface = cairo_pdf_surface_create (ptc->filename, width, height);
     if (cairo_surface_status (surface))
@@ -107,10 +108,11 @@ _cairo_boilerplate_pdf_create_surface (const char		 *name,
     return surface;
 }
 
-static cairo_status_t
-_cairo_boilerplate_pdf_finish (pdf_target_closure_t	*ptc,
-			       cairo_surface_t		*surface)
+cairo_status_t
+_cairo_boilerplate_pdf_finish_surface (cairo_surface_t		*surface)
 {
+    pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface,
+							     &pdf_closure_key);
     cairo_status_t status;
 
     /* Both surface and ptc->target were originally created at the
@@ -155,13 +157,8 @@ _cairo_boilerplate_pdf_surface_write_to_png (cairo_surface_t *surface, const cha
 {
     pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, &pdf_closure_key);
     char    command[4096];
-    cairo_status_t status;
     int exitstatus;
 
-    status = _cairo_boilerplate_pdf_finish (ptc, surface);
-    if (status)
-	return status;
-
     sprintf (command, "./pdf2png %s %s 1",
 	     ptc->filename, filename);
 
@@ -181,14 +178,9 @@ _cairo_boilerplate_pdf_convert_to_image (cairo_surface_t *surface)
 {
     pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface,
 							     &pdf_closure_key);
-    cairo_status_t status;
     FILE *file;
     cairo_surface_t *image;
 
-    status = _cairo_boilerplate_pdf_finish (ptc, surface);
-    if (status)
-	return cairo_boilerplate_surface_create_in_error (status);
-
     file = cairo_boilerplate_open_any2ppm (ptc->filename, 1);
     if (file == NULL)
 	return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
diff --git a/boilerplate/cairo-boilerplate-ps-private.h b/boilerplate/cairo-boilerplate-ps-private.h
index 7cd15bf..6f1bad6 100644
--- a/boilerplate/cairo-boilerplate-ps-private.h
+++ b/boilerplate/cairo-boilerplate-ps-private.h
@@ -42,6 +42,9 @@ void
 _cairo_boilerplate_ps_cleanup (void *closure);
 
 cairo_status_t
+_cairo_boilerplate_ps_finish_surface (cairo_surface_t		*surface);
+
+cairo_status_t
 _cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface, const char *filename);
 
 cairo_surface_t *
diff --git a/boilerplate/cairo-boilerplate-ps.c b/boilerplate/cairo-boilerplate-ps.c
index f1bd6e2..6df9776 100644
--- a/boilerplate/cairo-boilerplate-ps.c
+++ b/boilerplate/cairo-boilerplate-ps.c
@@ -47,6 +47,24 @@ typedef struct _ps_target_closure
     cairo_surface_t	*target;
 } ps_target_closure_t;
 
+static cairo_status_t
+_cairo_boilerplate_ps_surface_set_creation_date (cairo_surface_t *abstract_surface,
+						 time_t date)
+{
+    cairo_paginated_surface_t *paginated = (cairo_paginated_surface_t*) abstract_surface;
+    cairo_ps_surface_t *surface;
+
+    if (cairo_surface_get_type (abstract_surface) != CAIRO_SURFACE_TYPE_PS)
+	return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+
+    surface = (cairo_ps_surface_t*) paginated->target;
+
+    surface->has_creation_date = TRUE;
+    surface->creation_date = date;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 cairo_surface_t *
 _cairo_boilerplate_ps_create_surface (const char		 *name,
 				      cairo_content_t		  content,
@@ -69,6 +87,7 @@ _cairo_boilerplate_ps_create_surface (const char		 *name,
     *closure = ptc = xmalloc (sizeof (ps_target_closure_t));
 
     xasprintf (&ptc->filename, "%s-out.ps", name);
+    xunlink (ptc->filename);
 
     ptc->width = width;
     ptc->height = height;
@@ -77,6 +96,7 @@ _cairo_boilerplate_ps_create_surface (const char		 *name,
     if (cairo_surface_status (surface))
 	goto CLEANUP_FILENAME;
 
+    _cairo_boilerplate_ps_surface_set_creation_date (surface, 0);
     cairo_surface_set_fallback_resolution (surface, 72., 72.);
 
     if (content == CAIRO_CONTENT_COLOR) {
@@ -106,13 +126,11 @@ _cairo_boilerplate_ps_create_surface (const char		 *name,
 }
 
 cairo_status_t
-_cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface, const char *filename)
+_cairo_boilerplate_ps_finish_surface (cairo_surface_t		*surface)
 {
     ps_target_closure_t *ptc = cairo_surface_get_user_data (surface,
 							    &ps_closure_key);
-    char    command[4096];
     cairo_status_t status;
-    int exitstatus;
 
     /* Both surface and ptc->target were originally created at the
      * same dimensions. We want a 1:1 copy here, so we first clear any
@@ -148,6 +166,17 @@ _cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface, const char
     if (status)
 	return status;
 
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface, const char *filename)
+{
+    ps_target_closure_t *ptc = cairo_surface_get_user_data (surface,
+							    &ps_closure_key);
+    char    command[4096];
+    int exitstatus;
+
     sprintf (command, "gs -q -r72 -g%dx%d -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=%s %s",
 	     ptc->width, ptc->height, filename, ptc->filename);
     exitstatus = system (command);
diff --git a/boilerplate/cairo-boilerplate-svg-private.h b/boilerplate/cairo-boilerplate-svg-private.h
index 3f2856d..ea42948 100644
--- a/boilerplate/cairo-boilerplate-svg-private.h
+++ b/boilerplate/cairo-boilerplate-svg-private.h
@@ -38,8 +38,8 @@ _cairo_boilerplate_svg_create_surface (const char		 *name,
 				       int                        id,
 				       void			**closure);
 
-void
-_cairo_boilerplate_svg_cleanup (void *closure);
+cairo_status_t
+_cairo_boilerplate_svg_finish_surface (cairo_surface_t		*surface);
 
 cairo_status_t
 _cairo_boilerplate_svg_surface_write_to_png (cairo_surface_t *surface, const char *filename);
@@ -49,4 +49,7 @@ _cairo_boilerplate_svg_get_image_surface (cairo_surface_t *surface,
 					  int width,
 					  int height);
 
+void
+_cairo_boilerplate_svg_cleanup (void *closure);
+
 #endif
diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c
index 80354ef..7a07d1b 100644
--- a/boilerplate/cairo-boilerplate-svg.c
+++ b/boilerplate/cairo-boilerplate-svg.c
@@ -67,6 +67,7 @@ _cairo_boilerplate_svg_create_surface (const char		 *name,
     ptc->height = height;
 
     xasprintf (&ptc->filename, "%s-out.svg", name);
+    xunlink (ptc->filename);
 
     surface = cairo_svg_surface_create (ptc->filename, width, height);
     if (cairo_surface_status (surface))
@@ -100,10 +101,10 @@ _cairo_boilerplate_svg_create_surface (const char		 *name,
     return surface;
 }
 
-static cairo_status_t
-_cairo_boilerplate_svg_finish (svg_target_closure_t	*ptc,
-			       cairo_surface_t		*surface)
+cairo_status_t
+_cairo_boilerplate_svg_finish_surface (cairo_surface_t		*surface)
 {
+    svg_target_closure_t *ptc = cairo_surface_get_user_data (surface, &svg_closure_key);
     cairo_status_t status;
 
     /* Both surface and ptc->target were originally created at the
@@ -148,13 +149,8 @@ _cairo_boilerplate_svg_surface_write_to_png (cairo_surface_t *surface, const cha
 {
     svg_target_closure_t *ptc = cairo_surface_get_user_data (surface, &svg_closure_key);
     char    command[4096];
-    cairo_status_t status;
     int exitstatus;
 
-    status = _cairo_boilerplate_svg_finish (ptc, surface);
-    if (status)
-	return status;
-
     sprintf (command, "./svg2png %s %s",
 	     ptc->filename, filename);
 
@@ -174,14 +170,9 @@ _cairo_boilerplate_svg_convert_to_image (cairo_surface_t *surface)
 {
     svg_target_closure_t *ptc = cairo_surface_get_user_data (surface,
 							     &svg_closure_key);
-    cairo_status_t status;
     FILE *file;
     cairo_surface_t *image;
 
-    status = _cairo_boilerplate_svg_finish (ptc, surface);
-    if (status)
-	return cairo_boilerplate_surface_create_in_error (status);
-
     file = cairo_boilerplate_open_any2ppm (ptc->filename, 0);
     if (file == NULL)
 	return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
diff --git a/boilerplate/cairo-boilerplate-win32-printing.c b/boilerplate/cairo-boilerplate-win32-printing.c
index 691552d..faddb6a 100644
--- a/boilerplate/cairo-boilerplate-win32-printing.c
+++ b/boilerplate/cairo-boilerplate-win32-printing.c
@@ -182,6 +182,8 @@ _cairo_boilerplate_win32_printing_create_surface (const char              *name,
     *closure = ptc = xmalloc (sizeof (win32_target_closure_t));
 
     xasprintf (&ptc->filename, "%s-out.ps", name);
+    xunlink (ptc->filename);
+
     memset (&di, 0, sizeof (DOCINFO));
     di.cbSize = sizeof (DOCINFO);
     di.lpszDocName = ptc->filename;
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 20cf0c9..0a86107 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -258,120 +258,140 @@ static cairo_boilerplate_target_t targets[] =
     /* I'm uncompromising about leaving the image backend as 0
      * for tolerance. There shouldn't ever be anything that is out of
      * our control here. */
-    { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA, 0,
+    { "image", NULL, CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_image_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png },
-    { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0,
+    { "image", NULL, CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_image_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png },
 #ifdef CAIRO_HAS_TEST_SURFACES
-    { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+    { "test-fallback", NULL, CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
       CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_test_fallback_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png },
-    { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+    { "test-fallback", NULL, CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
       CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_test_fallback_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png },
-    { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+    { "test-meta", NULL, CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
       CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_test_meta_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png },
-    { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+    { "test-meta", NULL, CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
       CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_test_meta_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png },
-    { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+    { "test-paginated", NULL, CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
       CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_test_paginated_create_surface,
+      NULL,
       _cairo_boilerplate_test_paginated_get_image_surface,
       _cairo_boilerplate_test_paginated_surface_write_to_png,
       _cairo_boilerplate_test_paginated_cleanup },
-    { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+    { "test-paginated", NULL, CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
       CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_test_paginated_create_surface,
+      NULL,
       _cairo_boilerplate_test_paginated_get_image_surface,
       _cairo_boilerplate_test_paginated_surface_write_to_png,
       _cairo_boilerplate_test_paginated_cleanup },
 #endif
 #ifdef CAIRO_HAS_GLITZ_SURFACE
 #if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
-    { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ,CAIRO_CONTENT_COLOR_ALPHA, 0,
+    { "glitz-glx", NULL, CAIRO_SURFACE_TYPE_GLITZ,CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_glitz_glx_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_glitz_glx_cleanup },
-    { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
+    { "glitz-glx", NULL, CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_glitz_glx_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_glitz_glx_cleanup },
 #endif
 #if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
-    { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
+    { "glitz-agl", NULL, CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_glitz_agl_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_glitz_agl_cleanup },
-    { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
+    { "glitz-agl", NULL, CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_glitz_agl_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_glitz_agl_cleanup },
 #endif
 #if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE
-    { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
+    { "glitz-wgl", NULL, CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_glitz_wgl_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_glitz_wgl_cleanup },
-    { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
+    { "glitz-wgl", NULL, CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_glitz_wgl_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_glitz_wgl_cleanup },
 #endif
 #endif /* CAIRO_HAS_GLITZ_SURFACE */
 #if CAIRO_HAS_QUARTZ_SURFACE
-    { "quartz", CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
+    { "quartz", NULL, CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_quartz_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_quartz_cleanup },
-    { "quartz", CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR, 0,
+    { "quartz", NULL, CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_quartz_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_quartz_cleanup },
 #endif
 #if CAIRO_HAS_WIN32_SURFACE
-    { "win32", CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR, 0,
+    { "win32", NULL, CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_win32_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png },
     /* Testing the win32 surface isn't interesting, since for
      * ARGB images it just chains to the image backend
      */
-    { "win32", CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR_ALPHA, 0,
+    { "win32", NULL, CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_win32_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png },
 #if CAIRO_CAN_TEST_WIN32_PRINTING_SURFACE
-    { "win32-printing", CAIRO_SURFACE_TYPE_WIN32_PRINTING,
+    { "win32-printing", ".ps", CAIRO_SURFACE_TYPE_WIN32_PRINTING,
       CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
       _cairo_boilerplate_win32_printing_create_surface,
+      NULL,
       _cairo_boilerplate_win32_printing_get_image_surface,
       _cairo_boilerplate_win32_printing_surface_write_to_png,
       _cairo_boilerplate_win32_printing_cleanup,
       NULL, TRUE },
-    { "win32-printing", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
+    { "win32-printing", ".ps", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_win32_printing_create_surface,
+      NULL,
       _cairo_boilerplate_win32_printing_get_image_surface,
       _cairo_boilerplate_win32_printing_surface_write_to_png,
       _cairo_boilerplate_win32_printing_cleanup,
@@ -381,8 +401,9 @@ static cairo_boilerplate_target_t targets[] =
 #if CAIRO_HAS_XCB_SURFACE
     /* Acceleration architectures may make the results differ by a
      * bit, so we set the error tolerance to 1. */
-    { "xcb", CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
+    { "xcb", NULL, CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
       _cairo_boilerplate_xcb_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_xcb_cleanup,
@@ -391,14 +412,16 @@ static cairo_boilerplate_target_t targets[] =
 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
     /* Acceleration architectures may make the results differ by a
      * bit, so we set the error tolerance to 1. */
-    { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA, 1,
+    { "xlib", NULL, CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA, 1,
       _cairo_boilerplate_xlib_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_xlib_cleanup,
       _cairo_boilerplate_xlib_synchronize},
-    { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
+    { "xlib", NULL, CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
       _cairo_boilerplate_xlib_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_xlib_cleanup,
@@ -407,38 +430,43 @@ static cairo_boilerplate_target_t targets[] =
 #if CAIRO_HAS_XLIB_SURFACE
     /* This is a fallback surface which uses xlib fallbacks instead of
      * the Render extension. */
-    { "xlib-fallback", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
+    { "xlib-fallback", NULL, CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
       _cairo_boilerplate_xlib_fallback_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_xlib_cleanup,
       _cairo_boilerplate_xlib_synchronize},
 #endif
 #if CAIRO_HAS_PS_SURFACE && CAIRO_CAN_TEST_PS_SURFACE
-    { "ps", CAIRO_SURFACE_TYPE_PS,
+    { "ps", ".ps", CAIRO_SURFACE_TYPE_PS,
       CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
       _cairo_boilerplate_ps_create_surface,
+      _cairo_boilerplate_ps_finish_surface,
       _cairo_boilerplate_ps_get_image_surface,
       _cairo_boilerplate_ps_surface_write_to_png,
       _cairo_boilerplate_ps_cleanup,
       NULL, TRUE },
-    { "ps", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
+    { "ps", ".ps", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_ps_create_surface,
+      _cairo_boilerplate_ps_finish_surface,
       _cairo_boilerplate_ps_get_image_surface,
       _cairo_boilerplate_ps_surface_write_to_png,
       _cairo_boilerplate_ps_cleanup,
       NULL, TRUE },
 #endif
 #if CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE
-    { "pdf", CAIRO_SURFACE_TYPE_PDF,
+    { "pdf", ".pdf", CAIRO_SURFACE_TYPE_PDF,
       CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
       _cairo_boilerplate_pdf_create_surface,
+      _cairo_boilerplate_pdf_finish_surface,
       _cairo_boilerplate_pdf_get_image_surface,
       _cairo_boilerplate_pdf_surface_write_to_png,
       _cairo_boilerplate_pdf_cleanup,
       NULL, TRUE },
-    { "pdf", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
+    { "pdf", ".pdf", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_pdf_create_surface,
+      _cairo_boilerplate_pdf_finish_surface,
       _cairo_boilerplate_pdf_get_image_surface,
       _cairo_boilerplate_pdf_surface_write_to_png,
       _cairo_boilerplate_pdf_cleanup,
@@ -450,14 +478,16 @@ static cairo_boilerplate_target_t targets[] =
      * systems get an error of 1 for some pixels on some of the text
      * tests. XXX: I'd still like to chase these down at some point.
      * For now just set the svg error tolerance to 1. */
-    { "svg", CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1,
+    { "svg", ".svg", CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1,
       _cairo_boilerplate_svg_create_surface,
+      _cairo_boilerplate_svg_finish_surface,
       _cairo_boilerplate_svg_get_image_surface,
       _cairo_boilerplate_svg_surface_write_to_png,
       _cairo_boilerplate_svg_cleanup,
       NULL, TRUE },
-    { "svg", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
+    { "svg", ".svg", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1,
       _cairo_boilerplate_svg_create_surface,
+      _cairo_boilerplate_svg_finish_surface,
       _cairo_boilerplate_svg_get_image_surface,
       _cairo_boilerplate_svg_surface_write_to_png,
       _cairo_boilerplate_svg_cleanup,
@@ -467,18 +497,21 @@ static cairo_boilerplate_target_t targets[] =
     /* BeOS sometimes produces a slightly different image. Perhaps this
      * is related to the fact that it doesn't use premultiplied alpha...
      * Just ignore the small difference. */
-    { "beos", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR, 1,
+    { "beos", NULL, CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR, 1,
       _cairo_boilerplate_beos_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_beos_cleanup},
-    { "beos-bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR, 1,
+    { "beos-bitmap", NULL, CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR, 1,
       _cairo_boilerplate_beos_create_surface_for_bitmap,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_beos_cleanup_bitmap},
-    { "beos-bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR_ALPHA, 1,
+    { "beos-bitmap", NULL, CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR_ALPHA, 1,
       _cairo_boilerplate_beos_create_surface_for_bitmap,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_beos_cleanup_bitmap},
@@ -486,13 +519,15 @@ static cairo_boilerplate_target_t targets[] =
 
 
 #if CAIRO_HAS_DIRECTFB_SURFACE
-    { "directfb", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR, 0,
+    { "directfb", NULL, CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_directfb_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_directfb_cleanup},
-    { "directfb-bitmap", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR_ALPHA, 0,
+    { "directfb-bitmap", NULL, CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR_ALPHA, 0,
       _cairo_boilerplate_directfb_create_surface,
+      NULL,
       _cairo_boilerplate_get_image_surface,
       cairo_surface_write_to_png,
       _cairo_boilerplate_directfb_cleanup},
diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h
index 844eed9..ba1c03b 100644
--- a/boilerplate/cairo-boilerplate.h
+++ b/boilerplate/cairo-boilerplate.h
@@ -121,6 +121,9 @@ typedef cairo_surface_t *
 				       int                        id,
 				       void			**closure);
 
+typedef cairo_status_t
+(*cairo_boilerplate_finish_surface_t) (cairo_surface_t *surface);
+
 typedef cairo_surface_t *
 (*cairo_boilerplate_get_image_surface_t) (cairo_surface_t *surface,
 					  int width,
@@ -139,10 +142,12 @@ typedef void
 typedef struct _cairo_boilerplate_target
 {
     const char					*name;
+    const char					*file_extension;
     cairo_surface_type_t			 expected_type;
     cairo_content_t				 content;
     unsigned int				 error_tolerance;
     cairo_boilerplate_create_surface_t		 create_surface;
+    cairo_boilerplate_finish_surface_t		 finish_surface;
     cairo_boilerplate_get_image_surface_t	 get_image_surface;
     cairo_boilerplate_write_to_png_t		 write_to_png;
     cairo_boilerplate_cleanup_t			 cleanup;
diff --git a/boilerplate/xmalloc.c b/boilerplate/xmalloc.c
index 0a8eeb2..5b91108 100644
--- a/boilerplate/xmalloc.c
+++ b/boilerplate/xmalloc.c
@@ -29,6 +29,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
 
 void *
 xmalloc (size_t size)
@@ -129,3 +133,13 @@ xasprintf (char **strp, const char *fmt, ...)
     memset (*strp + ret, 0, len-ret);
 #endif /* !HAVE_VASNPRINTF */
 }
+
+void
+xunlink (const char *pathname)
+{
+    if (unlink (pathname) < 0 && errno != ENOENT) {
+	CAIRO_BOILERPLATE_LOG ("Error: Cannot remove %s: %s\n",
+			       pathname, strerror (errno));
+	exit (1);
+    }
+}
diff --git a/boilerplate/xmalloc.h b/boilerplate/xmalloc.h
index f49a1be..51273a7 100644
--- a/boilerplate/xmalloc.h
+++ b/boilerplate/xmalloc.h
@@ -44,4 +44,8 @@ xrealloc (void *buf, size_t size);
 void
 xasprintf (char **strp, const char *fmt, ...) CAIRO_BOILERPLATE_PRINTF_FORMAT(2, 3);
 
+#define xunlink cairo_boilerplate_xunlink
+void
+xunlink (const char *path);
+
 #endif
diff --git a/configure.in b/configure.in
index 2e4ce97..9985787 100644
--- a/configure.in
+++ b/configure.in
@@ -120,7 +120,7 @@ dnl ===========================================================================
 AC_CHECK_LIBM
 LIBS="$LIBS $LIBM"
 
-AC_CHECK_FUNCS(vasnprintf ctime_r drand48 flockfile)
+AC_CHECK_FUNCS(vasnprintf link ctime_r drand48 flockfile)
 
 AC_MSG_CHECKING([for Sun Solaris (non-POSIX ctime_r)])
 case "$host" in
diff --git a/src/cairo-png.c b/src/cairo-png.c
index 1b7df9a..d807dac 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -137,7 +137,6 @@ write_png (cairo_surface_t	*surface,
     void *image_extra;
     png_struct *png;
     png_info *info;
-    png_time pt;
     png_byte **volatile rows = NULL;
     png_color_16 white;
     int png_color_type;
@@ -225,8 +224,12 @@ write_png (cairo_surface_t	*surface,
     white.red = white.blue = white.green = white.gray;
     png_set_bKGD (png, info, &white);
 
-    png_convert_from_time_t (&pt, time (NULL));
-    png_set_tIME (png, info, &pt);
+    if (0) { /* XXX extract meta-data from surface (i.e. creation date) */
+	png_time pt;
+
+	png_convert_from_time_t (&pt, time (NULL));
+	png_set_tIME (png, info, &pt);
+    }
 
     /* We have to call png_write_info() before setting up the write
      * transformation, since it stores data internally in 'png'
diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h
index 657e14b..95a5dc5 100644
--- a/src/cairo-ps-surface-private.h
+++ b/src/cairo-ps-surface-private.h
@@ -80,6 +80,8 @@ typedef struct cairo_ps_surface {
     cairo_paginated_mode_t paginated_mode;
 
     cairo_bool_t force_fallbacks;
+    cairo_bool_t has_creation_date;
+    time_t creation_date;
 
     cairo_scaled_font_subsets_t *font_subsets;
 
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index b20c5b1..f1ce1d1 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -90,7 +90,10 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
     int level;
     const char *eps_header = "";
 
-    now = time (NULL);
+    if (surface->has_creation_date)
+	now = surface->creation_date;
+    else
+	now = time (NULL);
 
     if (surface->ps_level_used == CAIRO_PS_LEVEL_2)
 	level = 2;
diff --git a/test/.gitignore b/test/.gitignore
index 8590d8f..2834165 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -222,10 +222,9 @@ xlib-surface
 xlib-surface-source
 zero-alpha
 valgrind-log
-*-out.pdf
-*-out.png
-*-out.ps
-*-out.svg
+*-out.*
+*-pass.*
+*-last.*
 *-diff.png
 *.manifest
 *.gcda
diff --git a/test/Makefile.am b/test/Makefile.am
index aa7a03b..8ee55c0 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -921,14 +921,14 @@ CLEANFILES =					\
 # most systems cannot handle all of our clean files together.
 # Then it became a fancy find using many GNU extensions, but then the ugly
 # reality of portability was raised and it became....
-clean-local:
-	-${FIND} . -name '*-out.ps'   -print | ${XARGS} ${RM}
-	-${FIND} . -name '*-out.pdf'  -print | ${XARGS} ${RM}
-	-${FIND} . -name '*-out.svg'  -print | ${XARGS} ${RM}
-	-${FIND} . -name '*-out.png'  -print | ${XARGS} ${RM}
+clean-local: clean-caches
+	-${FIND} . -name '*-out.*'    -print | ${XARGS} ${RM}
 	-${FIND} . -name '*-diff.png' -print | ${XARGS} ${RM}
 	-${FIND} . -name '*.log'      -print | ${XARGS} ${RM}
 	-${FIND} . -name '*.[is]'     -print | ${XARGS} ${RM}
+clean-caches:
+	-${FIND} . -name '*-pass.*' -print | ${XARGS} ${RM}
+	-${FIND} . -name '*-last.*' -print | ${XARGS} ${RM}
 
 # The following definitions both should work.
 #FAILED_TESTS = `grep -l '\<FAIL\>' $(TESTS:$(EXEEXT)=.log) 2>/dev/null | sed -e 's/[.]log$$//' | xargs echo`
diff --git a/test/README b/test/README
index 3b154e1..984cbbe 100644
--- a/test/README
+++ b/test/README
@@ -42,6 +42,12 @@ This will re-run the test suite, but only on tests that failed on the
 last run. So this is a much faster way of checking if changes actually
 fix bugs rather than running the entire test suite again.
 
+The test suite first compares the output from the current run against the
+previous in order to skip more expensive image comparisons . If you think
+this is interfering with the results, you can clear the cached results using:
+
+  make clean-caches
+
 Running tests under modified enviroments or tools
 -------------------------------------------------
 To run tests under a tool like gdb, one can use the run target and
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 99478ca..c02c44f 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -68,7 +68,7 @@
 static cairo_user_data_key_t _cairo_test_context_key;
 
 static void
-xunlink (const cairo_test_context_t *ctx, const char *pathname);
+_xunlink (const cairo_test_context_t *ctx, const char *pathname);
 
 static const char *fail_face = "", *normal_face = "";
 
@@ -119,7 +119,7 @@ _cairo_test_init (cairo_test_context_t *ctx,
     ctx->expectation = expectation;
 
     xasprintf (&log_name, "%s%s", test_name, CAIRO_TEST_LOG_SUFFIX);
-    xunlink (NULL, log_name);
+    _xunlink (NULL, log_name);
 
     ctx->log_file = fopen (log_name, "a");
     if (ctx->log_file == NULL) {
@@ -239,7 +239,7 @@ cairo_test_log_path (const cairo_test_context_t *ctx,
 }
 
 static void
-xunlink (const cairo_test_context_t *ctx, const char *pathname)
+_xunlink (const cairo_test_context_t *ctx, const char *pathname)
 {
     if (unlink (pathname) < 0 && errno != ENOENT) {
 	cairo_test_log (ctx, "Error: Cannot remove %s: %s\n",
@@ -427,6 +427,71 @@ cairo_test_get_reference_image (cairo_test_context_t *ctx,
     return _cairo_test_flatten_reference_image (ctx, flatten);
 }
 
+static cairo_bool_t
+cairo_test_files_equal (const char *test_filename,
+			const char *pass_filename)
+{
+    FILE *test, *pass;
+    int t, p;
+
+    test = fopen (test_filename, "rb");
+    if (test == NULL)
+	return FALSE;
+
+    pass = fopen (pass_filename, "rb");
+    if (pass == NULL) {
+	fclose (test);
+	return FALSE;
+    }
+
+    /* as simple as it gets */
+    do {
+	t = getc (test);
+	p = getc (pass);
+	if (t != p)
+	    break;
+    } while (t != EOF && p != EOF);
+
+    fclose (pass);
+    fclose (test);
+
+    return t == p; /* both EOF */
+}
+
+static cairo_bool_t
+cairo_test_copy_file (const char *src_filename,
+		      const char *dst_filename)
+{
+    FILE *src, *dst;
+    int c;
+
+#if HAVE_LINK
+    if (link (src_filename, dst_filename) == 0)
+	return TRUE;
+
+    unlink (dst_filename);
+#endif
+
+    src = fopen (src_filename, "rb");
+    if (src == NULL)
+	return FALSE;
+
+    dst = fopen (dst_filename, "wb");
+    if (dst == NULL) {
+	fclose (src);
+	return FALSE;
+    }
+
+    /* as simple as it gets */
+    while ((c = getc (src)) != EOF)
+	putc (c, dst);
+
+    fclose (src);
+    fclose (dst);
+
+    return TRUE;
+}
+
 static cairo_test_status_t
 cairo_test_for_target (cairo_test_context_t		 *ctx,
 		       const cairo_boilerplate_target_t	 *target,
@@ -439,6 +504,7 @@ cairo_test_for_target (cairo_test_context_t		 *ctx,
     const char *empty_str = "";
     char *offset_str, *thread_str;
     char *base_name, *png_name, *ref_name, *diff_name;
+    char *test_filename = NULL, *pass_filename = NULL, *last_filename = NULL;
     cairo_test_status_t ret;
     cairo_content_t expected_content;
     cairo_font_options_t *font_options;
@@ -604,28 +670,45 @@ cairo_test_for_target (cairo_test_context_t		 *ctx,
 	cairo_status_t diff_status;
 
 	if (ref_name == NULL) {
-	    cairo_test_log (ctx, "Error: Cannot find reference image for %s/%s-%s-%s%s\n",
-			    ctx->srcdir,
-			    ctx->test->name,
-			    target->name,
-			    format,
-			    CAIRO_TEST_REF_SUFFIX);
+	    cairo_test_log (ctx, "Error: Cannot find reference image for %s\n",
+			    base_name);
 	    ret = CAIRO_TEST_FAILURE;
 	    goto UNWIND_CAIRO;
 	}
 
-	ref_image = cairo_test_get_reference_image (ctx, ref_name,
-						    target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
-	if (cairo_surface_status (ref_image)) {
-	    cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
-			    ref_name,
-			    cairo_status_to_string (cairo_surface_status (ref_image)));
-	    ret = CAIRO_TEST_FAILURE;
-	    goto UNWIND_CAIRO;
+	if (target->finish_surface != NULL) {
+	    diff_status = target->finish_surface (surface);
+	    if (diff_status) {
+		cairo_test_log (ctx, "Error: Failed to finish surface: %s\n",
+				cairo_status_to_string (diff_status));
+		ret = CAIRO_TEST_FAILURE;
+		goto UNWIND_CAIRO;
+	    }
+	}
+
+	if (target->file_extension != NULL) { /* compare vector surfaces */
+	    xasprintf (&test_filename, "%s-out%s",
+		       base_name, target->file_extension);
+	    xasprintf (&pass_filename, "%s-pass%s",
+		       base_name, target->file_extension);
+	    xasprintf (&last_filename, "%s-last%s",
+		       base_name, target->file_extension);
+	    if (cairo_test_files_equal (test_filename, pass_filename)) {
+		/* identical output as last known PASS */
+		cairo_test_log (ctx, "Vector surface matches last pass.\n");
+		ret = CAIRO_TEST_SUCCESS;
+		goto UNWIND_CAIRO;
+	    }
+	    if (cairo_test_files_equal (test_filename, last_filename)) {
+		/* identical output as last time, fail */
+		cairo_test_log (ctx, "Vector surface matches last fail.\n");
+		have_result = TRUE; /* presume these were kept around as well */
+		ret = CAIRO_TEST_FAILURE;
+		goto UNWIND_CAIRO;
+	    }
 	}
 
-	xunlink (ctx, png_name);
-	xunlink (ctx, diff_name);
+	_xunlink (ctx, png_name);
 
 	test_image = target->get_image_surface (surface,
 					       ctx->test->width,
@@ -647,6 +730,57 @@ cairo_test_for_target (cairo_test_context_t		 *ctx,
 	}
 	have_output = TRUE;
 
+	/* binary compare png files (no decompression) */
+	if (target->file_extension == NULL) {
+	    xasprintf (&test_filename, "%s", png_name);
+	    xasprintf (&pass_filename, "%s-pass.png", base_name);
+	    xasprintf (&last_filename, "%s-last.png", base_name);
+
+	    if (cairo_test_files_equal (test_filename, pass_filename)) {
+		/* identical output as last known PASS, pass */
+		cairo_test_log (ctx, "PNG file exactly matches last pass.\n");
+		cairo_surface_destroy (test_image);
+		ret = CAIRO_TEST_SUCCESS;
+		goto UNWIND_CAIRO;
+	    }
+	    if (cairo_test_files_equal (png_name, ref_name)) {
+		/* identical output as reference image */
+		cairo_test_log (ctx, "PNG file exactly reference image.\n");
+		cairo_surface_destroy (test_image);
+		ret = CAIRO_TEST_SUCCESS;
+		goto UNWIND_CAIRO;
+	    }
+
+	    if (cairo_test_files_equal (test_filename, last_filename)) {
+		cairo_test_log (ctx, "PNG file exactly matches last fail.\n");
+		/* identical output as last known time, fail */
+		have_result = TRUE; /* presume these were kept around as well */
+		cairo_surface_destroy (test_image);
+		ret = CAIRO_TEST_FAILURE;
+		goto UNWIND_CAIRO;
+	    }
+	} else {
+	    if (cairo_test_files_equal (png_name, ref_name)) {
+		cairo_test_log (ctx, "PNG file exactly matches reference image.\n");
+		cairo_surface_destroy (test_image);
+		ret = CAIRO_TEST_SUCCESS;
+		goto UNWIND_CAIRO;
+	    }
+	}
+
+	ref_image = cairo_test_get_reference_image (ctx, ref_name,
+						    target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
+	if (cairo_surface_status (ref_image)) {
+	    cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
+			    ref_name,
+			    cairo_status_to_string (cairo_surface_status (ref_image)));
+	    cairo_surface_destroy (test_image);
+	    ret = CAIRO_TEST_FAILURE;
+	    goto UNWIND_CAIRO;
+	}
+
+	_xunlink (ctx, diff_name);
+
 	diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
 						 ctx->test->width,
 						 ctx->test->height);
@@ -671,8 +805,12 @@ cairo_test_for_target (cairo_test_context_t		 *ctx,
 				cairo_status_to_string (diff_status));
 	    } else
 		have_result = TRUE;
+	} else { /* success */
+	    cairo_test_copy_file (test_filename, pass_filename);
 	}
 
+	cairo_test_copy_file (test_filename, last_filename);
+
 	cairo_surface_destroy (test_image);
 	cairo_surface_destroy (diff_image);
     }
@@ -697,6 +835,12 @@ UNWIND_SURFACE:
     }
 
 UNWIND_STRINGS:
+    if (test_filename != NULL)
+	free (test_filename);
+    if (last_filename != NULL)
+	free (last_filename);
+    if (pass_filename != NULL)
+	free (pass_filename);
     if (png_name)
       free (png_name);
     if (ref_name)
@@ -769,12 +913,12 @@ cairo_test_run (cairo_test_context_t *ctx)
 
 	    has_similar = cairo_test_target_has_similar (ctx, target);
 	    for (similar = 0; similar <= has_similar ; similar++) {
-		cairo_test_log (ctx, "Testing %s with %s%s target (dev offset %d)\n", ctx->test_name, similar ? " (similar)" : "", target->name, dev_offset);
+		cairo_test_log (ctx, "Testing %s with %s%s target (dev offset %d)\n", ctx->test_name, similar ? " (similar) " : "", target->name, dev_offset);
 		if (ctx->thread == 0) {
 		    printf ("%s-%s-%s [%d]%s:\t", ctx->test->name, target->name,
 			    cairo_boilerplate_content_name (target->content),
 			    dev_offset,
-			    similar ? " (similar)": "");
+			    similar ? " (similar) ": "");
 		    fflush (stdout);
 		}
 
commit 98bb04cf93549455583d95b693c01b243b712c61
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Aug 20 19:39:27 2008 +0100

    [ps] Check for end-of-stream after advancing character.
    
    Whilst writing the base85 stream we advance an extra character if we spot
    a '~', however we need to be paranoid that we have not stepped beyond the
    end of the data for this write.

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 77c3035..b20c5b1 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1583,7 +1583,10 @@ _string_array_stream_write (cairo_output_stream_t *base,
 	    _cairo_output_stream_write (stream->output, &c, 1);
 	    stream->column++;
 	    stream->string_size++;
-	    length--;
+
+	    if (length-- == 0)
+		break;
+
 	    c = *data++;
 	}
 	_cairo_output_stream_write (stream->output, &c, 1);
commit b47c772934571ffcabc3ec9b3468f4ef1a6d6863
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Aug 20 19:37:56 2008 +0100

    [test/bufferdiff] Move unused code.
    
    Only imagediff calls png_diff, so it makes sense to move that function out
    of the cairo-test and into the utility.

diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index b656b11..f37ef6e 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -46,16 +46,6 @@
  * claims that the images are identical */
 #define PERCEPTUAL_DIFF_THRESHOLD 25
 
-static void
-xunlink (const cairo_test_context_t *ctx, const char *pathname)
-{
-    if (unlink (pathname) < 0 && errno != ENOENT) {
-	cairo_test_log (ctx, "  Error: Cannot remove %s: %s\n",
-			pathname, strerror (errno));
-	exit (CAIRO_TEST_FAILURE);
-    }
-}
-
 /* Compare two buffers, returning the number of pixels that are
  * different and the maximum difference of any single color channel in
  * result_ret.
@@ -202,88 +192,6 @@ buffer_diff_noalpha (const unsigned char *buf_a,
 		     result);
 }
 
-static cairo_status_t
-stdio_write_func (void *closure, const unsigned char *data, unsigned int length)
-{
-    FILE *file = closure;
-
-    if (fwrite (data, 1, length, file) != length)
-	return CAIRO_STATUS_WRITE_ERROR;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-/* Flatten an ARGB surface by blending it over white. The resulting
- * surface, (still in ARGB32 format, but with only alpha==1.0
- * everywhere) is returned in the same surface pointer.
- *
- * The original surface will be destroyed.
- *
- * The (x,y) value specify an origin of interest for the original
- * image. The flattened image will be generated only from the box
- * extending from (x,y) to (width,height).
- */
-static void
-flatten_surface (const cairo_test_context_t *ctx,
-	         cairo_surface_t **surface,
-		 int x, int y)
-{
-    cairo_surface_t *flat;
-    cairo_t *cr;
-
-    flat = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-				       cairo_image_surface_get_width (*surface) - x,
-				       cairo_image_surface_get_height (*surface) - y);
-    cairo_surface_set_device_offset (flat, -x, -y);
-
-    cr = cairo_create (flat);
-    cairo_surface_destroy (flat);
-
-    cairo_set_source_rgb (cr, 1, 1, 1);
-    cairo_paint (cr);
-
-    cairo_set_source_surface (cr, *surface, 0, 0);
-    cairo_surface_destroy (*surface);
-    cairo_paint (cr);
-
-    *surface = cairo_surface_reference (cairo_get_target (cr));
-    cairo_destroy (cr);
-}
-
-/* Given an image surface, create a new surface that has the same
- * contents as the sub-surface with its origin at x,y.
- *
- * The original surface will be destroyed.
- */
-static void
-extract_sub_surface (const cairo_test_context_t *ctx,
-	             cairo_surface_t **surface,
-		     int x, int y)
-{
-    cairo_surface_t *sub;
-    cairo_t *cr;
-
-    sub = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-				      cairo_image_surface_get_width (*surface) - x,
-				      cairo_image_surface_get_height (*surface) - y);
-
-    /* We don't use a device offset like flatten_surface. That's not
-     * for any important reason, (the results should be
-     * identical). This style just seemed more natural to me this
-     * time, so I'm leaving both here so I can look at both to see
-     * which I like better. */
-    cr = cairo_create (sub);
-    cairo_surface_destroy (sub);
-
-    cairo_set_source_surface (cr, *surface, -x, -y);
-    cairo_surface_destroy (*surface);
-    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-    cairo_paint (cr);
-
-    *surface = cairo_surface_reference (cairo_get_target (cr));
-    cairo_destroy (cr);
-}
-
 static cairo_bool_t
 same_size (cairo_surface_t *a, cairo_surface_t *b)
 {
@@ -341,206 +249,3 @@ image_diff (const cairo_test_context_t *ctx,
 
     return CAIRO_STATUS_SUCCESS;
 }
-
-static cairo_status_t
-write_png (cairo_surface_t *surface, const char *filename)
-{
-    cairo_status_t status;
-    FILE *png_file;
-
-    if (filename != NULL) {
-	png_file = fopen (filename, "wb");
-	if (png_file == NULL) {
-	    switch (errno) {
-	    case ENOMEM:
-		return CAIRO_STATUS_NO_MEMORY;
-	    default:
-		return CAIRO_STATUS_WRITE_ERROR;
-	    }
-	}
-    } else
-	png_file = stdout;
-
-    status = cairo_surface_write_to_png_stream (surface,
-						stdio_write_func,
-						png_file);
-
-    if (png_file != stdout)
-	fclose (png_file);
-
-    return status;
-}
-
-
-
-cairo_status_t
-png_diff (const cairo_test_context_t *ctx,
-	  const char *filename_a,
-	  const char *filename_b,
-	  const char *filename_diff,
-	  int		ax,
-	  int		ay,
-	  int		bx,
-	  int		by,
-	  buffer_diff_result_t *result)
-{
-    cairo_surface_t *surface_a;
-    cairo_surface_t *surface_b;
-    cairo_surface_t *surface_diff;
-    cairo_status_t status;
-
-    surface_a = cairo_image_surface_create_from_png (filename_a);
-    status = cairo_surface_status (surface_a);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to create surface from %s: %s\n",
-			filename_a, cairo_status_to_string (status));
-	return status;
-    }
-
-    surface_b = cairo_image_surface_create_from_png (filename_b);
-    status = cairo_surface_status (surface_b);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to create surface from %s: %s\n",
-			filename_b, cairo_status_to_string (status));
-	cairo_surface_destroy (surface_a);
-	return status;
-    }
-
-    if (ax || ay) {
-	extract_sub_surface (ctx, &surface_a, ax, ay);
-	ax = ay = 0;
-    }
-
-    if (bx || by) {
-	extract_sub_surface (ctx, &surface_b, bx, by);
-	bx = by = 0;
-    }
-
-    status = cairo_surface_status (surface_a);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to extract surface from %s: %s\n",
-			filename_a, cairo_status_to_string (status));
-	cairo_surface_destroy (surface_a);
-	cairo_surface_destroy (surface_b);
-	return status;
-    }
-    status = cairo_surface_status (surface_b);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to extract surface from %s: %s\n",
-			filename_b, cairo_status_to_string (status));
-	cairo_surface_destroy (surface_a);
-	cairo_surface_destroy (surface_b);
-	return status;
-    }
-
-    surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-					       cairo_image_surface_get_width (surface_a),
-					       cairo_image_surface_get_height (surface_a));
-    status = cairo_surface_status (surface_diff);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to allocate surface to hold differences\n");
-	cairo_surface_destroy (surface_a);
-	cairo_surface_destroy (surface_b);
-	return CAIRO_STATUS_NO_MEMORY;
-    }
-
-    status = image_diff (ctx,
-			 surface_a, surface_b, surface_diff,
-			 result);
-
-    cairo_surface_destroy (surface_a);
-    cairo_surface_destroy (surface_b);
-    cairo_surface_destroy (surface_diff);
-
-    xunlink (ctx, filename_diff);
-    if (status == CAIRO_STATUS_SUCCESS &&
-	result->pixels_changed)
-    {
-	status = write_png (surface_diff, filename_diff);
-    }
-
-
-    return status;
-}
-
-cairo_status_t
-png_diff_flattened (const cairo_test_context_t *ctx,
-		    const char *filename_a,
-		    const char *filename_b,
-		    const char *filename_diff,
-		    int	  ax,
-		    int	  ay,
-		    int	  bx,
-		    int	  by,
-		    buffer_diff_result_t *result)
-{
-    cairo_surface_t *surface_a;
-    cairo_surface_t *surface_b;
-    cairo_surface_t *surface_diff;
-    cairo_status_t status;
-
-    surface_a = cairo_image_surface_create_from_png (filename_a);
-    status = cairo_surface_status (surface_a);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to create surface from %s: %s\n",
-			filename_a, cairo_status_to_string (status));
-	return status;
-    }
-
-    surface_b = cairo_image_surface_create_from_png (filename_b);
-    status = cairo_surface_status (surface_b);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to create surface from %s: %s\n",
-			filename_b, cairo_status_to_string (status));
-	cairo_surface_destroy (surface_a);
-	return status;
-    }
-
-    flatten_surface (ctx, &surface_a, ax, ay);
-    flatten_surface (ctx, &surface_b, bx, by);
-
-    status = cairo_surface_status (surface_a);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to extract surface from %s: %s\n",
-			filename_a, cairo_status_to_string (status));
-	cairo_surface_destroy (surface_a);
-	cairo_surface_destroy (surface_b);
-	return status;
-    }
-    status = cairo_surface_status (surface_b);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to extract surface from %s: %s\n",
-			filename_b, cairo_status_to_string (status));
-	cairo_surface_destroy (surface_a);
-	cairo_surface_destroy (surface_b);
-	return status;
-    }
-
-    surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-					       cairo_image_surface_get_width (surface_a),
-					       cairo_image_surface_get_height (surface_a));
-    status = cairo_surface_status (surface_diff);
-    if (status) {
-	cairo_test_log (ctx, "Error: Failed to allocate surface to hold differences\n");
-	cairo_surface_destroy (surface_a);
-	cairo_surface_destroy (surface_b);
-	return CAIRO_STATUS_NO_MEMORY;
-    }
-
-    status = image_diff (ctx,
-			 surface_a, surface_b, surface_diff,
-			 result);
-
-    xunlink (ctx, filename_diff);
-    if (status == CAIRO_STATUS_SUCCESS &&
-	result->pixels_changed)
-    {
-	status = write_png (surface_diff, filename_diff);
-    }
-
-    cairo_surface_destroy (surface_a);
-    cairo_surface_destroy (surface_b);
-    cairo_surface_destroy (surface_diff);
-
-    return status;
-}
diff --git a/test/buffer-diff.h b/test/buffer-diff.h
index 64bce92..c09bc64 100644
--- a/test/buffer-diff.h
+++ b/test/buffer-diff.h
@@ -53,42 +53,6 @@ buffer_diff_noalpha (const unsigned char *buf_a,
 		     int	    stride,
 		     buffer_diff_result_t *result);
 
-/* Compares two image buffers ignoring the alpha channel. A return
- * value of CAIRO_STATUS_SUCCESS indicates that a comparison was made,
- * (but the images may or may not differ). Failure modes include
- * CAIRO_STATUS_FILE_NOT_FOUND, CAIRO_STATUS_READ_ERROR,
- * CAIRO_STATUS_NO_MEMORY, and CAIRO_STATUS_SURFACE_TYPE_MISMATCH
- * (which is used if the image sizes differ).
- *
- * Provides number of pixels changed and maximum single-channel
- * difference in result.
- *
- * Also saves a "diff" image intended to visually show where the
- * images differ.
- */
-cairo_status_t
-png_diff (const cairo_test_context_t *ctx,
-	    const char *filename_a,
-	    const char *filename_b,
-	    const char *filename_diff,
-	    int		ax,
-	    int		ay,
-	    int		bx,
-	    int		by,
-	    buffer_diff_result_t *result);
-
-/* Like png_diff, but blending the contents of b over white first. */
-cairo_status_t
-png_diff_flattened (const cairo_test_context_t *ctx,
-	              const char *filename_a,
-		      const char *filename_b,
-		      const char *filename_diff,
-                      int         ax,
-                      int         ay,
-                      int         bx,
-                      int         by,
-		      buffer_diff_result_t *result);
-
 /* The central algorithm to compare two images, and return the differences
  * in the surface_diff.
  *
diff --git a/test/imagediff.c b/test/imagediff.c
index 6404242..73e4629 100644
--- a/test/imagediff.c
+++ b/test/imagediff.c
@@ -23,12 +23,227 @@
  *
  * Author: Richard D. Worth <richard at theworths.org> */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
 
 #include "buffer-diff.h"
 #include "xmalloc.h"
 
+static void
+_xunlink (const char *pathname)
+{
+    if (unlink (pathname) < 0 && errno != ENOENT) {
+	fprintf (stderr, "  Error: Cannot remove %s: %s\n",
+			pathname, strerror (errno));
+	exit (1);
+    }
+}
+
+/* Flatten an ARGB surface by blending it over white. The resulting
+ * surface, (still in ARGB32 format, but with only alpha==1.0
+ * everywhere) is returned in the same surface pointer.
+ *
+ * The original surface will be destroyed.
+ *
+ * The (x,y) value specify an origin of interest for the original
+ * image. The flattened image will be generated only from the box
+ * extending from (x,y) to (width,height).
+ */
+static void
+flatten_surface (cairo_surface_t **surface, int x, int y)
+{
+    cairo_surface_t *flat;
+    cairo_t *cr;
+
+    flat = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+				       cairo_image_surface_get_width (*surface) - x,
+				       cairo_image_surface_get_height (*surface) - y);
+    cairo_surface_set_device_offset (flat, -x, -y);
+
+    cr = cairo_create (flat);
+    cairo_surface_destroy (flat);
+
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+
+    cairo_set_source_surface (cr, *surface, 0, 0);
+    cairo_surface_destroy (*surface);
+    cairo_paint (cr);
+
+    *surface = cairo_surface_reference (cairo_get_target (cr));
+    cairo_destroy (cr);
+}
+
+/* Given an image surface, create a new surface that has the same
+ * contents as the sub-surface with its origin at x,y.
+ *
+ * The original surface will be destroyed.
+ */
+static void
+extract_sub_surface (cairo_surface_t **surface, int x, int y)
+{
+    cairo_surface_t *sub;
+    cairo_t *cr;
+
+    sub = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+				      cairo_image_surface_get_width (*surface) - x,
+				      cairo_image_surface_get_height (*surface) - y);
+
+    /* We don't use a device offset like flatten_surface. That's not
+     * for any important reason, (the results should be
+     * identical). This style just seemed more natural to me this
+     * time, so I'm leaving both here so I can look at both to see
+     * which I like better. */
+    cr = cairo_create (sub);
+    cairo_surface_destroy (sub);
+
+    cairo_set_source_surface (cr, *surface, -x, -y);
+    cairo_surface_destroy (*surface);
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    cairo_paint (cr);
+
+    *surface = cairo_surface_reference (cairo_get_target (cr));
+    cairo_destroy (cr);
+}
+
+static cairo_status_t
+stdio_write_func (void *closure, const unsigned char *data, unsigned int length)
+{
+    FILE *file = closure;
+
+    if (fwrite (data, 1, length, file) != length)
+	return CAIRO_STATUS_WRITE_ERROR;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+write_png (cairo_surface_t *surface, const char *filename)
+{
+    cairo_status_t status;
+    FILE *png_file;
+
+    if (filename != NULL) {
+	png_file = fopen (filename, "wb");
+	if (png_file == NULL) {
+	    switch (errno) {
+	    case ENOMEM:
+		return CAIRO_STATUS_NO_MEMORY;
+	    default:
+		return CAIRO_STATUS_WRITE_ERROR;
+	    }
+	}
+    } else
+	png_file = stdout;
+
+    status = cairo_surface_write_to_png_stream (surface,
+						stdio_write_func,
+						png_file);
+
+    if (png_file != stdout)
+	fclose (png_file);
+
+    return status;
+}
+
+static cairo_status_t
+png_diff (const char *filename_a,
+	  const char *filename_b,
+	  const char *filename_diff,
+	  int		ax,
+	  int		ay,
+	  int		bx,
+	  int		by,
+	  buffer_diff_result_t *result)
+{
+    cairo_surface_t *surface_a;
+    cairo_surface_t *surface_b;
+    cairo_surface_t *surface_diff;
+    cairo_status_t status;
+
+    surface_a = cairo_image_surface_create_from_png (filename_a);
+    status = cairo_surface_status (surface_a);
+    if (status) {
+	fprintf (stderr, "Error: Failed to create surface from %s: %s\n",
+		 filename_a, cairo_status_to_string (status));
+	return status;
+    }
+
+    surface_b = cairo_image_surface_create_from_png (filename_b);
+    status = cairo_surface_status (surface_b);
+    if (status) {
+	fprintf (stderr, "Error: Failed to create surface from %s: %s\n",
+		 filename_b, cairo_status_to_string (status));
+	cairo_surface_destroy (surface_a);
+	return status;
+    }
+
+    if (ax || ay) {
+	extract_sub_surface (&surface_a, ax, ay);
+	ax = ay = 0;
+    }
+
+    if (bx || by) {
+	extract_sub_surface (&surface_b, bx, by);
+	bx = by = 0;
+    }
+
+    status = cairo_surface_status (surface_a);
+    if (status) {
+	fprintf (stderr, "Error: Failed to extract surface from %s: %s\n",
+		 filename_a, cairo_status_to_string (status));
+	cairo_surface_destroy (surface_a);
+	cairo_surface_destroy (surface_b);
+	return status;
+    }
+    status = cairo_surface_status (surface_b);
+    if (status) {
+	fprintf (stderr, "Error: Failed to extract surface from %s: %s\n",
+		 filename_b, cairo_status_to_string (status));
+	cairo_surface_destroy (surface_a);
+	cairo_surface_destroy (surface_b);
+	return status;
+    }
+
+    surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+					       cairo_image_surface_get_width (surface_a),
+					       cairo_image_surface_get_height (surface_a));
+    status = cairo_surface_status (surface_diff);
+    if (status) {
+	fprintf (stderr,
+		 "Error: Failed to allocate surface to hold differences\n");
+	cairo_surface_destroy (surface_a);
+	cairo_surface_destroy (surface_b);
+	return CAIRO_STATUS_NO_MEMORY;
+    }
+
+    status = image_diff (NULL,
+			 surface_a, surface_b, surface_diff,
+			 result);
+
+    cairo_surface_destroy (surface_a);
+    cairo_surface_destroy (surface_b);
+    cairo_surface_destroy (surface_diff);
+
+    _xunlink (filename_diff);
+    if (status == CAIRO_STATUS_SUCCESS &&
+	result->pixels_changed)
+    {
+	status = write_png (surface_diff, filename_diff);
+    }
+
+
+    return status;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -54,7 +269,7 @@ main (int argc, char *argv[])
 	ax = ay = bx = by = 0;
     }
 
-    status = png_diff (NULL, argv[1], argv[2], NULL, ax, ay, bx, by, &result);
+    status = png_diff (argv[1], argv[2], NULL, ax, ay, bx, by, &result);
 
     if (status) {
 	fprintf (stderr, "Error comparing images: %s\n",


More information about the cairo-commit mailing list