From eb4667b6e1672043a9d9ff75a959e82b133618a7 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 10 Dec 2012 11:27:43 +0100 Subject: [PATCH] css: Do get_change directly on the tree without matching first Rather than first collecting matches and then getting the change for them we do the change collection directly on the tree. This is about twice as fast. --- gtk/gtkcssprovider.c | 70 ++++--- gtk/gtkcssselector.c | 387 ++++++++++++++++++++++++++++++++++++ gtk/gtkcssselectorprivate.h | 2 + gtk/gtkcsstypesprivate.h | 4 +- 4 files changed, 438 insertions(+), 25 deletions(-) diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c index a8e13edfab..7512668474 100644 --- a/gtk/gtkcssprovider.c +++ b/gtk/gtkcssprovider.c @@ -1273,12 +1273,6 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset, ruleset->styles[i].section = NULL; } -static GtkCssChange -gtk_css_ruleset_get_change (GtkCssRuleset *ruleset) -{ - return _gtk_css_selector_tree_match_get_change (ruleset->selector_match); -} - static void gtk_css_scanner_destroy (GtkCssScanner *scanner) { @@ -1441,6 +1435,49 @@ verify_tree_match_results (GtkCssProvider *provider, #endif } +static void +verify_tree_get_change_results (GtkCssProvider *provider, + const GtkCssMatcher *matcher, + GtkCssChange change) +{ +#ifdef VERIFY_TREE + { + GtkCssChange verify_change = 0; + GPtrArray *tree_rules; + int i; + + tree_rules = _gtk_css_selector_tree_match_all (provider->priv->tree, matcher); + verify_tree_match_results (provider, matcher, tree_rules); + + for (i = tree_rules->len - 1; i >= 0; i--) + { + GtkCssRuleset *ruleset; + + ruleset = tree_rules->pdata[i]; + + verify_change |= _gtk_css_selector_tree_match_get_change (ruleset->selector_match); + } + + if (change != verify_change) + { + GString *s; + + s = g_string_new (""); + g_string_append_printf (s, "expected change 0x%x, but it was 0x%x", verify_change, change); + if ((change & ~verify_change) != 0) + g_string_append_printf (s, ", unexpectedly set: 0x%x", change & ~verify_change); + if ((~change & verify_change) != 0) + g_string_append_printf (s, ", unexpectedly no set: 0x%x", ~change & verify_change); + g_warning (s->str); + g_string_free (s, TRUE); + } + + g_ptr_array_free (tree_rules, TRUE); + } +#endif +} + + static gboolean gtk_css_provider_get_style_property (GtkStyleProvider *provider, GtkWidgetPath *path, @@ -1585,29 +1622,14 @@ gtk_css_style_provider_get_change (GtkStyleProviderPrivate *provider, { GtkCssProvider *css_provider; GtkCssProviderPrivate *priv; - GtkCssChange change = 0; - GPtrArray *tree_rules; - int i; + GtkCssChange change; css_provider = GTK_CSS_PROVIDER (provider); priv = css_provider->priv; - tree_rules = _gtk_css_selector_tree_match_all (priv->tree, matcher); - verify_tree_match_results (css_provider, matcher, tree_rules); + change = _gtk_css_selector_tree_get_change_all (priv->tree, matcher); - for (i = tree_rules->len - 1; i >= 0; i--) - { - GtkCssRuleset *ruleset; - - ruleset = tree_rules->pdata[i]; - - if (ruleset->styles == NULL) - continue; - - change |= gtk_css_ruleset_get_change (ruleset); - } - - g_ptr_array_free (tree_rules, TRUE); + verify_tree_get_change_results (css_provider, matcher, change); return change; } diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c index 72f1eadd92..a6b6947a9b 100644 --- a/gtk/gtkcssselector.c +++ b/gtk/gtkcssselector.c @@ -25,6 +25,17 @@ #include "gtkcssprovider.h" #include "gtkstylecontextprivate.h" +/* 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 a match like *.class:active we'll + get a tree that first checks :active, if that matches we continue down + to the tree, and if we get a match we add CHANGE_CLASS. However, the + end of the tree where we have a match is an ANY which doesn't actually + modify the change, so we don't know if we have a match or not. We fix + this by setting GTK_CSS_CHANGE_GOT_MATCH which lets us guarantee + that change != 0 on any match. */ +#define GTK_CSS_CHANGE_GOT_MATCH GTK_CSS_CHANGE_RESERVED_BIT + typedef struct _GtkCssSelectorClass GtkCssSelectorClass; struct _GtkCssSelectorClass { @@ -39,6 +50,8 @@ struct _GtkCssSelectorClass { GHashTable *res); GtkCssChange (* get_change) (const GtkCssSelector *selector, GtkCssChange previous_change); + GtkCssChange (* tree_get_change) (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher); int (* compare_one) (const GtkCssSelector *a, const GtkCssSelector *b); @@ -117,6 +130,16 @@ gtk_css_selector_tree_match (const GtkCssSelectorTree *tree, tree->selector.class->tree_match (tree, matcher, res); } +static GtkCssChange +gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + if (tree == NULL) + return 0; + + return tree->selector.class->tree_get_change (tree, matcher); +} + static gboolean gtk_css_selector_match (const GtkCssSelector *selector, const GtkCssMatcher *matcher) @@ -172,6 +195,21 @@ gtk_css_selector_tree_get_sibling (const GtkCssSelectorTree *tree) return gtk_css_selector_tree_at_offset (tree, tree->sibling_offset); } +static GtkCssChange +gtk_css_selector_tree_get_previous_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkCssChange previous_change = 0; + const GtkCssSelectorTree *prev; + + for (prev = gtk_css_selector_tree_get_previous (tree); + prev != NULL; + prev = gtk_css_selector_tree_get_sibling (prev)) + previous_change |= gtk_css_selector_tree_get_change (prev, matcher); + + return previous_change; +} + /* DESCENDANT */ static void @@ -222,6 +260,33 @@ gtk_css_selector_descendant_tree_match (const GtkCssSelectorTree *tree, } } +static GtkCssChange +gtk_css_selector_descendant_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkCssMatcher ancestor; + GtkCssChange change, previous_change; + + change = 0; + previous_change = 0; + while (_gtk_css_matcher_get_parent (&ancestor, matcher)) + { + matcher = &ancestor; + + previous_change |= gtk_css_selector_tree_get_previous_change (tree, matcher); + + /* any matchers are dangerous here, as we may loop forever, but + we can terminate now as all possible matches have already been added */ + if (_gtk_css_matcher_matches_any (matcher)) + break; + } + + if (previous_change != 0) + change |= _gtk_css_change_for_child (previous_change) | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + static int gtk_css_selector_descendant_compare_one (const GtkCssSelector *a, const GtkCssSelector *b) @@ -241,6 +306,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT = { gtk_css_selector_descendant_match, gtk_css_selector_descendant_tree_match, gtk_css_selector_descendant_get_change, + gtk_css_selector_descendant_tree_get_change, gtk_css_selector_descendant_compare_one, FALSE, FALSE, FALSE, FALSE, FALSE }; @@ -283,6 +349,27 @@ gtk_css_selector_child_tree_match (const GtkCssSelectorTree *tree, gtk_css_selector_tree_match (prev, &parent, res); } + +static GtkCssChange +gtk_css_selector_child_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkCssMatcher parent; + GtkCssChange change, previous_change; + + if (!_gtk_css_matcher_get_parent (&parent, matcher)) + return 0; + + change = 0; + + previous_change = gtk_css_selector_tree_get_previous_change (tree, &parent); + + if (previous_change != 0) + change |= _gtk_css_change_for_child (previous_change) | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + static GtkCssChange gtk_css_selector_child_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) { @@ -302,6 +389,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CHILD = { gtk_css_selector_child_match, gtk_css_selector_child_tree_match, gtk_css_selector_child_get_change, + gtk_css_selector_child_tree_get_change, gtk_css_selector_child_compare_one, FALSE, FALSE, FALSE, FALSE, FALSE }; @@ -356,6 +444,34 @@ gtk_css_selector_sibling_tree_match (const GtkCssSelectorTree *tree, } } +static GtkCssChange +gtk_css_selector_sibling_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkCssMatcher previous; + GtkCssChange change, previous_change; + + change = 0; + + previous_change = 0; + while (_gtk_css_matcher_get_previous (&previous, matcher)) + { + matcher = &previous; + + previous_change |= gtk_css_selector_tree_get_previous_change (tree, matcher); + + /* any matchers are dangerous here, as we may loop forever, but + we can terminate now as all possible matches have already been added */ + if (_gtk_css_matcher_matches_any (matcher)) + break; + } + + if (previous_change != 0) + change |= _gtk_css_change_for_sibling (previous_change) | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + static GtkCssChange gtk_css_selector_sibling_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) { @@ -376,6 +492,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_SIBLING = { gtk_css_selector_sibling_match, gtk_css_selector_sibling_tree_match, gtk_css_selector_sibling_get_change, + gtk_css_selector_sibling_tree_get_change, gtk_css_selector_sibling_compare_one, FALSE, FALSE, FALSE, FALSE, FALSE }; @@ -420,6 +537,26 @@ gtk_css_selector_adjacent_tree_match (const GtkCssSelectorTree *tree, gtk_css_selector_tree_match (prev, matcher, res); } +static GtkCssChange +gtk_css_selector_adjacent_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkCssMatcher previous; + GtkCssChange change, previous_change; + + if (!_gtk_css_matcher_get_previous (&previous, matcher)) + return 0; + + change = 0; + + previous_change = gtk_css_selector_tree_get_previous_change (tree, &previous); + + if (previous_change != 0) + change |= _gtk_css_change_for_sibling (previous_change) | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + static GtkCssChange gtk_css_selector_adjacent_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) { @@ -439,6 +576,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ADJACENT = { gtk_css_selector_adjacent_match, gtk_css_selector_adjacent_tree_match, gtk_css_selector_adjacent_get_change, + gtk_css_selector_adjacent_tree_get_change, gtk_css_selector_adjacent_compare_one, FALSE, FALSE, FALSE, FALSE, FALSE }; @@ -495,6 +633,37 @@ gtk_css_selector_any_tree_match (const GtkCssSelectorTree *tree, } } +static GtkCssChange +gtk_css_selector_any_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + const GtkCssSelectorTree *prev; + GtkCssChange change, previous_change; + + change = 0; + + if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET) + change |= GTK_CSS_CHANGE_GOT_MATCH; + + previous_change = 0; + for (prev = gtk_css_selector_tree_get_previous (tree); + prev != NULL; + prev = gtk_css_selector_tree_get_sibling (prev)) + { + if (prev->selector.class == >K_CSS_SELECTOR_DESCENDANT && + _gtk_css_matcher_has_regions (matcher)) + previous_change |= gtk_css_selector_tree_get_previous_change (prev, matcher); + + previous_change |= gtk_css_selector_tree_get_change (prev, matcher); + } + + if (previous_change != 0) + change |= previous_change | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + + static GtkCssChange gtk_css_selector_any_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) { @@ -514,6 +683,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ANY = { gtk_css_selector_any_match, gtk_css_selector_any_tree_match, gtk_css_selector_any_get_change, + gtk_css_selector_any_tree_get_change, gtk_css_selector_any_compare_one, FALSE, FALSE, FALSE, TRUE, TRUE }; @@ -555,6 +725,28 @@ gtk_css_selector_name_tree_match (const GtkCssSelectorTree *tree, gtk_css_selector_tree_match (prev, matcher, res); } +static GtkCssChange +gtk_css_selector_name_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkCssChange change, previous_change; + + if (!_gtk_css_matcher_has_name (matcher, tree->selector.data)) + return 0; + + change = 0; + + if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET) + change |= GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_GOT_MATCH; + + previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher); + + if (previous_change) + change |= previous_change | GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + static GtkCssChange gtk_css_selector_name_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) @@ -575,6 +767,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_NAME = { gtk_css_selector_name_match, gtk_css_selector_name_tree_match, gtk_css_selector_name_get_change, + gtk_css_selector_name_tree_get_change, gtk_css_selector_name_compare_one, FALSE, FALSE, TRUE, TRUE, FALSE }; @@ -633,6 +826,42 @@ gtk_css_selector_region_tree_match (const GtkCssSelectorTree *tree, } } +static GtkCssChange +gtk_css_selector_region_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + const GtkCssSelectorTree *prev; + GtkCssChange change, previous_change; + + if (!_gtk_css_matcher_has_region (matcher, tree->selector.data, 0)) + return 0; + + change = 0; + + if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET) + change |= GTK_CSS_CHANGE_REGION | GTK_CSS_CHANGE_GOT_MATCH; + + previous_change = 0; + for (prev = gtk_css_selector_tree_get_previous (tree); + prev != NULL; + prev = gtk_css_selector_tree_get_sibling (prev)) + { + if (prev->selector.class == >K_CSS_SELECTOR_DESCENDANT) + previous_change |= gtk_css_selector_tree_get_previous_change (prev, matcher); + + previous_change |= gtk_css_selector_tree_get_change (prev, matcher); + } + + if (previous_change != 0) + { + previous_change |= GTK_CSS_CHANGE_REGION; + previous_change |= _gtk_css_change_for_child (previous_change); + change |= previous_change | GTK_CSS_CHANGE_GOT_MATCH; + } + + return change; +} + static GtkCssChange gtk_css_selector_region_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) { @@ -658,6 +887,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_REGION = { gtk_css_selector_region_match, gtk_css_selector_region_tree_match, gtk_css_selector_region_get_change, + gtk_css_selector_region_tree_get_change, gtk_css_selector_region_compare_one, FALSE, FALSE, TRUE, TRUE, TRUE }; @@ -700,6 +930,28 @@ gtk_css_selector_class_tree_match (const GtkCssSelectorTree *tree, gtk_css_selector_tree_match (prev, matcher, res); } +static GtkCssChange +gtk_css_selector_class_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkCssChange change, previous_change; + + if (!_gtk_css_matcher_has_class (matcher, GPOINTER_TO_UINT (tree->selector.data))) + return 0; + + change = 0; + + if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET) + change |= GTK_CSS_CHANGE_CLASS | GTK_CSS_CHANGE_GOT_MATCH; + + previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher); + + if (previous_change != 0) + change |= previous_change | GTK_CSS_CHANGE_CLASS | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + static GtkCssChange gtk_css_selector_class_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) { @@ -720,6 +972,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CLASS = { gtk_css_selector_class_match, gtk_css_selector_class_tree_match, gtk_css_selector_class_get_change, + gtk_css_selector_class_tree_get_change, gtk_css_selector_class_compare_one, FALSE, TRUE, FALSE, TRUE, FALSE }; @@ -762,6 +1015,28 @@ gtk_css_selector_id_tree_match (const GtkCssSelectorTree *tree, gtk_css_selector_tree_match (prev, matcher, res); } +static GtkCssChange +gtk_css_selector_id_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkCssChange change, previous_change; + + if (!_gtk_css_matcher_has_id (matcher, tree->selector.data)) + return 0; + + change = 0; + + if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET) + change |= GTK_CSS_CHANGE_ID | GTK_CSS_CHANGE_GOT_MATCH; + + previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher); + + if (previous_change != 0) + change |= previous_change | GTK_CSS_CHANGE_ID | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + static GtkCssChange gtk_css_selector_id_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) { @@ -782,6 +1057,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ID = { gtk_css_selector_id_match, gtk_css_selector_id_tree_match, gtk_css_selector_id_get_change, + gtk_css_selector_id_tree_get_change, gtk_css_selector_id_compare_one, TRUE, FALSE, FALSE, TRUE, FALSE }; @@ -849,6 +1125,28 @@ gtk_css_selector_pseudoclass_state_tree_match (const GtkCssSelectorTree *tree, gtk_css_selector_tree_match (prev, matcher, res); } +static GtkCssChange +gtk_css_selector_pseudoclass_state_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkStateFlags state = GPOINTER_TO_UINT (tree->selector.data); + GtkCssChange change, previous_change; + + if ((_gtk_css_matcher_get_state (matcher) & state) != state) + return 0; + + change = 0; + + if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET) + change |= GTK_CSS_CHANGE_STATE | GTK_CSS_CHANGE_GOT_MATCH; + + previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher); + + if (previous_change != 0) + change |= previous_change | GTK_CSS_CHANGE_STATE | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} static GtkCssChange gtk_css_selector_pseudoclass_state_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) @@ -869,6 +1167,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_PSEUDOCLASS_STATE = { gtk_css_selector_pseudoclass_state_match, gtk_css_selector_pseudoclass_state_tree_match, gtk_css_selector_pseudoclass_state_get_change, + gtk_css_selector_pseudoclass_state_tree_get_change, gtk_css_selector_pseudoclass_state_compare_one, FALSE, TRUE, FALSE, TRUE, FALSE }; @@ -1176,6 +1475,77 @@ gtk_css_selector_pseudoclass_position_tree_match (const GtkCssSelectorTree *tree } } +static GtkCssChange +gtk_css_selector_pseudoclass_position_tree_get_change_for_region (const GtkCssSelectorTree *tree, + const GtkCssSelectorTree *prev, + const GtkCssMatcher *matcher) +{ + const GtkCssSelectorTree *prev2; + GtkRegionFlags selector_flags; + GtkCssChange change, previous_change; + + if (!get_selector_flags_for_position_region_match (&tree->selector, &selector_flags)) + return 0; + + if (!_gtk_css_matcher_has_region (matcher, prev->selector.data, selector_flags)) + return 0; + + change = 0; + if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET) + change |= GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_GOT_MATCH; + + previous_change = 0; + for (prev2 = gtk_css_selector_tree_get_previous (prev); + prev2 != NULL; + prev2 = gtk_css_selector_tree_get_sibling (prev2)) + { + if (prev2->selector.class == >K_CSS_SELECTOR_DESCENDANT) + previous_change |= gtk_css_selector_tree_get_change (gtk_css_selector_tree_get_previous (prev2), matcher); + previous_change |= gtk_css_selector_tree_get_change (prev2, matcher); + } + + if (previous_change != 0) + change |= previous_change | GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + +static GtkCssChange +gtk_css_selector_pseudoclass_position_tree_get_change (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + const GtkCssSelectorTree *prev; + GtkCssChange change, previous_change; + + change = 0; + + for (prev = gtk_css_selector_tree_get_previous (tree); + prev != NULL; + prev = gtk_css_selector_tree_get_sibling (prev)) + { + if (prev->selector.class == >K_CSS_SELECTOR_REGION) + change |= gtk_css_selector_pseudoclass_position_tree_get_change_for_region (tree, prev, matcher); + } + + if (!get_position_match (&tree->selector, matcher)) + return change; + + if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET) + change |= GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_GOT_MATCH; + + previous_change = 0; + for (prev = gtk_css_selector_tree_get_previous (tree); prev != NULL; prev = gtk_css_selector_tree_get_sibling (prev)) + { + if (prev->selector.class != >K_CSS_SELECTOR_REGION) + previous_change |= gtk_css_selector_tree_get_change (prev, matcher); + } + + if (previous_change != 0) + change |= previous_change | GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_GOT_MATCH; + + return change; +} + static GtkCssChange gtk_css_selector_pseudoclass_position_get_change (const GtkCssSelector *selector, GtkCssChange previous_change) { @@ -1195,6 +1565,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION = { gtk_css_selector_pseudoclass_position_match, gtk_css_selector_pseudoclass_position_tree_match, gtk_css_selector_pseudoclass_position_get_change, + gtk_css_selector_pseudoclass_position_tree_get_change, gtk_css_selector_pseudoclass_position_compare_one, FALSE, TRUE, FALSE, TRUE, TRUE }; @@ -1765,6 +2136,22 @@ _gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree, return array; } +GtkCssChange +_gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher) +{ + GtkCssChange change; + + change = 0; + + for (; tree != NULL; + tree = gtk_css_selector_tree_get_sibling (tree)) + change |= gtk_css_selector_tree_get_change (tree, matcher); + + /* Never return reserved bit set */ + return change & ~GTK_CSS_CHANGE_RESERVED_BIT; +} + #ifdef PRINT_TREE static void _gtk_css_selector_tree_print (GtkCssSelectorTree *tree, GString *str, char *prefix) diff --git a/gtk/gtkcssselectorprivate.h b/gtk/gtkcssselectorprivate.h index cc7ec4b48f..17e3618d5f 100644 --- a/gtk/gtkcssselectorprivate.h +++ b/gtk/gtkcssselectorprivate.h @@ -42,6 +42,8 @@ int _gtk_css_selector_compare (const GtkCssSelector *a, void _gtk_css_selector_tree_free (GtkCssSelectorTree *tree); GPtrArray * _gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree, const GtkCssMatcher *matcher); +GtkCssChange _gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree, + const GtkCssMatcher *matcher); void _gtk_css_selector_tree_match_print (const GtkCssSelectorTree *tree, GString *str); GtkCssChange _gtk_css_selector_tree_match_get_change (const GtkCssSelectorTree *tree); diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h index d792c3c03d..9c1f92ba2b 100644 --- a/gtk/gtkcsstypesprivate.h +++ b/gtk/gtkcsstypesprivate.h @@ -50,7 +50,9 @@ typedef enum { /*< skip >*/ /* add more */ GTK_CSS_CHANGE_SOURCE = (1 << 16), GTK_CSS_CHANGE_ANIMATE = (1 << 17), - GTK_CSS_CHANGE_FORCE_INVALIDATE = (1 << 18) + GTK_CSS_CHANGE_FORCE_INVALIDATE = (1 << 18), + + GTK_CSS_CHANGE_RESERVED_BIT = (1 << 31) /* Used internally in gtkcssselector.c */ } GtkCssChange; #define GTK_CSS_CHANGE_ANY ((1 << 19) - 1)