Compare commits

..

3 Commits

Author SHA1 Message Date
Matthias Clasen
9e281fb2b5 Add another css change testcase
This one tests selectors similar to the ones we are using
for linked buttons and entries, involving siblings and
:first-child/:last-child.
2020-01-18 16:30:28 -05:00
Matthias Clasen
ccda2a094f change tests: Update expected results
These are the expected changes: A widget which does
not meet the conditions of a complex selector due
to its parents is no longer marked with various
parent- flags.
2020-01-18 16:30:28 -05:00
Matthias Clasen
79afff410a 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.
2020-01-18 16:30:28 -05:00
10 changed files with 1793 additions and 1816 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

@@ -984,18 +984,6 @@ gtk_css_provider_postprocess (GtkCssProvider *css_provider)
priv->tree = _gtk_css_selector_tree_builder_build (builder);
_gtk_css_selector_tree_builder_free (builder);
#ifndef VERIFY_TREE
for (i = 0; i < priv->rulesets->len; i++)
{
GtkCssRuleset *ruleset;
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
_gtk_css_selector_free (ruleset->selector);
ruleset->selector = NULL;
}
#endif
}
static void

View File

@@ -108,7 +108,6 @@ struct _GtkCssSelectorTree
gint32 parent_offset;
gint32 previous_offset;
gint32 sibling_offset;
gint32 non_name_sibling_offset;
gint32 matches_offset; /* pointers that we return as matches if selector matches */
};
@@ -233,12 +232,6 @@ gtk_css_selector_tree_get_sibling (const GtkCssSelectorTree *tree)
return gtk_css_selector_tree_at_offset (tree, tree->sibling_offset);
}
static const GtkCssSelectorTree *
gtk_css_selector_tree_get_sibling2 (const GtkCssSelectorTree *tree, gboolean skip_names)
{
return gtk_css_selector_tree_at_offset (tree, skip_names ? tree->non_name_sibling_offset: tree->sibling_offset);
}
/* DEFAULTS */
static void
@@ -323,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 */
@@ -365,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 */
@@ -412,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 */
@@ -454,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 */
@@ -733,30 +726,31 @@ comp_pseudoclass_state (const GtkCssSelector *a,
return a->state.state - b->state.state;
}
static GtkCssChange
change_pseudoclass_state (const GtkCssSelector *selector)
{
GtkStateFlags states = selector->state.state;
GtkCssChange change = 0;
#define GTK_CSS_CHANGE_PSEUDOCLASS_HOVER GTK_CSS_CHANGE_HOVER
DEFINE_SIMPLE_SELECTOR(pseudoclass_hover, PSEUDOCLASS_HOVER, print_pseudoclass_state,
match_pseudoclass_state, hash_pseudoclass_state, comp_pseudoclass_state,
FALSE, TRUE, FALSE, TRUE)
#undef GTK_CSS_CHANGE_PSEUDOCLASS_HOVER
if (states & GTK_STATE_FLAG_PRELIGHT)
change |= GTK_CSS_CHANGE_HOVER;
if (states & GTK_STATE_FLAG_INSENSITIVE)
change |= GTK_CSS_CHANGE_DISABLED;
if (states & GTK_STATE_FLAG_BACKDROP)
change |= GTK_CSS_CHANGE_BACKDROP;
if (states & GTK_STATE_FLAG_SELECTED)
change |= GTK_CSS_CHANGE_SELECTED;
if (states & ~(GTK_STATE_FLAG_PRELIGHT |
GTK_STATE_FLAG_INSENSITIVE |
GTK_STATE_FLAG_BACKDROP |
GTK_STATE_FLAG_SELECTED))
change |= GTK_CSS_CHANGE_STATE;
#define GTK_CSS_CHANGE_PSEUDOCLASS_DISABLED GTK_CSS_CHANGE_DISABLED
DEFINE_SIMPLE_SELECTOR(pseudoclass_disabled, PSEUDOCLASS_DISABLED, print_pseudoclass_state,
match_pseudoclass_state, hash_pseudoclass_state, comp_pseudoclass_state,
FALSE, TRUE, FALSE, TRUE)
#undef GTK_CSS_CHANGE_PSEUDOCLASS_DISABLED
return change;
}
#define GTK_CSS_CHANGE_PSEUDOCLASS_BACKDROP GTK_CSS_CHANGE_BACKDROP
DEFINE_SIMPLE_SELECTOR(pseudoclass_backdrop, PSEUDOCLASS_BACKDROP, print_pseudoclass_state,
match_pseudoclass_state, hash_pseudoclass_state, comp_pseudoclass_state,
FALSE, TRUE, FALSE, TRUE)
#undef GTK_CSS_CHANGE_PSEUDOCLASS_BACKDROP
#define GTK_CSS_CHANGE_PSEUDOCLASS_STATE change_pseudoclass_state (selector)
#define GTK_CSS_CHANGE_PSEUDOCLASS_SELECTED GTK_CSS_CHANGE_SELECTED
DEFINE_SIMPLE_SELECTOR(pseudoclass_selected, PSEUDOCLASS_SELECTED, print_pseudoclass_state,
match_pseudoclass_state, hash_pseudoclass_state, comp_pseudoclass_state,
FALSE, TRUE, FALSE, TRUE)
#undef GTK_CSS_CHANGE_PSEUDOCLASS_SELECTED
#define GTK_CSS_CHANGE_PSEUDOCLASS_STATE GTK_CSS_CHANGE_STATE
DEFINE_SIMPLE_SELECTOR(pseudoclass_state, PSEUDOCLASS_STATE, print_pseudoclass_state,
match_pseudoclass_state, hash_pseudoclass_state, comp_pseudoclass_state,
FALSE, TRUE, FALSE, TRUE)
@@ -1316,9 +1310,26 @@ gtk_css_selector_parse_selector_pseudo_class (GtkCssParser *parser,
{
if (pseudo_classes[i].state_flag)
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
if (pseudo_classes[i].state_flag == GTK_STATE_FLAG_PRELIGHT)
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_HOVER
: &GTK_CSS_SELECTOR_PSEUDOCLASS_HOVER,
selector);
else if (pseudo_classes[i].state_flag == GTK_STATE_FLAG_INSENSITIVE)
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_DISABLED
: &GTK_CSS_SELECTOR_PSEUDOCLASS_DISABLED,
selector);
else if (pseudo_classes[i].state_flag == GTK_STATE_FLAG_BACKDROP)
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_BACKDROP
: &GTK_CSS_SELECTOR_PSEUDOCLASS_BACKDROP,
selector);
else if (pseudo_classes[i].state_flag == GTK_STATE_FLAG_SELECTED)
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_SELECTED
: &GTK_CSS_SELECTOR_PSEUDOCLASS_SELECTED,
selector);
else
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
: &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
selector);
selector);
selector->state.state = pseudo_classes[i].state_flag;
}
else
@@ -1830,38 +1841,23 @@ gtk_css_selectors_skip_initial_selector (GtkCssSelector *selector, const GtkCssS
return (GtkCssSelector *)gtk_css_selector_previous (selector);
}
typedef struct {
gboolean matched_name;
GPtrArray *matches;
} MatchData;
static gboolean
gtk_css_selector_tree_match_foreach (const GtkCssSelector *selector,
const GtkCssMatcher *matcher,
gpointer res)
{
const GtkCssSelectorTree *tree = (const GtkCssSelectorTree *) selector;
MatchData *data = res;
MatchData level_data;
const GtkCssSelectorTree *prev;
if (!gtk_css_selector_match (selector, matcher))
return FALSE;
if (selector->class == &GTK_CSS_SELECTOR_NAME)
data->matched_name = TRUE;
gtk_css_selector_tree_found_match (tree, &data->matches);
level_data.matched_name = FALSE;
level_data.matches = data->matches;
gtk_css_selector_tree_found_match (tree, res);
for (prev = gtk_css_selector_tree_get_previous (tree);
prev != NULL;
prev = gtk_css_selector_tree_get_sibling2 (prev, level_data.matched_name))
gtk_css_selector_foreach (&prev->selector, matcher, gtk_css_selector_tree_match_foreach, &level_data);
data->matches = level_data.matches;
prev = gtk_css_selector_tree_get_sibling (prev))
gtk_css_selector_foreach (&prev->selector, matcher, gtk_css_selector_tree_match_foreach, res);
return FALSE;
}
@@ -1870,15 +1866,13 @@ GPtrArray *
_gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
{
MatchData data = { FALSE, NULL };
GPtrArray *array = NULL;
for (; tree != NULL;
tree = gtk_css_selector_tree_get_sibling2 (tree, data.matched_name))
{
gtk_css_selector_foreach (&tree->selector, matcher, gtk_css_selector_tree_match_foreach, &data);
}
tree = gtk_css_selector_tree_get_sibling (tree))
gtk_css_selector_foreach (&tree->selector, matcher, gtk_css_selector_tree_match_foreach, &array);
return data.matches;
return array;
}
/* The code for collecting matches assumes that the name, id and classes
@@ -1907,44 +1901,98 @@ 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;
return FALSE;
}
GtkCssChange
_gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
{
GtkCssChange change = 0;
for (; tree != NULL;
tree = gtk_css_selector_tree_get_sibling (tree))
gtk_css_selector_foreach (&tree->selector, matcher, gtk_css_selector_tree_change_foreach, &change);
/* Never return reserved bit set */
return change & ~GTK_CSS_CHANGE_GOT_MATCH;
}
gboolean
@@ -1953,27 +2001,9 @@ _gtk_css_selector_tree_is_empty (const GtkCssSelectorTree *tree)
return tree == NULL;
}
GtkCssChange
_gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
{
GtkCssChange change;
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);
/* Never return reserved bit set */
return change & ~GTK_CSS_CHANGE_RESERVED_BIT;
}
#define PRINT_TREE
#ifdef PRINT_TREE
static void
_gtk_css_selector_tree_print (const GtkCssSelectorTree *tree, GString *str, const char *prefix)
_gtk_css_selector_tree_print (const GtkCssSelectorTree *tree, GString *str, char *prefix)
{
gboolean first = TRUE;
int len, i;
@@ -2174,7 +2204,7 @@ subdivide_infos (GByteArray *array, GList *infos, gint32 parent_offset)
exact_matches = g_ptr_array_new ();
g_ptr_array_add (exact_matches, info->match);
if (info->selector_match != NULL)
*info->selector_match = GUINT_TO_POINTER (tree_offset);
*info->selector_match = GUINT_TO_POINTER (tree_offset);
}
else
matched = g_list_prepend (matched, info);
@@ -2265,33 +2295,6 @@ fixup_offsets (GtkCssSelectorTree *tree, guint8 *data)
}
}
static void
compute_non_name_offsets (GtkCssSelectorTree *tree)
{
GtkCssSelectorTree *current = tree;
for (; tree != NULL;
tree = (GtkCssSelectorTree *)gtk_css_selector_tree_get_sibling (tree))
{
compute_non_name_offsets ((GtkCssSelectorTree *)gtk_css_selector_tree_get_previous (tree));
if (tree->selector.class != &GTK_CSS_SELECTOR_NAME)
{
for (; current != tree;
current = (GtkCssSelectorTree *)gtk_css_selector_tree_get_sibling (current))
{
current->non_name_sibling_offset = ((guint8 *)tree - (guint8 *)current);
}
}
}
for (; current != NULL;
current = (GtkCssSelectorTree *)gtk_css_selector_tree_get_sibling (current))
{
current->non_name_sibling_offset = GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET;
}
}
GtkCssSelectorTree *
_gtk_css_selector_tree_builder_build (GtkCssSelectorTreeBuilder *builder)
{
@@ -2314,7 +2317,6 @@ _gtk_css_selector_tree_builder_build (GtkCssSelectorTreeBuilder *builder)
tree = (GtkCssSelectorTree *)data;
fixup_offsets (tree, data);
compute_non_name_offsets (tree);
/* Convert offsets to final pointers */
for (l = builder->infos; l != NULL; l = l->next)

File diff suppressed because it is too large Load Diff

1018
po/hr.po

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,7 @@ test_data = [
'test3.css', 'test3.ui', 'test3.nodes',
'test4.css', 'test4.ui', 'test4.nodes',
'test5.css', 'test5.ui', 'test5.nodes',
'test6.css', 'test6.ui', 'test6.nodes',
]
if get_option('install-tests')

View 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) name|sibling-name
box.horizontal:dir(ltr)
label:dir(ltr) name|sibling-name|parent-name|parent-sibling-name
label:dir(ltr) name|sibling-name
button:dir(ltr)
box.horizontal:dir(ltr)
checkbutton:dir(ltr)

