[cairo-commit] 4 commits - boilerplate/buffer-diff.c boilerplate/buffer-diff.h boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate.h boilerplate/cairo-test.c boilerplate/cairo-test.h boilerplate/Makefile.am boilerplate/README boilerplate/read-png.c boilerplate/read-png.h boilerplate/write-png.c boilerplate/write-png.h boilerplate/xmalloc.c test/buffer-diff.c test/buffer-diff.h test/cairo-test.c test/cairo-test.h test/imagediff.c test/Makefile.am

Carl Worth cworth at kemper.freedesktop.org
Thu Aug 31 01:40:38 PDT 2006


 boilerplate/Makefile.am         |   21 
 boilerplate/README              |   14 
 boilerplate/buffer-diff.c       |  348 ------
 boilerplate/cairo-boilerplate.c | 1511 ++++++++++++++++++++++++++++
 boilerplate/cairo-boilerplate.h |   88 +
 boilerplate/cairo-test.c        | 2147 ----------------------------------------
 boilerplate/read-png.c          |  196 ---
 boilerplate/read-png.h          |   45 
 boilerplate/write-png.c         |   99 -
 boilerplate/write-png.h         |   35 
 boilerplate/xmalloc.c           |    6 
 test/Makefile.am                |   13 
 test/buffer-diff.c              |  306 +++++
 test/cairo-test.c               |  683 ++++++++++++
 test/cairo-test.h               |   13 
 test/imagediff.c                |    2 
 16 files changed, 2627 insertions(+), 2900 deletions(-)

New commits:
diff-tree d52a1f762d33f3ada919b581e0d62f8ba1c2314c (from 95475218858792ccb20ac6ad28db22e233c783d7)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Aug 31 01:39:06 2006 -0700

    Move test-specific stuff out of boilerplate/ and back into test/
    
    This now gives us two separate libtool convenience libraries,
    so they have to have separate names now:
    libcairoboilerplate.la and libcairotest.la.

diff --git a/boilerplate/Makefile.am b/boilerplate/Makefile.am
index 2cc48ce..4bf07fa 100644
--- a/boilerplate/Makefile.am
+++ b/boilerplate/Makefile.am
@@ -1,23 +1,19 @@
-noinst_LTLIBRARIES = libcairotest.la
+noinst_LTLIBRARIES = libcairoboilerplate.la
 
-libcairotest_la_SOURCES =\
+libcairoboilerplate_la_SOURCES =\
 cairo-boilerplate.c	\
 cairo-bolierplate.h	\
-buffer-diff.c		\
-buffer-diff.h		\
-cairo-test.c		\
-cairo-test.h		\
 xmalloc.c		\
 xmalloc.h
 
 if CAIRO_HAS_BEOS_SURFACE
-libcairotest_la_SOURCES += cairo-test-beos.cpp cairo-test-beos.h
+libcairoboilerplate_la_SOURCES += cairo-test-beos.cpp cairo-test-beos.h
 # BeOS system headers trigger this warning
-libcairotest_la_CXXFLAGS = -Wno-multichar
+libcairoboilerplate_la_CXXFLAGS = -Wno-multichar
 endif
 
 if CAIRO_HAS_DIRECTFB_SURFACE
-libcairotest_la_SOURCES += cairo-test-directfb.c cairo-test-directfb.h
+libcairoboilerplate_la_SOURCES += cairo-test-directfb.c cairo-test-directfb.h
 endif
 
 # We're using _GNU_SOURCE to get the prototype for asprintf. This may
diff --git a/boilerplate/buffer-diff.c b/boilerplate/buffer-diff.c
deleted file mode 100644
index b59b5e8..0000000
--- a/boilerplate/buffer-diff.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/* imagediff - Compare two images
- *
- * Copyright © 2004 Richard D. Worth
- *
- * 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 Richard Worth
- * not be used in advertising or publicity pertaining to distribution
- * of the software without specific, written prior permission.
- * Richard Worth makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
- * NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Richard D. Worth <richard at theworths.org> */
-
-#if 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 <string.h>
-#include <pixman.h>
-
-#include "cairo-test.h"
-
-#include "buffer-diff.h"
-#include "xmalloc.h"
-
-static void
-xunlink (const char *pathname)
-{
-    if (unlink (pathname) < 0 && errno != ENOENT) {
-	cairo_test_log ("  Error: Cannot remove %s: %s\n",
-			pathname, strerror (errno));
-	exit (1);
-    }
-}
-
-/* This function should be rewritten to compare all formats supported by
- * cairo_format_t instead of taking a mask as a parameter.
- */
-static int
-buffer_diff_core (unsigned char *_buf_a,
-		  unsigned char *_buf_b,
-		  unsigned char *_buf_diff,
-		  int		width,
-		  int		height,
-		  int		stride_a,
-		  int		stride_b,
-		  int		stride_diff,
-		  pixman_bits_t mask)
-{
-    int x, y;
-    pixman_bits_t *row_a, *row_b, *row;
-    int pixels_changed = 0;
-    pixman_bits_t *buf_a = (pixman_bits_t*)_buf_a;
-    pixman_bits_t *buf_b = (pixman_bits_t*)_buf_b;
-    pixman_bits_t *buf_diff = (pixman_bits_t*)_buf_diff;
-
-    stride_a /= sizeof(pixman_bits_t);
-    stride_b /= sizeof(pixman_bits_t);
-    stride_diff /= sizeof(pixman_bits_t);
-    for (y = 0; y < height; y++)
-    {
-	row_a = buf_a + y * stride_a;
-	row_b = buf_b + y * stride_b;
-	row = buf_diff + y * stride_diff;
-	for (x = 0; x < width; x++)
-	{
-	    /* check if the pixels are the same */
-	    if ((row_a[x] & mask) != (row_b[x] & mask)) {
-		int channel;
-		pixman_bits_t diff_pixel = 0;
-
-		/* calculate a difference value for all 4 channels */
-		for (channel = 0; channel < 4; channel++) {
-		    int value_a = (row_a[x] >> (channel*8)) & 0xff;
-		    int value_b = (row_b[x] >> (channel*8)) & 0xff;
-		    unsigned int diff;
-		    diff = abs (value_a - value_b);
-		    diff *= 4;  /* emphasize */
-		    if (diff)
-		        diff += 128; /* make sure it's visible */
-		    if (diff > 255)
-		        diff = 255;
-		    diff_pixel |= diff << (channel*8);
-		}
-
-		pixels_changed++;
-		row[x] = diff_pixel;
-	    } else {
-		row[x] = 0;
-	    }
-	    row[x] |= 0xff000000; /* Set ALPHA to 100% (opaque) */
-	}
-    }
-
-    return pixels_changed;
-}
-
-int
-buffer_diff (unsigned char *buf_a,
-	     unsigned char *buf_b,
-	     unsigned char *buf_diff,
-	     int	   width,
-	     int	   height,
-	     int	   stride_a,
-	     int	   stride_b,
-	     int	   stride_diff)
-{
-    return buffer_diff_core(buf_a, buf_b, buf_diff,
-			    width, height, stride_a, stride_b, stride_diff, 0xffffffff);
-}
-
-int
-buffer_diff_noalpha (unsigned char *buf_a,
-		     unsigned char *buf_b,
-		     unsigned char *buf_diff,
-		     int	   width,
-		     int	   height,
-		     int	   stride_a,
-		     int	   stride_b,
-		     int	   stride_diff)
-{
-    return buffer_diff_core(buf_a, buf_b, buf_diff,
-			    width, height, stride_a, stride_b, stride_diff, 0x00ffffff);
-}
-
-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 (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_set_source_rgb (cr, 1, 1, 1);
-    cairo_paint (cr);
-    cairo_set_source_surface (cr, *surface, 0, 0);
-    cairo_paint (cr);
-    cairo_destroy (cr);
-
-    cairo_surface_destroy (*surface);
-    *surface = flat;
-}
-
-/* Image comparison code courtesy of Richard Worth <richard at theworths.org>
- * Returns number of pixels changed, (or -1 on error).
- * Also saves a "diff" image intended to visually show where the
- * images differ.
- */
-static int
-image_diff_core (const char *filename_a,
-		 const char *filename_b,
-		 const char *filename_diff,
-		 int		ax,
-		 int		ay,
-		 int		bx,
-		 int		by,
-		 cairo_bool_t	flatten)
-{
-    int pixels_changed;
-    unsigned int width_a, height_a, stride_a;
-    unsigned int width_b, height_b, stride_b;
-    cairo_surface_t *surface_a, *surface_b, *surface_diff;
-
-    surface_a = cairo_image_surface_create_from_png (filename_a);
-    if (cairo_surface_status (surface_a))
-	return -1;
-
-    surface_b = cairo_image_surface_create_from_png (filename_b);
-    if (cairo_surface_status (surface_b)) {
-	cairo_surface_destroy (surface_a);
-	return -1;
-    }
-
-    width_a = cairo_image_surface_get_width (surface_a) - ax;
-    height_a = cairo_image_surface_get_height (surface_a) - ay;
-    width_b = cairo_image_surface_get_width (surface_b) - bx;
-    height_b = cairo_image_surface_get_height (surface_b) - by;
-
-    if (width_a  != width_b  ||
-	height_a != height_b)
-    {
-	cairo_test_log ("Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n"
-			"       for %s vs. %s\n",
-			width_a, height_a,
-			width_b, height_b,
-			filename_a, filename_b);
-	cairo_surface_destroy (surface_a);
-	cairo_surface_destroy (surface_b);
-	return -1;
-    }
-
-    if (flatten) {
-	flatten_surface (&surface_a, ax, ay);
-	flatten_surface (&surface_b, bx, by);
-	ax = ay = bx = by = 0;
-    }
-
-    surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-					       width_a, height_a);
-
-    stride_a = cairo_image_surface_get_stride (surface_a);
-    stride_b = cairo_image_surface_get_stride (surface_b);
-
-    pixels_changed = buffer_diff (cairo_image_surface_get_data (surface_a)
-				  + (ay * stride_a) + ax * 4,
-                                  cairo_image_surface_get_data (surface_b)
-				  + (by * stride_b) + by * 4,
-                                  cairo_image_surface_get_data (surface_diff),
-                                  width_a, height_a,
-				  stride_a, stride_b,
-				  cairo_image_surface_get_stride (surface_diff));
-
-    if (pixels_changed) {
-	FILE *png_file;
-
-	if (filename_diff)
-	    png_file = fopen (filename_diff, "wb");
-	else
-	    png_file = stdout;
-
-	cairo_surface_write_to_png_stream (surface_diff, stdio_write_func, png_file);
-
-	if (png_file != stdout)
-	    fclose (png_file);
-    } else {
-	if (filename_diff)
-	    xunlink (filename_diff);
-    }
-
-    cairo_surface_destroy (surface_a);
-    cairo_surface_destroy (surface_b);
-    cairo_surface_destroy (surface_diff);
-
-    return pixels_changed;
-}
-
-int
-image_diff (const char *filename_a,
-	    const char *filename_b,
-	    const char *filename_diff,
-	    int		ax,
-	    int		ay,
-	    int		bx,
-	    int		by)
-{
-    return image_diff_core (filename_a, filename_b, filename_diff,
-			    ax, ay, bx, by,
-			    FALSE);
-}
-
-int
-image_diff_flattened (const char *filename_a,
-		      const char *filename_b,
-		      const char *filename_diff,
-		      int	  ax,
-		      int	  ay,
-		      int	  bx,
-		      int	  by)
-{
-    return image_diff_core (filename_a, filename_b, filename_diff,
-			    ax, ay, bx, by,
-			    TRUE);
-}
diff --git a/boilerplate/buffer-diff.h b/boilerplate/buffer-diff.h
deleted file mode 100644
index 2be2b39..0000000
--- a/boilerplate/buffer-diff.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* imagediff - Compare two images
- *
- * Copyright © 2004 Richard D. Worth
- *
- * 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 Richard Worth
- * not be used in advertising or publicity pertaining to distribution
- * of the software without specific, written prior permission.
- * Richard Worth makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
- * NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Richard D. Worth <richard at theworths.org> */
-
-#ifndef BUFFER_DIFF_H
-#define BUFFER_DIFF_H
-
-/* Returns number of pixels changed.
- * Also fills in a "diff" buffer intended to visually show where the
- * images differ.
- */
-int
-buffer_diff (unsigned char *buf_a,
-	     unsigned char *buf_b,
-	     unsigned char *buf_diff,
-	     int	    width,
-	     int	    height,
-	     int	    stride_a,
-	     int	    stride_b,
-	     int	    stride_diff);
-
-/* Returns number of pixels changed ignoring the alpha channel.
- * Also fills in a "diff" buffer intended to visually show where the
- * images differ.
- */
-int
-buffer_diff_noalpha (unsigned char *buf_a,
-		     unsigned char *buf_b,
-		     unsigned char *buf_diff,
-		     int	    width,
-		     int	    height,
-		     int	    stride_a,
-		     int	    stride_b,
-		     int	    stride_diff);
-
-/* Returns number of pixels changed, (or -1 on error).
- * Also saves a "diff" image intended to visually show where the
- * images differ.
- */
-int
-image_diff (const char *filename_a,
-	    const char *filename_b,
-	    const char *filename_diff,
-	    int		ax,
-	    int		ay,
-	    int		bx,
-	    int		by);
-
-/* Like image_diff, but blending the contents of b over white first. */
-int
-image_diff_flattened (const char *filename_a,
-		      const char *filename_b,
-		      const char *filename_diff,
-                      int         ax,
-                      int         ay,
-                      int         bx,
-                      int         by);
-
-#endif
diff --git a/boilerplate/cairo-test.c b/boilerplate/cairo-test.c
deleted file mode 100644
index 0d915a5..0000000
--- a/boilerplate/cairo-test.c
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- * Copyright © 2004 Red Hat, Inc.
- *
- * 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
- * Red Hat, Inc. 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.
- *
- * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at cworth.org>
- */
-
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <setjmp.h>
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#include <assert.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <errno.h>
-#include <string.h>
-#if HAVE_FCFINI
-#include <fontconfig/fontconfig.h>
-#endif
-
-#include "cairo-test.h"
-
-#include "buffer-diff.h"
-#include "xmalloc.h"
-
-/* This is copied from cairoint.h. That makes it painful to keep in
- * sync, but the slim stuff makes cairoint.h "hard" to include when
- * not actually building the cairo library itself. Fortunately, since
- * we're checking all these values, we do have a safeguard for keeping
- * them in sync.
- */
-typedef enum cairo_internal_surface_type {
-    CAIRO_INTERNAL_SURFACE_TYPE_META = 0x1000,
-    CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
-    CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
-    CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
-    CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
-    CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED
-} cairo_internal_surface_type_t;
-
-#ifdef _MSC_VER
-#define vsnprintf _vsnprintf
-#define access _access
-#define F_OK 0
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-#ifndef TRUE
-#define TRUE !FALSE
-#endif
-
-static void
-xunlink (const char *pathname);
-
-static const char *fail_face = "", *normal_face = "";
-
-#define CAIRO_TEST_LOG_SUFFIX ".log"
-#define CAIRO_TEST_PNG_SUFFIX "-out.png"
-#define CAIRO_TEST_REF_SUFFIX "-ref.png"
-#define CAIRO_TEST_DIFF_SUFFIX "-diff.png"
-
-#define NUM_DEVICE_OFFSETS 2
-
-/* Static data is messy, but we're coding for tests here, not a
- * general-purpose library, and it keeps the tests cleaner to avoid a
- * context object there, (though not a whole lot). */
-FILE *cairo_test_log_file = NULL;
-const char *srcdir;
-
-/* Used to catch crashes in a test, such that we report it as such and
- * continue testing, although one crasher may already have corrupted memory in
- * an nonrecoverable fashion. */
-jmp_buf jmpbuf;
-
-void
-cairo_test_init (const char *test_name)
-{
-    char *log_name;
-
-    xasprintf (&log_name, "%s%s", test_name, CAIRO_TEST_LOG_SUFFIX);
-    xunlink (log_name);
-
-    cairo_test_log_file = fopen (log_name, "a");
-    if (cairo_test_log_file == NULL) {
-	fprintf (stderr, "Error opening log file: %s\n", log_name);
-	cairo_test_log_file = stderr;
-    }
-    free (log_name);
-
-    printf ("\nTESTING %s\n", test_name);
-}
-
-void
-cairo_test_log (const char *fmt, ...)
-{
-    va_list va;
-    FILE *file = cairo_test_log_file ? cairo_test_log_file : stderr;
-
-    va_start (va, fmt);
-    vfprintf (file, fmt, va);
-    va_end (va);
-}
-
-static void
-xunlink (const char *pathname)
-{
-    if (unlink (pathname) < 0 && errno != ENOENT) {
-	cairo_test_log ("Error: Cannot remove %s: %s\n",
-			pathname, strerror (errno));
-	exit (1);
-    }
-}
-
-static char *
-cairo_ref_name_for_test_target_format (const char *test_name,
-				       const char *target_name,
-				       const char *format)
-{
-    char *ref_name = NULL;
-
-    /* First look for a target/format-specific reference image. */
-    xasprintf (&ref_name, "%s/%s-%s-%s%s", srcdir,
-	       test_name,
-	       target_name,
-	       format,
-	       CAIRO_TEST_REF_SUFFIX);
-    if (access (ref_name, F_OK) != 0)
-	free (ref_name);
-    else
-	goto done;
-
-    /* Next, look for taget-specifc reference image. */
-    xasprintf (&ref_name, "%s/%s-%s%s", srcdir,
-	       test_name,
-	       target_name,
-	       CAIRO_TEST_REF_SUFFIX);
-    if (access (ref_name, F_OK) != 0)
-	free (ref_name);
-    else
-	goto done;
-
-    /* Next, look for format-specifc reference image. */
-    xasprintf (&ref_name, "%s/%s-%s%s", srcdir,
-	       test_name,
-	       format,
-	       CAIRO_TEST_REF_SUFFIX);
-    if (access (ref_name, F_OK) != 0)
-	free (ref_name);
-    else
-	goto done;
-
-    /* Finally, look for the standard reference image. */
-    xasprintf (&ref_name, "%s/%s%s", srcdir,
-	       test_name,
-	       CAIRO_TEST_REF_SUFFIX);
-    if (access (ref_name, F_OK) != 0)
-	free (ref_name);
-    else
-	goto done;
-
-    ref_name = NULL;
-
-done:
-    return ref_name;
-}
-
-static cairo_test_status_t
-cairo_test_for_target (cairo_test_t		 *test,
-		       cairo_test_target_t	 *target,
-		       int			  dev_offset)
-{
-    cairo_test_status_t status;
-    cairo_surface_t *surface;
-    cairo_t *cr;
-    char *png_name, *ref_name, *diff_name, *offset_str;
-    cairo_test_status_t ret;
-    cairo_content_t expected_content;
-    cairo_font_options_t *font_options;
-    const char *format;
-
-    /* Get the strings ready that we'll need. */
-    format = _cairo_test_content_name (target->content);
-    if (dev_offset)
-	xasprintf (&offset_str, "-%d", dev_offset);
-    else
-	offset_str = strdup("");
-
-    xasprintf (&png_name, "%s-%s-%s%s%s",
-	       test->name,
-	       target->name,
-	       format,
-	       offset_str, CAIRO_TEST_PNG_SUFFIX);
-    ref_name = cairo_ref_name_for_test_target_format (test->name, target->name, format);
-    xasprintf (&diff_name, "%s-%s-%s%s%s",
-	       test->name,
-	       target->name,
-	       format,
-	       offset_str, CAIRO_TEST_DIFF_SUFFIX);
-
-    /* Run the actual drawing code. */
-    if (test->width && test->height) {
-	test->width += dev_offset;
-	test->height += dev_offset;
-    }
-
-    surface = (target->create_target_surface) (test->name,
-					       target->content,
-					       test->width,
-					       test->height,
-					       &target->closure);
-
-    if (test->width && test->height) {
-	test->width -= dev_offset;
-	test->height -= dev_offset;;
-    }
-
-    if (surface == NULL) {
-	cairo_test_log ("Error: Failed to set %s target\n", target->name);
-	ret = CAIRO_TEST_UNTESTED;
-	goto UNWIND_STRINGS;
-    }
-
-    /* Check that we created a surface of the expected type. */
-    if (cairo_surface_get_type (surface) != target->expected_type) {
-	cairo_test_log ("Error: Created surface is of type %d (expected %d)\n",
-			cairo_surface_get_type (surface), target->expected_type);
-	ret = CAIRO_TEST_FAILURE;
-	goto UNWIND_SURFACE;
-    }
-
-    /* Check that we created a surface of the expected content,
-     * (ignore the articifical
-     * CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value).
-     */
-    expected_content = target->content;
-    if (expected_content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
-	expected_content = CAIRO_CONTENT_COLOR_ALPHA;
-
-    if (cairo_surface_get_content (surface) != expected_content) {
-	cairo_test_log ("Error: Created surface has content %d (expected %d)\n",
-			cairo_surface_get_content (surface), expected_content);
-	ret = CAIRO_TEST_FAILURE;
-	goto UNWIND_SURFACE;
-    }
-
-    cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
-
-    cr = cairo_create (surface);
-
-    /* Clear to transparent (or black) depending on whether the target
-     * surface supports alpha. */
-    cairo_save (cr);
-    cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
-    cairo_paint (cr);
-    cairo_restore (cr);
-
-    /* Set all components of font_options to avoid backend differences
-     * and reduce number of needed reference images. */
-    font_options = cairo_font_options_create ();
-    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
-    cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON);
-    cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
-    cairo_set_font_options (cr, font_options);
-    cairo_font_options_destroy (font_options);
-
-    status = (test->draw) (cr, test->width, test->height);
-
-    /* Then, check all the different ways it could fail. */
-    if (status) {
-	cairo_test_log ("Error: Function under test failed\n");
-	ret = status;
-	goto UNWIND_CAIRO;
-    }
-
-    cairo_show_page (cr);
-
-    if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
-	cairo_test_log ("Error: Function under test left cairo status in an error state: %s\n",
-			cairo_status_to_string (cairo_status (cr)));
-	ret = CAIRO_TEST_FAILURE;
-	goto UNWIND_CAIRO;
-    }
-
-    /* Skip image check for tests with no image (width,height == 0,0) */
-    if (test->width != 0 && test->height != 0) {
-	int pixels_changed;
-	xunlink (png_name);
-	(target->write_to_png) (surface, png_name);
-
-	if (!ref_name) {
-	    cairo_test_log ("Error: Cannot find reference image for %s/%s-%s-%s%s\n",srcdir,
-			    test->name,
-			    target->name,
-			    format,
-			    CAIRO_TEST_REF_SUFFIX);
-	    ret = CAIRO_TEST_FAILURE;
-	    goto UNWIND_CAIRO;
-	}
-
-	if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
-	    pixels_changed = image_diff_flattened (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0);
-	else
-	    pixels_changed = image_diff (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0);
-	if (pixels_changed) {
-	    if (pixels_changed > 0)
-		cairo_test_log ("Error: %d pixels differ from reference image %s\n",
-				pixels_changed, ref_name);
-	    ret = CAIRO_TEST_FAILURE;
-	    goto UNWIND_CAIRO;
-	}
-    }
-
-    ret = CAIRO_TEST_SUCCESS;
-
-UNWIND_CAIRO:
-    cairo_destroy (cr);
-UNWIND_SURFACE:
-    cairo_surface_destroy (surface);
-
-    cairo_debug_reset_static_data ();
-
-    if (target->cleanup_target)
-	target->cleanup_target (target->closure);
-
-UNWIND_STRINGS:
-    if (png_name)
-      free (png_name);
-    if (ref_name)
-      free (ref_name);
-    if (diff_name)
-      free (diff_name);
-    if (offset_str)
-      free (offset_str);
-
-    return ret;
-}
-
-#ifdef HAVE_SIGNAL_H
-static void
-segfault_handler (int signal)
-{
-    longjmp (jmpbuf, signal);
-}
-#endif
-
-static cairo_test_status_t
-cairo_test_expecting (cairo_test_t *test,
-		      cairo_test_status_t expectation)
-{
-    /* we use volatile here to make sure values are not clobbered
-     * by longjmp */
-    volatile size_t i, j, num_targets;
-    volatile cairo_bool_t limited_targets = FALSE, print_fail_on_stdout = TRUE;
-    const char *tname;
-#ifdef HAVE_SIGNAL_H
-    void (*old_segfault_handler)(int);
-#endif
-    volatile cairo_test_status_t status, ret;
-    cairo_test_target_t ** volatile targets_to_test;
-
-#ifdef HAVE_UNISTD_H
-    if (isatty (2)) {
-	fail_face = "\033[41m\033[37m\033[1m";
-	normal_face = "\033[m";
-	if (isatty (1))
-	    print_fail_on_stdout = FALSE;
-    }
-#endif
-
-    srcdir = getenv ("srcdir");
-    if (!srcdir)
-	srcdir = ".";
-
-    cairo_test_init (test->name);
-    printf ("%s\n", test->description);
-
-    if (expectation == CAIRO_TEST_FAILURE)
-    printf ("Expecting failure\n");
-
-    if ((tname = getenv ("CAIRO_TEST_TARGET")) != NULL && *tname) {
-
-	limited_targets = TRUE;
-
-	num_targets = 0;
-	targets_to_test = NULL;
-
-	while (*tname) {
-	    int found = 0;
-	    const char *end = strpbrk (tname, " \t\r\n;:,");
-	    if (!end)
-	        end = tname + strlen (tname);
-
-	    for (i = 0; targets[i].name != NULL; i++) {
-		if (0 == strncmp (targets[i].name, tname, end - tname) &&
-		    !isalnum (targets[i].name[end - tname])) {
-		    /* realloc isn't exactly the best thing here, but meh. */
-		    targets_to_test = realloc (targets_to_test, sizeof(cairo_test_target_t *) * (num_targets+1));
-		    targets_to_test[num_targets++] = &targets[i];
-		    found = 1;
-		}
-	    }
-
-	    if (!found) {
-		fprintf (stderr, "Cannot test target '%.*s'\n", (int)(end - tname), tname);
-		exit(-1);
-	    }
-
-	    if (*end)
-	      end++;
-	    tname = end;
-	}
-    } else {
-	num_targets = 0;
-	for (i = 0; targets[i].name != NULL; i++)
-	    num_targets++;
-	targets_to_test = malloc (sizeof(cairo_test_target_t*) * num_targets);
-	for (i = 0; i < num_targets; i++) {
-	    targets_to_test[i] = &targets[i];
-	}
-    }
-
-    /* The intended logic here is that we return overall SUCCESS
-     * iff. there is at least one tested backend and that all tested
-     * backends return SUCCESS, OR, there's no backend to test at all.
-     * In other words:
-     *
-     *  if      no backend to test
-     *          -> SUCCESS
-     *	else if any backend not SUCCESS
-     *		-> FAILURE
-     *	else if all backends UNTESTED
-     *		-> FAILURE
-     *	else    (== some backend SUCCESS)
-     *		-> SUCCESS
-     */
-    ret = CAIRO_TEST_UNTESTED;
-    for (i = 0; i < num_targets; i++) {
-	for (j = 0; j < NUM_DEVICE_OFFSETS; j++) {
-	    cairo_test_target_t * volatile target = targets_to_test[i];
-	    volatile int dev_offset = j * 25;
-
-	    cairo_test_log ("Testing %s with %s target (dev offset %d)\n", test->name, target->name, dev_offset);
-	    printf ("%s-%s-%s [%d]:\t", test->name, target->name,
-		    _cairo_test_content_name (target->content),
-		    dev_offset);
-
-#ifdef HAVE_SIGNAL_H
-	    /* Set up a checkpoint to get back to in case of segfaults. */
-	    old_segfault_handler = signal (SIGSEGV, segfault_handler);
-	    if (0 == setjmp (jmpbuf))
-#endif
-		status = cairo_test_for_target (test, target, dev_offset);
-#ifdef HAVE_SIGNAL_H
-	    else
-	        status = CAIRO_TEST_CRASHED;
-	    signal (SIGSEGV, old_segfault_handler);
-#endif
-
-	    cairo_test_log ("TEST: %s TARGET: %s FORMAT: %s OFFSET: %d RESULT: ",
-			    test->name, target->name,
-			    _cairo_test_content_name (target->content),
-			    dev_offset);
-
-	    switch (status) {
-	    case CAIRO_TEST_SUCCESS:
-		printf ("PASS\n");
-		cairo_test_log ("PASS\n");
-		if (ret == CAIRO_TEST_UNTESTED)
-		    ret = CAIRO_TEST_SUCCESS;
-		break;
-	    case CAIRO_TEST_UNTESTED:
-		printf ("UNTESTED\n");
-		cairo_test_log ("UNTESTED\n");
-		break;
-	    case CAIRO_TEST_CRASHED:
-		if (print_fail_on_stdout) {
-		    printf ("!!!CRASHED!!!\n");
-		} else {
-		    /* eat the test name */
-		    printf ("\r");
-		    fflush (stdout);
-		}
-		cairo_test_log ("CRASHED\n");
-		fprintf (stderr, "%s-%s-%s [%d]:\t%s!!!CRASHED!!!%s\n",
-			 test->name, target->name,
-			 _cairo_test_content_name (target->content), dev_offset,
-			 fail_face, normal_face);
-		ret = CAIRO_TEST_FAILURE;
-		break;
-	    default:
-	    case CAIRO_TEST_FAILURE:
-		if (expectation == CAIRO_TEST_FAILURE) {
-		    printf ("XFAIL\n");
-		    cairo_test_log ("XFAIL\n");
-		} else {
-		    if (print_fail_on_stdout) {
-			printf ("FAIL\n");
-		    } else {
-			/* eat the test name */
-			printf ("\r");
-			fflush (stdout);
-		    }
-		    fprintf (stderr, "%s-%s-%s [%d]:\t%sFAIL%s\n",
-			     test->name, target->name,
-			     _cairo_test_content_name (target->content), dev_offset,
-			     fail_face, normal_face);
-		    cairo_test_log ("FAIL\n");
-		}
-		ret = status;
-		break;
-	    }
-	}
-    }
-
-    if (ret != CAIRO_TEST_SUCCESS)
-        printf ("Check %s%s out for more information.\n", test->name, CAIRO_TEST_LOG_SUFFIX);
-
-    /* if no target was requested for test, succeed, otherwise if all
-     * were untested, fail. */
-    if (ret == CAIRO_TEST_UNTESTED)
-	ret = num_targets ? CAIRO_TEST_FAILURE : CAIRO_TEST_SUCCESS;
-
-    /* if targets are limited using CAIRO_TEST_TARGET, and expecting failure,
-     * make it fail, such that we can pass test suite by limiting backends
-     * to test without triggering XPASS failures. */
-    if (limited_targets && expectation == CAIRO_TEST_FAILURE && ret == CAIRO_TEST_SUCCESS) {
-	printf ("All tested backends passed, but tested targets are manually limited\n"
-		"and the test suite expects this test to fail for at least one target.\n"
-		"Intentionally failing the test, to not fail the suite.\n");
-	ret = CAIRO_TEST_FAILURE;
-    }
-
-    fclose (cairo_test_log_file);
-
-    free (targets_to_test);
-
-#if HAVE_FCFINI
-    FcFini ();
-#endif
-
-    return ret;
-}
-
-cairo_test_status_t
-cairo_test (cairo_test_t *test)
-{
-    cairo_test_status_t expectation = CAIRO_TEST_SUCCESS;
-    const char *xfails;
-
-    if ((xfails = getenv ("CAIRO_XFAIL_TESTS")) != NULL) {
-	while (*xfails) {
-	    const char *end = strpbrk (xfails, " \t\r\n;:,");
-	    if (!end)
-	        end = xfails + strlen (xfails);
-
-	    if (0 == strncmp (test->name, xfails, end - xfails) &&
-		'\0' == test->name[end - xfails]) {
-		expectation = CAIRO_TEST_FAILURE;
-		break;
-	    }
-
-	    if (*end)
-	      end++;
-	    xfails = end;
-	}
-    }
-
-    return cairo_test_expecting (test, expectation);
-}
-
-cairo_surface_t *
-cairo_test_create_surface_from_png (const char *filename)
-{
-    cairo_surface_t *image;
-    char *srcdir = getenv ("srcdir");
-
-    image = cairo_image_surface_create_from_png (filename);
-    if (cairo_surface_status(image)) {
-        /* expect not found when running with srcdir != builddir
-         * such as when 'make distcheck' is run
-         */
-	if (srcdir) {
-	    char *srcdir_filename;
-	    xasprintf (&srcdir_filename, "%s/%s", srcdir, filename);
-	    image = cairo_image_surface_create_from_png (srcdir_filename);
-	    free (srcdir_filename);
-	}
-	if (cairo_surface_status(image))
-	    return NULL;
-    }
-
-    return image;
-}
-
-cairo_pattern_t *
-cairo_test_create_pattern_from_png (const char *filename)
-{
-    cairo_surface_t *image;
-    cairo_pattern_t *pattern;
-
-    image = cairo_test_create_surface_from_png (filename);
-
-    pattern = cairo_pattern_create_for_surface (image);
-
-    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
-
-    cairo_surface_destroy (image);
-
-    return pattern;
-}
-
-static cairo_status_t
-_draw_check (cairo_surface_t *surface, int width, int height)
-{
-    cairo_t *cr;
-    cairo_status_t status;
-
-    cr = cairo_create (surface);
-    cairo_set_source_rgb (cr, 0.75, 0.75, 0.75); /* light gray */
-    cairo_paint (cr);
-
-    cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); /* dark gray */
-    cairo_rectangle (cr, width / 2,  0, width / 2, height / 2);
-    cairo_rectangle (cr, 0, height / 2, width / 2, height / 2);
-    cairo_fill (cr);
-
-    status = cairo_status (cr);
-
-    cairo_destroy (cr);
-
-    return status;
-}
-
-cairo_status_t
-cairo_test_paint_checkered (cairo_t *cr)
-{
-    cairo_status_t status;
-    cairo_surface_t *check;
-
-    check = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 12, 12);
-    status = _draw_check (check, 12, 12);
-    if (status)
-	return status;
-
-    cairo_save (cr);
-    cairo_set_source_surface (cr, check, 0, 0);
-    cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
-    cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
-    cairo_paint (cr);
-    cairo_restore (cr);
-
-    cairo_surface_destroy (check);
-
-    return CAIRO_STATUS_SUCCESS;
-}
diff --git a/boilerplate/cairo-test.h b/boilerplate/cairo-test.h
deleted file mode 100644
index 75eadb4..0000000
--- a/boilerplate/cairo-test.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright © 2004 Red Hat, Inc.
- *
- * 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
- * Red Hat, Inc. 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.
- *
- * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at cworth.org>
- */
-
-#ifndef _CAIRO_TEST_H_
-#define _CAIRO_TEST_H_
-
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h>
-#include <math.h>
-#include <cairo.h>
-
-#define CAIRO_BOILERPLATE_LOG(...) cairo_test_log (__VA_ARGS__)
-#include "cairo-boilerplate.h"
-
-CAIRO_BEGIN_DECLS
-
-#if   HAVE_STDINT_H
-# include <stdint.h>
-#elif HAVE_INTTYPES_H
-# include <inttypes.h>
-#elif HAVE_SYS_INT_TYPES_H
-# include <sys/int_types.h>
-#elif defined(_MSC_VER)
-typedef __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-# ifndef HAVE_UINT64_T
-#  define HAVE_UINT64_T 1
-# endif
-#else
-#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, \etc.)
-#endif
-
-typedef enum cairo_test_status {
-    CAIRO_TEST_SUCCESS = 0,
-    CAIRO_TEST_FAILURE,
-    CAIRO_TEST_UNTESTED,
-    CAIRO_TEST_CRASHED
-} cairo_test_status_t;
-
-typedef cairo_test_status_t  (cairo_test_draw_function_t) (cairo_t *cr, int width, int height);
-
-typedef struct _cairo_test {
-    const char *name;
-    const char *description;
-    int width;
-    int height;
-    cairo_test_draw_function_t *draw;
-} cairo_test_t;
-
-/* The standard test interface which works by examining result image.
- *
- * cairo_test() accepts a test struct which will be called once for
- * each testable backend. The following checks will be performed for
- * each backend:
- *
- * 1) If draw() does not return CAIRO_TEST_SUCCESS then this backend
- *    fails.
- *
- * 2) Otherwise, if cairo_status(cr) indicates an error then this
- *    backend fails.
- *
- * 3) Otherwise, if the image size is 0, then this backend passes.
- *
- * 4) Otherwise, if every channel of every pixel exactly matches the
- *    reference image then this backend passes. If not, this backend
- *    fails.
- *
- * The overall test result is PASS if and only if there is at least
- * one backend that is tested and if all tested backend pass according
- * to the four criteria above.
- */
-cairo_test_status_t
-cairo_test (cairo_test_t *test);
-
-/* cairo_test_init() and cairo_test_log() exist to help in writing
- * tests for which cairo_test() is not appropriate for one reason or
- * another. For example, some tests might not be doing any drawing at
- * all, or may need to create their own cairo_t rather than be handed
- * one by cairo_test.
- */
-
-/* Initialize test-specific resources, (log files, etc.) */
-void
-cairo_test_init (const char *test_name);
-
-/* Print a message to the log file, ala printf. */
-void
-cairo_test_log (const char *fmt, ...) CAIRO_PRINTF_FORMAT(1, 2);
-
-/* Helper functions that take care of finding source images even when
- * building in a non-srcdir manner, (ie. the tests will be run in a
- * directory that is different from the one where the source image
- * exists). */
-cairo_surface_t *
-cairo_test_create_surface_from_png (const char *filename);
-
-cairo_pattern_t *
-cairo_test_create_pattern_from_png (const char *filename);
-
-cairo_status_t
-cairo_test_paint_checkered (cairo_t *cr);
-
-CAIRO_END_DECLS
-
-#endif
diff --git a/boilerplate/xmalloc.c b/boilerplate/xmalloc.c
index e98541c..10d1cef 100644
--- a/boilerplate/xmalloc.c
+++ b/boilerplate/xmalloc.c
@@ -26,7 +26,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "cairo-test.h"
+#include "cairo-boilerplate.h"
 #include "xmalloc.h"
 
 void *
