summaryrefslogtreecommitdiff
path: root/gtk/gtkcssnode.c
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2020-01-26 04:37:17 +0100
committerBenjamin Otte <otte@redhat.com>2020-01-28 02:17:03 +0100
commit170130f1d9c15e4274a24b9327fe01d36ad84290 (patch)
tree0a07692fba8a8b378ed08095480b7e5885fc3dd1 /gtk/gtkcssnode.c
parent6aac56e144e1088565db7d29591fc0bd9e3e509d (diff)
downloadgtk+-170130f1d9c15e4274a24b9327fe01d36ad84290.tar.gz
css: Add fast-path for parent selector matching
Add a fast path for parent selector matching that uses a bloom filter to quickly discard selectors that can't possibly match. Keep in mind that we match using a bloom filter, so we might accidentally include too many selectors when hash/bucket collisions occur. That's not a correctness problem though, because we'll do a real check afterwards. The idea for this change is taken from browsers, in particular WebKit.
Diffstat (limited to 'gtk/gtkcssnode.c')
-rw-r--r--gtk/gtkcssnode.c55
1 files changed, 37 insertions, 18 deletions
diff --git a/gtk/gtkcssnode.c b/gtk/gtkcssnode.c
index 013e9a26f5..b88e9f4fa3 100644
--- a/gtk/gtkcssnode.c
+++ b/gtk/gtkcssnode.c
@@ -354,8 +354,9 @@ store_in_global_parent_cache (GtkCssNode *node,
}
static GtkCssStyle *
-gtk_css_node_create_style (GtkCssNode *cssnode,
- GtkCssChange change)
+gtk_css_node_create_style (GtkCssNode *cssnode,
+ const GtkCountingBloomFilter *filter,
+ GtkCssChange change)
{
const GtkCssNodeDeclaration *decl;
GtkCssStyle *style;
@@ -380,6 +381,7 @@ gtk_css_node_create_style (GtkCssNode *cssnode,
}
style = gtk_css_static_style_new_compute (gtk_css_node_get_style_provider (cssnode),
+ filter,
cssnode,
style_change);
@@ -411,17 +413,18 @@ gtk_css_style_needs_recreation (GtkCssStyle *style,
}
static GtkCssStyle *
-gtk_css_node_real_update_style (GtkCssNode *cssnode,
- GtkCssChange change,
- gint64 timestamp,
- GtkCssStyle *style)
+gtk_css_node_real_update_style (GtkCssNode *cssnode,
+ const GtkCountingBloomFilter *filter,
+ GtkCssChange change,
+ gint64 timestamp,
+ GtkCssStyle *style)
{
GtkCssStyle *static_style, *new_static_style, *new_style;
static_style = GTK_CSS_STYLE (gtk_css_style_get_static_style (style));
if (gtk_css_style_needs_recreation (static_style, change))
- new_static_style = gtk_css_node_create_style (cssnode, change);
+ new_static_style = gtk_css_node_create_style (cssnode, filter, change);
else
new_static_style = g_object_ref (static_style);
@@ -950,8 +953,9 @@ gtk_css_node_needs_new_style (GtkCssNode *cssnode)
}
static void
-gtk_css_node_ensure_style (GtkCssNode *cssnode,
- gint64 current_time)
+gtk_css_node_ensure_style (GtkCssNode *cssnode,
+ const GtkCountingBloomFilter *filter,
+ gint64 current_time)
{
gboolean style_changed;
@@ -959,18 +963,19 @@ gtk_css_node_ensure_style (GtkCssNode *cssnode,
return;
if (cssnode->parent)
- gtk_css_node_ensure_style (cssnode->parent, current_time);
+ gtk_css_node_ensure_style (cssnode->parent, filter, current_time);
if (cssnode->style_is_invalid)
{
GtkCssStyle *new_style;
if (cssnode->previous_sibling)
- gtk_css_node_ensure_style (cssnode->previous_sibling, current_time);
+ gtk_css_node_ensure_style (cssnode->previous_sibling, filter, current_time);
g_clear_pointer (&cssnode->cache, gtk_css_node_style_cache_unref);
new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
+ filter,
cssnode->pending_changes,
current_time,
cssnode->style);
@@ -996,7 +1001,7 @@ gtk_css_node_get_style (GtkCssNode *cssnode)
{
gint64 timestamp = gtk_css_node_get_timestamp (cssnode);
- gtk_css_node_ensure_style (cssnode, timestamp);
+ gtk_css_node_ensure_style (cssnode, NULL, timestamp);
}
return cssnode->style;
@@ -1300,15 +1305,17 @@ gtk_css_node_invalidate (GtkCssNode *cssnode,
}
static void
-gtk_css_node_validate_internal (GtkCssNode *cssnode,
- gint64 timestamp)
+gtk_css_node_validate_internal (GtkCssNode *cssnode,
+ GtkCountingBloomFilter *filter,
+ gint64 timestamp)
{
GtkCssNode *child;
+ gboolean bloomed = FALSE;
if (!cssnode->invalid)
return;
- gtk_css_node_ensure_style (cssnode, timestamp);
+ gtk_css_node_ensure_style (cssnode, filter, timestamp);
/* need to set to FALSE then to TRUE here to make it chain up */
gtk_css_node_set_invalid (cssnode, FALSE);
@@ -1321,20 +1328,32 @@ gtk_css_node_validate_internal (GtkCssNode *cssnode,
child;
child = gtk_css_node_get_next_sibling (child))
{
- if (child->visible)
- gtk_css_node_validate_internal (child, timestamp);
+ if (!child->visible)
+ continue;
+
+ if (!bloomed)
+ {
+ gtk_css_node_declaration_add_bloom_hashes (cssnode->decl, filter);
+ bloomed = TRUE;
+ }
+
+ gtk_css_node_validate_internal (child, filter, timestamp);
}
+
+ if (bloomed)
+ gtk_css_node_declaration_remove_bloom_hashes (cssnode->decl, filter);
}
void
gtk_css_node_validate (GtkCssNode *cssnode)
{
+ GtkCountingBloomFilter filter = GTK_COUNTING_BLOOM_FILTER_INIT;
gint64 timestamp;
gint64 before = g_get_monotonic_time ();
timestamp = gtk_css_node_get_timestamp (cssnode);
- gtk_css_node_validate_internal (cssnode, timestamp);
+ gtk_css_node_validate_internal (cssnode, &filter, timestamp);
if (cssnode->parent == NULL)
{