selectors: Add a MatchingContext::nest function, make nesting_level private.

This commit is contained in:
Emilio Cobos Álvarez 2018-01-19 12:40:17 +01:00
parent 88d2982e23
commit e4f08ee2bb
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
4 changed files with 52 additions and 33 deletions

View file

@ -122,9 +122,9 @@ where
/// The current nesting level of selectors that we're matching. /// The current nesting level of selectors that we're matching.
/// ///
/// FIXME(emilio): Move this somewhere else and make MatchingContext /// FIXME(emilio): Consider putting the mutable stuff in a Cell.
/// immutable again. /// immutable again.
pub nesting_level: usize, nesting_level: usize,
/// An optional hook function for checking whether a pseudo-element /// An optional hook function for checking whether a pseudo-element
/// should match when matching_mode is ForStatelessPseudoElement. /// should match when matching_mode is ForStatelessPseudoElement.
@ -181,6 +181,12 @@ where
} }
} }
/// How many times deep are we in a selector.
#[inline]
pub fn nesting_level(&self) -> usize {
self.nesting_level
}
/// The quirks mode of the document. /// The quirks mode of the document.
#[inline] #[inline]
pub fn quirks_mode(&self) -> QuirksMode { pub fn quirks_mode(&self) -> QuirksMode {
@ -192,4 +198,16 @@ where
pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity { pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity {
self.classes_and_ids_case_sensitivity self.classes_and_ids_case_sensitivity
} }
/// Runs F with a deeper nesting level.
#[inline]
pub fn nest<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
self.nesting_level += 1;
let result = f(self);
self.nesting_level -= 1;
result
}
} }

View file

@ -289,7 +289,7 @@ where
// If this is the special pseudo-element mode, consume the ::pseudo-element // If this is the special pseudo-element mode, consume the ::pseudo-element
// before proceeding, since the caller has already handled that part. // before proceeding, since the caller has already handled that part.
if context.matching_mode == MatchingMode::ForStatelessPseudoElement && if context.matching_mode == MatchingMode::ForStatelessPseudoElement &&
context.nesting_level == 0 { context.nesting_level() == 0 {
// Consume the pseudo. // Consume the pseudo.
match *iter.next().unwrap() { match *iter.next().unwrap() {
Component::PseudoElement(ref pseudo) => { Component::PseudoElement(ref pseudo) => {
@ -347,7 +347,7 @@ fn matches_hover_and_active_quirk<Impl: SelectorImpl>(
return MatchesHoverAndActiveQuirk::No; return MatchesHoverAndActiveQuirk::No;
} }
if context.nesting_level != 0 { if context.nesting_level() != 0 {
return MatchesHoverAndActiveQuirk::No; return MatchesHoverAndActiveQuirk::No;
} }
@ -639,17 +639,15 @@ where
match *selector { match *selector {
Component::Combinator(_) => unreachable!(), Component::Combinator(_) => unreachable!(),
Component::Slotted(ref selector) => { Component::Slotted(ref selector) => {
context.shared.nesting_level += 1; context.shared.nest(|context| {
let result =
element.assigned_slot().is_some() && element.assigned_slot().is_some() &&
matches_complex_selector( matches_complex_selector(
selector.iter(), selector.iter(),
element, element,
context.shared, context,
flags_setter, flags_setter,
); )
context.shared.nesting_level -= 1; })
result
} }
Component::PseudoElement(ref pseudo) => { Component::PseudoElement(ref pseudo) => {
element.match_pseudo_element(pseudo, context.shared) element.match_pseudo_element(pseudo, context.shared)
@ -731,7 +729,7 @@ where
} }
Component::NonTSPseudoClass(ref pc) => { Component::NonTSPseudoClass(ref pc) => {
if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes && if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes &&
context.shared.nesting_level == 0 && context.shared.nesting_level() == 0 &&
E::Impl::is_active_or_hover(pc) && E::Impl::is_active_or_hover(pc) &&
!element.is_link() { !element.is_link() {
return false; return false;
@ -790,17 +788,22 @@ where
matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter) matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter)
} }
Component::Negation(ref negated) => { Component::Negation(ref negated) => {
context.shared.nesting_level += 1; let visited_handling = context.visited_handling;
let result = !negated.iter().all(|ss| { context.shared.nest(|context| {
matches_simple_selector( let mut local_context = LocalMatchingContext {
ss, visited_handling,
element, matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No,
context, shared: context,
flags_setter, };
) !negated.iter().all(|ss| {
}); matches_simple_selector(
context.shared.nesting_level -= 1; ss,
result element,
&mut local_context,
flags_setter,
)
})
})
} }
} }
} }

View file

@ -2119,12 +2119,11 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
} }
NonTSPseudoClass::MozPlaceholder => false, NonTSPseudoClass::MozPlaceholder => false,
NonTSPseudoClass::MozAny(ref sels) => { NonTSPseudoClass::MozAny(ref sels) => {
context.nesting_level += 1; context.nest(|context| {
let result = sels.iter().any(|s| { sels.iter().any(|s| {
matches_complex_selector(s.iter(), self, context, flags_setter) matches_complex_selector(s.iter(), self, context, flags_setter)
}); })
context.nesting_level -= 1; })
result
} }
NonTSPseudoClass::Lang(ref lang_arg) => { NonTSPseudoClass::Lang(ref lang_arg) => {
self.match_element_lang(None, lang_arg) self.match_element_lang(None, lang_arg)

View file

@ -162,12 +162,11 @@ impl<'a, E> Element for ElementWrapper<'a, E>
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
NonTSPseudoClass::MozAny(ref selectors) => { NonTSPseudoClass::MozAny(ref selectors) => {
use selectors::matching::matches_complex_selector; use selectors::matching::matches_complex_selector;
context.nesting_level += 1; return context.nest(|context| {
let result = selectors.iter().any(|s| { selectors.iter().any(|s| {
matches_complex_selector(s.iter(), self, context, _setter) matches_complex_selector(s.iter(), self, context, _setter)
})
}); });
context.nesting_level -= 1;
return result
} }
// :dir is implemented in terms of state flags, but which state flag // :dir is implemented in terms of state flags, but which state flag