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.
This commit is contained in:
Matthias Clasen
2020-01-17 14:38:31 -05:00
parent a463dccd81
commit 79afff410a
2 changed files with 80 additions and 36 deletions

View File

@@ -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.

View File

@@ -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 GtkCssChange
gtk_css_selector_tree_collect_change (const GtkCssSelectorTree *tree)
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_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 (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);
change |= change2;
}
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;
{
*ret |= tree->selector.class->get_change (&tree->selector, change & ~GTK_CSS_CHANGE_GOT_MATCH) | GTK_CSS_CHANGE_GOT_MATCH;
}
return change;
}
gboolean
_gtk_css_selector_tree_is_empty (const GtkCssSelectorTree *tree)
{
return tree == NULL;
return FALSE;
}
GtkCssChange
_gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
{
GtkCssChange change;
GtkCssChange change = 0;
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