mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-08 11:40:16 +00:00
6cd6da050b
This takes a render node tree and "replays" it by using the GtkSnapshot machinery. We don't necesserily expect to get back an exactly equal render node tree back, since GtkSnapshot applies various small optimizations where possible, but the original and the replayed nodes should render to identical textures. Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
489 lines
15 KiB
C
489 lines
15 KiB
C
#include <gtk/gtk.h>
|
|
|
|
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);
|
|
}
|
|
}
|