diff options
-rw-r--r-- | boilerplate/cairo-boilerplate-pdf-private.h | 5 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-pdf.c | 26 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-ps-private.h | 5 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-ps.c | 29 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-svg-private.h | 5 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-svg.c | 26 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-test-surfaces-private.h | 5 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-test-surfaces.c | 58 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-win32-printing.c | 26 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-win32-private.h | 5 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate.c | 135 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate.h | 62 | ||||
-rw-r--r-- | test/buffer-diff.c | 327 | ||||
-rw-r--r-- | test/buffer-diff.h | 38 | ||||
-rw-r--r-- | test/cairo-test.c | 160 | ||||
-rw-r--r-- | test/cairo-test.h | 4 | ||||
-rw-r--r-- | test/imagediff.c | 2 | ||||
-rw-r--r-- | test/xlib-expose-event.c | 10 |
18 files changed, 721 insertions, 207 deletions
diff --git a/boilerplate/cairo-boilerplate-pdf-private.h b/boilerplate/cairo-boilerplate-pdf-private.h index a792cc40..69f8da30 100644 --- a/boilerplate/cairo-boilerplate-pdf-private.h +++ b/boilerplate/cairo-boilerplate-pdf-private.h @@ -44,4 +44,9 @@ _cairo_boilerplate_pdf_cleanup (void *closure); cairo_status_t _cairo_boilerplate_pdf_surface_write_to_png (cairo_surface_t *surface, const char *filename); +cairo_surface_t * +_cairo_boilerplate_pdf_get_image_surface (cairo_surface_t *surface, + int width, + int height); + #endif diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c index 84e9f3e5..dc76435a 100644 --- a/boilerplate/cairo-boilerplate-pdf.c +++ b/boilerplate/cairo-boilerplate-pdf.c @@ -152,6 +152,32 @@ _cairo_boilerplate_pdf_surface_write_to_png (cairo_surface_t *surface, const cha return CAIRO_STATUS_SUCCESS; } +cairo_surface_t * +_cairo_boilerplate_pdf_get_image_surface (cairo_surface_t *surface, + int width, + int height) +{ + pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &pdf_closure_key); + char *filename; + cairo_status_t status; + + xasprintf (&filename, "%s.png", ptc->filename); + status = _cairo_boilerplate_pdf_surface_write_to_png (surface, filename); + if (status) + return cairo_boilerplate_surface_create_in_error (status); + + surface = cairo_boilerplate_get_image_surface_from_png (filename, + width, + height, + ptc->target == NULL); + + remove (filename); + free (filename); + + return surface; +} + void _cairo_boilerplate_pdf_cleanup (void *closure) { diff --git a/boilerplate/cairo-boilerplate-ps-private.h b/boilerplate/cairo-boilerplate-ps-private.h index 07b15f69..7cd15bf6 100644 --- a/boilerplate/cairo-boilerplate-ps-private.h +++ b/boilerplate/cairo-boilerplate-ps-private.h @@ -44,4 +44,9 @@ _cairo_boilerplate_ps_cleanup (void *closure); cairo_status_t _cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface, const char *filename); +cairo_surface_t * +_cairo_boilerplate_ps_get_image_surface (cairo_surface_t *surface, + int width, + int height); + #endif diff --git a/boilerplate/cairo-boilerplate-ps.c b/boilerplate/cairo-boilerplate-ps.c index f5bd28c0..f21d1720 100644 --- a/boilerplate/cairo-boilerplate-ps.c +++ b/boilerplate/cairo-boilerplate-ps.c @@ -103,7 +103,8 @@ _cairo_boilerplate_ps_create_surface (const char *name, cairo_status_t _cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface, const char *filename) { - ps_target_closure_t *ptc = cairo_surface_get_user_data (surface, &ps_closure_key); + ps_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &ps_closure_key); char command[4096]; cairo_status_t status; @@ -149,6 +150,32 @@ _cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface, const char return CAIRO_STATUS_WRITE_ERROR; } +cairo_surface_t * +_cairo_boilerplate_ps_get_image_surface (cairo_surface_t *surface, + int width, + int height) +{ + ps_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &ps_closure_key); + char *filename; + cairo_status_t status; + + xasprintf (&filename, "%s.png", ptc->filename); + status = _cairo_boilerplate_ps_surface_write_to_png (surface, filename); + if (status) + return cairo_boilerplate_surface_create_in_error (status); + + surface = cairo_boilerplate_get_image_surface_from_png (filename, + width, + height, + ptc->target == NULL); + + remove (filename); + free (filename); + + return surface; +} + void _cairo_boilerplate_ps_cleanup (void *closure) { diff --git a/boilerplate/cairo-boilerplate-svg-private.h b/boilerplate/cairo-boilerplate-svg-private.h index 4cf5f632..3f2856df 100644 --- a/boilerplate/cairo-boilerplate-svg-private.h +++ b/boilerplate/cairo-boilerplate-svg-private.h @@ -44,4 +44,9 @@ _cairo_boilerplate_svg_cleanup (void *closure); cairo_status_t _cairo_boilerplate_svg_surface_write_to_png (cairo_surface_t *surface, const char *filename); +cairo_surface_t * +_cairo_boilerplate_svg_get_image_surface (cairo_surface_t *surface, + int width, + int height); + #endif diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c index 1772988d..d931847f 100644 --- a/boilerplate/cairo-boilerplate-svg.c +++ b/boilerplate/cairo-boilerplate-svg.c @@ -145,6 +145,32 @@ _cairo_boilerplate_svg_surface_write_to_png (cairo_surface_t *surface, const cha return CAIRO_STATUS_SUCCESS; } +cairo_surface_t * +_cairo_boilerplate_svg_get_image_surface (cairo_surface_t *surface, + int width, + int height) +{ + svg_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &svg_closure_key); + char *filename; + cairo_status_t status; + + xasprintf (&filename, "%s.png", ptc->filename); + status = _cairo_boilerplate_svg_surface_write_to_png (surface, filename); + if (status) + return cairo_boilerplate_surface_create_in_error (status); + + surface = cairo_boilerplate_get_image_surface_from_png (filename, + width, + height, + FALSE); + + remove (filename); + free (filename); + + return surface; +} + void _cairo_boilerplate_svg_cleanup (void *closure) { diff --git a/boilerplate/cairo-boilerplate-test-surfaces-private.h b/boilerplate/cairo-boilerplate-test-surfaces-private.h index 0b2bebcb..ed6cb5b9 100644 --- a/boilerplate/cairo-boilerplate-test-surfaces-private.h +++ b/boilerplate/cairo-boilerplate-test-surfaces-private.h @@ -66,6 +66,11 @@ cairo_status_t _cairo_boilerplate_test_paginated_surface_write_to_png (cairo_surface_t *surface, const char *filename); +cairo_surface_t * +_cairo_boilerplate_test_paginated_get_image_surface (cairo_surface_t *surface, + int width, + int height); + void _cairo_boilerplate_test_paginated_cleanup (void *closure); diff --git a/boilerplate/cairo-boilerplate-test-surfaces.c b/boilerplate/cairo-boilerplate-test-surfaces.c index f38dda95..297faffe 100644 --- a/boilerplate/cairo-boilerplate-test-surfaces.c +++ b/boilerplate/cairo-boilerplate-test-surfaces.c @@ -85,23 +85,25 @@ _cairo_boilerplate_test_paginated_create_surface (const char *name, void **closure) { test_paginated_closure_t *tpc; + cairo_format_t format; cairo_surface_t *surface; cairo_status_t status; *closure = tpc = xmalloc (sizeof (test_paginated_closure_t)); + format = cairo_boilerplate_format_from_content (content); + tpc->content = content; tpc->width = width; tpc->height = height; - tpc->stride = width * 4; - - tpc->data = xcalloc (tpc->stride * height, 1); + tpc->stride = cairo_format_stride_for_width (format, width); + tpc->data = xcalloc (tpc->stride, height); surface = _cairo_test_paginated_surface_create_for_data (tpc->data, - tpc->content, - tpc->width, - tpc->height, - tpc->stride); + tpc->content, + tpc->width, + tpc->height, + tpc->stride); if (cairo_surface_status (surface)) goto CLEANUP; @@ -162,6 +164,48 @@ _cairo_boilerplate_test_paginated_surface_write_to_png (cairo_surface_t *surface return status; } +cairo_surface_t * +_cairo_boilerplate_test_paginated_get_image_surface (cairo_surface_t *surface, + int width, + int height) +{ + cairo_format_t format; + test_paginated_closure_t *tpc; + cairo_status_t status; + + /* show page first. the automatic show_page is too late for us */ + cairo_surface_show_page (surface); + status = cairo_surface_status (surface); + if (status) + return cairo_boilerplate_surface_create_in_error (status); + + tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key); + + format = cairo_boilerplate_format_from_content (tpc->content); + + if (0) { + return cairo_image_surface_create_for_data (tpc->data + tpc->stride * (tpc->height - height) + 4 * (tpc->width - width), /* hide the device offset */ + format, + width, + height, + tpc->stride); + } else { + cairo_surface_t *image, *surface; + + image = cairo_image_surface_create_for_data (tpc->data, + format, + tpc->width, + tpc->height, + tpc->stride); + cairo_surface_set_device_offset (image, + tpc->width - width, + tpc->height - height); + surface = _cairo_boilerplate_get_image_surface (image, width, height); + cairo_surface_destroy (image); + return surface; + } +} + void _cairo_boilerplate_test_paginated_cleanup (void *closure) { diff --git a/boilerplate/cairo-boilerplate-win32-printing.c b/boilerplate/cairo-boilerplate-win32-printing.c index 617b0871..691552d1 100644 --- a/boilerplate/cairo-boilerplate-win32-printing.c +++ b/boilerplate/cairo-boilerplate-win32-printing.c @@ -298,6 +298,32 @@ _cairo_boilerplate_win32_printing_surface_write_to_png (cairo_surface_t *surface return CAIRO_STATUS_SUCCESS; } +cairo_surface_t * +_cairo_boilerplate_win32_printing_get_image_surface (cairo_surface_t *surface, + int width, + int height) +{ + win32_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &win32_closure_key); + char *filename; + cairo_status_t status; + + xasprintf (&filename, "%s.png", ptc->filename); + status = _cairo_boilerplate_win32_printing_surface_write_to_png (surface, filename); + if (status) + return cairo_boilerplate_surface_create_in_error (status); + + surface = cairo_boilerplate_get_image_surface_from_png (filename, + width, + height, + ptc->target == NULL); + + remove (filename); + free (filename); + + return surface; +} + void _cairo_boilerplate_win32_printing_cleanup (void *closure) { diff --git a/boilerplate/cairo-boilerplate-win32-private.h b/boilerplate/cairo-boilerplate-win32-private.h index b982b2ab..093ca9b9 100644 --- a/boilerplate/cairo-boilerplate-win32-private.h +++ b/boilerplate/cairo-boilerplate-win32-private.h @@ -56,4 +56,9 @@ cairo_status_t _cairo_boilerplate_win32_printing_surface_write_to_png (cairo_surface_t *surface, const char *filename); +cairo_surface_t * +_cairo_boilerplate_win32_printing_get_image_surface (cairo_surface_t *surface, + int width, + int height); + #endif diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c index c0af5bdd..0ddcde5c 100644 --- a/boilerplate/cairo-boilerplate.c +++ b/boilerplate/cairo-boilerplate.c @@ -140,6 +140,106 @@ _cairo_boilerplate_image_create_surface (const char *name, return cairo_image_surface_create (format, width, height); } +cairo_surface_t * +_cairo_boilerplate_get_image_surface (cairo_surface_t *src, + int width, + int height) +{ + cairo_surface_t *surface; + cairo_t *cr; + +#if 0 + if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_IMAGE) { + int ww = cairo_image_surface_get_width (src); + int hh = cairo_image_surface_get_height (src); + if (width == ww && hh == height) { + return cairo_surface_reference (src); + } else { + cairo_format_t format = cairo_image_surface_get_format (src); + unsigned char *data = cairo_image_surface_get_data (src); + int stride = cairo_image_surface_get_stride (src); + + data += stride * (hh - height) + 4 * (ww - width); + return cairo_image_surface_create_for_data (data, + format, + width, + height, + stride); + } + } +#endif + + /* extract sub-surface */ + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_surface (cr, src, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +cairo_surface_t * +cairo_boilerplate_get_image_surface_from_png (const char *filename, + int width, + int height, + cairo_bool_t flatten) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_from_png (filename); + + if (flatten) { + cairo_t *cr; + cairo_surface_t *flattened; + + flattened = cairo_image_surface_create (cairo_image_surface_get_format (surface), + width, + height); + cr = cairo_create (flattened); + cairo_surface_destroy (flattened); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_surface (cr, surface, + width - cairo_image_surface_get_width (surface), + height - cairo_image_surface_get_height (surface)); + cairo_paint (cr); + + cairo_surface_destroy (surface); + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + } else if (cairo_image_surface_get_width (surface) != width || + cairo_image_surface_get_height (surface) != height) + { + cairo_t *cr; + cairo_surface_t *sub; + + sub = cairo_image_surface_create (cairo_image_surface_get_format (surface), + width, + height); + cr = cairo_create (sub); + cairo_surface_destroy (sub); + + cairo_set_source_surface (cr, surface, + width - cairo_image_surface_get_width (surface), + height - cairo_image_surface_get_height (surface)); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + cairo_surface_destroy (surface); + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + } + + return surface; +} static cairo_boilerplate_target_t targets[] = { @@ -148,35 +248,43 @@ static cairo_boilerplate_target_t targets[] = * our control here. */ { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_image_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_image_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, #ifdef CAIRO_HAS_TEST_SURFACES { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_test_fallback_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_test_fallback_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META, CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_test_meta_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_test_meta_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_test_paginated_create_surface, + _cairo_boilerplate_test_paginated_get_image_surface, _cairo_boilerplate_test_paginated_surface_write_to_png, _cairo_boilerplate_test_paginated_cleanup }, { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_test_paginated_create_surface, + _cairo_boilerplate_test_paginated_get_image_surface, _cairo_boilerplate_test_paginated_surface_write_to_png, _cairo_boilerplate_test_paginated_cleanup }, #endif @@ -184,30 +292,36 @@ static cairo_boilerplate_target_t targets[] = #if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ,CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_glitz_glx_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_glitz_glx_cleanup }, { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_glitz_glx_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_glitz_glx_cleanup }, #endif #if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_glitz_agl_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_glitz_agl_cleanup }, { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_glitz_agl_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_glitz_agl_cleanup }, #endif #if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_glitz_wgl_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_glitz_wgl_cleanup }, { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_glitz_wgl_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_glitz_wgl_cleanup }, #endif @@ -215,32 +329,38 @@ static cairo_boilerplate_target_t targets[] = #if CAIRO_HAS_QUARTZ_SURFACE { "quartz", CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_quartz_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_quartz_cleanup }, { "quartz", CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_quartz_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_quartz_cleanup }, #endif #if CAIRO_HAS_WIN32_SURFACE { "win32", CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_win32_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, /* Testing the win32 surface isn't interesting, since for * ARGB images it just chains to the image backend */ { "win32", CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_win32_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, #if CAIRO_CAN_TEST_WIN32_PRINTING_SURFACE { "win32-printing", CAIRO_SURFACE_TYPE_WIN32_PRINTING, CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0, _cairo_boilerplate_win32_printing_create_surface, + _cairo_boilerplate_win32_printing_get_image_surface, _cairo_boilerplate_win32_printing_surface_write_to_png, _cairo_boilerplate_win32_printing_cleanup, NULL, TRUE }, { "win32-printing", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_win32_printing_create_surface, + _cairo_boilerplate_win32_printing_get_image_surface, _cairo_boilerplate_win32_printing_surface_write_to_png, _cairo_boilerplate_win32_printing_cleanup, NULL, TRUE }, @@ -251,6 +371,7 @@ static cairo_boilerplate_target_t targets[] = * bit, so we set the error tolerance to 1. */ { "xcb", CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1, _cairo_boilerplate_xcb_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_xcb_cleanup, _cairo_boilerplate_xcb_synchronize}, @@ -260,11 +381,13 @@ static cairo_boilerplate_target_t targets[] = * bit, so we set the error tolerance to 1. */ { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA, 1, _cairo_boilerplate_xlib_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_xlib_cleanup, _cairo_boilerplate_xlib_synchronize}, { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1, _cairo_boilerplate_xlib_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_xlib_cleanup, _cairo_boilerplate_xlib_synchronize}, @@ -274,6 +397,7 @@ static cairo_boilerplate_target_t targets[] = * the Render extension. */ { "xlib-fallback", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1, _cairo_boilerplate_xlib_fallback_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_xlib_cleanup, _cairo_boilerplate_xlib_synchronize}, @@ -282,11 +406,13 @@ static cairo_boilerplate_target_t targets[] = { "ps", CAIRO_SURFACE_TYPE_PS, CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0, _cairo_boilerplate_ps_create_surface, + _cairo_boilerplate_ps_get_image_surface, _cairo_boilerplate_ps_surface_write_to_png, _cairo_boilerplate_ps_cleanup, NULL, TRUE }, { "ps", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_ps_create_surface, + _cairo_boilerplate_ps_get_image_surface, _cairo_boilerplate_ps_surface_write_to_png, _cairo_boilerplate_ps_cleanup, NULL, TRUE }, @@ -295,11 +421,13 @@ static cairo_boilerplate_target_t targets[] = { "pdf", CAIRO_SURFACE_TYPE_PDF, CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0, _cairo_boilerplate_pdf_create_surface, + _cairo_boilerplate_pdf_get_image_surface, _cairo_boilerplate_pdf_surface_write_to_png, _cairo_boilerplate_pdf_cleanup, NULL, TRUE }, { "pdf", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_pdf_create_surface, + _cairo_boilerplate_pdf_get_image_surface, _cairo_boilerplate_pdf_surface_write_to_png, _cairo_boilerplate_pdf_cleanup, NULL, TRUE }, @@ -312,11 +440,13 @@ static cairo_boilerplate_target_t targets[] = * For now just set the svg error tolerance to 1. */ { "svg", CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1, _cairo_boilerplate_svg_create_surface, + _cairo_boilerplate_svg_get_image_surface, _cairo_boilerplate_svg_surface_write_to_png, _cairo_boilerplate_svg_cleanup, NULL, TRUE }, { "svg", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 1, _cairo_boilerplate_svg_create_surface, + _cairo_boilerplate_svg_get_image_surface, _cairo_boilerplate_svg_surface_write_to_png, _cairo_boilerplate_svg_cleanup, NULL, TRUE }, @@ -327,14 +457,17 @@ static cairo_boilerplate_target_t targets[] = * Just ignore the small difference. */ { "beos", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR, 1, _cairo_boilerplate_beos_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_beos_cleanup}, { "beos-bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR, 1, _cairo_boilerplate_beos_create_surface_for_bitmap, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_beos_cleanup_bitmap}, { "beos-bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR_ALPHA, 1, _cairo_boilerplate_beos_create_surface_for_bitmap, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_beos_cleanup_bitmap}, #endif @@ -343,10 +476,12 @@ static cairo_boilerplate_target_t targets[] = #if CAIRO_HAS_DIRECTFB_SURFACE { "directfb", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR, 0, _cairo_boilerplate_directfb_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_directfb_cleanup}, { "directfb-bitmap", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR_ALPHA, 0, _cairo_boilerplate_directfb_create_surface, + _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png, _cairo_boilerplate_directfb_cleanup}, #endif diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h index 8031df8e..ccd30ffb 100644 --- a/boilerplate/cairo-boilerplate.h +++ b/boilerplate/cairo-boilerplate.h @@ -51,22 +51,23 @@ typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; -# ifndef HAVE_UINT64_T -# define HAVE_UINT64_T 1 -# endif -# ifndef INT16_MIN -# define INT16_MIN (-32767-1) -# endif -# ifndef INT16_MAX -# define INT16_MAX (32767) -# endif -# ifndef UINT16_MAX -# define UINT16_MAX (65535) -# endif #else #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) #endif +#ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +#endif +#ifndef INT16_MIN +# define INT16_MIN (-32767-1) +#endif +#ifndef INT16_MAX +# define INT16_MAX (32767) +#endif +#ifndef UINT16_MAX +# define UINT16_MAX (65535) +#endif + #ifndef CAIRO_BOILERPLATE_LOG #define CAIRO_BOILERPLATE_LOG(...) fprintf(stderr, __VA_ARGS__) #endif @@ -120,8 +121,14 @@ typedef cairo_surface_t * int id, void **closure); +typedef cairo_surface_t * +(*cairo_boilerplate_get_image_surface_t) (cairo_surface_t *surface, + int width, + int height); + typedef cairo_status_t -(*cairo_boilerplate_write_to_png_t) (cairo_surface_t *surface, const char *filename); +(*cairo_boilerplate_write_to_png_t) (cairo_surface_t *surface, + const char *filename); typedef void (*cairo_boilerplate_cleanup_t) (void *closure); @@ -131,15 +138,16 @@ typedef void typedef struct _cairo_boilerplate_target { - const char *name; - cairo_surface_type_t expected_type; - cairo_content_t content; - unsigned int error_tolerance; - cairo_boilerplate_create_surface_t create_surface; - cairo_boilerplate_write_to_png_t write_to_png; - cairo_boilerplate_cleanup_t cleanup; - cairo_boilerplate_wait_t synchronize; - cairo_bool_t is_vector; + const char *name; + cairo_surface_type_t expected_type; + cairo_content_t content; + unsigned int error_tolerance; + cairo_boilerplate_create_surface_t create_surface; + cairo_boilerplate_get_image_surface_t get_image_surface; + cairo_boilerplate_write_to_png_t write_to_png; + cairo_boilerplate_cleanup_t cleanup; + cairo_boilerplate_wait_t synchronize; + cairo_bool_t is_vector; } cairo_boilerplate_target_t; cairo_boilerplate_target_t ** @@ -149,6 +157,16 @@ void cairo_boilerplate_free_targets (cairo_boilerplate_target_t **targets); cairo_surface_t * +_cairo_boilerplate_get_image_surface (cairo_surface_t *src, + int width, + int height); +cairo_surface_t * +cairo_boilerplate_get_image_surface_from_png (const char *filename, + int width, + int height, + cairo_bool_t flatten); + +cairo_surface_t * cairo_boilerplate_surface_create_in_error (cairo_status_t status); #include "xmalloc.h" diff --git a/test/buffer-diff.c b/test/buffer-diff.c index ef708761..b656b112 100644 --- a/test/buffer-diff.c +++ b/test/buffer-diff.c @@ -64,28 +64,28 @@ xunlink (const cairo_test_context_t *ctx, const char *pathname) * cairo_format_t instead of taking a mask as a parameter. */ static void -buffer_diff_core (unsigned char *_buf_a, - unsigned char *_buf_b, - unsigned char *_buf_diff, +buffer_diff_core (const unsigned char *_buf_a, int stride_a, + const unsigned char *_buf_b, int stride_b, + unsigned char *_buf_diff, int stride_diff, int width, int height, - int stride, uint32_t mask, buffer_diff_result_t *result_ret) { + const uint32_t *buf_a = (const uint32_t*) _buf_a; + const uint32_t *buf_b = (const uint32_t*) _buf_b; + uint32_t *buf_diff = (uint32_t*) _buf_diff; int x, y; - uint32_t *row_a, *row_b, *row; buffer_diff_result_t result = {0, 0}; - uint32_t *buf_a = (uint32_t*)_buf_a; - uint32_t *buf_b = (uint32_t*)_buf_b; - uint32_t *buf_diff = (uint32_t*)_buf_diff; - stride /= sizeof(uint32_t); + stride_a /= sizeof (uint32_t); + stride_b /= sizeof (uint32_t); + stride_diff /= sizeof (uint32_t); for (y = 0; y < height; y++) { - row_a = buf_a + y * stride; - row_b = buf_b + y * stride; - row = buf_diff + y * stride; + const uint32_t *row_a = buf_a + y * stride_a; + const uint32_t *row_b = buf_b + y * stride_b; + uint32_t *row = buf_diff + y * stride_diff; for (x = 0; x < width; x++) { /* check if the pixels are the same */ @@ -121,7 +121,15 @@ buffer_diff_core (unsigned char *_buf_a, *result_ret = result; } -void +/* Compares two image surfaces + * + * Provides number of pixels changed and maximum single-channel + * difference in result. + * + * Also fills in a "diff" surface intended to visually show where the + * images differ. + */ +static void compare_surfaces (const cairo_test_context_t *ctx, cairo_surface_t *surface_a, cairo_surface_t *surface_b, @@ -141,12 +149,14 @@ compare_surfaces (const cairo_test_context_t *ctx, * runs about 3x slower if we run pdiff_compare first). */ buffer_diff_core (cairo_image_surface_get_data (surface_a), + cairo_image_surface_get_stride (surface_a), cairo_image_surface_get_data (surface_b), + cairo_image_surface_get_stride (surface_b), cairo_image_surface_get_data (surface_diff), + cairo_image_surface_get_stride (surface_diff), cairo_image_surface_get_width (surface_a), cairo_image_surface_get_height (surface_a), - cairo_image_surface_get_stride (surface_a), - 0xffffffff, + cairo_surface_get_content (surface_a) & CAIRO_CONTENT_ALPHA ? 0xffffffff : 0x00ffffff, result); if (result->pixels_changed == 0) return; @@ -176,16 +186,19 @@ compare_surfaces (const cairo_test_context_t *ctx, } void -buffer_diff_noalpha (unsigned char *buf_a, - unsigned char *buf_b, +buffer_diff_noalpha (const unsigned char *buf_a, + const unsigned char *buf_b, unsigned char *buf_diff, int width, int height, int stride, buffer_diff_result_t *result) { - buffer_diff_core(buf_a, buf_b, buf_diff, - width, height, stride, 0x00ffffff, + buffer_diff_core(buf_a, stride, + buf_b, stride, + buf_diff, stride, + width, height, + 0x00ffffff, result); } @@ -271,6 +284,21 @@ extract_sub_surface (const cairo_test_context_t *ctx, cairo_destroy (cr); } +static cairo_bool_t +same_size (cairo_surface_t *a, cairo_surface_t *b) +{ + unsigned int width_a, height_a; + unsigned int width_b, height_b; + + width_a = cairo_image_surface_get_width (a); + height_a = cairo_image_surface_get_height (a); + + width_b = cairo_image_surface_get_width (b); + height_b = cairo_image_surface_get_height (b); + + return width_a == width_b && height_a == height_b; +} + /* Image comparison code courtesy of Richard Worth <richard@theworths.org> * Returns number of pixels changed, (or -1 on error). * Also saves a "diff" image intended to visually show where the @@ -286,22 +314,80 @@ extract_sub_surface (const cairo_test_context_t *ctx, * CAIRO_STATUS_SURFACE_TYPE_MISMATCH (which is a bit of an abuse, but * oh well). */ +cairo_status_t +image_diff (const cairo_test_context_t *ctx, + cairo_surface_t *surface_a, + cairo_surface_t *surface_b, + cairo_surface_t *surface_diff, + buffer_diff_result_t *result) +{ + if (cairo_surface_status (surface_a)) + return cairo_surface_status (surface_a); + + if (cairo_surface_status (surface_b)) + return cairo_surface_status (surface_b); + + if (cairo_surface_status (surface_diff)) + return cairo_surface_status (surface_diff); + + if (! same_size (surface_a, surface_b) || + ! same_size (surface_a, surface_diff)) + { + cairo_test_log (ctx, "Error: Image size mismatch\n"); + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + } + + compare_surfaces (ctx, surface_a, surface_b, surface_diff, result); + + return CAIRO_STATUS_SUCCESS; +} + static cairo_status_t -image_diff_core (const cairo_test_context_t *ctx, - const char *filename_a, - const char *filename_b, - const char *filename_diff, - int ax, - int ay, - int bx, - int by, - buffer_diff_result_t *result, - cairo_bool_t flatten) +write_png (cairo_surface_t *surface, const char *filename) { cairo_status_t status; - 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; + FILE *png_file; + + if (filename != NULL) { + png_file = fopen (filename, "wb"); + if (png_file == NULL) { + switch (errno) { + case ENOMEM: + return CAIRO_STATUS_NO_MEMORY; + default: + return CAIRO_STATUS_WRITE_ERROR; + } + } + } else + png_file = stdout; + + status = cairo_surface_write_to_png_stream (surface, + stdio_write_func, + png_file); + + if (png_file != stdout) + fclose (png_file); + + return status; +} + + + +cairo_status_t +png_diff (const cairo_test_context_t *ctx, + const char *filename_a, + const char *filename_b, + const char *filename_diff, + int ax, + int ay, + int bx, + int by, + buffer_diff_result_t *result) +{ + cairo_surface_t *surface_a; + cairo_surface_t *surface_b; + cairo_surface_t *surface_diff; + cairo_status_t status; surface_a = cairo_image_surface_create_from_png (filename_a); status = cairo_surface_status (surface_a); @@ -320,12 +406,6 @@ image_diff_core (const cairo_test_context_t *ctx, return status; } - if (flatten) { - flatten_surface (ctx, &surface_a, ax, ay); - flatten_surface (ctx, &surface_b, bx, by); - ax = ay = bx = by = 0; - } - if (ax || ay) { extract_sub_surface (ctx, &surface_a, ax, ay); ax = ay = 0; @@ -353,29 +433,92 @@ image_diff_core (const cairo_test_context_t *ctx, return status; } - width_a = cairo_image_surface_get_width (surface_a); - height_a = cairo_image_surface_get_height (surface_a); - stride_a = cairo_image_surface_get_stride (surface_a); - width_b = cairo_image_surface_get_width (surface_b); - height_b = cairo_image_surface_get_height (surface_b); - stride_b = cairo_image_surface_get_stride (surface_b); + surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + cairo_image_surface_get_width (surface_a), + cairo_image_surface_get_height (surface_a)); + status = cairo_surface_status (surface_diff); + if (status) { + cairo_test_log (ctx, "Error: Failed to allocate surface to hold differences\n"); + cairo_surface_destroy (surface_a); + cairo_surface_destroy (surface_b); + return CAIRO_STATUS_NO_MEMORY; + } + + status = image_diff (ctx, + surface_a, surface_b, surface_diff, + result); - if (width_a != width_b || - height_a != height_b || - stride_a != stride_b) + cairo_surface_destroy (surface_a); + cairo_surface_destroy (surface_b); + cairo_surface_destroy (surface_diff); + + xunlink (ctx, filename_diff); + if (status == CAIRO_STATUS_SUCCESS && + result->pixels_changed) { - cairo_test_log (ctx, "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); + status = write_png (surface_diff, filename_diff); + } + + + return status; +} + +cairo_status_t +png_diff_flattened (const cairo_test_context_t *ctx, + const char *filename_a, + const char *filename_b, + const char *filename_diff, + int ax, + int ay, + int bx, + int by, + buffer_diff_result_t *result) +{ + cairo_surface_t *surface_a; + cairo_surface_t *surface_b; + cairo_surface_t *surface_diff; + cairo_status_t status; + + surface_a = cairo_image_surface_create_from_png (filename_a); + status = cairo_surface_status (surface_a); + if (status) { + cairo_test_log (ctx, "Error: Failed to create surface from %s: %s\n", + filename_a, cairo_status_to_string (status)); + return status; + } + + surface_b = cairo_image_surface_create_from_png (filename_b); + status = cairo_surface_status (surface_b); + if (status) { + cairo_test_log (ctx, "Error: Failed to create surface from %s: %s\n", + filename_b, cairo_status_to_string (status)); + cairo_surface_destroy (surface_a); + return status; + } + + flatten_surface (ctx, &surface_a, ax, ay); + flatten_surface (ctx, &surface_b, bx, by); + + status = cairo_surface_status (surface_a); + if (status) { + cairo_test_log (ctx, "Error: Failed to extract surface from %s: %s\n", + filename_a, cairo_status_to_string (status)); cairo_surface_destroy (surface_a); cairo_surface_destroy (surface_b); - return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + return status; + } + status = cairo_surface_status (surface_b); + if (status) { + cairo_test_log (ctx, "Error: Failed to extract surface from %s: %s\n", + filename_b, cairo_status_to_string (status)); + cairo_surface_destroy (surface_a); + cairo_surface_destroy (surface_b); + return status; } surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - width_a, height_a); + cairo_image_surface_get_width (surface_a), + cairo_image_surface_get_height (surface_a)); status = cairo_surface_status (surface_diff); if (status) { cairo_test_log (ctx, "Error: Failed to allocate surface to hold differences\n"); @@ -384,41 +527,15 @@ image_diff_core (const cairo_test_context_t *ctx, return CAIRO_STATUS_NO_MEMORY; } + status = image_diff (ctx, + surface_a, surface_b, surface_diff, + result); - compare_surfaces (ctx, surface_a, surface_b, surface_diff, result); - - status = CAIRO_STATUS_SUCCESS; - if (result->pixels_changed) { - FILE *png_file; - - if (filename_diff) { - png_file = fopen (filename_diff, "wb"); - if (png_file == NULL) { - int err = errno; - - cairo_surface_destroy (surface_a); - cairo_surface_destroy (surface_b); - cairo_surface_destroy (surface_diff); - - switch (err) { - case ENOMEM: - return CAIRO_STATUS_NO_MEMORY; - default: - return CAIRO_STATUS_WRITE_ERROR; - } - } - } else - png_file = stdout; - - status = cairo_surface_write_to_png_stream (surface_diff, - stdio_write_func, - png_file); - - if (png_file != stdout) - fclose (png_file); - } else { - if (filename_diff) - xunlink (ctx, filename_diff); + xunlink (ctx, filename_diff); + if (status == CAIRO_STATUS_SUCCESS && + result->pixels_changed) + { + status = write_png (surface_diff, filename_diff); } cairo_surface_destroy (surface_a); @@ -427,37 +544,3 @@ image_diff_core (const cairo_test_context_t *ctx, return status; } - -cairo_status_t -image_diff (const cairo_test_context_t *ctx, - const char *filename_a, - const char *filename_b, - const char *filename_diff, - int ax, - int ay, - int bx, - int by, - buffer_diff_result_t *result) -{ - return image_diff_core (ctx, - filename_a, filename_b, filename_diff, - ax, ay, bx, by, - result, FALSE); -} - -cairo_status_t -image_diff_flattened (const cairo_test_context_t *ctx, - const char *filename_a, - const char *filename_b, - const char *filename_diff, - int ax, - int ay, - int bx, - int by, - buffer_diff_result_t *result) -{ - return image_diff_core (ctx, - filename_a, filename_b, filename_diff, - ax, ay, bx, by, - result, TRUE); -} diff --git a/test/buffer-diff.h b/test/buffer-diff.h index 61daa897..64bce920 100644 --- a/test/buffer-diff.h +++ b/test/buffer-diff.h @@ -36,21 +36,6 @@ typedef struct _buffer_diff_result { unsigned int max_diff; } buffer_diff_result_t; -/* Compares two image surfaces - * - * Provides number of pixels changed and maximum single-channel - * difference in result. - * - * Also fills in a "diff" surface intended to visually show where the - * images differ. - */ -void -compare_surfaces (const cairo_test_context_t *ctx, - cairo_surface_t *surface_a, - cairo_surface_t *surface_b, - cairo_surface_t *surface_diff, - buffer_diff_result_t *result); - /* Compares two image buffers ignoring the alpha channel. * * Provides number of pixels changed and maximum single-channel @@ -60,8 +45,8 @@ compare_surfaces (const cairo_test_context_t *ctx, * images differ. */ void -buffer_diff_noalpha (unsigned char *buf_a, - unsigned char *buf_b, +buffer_diff_noalpha (const unsigned char *buf_a, + const unsigned char *buf_b, unsigned char *buf_diff, int width, int height, @@ -82,7 +67,7 @@ buffer_diff_noalpha (unsigned char *buf_a, * images differ. */ cairo_status_t -image_diff (const cairo_test_context_t *ctx, +png_diff (const cairo_test_context_t *ctx, const char *filename_a, const char *filename_b, const char *filename_diff, @@ -92,9 +77,9 @@ image_diff (const cairo_test_context_t *ctx, int by, buffer_diff_result_t *result); -/* Like image_diff, but blending the contents of b over white first. */ +/* Like png_diff, but blending the contents of b over white first. */ cairo_status_t -image_diff_flattened (const cairo_test_context_t *ctx, +png_diff_flattened (const cairo_test_context_t *ctx, const char *filename_a, const char *filename_b, const char *filename_diff, @@ -104,4 +89,17 @@ image_diff_flattened (const cairo_test_context_t *ctx, int by, buffer_diff_result_t *result); +/* The central algorithm to compare two images, and return the differences + * in the surface_diff. + * + * Provides number of pixels changed and maximum single-channel + * difference in result. + */ +cairo_status_t +image_diff (const cairo_test_context_t *ctx, + cairo_surface_t *surface_a, + cairo_surface_t *surface_b, + cairo_surface_t *surface_diff, + buffer_diff_result_t *result); + #endif diff --git a/test/cairo-test.c b/test/cairo-test.c index 739a0276..79d6c2b4 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -134,6 +134,10 @@ _cairo_test_init (cairo_test_context_t *ctx, ctx->refdir = getenv ("CAIRO_REF_DIR"); + ctx->ref_name = NULL; + ctx->ref_image = NULL; + ctx->ref_image_flattened = NULL; + ctx->thread = 0; { @@ -174,6 +178,11 @@ cairo_test_fini (cairo_test_context_t *ctx) fclose (ctx->log_file); ctx->log_file = NULL; + if (ctx->ref_name != NULL) + free (ctx->ref_name); + cairo_surface_destroy (ctx->ref_image); + cairo_surface_destroy (ctx->ref_image_flattened); + cairo_boilerplate_free_targets (ctx->targets_to_test); cairo_debug_reset_static_data (); @@ -351,8 +360,75 @@ cairo_test_target_has_similar (const cairo_test_context_t *ctx, return has_similar; } +static cairo_surface_t * +_cairo_test_flatten_reference_image (cairo_test_context_t *ctx, + cairo_bool_t flatten) +{ + cairo_surface_t *surface; + cairo_t *cr; + + if (! flatten) + return ctx->ref_image; + + if (ctx->ref_image_flattened != NULL) + return ctx->ref_image_flattened; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + cairo_image_surface_get_width (ctx->ref_image), + cairo_image_surface_get_height (ctx->ref_image)); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_surface (cr, ctx->ref_image, 0, 0); + cairo_paint (cr); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS) + ctx->ref_image_flattened = surface; + return surface; +} + +static cairo_surface_t * +cairo_test_get_reference_image (cairo_test_context_t *ctx, + const char *filename, + cairo_bool_t flatten) +{ + cairo_surface_t *surface; + int len; + + if (ctx->ref_name != NULL) { + if (strcmp (ctx->ref_name, filename) == 0) + return _cairo_test_flatten_reference_image (ctx, flatten); + + cairo_surface_destroy (ctx->ref_image); + ctx->ref_image = NULL; + + cairo_surface_destroy (ctx->ref_image_flattened); + ctx->ref_image_flattened = NULL; + + free (ctx->ref_name); + ctx->ref_name = NULL; + } + + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) + return surface; + + len = strlen (filename); + ctx->ref_name = xmalloc (len + 1); + memcpy (ctx->ref_name, filename, len + 1); + + ctx->ref_image = surface; + return _cairo_test_flatten_reference_image (ctx, flatten); +} + static cairo_test_status_t -cairo_test_for_target (const cairo_test_context_t *ctx, +cairo_test_for_target (cairo_test_context_t *ctx, const cairo_boilerplate_target_t *target, int dev_offset, cairo_bool_t similar) @@ -378,7 +454,6 @@ cairo_test_for_target (const cairo_test_context_t *ctx, ctx->test->name, target->name, format); - if (dev_offset) xasprintf (&offset_str, "-%d", dev_offset); else @@ -520,23 +595,15 @@ cairo_test_for_target (const cairo_test_context_t *ctx, /* Skip image check for tests with no image (width,height == 0,0) */ if (ctx->test->width != 0 && ctx->test->height != 0) { + cairo_surface_t *ref_image; + cairo_surface_t *test_image; + cairo_surface_t *diff_image; buffer_diff_result_t result; cairo_status_t diff_status; - xunlink (ctx, png_name); - - diff_status = (target->write_to_png) (surface, png_name); - if (diff_status) { - cairo_test_log (ctx, "Error: Failed to compare images: %s\n", - cairo_status_to_string (diff_status)); - ret = CAIRO_TEST_FAILURE; - goto UNWIND_CAIRO; - } - have_output = TRUE; - - if (!ref_name) { + if (ref_name == NULL) { cairo_test_log (ctx, "Error: Cannot find reference image for %s/%s-%s-%s%s\n", - ctx->srcdir, + ctx->srcdir, ctx->test->name, target->name, format, @@ -545,27 +612,64 @@ cairo_test_for_target (const cairo_test_context_t *ctx, goto UNWIND_CAIRO; } - if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) { - diff_status = image_diff_flattened (ctx, - png_name, ref_name, diff_name, - dev_offset, dev_offset, 0, 0, &result); - } else { - diff_status = image_diff (ctx, - png_name, ref_name, diff_name, - dev_offset, dev_offset, 0, 0, &result); + ref_image = cairo_test_get_reference_image (ctx, ref_name, + target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); + if (cairo_surface_status (ref_image)) { + cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", + ref_name, + cairo_status_to_string (cairo_surface_status (ref_image))); + ret = CAIRO_TEST_FAILURE; + goto UNWIND_CAIRO; } + + xunlink (ctx, png_name); + xunlink (ctx, diff_name); + + test_image = target->get_image_surface (surface, + ctx->test->width, + ctx->test->height); + if (cairo_surface_status (test_image)) { + cairo_test_log (ctx, "Error: Failed to extract image: %s\n", + cairo_status_to_string (cairo_surface_status (test_image))); + ret = CAIRO_TEST_FAILURE; + goto UNWIND_CAIRO; + } + + diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + ctx->test->width, + ctx->test->height); + + diff_status = image_diff (ctx, + test_image, ref_image, + diff_image, + &result); if (diff_status) { cairo_test_log (ctx, "Error: Failed to compare images: %s\n", cairo_status_to_string (diff_status)); ret = CAIRO_TEST_FAILURE; - goto UNWIND_CAIRO; } - - have_result = TRUE; - if (result.pixels_changed && result.max_diff > target->error_tolerance) { + else if (result.pixels_changed && + result.max_diff > target->error_tolerance) + { ret = CAIRO_TEST_FAILURE; - goto UNWIND_CAIRO; + + diff_status = cairo_surface_write_to_png (test_image, png_name); + if (diff_status) { + cairo_test_log (ctx, "Error: Failed to write output image: %s\n", + cairo_status_to_string (diff_status)); + } else + have_output = TRUE; + + diff_status = cairo_surface_write_to_png (diff_image, diff_name); + if (diff_status) { + cairo_test_log (ctx, "Error: Failed to write differences image: %s\n", + cairo_status_to_string (diff_status)); + } else + have_result = TRUE; } + + cairo_surface_destroy (test_image); + cairo_surface_destroy (diff_image); } UNWIND_CAIRO: diff --git a/test/cairo-test.h b/test/cairo-test.h index aff8079d..5dd61f88 100644 --- a/test/cairo-test.h +++ b/test/cairo-test.h @@ -120,6 +120,10 @@ struct _cairo_test_context { const char *srcdir; /* directory containing sources and input data */ const char *refdir; /* directory containing reference images */ + char *ref_name; /* cache of the current reference image */ + cairo_surface_t *ref_image; + cairo_surface_t *ref_image_flattened; + size_t num_targets; cairo_bool_t limited_targets; cairo_boilerplate_target_t **targets_to_test; diff --git a/test/imagediff.c b/test/imagediff.c index c170c8e5..64042426 100644 --- a/test/imagediff.c +++ b/test/imagediff.c @@ -54,7 +54,7 @@ main (int argc, char *argv[]) ax = ay = bx = by = 0; } - status = image_diff (NULL, argv[1], argv[2], NULL, ax, ay, bx, by, &result); + status = png_diff (NULL, argv[1], argv[2], NULL, ax, ay, bx, by, &result); if (status) { fprintf (stderr, "Error comparing images: %s\n", diff --git a/test/xlib-expose-event.c b/test/xlib-expose-event.c index bf320dab..189b8f1f 100644 --- a/test/xlib-expose-event.c +++ b/test/xlib-expose-event.c @@ -175,6 +175,7 @@ compare (const cairo_test_context_t *ctx, cairo_surface_t *surface) { cairo_t *cr; cairo_surface_t *image, *reference, *diff; + cairo_status_t status; buffer_diff_result_t result; diff = cairo_image_surface_create (CAIRO_FORMAT_RGB24, SIZE, SIZE); @@ -187,17 +188,14 @@ compare (const cairo_test_context_t *ctx, cairo_surface_t *surface) cairo_destroy (cr); reference = cairo_test_create_surface_from_png (ctx, "xlib-expose-event-ref.png"); - if (cairo_image_surface_get_width (image) != cairo_image_surface_get_width (reference) || - cairo_image_surface_get_height (image) != cairo_image_surface_get_height (reference)) - return CAIRO_TEST_FAILURE; - - compare_surfaces (ctx, reference, image, diff, &result); + status = image_diff (ctx, reference, image, diff, &result); cairo_surface_destroy (reference); cairo_surface_destroy (image); cairo_surface_destroy (diff); - return result.pixels_changed ? CAIRO_TEST_FAILURE : CAIRO_TEST_SUCCESS; + return status == CAIRO_STATUS_SUCCESS && ! result.pixels_changed ? + CAIRO_TEST_SUCCESS : CAIRO_TEST_FAILURE; } int |