diff --git a/gsk/gsktransform.c b/gsk/gsktransform.c index 4f7174d349..ada7164e37 100644 --- a/gsk/gsktransform.c +++ b/gsk/gsktransform.c @@ -857,7 +857,8 @@ normalize_angle (float angle) * @next: (nullable) (transfer full): the next transform * @angle: the rotation angle, in degrees (clockwise) * - * Rotates @next @angle degrees in 2D - or in 3D-speak, around the z axis. + * Rotates @next @angle degrees in 2D - or in 3D-speak, around the Z axis. + * The rotation happens around the origin point of (0, 0). * * Returns: (nullable): The new transform */ diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index 9cd4d4ae09..3f009142bf 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -717,6 +717,16 @@ gtk_snapshot_collect_repeat (GtkSnapshot *snapshot, return repeat_node; } +static GskRenderNode * +gtk_snapshot_collect_discard_repeat (GtkSnapshot *snapshot, + GtkSnapshotState *state, + GskRenderNode **nodes, + guint n_nodes) +{ + /* Drop the node and return nothing. */ + return NULL; +} + static void gtk_graphene_rect_scale_affine (const graphene_rect_t *rect, float scale_x, @@ -807,17 +817,24 @@ gtk_snapshot_push_repeat (GtkSnapshot *snapshot, const graphene_rect_t *child_bounds) { GtkSnapshotState *state; + gboolean empty_child_bounds = FALSE; graphene_rect_t real_child_bounds = { { 0 } }; float scale_x, scale_y, dx, dy; gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &dx, &dy); if (child_bounds) - gtk_graphene_rect_scale_affine (child_bounds, scale_x, scale_y, dx, dy, &real_child_bounds); + { + gtk_graphene_rect_scale_affine (child_bounds, scale_x, scale_y, dx, dy, &real_child_bounds); + if (real_child_bounds.size.width <= 0 || real_child_bounds.size.height <= 0) + empty_child_bounds = TRUE; + } state = gtk_snapshot_push_state (snapshot, gtk_snapshot_get_current_state (snapshot)->transform, - gtk_snapshot_collect_repeat, + empty_child_bounds + ? gtk_snapshot_collect_discard_repeat + : gtk_snapshot_collect_repeat, NULL); gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &state->data.repeat.bounds); @@ -2051,9 +2068,10 @@ gtk_snapshot_translate_3d (GtkSnapshot *snapshot, * @angle: the rotation angle, in degrees (clockwise) * * Rotates @@snapshot's coordinate system by @angle degrees in 2D space - - * or in 3D speak, rotates around the Z axis. + * or in 3D speak, rotates around the Z axis. The rotation happens around + * the origin point of (0, 0) in the @snapshot's current coordinate system. * - * To rotate around other axes, use [method@Gsk.Transform.rotate_3d]. + * To rotate around axes other than the Z axis, use [method@Gsk.Transform.rotate_3d]. */ void gtk_snapshot_rotate (GtkSnapshot *snapshot, diff --git a/testsuite/gsk/compare-render.c b/testsuite/gsk/compare-render.c index 7ba25ad961..1aeec97afd 100644 --- a/testsuite/gsk/compare-render.c +++ b/testsuite/gsk/compare-render.c @@ -9,6 +9,10 @@ static gboolean flip = FALSE; static gboolean rotate = FALSE; static gboolean repeat = FALSE; static gboolean mask = FALSE; +static gboolean replay = FALSE; + +extern void +replay_node (GskRenderNode *node, GtkSnapshot *snapshot); static const char * get_output_dir (void) @@ -159,6 +163,7 @@ static const GOptionEntry options[] = { { "rotate", 0, 0, G_OPTION_ARG_NONE, &rotate, "Do rotated test", NULL }, { "repeat", 0, 0, G_OPTION_ARG_NONE, &repeat, "Do repeated test", NULL }, { "mask", 0, 0, G_OPTION_ARG_NONE, &mask, "Do masked test", NULL }, + { "replay", 0, 0, G_OPTION_ARG_NONE, &replay, "Do replay test", NULL }, { NULL } }; @@ -487,6 +492,45 @@ main (int argc, char **argv) gsk_render_node_unref (node2); } + if (replay) + { + GskRenderNode *node2; + GdkTexture *rendered_texture2; + graphene_rect_t node_bounds, node2_bounds; + GtkSnapshot *snapshot = gtk_snapshot_new (); + + replay_node (node, snapshot); + node2 = gtk_snapshot_free_to_node (snapshot); + /* If the whole render node tree got eliminated, make sure we have + something to work with nevertheless. */ + if (!node2) + node2 = gsk_container_node_new (NULL, 0); + + gsk_render_node_get_bounds (node, &node_bounds); + gsk_render_node_get_bounds (node2, &node2_bounds); + /* Check that the node didn't grow. */ + success = success && graphene_rect_contains_rect (&node_bounds, &node2_bounds); + + rendered_texture = gsk_renderer_render_texture (renderer, node, &node_bounds); + rendered_texture2 = gsk_renderer_render_texture (renderer, node2, &node_bounds); + g_assert_nonnull (rendered_texture); + g_assert_nonnull (rendered_texture2); + + diff_texture = reftest_compare_textures (rendered_texture, rendered_texture2); + + if (diff_texture) + { + save_image (diff_texture, node_file, "-replayed.diff.png"); + save_node (node2, node_file, "-replayed.node"); + g_object_unref (diff_texture); + success = FALSE; + } + + g_clear_object (&rendered_texture); + g_clear_object (&rendered_texture2); + gsk_render_node_unref (node2); + } + gsk_render_node_unref (node); gsk_renderer_unrealize (renderer); diff --git a/testsuite/gsk/compare/color-matrix-merge.node b/testsuite/gsk/compare/color-matrix-merge.node new file mode 100644 index 0000000000..d4bd7820f2 --- /dev/null +++ b/testsuite/gsk/compare/color-matrix-merge.node @@ -0,0 +1,17 @@ +color-matrix { + matrix: matrix3d(1, 0, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 0, + 0, 0, 0, 1); + offset: -1 0 1 0; + child: color-matrix { + matrix: matrix3d(0, 1, 0, 0, + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + offset: 1 0 0 0; + child: color { + color: red; + } + } +} diff --git a/testsuite/gsk/compare/color-matrix-merge.png b/testsuite/gsk/compare/color-matrix-merge.png new file mode 100644 index 0000000000..90927b4981 Binary files /dev/null and b/testsuite/gsk/compare/color-matrix-merge.png differ diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index 01c0ec24d5..ace6e9d98b 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -1,5 +1,5 @@ compare_render = executable('compare-render', - ['compare-render.c', '../reftests/reftest-compare.c'], + ['compare-render.c', '../reftests/reftest-compare.c', 'replay-node.c'], dependencies: libgtk_dep, c_args: common_cflags, ) @@ -34,6 +34,7 @@ compare_render_tests = [ 'clip-translate-offscreen', 'color-blur0', 'color-matrix-identity', + 'color-matrix-merge', 'color-matrix-parsing', 'crossfade-clip-both-children', 'cross-fade-in-opacity', @@ -148,6 +149,13 @@ foreach renderer : renderers suites += 'wayland_gles_failing' endif + test_env = [ + 'GSK_RENDERER=' + renderer_name, + 'GTK_A11Y=test', + 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), + 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()) + ] + if ((exclude_term == '' or not testname.contains(exclude_term)) and (renderer_name != 'broadway' or broadway_enabled)) test(renderer_name + ' ' + testname, compare_render, @@ -156,12 +164,7 @@ foreach renderer : renderers join_paths(meson.current_source_dir(), 'compare', testname + '.node'), join_paths(meson.current_source_dir(), 'compare', testname + '.png'), ], - env: [ - 'GSK_RENDERER=' + renderer_name, - 'GTK_A11Y=test', - 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), - 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()) - ], + env: test_env, suite: suites, ) test(renderer_name + ' ' + testname + ' flipped', compare_render, @@ -171,12 +174,7 @@ foreach renderer : renderers join_paths(meson.current_source_dir(), 'compare', testname + '.node'), join_paths(meson.current_source_dir(), 'compare', testname + '.png'), ], - env: [ - 'GSK_RENDERER=' + renderer_name, - 'GTK_A11Y=test', - 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), - 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()) - ], + env: test_env, suite: suites + [ 'gsk-compare-flipped-' + renderer_name ], ) test(renderer_name + ' ' + testname + ' repeated', compare_render, @@ -186,12 +184,7 @@ foreach renderer : renderers join_paths(meson.current_source_dir(), 'compare', testname + '.node'), join_paths(meson.current_source_dir(), 'compare', testname + '.png'), ], - env: [ - 'GSK_RENDERER=' + renderer_name, - 'GTK_A11Y=test', - 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), - 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()) - ], + env: test_env, suite: suites + [ 'gsk-compare-repeated-' + renderer_name ], ) test(renderer_name + ' ' + testname + ' rotated', compare_render, @@ -201,12 +194,7 @@ foreach renderer : renderers join_paths(meson.current_source_dir(), 'compare', testname + '.node'), join_paths(meson.current_source_dir(), 'compare', testname + '.png'), ], - env: [ - 'GSK_RENDERER=' + renderer_name, - 'GTK_A11Y=test', - 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), - 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()) - ], + env: test_env, suite: suites + [ 'gsk-compare-rotated-' + renderer_name ], ) test(renderer_name + ' ' + testname + ' masked', compare_render, @@ -216,14 +204,19 @@ foreach renderer : renderers join_paths(meson.current_source_dir(), 'compare', testname + '.node'), join_paths(meson.current_source_dir(), 'compare', testname + '.png'), ], - env: [ - 'GSK_RENDERER=' + renderer_name, - 'GTK_A11Y=test', - 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), - 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()) - ], + env: test_env, suite: suites + [ 'gsk-compare-masked-' + renderer_name ], ) + test(renderer_name + ' ' + testname + ' replayed', compare_render, + args: [ + '--replay', + '--output', join_paths(meson.current_build_dir(), 'compare', renderer_name), + join_paths(meson.current_source_dir(), 'compare', testname + '.node'), + join_paths(meson.current_source_dir(), 'compare', testname + '.png'), + ], + env: test_env, + suite: suites + [ 'gsk-compare-replayed-' + renderer_name ], + ) endif endforeach endforeach diff --git a/testsuite/gsk/replay-node.c b/testsuite/gsk/replay-node.c new file mode 100644 index 0000000000..a9b93bfce8 --- /dev/null +++ b/testsuite/gsk/replay-node.c @@ -0,0 +1,488 @@ +#include + +void +replay_node (GskRenderNode *node, GtkSnapshot *snapshot); + +static void +replay_container_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + for (guint i = 0; i < gsk_container_node_get_n_children (node); i++) + replay_node (gsk_container_node_get_child (node, i), snapshot); +} + +static void +replay_cairo_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + cairo_surface_t *surface = gsk_cairo_node_get_surface (node); + graphene_rect_t bounds; + gsk_render_node_get_bounds (node, &bounds); + + cairo_t *cr = gtk_snapshot_append_cairo (snapshot, &bounds); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); +} + +static void +replay_color_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + graphene_rect_t bounds; + gsk_render_node_get_bounds (node, &bounds); + gtk_snapshot_append_color (snapshot, + gsk_color_node_get_color (node), + &bounds); +} + +static void +replay_linear_gradient_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + graphene_rect_t bounds; + const graphene_point_t *start_point, *end_point; + const GskColorStop *stops; + gsize n_stops; + + gsk_render_node_get_bounds (node, &bounds); + start_point = gsk_linear_gradient_node_get_start (node); + end_point = gsk_linear_gradient_node_get_end (node); + stops = gsk_linear_gradient_node_get_color_stops (node, &n_stops); + + if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE) + gtk_snapshot_append_repeating_linear_gradient (snapshot, &bounds, + start_point, end_point, + stops, n_stops); + else + gtk_snapshot_append_linear_gradient (snapshot, &bounds, + start_point, end_point, + stops, n_stops); +} + +static void +replay_radial_gradient_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + graphene_rect_t bounds; + gsk_render_node_get_bounds (node, &bounds); + const graphene_point_t *center = gsk_radial_gradient_node_get_center (node); + float hradius = gsk_radial_gradient_node_get_hradius (node); + float vradius = gsk_radial_gradient_node_get_vradius (node); + float start = gsk_radial_gradient_node_get_start (node); + float end = gsk_radial_gradient_node_get_end (node); + gsize n_stops; + const GskColorStop *stops = gsk_radial_gradient_node_get_color_stops (node, + &n_stops); + + if (gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE) + gtk_snapshot_append_repeating_radial_gradient (snapshot, &bounds, center, + hradius, vradius, start, end, + stops, n_stops); + else + gtk_snapshot_append_radial_gradient (snapshot, &bounds, center, + hradius, vradius, start, end, + stops, n_stops); +} + +static void +replay_conic_gradient_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + graphene_rect_t bounds; + gsk_render_node_get_bounds (node, &bounds); + const graphene_point_t *center = gsk_conic_gradient_node_get_center (node); + float rotation = gsk_conic_gradient_node_get_rotation (node); + gsize n_stops; + const GskColorStop *stops = gsk_conic_gradient_node_get_color_stops (node, + &n_stops); + + gtk_snapshot_append_conic_gradient (snapshot, &bounds, center, + rotation, stops, n_stops); +} + +static void +replay_border_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + const GskRoundedRect *outline = gsk_border_node_get_outline (node); + const float *border_width = gsk_border_node_get_widths (node); + const GdkRGBA *border_color = gsk_border_node_get_colors (node); + + gtk_snapshot_append_border (snapshot, outline, border_width, border_color); +} + +static void +replay_texture_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + GdkTexture *texture = gsk_texture_node_get_texture (node); + graphene_rect_t bounds; + gsk_render_node_get_bounds (node, &bounds); + + gtk_snapshot_append_texture (snapshot, texture, &bounds); +} + +static void +replay_inset_shadow_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + const GskRoundedRect *outline = gsk_inset_shadow_node_get_outline (node); + const GdkRGBA *color = gsk_inset_shadow_node_get_color (node); + float dx = gsk_inset_shadow_node_get_dx (node); + float dy = gsk_inset_shadow_node_get_dy (node); + float spread = gsk_inset_shadow_node_get_spread (node); + float blur_radius = gsk_inset_shadow_node_get_blur_radius (node); + + gtk_snapshot_append_inset_shadow (snapshot, outline, color, + dx, dy, spread, blur_radius); +} + +static void +replay_outset_shadow_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + const GskRoundedRect *outline = gsk_outset_shadow_node_get_outline (node); + const GdkRGBA *color = gsk_outset_shadow_node_get_color (node); + float dx = gsk_outset_shadow_node_get_dx (node); + float dy = gsk_outset_shadow_node_get_dy (node); + float spread = gsk_outset_shadow_node_get_spread (node); + float blur_radius = gsk_outset_shadow_node_get_blur_radius (node); + + gtk_snapshot_append_outset_shadow (snapshot, outline, color, + dx, dy, spread, blur_radius); +} + +static void +replay_transform_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + GskTransform *transform = gsk_transform_node_get_transform (node); + GskRenderNode *child = gsk_transform_node_get_child (node); + + gtk_snapshot_save (snapshot); + gtk_snapshot_transform (snapshot, transform); + replay_node (child, snapshot); + gtk_snapshot_restore (snapshot); +} + +static void +replay_opacity_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + float opacity = gsk_opacity_node_get_opacity (node); + GskRenderNode *child = gsk_opacity_node_get_child (node); + + gtk_snapshot_push_opacity (snapshot, opacity); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_color_matrix_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + const graphene_matrix_t *matrix = gsk_color_matrix_node_get_color_matrix (node); + const graphene_vec4_t *offset = gsk_color_matrix_node_get_color_offset (node); + GskRenderNode *child = gsk_color_matrix_node_get_child (node); + + gtk_snapshot_push_color_matrix (snapshot, matrix, offset); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_repeat_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + GskRenderNode *child = gsk_repeat_node_get_child (node); + const graphene_rect_t *child_bounds = gsk_repeat_node_get_child_bounds (node); + graphene_rect_t bounds; + gsk_render_node_get_bounds (node, &bounds); + + gtk_snapshot_push_repeat (snapshot, &bounds, child_bounds); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_clip_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + const graphene_rect_t *clip = gsk_clip_node_get_clip (node); + GskRenderNode *child = gsk_clip_node_get_child (node); + + gtk_snapshot_push_clip (snapshot, clip); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_rounded_clip_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + const GskRoundedRect *bounds = gsk_rounded_clip_node_get_clip (node); + GskRenderNode *child = gsk_rounded_clip_node_get_child (node); + + gtk_snapshot_push_rounded_clip (snapshot, bounds); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_shadow_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + gsize n_shadows = gsk_shadow_node_get_n_shadows (node); + /* Hack: we know GskShadowNode stores shadows in a contiguous array. */ + const GskShadow *shadow = gsk_shadow_node_get_shadow (node, 0); + GskRenderNode *child = gsk_shadow_node_get_child (node); + + gtk_snapshot_push_shadow (snapshot, shadow, n_shadows); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_blend_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node); + GskRenderNode *top_child = gsk_blend_node_get_top_child (node); + GskBlendMode blend_mode = gsk_blend_node_get_blend_mode (node); + + gtk_snapshot_push_blend (snapshot, blend_mode); + replay_node (bottom_child, snapshot); + gtk_snapshot_pop (snapshot); + replay_node (top_child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_cross_fade_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + GskRenderNode *start_child = gsk_cross_fade_node_get_start_child (node); + GskRenderNode *end_child = gsk_cross_fade_node_get_end_child (node); + float progress = gsk_cross_fade_node_get_progress (node); + + gtk_snapshot_push_cross_fade (snapshot, progress); + replay_node (start_child, snapshot); + gtk_snapshot_pop (snapshot); + replay_node (end_child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_text_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ +#if 0 + /* The following does not compile, since gtk_snapshot_append_text () is + * not exported. */ + + PangoFont *font = gsk_text_node_get_font (node); + PangoGlyphString glyphs; + guint n_glyphs = 0; + glyphs.glyphs = (PangoGlyphInfo *) gsk_text_node_get_glyphs (node, &n_glyphs); + const GdkRGBA *color = gsk_text_node_get_color (node); + const graphene_point_t *offset = gsk_text_node_get_offset (node); + + glyphs.num_glyphs = n_glyphs; + glyphs.log_clusters = NULL; + + gtk_snapshot_append_text (snapshot, font, glyphs, color, + offset->x, offset->y); +#else + gtk_snapshot_append_node (snapshot, node); +#endif +} + +static void +replay_blur_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + float radius = gsk_blur_node_get_radius (node); + GskRenderNode *child = gsk_blur_node_get_child (node); + + gtk_snapshot_push_blur (snapshot, radius); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_debug_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + const char *message = gsk_debug_node_get_message (node); + GskRenderNode *child = gsk_debug_node_get_child (node); + + gtk_snapshot_push_debug (snapshot, "%s", message); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_gl_shader_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + graphene_rect_t bounds; + gsk_render_node_get_bounds (node, &bounds); + GskGLShader *shader = gsk_gl_shader_node_get_shader (node); + GBytes *args = gsk_gl_shader_node_get_args (node); + + gtk_snapshot_push_gl_shader (snapshot, shader, &bounds, g_bytes_ref (args)); + for (guint i = 0; i < gsk_gl_shader_node_get_n_children (node); i++) + { + GskRenderNode *child = gsk_gl_shader_node_get_child (node, i); + replay_node (child, snapshot); + gtk_snapshot_gl_shader_pop_texture (snapshot); + } + gtk_snapshot_pop (snapshot); +} + +static void +replay_texture_scale_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + GdkTexture *texture = gsk_texture_scale_node_get_texture (node); + GskScalingFilter filter = gsk_texture_scale_node_get_filter (node); + graphene_rect_t bounds; + gsk_render_node_get_bounds (node, &bounds); + + gtk_snapshot_append_scaled_texture (snapshot, texture, filter, &bounds); +} + +static void +replay_mask_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + GskMaskMode mask_mode = gsk_mask_node_get_mask_mode (node); + GskRenderNode *source = gsk_mask_node_get_source (node); + GskRenderNode *mask = gsk_mask_node_get_mask (node); + + gtk_snapshot_push_mask (snapshot, mask_mode); + replay_node (mask, snapshot); + gtk_snapshot_pop (snapshot); + replay_node (source, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_fill_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + GskPath *path = gsk_fill_node_get_path (node); + GskFillRule fill_rule = gsk_fill_node_get_fill_rule (node); + GskRenderNode *child = gsk_fill_node_get_child (node); + + gtk_snapshot_push_fill (snapshot, path, fill_rule); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +static void +replay_stroke_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + GskPath *path = gsk_stroke_node_get_path (node); + const GskStroke *stroke = gsk_stroke_node_get_stroke (node); + GskRenderNode *child = gsk_stroke_node_get_child (node); + + gtk_snapshot_push_stroke (snapshot, path, stroke); + replay_node (child, snapshot); + gtk_snapshot_pop (snapshot); +} + +void +replay_node (GskRenderNode *node, GtkSnapshot *snapshot) +{ + switch (gsk_render_node_get_node_type (node)) + { + case GSK_CONTAINER_NODE: + replay_container_node (node, snapshot); + break; + + case GSK_CAIRO_NODE: + replay_cairo_node (node, snapshot); + break; + + case GSK_COLOR_NODE: + replay_color_node (node, snapshot); + break; + + case GSK_LINEAR_GRADIENT_NODE: + case GSK_REPEATING_LINEAR_GRADIENT_NODE: + replay_linear_gradient_node (node, snapshot); + break; + + case GSK_RADIAL_GRADIENT_NODE: + case GSK_REPEATING_RADIAL_GRADIENT_NODE: + replay_radial_gradient_node (node, snapshot); + break; + + case GSK_CONIC_GRADIENT_NODE: + replay_conic_gradient_node (node, snapshot); + break; + + case GSK_BORDER_NODE: + replay_border_node (node, snapshot); + break; + + case GSK_TEXTURE_NODE: + replay_texture_node (node, snapshot); + break; + + case GSK_INSET_SHADOW_NODE: + replay_inset_shadow_node (node, snapshot); + break; + + case GSK_OUTSET_SHADOW_NODE: + replay_outset_shadow_node (node, snapshot); + break; + + case GSK_TRANSFORM_NODE: + replay_transform_node (node, snapshot); + break; + + case GSK_OPACITY_NODE: + replay_opacity_node (node, snapshot); + break; + + case GSK_COLOR_MATRIX_NODE: + replay_color_matrix_node (node, snapshot); + break; + + case GSK_REPEAT_NODE: + replay_repeat_node (node, snapshot); + break; + + case GSK_CLIP_NODE: + replay_clip_node (node, snapshot); + break; + + case GSK_ROUNDED_CLIP_NODE: + replay_rounded_clip_node (node, snapshot); + break; + + case GSK_SHADOW_NODE: + replay_shadow_node (node, snapshot); + break; + + case GSK_BLEND_NODE: + replay_blend_node (node, snapshot); + break; + + case GSK_CROSS_FADE_NODE: + replay_cross_fade_node (node, snapshot); + break; + + case GSK_TEXT_NODE: + replay_text_node (node, snapshot); + break; + + case GSK_BLUR_NODE: + replay_blur_node (node, snapshot); + break; + + case GSK_DEBUG_NODE: + replay_debug_node (node, snapshot); + break; + + case GSK_GL_SHADER_NODE: + replay_gl_shader_node (node, snapshot); + break; + + case GSK_TEXTURE_SCALE_NODE: + replay_texture_scale_node (node, snapshot); + break; + + case GSK_MASK_NODE: + replay_mask_node (node, snapshot); + break; + + case GSK_FILL_NODE: + replay_fill_node (node, snapshot); + break; + + case GSK_STROKE_NODE: + replay_stroke_node (node, snapshot); + break; + + case GSK_NOT_A_RENDER_NODE: + default: + g_assert (FALSE); + } +}