style: Invalidate a bit more aggressively when a pseudo-element matches, in order to also invalidate the cached pseudo-styles on the parent

This should probably be fine. If it becomes a perf issue somehow we can
implement the RESTYLE_PSEUDOS hint or what not.

Differential Revision: https://phabricator.services.mozilla.com/D108338
This commit is contained in:
Oriol Brufau 2023-05-16 10:06:29 +02:00
parent 1be19485bb
commit ed19da405f
2 changed files with 31 additions and 75 deletions

View file

@ -20,10 +20,10 @@ pub trait InvalidationProcessor<'a, E>
where where
E: TElement, E: TElement,
{ {
/// Whether an invalidation that contains only an eager pseudo-element /// Whether an invalidation that contains only a pseudo-element selector
/// selector like ::before or ::after triggers invalidation of the element /// like ::before or ::after triggers invalidation of the element that would
/// that would originate it. /// originate it.
fn invalidates_on_eager_pseudo_element(&self) -> bool { fn invalidates_on_pseudo_element(&self) -> bool {
false false
} }
@ -878,76 +878,32 @@ where
.selector .selector
.combinator_at_parse_order(next_invalidation.offset - 1); .combinator_at_parse_order(next_invalidation.offset - 1);
if matches!(next_combinator, Combinator::PseudoElement) { if matches!(next_combinator, Combinator::PseudoElement) &&
// This will usually be the very next component, except for self.processor.invalidates_on_pseudo_element()
// the fact that we store compound selectors the other way {
// around, so there could also be state pseudo-classes. // We need to invalidate the element whenever pseudos change, for
let pseudo = next_invalidation // two reasons:
.dependency
.selector
.iter_raw_parse_order_from(next_invalidation.offset)
.flat_map(|c| {
if let Component::PseudoElement(ref pseudo) = *c {
return Some(pseudo);
}
// TODO: Would be nice to make this a diagnostic_assert! of
// sorts.
debug_assert!(
c.maybe_allowed_after_pseudo_element(),
"Someone seriously messed up selector parsing: \
{:?} at offset {:?}: {:?}",
next_invalidation.dependency,
next_invalidation.offset,
c,
);
None
})
.next()
.unwrap();
// FIXME(emilio): This is not ideal, and could not be
// accurate if we ever have stateful element-backed eager
// pseudos.
// //
// Ideally, we'd just remove element-backed eager pseudos // * Eager pseudo styles are stored as part of the originating
// altogether, given they work fine without it. Only gotcha // element's computed style.
// is that we wouldn't style them in parallel, which may or
// may not be an issue.
// //
// Also, this could be more fine grained now (perhaps a // * Lazy pseudo-styles might be cached on the originating
// RESTYLE_PSEUDOS hint?). // element's pseudo-style cache.
// //
// Note that we'll also restyle the pseudo-element because // This could be more fine-grained (perhaps with a RESTYLE_PSEUDOS
// it would match this invalidation. // hint?).
if self.processor.invalidates_on_eager_pseudo_element() { //
if pseudo.is_eager() { // Note that we'll also restyle the pseudo-element because it would
invalidated_self = true; // match this invalidation.
} //
// If we start or stop matching some marker rules, and // FIXME: For non-element-backed pseudos this is still not quite
// don't have a marker, then we need to restyle the // correct. For example for ::selection even though we invalidate
// element to potentially create one. // the style properly there's nothing that triggers a repaint
// // necessarily. Though this matches old Gecko behavior, and the
// Same caveats as for other eager pseudos apply, this // ::selection implementation needs to change significantly anyway
// could be more fine-grained. // to implement https://github.com/w3c/csswg-drafts/issues/2474 for
if pseudo.is_marker() && self.element.marker_pseudo_element().is_none() { // example.
invalidated_self = true; invalidated_self = true;
}
// FIXME: ::selection doesn't generate elements, so the
// regular invalidation doesn't work for it. We store
// the cached selection style holding off the originating
// element, so we need to restyle it in order to invalidate
// it. This is still not quite correct, since nothing
// triggers a repaint necessarily, but matches old Gecko
// behavior, and the ::selection implementation needs to
// change significantly anyway to implement
// https://github.com/w3c/csswg-drafts/issues/2474.
if pseudo.is_selection() {
invalidated_self = true;
}
}
} }
debug!( debug!(

View file

@ -158,10 +158,10 @@ impl<'a, 'b: 'a, E: 'a> InvalidationProcessor<'a, E>
where where
E: TElement, E: TElement,
{ {
/// We need to invalidate style on an eager pseudo-element, in order to /// We need to invalidate style on pseudo-elements, in order to process
/// process changes that could otherwise end up in ::before or ::after /// changes that could otherwise end up in ::before or ::after content being
/// content being generated. /// generated, and invalidate lazy pseudo caches.
fn invalidates_on_eager_pseudo_element(&self) -> bool { fn invalidates_on_pseudo_element(&self) -> bool {
true true
} }