[gtk/smarter-diff: 4/5] gsk: Make rendernode diffing smarter




commit 2d5dd7b3d72098a89ff610786a09bb23c3afbf05
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Mar 28 10:18:23 2021 -0400

    gsk: Make rendernode diffing smarter
    
    Allow comparing container nodes to any other
    node, by pretending the other node is a single
    child container (if it isn't one already).
    
    This fixes a glitch where we redraw the full
    entry text when the blinking cursor goes to
    opacity 0, since GskSnapshot then optimizes
    away first the opacity node, and then the
    single-child container.

 gsk/gskrendernode.c        | 21 +++++++++++++++------
 gsk/gskrendernodeimpl.c    | 41 +++++++++++++++++++++++++++++++++++------
 gsk/gskrendernodeprivate.h |  3 +++
 3 files changed, 53 insertions(+), 12 deletions(-)
---
diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c
index 00d893be06..fb2ddd3962 100644
--- a/gsk/gskrendernode.c
+++ b/gsk/gskrendernode.c
@@ -489,10 +489,14 @@ gsk_render_node_can_diff (const GskRenderNode *node1,
   if (node1 == node2)
     return TRUE;
 
-  if (_gsk_render_node_get_node_type (node1) != _gsk_render_node_get_node_type (node2))
-    return FALSE;
+  if (_gsk_render_node_get_node_type (node1) == _gsk_render_node_get_node_type (node2))
+    return GSK_RENDER_NODE_GET_CLASS (node1)->can_diff (node1, node2);
 
-  return GSK_RENDER_NODE_GET_CLASS (node1)->can_diff (node1, node2);
+  if (_gsk_render_node_get_node_type (node1) == GSK_CONTAINER_NODE ||
+      _gsk_render_node_get_node_type (node2) == GSK_CONTAINER_NODE)
+    return TRUE;
+
+  return FALSE;
 }
 
 static void
@@ -544,10 +548,15 @@ gsk_render_node_diff (GskRenderNode  *node1,
   if (node1 == node2)
     return;
 
-  if (_gsk_render_node_get_node_type (node1) != _gsk_render_node_get_node_type (node2))
-    return gsk_render_node_diff_impossible (node1, node2, region);
+  if (_gsk_render_node_get_node_type (node1) == _gsk_render_node_get_node_type (node2))
+    return GSK_RENDER_NODE_GET_CLASS (node1)->diff (node1, node2, region);
+
+  if (_gsk_render_node_get_node_type (node1) == GSK_CONTAINER_NODE)
+    return gsk_container_node_diff_with (node1, node2, region);
+  if (_gsk_render_node_get_node_type (node2) == GSK_CONTAINER_NODE)
+    return gsk_container_node_diff_with (node2, node1, region);
 
-  return GSK_RENDER_NODE_GET_CLASS (node1)->diff (node1, node2, region);
+  return gsk_render_node_diff_impossible (node1, node2, region);
 }
 
 /**
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index beeb147fc2..d611977acc 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -2641,6 +2641,36 @@ gsk_container_node_get_diff_settings (void)
   return settings;
 }
 
+static gboolean
+gsk_render_node_diff_multiple (GskRenderNode **nodes1,
+                               gsize           n_nodes1,
+                               GskRenderNode **nodes2,
+                               gsize           n_nodes2,
+                               cairo_region_t *region)
+{
+  return gsk_diff ((gconstpointer *) nodes1, n_nodes1,
+                   (gconstpointer *) nodes2, n_nodes2,
+                   gsk_container_node_get_diff_settings (),
+                   region) == GSK_DIFF_OK;
+}
+
+void
+gsk_container_node_diff_with (GskRenderNode   *container,
+                              GskRenderNode   *other,
+                              cairo_region_t  *region)
+{
+  GskContainerNode *self = (GskContainerNode *) container;
+
+  if (gsk_render_node_diff_multiple (self->children,
+                                     self->n_children,
+                                     &other,
+                                     1,
+                                     region))
+    return;
+
+  gsk_render_node_diff_impossible (container, other, region);
+}
+
 static void
 gsk_container_node_diff (GskRenderNode  *node1,
                          GskRenderNode  *node2,
@@ -2649,12 +2679,11 @@ gsk_container_node_diff (GskRenderNode  *node1,
   GskContainerNode *self1 = (GskContainerNode *) node1;
   GskContainerNode *self2 = (GskContainerNode *) node2;
 
-  if (gsk_diff ((gconstpointer *) self1->children,
-                self1->n_children,
-                (gconstpointer *) self2->children,
-                self2->n_children,
-                gsk_container_node_get_diff_settings (),
-                region) == GSK_DIFF_OK)
+  if (gsk_render_node_diff_multiple (self1->children,
+                                     self1->n_children,
+                                     self2->children,
+                                     self2->n_children,
+                                     region))
     return;
 
   gsk_render_node_diff_impossible (node1, node2, region);
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 07ec707c03..a767daa365 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -93,6 +93,9 @@ void            gsk_render_node_diff                    (GskRenderNode
 void            gsk_render_node_diff_impossible         (GskRenderNode               *node1,
                                                          GskRenderNode               *node2,
                                                          cairo_region_t              *region);
+void            gsk_container_node_diff_with            (GskRenderNode               *container,
+                                                         GskRenderNode               *other,
+                                                         cairo_region_t              *region);
 
 bool            gsk_border_node_get_uniform             (const GskRenderNode         *self);
 bool            gsk_border_node_get_uniform_color       (const GskRenderNode         *self);


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