@@ -36,7 +36,7 @@ xmalloc (size_t size)
 
     buf = malloc (size);
     if (!buf) {
-	cairo_test_log ("Error: Out of memory. Exiting.\n");
+	CAIRO_BOILERPLATE_LOG ("Error: Out of memory. Exiting.\n");
 	exit (1);
     }
 
@@ -50,7 +50,7 @@ xcalloc (size_t nmemb, size_t size)
 
     buf = calloc (nmemb, size);
     if (!buf) {
-	cairo_test_log ("Error: Out of memory. Exiting\n");
+	CAIRO_BOILERPLATE_LOG ("Error: Out of memory. Exiting\n");
 	exit (1);
     }
 
diff --git a/test/Makefile.am b/test/Makefile.am
index 54834c9..f595dcd 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -375,12 +375,23 @@ SUPPORT_PROGS =
 # problem.
 INCLUDES =					\
 	-D_GNU_SOURCE				\
+	-I$(srcdir)				\
 	-I$(top_srcdir)/boilerplate		\
 	-I$(top_srcdir)/pixman/src		\
 	-I$(top_srcdir)/src			\
 	$(CAIRO_CFLAGS)
 
-LDADD = $(top_builddir)/boilerplate/libcairotest.la $(top_builddir)/src/libcairo.la
+EXTRA_LTLIBRARIES = libcairotest.la
+
+libcairotest_la_SOURCES =\
+	buffer-diff.c	\
+	buffer-diff.h	\
+	cairo-test.c	\
+	cairo-test.h
+
+LDADD = libcairotest.la \
+        $(top_builddir)/boilerplate/libcairoboilerplate.la \
+	$(top_builddir)/src/libcairo.la
 
 if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
 LDADD += $(GLITZ_AGL_LIBS)
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
new file mode 100644
index 0000000..b59b5e8
--- /dev/null
+++ b/test/buffer-diff.c
@@ -0,0 +1,306 @@
+/* imagediff - Compare two images
+ *
+ * Copyright © 2004 Richard D. Worth
+ *
+ * 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 Richard Worth
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.
+ * Richard Worth makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Richard D. Worth <richard at theworths.org> */
+
+#if 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 <string.h>
+#include <pixman.h>
+
+#include "cairo-test.h"
+
+#include "buffer-diff.h"
+#include "xmalloc.h"
+
+static void
+xunlink (const char *pathname)
+{
+    if (unlink (pathname) < 0 && errno != ENOENT) {
+	cairo_test_log ("  Error: Cannot remove %s: %s\n",
+			pathname, strerror (errno));
+	exit (1);
+    }
+}
+
+/* This function should be rewritten to compare all formats supported by
+ * cairo_format_t instead of taking a mask as a parameter.
+ */
+static int
+buffer_diff_core (unsigned char *_buf_a,
+		  unsigned char *_buf_b,
+		  unsigned char *_buf_diff,
+		  int		width,
+		  int		height,
+		  int		stride_a,
+		  int		stride_b,
+		  int		stride_diff,
+		  pixman_bits_t mask)
+{
+    int x, y;
+    pixman_bits_t *row_a, *row_b, *row;
+    int pixels_changed = 0;
+    pixman_bits_t *buf_a = (pixman_bits_t*)_buf_a;
+    pixman_bits_t *buf_b = (pixman_bits_t*)_buf_b;
+    pixman_bits_t *buf_diff = (pixman_bits_t*)_buf_diff;
+
+    stride_a /= sizeof(pixman_bits_t);
+    stride_b /= sizeof(pixman_bits_t);
+    stride_diff /= sizeof(pixman_bits_t);
+    for (y = 0; y < height; y++)
+    {
+	row_a = buf_a + y * stride_a;
+	row_b = buf_b + y * stride_b;
+	row = buf_diff + y * stride_diff;
+	for (x = 0; x < width; x++)
+	{
+	    /* check if the pixels are the same */
+	    if ((row_a[x] & mask) != (row_b[x] & mask)) {
+		int channel;
+		pixman_bits_t diff_pixel = 0;
+
+		/* calculate a difference value for all 4 channels */
+		for (channel = 0; channel < 4; channel++) {
+		    int value_a = (row_a[x] >> (channel*8)) & 0xff;
+		    int value_b = (row_b[x] >> (channel*8)) & 0xff;
+		    unsigned int diff;
+		    diff = abs (value_a - value_b);
+		    diff *= 4;  /* emphasize */
+		    if (diff)
+		        diff += 128; /* make sure it's visible */
+		    if (diff > 255)
+		        diff = 255;
+		    diff_pixel |= diff << (channel*8);
+		}
+
+		pixels_changed++;
+		row[x] = diff_pixel;
+	    } else {
+		row[x] = 0;
+	    }
+	    row[x] |= 0xff000000; /* Set ALPHA to 100% (opaque) */
+	}
+    }
+
+    return pixels_changed;
+}
+
+int
+buffer_diff (unsigned char *buf_a,
+	     unsigned char *buf_b,
+	     unsigned char *buf_diff,
+	     int	   width,
+	     int	   height,
+	     int	   stride_a,
+	     int	   stride_b,
+	     int	   stride_diff)
+{
+    return buffer_diff_core(buf_a, buf_b, buf_diff,
+			    width, height, stride_a, stride_b, stride_diff, 0xffffffff);
+}
+
+int
+buffer_diff_noalpha (unsigned char *buf_a,
+		     unsigned char *buf_b,
+		     unsigned char *buf_diff,
+		     int	   width,
+		     int	   height,
+		     int	   stride_a,
+		     int	   stride_b,
+		     int	   stride_diff)
+{
+    return buffer_diff_core(buf_a, buf_b, buf_diff,
+			    width, height, stride_a, stride_b, stride_diff, 0x00ffffff);
+}
+
+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 (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_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+    cairo_set_source_surface (cr, *surface, 0, 0);
+    cairo_paint (cr);
+    cairo_destroy (cr);
+
+    cairo_surface_destroy (*surface);
+    *surface = flat;
+}
+
+/* Image comparison code courtesy of Richard Worth <richard at theworths.org>
+ * Returns number of pixels changed, (or -1 on error).
+ * Also saves a "diff" image intended to visually show where the
+ * images differ.
+ */
+static int
+image_diff_core (const char *filename_a,
+		 const char *filename_b,
+		 const char *filename_diff,
+		 int		ax,
+		 int		ay,
+		 int		bx,
+		 int		by,
+		 cairo_bool_t	flatten)
+{
+    int pixels_changed;
+    unsigned int width_a, height_a, stride_a;
+    unsigned int width_b, height_b, stride_b;
+    cairo_surface_t *surface_a, *surface_b, *surface_diff;
+
+    surface_a = cairo_image_surface_create_from_png (filename_a);
+    if (cairo_surface_status (surface_a))
+	return -1;
+
+    surface_b = cairo_image_surface_create_from_png (filename_b);
+    if (cairo_surface_status (surface_b)) {
+	cairo_surface_destroy (surface_a);
+	return -1;
+    }
+
+    width_a = cairo_image_surface_get_width (surface_a) - ax;
+    height_a = cairo_image_surface_get_height (surface_a) - ay;
+    width_b = cairo_image_surface_get_width (surface_b) - bx;
+    height_b = cairo_image_surface_get_height (surface_b) - by;
+
+    if (width_a  != width_b  ||
+	height_a != height_b)
+    {
+	cairo_test_log ("Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n"
+			"       for %s vs. %s\n",
+			width_a, height_a,
+			width_b, height_b,
+			filename_a, filename_b);
+	cairo_surface_destroy (surface_a);
+	cairo_surface_destroy (surface_b);
+	return -1;
+    }
+
+    if (flatten) {
+	flatten_surface (&surface_a, ax, ay);
+	flatten_surface (&surface_b, bx, by);
+	ax = ay = bx = by = 0;
+    }
+
+    surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+					       width_a, height_a);
+
+    stride_a = cairo_image_surface_get_stride (surface_a);
+    stride_b = cairo_image_surface_get_stride (surface_b);
+
+    pixels_changed = buffer_diff (cairo_image_surface_get_data (surface_a)
+				  + (ay * stride_a) + ax * 4,
+                                  cairo_image_surface_get_data (surface_b)
+				  + (by * stride_b) + by * 4,
+                                  cairo_image_surface_get_data (surface_diff),
+                                  width_a, height_a,
+				  stride_a, stride_b,
+				  cairo_image_surface_get_stride (surface_diff));
+
+    if (pixels_changed) {
+	FILE *png_file;
+
+	if (filename_diff)
+	    png_file = fopen (filename_diff, "wb");
+	else
+	    png_file = stdout;
+
+	cairo_surface_write_to_png_stream (surface_diff, stdio_write_func, png_file);
+
+	if (png_file != stdout)
+	    fclose (png_file);
+    } else {
+	if (filename_diff)
+	    xunlink (filename_diff);
+    }
+
+    cairo_surface_destroy (surface_a);
+    cairo_surface_destroy (surface_b);
+    cairo_surface_destroy (surface_diff);
+
+    return pixels_changed;
+}
+
+int
+image_diff (const char *filename_a,
+	    const char *filename_b,
+	    const char *filename_diff,
+	    int		ax,
+	    int		ay,
+	    int		bx,
+	    int		by)
+{
+    return image_diff_core (filename_a, filename_b, filename_diff,
+			    ax, ay, bx, by,
+			    FALSE);
+}
+
+int
+image_diff_flattened (const char *filename_a,
+		      const char *filename_b,
+		      const char *filename_diff,
+		      int	  ax,
+		      int	  ay,
+		      int	  bx,
+		      int	  by)
+{
+    return image_diff_core (filename_a, filename_b, filename_diff,
+			    ax, ay, bx, by,
+			    TRUE);
+}
diff --git a/test/buffer-diff.h b/test/buffer-diff.h
new file mode 100644
index 0000000..2be2b39
--- /dev/null
+++ b/test/buffer-diff.h
@@ -0,0 +1,80 @@
+/* imagediff - Compare two images
+ *
+ * Copyright © 2004 Richard D. Worth
+ *
+ * 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 Richard Worth
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.
+ * Richard Worth makes no representations about the suitability of this
+ * software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Richard D. Worth <richard at theworths.org> */
+
+#ifndef BUFFER_DIFF_H
+#define BUFFER_DIFF_H
+
+/* Returns number of pixels changed.
+ * Also fills in a "diff" buffer intended to visually show where the
+ * images differ.
+ */
+int
+buffer_diff (unsigned char *buf_a,
+	     unsigned char *buf_b,
+	     unsigned char *buf_diff,
+	     int	    width,
+	     int	    height,
+	     int	    stride_a,
+	     int	    stride_b,
+	     int	    stride_diff);
+
+/* Returns number of pixels changed ignoring the alpha channel.
+ * Also fills in a "diff" buffer intended to visually show where the
+ * images differ.
+ */
+int
+buffer_diff_noalpha (unsigned char *buf_a,
+		     unsigned char *buf_b,
+		     unsigned char *buf_diff,
+		     int	    width,
+		     int	    height,
+		     int	    stride_a,
+		     int	    stride_b,
+		     int	    stride_diff);
+
+/* Returns number of pixels changed, (or -1 on error).
+ * Also saves a "diff" image intended to visually show where the
+ * images differ.
+ */
+int
+image_diff (const char *filename_a,
+	    const char *filename_b,
+	    const char *filename_diff,
+	    int		ax,
+	    int		ay,
+	    int		bx,
+	    int		by);
+
+/* Like image_diff, but blending the contents of b over white first. */
+int
+image_diff_flattened (const char *filename_a,
+		      const char *filename_b,
+		      const char *filename_diff,
+                      int         ax,
+                      int         ay,
+                      int         bx,
+                      int         by);
+
+#endif
diff --git a/test/cairo-test.c b/test/cairo-test.c
new file mode 100644
index 0000000..0d915a5
--- /dev/null
+++ b/test/cairo-test.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * 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
+ * Red Hat, Inc. 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.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth at cworth.org>
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <setjmp.h>
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#if HAVE_FCFINI
+#include <fontconfig/fontconfig.h>
+#endif
+
+#include "cairo-test.h"
+
+#include "buffer-diff.h"
+#include "xmalloc.h"
+
+/* This is copied from cairoint.h. That makes it painful to keep in
+ * sync, but the slim stuff makes cairoint.h "hard" to include when
+ * not actually building the cairo library itself. Fortunately, since
+ * we're checking all these values, we do have a safeguard for keeping
+ * them in sync.
+ */
+typedef enum cairo_internal_surface_type {
+    CAIRO_INTERNAL_SURFACE_TYPE_META = 0x1000,
+    CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
+    CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
+    CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+    CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+    CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED
+} cairo_internal_surface_type_t;
+
+#ifdef _MSC_VER
+#define vsnprintf _vsnprintf
+#define access _access
+#define F_OK 0
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE !FALSE
+#endif
+
+static void
+xunlink (const char *pathname);
+
+static const char *fail_face = "", *normal_face = "";
+
+#define CAIRO_TEST_LOG_SUFFIX ".log"
+#define CAIRO_TEST_PNG_SUFFIX "-out.png"
+#define CAIRO_TEST_REF_SUFFIX "-ref.png"
+#define CAIRO_TEST_DIFF_SUFFIX "-diff.png"
+
+#define NUM_DEVICE_OFFSETS 2
+
+/* Static data is messy, but we're coding for tests here, not a
+ * general-purpose library, and it keeps the tests cleaner to avoid a
+ * context object there, (though not a whole lot). */
+FILE *cairo_test_log_file = NULL;
+const char *srcdir;
+
+/* Used to catch crashes in a test, such that we report it as such and
+ * continue testing, although one crasher may already have corrupted memory in
+ * an nonrecoverable fashion. */
+jmp_buf jmpbuf;
+
+void
+cairo_test_init (const char *test_name)
+{
+    char *log_name;
+
+    xasprintf (&log_name, "%s%s", test_name, CAIRO_TEST_LOG_SUFFIX);
+    xunlink (log_name);
+
+    cairo_test_log_file = fopen (log_name, "a");
+    if (cairo_test_log_file == NULL) {
+	fprintf (stderr, "Error opening log file: %s\n", log_name);
+	cairo_test_log_file = stderr;
+    }
+    free (log_name);
+
+    printf ("\nTESTING %s\n", test_name);
+}
+
+void
+cairo_test_log (const char *fmt, ...)
+{
+    va_list va;
+    FILE *file = cairo_test_log_file ? cairo_test_log_file : stderr;
+
+    va_start (va, fmt);
+    vfprintf (file, fmt, va);
+    va_end (va);
+}
+
+static void
+xunlink (const char *pathname)
+{
+    if (unlink (pathname) < 0 && errno != ENOENT) {
+	cairo_test_log ("Error: Cannot remove %s: %s\n",
+			pathname, strerror (errno));
+	exit (1);
+    }
+}
+
+static char *
+cairo_ref_name_for_test_target_format (const char *test_name,
+				       const char *target_name,
+				       const char *format)
+{
+    char *ref_name = NULL;
+
+    /* First look for a target/format-specific reference image. */
+    xasprintf (&ref_name, "%s/%s-%s-%s%s", srcdir,
+	       test_name,
+	       target_name,
+	       format,
+	       CAIRO_TEST_REF_SUFFIX);
+    if (access (ref_name, F_OK) != 0)
+	free (ref_name);
+    else
+	goto done;
+
+    /* Next, look for taget-specifc reference image. */
+    xasprintf (&ref_name, "%s/%s-%s%s", srcdir,
+	       test_name,
+	       target_name,
+	       CAIRO_TEST_REF_SUFFIX);
+    if (access (ref_name, F_OK) != 0)
+	free (ref_name);
+    else
+	goto done;
+
+    /* Next, look for format-specifc reference image. */
+    xasprintf (&ref_name, "%s/%s-%s%s", srcdir,
+	       test_name,
+	       format,
+	       CAIRO_TEST_REF_SUFFIX);
+    if (access (ref_name, F_OK) != 0)
+	free (ref_name);
+    else
+	goto done;
+
+    /* Finally, look for the standard reference image. */
+    xasprintf (&ref_name, "%s/%s%s", srcdir,
+	       test_name,
+	       CAIRO_TEST_REF_SUFFIX);
+    if (access (ref_name, F_OK) != 0)
+	free (ref_name);
+    else
+	goto done;
+
+    ref_name = NULL;
+
+done:
+    return ref_name;
+}
+
+static cairo_test_status_t
+cairo_test_for_target (cairo_test_t		 *test,
+		       cairo_test_target_t	 *target,
+		       int			  dev_offset)
+{
+    cairo_test_status_t status;
+    cairo_surface_t *surface;
+    cairo_t *cr;
+    char *png_name, *ref_name, *diff_name, *offset_str;
+    cairo_test_status_t ret;
+    cairo_content_t expected_content;
+    cairo_font_options_t *font_options;
+    const char *format;
+
+    /* Get the strings ready that we'll need. */
+    format = _cairo_test_content_name (target->content);
+    if (dev_offset)
+	xasprintf (&offset_str, "-%d", dev_offset);
+    else
+	offset_str = strdup("");
+
+    xasprintf (&png_name, "%s-%s-%s%s%s",
+	       test->name,
+	       target->name,
+	       format,
+	       offset_str, CAIRO_TEST_PNG_SUFFIX);
+    ref_name = cairo_ref_name_for_test_target_format (test->name, target->name, format);
+    xasprintf (&diff_name, "%s-%s-%s%s%s",
+	       test->name,
+	       target->name,
+	       format,
+	       offset_str, CAIRO_TEST_DIFF_SUFFIX);
+
+    /* Run the actual drawing code. */
+    if (test->width && test->height) {
+	test->width += dev_offset;
+	test->height += dev_offset;
+    }
+
+    surface = (target->create_target_surface) (test->name,
+					       target->content,
+					       test->width,
+					       test->height,
+					       &target->closure);
+
+    if (test->width && test->height) {
+	test->width -= dev_offset;
+	test->height -= dev_offset;;
+    }
+
+    if (surface == NULL) {
+	cairo_test_log ("Error: Failed to set %s target\n", target->name);
+	ret = CAIRO_TEST_UNTESTED;
+	goto UNWIND_STRINGS;
+    }
+
+    /* Check that we created a surface of the expected type. */
+    if (cairo_surface_get_type (surface) != target->expected_type) {
+	cairo_test_log ("Error: Created surface is of type %d (expected %d)\n",
+			cairo_surface_get_type (surface), target->expected_type);
+	ret = CAIRO_TEST_FAILURE;
+	goto UNWIND_SURFACE;
+    }
+
+    /* Check that we created a surface of the expected content,
+     * (ignore the articifical
+     * CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value).
+     */
+    expected_content = target->content;
+    if (expected_content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
+	expected_content = CAIRO_CONTENT_COLOR_ALPHA;
+
+    if (cairo_surface_get_content (surface) != expected_content) {
+	cairo_test_log ("Error: Created surface has content %d (expected %d)\n",
+			cairo_surface_get_content (surface), expected_content);
+	ret = CAIRO_TEST_FAILURE;
+	goto UNWIND_SURFACE;
+    }
+
+    cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
+
+    cr = cairo_create (surface);
+
+    /* Clear to transparent (or black) depending on whether the target
+     * surface supports alpha. */
+    cairo_save (cr);
+    cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    /* Set all components of font_options to avoid backend differences
+     * and reduce number of needed reference images. */
+    font_options = cairo_font_options_create ();
+    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
+    cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON);
+    cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
+    cairo_set_font_options (cr, font_options);
+    cairo_font_options_destroy (font_options);
+
+    status = (test->draw) (cr, test->width, test->height);
+
+    /* Then, check all the different ways it could fail. */
+    if (status) {
+	cairo_test_log ("Error: Function under test failed\n");
+	ret = status;
+	goto UNWIND_CAIRO;
+    }
+
+    cairo_show_page (cr);
+
+    if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
+	cairo_test_log ("Error: Function under test left cairo status in an error state: %s\n",
+			cairo_status_to_string (cairo_status (cr)));
+	ret = CAIRO_TEST_FAILURE;
+	goto UNWIND_CAIRO;
+    }
+
+    /* Skip image check for tests with no image (width,height == 0,0) */
+    if (test->width != 0 && test->height != 0) {
+	int pixels_changed;
+	xunlink (png_name);
+	(target->write_to_png) (surface, png_name);
+
+	if (!ref_name) {
+	    cairo_test_log ("Error: Cannot find reference image for %s/%s-%s-%s%s\n",srcdir,
+			    test->name,
+			    target->name,
+			    format,
+			    CAIRO_TEST_REF_SUFFIX);
+	    ret = CAIRO_TEST_FAILURE;
+	    goto UNWIND_CAIRO;
+	}
+
+	if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
+	    pixels_changed = image_diff_flattened (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0);
+	else
+	    pixels_changed = image_diff (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0);
+	if (pixels_changed) {
+	    if (pixels_changed > 0)
+		cairo_test_log ("Error: %d pixels differ from reference image %s\n",
+				pixels_changed, ref_name);
+	    ret = CAIRO_TEST_FAILURE;
+	    goto UNWIND_CAIRO;
+	}
+    }
+
+    ret = CAIRO_TEST_SUCCESS;
+
+UNWIND_CAIRO:
+    cairo_destroy (cr);
+UNWIND_SURFACE:
+    cairo_surface_destroy (surface);
+
+    cairo_debug_reset_static_data ();
+
+    if (target->cleanup_target)
+	target->cleanup_target (target->closure);
+
+UNWIND_STRINGS:
+    if (png_name)
+      free (png_name);
+    if (ref_name)
+      free (ref_name);
+    if (diff_name)
+      free (diff_name);
+    if (offset_str)
+      free (offset_str);
+
+    return ret;
+}
+
+#ifdef HAVE_SIGNAL_H
+static void
+segfault_handler (int signal)
+{
+    longjmp (jmpbuf, signal);
+}
+#endif
+
+static cairo_test_status_t
+cairo_test_expecting (cairo_test_t *test,
+		      cairo_test_status_t expectation)
+{
+    /* we use volatile here to make sure values are not clobbered
+     * by longjmp */
+    volatile size_t i, j, num_targets;
+    volatile cairo_bool_t limited_targets = FALSE, print_fail_on_stdout = TRUE;
+    const char *tname;
+#ifdef HAVE_SIGNAL_H
+    void (*old_segfault_handler)(int);
+#endif
+    volatile cairo_test_status_t status, ret;
+    cairo_test_target_t ** volatile targets_to_test;
+
+#ifdef HAVE_UNISTD_H
+    if (isatty (2)) {
+	fail_face = "\033[41m\033[37m\033[1m";
+	normal_face = "\033[m";
+	if (isatty (1))
+	    print_fail_on_stdout = FALSE;
+    }
+#endif
+
+    srcdir = getenv ("srcdir");
+    if (!srcdir)
+	srcdir = ".";
+
+    cairo_test_init (test->name);
+    printf ("%s\n", test->description);
+
+    if (expectation == CAIRO_TEST_FAILURE)
+    printf ("Expecting failure\n");
+
+    if ((tname = getenv ("CAIRO_TEST_TARGET")) != NULL && *tname) {
+
+	limited_targets = TRUE;
+
+	num_targets = 0;
+	targets_to_test = NULL;
+
+	while (*tname) {
+	    int found = 0;
+	    const char *end = strpbrk (tname, " \t\r\n;:,");
+	    if (!end)
+	        end = tname + strlen (tname);
+
+	    for (i = 0; targets[i].name != NULL; i++) {
+		if (0 == strncmp (targets[i].name, tname, end - tname) &&
+		    !isalnum (targets[i].name[end - tname])) {
+		    /* realloc isn't exactly the best thing here, but meh. */
+		    targets_to_test = realloc (targets_to_test, sizeof(cairo_test_target_t *) * (num_targets+1));
+		    targets_to_test[num_targets++] = &targets[i];
+		    found = 1;
+		}
+	    }
+
+	    if (!found) {
+		fprintf (stderr, "Cannot test target '%.*s'\n", (int)(end - tname), tname);
+		exit(-1);
+	    }
+
+	    if (*end)
+	      end++;
+	    tname = end;
+	}
+    } else {
+	num_targets = 0;
+	for (i = 0; targets[i].name != NULL; i++)
+	    num_targets++;
+	targets_to_test = malloc (sizeof(cairo_test_target_t*) * num_targets);
+	for (i = 0; i < num_targets; i++) {
+	    targets_to_test[i] = &targets[i];
+	}
+    }
+
+    /* The intended logic here is that we return overall SUCCESS
+     * iff. there is at least one tested backend and that all tested
+     * backends return SUCCESS, OR, there's no backend to test at all.
+     * In other words:
+     *
+     *  if      no backend to test
+     *          -> SUCCESS
+     *	else if any backend not SUCCESS
+     *		-> FAILURE
+     *	else if all backends UNTESTED
+     *		-> FAILURE
+     *	else    (== some backend SUCCESS)
+     *		-> SUCCESS
+     */
+    ret = CAIRO_TEST_UNTESTED;
+    for (i = 0; i < num_targets; i++) {
+	for (j = 0; j < NUM_DEVICE_OFFSETS; j++) {
+	    cairo_test_target_t * volatile target = targets_to_test[i];
+	    volatile int dev_offset = j * 25;
+
+	    cairo_test_log ("Testing %s with %s target (dev offset %d)\n", test->name, target->name, dev_offset);
+	    printf ("%s-%s-%s [%d]:\t", test->name, target->name,
+		    _cairo_test_content_name (target->content),
+		    dev_offset);
+
+#ifdef HAVE_SIGNAL_H
+	    /* Set up a checkpoint to get back to in case of segfaults. */
+	    old_segfault_handler = signal (SIGSEGV, segfault_handler);
+	    if (0 == setjmp (jmpbuf))
+#endif
+		status = cairo_test_for_target (test, target, dev_offset);
+#ifdef HAVE_SIGNAL_H
+	    else
+	        status = CAIRO_TEST_CRASHED;
+	    signal (SIGSEGV, old_segfault_handler);
+#endif
+
+	    cairo_test_log ("TEST: %s TARGET: %s FORMAT: %s OFFSET: %d RESULT: ",
+			    test->name, target->name,
+			    _cairo_test_content_name (target->content),
+			    dev_offset);
+
+	    switch (status) {
+	    case CAIRO_TEST_SUCCESS:
+		printf ("PASS\n");
+		cairo_test_log ("PASS\n");
+		if (ret == CAIRO_TEST_UNTESTED)
+		    ret = CAIRO_TEST_SUCCESS;
+		break;
+	    case CAIRO_TEST_UNTESTED:
+		printf ("UNTESTED\n");
+		cairo_test_log ("UNTESTED\n");
+		break;
+	    case CAIRO_TEST_CRASHED:
+		if (print_fail_on_stdout) {
+		    printf ("!!!CRASHED!!!\n");
+		} else {
+		    /* eat the test name */
+		    printf ("\r");
+		    fflush (stdout);
+		}
+		cairo_test_log ("CRASHED\n");
+		fprintf (stderr, "%s-%s-%s [%d]:\t%s!!!CRASHED!!!%s\n",
+			 test->name, target->name,
+			 _cairo_test_content_name (target->content), dev_offset,
+			 fail_face, normal_face);
+		ret = CAIRO_TEST_FAILURE;
+		break;
+	    default:
+	    case CAIRO_TEST_FAILURE:
+		if (expectation == CAIRO_TEST_FAILURE) {
+		    printf ("XFAIL\n");
+		    cairo_test_log ("XFAIL\n");
+		} else {
+		    if (print_fail_on_stdout) {
+			printf ("FAIL\n");
+		    } else {
+			/* eat the test name */
+			printf ("\r");
+			fflush (stdout);
+		    }
+		    fprintf (stderr, "%s-%s-%s [%d]:\t%sFAIL%s\n",
+			     test->name, target->name,
+			     _cairo_test_content_name (target->content), dev_offset,
+			     fail_face, normal_face);
+		    cairo_test_log ("FAIL\n");
+		}
+		ret = status;
+		break;
+	    }
+	}
+    }
+
+    if (ret != CAIRO_TEST_SUCCESS)
+        printf ("Check %s%s out for more information.\n", test->name, CAIRO_TEST_LOG_SUFFIX);
+
+    /* if no target was requested for test, succeed, otherwise if all
+     * were untested, fail. */
+    if (ret == CAIRO_TEST_UNTESTED)
+	ret = num_targets ? CAIRO_TEST_FAILURE : CAIRO_TEST_SUCCESS;
+
+    /* if targets are limited using CAIRO_TEST_TARGET, and expecting failure,
+     * make it fail, such that we can pass test suite by limiting backends
+     * to test without triggering XPASS failures. */
+    if (limited_targets && expectation == CAIRO_TEST_FAILURE && ret == CAIRO_TEST_SUCCESS) {
+	printf ("All tested backends passed, but tested targets are manually limited\n"
+		"and the test suite expects this test to fail for at least one target.\n"
+		"Intentionally failing the test, to not fail the suite.\n");
+	ret = CAIRO_TEST_FAILURE;
+    }
+
+    fclose (cairo_test_log_file);
+
+    free (targets_to_test);
+
+#if HAVE_FCFINI
+    FcFini ();
+#endif
+
+    return ret;
+}
+
+cairo_test_status_t
+cairo_test (cairo_test_t *test)
+{
+    cairo_test_status_t expectation = CAIRO_TEST_SUCCESS;
+    const char *xfails;
+
+    if ((xfails = getenv ("CAIRO_XFAIL_TESTS")) != NULL) {
+	while (*xfails) {
+	    const char *end = strpbrk (xfails, " \t\r\n;:,");
+	    if (!end)
+	        end = xfails + strlen (xfails);
+
+	    if (0 == strncmp (test->name, xfails, end - xfails) &&
+		'\0' == test->name[end - xfails]) {
+		expectation = CAIRO_TEST_FAILURE;
+		break;
+	    }
+
+	    if (*end)
+	      end++;
+	    xfails = end;
+	}
+    }
+
+    return cairo_test_expecting (test, expectation);
+}
+
+cairo_surface_t *
+cairo_test_create_surface_from_png (const char *filename)
+{
+    cairo_surface_t *image;
+    char *srcdir = getenv ("srcdir");
+
+    image = cairo_image_surface_create_from_png (filename);
+    if (cairo_surface_status(image)) {
+        /* expect not found when running with srcdir != builddir
+         * such as when 'make distcheck' is run
+         */
+	if (srcdir) {
+	    char *srcdir_filename;
+	    xasprintf (&srcdir_filename, "%s/%s", srcdir, filename);
+	    image = cairo_image_surface_create_from_png (srcdir_filename);
+	    free (srcdir_filename);
+	}
+	if (cairo_surface_status(image))
+	    return NULL;
+    }
+
+    return image;
+}
+
+cairo_pattern_t *
+cairo_test_create_pattern_from_png (const char *filename)
+{
+    cairo_surface_t *image;
+    cairo_pattern_t *pattern;
+
+    image = cairo_test_create_surface_from_png (filename);
+
+    pattern = cairo_pattern_create_for_surface (image);
+
+    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+
+    cairo_surface_destroy (image);
+
+    return pattern;
+}
+
+static cairo_status_t
+_draw_check (cairo_surface_t *surface, int width, int height)
+{
+    cairo_t *cr;
+    cairo_status_t status;
+
+    cr = cairo_create (surface);
+    cairo_set_source_rgb (cr, 0.75, 0.75, 0.75); /* light gray */
+    cairo_paint (cr);
+
+    cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); /* dark gray */
+    cairo_rectangle (cr, width / 2,  0, width / 2, height / 2);
+    cairo_rectangle (cr, 0, height / 2, width / 2, height / 2);
+    cairo_fill (cr);
+
+    status = cairo_status (cr);
+
+    cairo_destroy (cr);
+
+    return status;
+}
+
+cairo_status_t
+cairo_test_paint_checkered (cairo_t *cr)
+{
+    cairo_status_t status;
+    cairo_surface_t *check;
+
+    check = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 12, 12);
+    status = _draw_check (check, 12, 12);
+    if (status)
+	return status;
+
+    cairo_save (cr);
+    cairo_set_source_surface (cr, check, 0, 0);
+    cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
+    cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    cairo_surface_destroy (check);
+
+    return CAIRO_STATUS_SUCCESS;
+}
diff --git a/test/cairo-test.h b/test/cairo-test.h
new file mode 100644
index 0000000..75eadb4
--- /dev/null
+++ b/test/cairo-test.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * 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
+ * Red Hat, Inc. 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.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth at cworth.org>
+ */
+
+#ifndef _CAIRO_TEST_H_
+#define _CAIRO_TEST_H_
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <cairo.h>
+
+#define CAIRO_BOILERPLATE_LOG(...) cairo_test_log (__VA_ARGS__)
+#include "cairo-boilerplate.h"
+
+CAIRO_BEGIN_DECLS
+
+#if   HAVE_STDINT_H
+# include <stdint.h>
+#elif HAVE_INTTYPES_H
+# include <inttypes.h>
+#elif HAVE_SYS_INT_TYPES_H
+# include <sys/int_types.h>
+#elif defined(_MSC_VER)
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+# ifndef HAVE_UINT64_T
+#  define HAVE_UINT64_T 1
+# endif
+#else
+#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, \etc.)
+#endif
+
+typedef enum cairo_test_status {
+    CAIRO_TEST_SUCCESS = 0,
+    CAIRO_TEST_FAILURE,
+    CAIRO_TEST_UNTESTED,
+    CAIRO_TEST_CRASHED
+} cairo_test_status_t;
+
+typedef cairo_test_status_t  (cairo_test_draw_function_t) (cairo_t *cr, int width, int height);
+
+typedef struct _cairo_test {
+    const char *name;
+    const char *description;
+    int width;
+    int height;
+    cairo_test_draw_function_t *draw;
+} cairo_test_t;
+
+/* The standard test interface which works by examining result image.
+ *
+ * cairo_test() accepts a test struct which will be called once for
+ * each testable backend. The following checks will be performed for
+ * each backend:
+ *
+ * 1) If draw() does not return CAIRO_TEST_SUCCESS then this backend
+ *    fails.
+ *
+ * 2) Otherwise, if cairo_status(cr) indicates an error then this
+ *    backend fails.
+ *
+ * 3) Otherwise, if the image size is 0, then this backend passes.
+ *
+ * 4) Otherwise, if every channel of every pixel exactly matches the
+ *    reference image then this backend passes. If not, this backend
+ *    fails.
+ *
+ * The overall test result is PASS if and only if there is at least
+ * one backend that is tested and if all tested backend pass according
+ * to the four criteria above.
+ */
+cairo_test_status_t
+cairo_test (cairo_test_t *test);
+
+/* cairo_test_init() and cairo_test_log() exist to help in writing
+ * tests for which cairo_test() is not appropriate for one reason or
+ * another. For example, some tests might not be doing any drawing at
+ * all, or may need to create their own cairo_t rather than be handed
+ * one by cairo_test.
+ */
+
+/* Initialize test-specific resources, (log files, etc.) */
+void
+cairo_test_init (const char *test_name);
+
+/* Print a message to the log file, ala printf. */
+void
+cairo_test_log (const char *fmt, ...) CAIRO_PRINTF_FORMAT(1, 2);
+
+/* Helper functions that take care of finding source images even when
+ * building in a non-srcdir manner, (ie. the tests will be run in a
+ * directory that is different from the one where the source image
+ * exists). */
+cairo_surface_t *
+cairo_test_create_surface_from_png (const char *filename);
+
+cairo_pattern_t *
+cairo_test_create_pattern_from_png (const char *filename);
+
+cairo_status_t
+cairo_test_paint_checkered (cairo_t *cr);
+
+CAIRO_END_DECLS
+
+#endif
diff-tree 95475218858792ccb20ac6ad28db22e233c783d7 (from 37ce7058906a9a8c7e80bf4ed59c17ec912087cf)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Aug 30 23:41:48 2006 -0700

    boilerplate: Remove custom read/write-png code in favor of using cairo surfaces
    
    Also combine image_diff and image_diff_flattened into a single function

