LibWeb/CSS: Make non-nested & selector have 0 specificity

If a & simple selector is on a style rule with no parent style rule,
then it behaves like :scope - but notably, :scope provides 1
specificity in the class category, but & is supposed to provide 0.

To solve this, we stop replacing it directly, and just handle the & like
any other simple selector. We know that if the selector engine ever
sees one, it's equivalent to :scope, because the nested ones will have
been replaced with :is() before that point.

This gets us one more subtest pass. :^)
This commit is contained in:
Sam Atkins 2024-11-08 20:34:48 +00:00 committed by Andreas Kling
commit 7a104fef66
Notes: github-actions[bot] 2024-11-09 13:30:26 +00:00
4 changed files with 19 additions and 17 deletions

View file

@ -177,28 +177,25 @@ SelectorList const& CSSStyleRule::absolutized_selectors() const
// "When used in the selector of a nested style rule, the nesting selector represents the elements matched by the parent rule.
// When used in any other context, it represents the same elements as :scope in that context (unless otherwise defined)."
// https://drafts.csswg.org/css-nesting-1/#nest-selector
Selector::SimpleSelector parent_selector;
if (auto const* parent_style_rule = this->parent_style_rule()) {
// TODO: If there's only 1, we don't have to use `:is()` for it
parent_selector = {
Selector::SimpleSelector parent_selector = {
.type = Selector::SimpleSelector::Type::PseudoClass,
.value = Selector::SimpleSelector::PseudoClassSelector {
.type = PseudoClass::Is,
.argument_selector_list = parent_style_rule->absolutized_selectors(),
},
};
SelectorList absolutized_selectors;
for (auto const& selector : selectors())
absolutized_selectors.append(selector->absolutized(parent_selector));
m_cached_absolutized_selectors = move(absolutized_selectors);
} else {
parent_selector = {
.type = Selector::SimpleSelector::Type::PseudoClass,
.value = Selector::SimpleSelector::PseudoClassSelector { .type = PseudoClass::Scope },
};
// NOTE: We can't actually replace & with :scope, because & has to have 0 specificity.
// So we leave it, and treat & like :scope during matching.
m_cached_absolutized_selectors = m_selectors;
}
SelectorList absolutized_selectors;
for (auto const& selector : selectors())
absolutized_selectors.append(selector->absolutized(parent_selector));
m_cached_absolutized_selectors = move(absolutized_selectors);
return m_cached_absolutized_selectors.value();
}