mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
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:
parent
653245c94e
commit
a21762fc5b
1 changed files with 22 additions and 35 deletions
|
@ -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),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue