librsvg source for verification 2026-05-22
This commit is contained in:
258
librsvg-c/tests-c/test-utils.c
Normal file
258
librsvg-c/tests-c/test-utils.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/* -*- 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
|
||||
}
|
||||
Reference in New Issue
Block a user