css: Use the bloom filter for change matching
authorBenjamin Otte <otte@redhat.com>
Mon, 27 Jan 2020 02:26:39 +0000 (03:26 +0100)
committerBenjamin Otte <otte@redhat.com>
Tue, 28 Jan 2020 01:17:03 +0000 (02:17 +0100)
Instead of just doing radical change matching on the node itself, also
consider the parent nodes via the bloom filter.

This means a radical change is now also one where the parent
name/id/classes change, but since that's considered a radical change on
the parent already, those things are slow anyway.

Improves the benchmark times for CSS validation during backdrop
transitions in widget-factory from 45ms to 35ms on my machine.

gtk/gtkcssnode.c
gtk/gtkcssprovider.c
gtk/gtkcssselector.c
gtk/gtkcssselectorprivate.h
testsuite/css/change/test5.nodes

index b88e9f4fa317c02d80e3b7443e5901ac6ca2b0ea..ab52c2bcd30f06c019c1b20dd938c210da3be16e 100644 (file)
@@ -87,7 +87,9 @@
 
 /* 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.
index 9047b55b80e07ec080b3fa34fc52f165433f015d..f1eafed6955048f108f0a1c2315c3c608ecd184e 100644 (file)
@@ -498,7 +498,7 @@ gtk_css_style_provider_lookup (GtkStyleProvider             *provider,
     }
 
   if (change)
-    *change = _gtk_css_selector_tree_get_change_all (priv->tree, node);
+    *change = gtk_css_selector_tree_get_change_all (priv->tree, filter, node);
 }
 
 static void
index 8f4bbf0113ef5b729d4cdda908a4eefa6337661f..dfb002e32bb9752cc206a4d6671cb8249b17985e 100644 (file)
@@ -1957,21 +1957,6 @@ _gtk_css_selector_tree_match_all (const GtkCssSelectorTree     *tree,
   return tm.results;
 }
 
-/* The code for collecting matches assumes that the name, id and classes
- * of a node remain unchanged, and anything else can change. This needs to
- * be kept in sync with the definition of 'radical change' in gtkcssnode.c.
- */
-
-static gboolean
-gtk_css_selector_match_for_change (const GtkCssSelector *selector,
-                                   GtkCssNode           *node)
-{
-  if (selector->class->category != GTK_CSS_SELECTOR_CATEGORY_SIMPLE_RADICAL)
-    return TRUE;
-
-  return selector->class->match_one (selector, node);
-}
-
 /* When checking for changes via the tree we need to know if a rule further
    down the tree matched, because if so we need to add "our bit" to the
    Change. For instance in a match like *.class:active we'll
@@ -1983,39 +1968,56 @@ 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 GtkCssChange
-gtk_css_selector_tree_collect_change (const GtkCssSelectorTree *tree)
-{
-  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);
-
-  return change;
-}
+/* The code for collecting matches assumes that the name, id and classes
+ * of a node remain unchanged, and anything else can change. This needs to
+ * be kept in sync with the definition of 'radical change' in gtkcssnode.c.
+ */
 
 static GtkCssChange
-gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
-                                 GtkCssNode               *node)
+gtk_css_selector_tree_get_change (const GtkCssSelectorTree     *tree,
+                                  const GtkCountingBloomFilter *filter,
+                                 GtkCssNode                   *node,
+                                  gboolean                      skipping)
 {
   GtkCssChange change = 0;
   const GtkCssSelectorTree *prev;
 
-  if (!gtk_css_selector_match_for_change (&tree->selector, node))
-    return 0;
-
-  if (!gtk_css_selector_is_simple (&tree->selector))
-    return gtk_css_selector_tree_collect_change (tree) | GTK_CSS_CHANGE_GOT_MATCH;
+  switch (tree->selector.class->category)
+    {
+      case GTK_CSS_SELECTOR_CATEGORY_SIMPLE:
+        break;
+      case GTK_CSS_SELECTOR_CATEGORY_SIMPLE_RADICAL:
+        if (skipping)
+          break;
+        if (node)
+          {
+            if (!tree->selector.class->match_one (&tree->selector, node))
+              return 0;
+          }
+        else if (filter)
+          {
+            if (!gtk_counting_bloom_filter_may_contain (filter,
+                                                        gtk_css_selector_hash_one (&tree->selector)))
+              return 0;
+          }
+        break;
+      case GTK_CSS_SELECTOR_CATEGORY_PARENT:
+        skipping = FALSE;
+        node = NULL;
+        break;
+      case GTK_CSS_SELECTOR_CATEGORY_SIBLING:
+        skipping = TRUE;
+        node = NULL;
+        break;
+      default:
+        g_assert_not_reached ();
+        return 0;
+    }
 
   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, node);
+    change |= gtk_css_selector_tree_get_change (prev, filter, node, skipping);
 
   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;
@@ -2030,17 +2032,15 @@ _gtk_css_selector_tree_is_empty (const GtkCssSelectorTree *tree)
 }
 
 GtkCssChange
-_gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
-                                      GtkCssNode               *node)
+gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree     *tree,
+                                      const GtkCountingBloomFilter *filter,
+                                     GtkCssNode                   *node)
 {
-  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, node);
+    change |= gtk_css_selector_tree_get_change (tree, filter, node, FALSE);
 
   /* Never return reserved bit set */
   return change & ~GTK_CSS_CHANGE_RESERVED_BIT;
index a1e265d5d2cdd74fd84284139b0128d7dfdf8e6a..4d8e39f376ab32a0d59ea1ae81f948ebdbd18b2e 100644 (file)
@@ -45,7 +45,8 @@ void         _gtk_css_selector_tree_free             (GtkCssSelectorTree       *
 GPtrArray *  _gtk_css_selector_tree_match_all        (const GtkCssSelectorTree *tree,
                                                       const GtkCountingBloomFilter *filter,
                                                      GtkCssNode               *node);
-GtkCssChange _gtk_css_selector_tree_get_change_all   (const GtkCssSelectorTree *tree,
+GtkCssChange gtk_css_selector_tree_get_change_all    (const GtkCssSelectorTree *tree,
+                                                      const GtkCountingBloomFilter *filter,
                                                      GtkCssNode               *node);
 void         _gtk_css_selector_tree_match_print      (const GtkCssSelectorTree *tree,
                                                      GString                  *str);
index dbcbd2adf8e0382c0ef4e18363e2cd044e12a163..f9b7c8e94d05a4d7ac77b75442ea4d6eda11473c 100644 (file)
@@ -1,9 +1,9 @@
 window.background:dir(ltr)    
   decoration:dir(ltr)    
   grid.horizontal:dir(ltr)    
-    label:dir(ltr)    name|sibling-name|parent-name|parent-sibling-name
+    label:dir(ltr)    
     box.horizontal:dir(ltr)    
-    label:dir(ltr)    name|sibling-name|parent-name|parent-sibling-name
+    label:dir(ltr)    
     button:dir(ltr)    
       box.horizontal:dir(ltr)    
         checkbutton:dir(ltr)