diff --git a/boilerplate/Makefile.am b/boilerplate/Makefile.am
index b8ac3d3..2cc48ce 100644
--- a/boilerplate/Makefile.am
+++ b/boilerplate/Makefile.am
@@ -7,10 +7,6 @@ buffer-diff.c		\
 buffer-diff.h		\
 cairo-test.c		\
 cairo-test.h		\
-read-png.c		\
-read-png.h		\
-write-png.c		\
-write-png.h		\
 xmalloc.c		\
 xmalloc.h
 
diff --git a/boilerplate/buffer-diff.c b/boilerplate/buffer-diff.c
index ade0cc8..b59b5e8 100644
--- a/boilerplate/buffer-diff.c
+++ b/boilerplate/buffer-diff.c
@@ -39,8 +39,6 @@
 #include "cairo-test.h"
 
 #include "buffer-diff.h"
-#include "read-png.h"
-#include "write-png.h"
 #include "xmalloc.h"
 
 static void
@@ -143,71 +141,128 @@ buffer_diff_noalpha (unsigned char *buf_
 			    width, height, stride_a, stride_b, stride_diff, 0x00ffffff);
 }
 
+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 (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_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+    cairo_set_source_surface (cr, *surface, 0, 0);
+    cairo_paint (cr);
+    cairo_destroy (cr);
+
+    cairo_surface_destroy (*surface);
+    *surface = flat;
+}
+
 /* Image comparison code courtesy of Richard Worth <richard at theworths.org>
  * Returns number of pixels changed, (or -1 on error).
  * Also saves a "diff" image intended to visually show where the
  * images differ.
  */