View File

@@ -0,0 +1,19 @@
/* a simplified version of some of the things we do for linked buttons and entries */
box:not(.vertical).linked > button:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
box:not(.vertical).linked > button:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
box:not(.vetical).linked > *:disabled ~ entry:disabled {
border-left-color: red;
}
box:not(.vetical).linked > entry:focus + button {
border-left-color: blue;
}

View File

@@ -0,0 +1,12 @@
window.background:dir(ltr)
decoration:dir(ltr)
box.horizontal.linked:dir(ltr)
button:dir(ltr) name|first-child|last-child|parent-class|parent-name
button:dir(ltr) name|first-child|last-child|sibling-name|sibling-state|parent-class|parent-name
button:dir(ltr) name|first-child|last-child|sibling-name|sibling-state|parent-class|parent-name
box.horizontal.linked:dir(ltr)
entry:dir(ltr)
text:dir(ltr)
undershoot.left:dir(ltr)
undershoot.right:dir(ltr)
button:dir(ltr) name|first-child|last-child|sibling-name|sibling-state|parent-class|parent-name

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="type">popup</property>
<child>
<object class="GtkBox">
<style><class name="linked"/></style>
<child>
<object class="GtkButton"/>
</child>
<child>
<object class="GtkButton"/>
</child>
<child>
<object class="GtkButton"/>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<style><class name="linked"/></style>
<child>
<object class="GtkEntry"/>
</child>
<child>
<object class="GtkButton"/>
</child>
</object>
</child>
</object>
</interface>