[gtk/matthiasc/css-change-tracking-5: 1/3] Make change computation more precise



commit 79afff410ae60636d2eb5c486356deec331ab6d8
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jan 17 14:38:31 2020 -0500

    Make change computation more precise
    
    Don't ignore parent name, id, class when matching for change.
    This reduces the amount of parent-state in our change flags.
    The price we pay for this is that we need to treat parent-name,
    parent-id and parent-class as radical change now. But since
    they are less frequent than parent-state changes, it is still
    a win.
    
    When we meet a sibling or adjacent selector while collecting change
    flags, we want to 'always match', since just the right sibling might
    appear in the node tree. Calling gtk_css_selector_foreach does not
    achieve that, since it won't match if there is no sibling in the
    current tree. To fix this, pretend that there is one, and continue
    matching.

 gtk/gtkcssnode.c     |   9 ++++-
 gtk/gtkcssselector.c | 105 ++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 79 insertions(+), 35 deletions(-)
---
diff --git a/gtk/gtkcssnode.c b/gtk/gtkcssnode.c
index 4fe350d5ff..2893eee051 100644
--- a/gtk/gtkcssnode.c
+++ b/gtk/gtkcssnode.c
@@ -86,7 +86,14 @@
 
 /* When these change we do a full restyling. Otherwise we try to figure out
  * if we need to change things. */
-#define GTK_CSS_RADICAL_CHANGE (GTK_CSS_CHANGE_ID | GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_CLASS | 
GTK_CSS_CHANGE_SOURCE | GTK_CSS_CHANGE_PARENT_STYLE)
+#define GTK_CSS_RADICAL_CHANGE (GTK_CSS_CHANGE_ID | \
+                                GTK_CSS_CHANGE_NAME | \
+                                GTK_CSS_CHANGE_CLASS | \
+                                GTK_CSS_CHANGE_PARENT_ID | \
+                                GTK_CSS_CHANGE_PARENT_NAME | \
+                                GTK_CSS_CHANGE_PARENT_CLASS | \
+                                GTK_CSS_CHANGE_SOURCE | \
+                                GTK_CSS_CHANGE_PARENT_STYLE)
 
 /* When these change, we need to recompute the change flags for the new style
  * since they may have changed.
diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c
index dc35d839db..296a302d23 100644
--- a/gtk/gtkcssselector.c
+++ b/gtk/gtkcssselector.c
@@ -316,7 +316,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT = {
   gtk_css_selector_default_hash_one,
   gtk_css_selector_default_compare_one,
   FALSE,
-  TRUE
+  FALSE
 };
 
 /* CHILD */
@@ -358,7 +358,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CHILD = {
   gtk_css_selector_default_hash_one,
   gtk_css_selector_default_compare_one,
   FALSE,
-  TRUE
+  FALSE
 };
 
 /* SIBLING */
@@ -405,7 +405,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_SIBLING = {
   gtk_css_selector_default_hash_one,
   gtk_css_selector_default_compare_one,
   FALSE,
-  TRUE
+  FALSE,
 };
 
 /* ADJACENT */
@@ -447,7 +447,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ADJACENT = {
   gtk_css_selector_default_hash_one,
   gtk_css_selector_default_compare_one,
   FALSE,
-  TRUE
+  FALSE,
 };
 
 /* SIMPLE SELECTOR DEFINE */
