2017-12-25 11:56:21 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <glib/gstdio.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "reftest-compare.h"
|
|
|
|
|
2019-06-03 00:40:43 +00:00
|
|
|
static char *arg_output_dir = NULL;
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
get_output_dir (void)
|
|
|
|
{
|
|
|
|
static const char *output_dir = NULL;
|
|
|
|
GError *error = NULL;
|
2019-06-09 19:49:44 +00:00
|
|
|
GFile *file;
|
2019-06-03 00:40:43 +00:00
|
|
|
|
|
|
|
if (output_dir)
|
|
|
|
return output_dir;
|
|
|
|
|
|
|
|
if (arg_output_dir)
|
|
|
|
{
|
2020-05-18 09:44:38 +00:00
|
|
|
GFile *arg_file = g_file_new_for_commandline_arg (arg_output_dir);
|
2020-05-15 13:18:35 +00:00
|
|
|
const char *subdir;
|
|
|
|
|
|
|
|
subdir = g_getenv ("TEST_OUTPUT_SUBDIR");
|
|
|
|
if (subdir)
|
|
|
|
{
|
2020-05-18 09:44:38 +00:00
|
|
|
GFile *child = g_file_get_child (arg_file, subdir);
|
|
|
|
g_object_unref (arg_file);
|
|
|
|
arg_file = child;
|
2020-05-15 13:18:35 +00:00
|
|
|
}
|
|
|
|
|
2020-05-18 09:44:38 +00:00
|
|
|
output_dir = g_file_get_path (arg_file);
|
|
|
|
g_object_unref (arg_file);
|
2019-06-03 00:40:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
output_dir = g_get_tmp_dir ();
|
|
|
|
}
|
|
|
|
|
2019-06-09 19:49:44 +00:00
|
|
|
/* Just try to create the output directory.
|
|
|
|
* If it already exists, that's exactly what we wanted to check,
|
|
|
|
* so we can happily skip that error.
|
|
|
|
*/
|
|
|
|
file = g_file_new_for_path (output_dir);
|
|
|
|
if (!g_file_make_directory_with_parents (file, NULL, &error))
|
2019-06-03 00:40:43 +00:00
|
|
|
{
|
2019-06-09 19:49:44 +00:00
|
|
|
g_object_unref (file);
|
2019-06-03 00:40:43 +00:00
|
|
|
|
2019-06-09 19:49:44 +00:00
|
|
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
|
2019-06-03 00:40:43 +00:00
|
|
|
{
|
|
|
|
g_error ("Failed to create output dir: %s", error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-06-09 19:49:44 +00:00
|
|
|
g_error_free (error);
|
2019-06-03 00:40:43 +00:00
|
|
|
}
|
2019-07-07 05:23:05 +00:00
|
|
|
else
|
|
|
|
g_object_unref (file);
|
2019-06-09 19:49:44 +00:00
|
|
|
|
2019-06-03 00:40:43 +00:00
|
|
|
return output_dir;
|
|
|
|
}
|
|
|
|
|
2020-05-18 09:44:38 +00:00
|
|
|
static char *
|
2017-12-25 11:56:21 +00:00
|
|
|
file_replace_extension (const char *old_file,
|
|
|
|
const char *old_ext,
|
|
|
|
const char *new_ext)
|
|
|
|
{
|
|
|
|
GString *file = g_string_new (NULL);
|
|
|
|
|
|
|
|
if (g_str_has_suffix (old_file, old_ext))
|
|
|
|
g_string_append_len (file, old_file, strlen (old_file) - strlen (old_ext));
|
|
|
|
else
|
|
|
|
g_string_append (file, old_file);
|
|
|
|
|
|
|
|
g_string_append (file, new_ext);
|
|
|
|
|
|
|
|
return g_string_free (file, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
get_output_file (const char *file,
|
|
|
|
const char *orig_ext,
|
|
|
|
const char *new_ext)
|
|
|
|
{
|
|
|
|
const char *dir;
|
|
|
|
char *result, *base;
|
|
|
|
char *name;
|
|
|
|
|
2019-06-03 00:40:43 +00:00
|
|
|
dir = get_output_dir ();
|
2017-12-25 11:56:21 +00:00
|
|
|
base = g_path_get_basename (file);
|
|
|
|
name = file_replace_extension (base, orig_ext, new_ext);
|
|
|
|
|
|
|
|
result = g_strconcat (dir, G_DIR_SEPARATOR_S, name, NULL);
|
|
|
|
|
|
|
|
g_free (base);
|
|
|
|
g_free (name);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
save_image (cairo_surface_t *surface,
|
|
|
|
const char *test_name,
|
|
|
|
const char *extension)
|
|
|
|
{
|
|
|
|
char *filename = get_output_file (test_name, ".node", extension);
|
|
|
|
|
2019-03-19 02:57:04 +00:00
|
|
|
g_print ("Storing test result image at %s\n", filename);
|
2017-12-25 11:56:21 +00:00
|
|
|
g_assert (cairo_surface_write_to_png (surface, filename) == CAIRO_STATUS_SUCCESS);
|
|
|
|
g_free (filename);
|
|
|
|
}
|
|
|
|
|
2019-04-24 16:30:46 +00:00
|
|
|
static void
|
|
|
|
deserialize_error_func (const GtkCssSection *section,
|
|
|
|
const GError *error,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
char *section_str = gtk_css_section_to_string (section);
|
|
|
|
|
2019-05-20 01:29:11 +00:00
|
|
|
g_print ("Error at %s: %s", section_str, error->message);
|
|
|
|
*((gboolean *) user_data) = FALSE;
|
2019-04-24 16:30:46 +00:00
|
|
|
|
|
|
|
free (section_str);
|
|
|
|
}
|
|
|
|
|
2019-06-03 00:40:43 +00:00
|
|
|
static const GOptionEntry options[] = {
|
|
|
|
{ "output", 0, 0, G_OPTION_ARG_FILENAME, &arg_output_dir,
|
|
|
|
"Directory to save image files to", "DIR" },
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
2017-12-25 11:56:21 +00:00
|
|
|
/*
|
2019-06-03 00:40:43 +00:00
|
|
|
* Non-option arguments:
|
2017-12-25 11:56:21 +00:00
|
|
|
* 1) .node file to compare
|
|
|
|
* 2) .png file to compare the rendered .node file to
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
main (int argc, char **argv)
|
|
|
|
{
|
|
|
|
cairo_surface_t *reference_surface = NULL;
|
|
|
|
cairo_surface_t *rendered_surface = NULL;
|
|
|
|
cairo_surface_t *diff_surface = NULL;
|
|
|
|
GdkTexture *texture;
|
|
|
|
GskRenderer *renderer;
|
2018-03-20 10:40:08 +00:00
|
|
|
GdkSurface *window;
|
2017-12-25 11:56:21 +00:00
|
|
|
GskRenderNode *node;
|
|
|
|
const char *node_file;
|
|
|
|
const char *png_file;
|
2019-05-20 01:29:11 +00:00
|
|
|
gboolean success = TRUE;
|
2019-06-03 00:40:43 +00:00
|
|
|
GError *error = NULL;
|
|
|
|
GOptionContext *context;
|
|
|
|
|
2019-07-25 17:48:52 +00:00
|
|
|
context = g_option_context_new ("NODE REF - run GSK node tests");
|
2019-06-03 00:40:43 +00:00
|
|
|
g_option_context_add_main_entries (context, options, NULL);
|
|
|
|
g_option_context_set_ignore_unknown_options (context, TRUE);
|
|
|
|
|
|
|
|
if (!g_option_context_parse (context, &argc, &argv, &error))
|
|
|
|
{
|
|
|
|
g_error ("Option parsing failed: %s\n", error->message);
|
|
|
|
return 1;
|
|
|
|
}
|
2019-07-25 17:48:52 +00:00
|
|
|
else if (argc != 3)
|
|
|
|
{
|
|
|
|
char *help = g_option_context_get_help (context, TRUE, NULL);
|
|
|
|
g_print ("%s", help);
|
|
|
|
return 1;
|
|
|
|
}
|
2017-12-25 11:56:21 +00:00
|
|
|
|
|
|
|
gtk_init ();
|
|
|
|
|
|
|
|
node_file = argv[1];
|
|
|
|
png_file = argv[2];
|
|
|
|
|
2018-03-20 10:40:08 +00:00
|
|
|
window = gdk_surface_new_toplevel (gdk_display_get_default(), 10 , 10);
|
2018-03-20 11:05:26 +00:00
|
|
|
renderer = gsk_renderer_new_for_surface (window);
|
2017-12-25 11:56:21 +00:00
|
|
|
|
2019-03-19 02:57:04 +00:00
|
|
|
g_print ("Node file: '%s'\n", node_file);
|
|
|
|
g_print ("PNG file: '%s'\n", png_file);
|
2017-12-25 11:56:21 +00:00
|
|
|
|
|
|
|
/* Load the render node from the given .node file */
|
|
|
|
{
|
|
|
|
GBytes *bytes;
|
|
|
|
gsize len;
|
|
|
|
char *contents;
|
|
|
|
|
|
|
|
if (!g_file_get_contents (node_file, &contents, &len, &error))
|
|
|
|
{
|
2019-03-19 02:57:04 +00:00
|
|
|
g_print ("Could not open node file: %s\n", error->message);
|
2017-12-25 11:56:21 +00:00
|
|
|
g_clear_error (&error);
|
2019-05-20 01:29:11 +00:00
|
|
|
return 1;
|
2017-12-25 11:56:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bytes = g_bytes_new_take (contents, len);
|
2019-05-20 01:29:11 +00:00
|
|
|
node = gsk_render_node_deserialize (bytes, deserialize_error_func, &success);
|
2017-12-25 11:56:21 +00:00
|
|
|
g_bytes_unref (bytes);
|
|
|
|
|
2019-02-23 06:57:12 +00:00
|
|
|
g_assert_no_error (error);
|
2017-12-25 11:56:21 +00:00
|
|
|
g_assert (node != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Render the .node file and download to cairo surface */
|
|
|
|
texture = gsk_renderer_render_texture (renderer, node, NULL);
|
|
|
|
g_assert (texture != NULL);
|
|
|
|
|
|
|
|
rendered_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
|
|
gdk_texture_get_width (texture),
|
|
|
|
gdk_texture_get_height (texture));
|
|
|
|
gdk_texture_download (texture,
|
|
|
|
cairo_image_surface_get_data (rendered_surface),
|
|
|
|
cairo_image_surface_get_stride (rendered_surface));
|
|
|
|
cairo_surface_mark_dirty (rendered_surface);
|
|
|
|
|
|
|
|
/* Load the given reference png file */
|
|
|
|
reference_surface = cairo_image_surface_create_from_png (png_file);
|
2019-05-20 01:29:11 +00:00
|
|
|
if (cairo_surface_status (reference_surface))
|
|
|
|
{
|
|
|
|
g_print ("Error loading reference surface: %s\n",
|
|
|
|
cairo_status_to_string (cairo_surface_status (reference_surface)));
|
|
|
|
success = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Now compare the two */
|
|
|
|
diff_surface = reftest_compare_surfaces (rendered_surface, reference_surface);
|
|
|
|
|
|
|
|
if (diff_surface)
|
|
|
|
{
|
|
|
|
save_image (diff_surface, node_file, ".diff.png");
|
|
|
|
cairo_surface_destroy (diff_surface);
|
|
|
|
success = FALSE;
|
|
|
|
}
|
|
|
|
}
|
2017-12-25 11:56:21 +00:00
|
|
|
|
|
|
|
save_image (rendered_surface, node_file, ".out.png");
|
|
|
|
|
2019-05-20 01:29:11 +00:00
|
|
|
cairo_surface_destroy (reference_surface);
|
|
|
|
cairo_surface_destroy (rendered_surface);
|
|
|
|
g_object_unref (texture);
|
2017-12-25 11:56:21 +00:00
|
|
|
|
2019-05-20 01:29:11 +00:00
|
|
|
return success ? 0 : 1;
|
2017-12-25 11:56:21 +00:00
|
|
|
}
|