LibWeb: Invalidate sibling style for :only-child and :*-of-type

After f7a3f785a8, sibling nodes' styles
were no longer invalidated after a node was removed. This reuses the
flag for `:first-child` and `:last-child` to indicate that a node's
style might be affected by any structural change in its siblings.

Fixes #4631.

Resolves the `:only-child` ACID3 failure as documented in #1231.
This commit is contained in:
Jelle Raaijmakers 2025-05-07 12:27:42 +02:00 committed by Alexander Kalenik
commit c56f7d9cde
Notes: github-actions[bot] 2025-05-07 11:56:29 +00:00
5 changed files with 52 additions and 7 deletions

View file

@ -480,15 +480,18 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
}
case CSS::PseudoClass::FirstChild:
if (context.collect_per_element_selector_involvement_metadata) {
const_cast<DOM::Element&>(element).set_affected_by_first_or_last_child_pseudo_class(true);
const_cast<DOM::Element&>(element).set_affected_by_sibling_position_or_count_pseudo_class(true);
}
return !element.previous_element_sibling();
case CSS::PseudoClass::LastChild:
if (context.collect_per_element_selector_involvement_metadata) {
const_cast<DOM::Element&>(element).set_affected_by_first_or_last_child_pseudo_class(true);
const_cast<DOM::Element&>(element).set_affected_by_sibling_position_or_count_pseudo_class(true);
}
return !element.next_element_sibling();
case CSS::PseudoClass::OnlyChild:
if (context.collect_per_element_selector_involvement_metadata) {
const_cast<DOM::Element&>(element).set_affected_by_sibling_position_or_count_pseudo_class(true);
}
return !(element.previous_element_sibling() || element.next_element_sibling());
case CSS::PseudoClass::Empty: {
if (!element.has_children())
@ -514,10 +517,19 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
case CSS::PseudoClass::Scope:
return scope ? &element == scope : is<HTML::HTMLHtmlElement>(element);
case CSS::PseudoClass::FirstOfType:
if (context.collect_per_element_selector_involvement_metadata) {
const_cast<DOM::Element&>(element).set_affected_by_sibling_position_or_count_pseudo_class(true);
}
return !previous_sibling_with_same_tag_name(element);
case CSS::PseudoClass::LastOfType:
if (context.collect_per_element_selector_involvement_metadata) {
const_cast<DOM::Element&>(element).set_affected_by_sibling_position_or_count_pseudo_class(true);
}
return !next_sibling_with_same_tag_name(element);
case CSS::PseudoClass::OnlyOfType:
if (context.collect_per_element_selector_involvement_metadata) {
const_cast<DOM::Element&>(element).set_affected_by_sibling_position_or_count_pseudo_class(true);
}
return !previous_sibling_with_same_tag_name(element) && !next_sibling_with_same_tag_name(element);
case CSS::PseudoClass::Lang:
return matches_lang_pseudo_class(element, pseudo_class.languages);