Files
librsvg/librsvg-c/tests-c/test-utils.c

259 lines
8.1 KiB
C

/* -*- 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 <string.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>
#if !PANGO_VERSION_CHECK (1, 44, 0)
# include <hb.h>
#endif
#include <ft2build.h>
#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
}