[gtk+/wip/otte/rendernode: 87/110] gsk: Add cross-fade node



commit 3859b7d5dcf50447ccfecb1bfaabb24717d034c3
Author: Benjamin Otte <otte redhat com>
Date:   Sat Dec 17 07:44:10 2016 +0100

    gsk: Add cross-fade node
    
    And implement stack crossfades with it.

 docs/reference/gsk/gsk4-sections.txt   |    1 +
 gsk/gskenums.h                         |    4 +-
 gsk/gskrendernode.h                    |    5 +
 gsk/gskrendernodeimpl.c                |  136 ++++++++++++++++++++++++++++++++
 gsk/gskrendernodeprivate.h             |    4 +
 gtk/gtkstack.c                         |   52 +++++++------
 gtk/inspector/gtktreemodelrendernode.c |    9 ++
 7 files changed, 186 insertions(+), 25 deletions(-)
---
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt
index 59e1a39..f5cc151 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
 <SUBSECTION Standard>
 GSK_IS_RENDER_NODE
 GSK_RENDER_NODE
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 4e0e0bf..1d46c92 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 7562fb9..14fa797 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -118,6 +118,11 @@ GskRenderNode *         gsk_blend_node_new                      (GskRenderNode
                                                                  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,
                                                                  GskScalingFilter mag_filter);
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 5ab0d22..ee3cb46 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 e4b9ee4..e945ee7 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 d0656e3..8ef6db9 100644
--- a/gtk/gtkstack.c
+++ b/gtk/gtkstack.c
@@ -1925,37 +1925,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 6ac5b32..fff0a06 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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]