mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 06:00:22 +00:00
testsuite: Add offload tests
These tests come in two variants. The first takes .node and .offload file, parses the node file, and compares the resulting subsurface attachments to expected results. The second variant takes two .node/.offload file pairs and a .diff file, parses the node files, compares the resulting subsurface attachments, and then diffs the nodes, comparing the resulting area to the region in the .diff file.
This commit is contained in:
parent
d3a5aa5304
commit
44d977844b
180
testsuite/gsk/gskrendernodeattach.c
Normal file
180
testsuite/gsk/gskrendernodeattach.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2023, Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gskrendernodeattach.h"
|
||||
#include "gsk/gsk.h"
|
||||
#include "gsk/gskrendernodeprivate.h"
|
||||
#include "gdk/gdksurfaceprivate.h"
|
||||
#include "gdk/gdksubsurfaceprivate.h"
|
||||
|
||||
|
||||
static GskRenderNode *
|
||||
node_attach (const GskRenderNode *node,
|
||||
GdkSurface *surface,
|
||||
int *idx)
|
||||
{
|
||||
switch (GSK_RENDER_NODE_TYPE (node))
|
||||
{
|
||||
case GSK_CAIRO_NODE:
|
||||
case GSK_COLOR_NODE:
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
case GSK_BORDER_NODE:
|
||||
case GSK_TEXTURE_NODE:
|
||||
case GSK_TEXTURE_SCALE_NODE:
|
||||
case GSK_INSET_SHADOW_NODE:
|
||||
case GSK_OUTSET_SHADOW_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
return gsk_render_node_ref ((GskRenderNode *)node);
|
||||
|
||||
case GSK_TRANSFORM_NODE:
|
||||
return gsk_transform_node_new (node_attach (gsk_transform_node_get_child (node), surface, idx),
|
||||
gsk_transform_node_get_transform (node));
|
||||
|
||||
case GSK_OPACITY_NODE:
|
||||
return gsk_opacity_node_new (node_attach (gsk_opacity_node_get_child (node), surface, idx),
|
||||
gsk_opacity_node_get_opacity (node));
|
||||
|
||||
case GSK_COLOR_MATRIX_NODE:
|
||||
return gsk_color_matrix_node_new (node_attach (gsk_color_matrix_node_get_child (node), surface, idx),
|
||||
gsk_color_matrix_node_get_color_matrix (node),
|
||||
gsk_color_matrix_node_get_color_offset (node));
|
||||
|
||||
case GSK_REPEAT_NODE:
|
||||
return gsk_repeat_node_new (&node->bounds,
|
||||
node_attach (gsk_repeat_node_get_child (node), surface, idx),
|
||||
gsk_repeat_node_get_child_bounds (node));
|
||||
|
||||
case GSK_CONTAINER_NODE:
|
||||
{
|
||||
GskRenderNode **children = g_newa (GskRenderNode *, gsk_container_node_get_n_children (node));
|
||||
for (int i = 0; i < gsk_container_node_get_n_children (node); i++)
|
||||
children[i] = node_attach (gsk_container_node_get_child (node, i), surface, idx);
|
||||
return gsk_container_node_new (children, gsk_container_node_get_n_children (node));
|
||||
}
|
||||
|
||||
case GSK_CLIP_NODE:
|
||||
return gsk_clip_node_new (node_attach (gsk_clip_node_get_child (node), surface, idx),
|
||||
gsk_clip_node_get_clip (node));
|
||||
|
||||
case GSK_ROUNDED_CLIP_NODE:
|
||||
return gsk_rounded_clip_node_new (node_attach (gsk_rounded_clip_node_get_child (node), surface, idx),
|
||||
gsk_rounded_clip_node_get_clip (node));
|
||||
|
||||
case GSK_SHADOW_NODE:
|
||||
{
|
||||
GskShadow *shadows = g_newa (GskShadow, gsk_shadow_node_get_n_shadows (node));
|
||||
for (int i = 0; i < gsk_shadow_node_get_n_shadows (node); i++)
|
||||
shadows[i] = *gsk_shadow_node_get_shadow (node, i);
|
||||
|
||||
return gsk_shadow_node_new (node_attach (gsk_shadow_node_get_child (node), surface, idx),
|
||||
shadows,
|
||||
gsk_shadow_node_get_n_shadows (node));
|
||||
}
|
||||
|
||||
case GSK_BLEND_NODE:
|
||||
return gsk_blend_node_new (node_attach (gsk_blend_node_get_bottom_child (node), surface, idx),
|
||||
node_attach (gsk_blend_node_get_top_child (node), surface, idx),
|
||||
gsk_blend_node_get_blend_mode (node));
|
||||
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
return gsk_cross_fade_node_new (node_attach (gsk_cross_fade_node_get_start_child (node), surface, idx),
|
||||
node_attach (gsk_cross_fade_node_get_end_child (node), surface, idx),
|
||||
gsk_cross_fade_node_get_progress (node));
|
||||
|
||||
case GSK_BLUR_NODE:
|
||||
return gsk_blur_node_new (node_attach (gsk_blur_node_get_child (node), surface, idx),
|
||||
gsk_blur_node_get_radius (node));
|
||||
|
||||
case GSK_DEBUG_NODE:
|
||||
return gsk_debug_node_new (node_attach (gsk_debug_node_get_child (node), surface, idx),
|
||||
g_strdup (gsk_debug_node_get_message (node)));
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
{
|
||||
GskRenderNode **children;
|
||||
|
||||
children = g_newa (GskRenderNode *, gsk_gl_shader_node_get_n_children (node));
|
||||
for (int i = 0; i < gsk_gl_shader_node_get_n_children (node); i++)
|
||||
children[i] = node_attach (gsk_gl_shader_node_get_child (node, i), surface, idx);
|
||||
return gsk_gl_shader_node_new (gsk_gl_shader_node_get_shader (node),
|
||||
&node->bounds,
|
||||
gsk_gl_shader_node_get_args (node),
|
||||
children,
|
||||
gsk_gl_shader_node_get_n_children (node));
|
||||
}
|
||||
|
||||
case GSK_MASK_NODE:
|
||||
return gsk_mask_node_new (node_attach (gsk_mask_node_get_source (node), surface, idx),
|
||||
node_attach (gsk_mask_node_get_mask (node), surface, idx),
|
||||
gsk_mask_node_get_mask_mode (node));
|
||||
|
||||
case GSK_FILL_NODE:
|
||||
return gsk_fill_node_new (node_attach (gsk_fill_node_get_child (node), surface, idx),
|
||||
gsk_fill_node_get_path (node),
|
||||
gsk_fill_node_get_fill_rule (node));
|
||||
|
||||
case GSK_STROKE_NODE:
|
||||
return gsk_stroke_node_new (node_attach (gsk_stroke_node_get_child (node), surface, idx),
|
||||
gsk_stroke_node_get_path (node),
|
||||
gsk_stroke_node_get_stroke (node));
|
||||
|
||||
case GSK_SUBSURFACE_NODE:
|
||||
{
|
||||
GdkSubsurface *subsurface;
|
||||
|
||||
g_assert (gsk_subsurface_node_get_subsurface (node) == NULL);
|
||||
|
||||
if (*idx == -1)
|
||||
subsurface = gdk_surface_create_subsurface (surface);
|
||||
else
|
||||
{
|
||||
subsurface = gdk_surface_get_subsurface (surface, *idx);
|
||||
(*idx)++;
|
||||
}
|
||||
return gsk_subsurface_node_new (node_attach (gsk_subsurface_node_get_child (node), surface, idx),
|
||||
subsurface);
|
||||
}
|
||||
|
||||
case GSK_NOT_A_RENDER_NODE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Find all the subsurface nodes in the given tree, and attach them
|
||||
* to a subsurface of the given surface. If the surface already has
|
||||
* subsurfaces, we assume that we are just reattaching, and that the
|
||||
* nodes are still in the same order. Otherwise, we create new
|
||||
* subsurfaces.
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_render_node_attach (const GskRenderNode *node,
|
||||
GdkSurface *surface)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (gdk_surface_get_n_subsurfaces (surface) > 0)
|
||||
idx = 0;
|
||||
else
|
||||
idx = -1;
|
||||
|
||||
return node_attach (node, surface, &idx);
|
||||
}
|
6
testsuite/gsk/gskrendernodeattach.h
Normal file
6
testsuite/gsk/gskrendernodeattach.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "gsk/gsk.h"
|
||||
|
||||
GskRenderNode * gsk_render_node_attach (const GskRenderNode *node,
|
||||
GdkSurface *surface);
|
@ -371,11 +371,47 @@ foreach test : node_parser_tests
|
||||
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
|
||||
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
|
||||
],
|
||||
protocol: 'exitcode',
|
||||
suite: 'gsk',
|
||||
)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
# offload does not work outside of linux
|
||||
if os_linux
|
||||
offload = executable('offload', 'offload.c', 'gskrendernodeattach.c',
|
||||
dependencies : libgtk_static_dep,
|
||||
c_args: common_cflags,
|
||||
)
|
||||
|
||||
offload_tests = [
|
||||
'simple.node',
|
||||
'transforms.node',
|
||||
'deep.node',
|
||||
'move.node',
|
||||
'start_offloading.node',
|
||||
'stop_offloading.node',
|
||||
]
|
||||
|
||||
foreach test : offload_tests
|
||||
if test.endswith('.node') and not test.endswith('.out')
|
||||
test('parser ' + test, offload,
|
||||
args: [
|
||||
join_paths(meson.current_source_dir(), 'offload', test)
|
||||
],
|
||||
env: [
|
||||
'GSK_RENDERER=opengl',
|
||||
'GTK_A11Y=test',
|
||||
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
|
||||
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
|
||||
],
|
||||
protocol: 'exitcode',
|
||||
suite: 'gsk',
|
||||
)
|
||||
endif
|
||||
endforeach
|
||||
endif
|
||||
|
||||
tests = [
|
||||
['transform'],
|
||||
['shader'],
|
||||
|
614
testsuite/gsk/offload.c
Normal file
614
testsuite/gsk/offload.c
Normal file
@ -0,0 +1,614 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Red Hat Inc.
|
||||
*
|
||||
* Author:
|
||||
* Matthias Clasen <mclasen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdksurfaceprivate.h>
|
||||
#include <gdk/gdksubsurfaceprivate.h>
|
||||
#include <gsk/gskrendernodeparserprivate.h>
|
||||
#include <gsk/gskrendernodeprivate.h>
|
||||
#include <gsk/gskoffloadprivate.h>
|
||||
#include "gskrendernodeattach.h"
|
||||
|
||||
static char *
|
||||
test_get_sibling_file (const char *node_file,
|
||||
const char *old_ext,
|
||||
const char *new_ext)
|
||||
{
|
||||
GString *file = g_string_new (NULL);
|
||||
|
||||
if (g_str_has_suffix (node_file, old_ext))
|
||||
g_string_append_len (file, node_file, strlen (node_file) - 5);
|
||||
else
|
||||
g_string_append (file, node_file);
|
||||
|
||||
g_string_append (file, new_ext);
|
||||
|
||||
if (!g_file_test (file->str, G_FILE_TEST_EXISTS))
|
||||
{
|
||||
g_string_free (file, TRUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_string_free (file, FALSE);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
diff_with_file (const char *file1,
|
||||
GBytes *input,
|
||||
GError **error)
|
||||
{
|
||||
char *buffer;
|
||||
gsize len;
|
||||
static const char msg[] = "The output is not as expected";
|
||||
|
||||
g_file_get_contents (file1, &buffer, &len, NULL);
|
||||
if (strcmp (buffer, (char *) g_bytes_get_data (input, NULL)) == 0)
|
||||
{
|
||||
g_free (buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_free (buffer);
|
||||
return g_bytes_new_static (msg, strlen (msg) + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
append_error_value (GString *string,
|
||||
GType enum_type,
|
||||
guint value)
|
||||
{
|
||||
GEnumClass *enum_class;
|
||||
GEnumValue *enum_value;
|
||||
|
||||
enum_class = g_type_class_ref (enum_type);
|
||||
enum_value = g_enum_get_value (enum_class, value);
|
||||
|
||||
g_string_append (string, enum_value->value_name);
|
||||
|
||||
g_type_class_unref (enum_class);
|
||||
}
|
||||
|
||||
static void
|
||||
deserialize_error_func (const GskParseLocation *start,
|
||||
const GskParseLocation *end,
|
||||
const GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
GString *errors = user_data;
|
||||
GString *string = g_string_new ("<data>");
|
||||
|
||||
g_string_append_printf (string, ":%zu:%zu",
|
||||
start->lines + 1, start->line_chars + 1);
|
||||
if (start->lines != end->lines || start->line_chars != end->line_chars)
|
||||
{
|
||||
g_string_append (string, "-");
|
||||
if (start->lines != end->lines)
|
||||
g_string_append_printf (string, "%zu:", end->lines + 1);
|
||||
g_string_append_printf (string, "%zu", end->line_chars + 1);
|
||||
}
|
||||
|
||||
g_string_append_printf (errors, "%s: error: ", string->str);
|
||||
g_string_free (string, TRUE);
|
||||
|
||||
if (error->domain == GTK_CSS_PARSER_ERROR)
|
||||
append_error_value (errors, GTK_TYPE_CSS_PARSER_ERROR, error->code);
|
||||
else if (error->domain == GTK_CSS_PARSER_WARNING)
|
||||
append_error_value (errors, GTK_TYPE_CSS_PARSER_WARNING, error->code);
|
||||
else
|
||||
g_string_append_printf (errors,
|
||||
"%s %u\n",
|
||||
g_quark_to_string (error->domain),
|
||||
error->code);
|
||||
|
||||
g_string_append_c (errors, '\n');
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
node_from_file (GFile *file)
|
||||
{
|
||||
GBytes *bytes;
|
||||
GError *error = NULL;
|
||||
GString *errors = NULL;
|
||||
GskRenderNode *node = NULL;
|
||||
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, &error);
|
||||
if (error)
|
||||
{
|
||||
g_print ("Error loading file: %s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
errors = g_string_new ("");
|
||||
node = gsk_render_node_deserialize (bytes,
|
||||
deserialize_error_func,
|
||||
errors);
|
||||
if (errors->len > 0)
|
||||
{
|
||||
g_print ("Error loading file: %s\n", errors->str);
|
||||
g_string_free (errors, TRUE);
|
||||
g_bytes_unref (bytes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_string_free (errors, TRUE);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
node_from_path (const char *path)
|
||||
{
|
||||
GFile *file = g_file_new_for_path (path);
|
||||
GskRenderNode *node = node_from_file (file);
|
||||
g_object_unref (file);
|
||||
return node;
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
collect_offload_info (GdkSurface *surface,
|
||||
GskOffload *offload)
|
||||
{
|
||||
GString *s;
|
||||
GBytes *bytes;
|
||||
|
||||
s = g_string_new ("");
|
||||
|
||||
for (unsigned int i = 0; i < gdk_surface_get_n_subsurfaces (surface); i++)
|
||||
{
|
||||
GdkSubsurface *subsurface = gdk_surface_get_subsurface (surface, i);
|
||||
|
||||
g_object_set_data (G_OBJECT (subsurface), "pos", GUINT_TO_POINTER (i));
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < gdk_surface_get_n_subsurfaces (surface); i++)
|
||||
{
|
||||
GdkSubsurface *subsurface;
|
||||
GskOffloadInfo *info;
|
||||
char above[20];
|
||||
|
||||
subsurface = gdk_surface_get_subsurface (surface, i);
|
||||
info = gsk_offload_get_subsurface_info (offload, subsurface);
|
||||
|
||||
if (info->place_above)
|
||||
g_snprintf (above, sizeof (above), "%d",
|
||||
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (subsurface), "pos")));
|
||||
else
|
||||
g_snprintf (above, sizeof (above), "-");
|
||||
|
||||
if (info->can_offload)
|
||||
{
|
||||
g_string_append_printf (s, "%u: offloaded, %s%sabove: %s, ",
|
||||
i,
|
||||
info->was_offloaded ? "was offloaded, " : "",
|
||||
gdk_subsurface_is_above_parent (subsurface) ? "raised, " : "",
|
||||
above);
|
||||
g_string_append_printf (s, "texture: %dx%d, ",
|
||||
gdk_texture_get_width (info->texture),
|
||||
gdk_texture_get_height (info->texture));
|
||||
g_string_append_printf (s, "rect: %g %g %g %g\n",
|
||||
info->rect.origin.x, info->rect.origin.y,
|
||||
info->rect.size.width, info->rect.size.height);
|
||||
}
|
||||
else
|
||||
g_string_append_printf (s, "%u: %snot offloaded\n",
|
||||
i,
|
||||
info->was_offloaded ? "was offloaded, " : "");
|
||||
}
|
||||
|
||||
bytes = g_bytes_new (s->str, s->len + 1);
|
||||
|
||||
g_string_free (s, TRUE);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static char *
|
||||
region_to_string (cairo_region_t *region)
|
||||
{
|
||||
GString *s = g_string_new ("");
|
||||
|
||||
for (int i = 0; i < cairo_region_num_rectangles (region); i++)
|
||||
{
|
||||
cairo_rectangle_int_t r;
|
||||
|
||||
cairo_region_get_rectangle (region, i, &r);
|
||||
g_string_append_printf (s, "%d %d %d %d\n", r.x, r.y, r.width, r.height);
|
||||
}
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
region_contains_region (cairo_region_t *region1,
|
||||
cairo_region_t *region2)
|
||||
{
|
||||
for (int i = 0; i < cairo_region_num_rectangles (region2); i++)
|
||||
{
|
||||
cairo_rectangle_int_t r;
|
||||
|
||||
cairo_region_get_rectangle (region2, i, &r);
|
||||
if (cairo_region_contains_rectangle (region1, &r) != CAIRO_REGION_OVERLAP_IN)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
region_from_string (const char *str)
|
||||
{
|
||||
cairo_region_t *region;
|
||||
char **s;
|
||||
int len;
|
||||
|
||||
region = cairo_region_create ();
|
||||
|
||||
s = g_strsplit (str, "\n", 0);
|
||||
len = g_strv_length (s);
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
cairo_rectangle_int_t r;
|
||||
|
||||
if (s[i][0] == '\0')
|
||||
continue;
|
||||
|
||||
if (sscanf (s[i], "%d %d %d %d", &r.x, &r.y, &r.width, &r.height) == 4)
|
||||
cairo_region_union_rectangle (region, &r);
|
||||
else
|
||||
g_error ("failed to parse region");
|
||||
}
|
||||
|
||||
g_strfreev (s);
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
region_from_file (const char *path)
|
||||
{
|
||||
char *buffer;
|
||||
gsize len;
|
||||
GError *error = NULL;
|
||||
cairo_region_t *region;
|
||||
|
||||
if (!g_file_get_contents (path, &buffer, &len, &error))
|
||||
{
|
||||
g_error ("Failed to read region file: %s", error->message);
|
||||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
region = region_from_string (buffer);
|
||||
g_free (buffer);
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
static void
|
||||
notify_width (GdkSurface *surface,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
gboolean *done = data;
|
||||
|
||||
*done = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
compute_size (GdkToplevel *toplevel,
|
||||
GdkToplevelSize *size,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_connect (toplevel, "notify::width",
|
||||
G_CALLBACK (notify_width), data);
|
||||
gdk_toplevel_size_set_size (size, 800, 600);
|
||||
}
|
||||
|
||||
static GdkSurface *
|
||||
make_toplevel (void)
|
||||
{
|
||||
GdkSurface *surface;
|
||||
GdkToplevelLayout *layout;
|
||||
gboolean done;
|
||||
|
||||
surface = gdk_surface_new_toplevel (gdk_display_get_default ());
|
||||
|
||||
done = FALSE;
|
||||
g_signal_connect (surface, "compute-size", G_CALLBACK (compute_size), &done);
|
||||
|
||||
layout = gdk_toplevel_layout_new ();
|
||||
gdk_toplevel_present (GDK_TOPLEVEL (surface), layout);
|
||||
gdk_toplevel_layout_unref (layout);
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_node_file (GFile *file, const char *generate)
|
||||
{
|
||||
char *reference_file;
|
||||
GdkSurface *surface;
|
||||
GdkSubsurface *subsurface;
|
||||
GskOffload *offload;
|
||||
GskRenderNode *node, *tmp;
|
||||
GBytes *offload_state, *diff;
|
||||
GError *error = NULL;
|
||||
gboolean result = TRUE;
|
||||
cairo_region_t *clip, *region;
|
||||
char *path;
|
||||
GskRenderNode *node2;
|
||||
const char *generate_values[] = { "offload", "offload2", "diff", NULL };
|
||||
|
||||
if (generate && !g_strv_contains (generate_values, generate))
|
||||
{
|
||||
g_print ("Allowed --generate values are: ");
|
||||
for (int i = 0; generate_values[i]; i++)
|
||||
g_print ("%s ", generate_values[i]);
|
||||
g_print ("\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
surface = make_toplevel ();
|
||||
|
||||
subsurface = gdk_surface_create_subsurface (surface);
|
||||
if (subsurface == NULL)
|
||||
exit (77); /* subsurfaces aren't supported, skip these tests */
|
||||
g_clear_object (&subsurface);
|
||||
|
||||
node = node_from_file (file);
|
||||
if (node == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tmp = gsk_render_node_attach (node, surface);
|
||||
gsk_render_node_unref (node);
|
||||
node = tmp;
|
||||
|
||||
offload = gsk_offload_new (surface, node);
|
||||
offload_state = collect_offload_info (surface, offload);
|
||||
gsk_offload_free (offload);
|
||||
|
||||
if (g_strcmp0 (generate, "offload") == 0)
|
||||
{
|
||||
g_print ("%s", (char *)g_bytes_get_data (offload_state, NULL));
|
||||
g_bytes_unref (offload_state);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
reference_file = test_get_sibling_file (g_file_peek_path (file), ".node", ".offload");
|
||||
if (reference_file == NULL)
|
||||
return FALSE;
|
||||
|
||||
diff = diff_with_file (reference_file, offload_state, &error);
|
||||
g_assert_no_error (error);
|
||||
if (diff && g_bytes_get_size (diff) > 0)
|
||||
{
|
||||
g_print ("Resulting .offload file doesn't match reference:\n%s\n",
|
||||
(const char *) g_bytes_get_data (diff, NULL));
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
g_clear_pointer (&offload_state, g_bytes_unref);
|
||||
g_clear_pointer (&diff, g_bytes_unref);
|
||||
g_clear_pointer (&reference_file, g_free);
|
||||
|
||||
path = test_get_sibling_file (g_file_peek_path (file), ".node", ".node2");
|
||||
if (path)
|
||||
{
|
||||
node2 = node_from_path (path);
|
||||
tmp = gsk_render_node_attach (node2, surface);
|
||||
gsk_render_node_unref (node2);
|
||||
node2 = tmp;
|
||||
|
||||
offload = gsk_offload_new (surface, node2);
|
||||
offload_state = collect_offload_info (surface, offload);
|
||||
|
||||
if (g_strcmp0 (generate, "offload2") == 0)
|
||||
{
|
||||
g_print ("%s", (char *)g_bytes_get_data (offload_state, NULL));
|
||||
g_bytes_unref (offload_state);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
reference_file = test_get_sibling_file (g_file_peek_path (file), ".node", ".offload2");
|
||||
if (reference_file == NULL)
|
||||
return FALSE;
|
||||
|
||||
diff = diff_with_file (reference_file, offload_state, &error);
|
||||
g_assert_no_error (error);
|
||||
if (diff && g_bytes_get_size (diff) > 0)
|
||||
{
|
||||
g_print ("Resulting .offload2 file doesn't match reference:\n%s\n",
|
||||
(const char *) g_bytes_get_data (diff, NULL));
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
g_clear_pointer (&offload_state, g_bytes_unref);
|
||||
g_clear_pointer (&diff, g_bytes_unref);
|
||||
g_clear_pointer (&reference_file, g_free);
|
||||
|
||||
clip = cairo_region_create ();
|
||||
gsk_render_node_diff (node, node2, clip, offload);
|
||||
|
||||
if (g_strcmp0 (generate, "diff") == 0)
|
||||
{
|
||||
char *out = region_to_string (clip);
|
||||
g_print ("%s", out);
|
||||
cairo_region_destroy (clip);
|
||||
g_free (out);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
reference_file = test_get_sibling_file (g_file_peek_path (file), ".node", ".diff");
|
||||
region = region_from_file (reference_file);
|
||||
if (!region_contains_region (clip, region))
|
||||
{
|
||||
g_print ("Resulting region doesn't include reference:\n");
|
||||
g_print ("%s\n", region_to_string (clip));
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
g_clear_pointer (®ion, cairo_region_destroy);
|
||||
g_clear_pointer (&reference_file, g_free);
|
||||
g_clear_pointer (&clip, cairo_region_destroy);
|
||||
g_clear_pointer (&node2, gsk_render_node_unref);
|
||||
}
|
||||
|
||||
g_clear_pointer (&node, gsk_render_node_unref);
|
||||
gdk_surface_destroy (surface);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_file (GFile *file)
|
||||
{
|
||||
return parse_node_file (file, FALSE);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_files (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
GFile *file1 = G_FILE (a);
|
||||
GFile *file2 = G_FILE (b);
|
||||
char *path1, *path2;
|
||||
int result;
|
||||
|
||||
path1 = g_file_get_path (file1);
|
||||
path2 = g_file_get_path (file2);
|
||||
|
||||
result = strcmp (path1, path2);
|
||||
|
||||
g_free (path1);
|
||||
g_free (path2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_files_in_directory (GFile *dir)
|
||||
{
|
||||
GFileEnumerator *enumerator;
|
||||
GFileInfo *info;
|
||||
GList *l, *files;
|
||||
GError *error = NULL;
|
||||
gboolean result = TRUE;
|
||||
|
||||
enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
files = NULL;
|
||||
|
||||
while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
|
||||
{
|
||||
const char *filename;
|
||||
|
||||
filename = g_file_info_get_name (info);
|
||||
|
||||
if (!g_str_has_suffix (filename, ".node"))
|
||||
{
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
|
||||
files = g_list_prepend (files, g_file_get_child (dir, filename));
|
||||
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
g_assert_no_error (error);
|
||||
g_object_unref (enumerator);
|
||||
|
||||
files = g_list_sort (files, compare_files);
|
||||
for (l = files; l; l = l->next)
|
||||
{
|
||||
result &= test_file (l->data);
|
||||
}
|
||||
g_list_free_full (files, g_object_unref);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gboolean success;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
const char *basedir;
|
||||
GFile *dir;
|
||||
|
||||
gtk_test_init (&argc, &argv);
|
||||
|
||||
basedir = g_test_get_dir (G_TEST_DIST);
|
||||
dir = g_file_new_for_path (basedir);
|
||||
success = test_files_in_directory (dir);
|
||||
|
||||
g_object_unref (dir);
|
||||
}
|
||||
else if (g_str_has_prefix (argv[1], "--generate="))
|
||||
{
|
||||
/* We have up to 3 different result files, the extra
|
||||
* argument determines which one is generated. Possible
|
||||
* values are offload/offload2/diff.
|
||||
*/
|
||||
if (argc >= 3)
|
||||
{
|
||||
const char *generate = argv[1] + strlen ("--generate=");
|
||||
GFile *file = g_file_new_for_commandline_arg (argv[2]);
|
||||
|
||||
gtk_init ();
|
||||
|
||||
success = parse_node_file (file, generate);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
else
|
||||
success = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
guint i;
|
||||
|
||||
gtk_test_init (&argc, &argv);
|
||||
|
||||
success = TRUE;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
GFile *file = g_file_new_for_commandline_arg (argv[i]);
|
||||
|
||||
success &= test_file (file);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
}
|
||||
|
||||
return success ? 0 : 1;
|
||||
}
|
||||
|
58
testsuite/gsk/offload/deep.node
Normal file
58
testsuite/gsk/offload/deep.node
Normal file
@ -0,0 +1,58 @@
|
||||
subsurface {
|
||||
child: debug {
|
||||
message: "A node that is deep in, but still found";
|
||||
child: debug {
|
||||
message: "Affine transforms, debug nodes and single-child containers are ok";
|
||||
child: transform {
|
||||
transform: translate(10, 10) scale(5, 10);
|
||||
child: container {
|
||||
texture { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
subsurface {
|
||||
child: debug {
|
||||
message: "Multi-child containers are not ok";
|
||||
child: container {
|
||||
color { }
|
||||
texture { }
|
||||
}
|
||||
}
|
||||
}
|
||||
subsurface {
|
||||
child: debug {
|
||||
message: "other nodes, such as cross-fade, are not ok";
|
||||
child: cross-fade {
|
||||
start: texture { }
|
||||
end: texture { }
|
||||
progress: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
subsurface {
|
||||
child: debug {
|
||||
message: "Other nodes, such as cross-fade, are not ok";
|
||||
child: cross-fade {
|
||||
start: texture { }
|
||||
end: texture { }
|
||||
progress: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
subsurface {
|
||||
child: debug {
|
||||
message: "Clips (regardless how large) are not ok";
|
||||
child: clip {
|
||||
clip: 0 0 400 400;
|
||||
child: texture { }
|
||||
}
|
||||
}
|
||||
}
|
||||
subsurface {
|
||||
child: debug {
|
||||
message: "Can't offload non-textures";
|
||||
child: linear-gradient { }
|
||||
}
|
||||
}
|
6
testsuite/gsk/offload/deep.offload
Normal file
6
testsuite/gsk/offload/deep.offload
Normal file
@ -0,0 +1,6 @@
|
||||
0: offloaded, above: -, texture: 10x10, rect: 10 10 250 500
|
||||
1: not offloaded
|
||||
2: not offloaded
|
||||
3: not offloaded
|
||||
4: not offloaded
|
||||
5: not offloaded
|
2
testsuite/gsk/offload/move.diff
Normal file
2
testsuite/gsk/offload/move.diff
Normal file
@ -0,0 +1,2 @@
|
||||
20 20 16 16
|
||||
40 40 20 20
|
15
testsuite/gsk/offload/move.node
Normal file
15
testsuite/gsk/offload/move.node
Normal file
@ -0,0 +1,15 @@
|
||||
container {
|
||||
color {
|
||||
bounds: 0 0 800 600;
|
||||
color: red;
|
||||
}
|
||||
transform {
|
||||
transform: translate(20,20);
|
||||
child: subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="16" height="16"></svg>');
|
||||
bounds: 0 0 16 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
testsuite/gsk/offload/move.node2
Normal file
15
testsuite/gsk/offload/move.node2
Normal file
@ -0,0 +1,15 @@
|
||||
container {
|
||||
color {
|
||||
bounds: 0 0 800 600;
|
||||
color: red;
|
||||
}
|
||||
transform {
|
||||
transform: translate(40,40);
|
||||
child: subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="16" height="16"></svg>');
|
||||
bounds: 0 0 20 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
testsuite/gsk/offload/move.offload
Normal file
1
testsuite/gsk/offload/move.offload
Normal file
@ -0,0 +1 @@
|
||||
0: offloaded, raised, above: -, texture: 16x16, rect: 20 20 16 16
|
1
testsuite/gsk/offload/move.offload2
Normal file
1
testsuite/gsk/offload/move.offload2
Normal file
@ -0,0 +1 @@
|
||||
0: offloaded, raised, above: -, texture: 16x16, rect: 40 40 20 20
|
26
testsuite/gsk/offload/simple.node
Normal file
26
testsuite/gsk/offload/simple.node
Normal file
@ -0,0 +1,26 @@
|
||||
container {
|
||||
transform {
|
||||
transform: translate(20,20);
|
||||
child: subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="13" height="17"></svg>');
|
||||
}
|
||||
}
|
||||
}
|
||||
transform {
|
||||
transform: translate(0,100) scale(10, 10);
|
||||
child: subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="10" height="21"></svg>');
|
||||
}
|
||||
}
|
||||
}
|
||||
opacity {
|
||||
opacity: 0.5;
|
||||
child: subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="16" height="16"></svg>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
testsuite/gsk/offload/simple.offload
Normal file
3
testsuite/gsk/offload/simple.offload
Normal file
@ -0,0 +1,3 @@
|
||||
0: offloaded, above: -, texture: 13x17, rect: 20 20 50 50
|
||||
1: offloaded, raised, above: 1, texture: 10x21, rect: 0 100 500 500
|
||||
2: not offloaded
|
2
testsuite/gsk/offload/start_offloading.diff
Normal file
2
testsuite/gsk/offload/start_offloading.diff
Normal file
@ -0,0 +1,2 @@
|
||||
0 0 16 16
|
||||
16 16 16 16
|
12
testsuite/gsk/offload/start_offloading.node
Normal file
12
testsuite/gsk/offload/start_offloading.node
Normal file
@ -0,0 +1,12 @@
|
||||
subsurface {
|
||||
child: clip {
|
||||
clip: 0 0 200 200;
|
||||
child: transform {
|
||||
transform: translate(16, 16);
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="16" height="16"></svg>');
|
||||
bounds: 0 0 16 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
6
testsuite/gsk/offload/start_offloading.node2
Normal file
6
testsuite/gsk/offload/start_offloading.node2
Normal file
@ -0,0 +1,6 @@
|
||||
subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="16" height="16"></svg>');
|
||||
bounds: 0 0 16 16;
|
||||
}
|
||||
}
|
1
testsuite/gsk/offload/start_offloading.offload
Normal file
1
testsuite/gsk/offload/start_offloading.offload
Normal file
@ -0,0 +1 @@
|
||||
0: not offloaded
|
1
testsuite/gsk/offload/start_offloading.offload2
Normal file
1
testsuite/gsk/offload/start_offloading.offload2
Normal file
@ -0,0 +1 @@
|
||||
0: offloaded, raised, above: -, texture: 16x16, rect: 0 0 16 16
|
2
testsuite/gsk/offload/stop_offloading.diff
Normal file
2
testsuite/gsk/offload/stop_offloading.diff
Normal file
@ -0,0 +1,2 @@
|
||||
0 0 16 16
|
||||
16 16 16 16
|
6
testsuite/gsk/offload/stop_offloading.node
Normal file
6
testsuite/gsk/offload/stop_offloading.node
Normal file
@ -0,0 +1,6 @@
|
||||
subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="16" height="16"></svg>');
|
||||
bounds: 0 0 16 16;
|
||||
}
|
||||
}
|
12
testsuite/gsk/offload/stop_offloading.node2
Normal file
12
testsuite/gsk/offload/stop_offloading.node2
Normal file
@ -0,0 +1,12 @@
|
||||
subsurface {
|
||||
child: clip {
|
||||
clip: 0 0 200 200;
|
||||
child: transform {
|
||||
transform: translate(16, 16);
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="16" height="16"></svg>');
|
||||
bounds: 0 0 16 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
testsuite/gsk/offload/stop_offloading.offload
Normal file
1
testsuite/gsk/offload/stop_offloading.offload
Normal file
@ -0,0 +1 @@
|
||||
0: offloaded, raised, above: -, texture: 16x16, rect: 0 0 16 16
|
1
testsuite/gsk/offload/stop_offloading.offload2
Normal file
1
testsuite/gsk/offload/stop_offloading.offload2
Normal file
@ -0,0 +1 @@
|
||||
0: not offloaded
|
26
testsuite/gsk/offload/transforms.node
Normal file
26
testsuite/gsk/offload/transforms.node
Normal file
@ -0,0 +1,26 @@
|
||||
container {
|
||||
transform {
|
||||
transform: rotate(45);
|
||||
child: subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="13" height="17"></svg>');
|
||||
}
|
||||
}
|
||||
}
|
||||
transform {
|
||||
transform: translate3d(0, 1, 2);
|
||||
child: subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="10" height="21"></svg>');
|
||||
}
|
||||
}
|
||||
}
|
||||
transform {
|
||||
transform: translate(1, 2);
|
||||
child: subsurface {
|
||||
child: texture {
|
||||
texture: url('data:image/svg+xml;utf-8,<svg width="16" height="16"></svg>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
testsuite/gsk/offload/transforms.offload
Normal file
3
testsuite/gsk/offload/transforms.offload
Normal file
@ -0,0 +1,3 @@
|
||||
0: not offloaded
|
||||
1: not offloaded
|
||||
2: offloaded, raised, above: -, texture: 16x16, rect: 1 2 50 50
|
Loading…
Reference in New Issue
Block a user