diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index 59e1a3938d..f5cc1518aa 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -51,6 +51,7 @@ gsk_rounded_clip_node_new gsk_rounded_clip_node_get_child GskBlendMode gsk_blend_node_new +gsk_cross_fade_node_new GSK_IS_RENDER_NODE GSK_RENDER_NODE diff --git a/gsk/gskenums.h b/gsk/gskenums.h index 4e0e0bf35d..1d46c9230e 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -38,6 +38,7 @@ * @GSK_CLIP_NODE: A node that clips its child to a rectangular area * @GSK_ROUNDED_CLIP_NODE: A node that clips its child to a rounded rectangle * @GSK_BLEND_NODE: A node the blends two children together + * @GSK_CROSS_FADE_NODE: A node the cross-fades between two children * * The type of a node determines what the node is rendering. * @@ -55,7 +56,8 @@ typedef enum { GSK_OPACITY_NODE, GSK_CLIP_NODE, GSK_ROUNDED_CLIP_NODE, - GSK_BLEND_NODE + GSK_BLEND_NODE, + GSK_CROSS_FADE_NODE } GskRenderNodeType; /** diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 7562fb92ef..14fa797db9 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -117,6 +117,11 @@ GskRenderNode * gsk_blend_node_new (GskRenderNode GskRenderNode *top, GskBlendMode blend_mode); +GDK_AVAILABLE_IN_3_90 +GskRenderNode * gsk_cross_fade_node_new (GskRenderNode *start, + GskRenderNode *end, + double progress); + GDK_AVAILABLE_IN_3_90 void gsk_render_node_set_scaling_filter (GskRenderNode *node, GskScalingFilter min_filter, diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 5ab0d22beb..ee3cb46015 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -1402,3 +1402,139 @@ gsk_blend_node_get_blend_mode (GskRenderNode *node) return self->blend_mode; } +/*** GSK_CROSS_FADE_NODE ***/ + +typedef struct _GskCrossFadeNode GskCrossFadeNode; + +struct _GskCrossFadeNode +{ + GskRenderNode render_node; + + GskRenderNode *start; + GskRenderNode *end; + double progress; +}; + +static void +gsk_cross_fade_node_finalize (GskRenderNode *node) +{ + GskCrossFadeNode *self = (GskCrossFadeNode *) node; + + gsk_render_node_unref (self->start); + gsk_render_node_unref (self->end); +} + +static void +gsk_cross_fade_node_make_immutable (GskRenderNode *node) +{ + GskCrossFadeNode *self = (GskCrossFadeNode *) node; + + gsk_render_node_make_immutable (self->start); + gsk_render_node_make_immutable (self->end); +} + +static void +gsk_cross_fade_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskCrossFadeNode *self = (GskCrossFadeNode *) node; + + cairo_push_group (cr); + gsk_render_node_draw (self->start, cr); + + cairo_push_group (cr); + gsk_render_node_draw (self->end, cr); + + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint_with_alpha (cr, self->progress); + + cairo_pop_group_to_source (cr); /* resets operator */ + cairo_paint (cr); +} + +static void +gsk_cross_fade_node_get_bounds (GskRenderNode *node, + graphene_rect_t *bounds) +{ + GskCrossFadeNode *self = (GskCrossFadeNode *) node; + graphene_rect_t start_bounds, end_bounds; + + gsk_render_node_get_bounds (self->start, &start_bounds); + gsk_render_node_get_bounds (self->end, &end_bounds); + + graphene_rect_union (&start_bounds, &end_bounds, bounds); +} + +static const GskRenderNodeClass GSK_CROSS_FADE_NODE_CLASS = { + GSK_CROSS_FADE_NODE, + sizeof (GskCrossFadeNode), + "GskCrossFadeNode", + gsk_cross_fade_node_finalize, + gsk_cross_fade_node_make_immutable, + gsk_cross_fade_node_draw, + gsk_cross_fade_node_get_bounds +}; + +/** + * gsk_cross_fade_node_new: + * @start: The start node to be drawn + * @end: The node to be cross_fadeed onto the @start node + * @progress: How far the fade has progressed from start to end. The value will + * be clamped to the range [0 ... 1] + * + * Creates a #GskRenderNode that will do a cross-fade between @start and @end. + * + * Returns: A new #GskRenderNode + * + * Since: 3.90 + */ +GskRenderNode * +gsk_cross_fade_node_new (GskRenderNode *start, + GskRenderNode *end, + double progress) +{ + GskCrossFadeNode *self; + + g_return_val_if_fail (GSK_IS_RENDER_NODE (start), NULL); + g_return_val_if_fail (GSK_IS_RENDER_NODE (end), NULL); + + self = (GskCrossFadeNode *) gsk_render_node_new (&GSK_CROSS_FADE_NODE_CLASS); + + self->start = gsk_render_node_ref (start); + self->end = gsk_render_node_ref (end); + self->progress = CLAMP (progress, 0.0, 1.0); + + return &self->render_node; +} + +GskRenderNode * +gsk_cross_fade_node_get_start_child (GskRenderNode *node) +{ + GskCrossFadeNode *self = (GskCrossFadeNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CROSS_FADE_NODE), NULL); + + return self->start; +} + +GskRenderNode * +gsk_cross_fade_node_get_end_child (GskRenderNode *node) +{ + GskCrossFadeNode *self = (GskCrossFadeNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CROSS_FADE_NODE), NULL); + + return self->end; +} + +double +gsk_cross_fade_node_get_progress (GskRenderNode *node) +{ + GskCrossFadeNode *self = (GskCrossFadeNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CROSS_FADE_NODE), 0.0); + + return self->progress; +} + diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index e4b9ee4209..e945ee7b2c 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -64,6 +64,10 @@ GskRenderNode * gsk_blend_node_get_bottom_child (GskRenderNode *node); GskRenderNode * gsk_blend_node_get_top_child (GskRenderNode *node); GskBlendMode gsk_blend_node_get_blend_node (GskRenderNode *node); +GskRenderNode * gsk_cross_fade_node_get_start_child (GskRenderNode *node); +GskRenderNode * gsk_cross_fade_node_get_end_child (GskRenderNode *node); +double gsk_cross_fade_node_get_progress (GskRenderNode *node); + G_END_DECLS #endif /* __GSK_RENDER_NODE_PRIVATE_H__ */ diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c index 799cbdaa5a..f7ff1586f5 100644 --- a/gtk/gtkstack.c +++ b/gtk/gtkstack.c @@ -1913,37 +1913,41 @@ gtk_stack_snapshot_crossfade (GtkWidget *widget, GtkStack *stack = GTK_STACK (widget); GtkStackPrivate *priv = gtk_stack_get_instance_private (stack); gdouble progress = gtk_progress_tracker_get_progress (&priv->tracker, FALSE); - cairo_t *cr; + GskRenderNode *end_node, *node; + char *name; - cr = gtk_snapshot_append_cairo_node (snapshot, - &GRAPHENE_RECT_INIT( - 0, 0, - gtk_widget_get_allocated_width (widget), - gtk_widget_get_allocated_height (widget) - ), - "GtkStackCrossfade"); - - gtk_container_propagate_draw (GTK_CONTAINER (stack), + gtk_snapshot_push (snapshot, TRUE, "GtkStackCrossFadeEnd"); + gtk_container_snapshot_child (GTK_CONTAINER (stack), priv->visible_child->widget, - cr); - - /* Multiply alpha by progress */ - cairo_set_source_rgba (cr, 1, 1, 1, progress); - cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN); - cairo_paint (cr); - cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + snapshot); + end_node = gtk_snapshot_pop (snapshot); if (priv->last_visible_node) { - cairo_push_group (cr); - cairo_translate (cr, priv->last_visible_surface_allocation.x, priv->last_visible_surface_allocation.y); - gsk_render_node_draw (priv->last_visible_node, cr); - cairo_pop_group_to_source (cr); - cairo_set_operator (cr, CAIRO_OPERATOR_ADD); - cairo_paint_with_alpha (cr, MAX (1.0 - progress, 0)); + graphene_matrix_t identity; + GskRenderNode *start_node; + + graphene_matrix_init_identity (&identity); + + gtk_snapshot_push_transform (snapshot, &identity, "CrossFadeStart"); + gtk_snapshot_append_node (snapshot, priv->last_visible_node); + start_node = gtk_snapshot_pop (snapshot); + node = gsk_cross_fade_node_new (start_node, end_node, progress); + gsk_render_node_unref (start_node); + } + else + { + node = gsk_opacity_node_new (end_node, 1.0 - progress); } - cairo_destroy (cr); + name = g_strdup_printf ("CrossFade<%g>", progress); + gsk_render_node_set_name (node, name); + g_free (name); + + gtk_snapshot_append_node (snapshot, node); + + gsk_render_node_unref (node); + gsk_render_node_unref (end_node); } static void diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c index 6ac5b3238b..fff0a06f41 100644 --- a/gtk/inspector/gtktreemodelrendernode.c +++ b/gtk/inspector/gtktreemodelrendernode.c @@ -555,6 +555,15 @@ append_node (GtkTreeModelRenderNode *nodemodel, } break; + case GSK_CROSS_FADE_NODE: + { + int elt_index = priv->nodes->len - 1; + + append_node (nodemodel, gsk_cross_fade_node_get_start_child (node), elt_index); + append_node (nodemodel, gsk_cross_fade_node_get_end_child (node), elt_index); + } + break; + case GSK_CONTAINER_NODE: { gint elt_index;