mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-03 17:21:11 +00:00
cssselector: Handle region flags during parse
When parsing a selector like tab:active We used to create 2 selector objects, one for the region, and one for the pseudoclass. Now, for convenience, we special-case region pseudoclass parsing so that the active flag is added to the region selector. A side effect is that ":nth-child(1)" no longer works for regions. Hopefully people didn't use this but used the saner ":first-child" instead.
This commit is contained in:
parent
272a0083a3
commit
28e80aa40b
@ -83,7 +83,12 @@ union _GtkCssSelector
|
||||
struct {
|
||||
const GtkCssSelectorClass *class;
|
||||
const char *name; /* interned */
|
||||
} id, region;
|
||||
} id;
|
||||
struct {
|
||||
const GtkCssSelectorClass *class;
|
||||
const char *name; /* interned */
|
||||
GtkRegionFlags flags;
|
||||
} region;
|
||||
struct {
|
||||
const GtkCssSelectorClass *class;
|
||||
GQuark style_class;
|
||||
@ -1030,7 +1035,26 @@ static void
|
||||
gtk_css_selector_region_print (const GtkCssSelector *selector,
|
||||
GString *string)
|
||||
{
|
||||
char *region_names[] = {
|
||||
"even",
|
||||
"odd",
|
||||
"first-child",
|
||||
"last-child",
|
||||
"only-child",
|
||||
"sorted"
|
||||
};
|
||||
guint i;
|
||||
|
||||
g_string_append (string, selector->region.name);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (region_names); i++)
|
||||
{
|
||||
if (selector->region.flags & (1 << i))
|
||||
{
|
||||
g_string_append_c (string, ':');
|
||||
g_string_append (string, region_names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -1039,7 +1063,7 @@ gtk_css_selector_region_match (const GtkCssSelector *selector,
|
||||
{
|
||||
const GtkCssSelector *previous;
|
||||
|
||||
if (!_gtk_css_matcher_has_region (matcher, selector->region.name, 0))
|
||||
if (!_gtk_css_matcher_has_region (matcher, selector->region.name, selector->region.flags))
|
||||
return FALSE;
|
||||
|
||||
previous = gtk_css_selector_previous (selector);
|
||||
@ -1057,7 +1081,7 @@ gtk_css_selector_region_tree_match (const GtkCssSelectorTree *tree,
|
||||
{
|
||||
const GtkCssSelectorTree *prev;
|
||||
|
||||
if (!_gtk_css_matcher_has_region (matcher, tree->selector.region.name, 0))
|
||||
if (!_gtk_css_matcher_has_region (matcher, tree->selector.region.name, tree->selector.region.flags))
|
||||
return;
|
||||
|
||||
gtk_css_selector_tree_found_match (tree, res);
|
||||
@ -1080,7 +1104,7 @@ gtk_css_selector_region_tree_get_change (const GtkCssSelectorTree *tree,
|
||||
const GtkCssSelectorTree *prev;
|
||||
GtkCssChange change, previous_change;
|
||||
|
||||
if (!_gtk_css_matcher_has_region (matcher, tree->selector.region.name, 0))
|
||||
if (!_gtk_css_matcher_has_region (matcher, tree->selector.region.name, tree->selector.region.flags))
|
||||
return 0;
|
||||
|
||||
change = 0;
|
||||
@ -1124,14 +1148,20 @@ gtk_css_selector_region_get_change (const GtkCssSelector *selector, GtkCssChange
|
||||
static guint
|
||||
gtk_css_selector_region_hash_one (const GtkCssSelector *a)
|
||||
{
|
||||
return g_str_hash (a->region.name);
|
||||
return g_str_hash (a->region.name) ^ a->region.flags;
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_css_selector_region_compare_one (const GtkCssSelector *a,
|
||||
const GtkCssSelector *b)
|
||||
{
|
||||
return strcmp (a->region.name, b->region.name);
|
||||
int diff;
|
||||
|
||||
diff = strcmp (a->region.name, b->region.name);
|
||||
if (diff)
|
||||
return diff;
|
||||
|
||||
return a->region.flags - b->region.flags;
|
||||
}
|
||||
|
||||
static const GtkCssSelectorClass GTK_CSS_SELECTOR_REGION = {
|
||||
@ -1352,64 +1382,6 @@ gtk_css_selector_pseudoclass_position_print (const GtkCssSelector *selector,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_selector_flags_for_position_region_match (const GtkCssSelector *selector, GtkRegionFlags *selector_flags)
|
||||
{
|
||||
switch (selector->position.type)
|
||||
{
|
||||
case POSITION_FORWARD:
|
||||
if (selector->position.a == 0 && selector->position.b == 1)
|
||||
*selector_flags = GTK_REGION_FIRST;
|
||||
else if (selector->position.a == 2 && selector->position.b == 0)
|
||||
*selector_flags = GTK_REGION_EVEN;
|
||||
else if (selector->position.a == 2 && selector->position.b == 1)
|
||||
*selector_flags = GTK_REGION_ODD;
|
||||
else
|
||||
return FALSE;
|
||||
break;
|
||||
case POSITION_BACKWARD:
|
||||
if (selector->position.a == 0 && selector->position.b == 1)
|
||||
*selector_flags = GTK_REGION_LAST;
|
||||
else
|
||||
return FALSE;
|
||||
break;
|
||||
case POSITION_ONLY:
|
||||
*selector_flags = GTK_REGION_ONLY;
|
||||
break;
|
||||
case POSITION_SORTED:
|
||||
*selector_flags = GTK_REGION_SORTED;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_selector_pseudoclass_position_match_for_region (const GtkCssSelector *selector,
|
||||
const GtkCssMatcher *matcher)
|
||||
{
|
||||
GtkRegionFlags selector_flags;
|
||||
const GtkCssSelector *previous;
|
||||
|
||||
if (!get_selector_flags_for_position_region_match (selector, &selector_flags))
|
||||
return FALSE;
|
||||
|
||||
selector = gtk_css_selector_previous (selector);
|
||||
|
||||
if (!_gtk_css_matcher_has_region (matcher, selector->region.name, selector_flags))
|
||||
return FALSE;
|
||||
|
||||
previous = gtk_css_selector_previous (selector);
|
||||
if (previous && previous->class == >K_CSS_SELECTOR_DESCENDANT &&
|
||||
gtk_css_selector_match (gtk_css_selector_previous (previous), matcher))
|
||||
return TRUE;
|
||||
|
||||
return gtk_css_selector_match (previous, matcher);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_position_match (const GtkCssSelector *selector,
|
||||
const GtkCssMatcher *matcher)
|
||||
@ -1443,43 +1415,10 @@ static gboolean
|
||||
gtk_css_selector_pseudoclass_position_match (const GtkCssSelector *selector,
|
||||
const GtkCssMatcher *matcher)
|
||||
{
|
||||
const GtkCssSelector *previous;
|
||||
|
||||
previous = gtk_css_selector_previous (selector);
|
||||
if (previous && previous->class == >K_CSS_SELECTOR_REGION)
|
||||
return gtk_css_selector_pseudoclass_position_match_for_region (selector, matcher);
|
||||
|
||||
if (!get_position_match (selector, matcher))
|
||||
return FALSE;
|
||||
|
||||
return gtk_css_selector_match (previous, matcher);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_selector_pseudoclass_position_tree_match_for_region (const GtkCssSelectorTree *tree,
|
||||
const GtkCssSelectorTree *prev,
|
||||
const GtkCssMatcher *matcher,
|
||||
GHashTable *res)
|
||||
{
|
||||
const GtkCssSelectorTree *prev2;
|
||||
GtkRegionFlags selector_flags;
|
||||
|
||||
if (!get_selector_flags_for_position_region_match (&tree->selector, &selector_flags))
|
||||
return;
|
||||
|
||||
if (!_gtk_css_matcher_has_region (matcher, prev->selector.region.name, selector_flags))
|
||||
return;
|
||||
|
||||
gtk_css_selector_tree_found_match (prev, res);
|
||||
|
||||
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)
|
||||
gtk_css_selector_tree_match (gtk_css_selector_tree_get_previous (prev2), matcher, res);
|
||||
gtk_css_selector_tree_match (prev2, matcher, res);
|
||||
}
|
||||
return gtk_css_selector_match (gtk_css_selector_previous (selector), matcher);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1487,92 +1426,29 @@ gtk_css_selector_pseudoclass_position_tree_match (const GtkCssSelectorTree *tree
|
||||
const GtkCssMatcher *matcher,
|
||||
GHashTable *res)
|
||||
{
|
||||
const GtkCssSelectorTree *prev;
|
||||
|
||||
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)
|
||||
gtk_css_selector_pseudoclass_position_tree_match_for_region (tree, prev, matcher, res);
|
||||
}
|
||||
|
||||
if (!get_position_match (&tree->selector, matcher))
|
||||
return;
|
||||
|
||||
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_sibling (prev))
|
||||
{
|
||||
if (prev->selector.class != >K_CSS_SELECTOR_REGION)
|
||||
gtk_css_selector_tree_match (prev, matcher, res);
|
||||
}
|
||||
}
|
||||
|
||||
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.region.name, 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;
|
||||
gtk_css_selector_tree_match_previous (tree, matcher, res);
|
||||
}
|
||||
|
||||
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;
|
||||
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 (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);
|
||||
}
|
||||
previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher);
|
||||
|
||||
if (previous_change != 0)
|
||||
change |= previous_change | GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_GOT_MATCH;
|
||||
@ -1839,6 +1715,31 @@ parse_selector_pseudo_class_nth_child (GtkCssParser *parser,
|
||||
return selector;
|
||||
}
|
||||
|
||||
static GtkRegionFlags
|
||||
try_parse_selector_region_pseudo_class (GtkCssParser *parser)
|
||||
{
|
||||
static const struct {
|
||||
const char *name;
|
||||
GtkRegionFlags flags;
|
||||
} region_flags[] = {
|
||||
{ "even", GTK_REGION_EVEN },
|
||||
{ "odd", GTK_REGION_ODD },
|
||||
{ "first-child", GTK_REGION_FIRST },
|
||||
{ "last-child", GTK_REGION_LAST },
|
||||
{ "only-child", GTK_REGION_ONLY },
|
||||
{ "sorted", GTK_REGION_SORTED }
|
||||
};
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (region_flags); i++)
|
||||
{
|
||||
if (_gtk_css_parser_try (parser, region_flags[i].name, FALSE))
|
||||
return region_flags[i].flags;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GtkCssSelector *
|
||||
parse_selector_pseudo_class (GtkCssParser *parser,
|
||||
GtkCssSelector *selector,
|
||||
@ -1961,6 +1862,7 @@ parse_simple_selector (GtkCssParser *parser,
|
||||
GtkCssSelector *selector)
|
||||
{
|
||||
gboolean parsed_something = FALSE;
|
||||
guint region_offset = 0;
|
||||
char *name;
|
||||
|
||||
name = _gtk_css_parser_try_ident (parser, FALSE);
|
||||
@ -1971,6 +1873,7 @@ parse_simple_selector (GtkCssParser *parser,
|
||||
selector = gtk_css_selector_new (>K_CSS_SELECTOR_REGION,
|
||||
selector);
|
||||
selector->region.name = g_intern_string (name);
|
||||
region_offset = gtk_css_selector_size (selector);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1995,7 +1898,18 @@ parse_simple_selector (GtkCssParser *parser,
|
||||
else if (_gtk_css_parser_try (parser, ":not(", TRUE))
|
||||
selector = parse_selector_negation (parser, selector);
|
||||
else if (_gtk_css_parser_try (parser, ":", FALSE))
|
||||
selector = parse_selector_pseudo_class (parser, selector, FALSE);
|
||||
{
|
||||
GtkRegionFlags region_flags;
|
||||
if (region_offset &&
|
||||
(region_flags = try_parse_selector_region_pseudo_class (parser)))
|
||||
{
|
||||
selector[gtk_css_selector_size (selector) - region_offset].region.flags |= region_flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
selector = parse_selector_pseudo_class (parser, selector, FALSE);
|
||||
}
|
||||
}
|
||||
else if (!parsed_something)
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected a valid selector");
|
||||
|
Loading…
Reference in New Issue
Block a user