/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* vim: set sw=4 sts=4 ts=4 expandtab: */ #include "test-utils.h" #include #include #include #if !PANGO_VERSION_CHECK (1, 44, 0) # include #endif #include #include FT_FREETYPE_H /* 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 void buffer_diff_core (unsigned char *_buf_a, unsigned char *_buf_b, unsigned char *_buf_diff, int width, int height, int stride, guint32 mask, TestUtilsBufferDiffResult *result_ret) { int x, y; guint32 *row_a, *row_b, *row; TestUtilsBufferDiffResult result = {0, 0}; guint32 *buf_a = (guint32 *) _buf_a; guint32 *buf_b = (guint32 *) _buf_b; guint32 *buf_diff = (guint32 *) _buf_diff; stride /= sizeof(guint32); for (y = 0; y < height; y++) { row_a = buf_a + y * stride; row_b = buf_b + y * stride; row = buf_diff + y * stride; for (x = 0; x < width; x++) { /* check if the pixels are the same */ if ((row_a[x] & mask) != (row_b[x] & mask)) { int channel; guint32 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); if (diff > result.max_diff) result.max_diff = diff; diff *= 4; /* emphasize */ if (diff) diff += 128; /* make sure it's visible */ if (diff > 255) diff = 255; diff_pixel |= diff << (channel*8); } result.pixels_changed++; if ((diff_pixel & 0x00ffffff) == 0) { /* alpha only difference, convert to luminance */ guint8 alpha = diff_pixel >> 24; diff_pixel = alpha * 0x010101; } row[x] = diff_pixel; } else { row[x] = 0; } row[x] |= 0xff000000; /* Set ALPHA to 100% (opaque) */ } } *result_ret = result; } void test_utils_compare_surfaces (cairo_surface_t *surface_a, cairo_surface_t *surface_b, cairo_surface_t *surface_diff, TestUtilsBufferDiffResult *result) { /* Here, we run cairo's old buffer_diff algorithm which looks for * pixel-perfect images. */ buffer_diff_core (cairo_image_surface_get_data (surface_a), cairo_image_surface_get_data (surface_b), cairo_image_surface_get_data (surface_diff), cairo_image_surface_get_width (surface_a), cairo_image_surface_get_height (surface_a), cairo_image_surface_get_stride (surface_a), 0xffffffff, result); if (result->pixels_changed == 0) return; g_test_message ("%d pixels differ (with maximum difference of %d) from reference image\n", result->pixels_changed, result->max_diff); } #ifdef HAVE_PIXBUF /* Copied from gdk_cairo_surface_paint_pixbuf in gdkcairo.c, * we do not want to depend on GDK */ static void test_utils_cairo_surface_paint_pixbuf (cairo_surface_t *surface, const GdkPixbuf *pixbuf) { gint width, height; guchar *gdk_pixels, *cairo_pixels; int gdk_rowstride, cairo_stride; int n_channels; int j; if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) return; /* This function can't just copy any pixbuf to any surface, be * sure to read the invariants here before calling it */ g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE); g_assert (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_RGB24 || cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32); g_assert (cairo_image_surface_get_width (surface) == gdk_pixbuf_get_width (pixbuf)); g_assert (cairo_image_surface_get_height (surface) == gdk_pixbuf_get_height (pixbuf)); cairo_surface_flush (surface); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf); n_channels = gdk_pixbuf_get_n_channels (pixbuf); cairo_stride = cairo_image_surface_get_stride (surface); cairo_pixels = cairo_image_surface_get_data (surface); for (j = height; j; j--) { guchar *p = gdk_pixels; guchar *q = cairo_pixels; if (n_channels == 3) { guchar *end = p + 3 * width; while (p < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN q[0] = p[2]; q[1] = p[1]; q[2] = p[0]; #else q[1] = p[0]; q[2] = p[1]; q[3] = p[2]; #endif p += 3; q += 4; } } else { guchar *end = p + 4 * width; guint t1,t2,t3; #define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END while (p < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN MULT(q[0], p[2], p[3], t1); MULT(q[1], p[1], p[3], t2); MULT(q[2], p[0], p[3], t3); q[3] = p[3]; #else q[0] = p[3]; MULT(q[1], p[0], p[3], t1); MULT(q[2], p[1], p[3], t2); MULT(q[3], p[2], p[3], t3); #endif p += 4; q += 4; } #undef MULT } gdk_pixels += gdk_rowstride; cairo_pixels += cairo_stride; } cairo_surface_mark_dirty (surface); } cairo_surface_t * test_utils_cairo_surface_from_pixbuf (const GdkPixbuf *pixbuf) { cairo_surface_t *surface; g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); g_return_val_if_fail (gdk_pixbuf_get_n_channels (pixbuf) == 4, NULL); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf)); test_utils_cairo_surface_paint_pixbuf (surface, pixbuf); return surface; } #endif /* defined(HAVE_PIXBUF) */ static gchar *data_path = NULL; const gchar * test_utils_get_test_data_path (void) { if (data_path) return data_path; data_path = g_test_build_filename (G_TEST_DIST, "../../rsvg/tests/fixtures", NULL); return data_path; } void test_utils_print_dependency_versions (void) { FT_Library ft_lib; FT_Int ft_major = 0; FT_Int ft_minor = 0; FT_Int ft_patch = 0; FT_Init_FreeType (&ft_lib); FT_Library_Version (ft_lib, &ft_major, &ft_minor, &ft_patch); FT_Done_FreeType (ft_lib); g_test_message ("Cairo version: %s", cairo_version_string ()); g_test_message ("Pango version: %s", pango_version_string ()); g_test_message ("Freetype version: %d.%d.%d", ft_major, ft_minor, ft_patch); #if PANGO_VERSION_CHECK (1, 44, 0) g_test_message ("Harfbuzz version: %s", hb_version_string ()); #else g_test_message ("Not printing Harfbuzz version since Pango is older than 1.44"); #endif }