-int
-image_diff (const char *filename_a,
-	    const char *filename_b,
-	    const char *filename_diff,
-	    int		ax,
-	    int		ay,
-	    int		bx,
-	    int		by)
+static int
+image_diff_core (const char *filename_a,
+		 const char *filename_b,
+		 const char *filename_diff,
+		 int		ax,
+		 int		ay,
+		 int		bx,
+		 int		by,
+		 cairo_bool_t	flatten)
 {
     int pixels_changed;
     unsigned int width_a, height_a, stride_a;
     unsigned int width_b, height_b, stride_b;
-    unsigned int stride_diff;
-    unsigned char *buf_a, *buf_b, *buf_diff;
-    read_png_status_t status;
+    cairo_surface_t *surface_a, *surface_b, *surface_diff;
 
-    status = read_png_argb32 (filename_a, &buf_a, &width_a, &height_a, &stride_a);
-    if (status)
+    surface_a = cairo_image_surface_create_from_png (filename_a);
+    if (cairo_surface_status (surface_a))
 	return -1;
 
-    status = read_png_argb32 (filename_b, &buf_b, &width_b, &height_b, &stride_b);
-    if (status) {
-	free (buf_a);
+    surface_b = cairo_image_surface_create_from_png (filename_b);
+    if (cairo_surface_status (surface_b)) {
+	cairo_surface_destroy (surface_a);
 	return -1;
     }
 
-    width_a -= ax;
-    height_a -= ay;
-    width_b -= bx;
-    height_b -= by;
+    width_a = cairo_image_surface_get_width (surface_a) - ax;
+    height_a = cairo_image_surface_get_height (surface_a) - ay;
+    width_b = cairo_image_surface_get_width (surface_b) - bx;
+    height_b = cairo_image_surface_get_height (surface_b) - by;
 
     if (width_a  != width_b  ||
 	height_a != height_b)
     {
-	cairo_test_log ("Error: Image size mismatch: (%dx%d@%d) vs. (%dx%d@%d)\n"
+	cairo_test_log ("Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n"
 			"       for %s vs. %s\n",
-			width_a, height_a, stride_a,
-			width_b, height_b, stride_b,
+			width_a, height_a,
+			width_b, height_b,
 			filename_a, filename_b);
-	free (buf_a);
-	free (buf_b);
+	cairo_surface_destroy (surface_a);
+	cairo_surface_destroy (surface_b);
 	return -1;
     }
 
-    stride_diff = 4 * width_a;
-    buf_diff = xcalloc (stride_diff * height_a, 1);
+    if (flatten) {
+	flatten_surface (&surface_a, ax, ay);
+	flatten_surface (&surface_b, bx, by);
+	ax = ay = bx = by = 0;
+    }
+
+    surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+					       width_a, height_a);
 
-    pixels_changed = buffer_diff (buf_a + (ay * stride_a) + ax * 4,
-                                  buf_b + (by * stride_b) + by * 4,
-                                  buf_diff,
+    stride_a = cairo_image_surface_get_stride (surface_a);
+    stride_b = cairo_image_surface_get_stride (surface_b);
+
+    pixels_changed = buffer_diff (cairo_image_surface_get_data (surface_a)
+				  + (ay * stride_a) + ax * 4,
+                                  cairo_image_surface_get_data (surface_b)
+				  + (by * stride_b) + by * 4,
+                                  cairo_image_surface_get_data (surface_diff),
                                   width_a, height_a,
-				  stride_a, stride_b, stride_diff);
+				  stride_a, stride_b,
+				  cairo_image_surface_get_stride (surface_diff));
 
     if (pixels_changed) {
 	FILE *png_file;
+
 	if (filename_diff)
 	    png_file = fopen (filename_diff, "wb");
 	else
 	    png_file = stdout;
-	write_png_argb32 (buf_diff, png_file, width_a, height_a, stride_diff);
+
+	cairo_surface_write_to_png_stream (surface_diff, stdio_write_func, png_file);
+
 	if (png_file != stdout)
 	    fclose (png_file);
     } else {
@@ -215,25 +270,27 @@ image_diff (const char *filename_a,
 	    xunlink (filename_diff);
     }
 
-    free (buf_a);
-    free (buf_b);
-    free (buf_diff);
+    cairo_surface_destroy (surface_a);
+    cairo_surface_destroy (surface_b);
+    cairo_surface_destroy (surface_diff);
 
     return pixels_changed;
 }
 
-/* Like image_diff, but first "flatten" the contents of filename_b by
- * blending over white.
- *
- * Yes, this is an ugly copy-and-paste of another function. I'm doing
- * this for two reasons:
- *
- * 1) I want to rewrite all of the image_diff interfaces anyway
- *    (should use cairo_image_surface_create_from_png, should save
- *    loaded buffers for re-use).
- *
- * 2) There is a second reason no more.
- */
+int
+image_diff (const char *filename_a,
+	    const char *filename_b,
+	    const char *filename_diff,
+	    int		ax,
+	    int		ay,
+	    int		bx,
+	    int		by)
+{
+    return image_diff_core (filename_a, filename_b, filename_diff,
+			    ax, ay, bx, by,
+			    FALSE);
+}
+
 int
 image_diff_flattened (const char *filename_a,
 		      const char *filename_b,
@@ -243,106 +300,7 @@ image_diff_flattened (const char *filena
 		      int	  bx,
 		      int	  by)
 {
-    int pixels_changed;
-    unsigned int width_a, height_a, stride_a;
-    unsigned int width_b, height_b, stride_b;
-    unsigned char *buf_a, *buf_b, *buf_diff;
-    unsigned char *a_flat, *b_flat;
-    cairo_surface_t *buf_a_surface, *a_flat_surface;
-    cairo_surface_t *buf_b_surface, *b_flat_surface;
-    cairo_t *cr;
-    read_png_status_t status;
-
-    status = read_png_argb32 (filename_a, &buf_a, &width_a, &height_a, &stride_a);
-    if (status)
-	return -1;
-
-    status = read_png_argb32 (filename_b, &buf_b, &width_b, &height_b, &stride_b);
-    if (status) {
-	free (buf_a);
-	return -1;
-    }
-
-    width_a -= ax;
-    height_a -= ay;
-    width_b -= bx;
-    height_b -= by;
-
-    if (width_a  != width_b  ||
-	height_a != height_b)
-    {
-	cairo_test_log ("Error: Image size mismatch: (%dx%d@%d) vs. (%dx%d@%d)\n"
-			"       for %s vs. %s\n",
-			width_a, height_a, stride_a,
-			width_b, height_b, stride_b,
-			filename_a, filename_b);
-	free (buf_a);
-	free (buf_b);
-	return -1;
-    }
-
-    buf_a_surface =  cairo_image_surface_create_for_data (buf_a,
-							  CAIRO_FORMAT_ARGB32,
-							  width_a + ax, height_a + ay,
-							  stride_a);
-    buf_b_surface =  cairo_image_surface_create_for_data (buf_b,
-							  CAIRO_FORMAT_ARGB32,
-							  width_b + bx, height_b + by,
-							  stride_b);
-
-    buf_diff = xcalloc (stride_a * height_a, 1);
-
-    a_flat = xcalloc (stride_a * height_a, 1);
-    b_flat = xcalloc (stride_b * height_b, 1);
-
-    a_flat_surface = cairo_image_surface_create_for_data (a_flat,
-							  CAIRO_FORMAT_ARGB32,
-							  width_a, height_a,
-							  stride_a);
-    cairo_surface_set_device_offset (a_flat_surface, -ax, -ay);
-    b_flat_surface = cairo_image_surface_create_for_data (b_flat,
-							  CAIRO_FORMAT_ARGB32,
-							  width_b, height_b,
-							  stride_b);
-    cairo_surface_set_device_offset (b_flat_surface, -bx, -by);
-
-    cr = cairo_create (a_flat_surface);
-    cairo_set_source_rgb (cr, 1, 1, 1);
-    cairo_paint (cr);
-    cairo_set_source_surface (cr, buf_a_surface, 0, 0);
-    cairo_paint (cr);
-    cairo_destroy (cr);
-    cairo_surface_destroy (a_flat_surface);
-    cairo_surface_destroy (buf_a_surface);
-
-    cr = cairo_create (b_flat_surface);
-    cairo_set_source_rgb (cr, 1, 1, 1);
-    cairo_paint (cr);
-    cairo_set_source_surface (cr, buf_b_surface, 0, 0);
-    cairo_paint (cr);
-    cairo_destroy (cr);
-    cairo_surface_destroy (b_flat_surface);
-    cairo_surface_destroy (buf_b_surface);
-
-    pixels_changed = buffer_diff (a_flat,
-                                  b_flat,
-                                  buf_diff,
-				  width_a, height_a,
-                                  stride_a, stride_b, stride_a);
-
-    if (pixels_changed) {
-	FILE *png_file = fopen (filename_diff, "wb");
-	write_png_argb32 (buf_diff, png_file, width_a, height_a, stride_a);
-	fclose (png_file);
-    } else {
-	xunlink (filename_diff);
-    }
-
-    free (buf_a);
-    free (buf_b);
-    free (a_flat);
-    free (b_flat);
-    free (buf_diff);
-
-    return pixels_changed;
+    return image_diff_core (filename_a, filename_b, filename_diff,
+			    ax, ay, bx, by,
+			    TRUE);
 }
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 60b4f5c..eb4ab05 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2004 Red Hat, Inc.
+ * Copyright © 2004,2006 Red Hat, Inc.
  *
  * Permission to use, copy, modify, distribute, and sell this software
  * and its documentation for any purpose is hereby granted without
diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h
index 183f6a2..f91ebff 100644
--- a/boilerplate/cairo-boilerplate.h
+++ b/boilerplate/cairo-boilerplate.h
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2004-2006 Red Hat, Inc.
+ * Copyright © 2004,2006 Red Hat, Inc.
  *
  * Permission to use, copy, modify, distribute, and sell this software
  * and its documentation for any purpose is hereby granted without
@@ -41,6 +41,14 @@
 const char *
 _cairo_test_content_name (cairo_content_t content);
 
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
 typedef cairo_surface_t *
 (*cairo_test_create_target_surface_t) (const char	 *name,
 				       cairo_content_t	  content,
diff --git a/boilerplate/cairo-test.c b/boilerplate/cairo-test.c
index 0243edf..0d915a5 100644
--- a/boilerplate/cairo-test.c
+++ b/boilerplate/cairo-test.c
@@ -48,8 +48,6 @@
 #include "cairo-test.h"
 
 #include "buffer-diff.h"
-#include "read-png.h"
-#include "write-png.h"
 #include "xmalloc.h"
 
 /* This is copied from cairoint.h. That makes it painful to keep in
diff --git a/boilerplate/read-png.c b/boilerplate/read-png.c
deleted file mode 100644
index bb02e50..0000000
--- a/boilerplate/read-png.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright © 2003 USC, Information Sciences Institute
- *
- * 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 the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at isi.edu>
- */
-
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#if   HAVE_STDINT_H
-# include <stdint.h>
-#elif HAVE_INTTYPES_H
-# include <inttypes.h>
-#elif HAVE_SYS_INT_TYPES_H
-# include <sys/int_types.h>
-#elif defined(_MSC_VER)
-  typedef __int8 int8_t;
-  typedef unsigned __int8 uint8_t;
-  typedef __int16 int16_t;
-  typedef unsigned __int16 uint16_t;
-  typedef __int32 int32_t;
-  typedef unsigned __int32 uint32_t;
-  typedef __int64 int64_t;
-  typedef unsigned __int64 uint64_t;
-# ifndef HAVE_UINT64_T
-#  define HAVE_UINT64_T 1
-# endif
-#else
-#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <png.h>
-
-#include "cairo-test.h"
-#include "read-png.h"
-#include "xmalloc.h"
-
-static void
-premultiply_data (png_structp   png,
-                  png_row_infop row_info,
-                  png_bytep     data)
-{
-    size_t i;
-
-    for (i = 0; i < row_info->rowbytes; i += 4) {
-	uint8_t *base = &data[i];
-	uint8_t  blue = base[0];
-	uint8_t  green = base[1];
-	uint8_t  red = base[2];
-	uint8_t  alpha = base[3];
-	uint32_t p;
-
-	red = ((unsigned) red * (unsigned) alpha + 127) / 255;
-	green = ((unsigned) green * (unsigned) alpha + 127) / 255;
-	blue = ((unsigned) blue * (unsigned) alpha + 127) / 255;
-	p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
-	memcpy (base, &p, sizeof (uint32_t));
-    }
-}
-
-read_png_status_t
-read_png_argb32 (const char         *filename,
-		 unsigned char      **data,
-		 unsigned int       *width,
-		 unsigned int       *height,
-		 unsigned int	    *stride)
-{
-    size_t i;
-    FILE *file;
-#define PNG_SIG_SIZE 8
-    unsigned char png_sig[PNG_SIG_SIZE];
-    int sig_bytes;
-    png_struct *png;
-    png_info *info;
-    png_uint_32 png_width, png_height;
-    int depth, color_type, interlace;
-    unsigned int pixel_size;
-    png_byte **row_pointers;
-
-    file = fopen (filename, "rb");
-    if (file == NULL) {
-	cairo_test_log ("Error: File not found: %s\n", filename);
-	return READ_PNG_FILE_NOT_FOUND;
-    }
-
-    sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file);
-    if (png_check_sig (png_sig, sig_bytes) == 0) {
-        fclose (file);
-	cairo_test_log ("Error: File is not a PNG image: %s\n", filename);
-	return READ_PNG_FILE_NOT_PNG;
-    }
-
-    /* XXX: Perhaps we'll want some other error handlers? */
-    png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
-                                  NULL,
-                                  NULL,
-                                  NULL);
-    if (png == NULL) {
-        fclose (file);
-	cairo_test_log ("Error: Out of memory while reading %s\n", filename);
-	return READ_PNG_NO_MEMORY;
-    }
-
-    info = png_create_info_struct (png);
-    if (info == NULL) {
-        fclose (file);
-        png_destroy_read_struct (&png, NULL, NULL);
-	cairo_test_log ("Error: Out of memory while reading %s\n", filename);
-	return READ_PNG_NO_MEMORY;
-    }
-
-    png_init_io (png, file);
-    png_set_sig_bytes (png, sig_bytes);
-
-    png_read_info (png, info);
-
-    png_get_IHDR (png, info,
-                  &png_width, &png_height, &depth,
-                  &color_type, &interlace, NULL, NULL);
-    *width = png_width;
-    *height = png_height;
-    *stride = 4 * png_width;
-
-    /* convert palette/gray image to rgb */
-    if (color_type == PNG_COLOR_TYPE_PALETTE)
-        png_set_palette_to_rgb (png);
-
-    /* expand gray bit depth if needed */
-    if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8)
-        png_set_gray_1_2_4_to_8 (png);
-    /* transform transparency to alpha */
-    if (png_get_valid(png, info, PNG_INFO_tRNS))
-        png_set_tRNS_to_alpha (png);
-
-    if (depth == 16)
-        png_set_strip_16 (png);
-
-    if (depth < 8)
-        png_set_packing (png);
-
-    /* convert grayscale to RGB */
-    if (color_type == PNG_COLOR_TYPE_GRAY
-        || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
-        png_set_gray_to_rgb (png);
-
-    if (interlace != PNG_INTERLACE_NONE)
-        png_set_interlace_handling (png);
-
-    png_set_bgr (png);
-    png_set_filler (png, 0xff, PNG_FILLER_AFTER);
-
-    png_set_read_user_transform_fn (png, premultiply_data);
-
-    png_read_update_info (png, info);
-
-    pixel_size = 4;
-    *data = xmalloc (png_width * png_height * pixel_size);
-
-    row_pointers = malloc (png_height * sizeof(char *));
-    for (i=0; i < png_height; i++)
-        row_pointers[i] = (png_byte *) (*data + i * png_width * pixel_size);
-
-    png_read_image (png, row_pointers);
-    png_read_end (png, info);
-
-    free (row_pointers);
-    fclose (file);
-
-    png_destroy_read_struct (&png, &info, NULL);
-
-    return READ_PNG_SUCCESS;
-}
diff --git a/boilerplate/read-png.h b/boilerplate/read-png.h
deleted file mode 100644
index 9c9ba43..0000000
--- a/boilerplate/read-png.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright © 2003 USC, Information Sciences Institute
- *
- * 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 the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at isi.edu>
- */
-
-#ifndef READ_PNG_H
-#define READ_PNG_H
-
-typedef enum {
-    READ_PNG_SUCCESS = 0,
-    READ_PNG_FILE_NOT_FOUND,
-    READ_PNG_FILE_NOT_PNG,
-    READ_PNG_NO_MEMORY
-} read_png_status_t;
-
-read_png_status_t
-read_png_argb32 (const char         *filename,
-		 unsigned char      **data,
-		 unsigned int       *width,
-		 unsigned int       *height,
-		 unsigned int	    *stride);
-
-#endif
diff --git a/boilerplate/write-png.c b/boilerplate/write-png.c
deleted file mode 100644
index c906df5..0000000
--- a/boilerplate/write-png.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright © 2003 USC, Information Sciences Institute
- *
- * 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 the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at cworth.org>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <png.h>
-
-#include "write-png.h"
-
-static void
-unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
-{
-    size_t i;
-
-    for (i = 0; i < row_info->rowbytes; i += 4) {
-        unsigned char *b = &data[i];
-        unsigned int pixel;
-        unsigned char alpha;
-
-	memcpy (&pixel, b, sizeof (unsigned int));
-	alpha = (pixel & 0xff000000) >> 24;
-        if (alpha == 0) {
-	    b[0] = b[1] = b[2] = b[3] = 0;
-	} else {
-            b[0] = (((pixel & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha;
-            b[1] = (((pixel & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha;
-            b[2] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
-	    b[3] = alpha;
-	}
-    }
-}
-
-void
-write_png_argb32 (unsigned char *buffer, FILE *file,
-		  int width, int height, int stride)
-{
-    int i;
-    png_struct *png;
-    png_info *info;
-    png_byte **rows;
-    png_color_16 white;
-
-    rows = malloc (height * sizeof(png_byte*));
-
-    for (i = 0; i < height; i++) {
-	rows[i] = buffer + i * stride;
-    }
-
-    png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    info = png_create_info_struct (png);
-
-    png_init_io (png, file);
-    png_set_IHDR (png, info,
-		  width, height, 8,
-		  PNG_COLOR_TYPE_RGB_ALPHA,
-		  PNG_INTERLACE_NONE,
-		  PNG_COMPRESSION_TYPE_DEFAULT,
-		  PNG_FILTER_TYPE_DEFAULT);
-
-    white.red = 0xff;
-    white.blue = 0xff;
-    white.green = 0xff;
-    png_set_bKGD (png, info, &white);
-
-    png_set_write_user_transform_fn (png, unpremultiply_data);
-    png_set_bgr (png);
-
-    png_write_info (png, info);
-    png_write_image (png, rows);
-    png_write_end (png, info);
-
-    png_destroy_write_struct (&png, &info);
-
-    free (rows);
-}
diff --git a/boilerplate/write-png.h b/boilerplate/write-png.h
deleted file mode 100644
index 8074666..0000000
--- a/boilerplate/write-png.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright © 2003 USC, Information Sciences Institute
- *
- * 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 the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at isi.edu>
- */
-
-#ifndef WRITE_PNG_H
-#define WRITE_PNG_H
-
-void
-write_png_argb32 (unsigned char *buffer, FILE * file,
-		  int width, int height, int stride);
-
-#endif
diff --git a/test/imagediff.c b/test/imagediff.c
index d030e76..9030877 100644
--- a/test/imagediff.c
+++ b/test/imagediff.c
@@ -27,8 +27,6 @@
 #include <stdlib.h>
 
 #include "buffer-diff.h"
-#include "read-png.h"
-#include "write-png.h"
 #include "xmalloc.h"
 
 int
diff-tree 37ce7058906a9a8c7e80bf4ed59c17ec912087cf (from a0ca4369ff71ca76e593ea8db3e728218814814d)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Aug 30 22:56:36 2006 -0700

    Separate the sharable stuff out of cairo-test.c into cairo-boilerplate.c

diff --git a/boilerplate/Makefile.am b/boilerplate/Makefile.am
index 7fa27d9..b8ac3d3 100644
--- a/boilerplate/Makefile.am
+++ b/boilerplate/Makefile.am
@@ -1,6 +1,8 @@
 noinst_LTLIBRARIES = libcairotest.la
 
 libcairotest_la_SOURCES =\
+cairo-boilerplate.c	\
+cairo-bolierplate.h	\
 buffer-diff.c		\
 buffer-diff.h		\
 cairo-test.c		\
@@ -30,6 +32,5 @@ INCLUDES =					\
 	-D_GNU_SOURCE				\
 	-I$(srcdir)				\
 	-I$(top_srcdir)/pixman/src		\
-	-I$(top_builddir)/src			\
 	-I$(top_srcdir)/src			\
 	$(CAIRO_CFLAGS)
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
new file mode 100644
index 0000000..60b4f5c
--- /dev/null
+++ b/boilerplate/cairo-boilerplate.c
@@ -0,0 +1,1511 @@
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * 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
+ * Red Hat, Inc. 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.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth at cworth.org>
+ */
+
+#include "cairo-boilerplate.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <setjmp.h>
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#if HAVE_FCFINI
+#include <fontconfig/fontconfig.h>
+#endif
+
+static const char *vector_ignored_tests[] = {
+    /* We can't match the results of tests that depend on
+     * CAIRO_ANTIALIAS_NONE/SUBPIXEL for vector backends
+     * (nor do we care). */
+    "ft-text-antialias-none",
+    "rectangle-rounding-error",
+    "text-antialias-gray",
+    "text-antialias-none",
+    "text-antialias-subpixel",
+    "unantialiased-shapes",
+    NULL
+};
+
+const char *
+_cairo_test_content_name (cairo_content_t content)
+{
+    /* For the purpose of the content name, we don't distinguish the
+     * flattened content value.
+     */
+    if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
+	content = CAIRO_CONTENT_COLOR_ALPHA;
+
+    switch (content) {
+    case CAIRO_CONTENT_COLOR:
+	return "rgb24";
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	return "argb32";
+    case CAIRO_CONTENT_ALPHA:
+    default:
+	assert (0); /* not reached */
+	return "---";
+    }
+}
+
+static cairo_surface_t *
+create_image_surface (const char	 *name,
+		      cairo_content_t	  content,
+		      int		  width,
+		      int		  height,
+		      void		**closure)
+{
+    cairo_format_t format;
+    *closure = NULL;
+
+    if (content == CAIRO_CONTENT_COLOR_ALPHA) {
+	format = CAIRO_FORMAT_ARGB32;
+    } else if (content == CAIRO_CONTENT_COLOR) {
+	format = CAIRO_FORMAT_RGB24;
+    } else {
+	assert (0); /* not reached */
+	return NULL;
+    }
+
+    return cairo_image_surface_create (format, width, height);
+}
+
+#ifdef CAIRO_HAS_TEST_SURFACES
+
+#include "test-fallback-surface.h"
+#include "test-meta-surface.h"
+#include "test-paginated-surface.h"
+
+static cairo_surface_t *
+create_test_fallback_surface (const char	 *name,
+			      cairo_content_t	  content,
+			      int		  width,
+			      int		  height,
+			      void		**closure)
+{
+    *closure = NULL;
+    return _test_fallback_surface_create (content, width, height);
+}
+
+static cairo_surface_t *
+create_test_meta_surface (const char		 *name,
+			  cairo_content_t	  content,
+			  int			  width,
+			  int			  height,
+			  void			**closure)
+{
+    *closure = NULL;
+    return _test_meta_surface_create (content, width, height);
+}
+
+static const cairo_user_data_key_t test_paginated_closure_key;
+
+typedef struct {
+    unsigned char *data;
+    cairo_content_t content;
+    int width;
+    int height;
+    int stride;
+} test_paginated_closure_t;
+
+static cairo_surface_t *
+create_test_paginated_surface (const char	 *name,
+			       cairo_content_t	  content,
+			       int		  width,
+			       int		  height,
+			       void		**closure)
+{
+    test_paginated_closure_t *tpc;
+    cairo_surface_t *surface;
+
+    *closure = tpc = xmalloc (sizeof (test_paginated_closure_t));
+
+    tpc->content = content;
+    tpc->width = width;
+    tpc->height = height;
+    tpc->stride = width * 4;
+
+    tpc->data = xcalloc (tpc->stride * height, 1);
+
+    surface = _test_paginated_surface_create_for_data (tpc->data,
+						       tpc->content,
+						       tpc->width,
+						       tpc->height,
+						       tpc->stride);
+
+    cairo_surface_set_user_data (surface, &test_paginated_closure_key,
+				 tpc, NULL);
+
+    return surface;
+}
+
+/* The only reason we go through all these machinations to write a PNG
+ * image is to _really ensure_ that the data actually landed in our
+ * buffer through the paginated surface to the test_paginated_surface.
+ *
+ * If we didn't implement this function then the default
+ * cairo_surface_write_to_png would result in the paginated_surface's
+ * acquire_source_image function replaying the meta-surface to an
+ * intermediate image surface. And in that case the
+ * test_paginated_surface would not be involved and wouldn't be
+ * tested.
+ */
+static cairo_status_t
+test_paginated_write_to_png (cairo_surface_t *surface,
+			     const char	     *filename)
+{
+    cairo_surface_t *image;
+    cairo_format_t format;
+    test_paginated_closure_t *tpc;
+
+    tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key);
+
+    switch (tpc->content) {
+    case CAIRO_CONTENT_COLOR:
+	format = CAIRO_FORMAT_RGB24;
+	break;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	format = CAIRO_FORMAT_ARGB32;
+	break;
+    case CAIRO_CONTENT_ALPHA:
+    default:
+	assert (0); /* not reached */
+	return CAIRO_STATUS_NO_MEMORY;
+    }
+
+    image = cairo_image_surface_create_for_data (tpc->data,
+						 format,
+						 tpc->width,
+						 tpc->height,
+						 tpc->stride);
+
+    cairo_surface_write_to_png (image, filename);
+
+    cairo_surface_destroy (image);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+cleanup_test_paginated (void *closure)
+{
+    test_paginated_closure_t *tpc = closure;
+
+    free (tpc->data);
+    free (tpc);
+}
+
+#endif
+
+#ifdef CAIRO_HAS_GLITZ_SURFACE
+#include <glitz.h>
+#include <cairo-glitz.h>
+
+static const cairo_user_data_key_t glitz_closure_key;
+
+typedef struct _glitz_target_closure_base {
+    int width;
+    int height;
+    cairo_content_t content;
+} glitz_target_closure_base_t;
+
+#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
+#include <glitz-glx.h>
+
+typedef struct _glitz_glx_target_closure {
+    glitz_target_closure_base_t base;
+    Display        *dpy;
+    int             scr;
+    Window          win;
+} glitz_glx_target_closure_t;
+
+static glitz_surface_t *
+create_glitz_glx_surface (glitz_format_name_t	      formatname,
+			  int			      width,
+			  int			      height,
+			  glitz_glx_target_closure_t *closure)
+{
+    Display                 * dpy = closure->dpy;
+    int                       scr = closure->scr;
+    glitz_drawable_format_t   templ;
+    glitz_drawable_format_t * dformat = NULL;
+    unsigned long             mask;
+    glitz_drawable_t        * drawable = NULL;
+    glitz_format_t          * format;
+    glitz_surface_t         * sr;
+
+    XSizeHints                xsh;
+    XSetWindowAttributes      xswa;
+    XVisualInfo             * vinfo;
+
+    memset(&templ, 0, sizeof(templ));
+    templ.color.red_size = 8;
+    templ.color.green_size = 8;
+    templ.color.blue_size = 8;
+    templ.color.alpha_size = 8;
+    templ.color.fourcc = GLITZ_FOURCC_RGB;
+    templ.samples = 1;
+
+    glitz_glx_init (NULL);
+
+    mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
+	GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
+	GLITZ_FORMAT_BLUE_SIZE_MASK;
+    if (formatname == GLITZ_STANDARD_ARGB32)
+	mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
+
+    /* Try for a pbuffer first */
+    if (!getenv("CAIRO_TEST_FORCE_GLITZ_WINDOW"))
+	dformat = glitz_glx_find_pbuffer_format (dpy, scr, mask, &templ, 0);
+
+    if (dformat) {
+	closure->win = None;
+
+	drawable = glitz_glx_create_pbuffer_drawable (dpy, scr, dformat,
+						      width, height);
+	if (!drawable)
+	    goto FAIL;
+    } else {
+	/* No pbuffer, try window */
+	dformat = glitz_glx_find_window_format (dpy, scr, mask, &templ, 0);
+
+	if (!dformat)
+	    goto FAIL;
+
+	vinfo = glitz_glx_get_visual_info_from_format(dpy,
+						      DefaultScreen(dpy),
+						      dformat);
+
+	if (!vinfo)
+	    goto FAIL;
+
+	xsh.flags = PSize;
+	xsh.x = 0;
+	xsh.y = 0;
+	xsh.width = width;
+	xsh.height = height;
+
+	xswa.colormap = XCreateColormap (dpy, RootWindow(dpy, scr),
+					 vinfo->visual, AllocNone);
+	closure->win = XCreateWindow (dpy, RootWindow(dpy, scr),
+				      xsh.x, xsh.y, xsh.width, xsh.height,
+				      0, vinfo->depth, CopyFromParent,
+				      vinfo->visual, CWColormap, &xswa);
+	XFree (vinfo);
+
+	drawable =
+	    glitz_glx_create_drawable_for_window (dpy, scr,
+						  dformat, closure->win,
+						  width, height);
+
+	if (!drawable)
+	    goto DESTROY_WINDOW;
+    }
+
+    format = glitz_find_standard_format (drawable, formatname);
+    if (!format)
+	goto DESTROY_DRAWABLE;
+
+    sr = glitz_surface_create (drawable, format, width, height, 0, NULL);
+    if (!sr)
+	goto DESTROY_DRAWABLE;
+
+    if (closure->win == None || dformat->doublebuffer) {
+	glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_BACK_COLOR);
+    } else {
+	XMapWindow (closure->dpy, closure->win);
+	glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
+    }
+
+    glitz_drawable_destroy (drawable);
+
+    return sr;
+ DESTROY_DRAWABLE:
+    glitz_drawable_destroy (drawable);
+ DESTROY_WINDOW:
+    if (closure->win)
+	XDestroyWindow (dpy, closure->win);
+ FAIL:
+    return NULL;
+}
+
+static cairo_surface_t *
+create_cairo_glitz_glx_surface (const char	 *name,
+				cairo_content_t   content,
+				int		  width,
+				int		  height,
+				void		**closure)
+{
+    int width = width;
+    int height = height;
+    glitz_glx_target_closure_t *gxtc;
+    glitz_surface_t  * glitz_surface;
+    cairo_surface_t  * surface;
+
+    *closure = gxtc = xmalloc (sizeof (glitz_glx_target_closure_t));
+
+    if (width == 0)
+	width = 1;
+    if (height == 0)
+	height = 1;
+
+    gxtc->dpy = XOpenDisplay (getenv("CAIRO_TEST_GLITZ_DISPLAY"));
+    if (!gxtc->dpy) {
+	CAIRO_BOILERPLATE_LOG ("Failed to open display: %s\n", XDisplayName(0));
+	goto FAIL;
+    }
+
+    XSynchronize (gxtc->dpy, 1);
+
+    gxtc->scr = DefaultScreen(gxtc->dpy);
+
+    switch (content) {
+    case CAIRO_CONTENT_COLOR:
+	glitz_surface = create_glitz_glx_surface (GLITZ_STANDARD_RGB24, width, height, gxtc);
+	break;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	glitz_surface = create_glitz_glx_surface (GLITZ_STANDARD_ARGB32, width, height, gxtc);
+	break;
+    default:
+	CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-glx test: %d\n", content);
+	goto FAIL_CLOSE_DISPLAY;
+    }
+    if (!glitz_surface) {
+	CAIRO_BOILERPLATE_LOG ("Failed to create glitz-glx surface\n");
+	goto FAIL_CLOSE_DISPLAY;
+    }
+
+    surface = cairo_glitz_surface_create (glitz_surface);
+
+    gxtc->base.width = width;
+    gxtc->base.height = height;
+    gxtc->base.content = content;
+    cairo_surface_set_user_data (surface, &glitz_closure_key,
+				 gxtc, NULL);
+
+    return surface;
+
+ FAIL_CLOSE_DISPLAY:
+    XCloseDisplay (gxtc->dpy);
+ FAIL:
+    return NULL;
+}
+
+static void
+cleanup_cairo_glitz_glx (void *closure)
+{
+    glitz_glx_target_closure_t *gxtc = closure;
+
+    glitz_glx_fini ();
+
+    if (gxtc->win)
+	XDestroyWindow (gxtc->dpy, gxtc->win);
+
+    XCloseDisplay (gxtc->dpy);
+
+    free (gxtc);
+}
+
+#endif /* CAIRO_CAN_TEST_GLITZ_GLX_SURFACE */
+
+#if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
+#include <glitz-agl.h>
+
+typedef struct _glitz_agl_target_closure {
+    glitz_target_closure_base_t base;
+} glitz_agl_target_closure_t;
+
+static glitz_surface_t *
+create_glitz_agl_surface (glitz_format_name_t formatname,
+			  int width, int height,
+			  glitz_agl_target_closure_t *closure)
+{
+    glitz_drawable_format_t *dformat;
+    glitz_drawable_format_t templ;
+    glitz_drawable_t *gdraw;
+    glitz_format_t *format;
+    glitz_surface_t *sr = NULL;
+    unsigned long mask;
+
+    memset(&templ, 0, sizeof(templ));
+    templ.color.red_size = 8;
+    templ.color.green_size = 8;
+    templ.color.blue_size = 8;
+    templ.color.alpha_size = 8;
+    templ.color.fourcc = GLITZ_FOURCC_RGB;
+    templ.samples = 1;
+
+    mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
+	GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
+	GLITZ_FORMAT_BLUE_SIZE_MASK;
+    if (formatname == GLITZ_STANDARD_ARGB32)
+	mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
+
+    dformat = glitz_agl_find_pbuffer_format (mask, &templ, 0);
+    if (!dformat) {
+	CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template.");
+	goto FAIL;
+    }
+
+    gdraw = glitz_agl_create_pbuffer_drawable (dformat, width, height);
+    if (!gdraw) {
+	CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable.");
+	goto FAIL;
+    }
+
+    format = glitz_find_standard_format (gdraw, formatname);
+    if (!format) {
+	CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable.");
+	goto DESTROY_DRAWABLE;
+    }
+
+    sr = glitz_surface_create (gdraw, format, width, height, 0, NULL);
+    if (!sr) {
+	CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface.");
+	goto DESTROY_DRAWABLE;
+    }
+
+    glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
+
+ DESTROY_DRAWABLE:
+    glitz_drawable_destroy (gdraw);
+
+ FAIL:
+    return sr; /* will be NULL unless we create it and attach */
+}
+
+static cairo_surface_t *
+create_cairo_glitz_agl_surface (const char	 *name,
+				cairo_content_t   content,
+				int		  width,
+				int		  height,
+				void		**closure)
+{
+    glitz_surface_t *glitz_surface;
+    cairo_surface_t *surface;
+    glitz_agl_target_closure_t *aglc;
+
+    glitz_agl_init ();
+
+    *closure = aglc = xmalloc (sizeof (glitz_agl_target_closure_t));
+
+    switch (content) {
+    case CAIRO_CONTENT_COLOR:
+	glitz_surface = create_glitz_agl_surface (GLITZ_STANDARD_RGB24, width, height, NULL);
+	break;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	glitz_surface = create_glitz_agl_surface (GLITZ_STANDARD_ARGB32, width, height, NULL);
+	break;
+    default:
+	CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-agl test: %d\n", content);
+	goto FAIL;
+    }
+
+    if (!glitz_surface)
+	goto FAIL;
+
+    surface = cairo_glitz_surface_create (glitz_surface);
+
+    aglc->base.width = width;
+    aglc->base.height = height;
+    aglc->base.content = content;
+    cairo_surface_set_user_data (surface, &glitz_closure_key, aglc, NULL);
+
+    return surface;
+
+ FAIL:
+    return NULL;
+}
+
+static void
+cleanup_cairo_glitz_agl (void *closure)
+{
+    free (closure);
+    glitz_agl_fini ();
+}
+
+#endif /* CAIRO_CAN_TEST_GLITZ_AGL_SURFACE */
+
+#if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE
+#include <glitz-wgl.h>
+
+typedef struct _glitz_wgl_target_closure {
+    glitz_target_closure_base_t base;
+} glitz_wgl_target_closure_t;
+
+static glitz_surface_t *
+create_glitz_wgl_surface (glitz_format_name_t formatname,
+			  int width, int height,
+			  glitz_wgl_target_closure_t *closure)
+{
+    glitz_drawable_format_t *dformat;
+    glitz_drawable_format_t templ;
+    glitz_drawable_t *gdraw;
+    glitz_format_t *format;
+    glitz_surface_t *sr = NULL;
+    unsigned long mask;
+
+    memset(&templ, 0, sizeof(templ));
+    templ.color.red_size = 8;
+    templ.color.green_size = 8;
+    templ.color.blue_size = 8;
+    templ.color.alpha_size = 8;
+    templ.color.fourcc = GLITZ_FOURCC_RGB;
+    templ.samples = 1;
+
+    mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
+	GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
+	GLITZ_FORMAT_BLUE_SIZE_MASK;
+    if (formatname == GLITZ_STANDARD_ARGB32)
+	mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
+
+    dformat = glitz_wgl_find_pbuffer_format (mask, &templ, 0);
+    if (!dformat) {
+	CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template.");
+	goto FAIL;
+    }
+
+    gdraw = glitz_wgl_create_pbuffer_drawable (dformat, width, height);
+    if (!gdraw) {
+	CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable.");
+	goto FAIL;
+    }
+
+    format = glitz_find_standard_format (gdraw, formatname);
+    if (!format) {
+	CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable.");
+	goto DESTROY_DRAWABLE;
+    }
+
+    sr = glitz_surface_create (gdraw, format, width, height, 0, NULL);
+    if (!sr) {
+	CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface.");
+	goto DESTROY_DRAWABLE;
+    }
+
+    glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
+
+ DESTROY_DRAWABLE:
+    glitz_drawable_destroy (gdraw);
+
+ FAIL:
+    return sr; /* will be NULL unless we create it and attach */
+}
+
+static cairo_surface_t *
+create_cairo_glitz_wgl_surface (const char	 *name,
+				cairo_content_t	  content,
+				int		  width,
+				int		  height,
+				void		**closure)
+{
+    glitz_surface_t *glitz_surface;
+    cairo_surface_t *surface;
+    glitz_wgl_target_closure_t *wglc;
+
+    glitz_wgl_init (NULL);
+
+    *closure = wglc = xmalloc (sizeof (glitz_wgl_target_closure_t));
+
+    switch (content) {
+    case CAIRO_CONTENT_COLOR:
+	glitz_surface = create_glitz_wgl_surface (GLITZ_STANDARD_RGB24, width, height, NULL);
+	break;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	glitz_surface = create_glitz_wgl_surface (GLITZ_STANDARD_ARGB32, width, height, NULL);
+	break;
+    default:
+	CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-wgl test: %d\n", content);
+	goto FAIL;
+    }
+
+    if (!glitz_surface)
+	goto FAIL;
+
+    surface = cairo_glitz_surface_create (glitz_surface);
+
+    wglc->base.width = width;
+    wglc->base.height = height;
+    wglc->base.content = content;
+    cairo_surface_set_user_data (surface, &glitz_closure_key, wglc, NULL);
+
+    return surface;
+
+ FAIL:
+    return NULL;
+}
+
+static void
+cleanup_cairo_glitz_wgl (void *closure)
+{
+    free (closure);
+    glitz_wgl_fini ();
+}
+
+#endif /* CAIRO_CAN_TEST_GLITZ_WGL_SURFACE */
+
+#endif /* CAIRO_HAS_GLITZ_SURFACE */
+
+#if 0 && CAIRO_HAS_QUARTZ_SURFACE
+static cairo_surface_t *
+create_quartz_surface (int width, int height, void **closure)
+{
+#error Not yet implemented
+}
+
+static void
+cleanup_quartz (void *closure)
+{
+#error Not yet implemented
+}
+#endif
+
+/* Testing the win32 surface isn't interesting, since for
+ * ARGB images it just chains to the image backend
+ */
+#if CAIRO_HAS_WIN32_SURFACE
+#include "cairo-win32.h"
+typedef struct _win32_target_closure
+{
+  HDC dc;
+  HBITMAP bmp;
+} win32_target_closure_t;
+
+static cairo_surface_t *
+create_win32_surface (const char	 *name,
+		      cairo_content_t	  content,
+		      int		  width,
+		      int		  height,
+		      void		**closure)
+{
+    int width = width;
+    int height = height;
+
+    BITMAPINFO bmpInfo;
+    unsigned char *bits = NULL;
+    win32_target_closure_t *data = malloc(sizeof(win32_target_closure_t));
+    *closure = data;
+
+    data->dc = CreateCompatibleDC(NULL);
+
+    /* initialize the bitmapinfoheader */
+    memset(&bmpInfo.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
+    bmpInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+    bmpInfo.bmiHeader.biWidth = width;
+    bmpInfo.bmiHeader.biHeight = -height;
+    bmpInfo.bmiHeader.biPlanes = 1;
+    bmpInfo.bmiHeader.biBitCount = 24;
+    bmpInfo.bmiHeader.biCompression = BI_RGB;
+
+    /* create a DIBSection */
+    data->bmp = CreateDIBSection(data->dc, &bmpInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+
+    /* Flush GDI to make sure the DIBSection is actually created */
+    GdiFlush();
+
+    /* Select the bitmap in to the DC */
+    SelectObject(data->dc, data->bmp);
+
+    return cairo_win32_surface_create(data->dc);
+}
+
+static void
+cleanup_win32 (void *closure)
+{
+  win32_target_closure_t *data = (win32_target_closure_t*)closure;
+  DeleteObject(data->bmp);
+  DeleteDC(data->dc);
+
+  free(closure);
+}
+#endif
+
+#if CAIRO_HAS_XCB_SURFACE
+#include "cairo-xcb-xrender.h"
+typedef struct _xcb_target_closure
+{
+    XCBConnection *c;
+    XCBDRAWABLE drawable;
+} xcb_target_closure_t;
+
+/* XXX: This is a nasty hack. Something like this should be in XCB's
+ * bindings for Render, not here in this test. */
+static XCBRenderPICTFORMINFO
+_format_from_cairo(XCBConnection *c, cairo_format_t fmt)
+{
+    XCBRenderPICTFORMINFO ret = {{ 0 }};
+    struct tmpl_t {
+	XCBRenderDIRECTFORMAT direct;
+	CARD8 depth;
+    };
+    static const struct tmpl_t templates[] = {
+	/* CAIRO_FORMAT_ARGB32 */
+	{
+	    {
+		16, 0xff,
+		8,  0xff,
+		0,  0xff,
+		24, 0xff
+	    },
+	    32
+	},
+	/* CAIRO_FORMAT_RGB24 */
+	{
+	    {
+		16, 0xff,
+		8,  0xff,
+		0,  0xff,
+		0,  0x00
+	    },
+	    24
+	},
+	/* CAIRO_FORMAT_A8 */
+	{
+	    {
+		0,  0x00,
+		0,  0x00,
+		0,  0x00,
+		0,  0xff
+	    },
+	    8
+	},
+	/* CAIRO_FORMAT_A1 */
+	{
+	    {
+		0,  0x00,
+		0,  0x00,
+		0,  0x00,
+		0,  0x01
+	    },
+	    1
+	},
+    };
+    const struct tmpl_t *tmpl;
+    XCBRenderQueryPictFormatsRep *r;
+    XCBRenderPICTFORMINFOIter fi;
+
+    if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates)))
+	return ret;
+    tmpl = templates + fmt;
+
+    r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
+    if(!r)
+	return ret;
+
+    for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
+    {
+	const XCBRenderDIRECTFORMAT *t, *f;
+	if(fi.data->type != XCBRenderPictTypeDirect)
+	    continue;
+	if(fi.data->depth != tmpl->depth)
+	    continue;
+	t = &tmpl->direct;
+	f = &fi.data->direct;
+	if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift))
+	    continue;
+	if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift))
+	    continue;
+	if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift))
+	    continue;
+	if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
+	    continue;
+
+	ret = *fi.data;
+    }
+
+    free(r);
+    return ret;
+}
+
+static cairo_surface_t *
+create_xcb_surface (const char		 *name,
+		    cairo_content_t	  content,
+		    int			  width,
+		    int			  height,
+		    void		**closure)
+{
+    int width = width;
+    int height = height;
+    XCBSCREEN *root;
+    xcb_target_closure_t *xtc;
+    cairo_surface_t *surface;
+    XCBConnection *c;
+    XCBRenderPICTFORMINFO render_format;
+    cairo_format_t format;
+
+    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+    if (width == 0)
+	width = 1;
+    if (height == 0)
+	height = 1;
+
+    xtc->c = c = XCBConnect(NULL,NULL);
+    if (c == NULL) {
+	CAIRO_BOILERPLATE_LOG ("Failed to connect to X server through XCB\n");
+	return NULL;
+    }
+
+    root = XCBSetupRootsIter(XCBGetSetup(c)).data;
+
+    xtc->drawable.pixmap = XCBPIXMAPNew (c);
+    {
+	XCBDRAWABLE root_drawable;
+	root_drawable.window = root->root;
+	XCBCreatePixmap (c, 32, xtc->drawable.pixmap, root_drawable,
+			 width, height);
+    }
+
+    switch (content) {
+    case CAIRO_CONTENT_COLOR:
+	format = CAIRO_FORMAT_RGB24;
+	break;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	format = CAIRO_FORMAT_ARGB32;
+	break;
+    default:
+	CAIRO_BOILERPLATE_LOG ("Invalid content for XCB test: %d\n", content);
+	return NULL;
+    }
+
+    render_format = _format_from_cairo (c, format);
+    if (render_format.id.xid == 0)
+	return NULL;
+    surface = cairo_xcb_surface_create_with_xrender_format (c, xtc->drawable, root,
+							    &render_format,
+							    width, height);
+
+    return surface;
+}
+
+static void
+cleanup_xcb (void *closure)
+{
+    xcb_target_closure_t *xtc = closure;
+
+    XCBFreePixmap (xtc->c, xtc->drawable.pixmap);
+    XCBDisconnect (xtc->c);
+    free (xtc);
+}
+#endif
+
+#if CAIRO_HAS_XLIB_SURFACE
+#include "cairo-xlib-xrender.h"
+typedef struct _xlib_target_closure
+{
+    Display *dpy;
+    Pixmap pixmap;
+} xlib_target_closure_t;
+
+static cairo_surface_t *
+create_xlib_surface (const char		 *name,
+		     cairo_content_t	  content,
+		     int		  width,
+		     int		  height,
+		     void		**closure)
+{
+    xlib_target_closure_t *xtc;
+    cairo_surface_t *surface;
+    Display *dpy;
+    XRenderPictFormat *xrender_format;
+
+    *closure = xtc = xmalloc (sizeof (xlib_target_closure_t));
+
+    if (width == 0)
+	width = 1;
+    if (height == 0)
+	height = 1;
+
+    xtc->dpy = dpy = XOpenDisplay (NULL);
+    if (xtc->dpy == NULL) {
+	CAIRO_BOILERPLATE_LOG ("Failed to open display: %s\n", XDisplayName(0));
+	return NULL;
+    }
+
+    XSynchronize (xtc->dpy, 1);
+
+    /* XXX: Currently we don't do any xlib testing when the X server
+     * doesn't have the Render extension. We could do better here,
+     * (perhaps by converting the tests from ARGB32 to RGB24). One
+     * step better would be to always test the non-Render fallbacks
+     * for each test even if the server does have the Render
+     * extension. That would probably be through another
+     * cairo_test_target which would use an extended version of
+     * cairo_test_xlib_disable_render.  */
+    switch (content) {
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
+	break;
+    case CAIRO_CONTENT_COLOR:
+	xrender_format = XRenderFindStandardFormat (dpy, PictStandardRGB24);
+	break;
+    case CAIRO_CONTENT_ALPHA:
+    default:
+	CAIRO_BOILERPLATE_LOG ("Invalid content for xlib test: %d\n", content);
+	return NULL;
+    }
+    if (xrender_format == NULL) {
+	CAIRO_BOILERPLATE_LOG ("X server does not have the Render extension.\n");
+	return NULL;
+    }
+
+    xtc->pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy),
+				 width, height, xrender_format->depth);
+
+    surface = cairo_xlib_surface_create_with_xrender_format (dpy, xtc->pixmap,
+							     DefaultScreenOfDisplay (dpy),
+							     xrender_format,
+							     width, height);
+    return surface;
+}
+
+static void
+cleanup_xlib (void *closure)
+{
+    xlib_target_closure_t *xtc = closure;
+
+    XFreePixmap (xtc->dpy, xtc->pixmap);
+    XCloseDisplay (xtc->dpy);
+    free (xtc);
+}
+#endif
+
+#if CAIRO_HAS_BEOS_SURFACE
+/* BeOS test functions are external as they need to be C++ */
+#include "cairo-test-beos.h"
+#endif
+
+#if CAIRO_HAS_DIRECTFB_SURFACE
+#include "cairo-test-directfb.h"
+#endif
+
+#if CAIRO_HAS_PS_SURFACE
+#include "cairo-ps.h"
+
+cairo_user_data_key_t	ps_closure_key;
+
+typedef struct _ps_target_closure
+{
+    char		*filename;
+    int			 width;
+    int			 height;
+    cairo_surface_t	*target;
+} ps_target_closure_t;
+
+static cairo_surface_t *
+create_ps_surface (const char		 *name,
+		   cairo_content_t	  content,
+		   int			  width,
+		   int			  height,
+		   void			**closure)
+{
+    ps_target_closure_t	*ptc;
+    cairo_surface_t *surface;
+    int i;
+
+    for (i = 0; vector_ignored_tests[i] != NULL; i++)
+	if (strcmp (name, vector_ignored_tests[i]) == 0)
+	    return NULL;
+
+    /* Sanitize back to a real cairo_content_t value. */
+    if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
+	content = CAIRO_CONTENT_COLOR_ALPHA;
+
+    *closure = ptc = xmalloc (sizeof (ps_target_closure_t));
+
+    xasprintf (&ptc->filename, "%s-ps-%s-out.ps",
+	       name, _cairo_test_content_name (content));
+
+    ptc->width = width;
+    ptc->height = height;
+
+    surface = cairo_ps_surface_create (ptc->filename, width, height);
+    if (cairo_surface_status (surface)) {
+	free (ptc->filename);
+	free (ptc);
+	return NULL;
+    }
+    cairo_surface_set_fallback_resolution (surface, 72., 72.);
+
+    if (content == CAIRO_CONTENT_COLOR) {
+	ptc->target = surface;
+	surface = cairo_surface_create_similar (ptc->target,
+						CAIRO_CONTENT_COLOR,
+						width, height);
+    } else {
+	ptc->target = NULL;
+    }
+
+    cairo_surface_set_user_data (surface, &ps_closure_key, ptc, NULL);
+
+    return surface;
+}
+
+static cairo_status_t
+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];
+
+    /* Both surface and ptc->target were originally created at the
+     * same dimensions. We want a 1:1 copy here, so we first clear any
+     * device offset on surface.
+     *
+     * In a more realistic use case of device offsets, the target of
+     * this copying would be of a different size than the source, and
+     * the offset would be desirable during the copy operation. */
+    cairo_surface_set_device_offset (surface, 0, 0);
+
+    if (ptc->target) {
+	cairo_t *cr;
+	cr = cairo_create (ptc->target);
+	cairo_set_source_surface (cr, surface, 0, 0);
+	cairo_paint (cr);
+	cairo_show_page (cr);
+	cairo_destroy (cr);
+
+	cairo_surface_finish (surface);
+	surface = ptc->target;
+    }
+
+    cairo_surface_finish (surface);
+    sprintf (command, "gs -q -r72 -g%dx%d -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=%s %s",
+	     ptc->width, ptc->height, filename, ptc->filename);
+    if (system (command) == 0)
+	return CAIRO_STATUS_SUCCESS;
+    return CAIRO_STATUS_WRITE_ERROR;
+}
+
+static void
+cleanup_ps (void *closure)
+{
+    ps_target_closure_t *ptc = closure;
+    if (ptc->target)
+	cairo_surface_destroy (ptc->target);
+    free (ptc->filename);
+    free (ptc);
+}
+#endif /* CAIRO_HAS_PS_SURFACE */
+
+#if CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE
+#include "cairo-pdf.h"
+
+cairo_user_data_key_t pdf_closure_key;
+
+typedef struct _pdf_target_closure
+{
+    char		*filename;
+    int			 width;
+    int			 height;
+    cairo_surface_t	*target;
+} pdf_target_closure_t;
+
+static cairo_surface_t *
+create_pdf_surface (const char		 *name,
+		    cairo_content_t	  content,
+		    int			  width,
+		    int			  height,
+		    void		**closure)
+{
+    int width = width;
+    int height = height;
+    pdf_target_closure_t *ptc;
+    cairo_surface_t *surface;
+    int i;
+
+    for (i = 0; vector_ignored_tests[i] != NULL; i++)
+	if (strcmp (name, vector_ignored_tests[i]) == 0)
+	    return NULL;
+
+    /* Sanitize back to a real cairo_content_t value. */
+    if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
+	content = CAIRO_CONTENT_COLOR_ALPHA;
+
+    *closure = ptc = xmalloc (sizeof (pdf_target_closure_t));
+
+    ptc->width = width;
+    ptc->height = height;
+
+    xasprintf (&ptc->filename, "%s-pdf-%s-out.pdf",
+	       name, _cairo_test_content_name (content));
+
+    surface = cairo_pdf_surface_create (ptc->filename, width, height);
+    if (cairo_surface_status (surface)) {
+	free (ptc->filename);
+	free (ptc);
+	return NULL;
+    }
+    cairo_surface_set_fallback_resolution (surface, 72., 72.);
+
+    if (content == CAIRO_CONTENT_COLOR) {
+	ptc->target = surface;
+	surface = cairo_surface_create_similar (ptc->target,
+						CAIRO_CONTENT_COLOR,
+						width, height);
+    } else {
+	ptc->target = NULL;
+    }
+
+    cairo_surface_set_user_data (surface, &pdf_closure_key, ptc, NULL);
+
+    return surface;
+}
+
+static cairo_status_t
+pdf_surface_write_to_png (cairo_surface_t *surface, const char *filename)
+{
+    pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, &pdf_closure_key);
+    char    command[4096];
+
+    /* Both surface and ptc->target were originally created at the
+     * same dimensions. We want a 1:1 copy here, so we first clear any
+     * device offset on surface.
+     *
+     * In a more realistic use case of device offsets, the target of
+     * this copying would be of a different size than the source, and
+     * the offset would be desirable during the copy operation. */
+    cairo_surface_set_device_offset (surface, 0, 0);
+
+    if (ptc->target) {
+	cairo_t *cr;
+	cr = cairo_create (ptc->target);
+	cairo_set_source_surface (cr, surface, 0, 0);
+	cairo_paint (cr);
+	cairo_show_page (cr);
+	cairo_destroy (cr);
+
+	cairo_surface_finish (surface);
+	surface = ptc->target;
+    }
+
+    cairo_surface_finish (surface);
+    sprintf (command, "./pdf2png %s %s 1",
+	     ptc->filename, filename);
+
+    if (system (command) != 0)
+	return CAIRO_STATUS_WRITE_ERROR;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+cleanup_pdf (void *closure)
+{
+    pdf_target_closure_t *ptc = closure;
+    if (ptc->target)
+	cairo_surface_destroy (ptc->target);
+    free (ptc->filename);
+    free (ptc);
+}
+#endif /* CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE */
+
+#if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE
+#include "cairo-svg.h"
+
+cairo_user_data_key_t	svg_closure_key;
+
+typedef struct _svg_target_closure
+{
+    char    *filename;
+    int	    width, height;
+    cairo_surface_t	*target;
+} svg_target_closure_t;
+
+static cairo_surface_t *
+create_svg_surface (const char		 *name,
+		    cairo_content_t	  content,
+		    int			  width,
+		    int			  height,
+		    void		**closure)
+{
+    int width = width;
+    int height = height;
+    int i;
+    svg_target_closure_t *ptc;
+    cairo_surface_t *surface;
+
+    for (i = 0; vector_ignored_tests[i] != NULL; i++)
+	if (strcmp (name, vector_ignored_tests[i]) == 0)
+	    return NULL;
+
+    *closure = ptc = xmalloc (sizeof (svg_target_closure_t));
+
+    ptc->width = width;
+    ptc->height = height;
+
+    xasprintf (&ptc->filename, "%s-svg-%s-out.svg",
+	       name, _cairo_test_content_name (content));
+
+    surface = cairo_svg_surface_create (ptc->filename, width, height);
+    if (cairo_surface_status (surface)) {
+	free (ptc->filename);
+	free (ptc);
+	return NULL;
+    }
+    cairo_surface_set_fallback_resolution (surface, 72., 72.);
+
+    if (content == CAIRO_CONTENT_COLOR) {
+	ptc->target = surface;
+	surface = cairo_surface_create_similar (ptc->target,
+						CAIRO_CONTENT_COLOR,
+						width, height);
+    } else {
+	ptc->target = NULL;
+    }
+
+    cairo_surface_set_user_data (surface, &svg_closure_key, ptc, NULL);
+
+    return surface;
+}
+
+static cairo_status_t
+svg_surface_write_to_png (cairo_surface_t *surface, const char *filename)
+{
+    svg_target_closure_t *ptc = cairo_surface_get_user_data (surface, &svg_closure_key);
+    char    command[4096];
+
+    /* Both surface and ptc->target were originally created at the
+     * same dimensions. We want a 1:1 copy here, so we first clear any
+     * device offset on surface.
+     *
+     * In a more realistic use case of device offsets, the target of
+     * this copying would be of a different size than the source, and
+     * the offset would be desirable during the copy operation. */
+    cairo_surface_set_device_offset (surface, 0, 0);
+
+    if (ptc->target) {
+	cairo_t *cr;
+	cr = cairo_create (ptc->target);
+	cairo_set_source_surface (cr, surface, 0, 0);
+	cairo_paint (cr);
+	cairo_show_page (cr);
+	cairo_destroy (cr);
+
+	cairo_surface_finish (surface);
+	surface = ptc->target;
+    }
+
+    cairo_surface_finish (surface);
+    sprintf (command, "./svg2png %s %s",
+	     ptc->filename, filename);
+
+    if (system (command) != 0)
+	return CAIRO_STATUS_WRITE_ERROR;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+cleanup_svg (void *closure)
+{
+    svg_target_closure_t *ptc = closure;
+    if (ptc->target)
+	cairo_surface_destroy (ptc->target);
+    free (ptc->filename);
+    free (ptc);
+}
+#endif /* CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE */
+
+cairo_test_target_t targets[] =
+{
+    { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA,
+      create_image_surface, cairo_surface_write_to_png, NULL},
+    { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR,
+      create_image_surface, cairo_surface_write_to_png, NULL},
+#ifdef CAIRO_HAS_TEST_SURFACES
+    { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+      CAIRO_CONTENT_COLOR_ALPHA,
+      create_test_fallback_surface, cairo_surface_write_to_png, NULL },
+    { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+      CAIRO_CONTENT_COLOR,
+      create_test_fallback_surface, cairo_surface_write_to_png, NULL },
+    { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+      CAIRO_CONTENT_COLOR_ALPHA,
+      create_test_meta_surface, cairo_surface_write_to_png, NULL },
+    { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+      CAIRO_CONTENT_COLOR,
+      create_test_meta_surface, cairo_surface_write_to_png, NULL },
+    { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+      CAIRO_CONTENT_COLOR_ALPHA,
+      create_test_paginated_surface,
+      test_paginated_write_to_png,
+      cleanup_test_paginated },
+    { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+      CAIRO_CONTENT_COLOR,
+      create_test_paginated_surface,
+      test_paginated_write_to_png,
+      cleanup_test_paginated },
+#endif
+#ifdef CAIRO_HAS_GLITZ_SURFACE
+#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
+    { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ,CAIRO_CONTENT_COLOR_ALPHA,
+      create_cairo_glitz_glx_surface, cairo_surface_write_to_png,
+      cleanup_cairo_glitz_glx },
+    { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR,
+      create_cairo_glitz_glx_surface, cairo_surface_write_to_png,
+      cleanup_cairo_glitz_glx },
+#endif
+#if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
+    { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA,
+      create_cairo_glitz_agl_surface, cairo_surface_write_to_png,
+      cleanup_cairo_glitz_agl },
+    { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR,
+      create_cairo_glitz_agl_surface, cairo_surface_write_to_png,
+      cleanup_cairo_glitz_agl },
+#endif
+#if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE
+    { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA,
+      create_cairo_glitz_wgl_surface, cairo_surface_write_to_png,
+      cleanup_cairo_glitz_wgl },
+    { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR,
+      create_cairo_glitz_wgl_surface, cairo_surface_write_to_png,
+      cleanup_cairo_glitz_wgl },
+#endif
+#endif /* CAIRO_HAS_GLITZ_SURFACE */
+#if 0 && CAIRO_HAS_QUARTZ_SURFACE
+    { "quartz", CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR,
+      create_quartz_surface, cairo_surface_write_to_png,
+      cleanup_quartz },
+#endif
+#if CAIRO_HAS_WIN32_SURFACE
+    { "win32", CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR,
+      create_win32_surface, cairo_surface_write_to_png, cleanup_win32 },
+#endif
+#if CAIRO_HAS_XCB_SURFACE
+    { "xcb", CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA,
+      create_xcb_surface, cairo_surface_write_to_png, cleanup_xcb},
+#endif
+#if CAIRO_HAS_XLIB_SURFACE
+    { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA,
+      create_xlib_surface, cairo_surface_write_to_png, cleanup_xlib},
+    { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR,
+      create_xlib_surface, cairo_surface_write_to_png, cleanup_xlib},
+#endif
+#if CAIRO_HAS_PS_SURFACE
+    { "ps", CAIRO_SURFACE_TYPE_PS,
+      CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED,
+      create_ps_surface, ps_surface_write_to_png, cleanup_ps },
+
+    /* XXX: We expect type image here only due to a limitation in
+     * the current PS/meta-surface code. A PS surface is
+     * "naturally" COLOR_ALPHA, so the COLOR-only variant goes
+     * through create_similar in create_ps_surface which results
+     * in the similar surface being used as a source. We do not yet
+     * have source support for PS/meta-surfaces, so the
+     * create_similar path for all paginated surfaces currently
+     * returns an image surface.*/
+    { "ps", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR,
+      create_ps_surface, ps_surface_write_to_png, cleanup_ps },
+#endif
+#if CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE
+    { "pdf", CAIRO_SURFACE_TYPE_PDF,
+      CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED,
+      create_pdf_surface, pdf_surface_write_to_png, cleanup_pdf },
+
+    /* XXX: We expect type image here only due to a limitation in
+     * the current PDF/meta-surface code. A PDF surface is
+     * "naturally" COLOR_ALPHA, so the COLOR-only variant goes
+     * through create_similar in create_pdf_surface which results
+     * in the similar surface being used as a source. We do not yet
+     * have source support for PDF/meta-surfaces, so the
+     * create_similar path for all paginated surfaces currently
+     * returns an image surface.*/
+    { "pdf", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR,
+      create_pdf_surface, pdf_surface_write_to_png, cleanup_pdf },
+#endif
+#if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE
+    { "svg", CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA,
+      create_svg_surface, svg_surface_write_to_png, cleanup_svg },
+    { "svg", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR,
+      create_svg_surface, svg_surface_write_to_png, cleanup_svg },
+#endif
+#if CAIRO_HAS_BEOS_SURFACE
+    { "beos", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR,
+      create_beos_surface, cairo_surface_write_to_png, cleanup_beos},
+    { "beos-bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR,
+      create_beos_bitmap_surface, cairo_surface_write_to_png, cleanup_beos_bitmap},
+    { "beos-bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR_ALPHA,
+      create_beos_bitmap_surface, cairo_surface_write_to_png, cleanup_beos_bitmap},
+#endif
+
+#if CAIRO_HAS_DIRECTFB_SURFACE
+    { "directfb", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR,
+      create_directfb_surface, cairo_surface_write_to_png, cleanup_directfb},
+    { "directfb-bitmap", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR_ALPHA,
+      create_directfb_bitmap_surface, cairo_surface_write_to_png,cleanup_directfb},
+#endif
+
+    { NULL }
+};
+
+void
+xasprintf (char **strp, const char *fmt, ...)
+{
+#ifdef HAVE_VASPRINTF
+    va_list va;
+    int ret;
+
+    va_start (va, fmt);
+    ret = vasprintf (strp, fmt, va);
+    va_end (va);
+
+    if (ret < 0) {
+	cairo_test_log ("Out of memory\n");
+	exit (1);
+    }
+#else /* !HAVE_VASNPRINTF */
+#define BUF_SIZE 1024
+    va_list va;
+    char buffer[BUF_SIZE];
+    int ret;
+
+    va_start (va, fmt);
+    ret = vsnprintf (buffer, sizeof(buffer), fmt, va);
+    va_end (va);
+
+    if (ret < 0) {
+	CAIRO_BOILERPLATE_LOG ("Failure in vsnprintf\n");
+	exit (1);
+    }
+
+    if (strlen (buffer) == sizeof(buffer) - 1) {
+	CAIRO_BOILERPLATE_LOG ("Overflowed fixed buffer\n");
+	exit (1);
+    }
+
+    *strp = strdup (buffer);
+    if (!*strp) {
+	CAIRO_BOILERPLATE_LOG ("Out of memory\n");
+	exit (1);
+    }
+#endif /* !HAVE_VASNPRINTF */
+}
diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h
new file mode 100644
index 0000000..183f6a2
--- /dev/null
+++ b/boilerplate/cairo-boilerplate.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2004-2006 Red Hat, Inc.
+ *
+ * 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
+ * Red Hat, Inc. 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.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth at cworth.org>
+ */
+
+#ifndef _CAIRO_BOILERPLATE_H_
+#define _CAIRO_BOILERPLATE_H_
+
+#include <cairo.h>
+
+#include "xmalloc.h"
+
+#ifndef CAIRO_BOILERPLATE_LOG
+#define CAIRO_BOILERPLATE_LOG(...) fprintf(stderr, __VA_ARGS__)
+#endif
+
+/* A fake format we use for the flattened ARGB output of the PS and
+ * PDF surfaces. */
+#define CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED ((unsigned int) -1)
+
+const char *
+_cairo_test_content_name (cairo_content_t content);
+
+typedef cairo_surface_t *
+(*cairo_test_create_target_surface_t) (const char	 *name,
+				       cairo_content_t	  content,
+				       int		  width,
+				       int		  height,
+				       void		**closure);
+
+typedef cairo_status_t
+(*cairo_test_write_to_png_t) (cairo_surface_t *surface, const char *filename);
+
+typedef void
+(*cairo_test_cleanup_target_t) (void *closure);
+
+typedef struct _cairo_test_target
+{
+    const char		       	       *name;
+    cairo_surface_type_t		expected_type;
+    cairo_content_t			content;
+    cairo_test_create_target_surface_t	create_target_surface;
+    cairo_test_write_to_png_t		write_to_png;
+    cairo_test_cleanup_target_t		cleanup_target;
+    void			       *closure;
+} cairo_test_target_t;
+
+extern cairo_test_target_t targets[];
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
+	__attribute__((__format__(__printf__, fmt_index, va_index)))
+#else
+#define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
+#endif
+
+void
+xasprintf (char **strp, const char *fmt, ...) CAIRO_PRINTF_FORMAT(2, 3);
+
+#endif
diff --git a/boilerplate/cairo-test.c b/boilerplate/cairo-test.c
index bf52f8a..0243edf 100644
--- a/boilerplate/cairo-test.c
+++ b/boilerplate/cairo-test.c
@@ -67,19 +67,6 @@ typedef enum cairo_internal_surface_type
     CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED
 } cairo_internal_surface_type_t;
 
