[cairo-commit] Makefile.am test/buffer-diff.c test/buffer-diff.h
test/cairo-test.c test/imagediff.c test/xlib-surface.c
Carl Worth
cworth at kemper.freedesktop.org
Thu Aug 31 04:01:17 PDT 2006
Makefile.am | 2 -
test/buffer-diff.c | 94 ++++++++++++++++++++++++++++++++--------------------
test/buffer-diff.h | 63 ++++++++++++++++++++++++++--------
test/cairo-test.c | 67 ++++++++++++++++++++++++++++++++-----
test/imagediff.c | 19 +++++++---
test/xlib-surface.c | 75 +++++++++++++++++++++++------------------
6 files changed, 221 insertions(+), 99 deletions(-)
New commits:
diff-tree d1834cca192fe6f8e429be0461fab6914e04024d (from d52a1f762d33f3ada919b581e0d62f8ba1c2314c)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Aug 31 04:01:10 2006 -0700
test: Ignore single-bit errors for SVG backend.
The interface of the various buffer/image_diff functions is improved to
provide the maximum pixel difference in addition to the number of pixels
that differ. This value can then be used to compare against a per-backend
tolerance.
Currently I've set the SVG backend's tolerance to 1 to handle some issues
we're currently seeing of single-bit differences on different systems, (but
we're not exactly sure why yet).
Also I improved the image_diff routines to properly report a status value
on failure rather than the bogus value of -1 for pixels_changed.
diff --git a/Makefile.am b/Makefile.am
index cb4496c..5f376d4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-DIST_SUBDIRS = pixman src test doc
+DIST_SUBDIRS = pixman src boilerplate test doc
SUBDIRS = pixman src doc
.PHONY: doc test retest recheck check-valgrind
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index b59b5e8..8009333 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -51,10 +51,14 @@ xunlink (const char *pathname)
}
}
-/* This function should be rewritten to compare all formats supported by
+/* Compare two buffers, returning the number of pixels that are
+ * different and the maximum difference of any single color channel in
+ * result_ret.
+ *
+ * This function should be rewritten to compare all formats supported by
* cairo_format_t instead of taking a mask as a parameter.
*/
-static int
+static void
buffer_diff_core (unsigned char *_buf_a,
unsigned char *_buf_b,
unsigned char *_buf_diff,
@@ -63,11 +67,12 @@ buffer_diff_core (unsigned char *_buf_a,
int stride_a,
int stride_b,
int stride_diff,
- pixman_bits_t mask)
+ pixman_bits_t mask,
+ buffer_diff_result_t *result_ret)
{
int x, y;
pixman_bits_t *row_a, *row_b, *row;
- int pixels_changed = 0;
+ buffer_diff_result_t result = {0, 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;
@@ -93,6 +98,8 @@ buffer_diff_core (unsigned char *_buf_a,
int value_b = (row_b[x] >> (channel*8)) & 0xff;
unsigned int diff;
diff = abs (value_a - value_b);
+ if (diff > result.max_diff)
+ result.max_diff = diff;
diff *= 4; /* emphasize */
if (diff)
diff += 128; /* make sure it's visible */
@@ -101,7 +108,7 @@ buffer_diff_core (unsigned char *_buf_a,
diff_pixel |= diff << (channel*8);
}
- pixels_changed++;
+ result.pixels_changed++;
row[x] = diff_pixel;
} else {
row[x] = 0;
@@ -110,10 +117,10 @@ buffer_diff_core (unsigned char *_buf_a,
}
}
- return pixels_changed;
+ *result_ret = result;
}
-int
+void
buffer_diff (unsigned char *buf_a,
unsigned char *buf_b,
unsigned char *buf_diff,
@@ -121,13 +128,15 @@ buffer_diff (unsigned char *buf_a,
int height,
int stride_a,
int stride_b,
- int stride_diff)
+ int stride_diff,
+ buffer_diff_result_t *result)
{
- return buffer_diff_core(buf_a, buf_b, buf_diff,
- width, height, stride_a, stride_b, stride_diff, 0xffffffff);
+ buffer_diff_core(buf_a, buf_b, buf_diff,
+ width, height, stride_a, stride_b, stride_diff, 0xffffffff,
+ result);
}
-int
+void
buffer_diff_noalpha (unsigned char *buf_a,
unsigned char *buf_b,
unsigned char *buf_diff,
@@ -135,10 +144,12 @@ buffer_diff_noalpha (unsigned char *buf_
int height,
int stride_a,
int stride_b,
- int stride_diff)
+ int stride_diff,
+ buffer_diff_result_t *result)
{
- return buffer_diff_core(buf_a, buf_b, buf_diff,
- width, height, stride_a, stride_b, stride_diff, 0x00ffffff);
+ buffer_diff_core(buf_a, buf_b, buf_diff,
+ width, height, stride_a, stride_b, stride_diff, 0x00ffffff,
+ result);
}
static cairo_status_t
@@ -188,8 +199,18 @@ flatten_surface (cairo_surface_t **surfa
* Returns number of pixels changed, (or -1 on error).
* Also saves a "diff" image intended to visually show where the
* images differ.
+ *
+ * The return value simply indicates whether a check was successfully
+ * made, (as opposed to a file-not-found condition or similar). It
+ * does not indicate anything about how much the images differ. For
+ * that, see result.
+ *
+ * One failure mode is if the two images provided do not have the same
+ * dimensions. In this case, this function will return
+ * CAIRO_STATUS_SURFACE_TYPE_MISMATCH (which is a bit of an abuse, but
+ * oh well).
*/
-static int
+static cairo_status_t
image_diff_core (const char *filename_a,
const char *filename_b,
const char *filename_diff,
@@ -197,21 +218,21 @@ image_diff_core (const char *filename_a,
int ay,
int bx,
int by,
+ buffer_diff_result_t *result,
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;
+ return cairo_surface_status (surface_a);
surface_b = cairo_image_surface_create_from_png (filename_b);
if (cairo_surface_status (surface_b)) {
cairo_surface_destroy (surface_a);
- return -1;
+ return cairo_surface_status (surface_b);
}
width_a = cairo_image_surface_get_width (surface_a) - ax;
@@ -229,7 +250,7 @@ image_diff_core (const char *filename_a,
filename_a, filename_b);
cairo_surface_destroy (surface_a);
cairo_surface_destroy (surface_b);
- return -1;
+ return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
}
if (flatten) {
@@ -244,16 +265,17 @@ image_diff_core (const char *filename_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));
+ 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),
+ result);
- if (pixels_changed) {
+ if (result->pixels_changed) {
FILE *png_file;
if (filename_diff)
@@ -274,33 +296,35 @@ image_diff_core (const char *filename_a,
cairo_surface_destroy (surface_b);
cairo_surface_destroy (surface_diff);
- return pixels_changed;
+ return CAIRO_STATUS_SUCCESS;
}
-int
+cairo_status_t
image_diff (const char *filename_a,
const char *filename_b,
const char *filename_diff,
int ax,
int ay,
int bx,
- int by)
+ int by,
+ buffer_diff_result_t *result)
{
return image_diff_core (filename_a, filename_b, filename_diff,
ax, ay, bx, by,
- FALSE);
+ result, FALSE);
}
-int
+cairo_status_t
image_diff_flattened (const char *filename_a,
const char *filename_b,
const char *filename_diff,
int ax,
int ay,
int bx,
- int by)
+ int by,
+ buffer_diff_result_t *result)
{
return image_diff_core (filename_a, filename_b, filename_diff,
ax, ay, bx, by,
- TRUE);
+ result, TRUE);
}
diff --git a/test/buffer-diff.h b/test/buffer-diff.h
index 2be2b39..bef42cf 100644
--- a/test/buffer-diff.h
+++ b/test/buffer-diff.h
@@ -1,36 +1,50 @@
/* imagediff - Compare two images
*
* Copyright © 2004 Richard D. Worth
+ * Copyright © 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 Richard Worth
+ * appear in supporting documentation, and that the name of the authors
* 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
+ * The authors make 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,
+ * THE AUTHORS DISCLAIM 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
+ * NO EVENT SHALL THE AUTHORS 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> */
+ * Authors: Richard D. Worth <richard at theworths.org>
+ * Carl Worth <cworth at cworth.org>
+ */
#ifndef BUFFER_DIFF_H
#define BUFFER_DIFF_H
-/* Returns number of pixels changed.
+#include "cairo-test.h"
+
+typedef struct _buffer_diff_result {
+ unsigned int pixels_changed;
+ unsigned int max_diff;
+} buffer_diff_result_t;
+
+/* Compares two image buffers.
+ *
+ * Provides number of pixels changed and maximum single-channel
+ * difference in result.
+ *
* Also fills in a "diff" buffer intended to visually show where the
* images differ.
*/
-int
+void
buffer_diff (unsigned char *buf_a,
unsigned char *buf_b,
unsigned char *buf_diff,
@@ -38,13 +52,18 @@ buffer_diff (unsigned char *buf_a,
int height,
int stride_a,
int stride_b,
- int stride_diff);
+ int stride_diff,
+ buffer_diff_result_t *result);
-/* Returns number of pixels changed ignoring the alpha channel.
+/* Compares two image buffers ignoring the alpha channel.
+ *
+ * Provides number of pixels changed and maximum single-channel
+ * difference in result.
+ *
* Also fills in a "diff" buffer intended to visually show where the
* images differ.
*/
-int
+void
buffer_diff_noalpha (unsigned char *buf_a,
unsigned char *buf_b,
unsigned char *buf_diff,
@@ -52,29 +71,41 @@ buffer_diff_noalpha (unsigned char *buf_
int height,
int stride_a,
int stride_b,
- int stride_diff);
+ int stride_diff,
+ buffer_diff_result_t *result);
-/* Returns number of pixels changed, (or -1 on error).
+/* Compares two image buffers ignoring the alpha channel. A return
+ * value of CAIRO_STATUS_SUCCESS indicates that a comparison was made,
+ * (but the images may or may not differ). Failure modes include
+ * CAIRO_STATUS_FILE_NOT_FOUND, CAIRO_STATUS_READ_ERROR,
+ * CAIRO_STATUS_NO_MEMORY, and CAIRO_STATUS_SURFACE_TYPE_MISMATCH
+ * (which is used if the image sizes differ).
+ *
+ * Provides number of pixels changed and maximum single-channel
+ * difference in result.
+ *
* Also saves a "diff" image intended to visually show where the
* images differ.
*/
-int
+cairo_status_t
image_diff (const char *filename_a,
const char *filename_b,
const char *filename_diff,
int ax,
int ay,
int bx,
- int by);
+ int by,
+ buffer_diff_result_t *result);
/* Like image_diff, but blending the contents of b over white first. */
-int
+cairo_status_t
image_diff_flattened (const char *filename_a,
const char *filename_b,
const char *filename_diff,
int ax,
int ay,
int bx,
- int by);
+ int by,
+ buffer_diff_result_t *result);
#endif
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 0d915a5..fbb7aa6 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -100,6 +100,44 @@ const char *srcdir;
* an nonrecoverable fashion. */
jmp_buf jmpbuf;
+/* What's the maximum single-channel difference we will tolerate and
+ * still allow a test to pass? */
+static unsigned int
+target_tolerance (cairo_test_target_t *target)
+{
+ switch (target->expected_type) {
+ /* I'm uncompromising about leaving the image backend as no
+ * tolerance. There's shouldn't ever be anything that is out of
+ * our control here. */
+ case CAIRO_SURFACE_TYPE_IMAGE:
+ return 0;
+
+ /* It seems we should be able to round-trip SVG content perfrectly
+ * through librsvg and cairo, but for some mysterious reason, some
+ * systems get an error of 1 for some pixels on some of the text
+ * tests. XXX: I'd still like to chase these down at some point. */
+ case CAIRO_SURFACE_TYPE_SVG:
+ return 1;
+
+ /* Everything else gets the no-tolerance policy. It would actually
+ * be nice to go through some of the backends and see * if it
+ * wouldn't make sense to increase this. For example, * could we
+ * use a small value here for the PS backend and * eliminate some
+ * of the ps-specific reference images? */
+ case CAIRO_SURFACE_TYPE_PDF:
+ case CAIRO_SURFACE_TYPE_PS:
+ case CAIRO_SURFACE_TYPE_XLIB:
+ case CAIRO_SURFACE_TYPE_XCB:
+ case CAIRO_SURFACE_TYPE_GLITZ:
+ case CAIRO_SURFACE_TYPE_QUARTZ:
+ case CAIRO_SURFACE_TYPE_WIN32:
+ case CAIRO_SURFACE_TYPE_BEOS:
+ case CAIRO_SURFACE_TYPE_DIRECTFB:
+ default:
+ return 0;
+ }
+}
+
void
cairo_test_init (const char *test_name)
{
@@ -311,7 +349,8 @@ cairo_test_for_target (cairo_test_t *t
/* Skip image check for tests with no image (width,height == 0,0) */
if (test->width != 0 && test->height != 0) {
- int pixels_changed;
+ buffer_diff_result_t result;
+ cairo_status_t diff_status;
xunlink (png_name);
(target->write_to_png) (surface, png_name);
@@ -325,17 +364,27 @@ cairo_test_for_target (cairo_test_t *t
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);
+ if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) {
+ diff_status= image_diff_flattened (png_name, ref_name, diff_name,
+ dev_offset, dev_offset, 0, 0, &result);
+ } else {
+ diff_status = image_diff (png_name, ref_name, diff_name,
+ dev_offset, dev_offset, 0, 0, &result);
+ }
+ if (diff_status) {
+ cairo_test_log ("Error: Failed to compare images: %s\n",
+ cairo_status_to_string (diff_status));
ret = CAIRO_TEST_FAILURE;
goto UNWIND_CAIRO;
}
+ if (result.pixels_changed) {
+ cairo_test_log ("%d pixels differ (with maximum difference of %d) from reference image %s\n",
+ result.pixels_changed, result.max_diff, ref_name);
+ if (result.max_diff > target_tolerance (target)) {
+ ret = CAIRO_TEST_FAILURE;
+ goto UNWIND_CAIRO;
+ }
+ }
}
ret = CAIRO_TEST_SUCCESS;
diff --git a/test/imagediff.c b/test/imagediff.c
index 9030877..188c1a9 100644
--- a/test/imagediff.c
+++ b/test/imagediff.c
@@ -32,7 +32,8 @@
int
main (int argc, char *argv[])
{
- int total_pixels_changed;
+ buffer_diff_result_t result;
+ cairo_status_t status;
unsigned int ax, ay, bx, by;
@@ -53,10 +54,18 @@ main (int argc, char *argv[])
ax = ay = bx = by = 0;
}
- total_pixels_changed = image_diff (argv[1], argv[2], NULL, ax, ay, bx, by);
+ status = image_diff (argv[1], argv[2], NULL, ax, ay, bx, by, &result);
- if (total_pixels_changed)
- fprintf (stderr, "Total pixels changed: %d\n", total_pixels_changed);
+ if (status) {
+ fprintf (stderr, "Error comparing images: %s\n",
+ cairo_status_to_string (status));
+ return 1;
+ }
+
+ if (result.pixels_changed)
+ fprintf (stderr, "Total pixels changed: %d with a maximum channel difference of %d.\n",
+ result.pixels_changed,
+ result.max_diff);
- return (total_pixels_changed != 0);
+ return (result.pixels_changed != 0);
}
diff --git a/test/xlib-surface.c b/test/xlib-surface.c
index e20b6eb..ccde14c 100644
--- a/test/xlib-surface.c
+++ b/test/xlib-surface.c
@@ -74,7 +74,7 @@ erase_pattern (cairo_surface_t *surface)
cairo_destroy (cr);
}
-static cairo_bool_t
+static cairo_test_status_t
do_test (Display *dpy,
unsigned char *reference_data,
unsigned char *test_data,
@@ -87,12 +87,12 @@ do_test (Display *dpy,
cairo_surface_t *surface;
cairo_surface_t *test_surface;
cairo_t *test_cr;
- cairo_bool_t result;
+ buffer_diff_result_t result;
Drawable drawable;
int screen = DefaultScreen (dpy);
if (use_pixmap && offscreen)
- return 1;
+ return CAIRO_TEST_SUCCESS;
if (use_pixmap) {
drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy),
@@ -129,7 +129,7 @@ do_test (Display *dpy,
if (cairo_xlib_surface_get_width (surface) != SIZE ||
cairo_xlib_surface_get_height (surface) != SIZE)
- return 0;
+ return CAIRO_TEST_FAILURE;
}
draw_pattern (surface);
@@ -160,23 +160,25 @@ do_test (Display *dpy,
if (offscreen) {
size_t offset = 4 * (SIZE * OFFSCREEN_OFFSET + OFFSCREEN_OFFSET);
- result = !buffer_diff_noalpha (reference_data + offset,
- test_data + offset,
- diff_data + offset,
- SIZE - OFFSCREEN_OFFSET,
- SIZE - OFFSCREEN_OFFSET,
- 4 * SIZE,
- 4 * SIZE,
- 4 * SIZE);
+ buffer_diff_noalpha (reference_data + offset,
+ test_data + offset,
+ diff_data + offset,
+ SIZE - OFFSCREEN_OFFSET,
+ SIZE - OFFSCREEN_OFFSET,
+ 4 * SIZE,
+ 4 * SIZE,
+ 4 * SIZE,
+ &result);
} else {
- result = !buffer_diff_noalpha (reference_data,
- test_data,
- diff_data,
- SIZE,
- SIZE,
- 4 * SIZE,
- 4 * SIZE,
- 4 * SIZE);
+ buffer_diff_noalpha (reference_data,
+ test_data,
+ diff_data,
+ SIZE,
+ SIZE,
+ 4 * SIZE,
+ 4 * SIZE,
+ 4 * SIZE,
+ &result);
}
fprintf (log_file, "xlib-surface: %s, %s, %s%s: %s\n",
@@ -186,9 +188,12 @@ do_test (Display *dpy,
use_pixmap ?
" " :
(offscreen ? ", offscreen" : ", onscreen"),
- result ? "PASS" : "FAIL");
+ result.pixels_changed ? "FAIL" : "PASS");
- return result;
+ if (result.pixels_changed)
+ return CAIRO_TEST_FAILURE;
+ else
+ return CAIRO_TEST_SUCCESS;
}
static cairo_bool_t
@@ -218,7 +223,7 @@ main (void)
cairo_bool_t use_pixmap;
cairo_bool_t set_size;
cairo_bool_t offscreen;
- result = 0;
+ cairo_test_status_t status, result = CAIRO_TEST_SUCCESS;
cairo_test_init ("xlib-surface");
log_file = fopen ("xlib-surface.log", "w");
@@ -254,21 +259,25 @@ main (void)
for (set_size = 0; set_size <= 1; set_size++)
for (use_pixmap = 0; use_pixmap <= 1; use_pixmap++)
- for (offscreen = 0; offscreen <= 1; offscreen++)
- if (!do_test (dpy,
- reference_data, test_data, diff_data,
- 1, use_pixmap, set_size, offscreen))
- result = 1;
+ for (offscreen = 0; offscreen <= 1; offscreen++) {
+ status = do_test (dpy,
+ reference_data, test_data, diff_data,
+ 1, use_pixmap, set_size, offscreen);
+ if (status)
+ result = status;
+ }
_cairo_xlib_test_disable_render ();
for (set_size = 0; set_size <= 1; set_size++)
for (use_pixmap = 0; use_pixmap <= 1; use_pixmap++)
- for (offscreen = 0; offscreen <= 1; offscreen++)
- if (!do_test (dpy,
- reference_data, test_data, diff_data,
- 0, use_pixmap, set_size, offscreen))
- result = 1;
+ for (offscreen = 0; offscreen <= 1; offscreen++) {
+ status = do_test (dpy,
+ reference_data, test_data, diff_data,
+ 0, use_pixmap, set_size, offscreen);
+ if (status)
+ result = status;
+ }
free (reference_data);
free (test_data);
More information about the cairo-commit
mailing list