[gtk+/wip/otte/rendernode] stack: Implement snapshot()



commit 44cc75762c39d62f18e86095c899d880087cc1cd
Author: Benjamin Otte <otte redhat com>
Date:   Tue Dec 13 09:45:09 2016 +0100

    stack: Implement snapshot()
    
    This uses the new push()/pop() mechanism to its fullest extent when
    implementing transitions. It's fun to inspect the results in the
    inspector.
    
    Crossfades don't work yet, they continue using a Cairo fallback.
    
    A side effect of the stack conversion is that widget-factory now uses
    snapshots for a lot more things.

 gtk/gtkstack.c |  157 +++++++++++++++++++++++++++-----------------------------
 1 files changed, 76 insertions(+), 81 deletions(-)
---
diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c
index b657b64..d0656e3 100644
--- a/gtk/gtkstack.c
+++ b/gtk/gtkstack.c
@@ -145,7 +145,7 @@ typedef struct {
   guint transition_duration;
 
   GtkStackChildInfo *last_visible_child;
-  cairo_surface_t *last_visible_surface;
+  GskRenderNode *last_visible_node;
   GtkAllocation last_visible_surface_allocation;
   guint tick_id;
   GtkProgressTracker tracker;
@@ -176,8 +176,8 @@ static void     gtk_stack_compute_expand                 (GtkWidget     *widget,
                                                           gboolean      *vexpand);
 static void     gtk_stack_size_allocate                  (GtkWidget     *widget,
                                                           GtkAllocation *allocation);
-static gboolean gtk_stack_draw                           (GtkWidget     *widget,
-                                                          cairo_t       *cr);
+static void     gtk_stack_snapshot                       (GtkWidget     *widget,
+                                                          GtkSnapshot   *snapshot);
 static void     gtk_stack_measure_                       (GtkWidget      *widget,
                                                           GtkOrientation  orientation,
                                                           int             for_size,
@@ -231,8 +231,7 @@ gtk_stack_finalize (GObject *obj)
 
   gtk_stack_unschedule_ticks (stack);
 
-  if (priv->last_visible_surface != NULL)
-    cairo_surface_destroy (priv->last_visible_surface);
+  g_clear_pointer (&priv->last_visible_node, gsk_render_node_unref);
 
   g_clear_object (&priv->gadget);
 
@@ -420,7 +419,7 @@ gtk_stack_class_init (GtkStackClass *klass)
   object_class->finalize = gtk_stack_finalize;
 
   widget_class->size_allocate = gtk_stack_size_allocate;
-  widget_class->draw = gtk_stack_draw;
+  widget_class->snapshot = gtk_stack_snapshot;
   widget_class->realize = gtk_stack_realize;
   widget_class->unrealize = gtk_stack_unrealize;
   widget_class->map = gtk_stack_map;
@@ -886,11 +885,7 @@ gtk_stack_progress_updated (GtkStack *stack)
 
   if (gtk_progress_tracker_get_state (&priv->tracker) == GTK_PROGRESS_STATE_AFTER)
     {
-      if (priv->last_visible_surface != NULL)
-        {
-          cairo_surface_destroy (priv->last_visible_surface);
-          priv->last_visible_surface = NULL;
-        }
+      g_clear_pointer (&priv->last_visible_node, gsk_render_node_unref);
 
       if (priv->last_visible_child != NULL)
         {
@@ -1077,9 +1072,7 @@ set_visible_child (GtkStack               *stack,
     gtk_widget_set_child_visible (priv->last_visible_child->widget, FALSE);
   priv->last_visible_child = NULL;
 
-  if (priv->last_visible_surface != NULL)
-    cairo_surface_destroy (priv->last_visible_surface);
-  priv->last_visible_surface = NULL;
+  g_clear_pointer (&priv->last_visible_node, gsk_render_node_unref);
 
   if (priv->visible_child && priv->visible_child->widget)
     {
@@ -1889,6 +1882,7 @@ gtk_stack_forall (GtkContainer *container,
     }
 }
 
+#include <gsk/gskrendernodeprivate.h>
 static void
 gtk_stack_compute_expand (GtkWidget *widget,
                           gboolean  *hexpand_p,
@@ -1925,43 +1919,48 @@ gtk_stack_compute_expand (GtkWidget *widget,
 }
 
 static void
-gtk_stack_draw_crossfade (GtkWidget *widget,
-                          cairo_t   *cr)
+gtk_stack_snapshot_crossfade (GtkWidget   *widget,
+                              GtkSnapshot *snapshot)
 {
   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;
+
+  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");
 
-  cairo_push_group (cr);
   gtk_container_propagate_draw (GTK_CONTAINER (stack),
                                 priv->visible_child->widget,
                                 cr);
-  cairo_save (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);
 
-  if (priv->last_visible_surface)
+  if (priv->last_visible_node)
     {
-      cairo_set_source_surface (cr, priv->last_visible_surface,
-                                priv->last_visible_surface_allocation.x,
-                                priv->last_visible_surface_allocation.y);
+      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));
     }
 
-  cairo_restore (cr);
-
-  cairo_pop_group_to_source (cr);
-  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-  cairo_paint (cr);
+  cairo_destroy (cr);
 }
 
 static void
-gtk_stack_draw_under (GtkWidget *widget,
-                      cairo_t   *cr)
+gtk_stack_snapshot_under (GtkWidget   *widget,
+                          GtkSnapshot *snapshot)
 {
   GtkStack *stack = GTK_STACK (widget);
   GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
@@ -2000,33 +1999,39 @@ gtk_stack_draw_under (GtkWidget *widget,
       g_assert_not_reached ();
     }
 
-  cairo_save (cr);
-  cairo_rectangle (cr, x, y, width, height);
-  cairo_clip (cr);
+  gtk_snapshot_push_clip (snapshot,
+                          &GRAPHENE_RECT_INIT(x, y, width, height),
+                          "StackUnder");
 
-  gtk_container_propagate_draw (GTK_CONTAINER (stack),
+  gtk_container_snapshot_child (GTK_CONTAINER (stack),
                                 priv->visible_child->widget,
-                                cr);
+                                snapshot);
 
-  cairo_restore (cr);
+  gtk_snapshot_pop_and_append (snapshot);
 
-  if (priv->last_visible_surface)
+  if (priv->last_visible_node)
     {
-      cairo_set_source_surface (cr, priv->last_visible_surface, pos_x, pos_y);
-      cairo_paint (cr);
+      graphene_matrix_t matrix;
+
+      graphene_matrix_init_translate (&matrix, &GRAPHENE_POINT3D_INIT (pos_x, pos_y, 0));
+
+      gtk_snapshot_push_transform (snapshot, &matrix, "StackUnder");
+      gtk_snapshot_append_node (snapshot, priv->last_visible_node);
+      gtk_snapshot_pop_and_append (snapshot);
     }
 }
 
 static void
-gtk_stack_draw_slide (GtkWidget *widget,
-                      cairo_t   *cr)
+gtk_stack_snapshot_slide (GtkWidget   *widget,
+                          GtkSnapshot *snapshot)
 {
   GtkStack *stack = GTK_STACK (widget);
   GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 
-  if (priv->last_visible_surface)
+  if (priv->last_visible_node)
     {
       GtkAllocation allocation;
+      graphene_matrix_t matrix;
       int x, y;
 
       gtk_widget_get_allocation (widget, &allocation);
@@ -2064,39 +2069,36 @@ gtk_stack_draw_slide (GtkWidget *widget,
       x += priv->last_visible_surface_allocation.x;
       y += priv->last_visible_surface_allocation.y;
 
-
       if (gtk_widget_get_valign (priv->last_visible_child->widget) == GTK_ALIGN_END &&
           priv->last_visible_widget_height > allocation.height)
         y -= priv->last_visible_widget_height - allocation.height;
       else if (gtk_widget_get_valign (priv->last_visible_child->widget) == GTK_ALIGN_CENTER)
         y -= (priv->last_visible_widget_height - allocation.height) / 2;
 
-      cairo_save (cr);
-      cairo_set_source_surface (cr, priv->last_visible_surface, x, y);
-      cairo_paint (cr);
-      cairo_restore (cr);
+      graphene_matrix_init_translate (&matrix, &GRAPHENE_POINT3D_INIT (x, y, 0));
+      gtk_snapshot_push_transform (snapshot, &matrix, "StackSlide");
+      gtk_snapshot_append_node (snapshot, priv->last_visible_node);
+      gtk_snapshot_pop_and_append (snapshot);
      }
 
-  gtk_container_propagate_draw (GTK_CONTAINER (stack),
+  gtk_container_snapshot_child (GTK_CONTAINER (stack),
                                 priv->visible_child->widget,
-                                cr);
+                                snapshot);
 }
 
-static gboolean
-gtk_stack_draw (GtkWidget *widget,
-                cairo_t   *cr)
+static void
+gtk_stack_snapshot (GtkWidget   *widget,
+                    GtkSnapshot *snapshot)
 {
   GtkStack *stack = GTK_STACK (widget);
   GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 
-  gtk_css_gadget_draw (priv->gadget, cr);
-
-  return FALSE;
+  gtk_css_gadget_snapshot (priv->gadget, snapshot);
 }
 
 static gboolean
 gtk_stack_render (GtkCssGadget *gadget,
-                  cairo_t      *cr,
+                  GtkSnapshot  *snapshot,
                   int           x,
                   int           y,
                   int           width,
@@ -2106,40 +2108,33 @@ gtk_stack_render (GtkCssGadget *gadget,
   GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
   GtkStack *stack = GTK_STACK (widget);
   GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
-  cairo_t *pattern_cr;
 
   if (priv->visible_child)
     {
       if (gtk_progress_tracker_get_state (&priv->tracker) != GTK_PROGRESS_STATE_AFTER)
         {
-          if (priv->last_visible_surface == NULL &&
+          if (priv->last_visible_node == NULL &&
               priv->last_visible_child != NULL)
             {
               gtk_widget_get_allocation (priv->last_visible_child->widget,
                                          &priv->last_visible_surface_allocation);
-              priv->last_visible_surface =
-                gdk_window_create_similar_surface (gtk_widget_get_window (widget),
-                                                   CAIRO_CONTENT_COLOR_ALPHA,
-                                                   priv->last_visible_surface_allocation.width,
-                                                   priv->last_visible_surface_allocation.height);
-              pattern_cr = cairo_create (priv->last_visible_surface);
-              /* We don't use propagate_draw here, because we don't want to apply
-               * the bin_window offset
-               */
-              gtk_widget_draw (priv->last_visible_child->widget, pattern_cr);
-              cairo_destroy (pattern_cr);
+              gtk_snapshot_push (snapshot, FALSE, "StackCaptureLastVisibleChild");
+              gtk_widget_snapshot (priv->last_visible_child->widget, snapshot);
+              priv->last_visible_node = gtk_snapshot_pop (snapshot);
             }
 
-          cairo_rectangle (cr,
-                           0, 0,
-                           gtk_widget_get_allocated_width (widget),
-                           gtk_widget_get_allocated_height (widget));
-          cairo_clip (cr);
+          gtk_snapshot_push_clip (snapshot,
+                                  &GRAPHENE_RECT_INIT(
+                                      0, 0,
+                                      gtk_widget_get_allocated_width (widget),
+                                      gtk_widget_get_allocated_height (widget)
+                                  ),
+                                  "StackAnimationClip");
 
           switch (priv->active_transition_type)
             {
             case GTK_STACK_TRANSITION_TYPE_CROSSFADE:
-             gtk_stack_draw_crossfade (widget, cr);
+             gtk_stack_snapshot_crossfade (widget, snapshot);
               break;
             case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT:
             case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT:
@@ -2149,23 +2144,24 @@ gtk_stack_render (GtkCssGadget *gadget,
             case GTK_STACK_TRANSITION_TYPE_OVER_DOWN:
             case GTK_STACK_TRANSITION_TYPE_OVER_LEFT:
             case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT:
-              gtk_stack_draw_slide (widget, cr);
+              gtk_stack_snapshot_slide (widget, snapshot);
               break;
             case GTK_STACK_TRANSITION_TYPE_UNDER_UP:
             case GTK_STACK_TRANSITION_TYPE_UNDER_DOWN:
             case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT:
             case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT:
-             gtk_stack_draw_under (widget, cr);
+             gtk_stack_snapshot_under (widget, snapshot);
               break;
             default:
               g_assert_not_reached ();
             }
 
+          gtk_snapshot_pop_and_append (snapshot);
         }
       else
-        gtk_container_propagate_draw (GTK_CONTAINER (stack),
+        gtk_container_snapshot_child (GTK_CONTAINER (stack),
                                       priv->visible_child->widget,
-                                      cr);
+                                      snapshot);
     }
 
   return FALSE;
@@ -2238,8 +2234,7 @@ gtk_stack_allocate (GtkCssGadget        *gadget,
       if (!gdk_rectangle_equal (&priv->last_visible_surface_allocation,
                                 &child_allocation))
         {
-          cairo_surface_destroy (priv->last_visible_surface);
-          priv->last_visible_surface = NULL;
+          g_clear_pointer (&priv->last_visible_node, gsk_render_node_unref);
         }
     }
 
@@ -2376,8 +2371,8 @@ gtk_stack_init (GtkStack *stack)
                                                      GTK_WIDGET (stack),
                                                      gtk_stack_measure,
                                                      gtk_stack_allocate,
-                                                     gtk_stack_render,
                                                      NULL,
+                                                     gtk_stack_render,
                                                      NULL,
                                                      NULL);
 


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