@@ -1901,67 +1901,104 @@ gtk_css_selector_match_for_change (const GtkCssSelector *selector,
    that change != 0 on any match. */
 #define GTK_CSS_CHANGE_GOT_MATCH GTK_CSS_CHANGE_RESERVED_BIT
 
+static void
+print_sel (const char *format, const GtkCssSelector *selector)
+{
+  GString *s = g_string_new ("");
+  selector->class->print (selector, s);
+  g_print (format, s->str);
+  g_string_free (s, TRUE);
+}
+
+static gboolean gtk_css_selector_tree_change_foreach (const GtkCssSelector *selector,
+                                                      const GtkCssMatcher  *matcher,
+                                                      gpointer              res);
+
+/* Handle the case that a new sibling with just the right properties might appear.
+ * This is done by collecting the sibling selector and all following simple selectors,
+ * before resuming matching.
+ */
 static GtkCssChange
-gtk_css_selector_tree_collect_change (const GtkCssSelectorTree *tree)
+gtk_css_selector_tree_change_for_sibling (const GtkCssSelector *selector,
+                                          const GtkCssMatcher  *matcher,
+                                          gboolean              skip_first)
 {
+  const GtkCssSelectorTree *tree = (const GtkCssSelectorTree *) selector;
   GtkCssChange change = 0;
-  const GtkCssSelectorTree *prev;
 
-  for (prev = gtk_css_selector_tree_get_previous (tree);
-       prev != NULL;
-       prev = gtk_css_selector_tree_get_sibling (prev))
-    change |= gtk_css_selector_tree_collect_change (prev);
-
-  change = tree->selector.class->get_change (&tree->selector, change);
+  if (skip_first || tree->selector.class->is_simple)
+    {
+      const GtkCssSelectorTree *prev;
+      for (prev = gtk_css_selector_tree_get_previous (tree);
+           prev;
+           prev = gtk_css_selector_tree_get_sibling (prev))
+        change |= gtk_css_selector_tree_change_for_sibling (prev, matcher, FALSE);
+      change = selector->class->get_change (selector, change);
+    }
+  else
+    {
+      gtk_css_selector_tree_change_foreach (selector, matcher, &change);
+    }
 
   return change;
 }
 
-static GtkCssChange
-gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
-                                 const GtkCssMatcher      *matcher)
+static gboolean
+gtk_css_selector_tree_change_foreach (const GtkCssSelector *selector,
+                                     const GtkCssMatcher  *matcher,
+                                      gpointer              res)
 {
-  GtkCssChange change = 0;
+  const GtkCssSelectorTree *tree = (const GtkCssSelectorTree *) selector;
   const GtkCssSelectorTree *prev;
+  GtkCssChange *ret = res;
+  GtkCssChange change = 0;
 
   if (!gtk_css_selector_match_for_change (&tree->selector, matcher))
-    return 0;
+    return FALSE;
 
-  if (!tree->selector.class->is_simple)
-    return gtk_css_selector_tree_collect_change (tree) | GTK_CSS_CHANGE_GOT_MATCH;
+//  print_sel ("match at %s\n", selector);
 
   for (prev = gtk_css_selector_tree_get_previous (tree);
        prev != NULL;
        prev = gtk_css_selector_tree_get_sibling (prev))
-    change |= gtk_css_selector_tree_get_change (prev, matcher);
+    {
+      GtkCssChange change2 = 0;
 
-  if (change || gtk_css_selector_tree_get_matches (tree))
-    change = tree->selector.class->get_change (&tree->selector, change & ~GTK_CSS_CHANGE_GOT_MATCH) | 
GTK_CSS_CHANGE_GOT_MATCH;
+      if (prev->selector.class == &GTK_CSS_SELECTOR_SIBLING ||
+          prev->selector.class == &GTK_CSS_SELECTOR_ADJACENT)
+        change2 = gtk_css_selector_tree_change_for_sibling (&prev->selector, matcher, TRUE);
+      else
+        gtk_css_selector_foreach (&prev->selector, matcher, gtk_css_selector_tree_change_foreach, &change2);
 
-  return change;
-}
+      change |= change2;
+    }
 
-gboolean
-_gtk_css_selector_tree_is_empty (const GtkCssSelectorTree *tree)
-{
-  return tree == NULL;
+  if (change || gtk_css_selector_tree_get_matches (tree))
+    {
+      *ret |= tree->selector.class->get_change (&tree->selector, change & ~GTK_CSS_CHANGE_GOT_MATCH) | 
GTK_CSS_CHANGE_GOT_MATCH;
+    }
+
+  return FALSE;
 }
 
 GtkCssChange
 _gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
                                       const GtkCssMatcher *matcher)
 {
-  GtkCssChange change;
-
-  change = 0;
+  GtkCssChange change = 0;
 
-  /* no need to foreach here because we abort for non-simple selectors */
   for (; tree != NULL;
        tree = gtk_css_selector_tree_get_sibling (tree))
-    change |= gtk_css_selector_tree_get_change (tree, matcher);
+    gtk_css_selector_foreach (&tree->selector, matcher, gtk_css_selector_tree_change_foreach, &change);
 
   /* Never return reserved bit set */
-  return change & ~GTK_CSS_CHANGE_RESERVED_BIT;
+  return change & ~GTK_CSS_CHANGE_GOT_MATCH;
+}
+
+gboolean
+_gtk_css_selector_tree_is_empty (const GtkCssSelectorTree *tree)
+{
+  return tree == NULL;
 }
 
 #ifdef PRINT_TREE


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