cssnode: Refactor node tree modification code
authorBenjamin Otte <otte@redhat.com>
Mon, 9 Feb 2015 21:03:13 +0000 (22:03 +0100)
committerBenjamin Otte <otte@redhat.com>
Wed, 18 Mar 2015 14:23:31 +0000 (15:23 +0100)
This allows adding more API for it.

It also includes code that tracks modifications and invalidates siblings
and their positions whenever nodes get added or removed.

gtk/gtkcssnode.c
gtk/gtkcssnodeprivate.h

index 816c667d3d812b7fb25070b779122f5e82f8c9b8..92b165dfa3142afd677a78f3b8fcdb8b65d962e9 100644 (file)
@@ -359,73 +359,118 @@ gtk_css_node_parent_will_be_set (GtkCssNode *node)
     GTK_CSS_NODE_GET_CLASS (node)->dequeue_validate (node);
 }
 
-void
-gtk_css_node_set_parent (GtkCssNode *node,
-                         GtkCssNode *parent)
+static void
+gtk_css_node_unlink_from_siblings (GtkCssNode *node)
 {
-  if (node->parent == parent)
+  if (GTK_IS_CSS_TRANSIENT_NODE (node))
     return;
 
-  /* Take a reference here so the whole function has a reference */
-  g_object_ref (node);
+  if (node->previous_sibling)
+    node->previous_sibling->next_sibling = node->next_sibling;
+  else
+    node->parent->first_child = node->next_sibling;
 
-  if (node->parent != NULL)
+  if (node->next_sibling)
+    node->next_sibling->previous_sibling = node->previous_sibling;
+  else
+    node->parent->last_child = node->previous_sibling;
+
+  node->previous_sibling = NULL;
+  node->next_sibling = NULL;
+}
+
+static void
+gtk_css_node_link_to_siblings (GtkCssNode *node,
+                               GtkCssNode *new_previous)
+{
+  if (GTK_IS_CSS_TRANSIENT_NODE (node))
+    return;
+
+  if (new_previous)
     {
-      if (!GTK_IS_CSS_TRANSIENT_NODE (node))
-        {
-          if (node->previous_sibling)
-            node->previous_sibling->next_sibling = node->next_sibling;
-          else
-            node->parent->first_child = node->next_sibling;
+      node->previous_sibling = new_previous;
+      node->next_sibling = new_previous->next_sibling;
+      new_previous->next_sibling = node;
+    }
+  else
+    {
+      node->next_sibling = node->parent->first_child;
+      node->parent->first_child = node;
+    }
+
+  if (node->next_sibling)
+    node->next_sibling->previous_sibling = node;
+  else
+    node->parent->last_child = node;
+}
 
-          if (node->next_sibling)
-            node->next_sibling->previous_sibling = node->previous_sibling;
-          else
-            node->parent->last_child = node->previous_sibling;
+static void
+gtk_css_node_set_children_changed (GtkCssNode *node)
+{
+  if (node->children_changed)
+    return;
 
-          node->parent->n_children--;
-        }
+  node->children_changed = TRUE;
+  gtk_css_node_set_invalid (node, TRUE);
+}
 
-      node->parent = NULL;
-      node->next_sibling = NULL;
-      node->previous_sibling = NULL;
+static void
+gtk_css_node_reposition (GtkCssNode *node,
+                         GtkCssNode *parent,
+                         GtkCssNode *previous)
+{
+  g_assert (! (parent == NULL && previous != NULL));
 
-      g_object_unref (node);
+  /* Take a reference here so the whole function has a reference */
+  g_object_ref (node);
 
-      if (parent == NULL)
-        gtk_css_node_parent_was_unset (node);
-    }
+  if (node->parent != NULL)
+    gtk_css_node_unlink_from_siblings (node);
 
-  if (parent)
+  if (node->parent != parent)
     {
       if (node->parent == NULL)
-        gtk_css_node_parent_will_be_set (node);
+        {
+          gtk_css_node_parent_will_be_set (node);
+        }
+      else
+        {
+          g_object_unref (node);
+          gtk_css_node_set_children_changed (node->parent);
+        }
 
       node->parent = parent;
 
-      if (!GTK_IS_CSS_TRANSIENT_NODE (node))
+      if (parent)
         {
-          parent->n_children++;
+          gtk_css_node_set_children_changed (parent);
+          g_object_ref (node);
 
-          if (parent->last_child)
-            {
-              parent->last_child->next_sibling = node;
-              node->previous_sibling = parent->last_child;
-            }
-          parent->last_child = node;
-
-          if (parent->first_child == NULL)
-            parent->first_child = node;
+          if (node->invalid)
+            gtk_css_node_set_invalid (parent, TRUE);
+        }
+      else
+        {
+          gtk_css_node_parent_was_unset (node);
         }
-
-      if (node->invalid)
-        gtk_css_node_set_invalid (parent, TRUE);
     }
 
+  if (parent)
+    gtk_css_node_link_to_siblings (node, previous);
+
   gtk_css_node_invalidate (node, GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING);
 
-  if (node->parent == NULL)
-    g_object_unref (node);
+  g_object_unref (node);
+}
+
+void
+gtk_css_node_set_parent (GtkCssNode *node,
+                         GtkCssNode *parent)
+{
+  if (node->parent == parent)
+    return;
+
+  gtk_css_node_reposition (node, parent, parent ? parent->last_child : NULL);
 }
 
 GtkCssNode *
@@ -638,6 +683,11 @@ gtk_css_node_propagate_pending_changes (GtkCssNode *cssnode)
     return;
 
   change = _gtk_css_change_for_child (cssnode->pending_changes);
+  if (cssnode->children_changed)
+    {
+      change |= GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_ANY_SIBLING;
+      cssnode->children_changed = FALSE;
+    }
 
   for (child = gtk_css_node_get_first_child (cssnode);
        child;
@@ -671,11 +721,11 @@ gtk_css_node_validate (GtkCssNode            *cssnode,
   if (G_UNLIKELY (gtk_get_debug_flags () & GTK_DEBUG_NO_CSS_CACHE))
     change = GTK_CSS_CHANGE_ANY;
 
+  gtk_css_node_propagate_pending_changes (cssnode);
+
   if (!cssnode->invalid && change == 0 && _gtk_bitmask_is_empty (parent_changes))
     return;
 
-  gtk_css_node_propagate_pending_changes (cssnode);
-
   gtk_css_node_set_invalid (cssnode, FALSE);
 
   change = cssnode->pending_changes;
index 4207d2ff569e9b98655b45cd5baa8949c8dbb852..b1339b0b9c239f9e98af83f3a3319b5b95b0b09c 100644 (file)
@@ -43,7 +43,6 @@ struct _GtkCssNode
   GtkCssNode *next_sibling;
   GtkCssNode *first_child;
   GtkCssNode *last_child;
-  guint n_children;
 
   GtkCssNodeDeclaration *decl;
   GtkCssStyle           *style;
@@ -51,6 +50,7 @@ struct _GtkCssNode
   GtkCssChange           pending_changes;       /* changes that accumulated since the style was last computed */
 
   guint                  invalid :1;            /* node or a child needs to be validated (even if just for animation) */
+  guint                  children_changed :1;   /* the children changed since last validation */
 };
 
 struct _GtkCssNodeClass