LibWeb/CSS: Reject invalid :has() contents after absolutizing nesting
After we absolutize the contents of :has(), we check that those child selectors don't contain anything that :has() rejects. This is a separate path than the checks inside the parser, which is unfortunate. Fixes a WPT ref test. :^)
This commit is contained in:
parent
da31c10ce1
commit
3a71b8cda3
Notes:
github-actions[bot]
2024-11-14 19:08:17 +00:00
Author: https://github.com/AtkinsSJ Commit: https://github.com/LadybirdBrowser/ladybird/commit/3a71b8cda36 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2340
2 changed files with 38 additions and 1 deletions
|
@ -624,6 +624,33 @@ Optional<Selector::CompoundSelector> Selector::CompoundSelector::absolutized(Sel
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool contains_invalid_contents_for_has(Selector const& selector)
|
||||||
|
{
|
||||||
|
// :has() has special validity rules:
|
||||||
|
// - It can't appear inside itself
|
||||||
|
// - It bans most pseudo-elements
|
||||||
|
// https://drafts.csswg.org/selectors/#relational
|
||||||
|
|
||||||
|
for (auto const& compound_selector : selector.compound_selectors()) {
|
||||||
|
for (auto const& simple_selector : compound_selector.simple_selectors) {
|
||||||
|
if (simple_selector.type == Selector::SimpleSelector::Type::PseudoElement) {
|
||||||
|
if (!is_has_allowed_pseudo_element(simple_selector.pseudo_element().type()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (simple_selector.type == Selector::SimpleSelector::Type::PseudoClass) {
|
||||||
|
if (simple_selector.pseudo_class().type == PseudoClass::Has)
|
||||||
|
return true;
|
||||||
|
for (auto& child_selector : simple_selector.pseudo_class().argument_selector_list) {
|
||||||
|
if (contains_invalid_contents_for_has(*child_selector))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Optional<Selector::SimpleSelector> Selector::SimpleSelector::absolutized(Selector::SimpleSelector const& selector_for_nesting) const
|
Optional<Selector::SimpleSelector> Selector::SimpleSelector::absolutized(Selector::SimpleSelector const& selector_for_nesting) const
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -647,6 +674,17 @@ Optional<Selector::SimpleSelector> Selector::SimpleSelector::absolutized(Selecto
|
||||||
}
|
}
|
||||||
pseudo_class.argument_selector_list = move(new_selector_list);
|
pseudo_class.argument_selector_list = move(new_selector_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// :has() has special validity rules
|
||||||
|
if (pseudo_class.type == PseudoClass::Has) {
|
||||||
|
for (auto const& selector : pseudo_class.argument_selector_list) {
|
||||||
|
if (contains_invalid_contents_for_has(selector)) {
|
||||||
|
dbgln_if(CSS_PARSER_DEBUG, "After absolutizing, :has() would contain invalid contents; rejecting");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SimpleSelector {
|
return SimpleSelector {
|
||||||
.type = Type::PseudoClass,
|
.type = Type::PseudoClass,
|
||||||
.value = move(pseudo_class),
|
.value = move(pseudo_class),
|
||||||
|
|
|
@ -59,7 +59,6 @@ Text/input/wpt-import/html/infrastructure/safe-passing-of-structured-data/resour
|
||||||
Text/input/wpt-import/css/css-flexbox/flex-item-compressible-001.html
|
Text/input/wpt-import/css/css-flexbox/flex-item-compressible-001.html
|
||||||
|
|
||||||
; WPT ref-tests that currently fail
|
; WPT ref-tests that currently fail
|
||||||
Ref/input/wpt-import/css/css-nesting/has-nesting.html
|
|
||||||
Ref/input/wpt-import/css/css-nesting/host-nesting-003.html
|
Ref/input/wpt-import/css/css-nesting/host-nesting-003.html
|
||||||
Ref/input/wpt-import/css/css-nesting/host-nesting-004.html
|
Ref/input/wpt-import/css/css-nesting/host-nesting-004.html
|
||||||
Ref/input/wpt-import/css/CSS2/floats/floats-wrap-top-below-bfc-002r.xht
|
Ref/input/wpt-import/css/CSS2/floats/floats-wrap-top-below-bfc-002r.xht
|
||||||
|
|
Loading…
Add table
Reference in a new issue