style: Compute hover / active quirk state lazily

This makes the inner function much smaller which improves selector-matching
performance very mildly for the benchmarks I've been looking at. Also, this
should help selector matching on quirks mode by only doing this when we
actually find :hover / :active pseudo-classes.

Differential Revision: https://phabricator.services.mozilla.com/D145484
This commit is contained in:
Emilio Cobos Álvarez 2022-05-06 23:52:23 +00:00 committed by Martin Robinson
parent 653245c94e
commit a21762fc5b

View file

@ -63,7 +63,7 @@ impl ElementSelectorFlags {
/// Holds per-compound-selector data. /// Holds per-compound-selector data.
struct LocalMatchingContext<'a, 'b: 'a, Impl: SelectorImpl> { struct LocalMatchingContext<'a, 'b: 'a, Impl: SelectorImpl> {
shared: &'a mut MatchingContext<'b, Impl>, shared: &'a mut MatchingContext<'b, Impl>,
matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk, quirks_data: Option<(Rightmost, SelectorIter<'a, Impl>)>,
} }
#[inline(always)] #[inline(always)]
@ -165,15 +165,6 @@ enum SelectorMatchingResult {
NotMatchedGlobally, NotMatchedGlobally,
} }
/// Whether the :hover and :active quirk applies.
///
/// https://quirks.spec.whatwg.org/#the-active-and-hover-quirk
#[derive(Clone, Copy, Debug, PartialEq)]
enum MatchesHoverAndActiveQuirk {
Yes,
No,
}
/// Matches a selector, fast-rejecting against a bloom filter. /// Matches a selector, fast-rejecting against a bloom filter.
/// ///
/// We accept an offset to allow consumers to represent and match against /// We accept an offset to allow consumers to represent and match against
@ -239,7 +230,7 @@ where
let mut local_context = LocalMatchingContext { let mut local_context = LocalMatchingContext {
shared: context, shared: context,
matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No, quirks_data: None,
}; };
// Find the end of the selector or the next combinator, then match // Find the end of the selector or the next combinator, then match
@ -334,18 +325,20 @@ where
matches!(result, SelectorMatchingResult::Matched) matches!(result, SelectorMatchingResult::Matched)
} }
#[inline] /// Whether the :hover and :active quirk applies.
fn matches_hover_and_active_quirk<Impl: SelectorImpl>( ///
/// https://quirks.spec.whatwg.org/#the-active-and-hover-quirk
fn hover_and_active_quirk_applies<Impl: SelectorImpl>(
selector_iter: &SelectorIter<Impl>, selector_iter: &SelectorIter<Impl>,
context: &MatchingContext<Impl>, context: &MatchingContext<Impl>,
rightmost: Rightmost, rightmost: Rightmost,
) -> MatchesHoverAndActiveQuirk { ) -> bool {
if context.quirks_mode() != QuirksMode::Quirks { if context.quirks_mode() != QuirksMode::Quirks {
return MatchesHoverAndActiveQuirk::No; return false;
} }
if context.is_nested() { if context.is_nested() {
return MatchesHoverAndActiveQuirk::No; return false;
} }
// This compound selector had a pseudo-element to the right that we // This compound selector had a pseudo-element to the right that we
@ -353,10 +346,10 @@ fn matches_hover_and_active_quirk<Impl: SelectorImpl>(
if rightmost == Rightmost::Yes && if rightmost == Rightmost::Yes &&
context.matching_mode() == MatchingMode::ForStatelessPseudoElement context.matching_mode() == MatchingMode::ForStatelessPseudoElement
{ {
return MatchesHoverAndActiveQuirk::No; return false;
} }
let all_match = selector_iter.clone().all(|simple| match *simple { selector_iter.clone().all(|simple| match *simple {
Component::LocalName(_) | Component::LocalName(_) |
Component::AttributeInNoNamespaceExists { .. } | Component::AttributeInNoNamespaceExists { .. } |
Component::AttributeInNoNamespace { .. } | Component::AttributeInNoNamespace { .. } |
@ -378,13 +371,7 @@ fn matches_hover_and_active_quirk<Impl: SelectorImpl>(
Component::OnlyOfType => false, Component::OnlyOfType => false,
Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(), Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(),
_ => true, _ => true,
}); })
if all_match {
MatchesHoverAndActiveQuirk::Yes
} else {
MatchesHoverAndActiveQuirk::No
}
} }
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
@ -596,8 +583,11 @@ fn matches_compound_selector<E>(
where where
E: Element, E: Element,
{ {
let matches_hover_and_active_quirk = let quirks_data = if context.quirks_mode() == QuirksMode::Quirks {
matches_hover_and_active_quirk(&selector_iter, context, rightmost); Some((rightmost, selector_iter.clone()))
} else {
None
};
// Handle some common cases first. // Handle some common cases first.
// We may want to get rid of this at some point if we can make the // We may want to get rid of this at some point if we can make the
@ -629,7 +619,7 @@ where
let mut local_context = LocalMatchingContext { let mut local_context = LocalMatchingContext {
shared: context, shared: context,
matches_hover_and_active_quirk, quirks_data,
}; };
iter::once(selector) iter::once(selector)
.chain(selector_iter) .chain(selector_iter)
@ -775,14 +765,11 @@ where
) )
}, },
Component::NonTSPseudoClass(ref pc) => { Component::NonTSPseudoClass(ref pc) => {
if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes && if let Some((ref rightmost, ref iter)) = context.quirks_data {
!context.shared.is_nested() && if pc.is_active_or_hover() && !element.is_link() && hover_and_active_quirk_applies(iter, context.shared, *rightmost) {
pc.is_active_or_hover() && return false;
!element.is_link() }
{
return false;
} }
element.match_non_ts_pseudo_class(pc, &mut context.shared) element.match_non_ts_pseudo_class(pc, &mut context.shared)
}, },
Component::FirstChild => matches_first_child(element, context.shared), Component::FirstChild => matches_first_child(element, context.shared),