style: Record attribute dependencies within the selector list of :nth-child(... of <selector list>)

There are separate filters for IDs, classes, attribute local names, and
element state.

Also, we invalidate siblings of elements matched against the selector
list of :nth-child(... of <selector list>) by marking matched elements
with NODE_HAS_SLOW_SELECTOR_NTH_OF.

The only remaining invalidation case invalidation case is
`:nth-child(An+B of :has())` (bug 1818155), which should not block
shipping `layout.css.nth-child-of.enabled`, because :has(...) is still
being implemented (bug 418039).

Depends on D172352

Differential Revision: https://phabricator.services.mozilla.com/D171936
This commit is contained in:
Zach Hoffman 2023-03-15 06:56:21 +00:00 committed by Martin Robinson
parent c7f8845665
commit 356e886d26
7 changed files with 261 additions and 28 deletions

View file

@ -38,14 +38,24 @@ bitflags! {
/// :first-of-type, or :nth-of-type.
const HAS_SLOW_SELECTOR_LATER_SIBLINGS = 1 << 1;
/// When a DOM mutation occurs on a child that might be matched by
/// :nth-last-child(.. of <selector list>), earlier children must be
/// restyled, and HAS_SLOW_SELECTOR will be set (which normally
/// indicates that all children will be restyled).
///
/// Similarly, when a DOM mutation occurs on a child that might be
/// matched by :nth-child(.. of <selector list>), later children must be
/// restyled, and HAS_SLOW_SELECTOR_LATER_SIBLINGS will be set.
const HAS_SLOW_SELECTOR_NTH_OF = 1 << 2;
/// When a child is added or removed from the parent, the first and
/// last children must be restyled, because they may match :first-child,
/// :last-child, or :only-child.
const HAS_EDGE_CHILD_SELECTOR = 1 << 2;
const HAS_EDGE_CHILD_SELECTOR = 1 << 3;
/// The element has an empty selector, so when a child is appended we
/// might need to restyle the parent completely.
const HAS_EMPTY_SELECTOR = 1 << 3;
const HAS_EMPTY_SELECTOR = 1 << 4;
}
}
@ -59,6 +69,7 @@ impl ElementSelectorFlags {
pub fn for_parent(self) -> ElementSelectorFlags {
self & (ElementSelectorFlags::HAS_SLOW_SELECTOR |
ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS |
ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF |
ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR)
}
}
@ -939,13 +950,17 @@ where
let is_edge_child_selector = a == 0 && b == 1 && !is_of_type && selectors.is_empty();
if context.needs_selector_flags() {
element.apply_selector_flags(if is_edge_child_selector {
let mut flags = if is_edge_child_selector {
ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR
} else if is_from_end {
ElementSelectorFlags::HAS_SLOW_SELECTOR
} else {
ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
});
};
if !selectors.is_empty() {
flags |= ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF;
}
element.apply_selector_flags(flags);
}
if !selectors.is_empty() && !list_matches_complex_selector(selectors, element, context) {