-static const char *vector_ignored_tests[] = {
-    /* We can't match the results of tests that depend on
-     * CAIRO_ANTIALIAS_NONE/SUBPIXEL for vector backends
-     * (nor do we care). */
-    "ft-text-antialias-none",
-    "rectangle-rounding-error",
-    "text-antialias-gray",
-    "text-antialias-none",
-    "text-antialias-subpixel",
-    "unantialiased-shapes",
-    NULL
-};
-
 #ifdef _MSC_VER
 #define vsnprintf _vsnprintf
 #define access _access
@@ -104,10 +91,6 @@ static const char *fail_face = "", *norm
 
 #define NUM_DEVICE_OFFSETS 2
 
-/* A fake format we use for the flattened ARGB output of the PS and
- * PDF surfaces. */
-#define CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED ((unsigned int) -1)
-
 /* Static data is messy, but we're coding for tests here, not a
  * general-purpose library, and it keeps the tests cleaner to avoid a
  * context object there, (though not a whole lot). */
@@ -148,49 +131,6 @@ cairo_test_log (const char *fmt, ...)
     va_end (va);
 }
 
-void
-xasprintf (char **strp, const char *fmt, ...)
-{
-#ifdef HAVE_VASPRINTF
-    va_list va;
-    int ret;
-
-    va_start (va, fmt);
-    ret = vasprintf (strp, fmt, va);
-    va_end (va);
-
-    if (ret < 0) {
-	cairo_test_log ("Out of memory\n");
-	exit (1);
-    }
-#else /* !HAVE_VASNPRINTF */
-#define BUF_SIZE 1024
-    va_list va;
-    char buffer[BUF_SIZE];
-    int ret;
-
-    va_start (va, fmt);
-    ret = vsnprintf (buffer, sizeof(buffer), fmt, va);
-    va_end (va);
-
-    if (ret < 0) {
-	cairo_test_log ("Failure in vsnprintf\n");
-	exit (1);
-    }
-
-    if (strlen (buffer) == sizeof(buffer) - 1) {
-	cairo_test_log ("Overflowed fixed buffer\n");
-	exit (1);
-    }
-
-    *strp = strdup (buffer);
-    if (!*strp) {
-	cairo_test_log ("Out of memory\n");
-	exit (1);
-    }
-#endif /* !HAVE_VASNPRINTF */
-}
-
 static void
 xunlink (const char *pathname)
 {
@@ -201,1285 +141,6 @@ xunlink (const char *pathname)
     }
 }
 
