forked from AuroraMiddleware/gtk
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.
This commit is contained in:
parent
6aac56e144
commit
170130f1d9
158
gtk/gtkcountingbloomfilterprivate.h
Normal file
158
gtk/gtkcountingbloomfilterprivate.h
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2020 Benjamin Otte
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authors: Benjamin Otte <otte@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GTK_COUNTING_BLOOM_FILTER_PRIVATE_H__
|
||||||
|
#define __GTK_COUNTING_BLOOM_FILTER_PRIVATE_H__
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SECTION:gtkcountingbloomfilter
|
||||||
|
* @Short_description: A counting bloom filter
|
||||||
|
* @Title: GtkCountingBloomFilter
|
||||||
|
* @See_also: https://en.wikipedia.org/wiki/Bloom_filter,
|
||||||
|
* https://en.wikipedia.org/wiki/Counting_Bloom_filter
|
||||||
|
*
|
||||||
|
* This implements a counting bloom filter. A bloom filter is a space-efficient
|
||||||
|
* probabilistic data structure that is used to test whether an element may be
|
||||||
|
* a member of a set.
|
||||||
|
* The Wikipedia links provide a lot more details into how and why this data
|
||||||
|
* structure works and when to use it.
|
||||||
|
*
|
||||||
|
* This implementation is based on similar implementations in web browsers, because it's
|
||||||
|
* original use case is the same: Making CSS lookups fast.
|
||||||
|
*
|
||||||
|
* As such, the number of bits is hardcoded to 12 and the elements in the set
|
||||||
|
* are 16bit hash values.
|
||||||
|
* It is possible to use 32bit hash values or a different number of bits, should this
|
||||||
|
* be considered useful.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The number of bits from the hash we care about */
|
||||||
|
#define GTK_COUNTING_BLOOM_FILTER_BITS (12)
|
||||||
|
|
||||||
|
/* The necessary size of the filter */
|
||||||
|
#define GTK_COUNTING_BLOOM_FILTER_SIZE (1 << GTK_COUNTING_BLOOM_FILTER_BITS)
|
||||||
|
|
||||||
|
typedef struct _GtkCountingBloomFilter GtkCountingBloomFilter;
|
||||||
|
|
||||||
|
struct _GtkCountingBloomFilter
|
||||||
|
{
|
||||||
|
guint8 buckets[GTK_COUNTING_BLOOM_FILTER_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void gtk_counting_bloom_filter_add (GtkCountingBloomFilter *self,
|
||||||
|
guint16 hash);
|
||||||
|
static inline void gtk_counting_bloom_filter_remove (GtkCountingBloomFilter *self,
|
||||||
|
guint16 hash);
|
||||||
|
static inline gboolean gtk_counting_bloom_filter_may_contain (const GtkCountingBloomFilter *self,
|
||||||
|
guint16 hash);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GTK_COUNTING_BLOOM_FILTER_INIT:
|
||||||
|
*
|
||||||
|
* Initialize the bloom filter. As bloom filters are always stack-allocated,
|
||||||
|
* initialization should happen when defining them, like:
|
||||||
|
* ```c
|
||||||
|
* GtkCountingBloomFilter filter = GTK_COUNTING_BLOOM_FILTER_INIT;
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The filter does not need to be freed.
|
||||||
|
*/
|
||||||
|
#define GTK_COUNTING_BLOOM_FILTER_INIT { 0, }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gtk_counting_bloom_filter_add:
|
||||||
|
* @self: a #GtkCountingBloomFilter
|
||||||
|
* @hash: a hash value to add to the filter
|
||||||
|
*
|
||||||
|
* Adds the hash value to the filter.
|
||||||
|
*
|
||||||
|
* If the same hash value gets added multiple times, it will
|
||||||
|
* be considered as contained in the hash until it has been
|
||||||
|
* removed as many times.
|
||||||
|
**/
|
||||||
|
static inline void
|
||||||
|
gtk_counting_bloom_filter_add (GtkCountingBloomFilter *self,
|
||||||
|
guint16 hash)
|
||||||
|
{
|
||||||
|
guint16 bucket = hash % GTK_COUNTING_BLOOM_FILTER_SIZE;
|
||||||
|
|
||||||
|
if (self->buckets[bucket] == 255)
|
||||||
|
return;
|
||||||
|
|
||||||
|
self->buckets[bucket]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gtk_counting_bloom_filter_remove:
|
||||||
|
* @self: a #GtkCountingBloomFilter
|
||||||
|
* @hash: a hash value to remove from the filter
|
||||||
|
*
|
||||||
|
* Removes a hash value from the filter that has previously
|
||||||
|
* been added via gtk_counting_bloom_filter_add().
|
||||||
|
**/
|
||||||
|
static inline void
|
||||||
|
gtk_counting_bloom_filter_remove (GtkCountingBloomFilter *self,
|
||||||
|
guint16 hash)
|
||||||
|
{
|
||||||
|
guint16 bucket = hash % GTK_COUNTING_BLOOM_FILTER_SIZE;
|
||||||
|
|
||||||
|
if (self->buckets[bucket] == 255)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_assert (self->buckets[bucket] > 0);
|
||||||
|
|
||||||
|
self->buckets[bucket]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gtk_counting_bloom_filter_may_contain:
|
||||||
|
* @self: a #GtkCountingBloomFilter
|
||||||
|
* @hash: the hash value to check
|
||||||
|
*
|
||||||
|
* Checks if @hash may be contained in @self.
|
||||||
|
*
|
||||||
|
* A return value of %FALSE means that @hash is definitely not part
|
||||||
|
* of @self.
|
||||||
|
*
|
||||||
|
* A return value of %TRUE means that @hash may or may not have been
|
||||||
|
* added to @self. In that case a different method must be used to
|
||||||
|
* confirm that @hash is indeed part of the set.
|
||||||
|
*
|
||||||
|
* Returns: %FALSE if @hash is not part of @self.
|
||||||
|
**/
|
||||||
|
static inline gboolean
|
||||||
|
gtk_counting_bloom_filter_may_contain (const GtkCountingBloomFilter *self,
|
||||||
|
guint16 hash)
|
||||||
|
{
|
||||||
|
guint16 bucket = hash % GTK_COUNTING_BLOOM_FILTER_SIZE;
|
||||||
|
|
||||||
|
return self->buckets[bucket] != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __GTK_COUNTING_BLOOM_FILTER_PRIVATE_H_ */
|
@ -354,8 +354,9 @@ store_in_global_parent_cache (GtkCssNode *node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GtkCssStyle *
|
static GtkCssStyle *
|
||||||
gtk_css_node_create_style (GtkCssNode *cssnode,
|
gtk_css_node_create_style (GtkCssNode *cssnode,
|
||||||
GtkCssChange change)
|
const GtkCountingBloomFilter *filter,
|
||||||
|
GtkCssChange change)
|
||||||
{
|
{
|
||||||
const GtkCssNodeDeclaration *decl;
|
const GtkCssNodeDeclaration *decl;
|
||||||
GtkCssStyle *style;
|
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),
|
style = gtk_css_static_style_new_compute (gtk_css_node_get_style_provider (cssnode),
|
||||||
|
filter,
|
||||||
cssnode,
|
cssnode,
|
||||||
style_change);
|
style_change);
|
||||||
|
|
||||||
@ -411,17 +413,18 @@ gtk_css_style_needs_recreation (GtkCssStyle *style,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GtkCssStyle *
|
static GtkCssStyle *
|
||||||
gtk_css_node_real_update_style (GtkCssNode *cssnode,
|
gtk_css_node_real_update_style (GtkCssNode *cssnode,
|
||||||
GtkCssChange change,
|
const GtkCountingBloomFilter *filter,
|
||||||
gint64 timestamp,
|
GtkCssChange change,
|
||||||
GtkCssStyle *style)
|
gint64 timestamp,
|
||||||
|
GtkCssStyle *style)
|
||||||
{
|
{
|
||||||
GtkCssStyle *static_style, *new_static_style, *new_style;
|
GtkCssStyle *static_style, *new_static_style, *new_style;
|
||||||
|
|
||||||
static_style = GTK_CSS_STYLE (gtk_css_style_get_static_style (style));
|
static_style = GTK_CSS_STYLE (gtk_css_style_get_static_style (style));
|
||||||
|
|
||||||
if (gtk_css_style_needs_recreation (static_style, change))
|
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
|
else
|
||||||
new_static_style = g_object_ref (static_style);
|
new_static_style = g_object_ref (static_style);
|
||||||
|
|
||||||
@ -950,8 +953,9 @@ gtk_css_node_needs_new_style (GtkCssNode *cssnode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_css_node_ensure_style (GtkCssNode *cssnode,
|
gtk_css_node_ensure_style (GtkCssNode *cssnode,
|
||||||
gint64 current_time)
|
const GtkCountingBloomFilter *filter,
|
||||||
|
gint64 current_time)
|
||||||
{
|
{
|
||||||
gboolean style_changed;
|
gboolean style_changed;
|
||||||
|
|
||||||
@ -959,18 +963,19 @@ gtk_css_node_ensure_style (GtkCssNode *cssnode,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (cssnode->parent)
|
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)
|
if (cssnode->style_is_invalid)
|
||||||
{
|
{
|
||||||
GtkCssStyle *new_style;
|
GtkCssStyle *new_style;
|
||||||
|
|
||||||
if (cssnode->previous_sibling)
|
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);
|
g_clear_pointer (&cssnode->cache, gtk_css_node_style_cache_unref);
|
||||||
|
|
||||||
new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
|
new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
|
||||||
|
filter,
|
||||||
cssnode->pending_changes,
|
cssnode->pending_changes,
|
||||||
current_time,
|
current_time,
|
||||||
cssnode->style);
|
cssnode->style);
|
||||||
@ -996,7 +1001,7 @@ gtk_css_node_get_style (GtkCssNode *cssnode)
|
|||||||
{
|
{
|
||||||
gint64 timestamp = gtk_css_node_get_timestamp (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;
|
return cssnode->style;
|
||||||
@ -1300,15 +1305,17 @@ gtk_css_node_invalidate (GtkCssNode *cssnode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_css_node_validate_internal (GtkCssNode *cssnode,
|
gtk_css_node_validate_internal (GtkCssNode *cssnode,
|
||||||
gint64 timestamp)
|
GtkCountingBloomFilter *filter,
|
||||||
|
gint64 timestamp)
|
||||||
{
|
{
|
||||||
GtkCssNode *child;
|
GtkCssNode *child;
|
||||||
|
gboolean bloomed = FALSE;
|
||||||
|
|
||||||
if (!cssnode->invalid)
|
if (!cssnode->invalid)
|
||||||
return;
|
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 */
|
/* need to set to FALSE then to TRUE here to make it chain up */
|
||||||
gtk_css_node_set_invalid (cssnode, FALSE);
|
gtk_css_node_set_invalid (cssnode, FALSE);
|
||||||
@ -1321,20 +1328,32 @@ gtk_css_node_validate_internal (GtkCssNode *cssnode,
|
|||||||
child;
|
child;
|
||||||
child = gtk_css_node_get_next_sibling (child))
|
child = gtk_css_node_get_next_sibling (child))
|
||||||
{
|
{
|
||||||
if (child->visible)
|
if (!child->visible)
|
||||||
gtk_css_node_validate_internal (child, timestamp);
|
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
|
void
|
||||||
gtk_css_node_validate (GtkCssNode *cssnode)
|
gtk_css_node_validate (GtkCssNode *cssnode)
|
||||||
{
|
{
|
||||||
|
GtkCountingBloomFilter filter = GTK_COUNTING_BLOOM_FILTER_INIT;
|
||||||
gint64 timestamp;
|
gint64 timestamp;
|
||||||
gint64 before = g_get_monotonic_time ();
|
gint64 before = g_get_monotonic_time ();
|
||||||
|
|
||||||
timestamp = gtk_css_node_get_timestamp (cssnode);
|
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)
|
if (cssnode->parent == NULL)
|
||||||
{
|
{
|
||||||
|
@ -312,6 +312,40 @@ gtk_css_node_declaration_get_classes (const GtkCssNodeDeclaration *decl,
|
|||||||
return decl->classes;
|
return decl->classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gtk_css_node_declaration_add_bloom_hashes (const GtkCssNodeDeclaration *decl,
|
||||||
|
GtkCountingBloomFilter *filter)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (decl->name)
|
||||||
|
gtk_counting_bloom_filter_add (filter, gtk_css_hash_name (decl->name));
|
||||||
|
if (decl->id)
|
||||||
|
gtk_counting_bloom_filter_add (filter, gtk_css_hash_id (decl->id));
|
||||||
|
|
||||||
|
for (i = 0; i < decl->n_classes; i++)
|
||||||
|
{
|
||||||
|
gtk_counting_bloom_filter_add (filter, gtk_css_hash_class (decl->classes[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gtk_css_node_declaration_remove_bloom_hashes (const GtkCssNodeDeclaration *decl,
|
||||||
|
GtkCountingBloomFilter *filter)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (decl->name)
|
||||||
|
gtk_counting_bloom_filter_remove (filter, gtk_css_hash_name (decl->name));
|
||||||
|
if (decl->id)
|
||||||
|
gtk_counting_bloom_filter_remove (filter, gtk_css_hash_id (decl->id));
|
||||||
|
|
||||||
|
for (i = 0; i < decl->n_classes; i++)
|
||||||
|
{
|
||||||
|
gtk_counting_bloom_filter_remove (filter, gtk_css_hash_class (decl->classes[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
guint
|
guint
|
||||||
gtk_css_node_declaration_hash (gconstpointer elem)
|
gtk_css_node_declaration_hash (gconstpointer elem)
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#ifndef __GTK_CSS_NODE_DECLARATION_PRIVATE_H__
|
#ifndef __GTK_CSS_NODE_DECLARATION_PRIVATE_H__
|
||||||
#define __GTK_CSS_NODE_DECLARATION_PRIVATE_H__
|
#define __GTK_CSS_NODE_DECLARATION_PRIVATE_H__
|
||||||
|
|
||||||
|
#include "gtkcountingbloomfilterprivate.h"
|
||||||
#include "gtkcsstypesprivate.h"
|
#include "gtkcsstypesprivate.h"
|
||||||
#include "gtkenums.h"
|
#include "gtkenums.h"
|
||||||
|
|
||||||
@ -47,6 +48,11 @@ gboolean gtk_css_node_declaration_has_class (const G
|
|||||||
const GQuark * gtk_css_node_declaration_get_classes (const GtkCssNodeDeclaration *decl,
|
const GQuark * gtk_css_node_declaration_get_classes (const GtkCssNodeDeclaration *decl,
|
||||||
guint *n_classes);
|
guint *n_classes);
|
||||||
|
|
||||||
|
void gtk_css_node_declaration_add_bloom_hashes (const GtkCssNodeDeclaration *decl,
|
||||||
|
GtkCountingBloomFilter *filter);
|
||||||
|
void gtk_css_node_declaration_remove_bloom_hashes (const GtkCssNodeDeclaration *decl,
|
||||||
|
GtkCountingBloomFilter *filter);
|
||||||
|
|
||||||
guint gtk_css_node_declaration_hash (gconstpointer elem);
|
guint gtk_css_node_declaration_hash (gconstpointer elem);
|
||||||
gboolean gtk_css_node_declaration_equal (gconstpointer elem1,
|
gboolean gtk_css_node_declaration_equal (gconstpointer elem1,
|
||||||
gconstpointer elem2);
|
gconstpointer elem2);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#ifndef __GTK_CSS_NODE_PRIVATE_H__
|
#ifndef __GTK_CSS_NODE_PRIVATE_H__
|
||||||
#define __GTK_CSS_NODE_PRIVATE_H__
|
#define __GTK_CSS_NODE_PRIVATE_H__
|
||||||
|
|
||||||
|
#include "gtkcountingbloomfilterprivate.h"
|
||||||
#include "gtkcssnodedeclarationprivate.h"
|
#include "gtkcssnodedeclarationprivate.h"
|
||||||
#include "gtkcssnodestylecacheprivate.h"
|
#include "gtkcssnodestylecacheprivate.h"
|
||||||
#include "gtkcssstylechangeprivate.h"
|
#include "gtkcssstylechangeprivate.h"
|
||||||
@ -81,6 +82,7 @@ struct _GtkCssNodeClass
|
|||||||
/* get frame clock or NULL (only relevant for root node) */
|
/* get frame clock or NULL (only relevant for root node) */
|
||||||
GdkFrameClock * (* get_frame_clock) (GtkCssNode *cssnode);
|
GdkFrameClock * (* get_frame_clock) (GtkCssNode *cssnode);
|
||||||
GtkCssStyle * (* update_style) (GtkCssNode *cssnode,
|
GtkCssStyle * (* update_style) (GtkCssNode *cssnode,
|
||||||
|
const GtkCountingBloomFilter *filter,
|
||||||
GtkCssChange pending_changes,
|
GtkCssChange pending_changes,
|
||||||
gint64 timestamp,
|
gint64 timestamp,
|
||||||
GtkCssStyle *old_style);
|
GtkCssStyle *old_style);
|
||||||
|
@ -448,10 +448,11 @@ gtk_css_style_provider_get_keyframes (GtkStyleProvider *provider,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_css_style_provider_lookup (GtkStyleProvider *provider,
|
gtk_css_style_provider_lookup (GtkStyleProvider *provider,
|
||||||
GtkCssNode *node,
|
const GtkCountingBloomFilter *filter,
|
||||||
GtkCssLookup *lookup,
|
GtkCssNode *node,
|
||||||
GtkCssChange *change)
|
GtkCssLookup *lookup,
|
||||||
|
GtkCssChange *change)
|
||||||
{
|
{
|
||||||
GtkCssProvider *css_provider = GTK_CSS_PROVIDER (provider);
|
GtkCssProvider *css_provider = GTK_CSS_PROVIDER (provider);
|
||||||
GtkCssProviderPrivate *priv = gtk_css_provider_get_instance_private (css_provider);
|
GtkCssProviderPrivate *priv = gtk_css_provider_get_instance_private (css_provider);
|
||||||
@ -463,7 +464,7 @@ gtk_css_style_provider_lookup (GtkStyleProvider *provider,
|
|||||||
if (_gtk_css_selector_tree_is_empty (priv->tree))
|
if (_gtk_css_selector_tree_is_empty (priv->tree))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tree_rules = _gtk_css_selector_tree_match_all (priv->tree, node);
|
tree_rules = _gtk_css_selector_tree_match_all (priv->tree, filter, node);
|
||||||
if (tree_rules)
|
if (tree_rules)
|
||||||
{
|
{
|
||||||
verify_tree_match_results (css_provider, node, tree_rules);
|
verify_tree_match_results (css_provider, node, tree_rules);
|
||||||
|
@ -168,24 +168,6 @@ g_ptr_array_insert_sorted (GPtrArray *array,
|
|||||||
g_ptr_array_insert (array, i, data);
|
g_ptr_array_insert (array, i, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
|
|
||||||
GPtrArray **array)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
gpointer *matches;
|
|
||||||
|
|
||||||
matches = gtk_css_selector_tree_get_matches (tree);
|
|
||||||
if (matches)
|
|
||||||
{
|
|
||||||
if (!*array)
|
|
||||||
*array = g_ptr_array_sized_new (16);
|
|
||||||
|
|
||||||
for (i = 0; matches[i] != NULL; i++)
|
|
||||||
g_ptr_array_insert_sorted (*array, matches[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
gtk_css_selector_match (const GtkCssSelector *selector,
|
gtk_css_selector_match (const GtkCssSelector *selector,
|
||||||
GtkCssNode *node)
|
GtkCssNode *node)
|
||||||
@ -1864,38 +1846,115 @@ gtk_css_selectors_skip_initial_selector (GtkCssSelector *selector, const GtkCssS
|
|||||||
return (GtkCssSelector *)gtk_css_selector_previous (selector);
|
return (GtkCssSelector *)gtk_css_selector_previous (selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gtk_css_selector_tree_match_bloom (const GtkCssSelectorTree *tree,
|
||||||
|
const GtkCountingBloomFilter *filter,
|
||||||
|
gboolean skipping)
|
||||||
|
{
|
||||||
|
const GtkCssSelectorTree *prev;
|
||||||
|
|
||||||
|
switch (tree->selector.class->category)
|
||||||
|
{
|
||||||
|
case GTK_CSS_SELECTOR_CATEGORY_SIMPLE:
|
||||||
|
break;
|
||||||
|
case GTK_CSS_SELECTOR_CATEGORY_SIMPLE_RADICAL:
|
||||||
|
if (skipping)
|
||||||
|
break;
|
||||||
|
if (!gtk_counting_bloom_filter_may_contain (filter,
|
||||||
|
gtk_css_selector_hash_one (&tree->selector)))
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
case GTK_CSS_SELECTOR_CATEGORY_PARENT:
|
||||||
|
skipping = FALSE;
|
||||||
|
break;
|
||||||
|
case GTK_CSS_SELECTOR_CATEGORY_SIBLING:
|
||||||
|
skipping = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtk_css_selector_tree_get_matches (tree))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
for (prev = gtk_css_selector_tree_get_previous (tree);
|
||||||
|
prev != NULL;
|
||||||
|
prev = gtk_css_selector_tree_get_sibling (prev))
|
||||||
|
{
|
||||||
|
if (gtk_css_selector_tree_match_bloom (prev, filter, skipping))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const GtkCountingBloomFilter *filter;
|
||||||
|
GPtrArray *results;
|
||||||
|
} TreeMatchData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
|
||||||
|
TreeMatchData *tm)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
gpointer *matches;
|
||||||
|
|
||||||
|
matches = gtk_css_selector_tree_get_matches (tree);
|
||||||
|
if (matches)
|
||||||
|
{
|
||||||
|
if (tm->results == NULL)
|
||||||
|
tm->results = g_ptr_array_sized_new (16);
|
||||||
|
|
||||||
|
for (i = 0; matches[i] != NULL; i++)
|
||||||
|
g_ptr_array_insert_sorted (tm->results, matches[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_css_selector_tree_match_foreach (const GtkCssSelector *selector,
|
gtk_css_selector_tree_match_foreach (const GtkCssSelector *selector,
|
||||||
GtkCssNode *node,
|
GtkCssNode *node,
|
||||||
gpointer res)
|
gpointer data)
|
||||||
{
|
{
|
||||||
|
TreeMatchData *tm = data;
|
||||||
const GtkCssSelectorTree *tree = (const GtkCssSelectorTree *) selector;
|
const GtkCssSelectorTree *tree = (const GtkCssSelectorTree *) selector;
|
||||||
const GtkCssSelectorTree *prev;
|
const GtkCssSelectorTree *prev;
|
||||||
|
|
||||||
if (!gtk_css_selector_match (selector, node))
|
if (!gtk_css_selector_match (selector, node))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
gtk_css_selector_tree_found_match (tree, res);
|
gtk_css_selector_tree_found_match (tree, tm);
|
||||||
|
|
||||||
|
if (tm->filter && !gtk_css_selector_is_simple (&tree->selector))
|
||||||
|
{
|
||||||
|
/* We can pass both TRUE or FALSE for skipping here, because the
|
||||||
|
* function will immediately update it. */
|
||||||
|
if (!gtk_css_selector_tree_match_bloom (tree, tm->filter, FALSE))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
for (prev = gtk_css_selector_tree_get_previous (tree);
|
for (prev = gtk_css_selector_tree_get_previous (tree);
|
||||||
prev != NULL;
|
prev != NULL;
|
||||||
prev = gtk_css_selector_tree_get_sibling (prev))
|
prev = gtk_css_selector_tree_get_sibling (prev))
|
||||||
gtk_css_selector_foreach (&prev->selector, node, gtk_css_selector_tree_match_foreach, res);
|
gtk_css_selector_foreach (&prev->selector, node, gtk_css_selector_tree_match_foreach, tm);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPtrArray *
|
GPtrArray *
|
||||||
_gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
|
_gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
|
||||||
GtkCssNode *node)
|
const GtkCountingBloomFilter *filter,
|
||||||
|
GtkCssNode *node)
|
||||||
{
|
{
|
||||||
GPtrArray *array = NULL;
|
TreeMatchData tm = { filter, NULL };
|
||||||
|
|
||||||
for (; tree != NULL;
|
for (; tree != NULL;
|
||||||
tree = gtk_css_selector_tree_get_sibling (tree))
|
tree = gtk_css_selector_tree_get_sibling (tree))
|
||||||
gtk_css_selector_foreach (&tree->selector, node, gtk_css_selector_tree_match_foreach, &array);
|
gtk_css_selector_foreach (&tree->selector, node, gtk_css_selector_tree_match_foreach, &tm);
|
||||||
|
|
||||||
return array;
|
return tm.results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The code for collecting matches assumes that the name, id and classes
|
/* The code for collecting matches assumes that the name, id and classes
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#ifndef __GTK_CSS_SELECTOR_PRIVATE_H__
|
#ifndef __GTK_CSS_SELECTOR_PRIVATE_H__
|
||||||
#define __GTK_CSS_SELECTOR_PRIVATE_H__
|
#define __GTK_CSS_SELECTOR_PRIVATE_H__
|
||||||
|
|
||||||
|
#include "gtk/gtkcountingbloomfilterprivate.h"
|
||||||
#include "gtk/gtkcsstypesprivate.h"
|
#include "gtk/gtkcsstypesprivate.h"
|
||||||
#include "gtk/gtkcssparserprivate.h"
|
#include "gtk/gtkcssparserprivate.h"
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ int _gtk_css_selector_compare (const GtkCssSelector *a,
|
|||||||
|
|
||||||
void _gtk_css_selector_tree_free (GtkCssSelectorTree *tree);
|
void _gtk_css_selector_tree_free (GtkCssSelectorTree *tree);
|
||||||
GPtrArray * _gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
|
GPtrArray * _gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
|
||||||
|
const GtkCountingBloomFilter *filter,
|
||||||
GtkCssNode *node);
|
GtkCssNode *node);
|
||||||
GtkCssChange _gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
|
GtkCssChange _gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
|
||||||
GtkCssNode *node);
|
GtkCssNode *node);
|
||||||
|
@ -161,10 +161,12 @@ gtk_css_static_style_get_default (void)
|
|||||||
*/
|
*/
|
||||||
if (default_style == NULL)
|
if (default_style == NULL)
|
||||||
{
|
{
|
||||||
|
GtkCountingBloomFilter filter = GTK_COUNTING_BLOOM_FILTER_INIT;
|
||||||
GtkSettings *settings;
|
GtkSettings *settings;
|
||||||
|
|
||||||
settings = gtk_settings_get_default ();
|
settings = gtk_settings_get_default ();
|
||||||
default_style = gtk_css_static_style_new_compute (GTK_STYLE_PROVIDER (settings),
|
default_style = gtk_css_static_style_new_compute (GTK_STYLE_PROVIDER (settings),
|
||||||
|
&filter,
|
||||||
NULL,
|
NULL,
|
||||||
0);
|
0);
|
||||||
g_object_set_data_full (G_OBJECT (settings), I_("gtk-default-style"),
|
g_object_set_data_full (G_OBJECT (settings), I_("gtk-default-style"),
|
||||||
@ -175,9 +177,10 @@ gtk_css_static_style_get_default (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GtkCssStyle *
|
GtkCssStyle *
|
||||||
gtk_css_static_style_new_compute (GtkStyleProvider *provider,
|
gtk_css_static_style_new_compute (GtkStyleProvider *provider,
|
||||||
GtkCssNode *node,
|
const GtkCountingBloomFilter *filter,
|
||||||
GtkCssChange change)
|
GtkCssNode *node,
|
||||||
|
GtkCssChange change)
|
||||||
{
|
{
|
||||||
GtkCssStaticStyle *result;
|
GtkCssStaticStyle *result;
|
||||||
GtkCssLookup lookup;
|
GtkCssLookup lookup;
|
||||||
@ -187,6 +190,7 @@ gtk_css_static_style_new_compute (GtkStyleProvider *provider,
|
|||||||
|
|
||||||
if (node)
|
if (node)
|
||||||
gtk_style_provider_lookup (provider,
|
gtk_style_provider_lookup (provider,
|
||||||
|
filter,
|
||||||
node,
|
node,
|
||||||
&lookup,
|
&lookup,
|
||||||
change == 0 ? &change : NULL);
|
change == 0 ? &change : NULL);
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include "gtk/gtkcssstyleprivate.h"
|
#include "gtk/gtkcssstyleprivate.h"
|
||||||
|
|
||||||
|
#include "gtk/gtkcountingbloomfilterprivate.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define GTK_TYPE_CSS_STATIC_STYLE (gtk_css_static_style_get_type ())
|
#define GTK_TYPE_CSS_STATIC_STYLE (gtk_css_static_style_get_type ())
|
||||||
@ -51,18 +53,19 @@ struct _GtkCssStaticStyleClass
|
|||||||
GType gtk_css_static_style_get_type (void) G_GNUC_CONST;
|
GType gtk_css_static_style_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
GtkCssStyle * gtk_css_static_style_get_default (void);
|
GtkCssStyle * gtk_css_static_style_get_default (void);
|
||||||
GtkCssStyle * gtk_css_static_style_new_compute (GtkStyleProvider *provider,
|
GtkCssStyle * gtk_css_static_style_new_compute (GtkStyleProvider *provider,
|
||||||
GtkCssNode *node,
|
const GtkCountingBloomFilter *filter,
|
||||||
GtkCssChange change);
|
GtkCssNode *node,
|
||||||
|
GtkCssChange change);
|
||||||
|
|
||||||
void gtk_css_static_style_compute_value (GtkCssStaticStyle *style,
|
void gtk_css_static_style_compute_value (GtkCssStaticStyle *style,
|
||||||
GtkStyleProvider *provider,
|
GtkStyleProvider *provider,
|
||||||
GtkCssStyle *parent_style,
|
GtkCssStyle *parent_style,
|
||||||
guint id,
|
guint id,
|
||||||
GtkCssValue *specified,
|
GtkCssValue *specified,
|
||||||
GtkCssSection *section);
|
GtkCssSection *section);
|
||||||
|
|
||||||
GtkCssChange gtk_css_static_style_get_change (GtkCssStaticStyle *style);
|
GtkCssChange gtk_css_static_style_get_change (GtkCssStaticStyle *style);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
@ -23,13 +23,14 @@
|
|||||||
G_DEFINE_TYPE (GtkCssTransientNode, gtk_css_transient_node, GTK_TYPE_CSS_NODE)
|
G_DEFINE_TYPE (GtkCssTransientNode, gtk_css_transient_node, GTK_TYPE_CSS_NODE)
|
||||||
|
|
||||||
static GtkCssStyle *
|
static GtkCssStyle *
|
||||||
gtk_css_transient_node_update_style (GtkCssNode *cssnode,
|
gtk_css_transient_node_update_style (GtkCssNode *cssnode,
|
||||||
GtkCssChange change,
|
const GtkCountingBloomFilter *filter,
|
||||||
gint64 timestamp,
|
GtkCssChange change,
|
||||||
GtkCssStyle *style)
|
gint64 timestamp,
|
||||||
|
GtkCssStyle *style)
|
||||||
{
|
{
|
||||||
/* This should get rid of animations */
|
/* This should get rid of animations */
|
||||||
return GTK_CSS_NODE_CLASS (gtk_css_transient_node_parent_class)->update_style (cssnode, change, 0, style);
|
return GTK_CSS_NODE_CLASS (gtk_css_transient_node_parent_class)->update_style (cssnode, filter, change, 0, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -179,10 +179,11 @@ gtk_style_cascade_get_keyframes (GtkStyleProvider *provider,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_style_cascade_lookup (GtkStyleProvider *provider,
|
gtk_style_cascade_lookup (GtkStyleProvider *provider,
|
||||||
GtkCssNode *node,
|
const GtkCountingBloomFilter *filter,
|
||||||
GtkCssLookup *lookup,
|
GtkCssNode *node,
|
||||||
GtkCssChange *change)
|
GtkCssLookup *lookup,
|
||||||
|
GtkCssChange *change)
|
||||||
{
|
{
|
||||||
GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
|
GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
|
||||||
GtkStyleCascadeIter iter;
|
GtkStyleCascadeIter iter;
|
||||||
@ -193,7 +194,7 @@ gtk_style_cascade_lookup (GtkStyleProvider *provider,
|
|||||||
item;
|
item;
|
||||||
item = gtk_style_cascade_iter_next (cascade, &iter))
|
item = gtk_style_cascade_iter_next (cascade, &iter))
|
||||||
{
|
{
|
||||||
gtk_style_provider_lookup (item, node, lookup,
|
gtk_style_provider_lookup (item, filter, node, lookup,
|
||||||
change ? &iter_change : NULL);
|
change ? &iter_change : NULL);
|
||||||
if (change)
|
if (change)
|
||||||
*change |= iter_change;
|
*change |= iter_change;
|
||||||
|
@ -92,10 +92,11 @@ gtk_style_provider_get_keyframes (GtkStyleProvider *provider,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gtk_style_provider_lookup (GtkStyleProvider *provider,
|
gtk_style_provider_lookup (GtkStyleProvider *provider,
|
||||||
GtkCssNode *node,
|
const GtkCountingBloomFilter *filter,
|
||||||
GtkCssLookup *lookup,
|
GtkCssNode *node,
|
||||||
GtkCssChange *out_change)
|
GtkCssLookup *lookup,
|
||||||
|
GtkCssChange *out_change)
|
||||||
{
|
{
|
||||||
GtkStyleProviderInterface *iface;
|
GtkStyleProviderInterface *iface;
|
||||||
|
|
||||||
@ -111,7 +112,7 @@ gtk_style_provider_lookup (GtkStyleProvider *provider,
|
|||||||
if (!iface->lookup)
|
if (!iface->lookup)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
iface->lookup (provider, node, lookup, out_change);
|
iface->lookup (provider, filter, node, lookup, out_change);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#define __GTK_STYLE_PROVIDER_PRIVATE_H__
|
#define __GTK_STYLE_PROVIDER_PRIVATE_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
#include "gtk/gtkcountingbloomfilterprivate.h"
|
||||||
#include "gtk/gtkcsskeyframesprivate.h"
|
#include "gtk/gtkcsskeyframesprivate.h"
|
||||||
#include "gtk/gtkcsslookupprivate.h"
|
#include "gtk/gtkcsslookupprivate.h"
|
||||||
#include "gtk/gtkcssnodeprivate.h"
|
#include "gtk/gtkcssnodeprivate.h"
|
||||||
@ -42,6 +43,7 @@ struct _GtkStyleProviderInterface
|
|||||||
const char *name);
|
const char *name);
|
||||||
int (* get_scale) (GtkStyleProvider *provider);
|
int (* get_scale) (GtkStyleProvider *provider);
|
||||||
void (* lookup) (GtkStyleProvider *provider,
|
void (* lookup) (GtkStyleProvider *provider,
|
||||||
|
const GtkCountingBloomFilter *filter,
|
||||||
GtkCssNode *node,
|
GtkCssNode *node,
|
||||||
GtkCssLookup *lookup,
|
GtkCssLookup *lookup,
|
||||||
GtkCssChange *out_change);
|
GtkCssChange *out_change);
|
||||||
@ -59,6 +61,7 @@ GtkCssKeyframes * gtk_style_provider_get_keyframes (GtkStyleProvid
|
|||||||
const char *name);
|
const char *name);
|
||||||
int gtk_style_provider_get_scale (GtkStyleProvider *provider);
|
int gtk_style_provider_get_scale (GtkStyleProvider *provider);
|
||||||
void gtk_style_provider_lookup (GtkStyleProvider *provider,
|
void gtk_style_provider_lookup (GtkStyleProvider *provider,
|
||||||
|
const GtkCountingBloomFilter *filter,
|
||||||
GtkCssNode *node,
|
GtkCssNode *node,
|
||||||
GtkCssLookup *lookup,
|
GtkCssLookup *lookup,
|
||||||
GtkCssChange *out_change);
|
GtkCssChange *out_change);
|
||||||
|
Loading…
Reference in New Issue
Block a user