style: Handle correctly document state invalidation inside negation.

This commit is contained in:
Emilio Cobos Álvarez 2018-01-18 14:47:30 +01:00
parent bccb757bcd
commit e74fad6259
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
3 changed files with 32 additions and 3 deletions

View file

@ -127,6 +127,9 @@ where
/// MatchingContext immutable again. /// MatchingContext immutable again.
nesting_level: usize, nesting_level: usize,
/// Whether we're inside a negation or not.
in_negation: bool,
/// 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.
pub pseudo_element_matching_fn: Option<&'a Fn(&Impl::PseudoElement) -> bool>, pub pseudo_element_matching_fn: Option<&'a Fn(&Impl::PseudoElement) -> bool>,
@ -176,6 +179,7 @@ where
classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(), classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
scope_element: None, scope_element: None,
nesting_level: 0, nesting_level: 0,
in_negation: false,
pseudo_element_matching_fn: None, pseudo_element_matching_fn: None,
extra_data: Default::default(), extra_data: Default::default(),
_impl: ::std::marker::PhantomData, _impl: ::std::marker::PhantomData,
@ -188,6 +192,12 @@ where
self.nesting_level != 0 self.nesting_level != 0
} }
/// Whether we're matching inside a :not(..) selector.
#[inline]
pub fn in_negation(&self) -> bool {
self.in_negation
}
/// 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 {
@ -212,6 +222,23 @@ where
result result
} }
/// Runs F with a deeper nesting level, and marking ourselves in a negation,
/// for a :not(..) selector, for example.
#[inline]
pub fn nest_for_negation<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
debug_assert!(
!self.in_negation,
"Someone messed up parsing?"
);
self.in_negation = true;
let result = self.nest(f);
self.in_negation = false;
result
}
#[inline] #[inline]
pub fn visited_handling(&self) -> VisitedHandlingMode { pub fn visited_handling(&self) -> VisitedHandlingMode {
self.visited_handling self.visited_handling

View file

@ -625,6 +625,8 @@ where
E: Element, E: Element,
F: FnMut(&E, ElementSelectorFlags), F: FnMut(&E, ElementSelectorFlags),
{ {
debug_assert!(context.shared.is_nested() || !context.shared.in_negation());
match *selector { match *selector {
Component::Combinator(_) => unreachable!(), Component::Combinator(_) => unreachable!(),
Component::Slotted(ref selector) => { Component::Slotted(ref selector) => {
@ -777,7 +779,7 @@ 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.nest(|context| { context.shared.nest_for_negation(|context| {
let mut local_context = LocalMatchingContext { let mut local_context = LocalMatchingContext {
matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No, matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No,
shared: context, shared: context,

View file

@ -2111,7 +2111,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::MozWindowInactive => { NonTSPseudoClass::MozWindowInactive => {
let state_bit = DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE; let state_bit = DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE;
if context.extra_data.document_state.intersects(state_bit) { if context.extra_data.document_state.intersects(state_bit) {
return true; return !context.in_negation();
} }
self.document_state().contains(state_bit) self.document_state().contains(state_bit)
@ -2132,7 +2132,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
if context.extra_data.document_state.intersects(state_bit) { if context.extra_data.document_state.intersects(state_bit) {
// NOTE(emilio): We could still return false for // NOTE(emilio): We could still return false for
// Direction::Other(..), but we don't bother. // Direction::Other(..), but we don't bother.
return true; return !context.in_negation();
} }
let doc_is_rtl = self.document_state().contains(state_bit); let doc_is_rtl = self.document_state().contains(state_bit);