-typedef cairo_surface_t *
-(*cairo_test_create_target_surface_t) (cairo_test_t	 *test,
-				       cairo_content_t	  content,
-				       void		**closure);
-
-typedef cairo_status_t
-(*cairo_test_write_to_png_t) (cairo_surface_t *surface, const char *filename);
-
-typedef void
-(*cairo_test_cleanup_target_t) (void *closure);
-
-typedef struct _cairo_test_target
-{
-    const char		       	       *name;
-    cairo_surface_type_t		expected_type;
-    cairo_content_t			content;
-    cairo_test_create_target_surface_t	create_target_surface;
-    cairo_test_write_to_png_t		write_to_png;
-    cairo_test_cleanup_target_t		cleanup_target;
-    void			       *closure;
-} cairo_test_target_t;
-
-static const char *
-_cairo_test_content_name (cairo_content_t content)
-{
-    /* For the purpose of the content name, we don't distinguish the
-     * flattened content value.
-     */
-    if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
-	content = CAIRO_CONTENT_COLOR_ALPHA;
-
-    switch (content) {
-    case CAIRO_CONTENT_COLOR:
-	return "rgb24";
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	return "argb32";
-    case CAIRO_CONTENT_ALPHA:
-    default:
-	assert (0); /* not reached */
-	return "---";
-    }
-}
-
-static cairo_surface_t *
-create_image_surface (cairo_test_t	 *test,
-		      cairo_content_t	  content,
-		      void		**closure)
-{
-    cairo_format_t format;
-    *closure = NULL;
-
-    if (content == CAIRO_CONTENT_COLOR_ALPHA) {
-	format = CAIRO_FORMAT_ARGB32;
-    } else if (content == CAIRO_CONTENT_COLOR) {
-	format = CAIRO_FORMAT_RGB24;
-    } else {
-	assert (0); /* not reached */
-	return NULL;
-    }
-
-    return cairo_image_surface_create (format, test->width, test->height);
-}
-
-#ifdef CAIRO_HAS_TEST_SURFACES
-
-#include "test-fallback-surface.h"
-#include "test-meta-surface.h"
-#include "test-paginated-surface.h"
-
-static cairo_surface_t *
-create_test_fallback_surface (cairo_test_t	 *test,
-			      cairo_content_t	  content,
-			      void		**closure)
-{
-    *closure = NULL;
-    return _test_fallback_surface_create (content, test->width, test->height);
-}
-
-static cairo_surface_t *
-create_test_meta_surface (cairo_test_t		 *test,
-			  cairo_content_t	  content,
-			  void			**closure)
-{
-    *closure = NULL;
-    return _test_meta_surface_create (content, test->width, test->height);
-}
-
-static const cairo_user_data_key_t test_paginated_closure_key;
-
-typedef struct {
-    unsigned char *data;
-    cairo_content_t content;
-    int width;
-    int height;
-    int stride;
-} test_paginated_closure_t;
-
-static cairo_surface_t *
-create_test_paginated_surface (cairo_test_t	 *test,
-			       cairo_content_t	  content,
-			       void		**closure)
-{
-    test_paginated_closure_t *tpc;
-    cairo_surface_t *surface;
-
-    *closure = tpc = xmalloc (sizeof (test_paginated_closure_t));
-
-    tpc->content = content;
-    tpc->width = test->width;
-    tpc->height = test->height;
-    tpc->stride = test->width * 4;
-
-    tpc->data = xcalloc (tpc->stride * test->height, 1);
-
-    surface = _test_paginated_surface_create_for_data (tpc->data,
-						       tpc->content,
-						       tpc->width,
-						       tpc->height,
-						       tpc->stride);
-
-    cairo_surface_set_user_data (surface, &test_paginated_closure_key,
-				 tpc, NULL);
-
-    return surface;
-}
-
-/* The only reason we go through all these machinations to write a PNG
- * image is to _really ensure_ that the data actually landed in our
- * buffer through the paginated surface to the test_paginated_surface.
- *
- * If we didn't implement this function then the default
- * cairo_surface_write_to_png would result in the paginated_surface's
- * acquire_source_image function replaying the meta-surface to an
- * intermediate image surface. And in that case the
- * test_paginated_surface would not be involved and wouldn't be
- * tested.
- */
-static cairo_status_t
-test_paginated_write_to_png (cairo_surface_t *surface,
-			     const char	     *filename)
-{
-    cairo_surface_t *image;
-    cairo_format_t format;
-    test_paginated_closure_t *tpc;
-
-    tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key);
-
-    switch (tpc->content) {
-    case CAIRO_CONTENT_COLOR:
-	format = CAIRO_FORMAT_RGB24;
-	break;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	format = CAIRO_FORMAT_ARGB32;
-	break;
-    case CAIRO_CONTENT_ALPHA:
-    default:
-	assert (0); /* not reached */
-	return CAIRO_STATUS_NO_MEMORY;
-    }
-
-    image = cairo_image_surface_create_for_data (tpc->data,
-						 format,
-						 tpc->width,
-						 tpc->height,
-						 tpc->stride);
-
-    cairo_surface_write_to_png (image, filename);
-
-    cairo_surface_destroy (image);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-cleanup_test_paginated (void *closure)
-{
-    test_paginated_closure_t *tpc = closure;
-
-    free (tpc->data);
-    free (tpc);
-}
-
-#endif
-
-#ifdef CAIRO_HAS_GLITZ_SURFACE
-#include <glitz.h>
-#include <cairo-glitz.h>
-
-static const cairo_user_data_key_t glitz_closure_key;
-
-typedef struct _glitz_target_closure_base {
-    int width;
-    int height;
-    cairo_content_t content;
-} glitz_target_closure_base_t;
-
-#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
-#include <glitz-glx.h>
-
-typedef struct _glitz_glx_target_closure {
-    glitz_target_closure_base_t base;
-    Display        *dpy;
-    int             scr;
-    Window          win;
-} glitz_glx_target_closure_t;
-
-static glitz_surface_t *
-create_glitz_glx_surface (glitz_format_name_t	      formatname,
-			  int			      width,
-			  int			      height,
-			  glitz_glx_target_closure_t *closure)
-{
-    Display                 * dpy = closure->dpy;
-    int                       scr = closure->scr;
-    glitz_drawable_format_t   templ;
-    glitz_drawable_format_t * dformat = NULL;
-    unsigned long             mask;
-    glitz_drawable_t        * drawable = NULL;
-    glitz_format_t          * format;
-    glitz_surface_t         * sr;
-
-    XSizeHints                xsh;
-    XSetWindowAttributes      xswa;
-    XVisualInfo             * vinfo;
-
-    memset(&templ, 0, sizeof(templ));
-    templ.color.red_size = 8;
-    templ.color.green_size = 8;
-    templ.color.blue_size = 8;
-    templ.color.alpha_size = 8;
-    templ.color.fourcc = GLITZ_FOURCC_RGB;
-    templ.samples = 1;
-
-    glitz_glx_init (NULL);
-
-    mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
-	GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
-	GLITZ_FORMAT_BLUE_SIZE_MASK;
-    if (formatname == GLITZ_STANDARD_ARGB32)
-	mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
-
-    /* Try for a pbuffer first */
-    if (!getenv("CAIRO_TEST_FORCE_GLITZ_WINDOW"))
-	dformat = glitz_glx_find_pbuffer_format (dpy, scr, mask, &templ, 0);
-
-    if (dformat) {
-	closure->win = None;
-
-	drawable = glitz_glx_create_pbuffer_drawable (dpy, scr, dformat,
-						      width, height);
-	if (!drawable)
-	    goto FAIL;
-    } else {
-	/* No pbuffer, try window */
-	dformat = glitz_glx_find_window_format (dpy, scr, mask, &templ, 0);
-
-	if (!dformat)
-	    goto FAIL;
-
-	vinfo = glitz_glx_get_visual_info_from_format(dpy,
-						      DefaultScreen(dpy),
-						      dformat);
-
-	if (!vinfo)
-	    goto FAIL;
-
-	xsh.flags = PSize;
-	xsh.x = 0;
-	xsh.y = 0;
-	xsh.width = width;
-	xsh.height = height;
-
-	xswa.colormap = XCreateColormap (dpy, RootWindow(dpy, scr),
-					 vinfo->visual, AllocNone);
-	closure->win = XCreateWindow (dpy, RootWindow(dpy, scr),
-				      xsh.x, xsh.y, xsh.width, xsh.height,
-				      0, vinfo->depth, CopyFromParent,
-				      vinfo->visual, CWColormap, &xswa);
-	XFree (vinfo);
-
-	drawable =
-	    glitz_glx_create_drawable_for_window (dpy, scr,
-						  dformat, closure->win,
-						  width, height);
-
-	if (!drawable)
-	    goto DESTROY_WINDOW;
-    }
-
-    format = glitz_find_standard_format (drawable, formatname);
-    if (!format)
-	goto DESTROY_DRAWABLE;
-
-    sr = glitz_surface_create (drawable, format, width, height, 0, NULL);
-    if (!sr)
-	goto DESTROY_DRAWABLE;
-
-    if (closure->win == None || dformat->doublebuffer) {
-	glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_BACK_COLOR);
-    } else {
-	XMapWindow (closure->dpy, closure->win);
-	glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
-    }
-
-    glitz_drawable_destroy (drawable);
-
-    return sr;
- DESTROY_DRAWABLE:
-    glitz_drawable_destroy (drawable);
- DESTROY_WINDOW:
-    if (closure->win)
-	XDestroyWindow (dpy, closure->win);
- FAIL:
-    return NULL;
-}
-
-static cairo_surface_t *
-create_cairo_glitz_glx_surface (cairo_test_t   *test,
-				cairo_content_t content,
-				void    **closure)
-{
-    int width = test->width;
-    int height = test->height;
-    glitz_glx_target_closure_t *gxtc;
-    glitz_surface_t  * glitz_surface;
-    cairo_surface_t  * surface;
-
-    *closure = gxtc = xmalloc (sizeof (glitz_glx_target_closure_t));
-
-    if (width == 0)
-	width = 1;
-    if (height == 0)
-	height = 1;
-
-    gxtc->dpy = XOpenDisplay (getenv("CAIRO_TEST_GLITZ_DISPLAY"));
-    if (!gxtc->dpy) {
-	cairo_test_log ("Failed to open display: %s\n", XDisplayName(0));
-	goto FAIL;
-    }
-
-    XSynchronize (gxtc->dpy, 1);
-
-    gxtc->scr = DefaultScreen(gxtc->dpy);
-
-    switch (content) {
-    case CAIRO_CONTENT_COLOR:
-	glitz_surface = create_glitz_glx_surface (GLITZ_STANDARD_RGB24, width, height, gxtc);
-	break;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	glitz_surface = create_glitz_glx_surface (GLITZ_STANDARD_ARGB32, width, height, gxtc);
-	break;
-    default:
-	cairo_test_log ("Invalid content for glitz-glx test: %d\n", content);
-	goto FAIL_CLOSE_DISPLAY;
-    }
-    if (!glitz_surface) {
-	cairo_test_log ("Failed to create glitz-glx surface\n");
-	goto FAIL_CLOSE_DISPLAY;
-    }
-
-    surface = cairo_glitz_surface_create (glitz_surface);
-
-    gxtc->base.width = test->width;
-    gxtc->base.height = test->height;
-    gxtc->base.content = content;
-    cairo_surface_set_user_data (surface, &glitz_closure_key,
-				 gxtc, NULL);
-
-    return surface;
-
- FAIL_CLOSE_DISPLAY:
-    XCloseDisplay (gxtc->dpy);
- FAIL:
-    return NULL;
-}
-
-static void
-cleanup_cairo_glitz_glx (void *closure)
-{
-    glitz_glx_target_closure_t *gxtc = closure;
-
-    glitz_glx_fini ();
-
-    if (gxtc->win)
-	XDestroyWindow (gxtc->dpy, gxtc->win);
-
-    XCloseDisplay (gxtc->dpy);
-
-    free (gxtc);
-}
-
-#endif /* CAIRO_CAN_TEST_GLITZ_GLX_SURFACE */
-
-#if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
-#include <glitz-agl.h>
-
-typedef struct _glitz_agl_target_closure {
-    glitz_target_closure_base_t base;
-} glitz_agl_target_closure_t;
-
-static glitz_surface_t *
-create_glitz_agl_surface (glitz_format_name_t formatname,
-			  int width, int height,
-			  glitz_agl_target_closure_t *closure)
-{
-    glitz_drawable_format_t *dformat;
-    glitz_drawable_format_t templ;
-    glitz_drawable_t *gdraw;
-    glitz_format_t *format;
-    glitz_surface_t *sr = NULL;
-    unsigned long mask;
-
-    memset(&templ, 0, sizeof(templ));
-    templ.color.red_size = 8;
-    templ.color.green_size = 8;
-    templ.color.blue_size = 8;
-    templ.color.alpha_size = 8;
-    templ.color.fourcc = GLITZ_FOURCC_RGB;
-    templ.samples = 1;
-
-    mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
-	GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
-	GLITZ_FORMAT_BLUE_SIZE_MASK;
-    if (formatname == GLITZ_STANDARD_ARGB32)
-	mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
-
-    dformat = glitz_agl_find_pbuffer_format (mask, &templ, 0);
-    if (!dformat) {
-	cairo_test_log ("Glitz failed to find pbuffer format for template.");
-	goto FAIL;
-    }
-
-    gdraw = glitz_agl_create_pbuffer_drawable (dformat, width, height);
-    if (!gdraw) {
-	cairo_test_log ("Glitz failed to create pbuffer drawable.");
-	goto FAIL;
-    }
-
-    format = glitz_find_standard_format (gdraw, formatname);
-    if (!format) {
-	cairo_test_log ("Glitz failed to find standard format for drawable.");
-	goto DESTROY_DRAWABLE;
-    }
-
-    sr = glitz_surface_create (gdraw, format, width, height, 0, NULL);
-    if (!sr) {
-	cairo_test_log ("Glitz failed to create a surface.");
-	goto DESTROY_DRAWABLE;
-    }
-
-    glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
-
- DESTROY_DRAWABLE:
-    glitz_drawable_destroy (gdraw);
-
- FAIL:
-    return sr; /* will be NULL unless we create it and attach */
-}
-
-static cairo_surface_t *
-create_cairo_glitz_agl_surface (cairo_test_t *test,
-				cairo_content_t content,
-				void **closure)
-{
-    glitz_surface_t *glitz_surface;
-    cairo_surface_t *surface;
-    glitz_agl_target_closure_t *aglc;
-
-    glitz_agl_init ();
-
-    *closure = aglc = xmalloc (sizeof (glitz_agl_target_closure_t));
-
-    switch (content) {
-    case CAIRO_CONTENT_COLOR:
-	glitz_surface = create_glitz_agl_surface (GLITZ_STANDARD_RGB24, test->width, test->height, NULL);
-	break;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	glitz_surface = create_glitz_agl_surface (GLITZ_STANDARD_ARGB32, test->width, test->height, NULL);
-	break;
-    default:
-	cairo_test_log ("Invalid content for glitz-agl test: %d\n", content);
-	goto FAIL;
-    }
-
-    if (!glitz_surface)
-	goto FAIL;
-
-    surface = cairo_glitz_surface_create (glitz_surface);
-
-    aglc->base.width = test->width;
-    aglc->base.height = test->height;
-    aglc->base.content = content;
-    cairo_surface_set_user_data (surface, &glitz_closure_key, aglc, NULL);
-
-    return surface;
-
- FAIL:
-    return NULL;
-}
-
-static void
-cleanup_cairo_glitz_agl (void *closure)
-{
-    free (closure);
-    glitz_agl_fini ();
-}
-
-#endif /* CAIRO_CAN_TEST_GLITZ_AGL_SURFACE */
-
-#if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE
-#include <glitz-wgl.h>
-
-typedef struct _glitz_wgl_target_closure {
-    glitz_target_closure_base_t base;
-} glitz_wgl_target_closure_t;
-
-static glitz_surface_t *
-create_glitz_wgl_surface (glitz_format_name_t formatname,
-			  int width, int height,
-			  glitz_wgl_target_closure_t *closure)
-{
-    glitz_drawable_format_t *dformat;
-    glitz_drawable_format_t templ;
-    glitz_drawable_t *gdraw;
-    glitz_format_t *format;
-    glitz_surface_t *sr = NULL;
-    unsigned long mask;
-
-    memset(&templ, 0, sizeof(templ));
-    templ.color.red_size = 8;
-    templ.color.green_size = 8;
-    templ.color.blue_size = 8;
-    templ.color.alpha_size = 8;
-    templ.color.fourcc = GLITZ_FOURCC_RGB;
-    templ.samples = 1;
-
-    mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
-	GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
-	GLITZ_FORMAT_BLUE_SIZE_MASK;
-    if (formatname == GLITZ_STANDARD_ARGB32)
-	mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
-
-    dformat = glitz_wgl_find_pbuffer_format (mask, &templ, 0);
-    if (!dformat) {
-	cairo_test_log ("Glitz failed to find pbuffer format for template.");
-	goto FAIL;
-    }
-
-    gdraw = glitz_wgl_create_pbuffer_drawable (dformat, width, height);
-    if (!gdraw) {
-	cairo_test_log ("Glitz failed to create pbuffer drawable.");
-	goto FAIL;
-    }
-
-    format = glitz_find_standard_format (gdraw, formatname);
-    if (!format) {
-	cairo_test_log ("Glitz failed to find standard format for drawable.");
-	goto DESTROY_DRAWABLE;
-    }
-
-    sr = glitz_surface_create (gdraw, format, width, height, 0, NULL);
-    if (!sr) {
-	cairo_test_log ("Glitz failed to create a surface.");
-	goto DESTROY_DRAWABLE;
-    }
-
-    glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
-
- DESTROY_DRAWABLE:
-    glitz_drawable_destroy (gdraw);
-
- FAIL:
-    return sr; /* will be NULL unless we create it and attach */
-}
-
-static cairo_surface_t *
-create_cairo_glitz_wgl_surface (cairo_test_t *test,
-				cairo_content_t content,
-				void **closure)
-{
-    glitz_surface_t *glitz_surface;
-    cairo_surface_t *surface;
-    glitz_wgl_target_closure_t *wglc;
-
-    glitz_wgl_init (NULL);
-
-    *closure = wglc = xmalloc (sizeof (glitz_wgl_target_closure_t));
-
-    switch (content) {
-    case CAIRO_CONTENT_COLOR:
-	glitz_surface = create_glitz_wgl_surface (GLITZ_STANDARD_RGB24, test->width, test->height, NULL);
-	break;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	glitz_surface = create_glitz_wgl_surface (GLITZ_STANDARD_ARGB32, test->width, test->height, NULL);
-	break;
-    default:
-	cairo_test_log ("Invalid content for glitz-wgl test: %d\n", content);
-	goto FAIL;
-    }
-
-    if (!glitz_surface)
-	goto FAIL;
-
-    surface = cairo_glitz_surface_create (glitz_surface);
-
-    wglc->base.width = test->width;
-    wglc->base.height = test->height;
-    wglc->base.content = content;
-    cairo_surface_set_user_data (surface, &glitz_closure_key, wglc, NULL);
-
-    return surface;
-
- FAIL:
-    return NULL;
-}
-
-static void
-cleanup_cairo_glitz_wgl (void *closure)
-{
-    free (closure);
-    glitz_wgl_fini ();
-}
-
-#endif /* CAIRO_CAN_TEST_GLITZ_WGL_SURFACE */
-
-#endif /* CAIRO_HAS_GLITZ_SURFACE */
-
-#if 0 && CAIRO_HAS_QUARTZ_SURFACE
-static cairo_surface_t *
-create_quartz_surface (int width, int height, void **closure)
-{
-#error Not yet implemented
-}
-
-static void
-cleanup_quartz (void *closure)
-{
-#error Not yet implemented
-}
-#endif
-
-/* Testing the win32 surface isn't interesting, since for
- * ARGB images it just chains to the image backend
- */
-#if CAIRO_HAS_WIN32_SURFACE
-#include "cairo-win32.h"
-typedef struct _win32_target_closure
-{
-  HDC dc;
-  HBITMAP bmp;
-} win32_target_closure_t;
-
-static cairo_surface_t *
-create_win32_surface (cairo_test_t	 *test,
-		      cairo_content_t	  content,
-		      void		**closure)
-{
-    int width = test->width;
-    int height = test->height;
-
-    BITMAPINFO bmpInfo;
-    unsigned char *bits = NULL;
-    win32_target_closure_t *data = malloc(sizeof(win32_target_closure_t));
-    *closure = data;
-
-    data->dc = CreateCompatibleDC(NULL);
-
-    /* initialize the bitmapinfoheader */
-    memset(&bmpInfo.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
-    bmpInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
-    bmpInfo.bmiHeader.biWidth = width;
-    bmpInfo.bmiHeader.biHeight = -height;
-    bmpInfo.bmiHeader.biPlanes = 1;
-    bmpInfo.bmiHeader.biBitCount = 24;
-    bmpInfo.bmiHeader.biCompression = BI_RGB;
-
-    /* create a DIBSection */
-    data->bmp = CreateDIBSection(data->dc, &bmpInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
-
-    /* Flush GDI to make sure the DIBSection is actually created */
-    GdiFlush();
-
-    /* Select the bitmap in to the DC */
-    SelectObject(data->dc, data->bmp);
-
-    return cairo_win32_surface_create(data->dc);
-}
-
-static void
-cleanup_win32 (void *closure)
-{
-  win32_target_closure_t *data = (win32_target_closure_t*)closure;
-  DeleteObject(data->bmp);
-  DeleteDC(data->dc);
-
-  free(closure);
-}
-#endif
-
-#if CAIRO_HAS_XCB_SURFACE
-#include "cairo-xcb-xrender.h"
-typedef struct _xcb_target_closure
-{
-    XCBConnection *c;
-    XCBDRAWABLE drawable;
-} xcb_target_closure_t;
-
-/* XXX: This is a nasty hack. Something like this should be in XCB's
- * bindings for Render, not here in this test. */
-static XCBRenderPICTFORMINFO
-_format_from_cairo(XCBConnection *c, cairo_format_t fmt)
-{
-    XCBRenderPICTFORMINFO ret = {{ 0 }};
-    struct tmpl_t {
-	XCBRenderDIRECTFORMAT direct;
-	CARD8 depth;
-    };
-    static const struct tmpl_t templates[] = {
-	/* CAIRO_FORMAT_ARGB32 */
-	{
-	    {
-		16, 0xff,
-		8,  0xff,
-		0,  0xff,
-		24, 0xff
-	    },
-	    32
-	},
-	/* CAIRO_FORMAT_RGB24 */
-	{
-	    {
-		16, 0xff,
-		8,  0xff,
-		0,  0xff,
-		0,  0x00
-	    },
-	    24
-	},
-	/* CAIRO_FORMAT_A8 */
-	{
-	    {
-		0,  0x00,
-		0,  0x00,
-		0,  0x00,
-		0,  0xff
-	    },
-	    8
-	},
-	/* CAIRO_FORMAT_A1 */
-	{
-	    {
-		0,  0x00,
-		0,  0x00,
-		0,  0x00,
-		0,  0x01
-	    },
-	    1
-	},
-    };
-    const struct tmpl_t *tmpl;
-    XCBRenderQueryPictFormatsRep *r;
-    XCBRenderPICTFORMINFOIter fi;
-
-    if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates)))
-	return ret;
-    tmpl = templates + fmt;
-
-    r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
-    if(!r)
-	return ret;
-
-    for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
-    {
-	const XCBRenderDIRECTFORMAT *t, *f;
-	if(fi.data->type != XCBRenderPictTypeDirect)
-	    continue;
-	if(fi.data->depth != tmpl->depth)
-	    continue;
-	t = &tmpl->direct;
-	f = &fi.data->direct;
-	if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift))
-	    continue;
-	if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift))
-	    continue;
-	if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift))
-	    continue;
-	if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
-	    continue;
-
-	ret = *fi.data;
-    }
-
-    free(r);
-    return ret;
-}
-
-static cairo_surface_t *
-create_xcb_surface (cairo_test_t	 *test,
-		    cairo_content_t	  content,
-		    void		**closure)
-{
-    int width = test->width;
-    int height = test->height;
-    XCBSCREEN *root;
-    xcb_target_closure_t *xtc;
-    cairo_surface_t *surface;
-    XCBConnection *c;
-    XCBRenderPICTFORMINFO render_format;
-    cairo_format_t format;
-
-    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
-
-    if (width == 0)
-	width = 1;
-    if (height == 0)
-	height = 1;
-
-    xtc->c = c = XCBConnect(NULL,NULL);
-    if (c == NULL) {
-	cairo_test_log ("Failed to connect to X server through XCB\n");
-	return NULL;
-    }
-
-    root = XCBSetupRootsIter(XCBGetSetup(c)).data;
-
-    xtc->drawable.pixmap = XCBPIXMAPNew (c);
-    {
-	XCBDRAWABLE root_drawable;
-	root_drawable.window = root->root;
-	XCBCreatePixmap (c, 32, xtc->drawable.pixmap, root_drawable,
-			 width, height);
-    }
-
-    switch (content) {
-    case CAIRO_CONTENT_COLOR:
-	format = CAIRO_FORMAT_RGB24;
-	break;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	format = CAIRO_FORMAT_ARGB32;
-	break;
-    default:
-	cairo_test_log ("Invalid content for XCB test: %d\n", content);
-	return NULL;
-    }
-
-    render_format = _format_from_cairo (c, format);
-    if (render_format.id.xid == 0)
-	return NULL;
-    surface = cairo_xcb_surface_create_with_xrender_format (c, xtc->drawable, root,
-							    &render_format,
-							    width, height);
-
-    return surface;
-}
-
-static void
-cleanup_xcb (void *closure)
-{
-    xcb_target_closure_t *xtc = closure;
-
-    XCBFreePixmap (xtc->c, xtc->drawable.pixmap);
-    XCBDisconnect (xtc->c);
-    free (xtc);
-}
-#endif
-
-#if CAIRO_HAS_XLIB_SURFACE
-#include "cairo-xlib-xrender.h"
-typedef struct _xlib_target_closure
-{
-    Display *dpy;
-    Pixmap pixmap;
-} xlib_target_closure_t;
-
-static cairo_surface_t *
-create_xlib_surface (cairo_test_t	 *test,
-		     cairo_content_t	  content,
-		     void		**closure)
-{
-    int width = test->width;
-    int height = test->height;
-    xlib_target_closure_t *xtc;
-    cairo_surface_t *surface;
-    Display *dpy;
-    XRenderPictFormat *xrender_format;
-
-    *closure = xtc = xmalloc (sizeof (xlib_target_closure_t));
-
-    if (width == 0)
-	width = 1;
-    if (height == 0)
-	height = 1;
-
-    xtc->dpy = dpy = XOpenDisplay (NULL);
-    if (xtc->dpy == NULL) {
-	cairo_test_log ("Failed to open display: %s\n", XDisplayName(0));
-	return NULL;
-    }
-
-    XSynchronize (xtc->dpy, 1);
-
-    /* XXX: Currently we don't do any xlib testing when the X server
-     * doesn't have the Render extension. We could do better here,
-     * (perhaps by converting the tests from ARGB32 to RGB24). One
-     * step better would be to always test the non-Render fallbacks
-     * for each test even if the server does have the Render
-     * extension. That would probably be through another
-     * cairo_test_target which would use an extended version of
-     * cairo_test_xlib_disable_render.  */
-    switch (content) {
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
-	break;
-    case CAIRO_CONTENT_COLOR:
-	xrender_format = XRenderFindStandardFormat (dpy, PictStandardRGB24);
-	break;
-    case CAIRO_CONTENT_ALPHA:
-    default:
-	cairo_test_log ("Invalid content for xlib test: %d\n", content);
-	return NULL;
-    }
-    if (xrender_format == NULL) {
-	cairo_test_log ("X server does not have the Render extension.\n");
-	return NULL;
-    }
-
-    xtc->pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy),
-				 width, height, xrender_format->depth);
-
-    surface = cairo_xlib_surface_create_with_xrender_format (dpy, xtc->pixmap,
-							     DefaultScreenOfDisplay (dpy),
-							     xrender_format,
-							     width, height);
-    return surface;
-}
-
-static void
-cleanup_xlib (void *closure)
-{
-    xlib_target_closure_t *xtc = closure;
-
-    XFreePixmap (xtc->dpy, xtc->pixmap);
-    XCloseDisplay (xtc->dpy);
-    free (xtc);
-}
-#endif
-
-#if CAIRO_HAS_BEOS_SURFACE
-/* BeOS test functions are external as they need to be C++ */
-#include "cairo-test-beos.h"
-#endif
-
-#if CAIRO_HAS_DIRECTFB_SURFACE
-#include "cairo-test-directfb.h"
-#endif
-
-#if CAIRO_HAS_PS_SURFACE
-#include "cairo-ps.h"
-
-cairo_user_data_key_t	ps_closure_key;
-
-typedef struct _ps_target_closure
-{
-    char		*filename;
-    int			 width;
-    int			 height;
-    cairo_surface_t	*target;
-} ps_target_closure_t;
-
-static cairo_surface_t *
-create_ps_surface (cairo_test_t		 *test,
-		   cairo_content_t	  content,
-		   void			**closure)
-{
-    int width = test->width;
-    int height = test->height;
-    ps_target_closure_t	*ptc;
-    cairo_surface_t *surface;
-    int i;
-
-    for (i = 0; vector_ignored_tests[i] != NULL; i++)
-	if (strcmp (test->name, vector_ignored_tests[i]) == 0)
-	    return NULL;
-
-    /* Sanitize back to a real cairo_content_t value. */
-    if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
-	content = CAIRO_CONTENT_COLOR_ALPHA;
-
-    *closure = ptc = xmalloc (sizeof (ps_target_closure_t));
-
-    xasprintf (&ptc->filename, "%s-ps-%s-out.ps",
-	       test->name, _cairo_test_content_name (content));
-
-    ptc->width = width;
-    ptc->height = height;
-
-    surface = cairo_ps_surface_create (ptc->filename, width, height);
-    if (cairo_surface_status (surface)) {
-	free (ptc->filename);
-	free (ptc);
-	return NULL;
-    }
-    cairo_surface_set_fallback_resolution (surface, 72., 72.);
-
-    if (content == CAIRO_CONTENT_COLOR) {
-	ptc->target = surface;
-	surface = cairo_surface_create_similar (ptc->target,
-						CAIRO_CONTENT_COLOR,
-						width, height);
-    } else {
-	ptc->target = NULL;
-    }
-
-    cairo_surface_set_user_data (surface, &ps_closure_key, ptc, NULL);
-
-    return surface;
-}
-
-static cairo_status_t
-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];
-
-    /* Both surface and ptc->target were originally created at the
-     * same dimensions. We want a 1:1 copy here, so we first clear any
-     * device offset on surface.
-     *
-     * In a more realistic use case of device offsets, the target of
-     * this copying would be of a different size than the source, and
-     * the offset would be desirable during the copy operation. */
-    cairo_surface_set_device_offset (surface, 0, 0);
-
-    if (ptc->target) {
-	cairo_t *cr;
-	cr = cairo_create (ptc->target);
-	cairo_set_source_surface (cr, surface, 0, 0);
-	cairo_paint (cr);
-	cairo_show_page (cr);
-	cairo_destroy (cr);
-
-	cairo_surface_finish (surface);
-	surface = ptc->target;
-    }
-
-    cairo_surface_finish (surface);
-    sprintf (command, "gs -q -r72 -g%dx%d -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=%s %s",
-	     ptc->width, ptc->height, filename, ptc->filename);
-    if (system (command) == 0)
-	return CAIRO_STATUS_SUCCESS;
-    return CAIRO_STATUS_WRITE_ERROR;
-}
-
-static void
-cleanup_ps (void *closure)
-{
-    ps_target_closure_t *ptc = closure;
-    if (ptc->target)
-	cairo_surface_destroy (ptc->target);
-    free (ptc->filename);
-    free (ptc);
-}
-#endif /* CAIRO_HAS_PS_SURFACE */
-
-#if CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE
-#include "cairo-pdf.h"
-
-cairo_user_data_key_t pdf_closure_key;
-
-typedef struct _pdf_target_closure
-{
-    char		*filename;
-    int			 width;
-    int			 height;
-    cairo_surface_t	*target;
-} pdf_target_closure_t;
-
-static cairo_surface_t *
-create_pdf_surface (cairo_test_t	 *test,
-		    cairo_content_t	  content,
-		    void		**closure)
-{
-    int width = test->width;
-    int height = test->height;
-    pdf_target_closure_t *ptc;
-    cairo_surface_t *surface;
-    int i;
-
-    for (i = 0; vector_ignored_tests[i] != NULL; i++)
-	if (strcmp (test->name, vector_ignored_tests[i]) == 0)
-	    return NULL;
-
-    /* Sanitize back to a real cairo_content_t value. */
-    if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
-	content = CAIRO_CONTENT_COLOR_ALPHA;
-
-    *closure = ptc = xmalloc (sizeof (pdf_target_closure_t));
-
-    ptc->width = width;
-    ptc->height = height;
-
-    xasprintf (&ptc->filename, "%s-pdf-%s-out.pdf",
-	       test->name, _cairo_test_content_name (content));
-
-    surface = cairo_pdf_surface_create (ptc->filename, width, height);
-    if (cairo_surface_status (surface)) {
-	free (ptc->filename);
-	free (ptc);
-	return NULL;
-    }
-    cairo_surface_set_fallback_resolution (surface, 72., 72.);
-
-    if (content == CAIRO_CONTENT_COLOR) {
-	ptc->target = surface;
-	surface = cairo_surface_create_similar (ptc->target,
-						CAIRO_CONTENT_COLOR,
-						width, height);
-    } else {
-	ptc->target = NULL;
-    }
-
-    cairo_surface_set_user_data (surface, &pdf_closure_key, ptc, NULL);
-
-    return surface;
-}
-
-static cairo_status_t
-pdf_surface_write_to_png (cairo_surface_t *surface, const char *filename)
-{
-    pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, &pdf_closure_key);
-    char    command[4096];
-
-    /* Both surface and ptc->target were originally created at the
-     * same dimensions. We want a 1:1 copy here, so we first clear any
-     * device offset on surface.
-     *
-     * In a more realistic use case of device offsets, the target of
-     * this copying would be of a different size than the source, and
-     * the offset would be desirable during the copy operation. */
-    cairo_surface_set_device_offset (surface, 0, 0);
-
-    if (ptc->target) {
-	cairo_t *cr;
-	cr = cairo_create (ptc->target);
-	cairo_set_source_surface (cr, surface, 0, 0);
-	cairo_paint (cr);
-	cairo_show_page (cr);
-	cairo_destroy (cr);
-
-	cairo_surface_finish (surface);
-	surface = ptc->target;
-    }
-
-    cairo_surface_finish (surface);
-    sprintf (command, "./pdf2png %s %s 1",
-	     ptc->filename, filename);
-
-    if (system (command) != 0)
-	return CAIRO_STATUS_WRITE_ERROR;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-cleanup_pdf (void *closure)
-{
-    pdf_target_closure_t *ptc = closure;
-    if (ptc->target)
-	cairo_surface_destroy (ptc->target);
-    free (ptc->filename);
-    free (ptc);
-}
-#endif /* CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE */
-
-#if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE
-#include "cairo-svg.h"
-
-cairo_user_data_key_t	svg_closure_key;
-
-typedef struct _svg_target_closure
-{
-    char    *filename;
-    int	    width, height;
-    cairo_surface_t	*target;
-} svg_target_closure_t;
-
-static cairo_surface_t *
-create_svg_surface (cairo_test_t	 *test,
-		    cairo_content_t	  content,
-		    void		**closure)
-{
-    int width = test->width;
-    int height = test->height;
-    int i;
-    svg_target_closure_t *ptc;
-    cairo_surface_t *surface;
-
-    for (i = 0; vector_ignored_tests[i] != NULL; i++)
-	if (strcmp (test->name, vector_ignored_tests[i]) == 0)
-	    return NULL;
-
-    *closure = ptc = xmalloc (sizeof (svg_target_closure_t));
-
-    ptc->width = width;
-    ptc->height = height;
-
-    xasprintf (&ptc->filename, "%s-svg-%s-out.svg",
-	       test->name, _cairo_test_content_name (content));
-
-    surface = cairo_svg_surface_create (ptc->filename, width, height);
-    if (cairo_surface_status (surface)) {
-	free (ptc->filename);
-	free (ptc);
-	return NULL;
-    }
-    cairo_surface_set_fallback_resolution (surface, 72., 72.);
-
-    if (content == CAIRO_CONTENT_COLOR) {
-	ptc->target = surface;
-	surface = cairo_surface_create_similar (ptc->target,
-						CAIRO_CONTENT_COLOR,
-						width, height);
-    } else {
-	ptc->target = NULL;
-    }
-
-    cairo_surface_set_user_data (surface, &svg_closure_key, ptc, NULL);
-
-    return surface;
-}
-
-static cairo_status_t
-svg_surface_write_to_png (cairo_surface_t *surface, const char *filename)
-{
-    svg_target_closure_t *ptc = cairo_surface_get_user_data (surface, &svg_closure_key);
-    char    command[4096];
-
-    /* Both surface and ptc->target were originally created at the
-     * same dimensions. We want a 1:1 copy here, so we first clear any
-     * device offset on surface.
-     *
-     * In a more realistic use case of device offsets, the target of
-     * this copying would be of a different size than the source, and
-     * the offset would be desirable during the copy operation. */
-    cairo_surface_set_device_offset (surface, 0, 0);
-
-    if (ptc->target) {
-	cairo_t *cr;
-	cr = cairo_create (ptc->target);
-	cairo_set_source_surface (cr, surface, 0, 0);
-	cairo_paint (cr);
-	cairo_show_page (cr);
-	cairo_destroy (cr);
-
-	cairo_surface_finish (surface);
-	surface = ptc->target;
-    }
-
-    cairo_surface_finish (surface);
-    sprintf (command, "./svg2png %s %s",
-	     ptc->filename, filename);
-
-    if (system (command) != 0)
-	return CAIRO_STATUS_WRITE_ERROR;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-cleanup_svg (void *closure)
-{
-    svg_target_closure_t *ptc = closure;
-    if (ptc->target)
-	cairo_surface_destroy (ptc->target);
-    free (ptc->filename);
-    free (ptc);
-}
-#endif /* CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE */
-
 static char *
 cairo_ref_name_for_test_target_format (const char *test_name,
 				       const char *target_name,
@@ -1572,7 +233,11 @@ cairo_test_for_target (cairo_test_t		 *t
 	test->height += dev_offset;
     }
 
-    surface = (target->create_target_surface) (test, target->content, &target->closure);
+    surface = (target->create_target_surface) (test->name,
+					       target->content,
+					       test->width,
+					       test->height,
+					       &target->closure);
 
     if (test->width && test->height) {
 	test->width -= dev_offset;
@@ -1722,135 +387,6 @@ cairo_test_expecting (cairo_test_t *test
 #endif
     volatile cairo_test_status_t status, ret;
     cairo_test_target_t ** volatile targets_to_test;
-    cairo_test_target_t targets[] =
-	{
-	    { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA,
-	      create_image_surface, cairo_surface_write_to_png, NULL},
-	    { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR,
-	      create_image_surface, cairo_surface_write_to_png, NULL},
-#ifdef CAIRO_HAS_TEST_SURFACES
-	    { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
-	      CAIRO_CONTENT_COLOR_ALPHA,
-	      create_test_fallback_surface, cairo_surface_write_to_png, NULL },
-	    { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
-	      CAIRO_CONTENT_COLOR,
-	      create_test_fallback_surface, cairo_surface_write_to_png, NULL },
-	    { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
-	      CAIRO_CONTENT_COLOR_ALPHA,
-	      create_test_meta_surface, cairo_surface_write_to_png, NULL },
-	    { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
-	      CAIRO_CONTENT_COLOR,
-	      create_test_meta_surface, cairo_surface_write_to_png, NULL },
-	    { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
-	      CAIRO_CONTENT_COLOR_ALPHA,
-	      create_test_paginated_surface,
-	      test_paginated_write_to_png,
-	      cleanup_test_paginated },
-	    { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
-	      CAIRO_CONTENT_COLOR,
-	      create_test_paginated_surface,
-	      test_paginated_write_to_png,
-	      cleanup_test_paginated },
-#endif
-#ifdef CAIRO_HAS_GLITZ_SURFACE
-#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
-	    { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ,CAIRO_CONTENT_COLOR_ALPHA,
-		create_cairo_glitz_glx_surface, cairo_surface_write_to_png,
-		cleanup_cairo_glitz_glx },
-	    { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR,
-		create_cairo_glitz_glx_surface, cairo_surface_write_to_png,
-		cleanup_cairo_glitz_glx },
-#endif
-#if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
-	    { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA,
-		create_cairo_glitz_agl_surface, cairo_surface_write_to_png,
-		cleanup_cairo_glitz_agl },
-	    { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR,
-		create_cairo_glitz_agl_surface, cairo_surface_write_to_png,
-		cleanup_cairo_glitz_agl },
-#endif
-#if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE
-	    { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA,
-		create_cairo_glitz_wgl_surface, cairo_surface_write_to_png,
-		cleanup_cairo_glitz_wgl },
-	    { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR,
-		create_cairo_glitz_wgl_surface, cairo_surface_write_to_png,
-		cleanup_cairo_glitz_wgl },
-#endif
-#endif /* CAIRO_HAS_GLITZ_SURFACE */
-#if 0 && CAIRO_HAS_QUARTZ_SURFACE
-	    { "quartz", CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR,
-		create_quartz_surface, cairo_surface_write_to_png,
-		cleanup_quartz },
-#endif
-#if CAIRO_HAS_WIN32_SURFACE
-	    { "win32", CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR,
-		create_win32_surface, cairo_surface_write_to_png, cleanup_win32 },
-#endif
-#if CAIRO_HAS_XCB_SURFACE
-	    { "xcb", CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA,
-		create_xcb_surface, cairo_surface_write_to_png, cleanup_xcb},
-#endif
-#if CAIRO_HAS_XLIB_SURFACE
-	    { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA,
-		create_xlib_surface, cairo_surface_write_to_png, cleanup_xlib},
-	    { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR,
-		create_xlib_surface, cairo_surface_write_to_png, cleanup_xlib},
-#endif
-#if CAIRO_HAS_PS_SURFACE
-	    { "ps", CAIRO_SURFACE_TYPE_PS,
-	        CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED,
-		create_ps_surface, ps_surface_write_to_png, cleanup_ps },
-
-	    /* XXX: We expect type image here only due to a limitation in
-	     * the current PS/meta-surface code. A PS surface is
-	     * "naturally" COLOR_ALPHA, so the COLOR-only variant goes
-	     * through create_similar in create_ps_surface which results
-	     * in the similar surface being used as a source. We do not yet
-	     * have source support for PS/meta-surfaces, so the
-	     * create_similar path for all paginated surfaces currently
-	     * returns an image surface.*/
-	    { "ps", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR,
-		create_ps_surface, ps_surface_write_to_png, cleanup_ps },
-#endif
-#if CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE
-	    { "pdf", CAIRO_SURFACE_TYPE_PDF,
-	        CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED,
-		create_pdf_surface, pdf_surface_write_to_png, cleanup_pdf },
-
-	    /* XXX: We expect type image here only due to a limitation in
-	     * the current PDF/meta-surface code. A PDF surface is
-	     * "naturally" COLOR_ALPHA, so the COLOR-only variant goes
-	     * through create_similar in create_pdf_surface which results
-	     * in the similar surface being used as a source. We do not yet
-	     * have source support for PDF/meta-surfaces, so the
-	     * create_similar path for all paginated surfaces currently
-	     * returns an image surface.*/
-	    { "pdf", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR,
-		create_pdf_surface, pdf_surface_write_to_png, cleanup_pdf },
-#endif
-#if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE
-	    { "svg", CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA,
-		    create_svg_surface, svg_surface_write_to_png, cleanup_svg },
-	    { "svg", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR,
-		    create_svg_surface, svg_surface_write_to_png, cleanup_svg },
-#endif
-#if CAIRO_HAS_BEOS_SURFACE
-	    { "beos", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR,
-		create_beos_surface, cairo_surface_write_to_png, cleanup_beos},
-	    { "beos-bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR,
-		create_beos_bitmap_surface, cairo_surface_write_to_png, cleanup_beos_bitmap},
-	    { "beos-bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR_ALPHA,
-		create_beos_bitmap_surface, cairo_surface_write_to_png, cleanup_beos_bitmap},
-#endif
-
-#if CAIRO_HAS_DIRECTFB_SURFACE
-	    { "directfb", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR,
-		create_directfb_surface, cairo_surface_write_to_png, cleanup_directfb},
-	    { "directfb-bitmap", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR_ALPHA,
-		create_directfb_bitmap_surface, cairo_surface_write_to_png,cleanup_directfb},
-#endif
-	};
 
 #ifdef HAVE_UNISTD_H
     if (isatty (2)) {
@@ -1871,7 +407,6 @@ cairo_test_expecting (cairo_test_t *test
     if (expectation == CAIRO_TEST_FAILURE)
     printf ("Expecting failure\n");
 
-
     if ((tname = getenv ("CAIRO_TEST_TARGET")) != NULL && *tname) {
 
 	limited_targets = TRUE;
@@ -1885,7 +420,7 @@ cairo_test_expecting (cairo_test_t *test
 	    if (!end)
 	        end = tname + strlen (tname);
 
-	    for (i = 0; i < sizeof(targets)/sizeof(targets[0]); i++) {
+	    for (i = 0; targets[i].name != NULL; i++) {
 		if (0 == strncmp (targets[i].name, tname, end - tname) &&
 		    !isalnum (targets[i].name[end - tname])) {
 		    /* realloc isn't exactly the best thing here, but meh. */
@@ -1905,10 +440,13 @@ cairo_test_expecting (cairo_test_t *test
 	    tname = end;
 	}
     } else {
-	num_targets = sizeof(targets)/sizeof(targets[0]);
+	num_targets = 0;
+	for (i = 0; targets[i].name != NULL; i++)
+	    num_targets++;
 	targets_to_test = malloc (sizeof(cairo_test_target_t*) * num_targets);
-	for (i = 0; i < num_targets; i++)
+	for (i = 0; i < num_targets; i++) {
 	    targets_to_test[i] = &targets[i];
+	}
     }
 
     /* The intended logic here is that we return overall SUCCESS
diff --git a/boilerplate/cairo-test.h b/boilerplate/cairo-test.h
index 8402d13..75eadb4 100644
--- a/boilerplate/cairo-test.h
+++ b/boilerplate/cairo-test.h
@@ -34,6 +34,9 @@
 #include <math.h>
 #include <cairo.h>
 
+#define CAIRO_BOILERPLATE_LOG(...) cairo_test_log (__VA_ARGS__)
+#include "cairo-boilerplate.h"
+
 CAIRO_BEGIN_DECLS
 
 #if   HAVE_STDINT_H
@@ -58,13 +61,6 @@ typedef unsigned __int64 uint64_t;
 #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, \etc.)
 #endif
 
-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
-#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
-	__attribute__((__format__(__printf__, fmt_index, va_index)))
-#else
-#define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
-#endif
-
 typedef enum cairo_test_status {
     CAIRO_TEST_SUCCESS = 0,
     CAIRO_TEST_FAILURE,
@@ -135,9 +131,6 @@ cairo_test_create_pattern_from_png (cons
 cairo_status_t
 cairo_test_paint_checkered (cairo_t *cr);
 
-void
-xasprintf (char **strp, const char *fmt, ...) CAIRO_PRINTF_FORMAT(2, 3);
-
 CAIRO_END_DECLS
 
 #endif
diff-tree a0ca4369ff71ca76e593ea8db3e728218814814d (from 5ef4c991f6ad00a37fc0645a38ba2cb9f832d9f1)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Aug 30 22:33:53 2006 -0700

    Add boilerplate/README explaining its purpose

diff --git a/boilerplate/README b/boilerplate/README
new file mode 100644
index 0000000..2a27c41
--- /dev/null
+++ b/boilerplate/README
@@ -0,0 +1,14 @@
+This directory provides code that is common to both of cairo's tests
+suites:
+
+ * The test suite for correctness in test/
+ * The test suite for performance in perf/
+
+We call it boilerplate as it consists primarily of the boilerplate
+code necessary for initializing a backend in order to create a surface
+for that backend.
+
+The code here just might be useful for someone looking to get started
+writing cairo code to use a particular backend, (but there are no
+promises that the boilerplate code found here for any particular
+backend is exemplary).


More information about the cairo-commit mailing list