diff --git a/components/selectors/context.rs b/components/selectors/context.rs index 75abfea9f18..f61823a626d 100644 --- a/components/selectors/context.rs +++ b/components/selectors/context.rs @@ -127,6 +127,9 @@ where /// MatchingContext immutable again. nesting_level: usize, + /// Whether we're inside a negation or not. + in_negation: bool, + /// An optional hook function for checking whether a pseudo-element /// should match when matching_mode is ForStatelessPseudoElement. 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(), scope_element: None, nesting_level: 0, + in_negation: false, pseudo_element_matching_fn: None, extra_data: Default::default(), _impl: ::std::marker::PhantomData, @@ -188,6 +192,12 @@ where 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. #[inline] pub fn quirks_mode(&self) -> QuirksMode { @@ -212,6 +222,23 @@ where 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(&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] pub fn visited_handling(&self) -> VisitedHandlingMode { self.visited_handling diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index 6b1fae8cc32..d52b51d7270 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -625,6 +625,8 @@ where E: Element, F: FnMut(&E, ElementSelectorFlags), { + debug_assert!(context.shared.is_nested() || !context.shared.in_negation()); + match *selector { Component::Combinator(_) => unreachable!(), Component::Slotted(ref selector) => { @@ -777,7 +779,7 @@ where matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter) } Component::Negation(ref negated) => { - context.shared.nest(|context| { + context.shared.nest_for_negation(|context| { let mut local_context = LocalMatchingContext { matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No, shared: context, diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index cdfd8258536..de4855c4ed4 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -2111,7 +2111,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { NonTSPseudoClass::MozWindowInactive => { let state_bit = DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE; if context.extra_data.document_state.intersects(state_bit) { - return true; + return !context.in_negation(); } 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) { // NOTE(emilio): We could still return false for // Direction::Other(..), but we don't bother. - return true; + return !context.in_negation(); } let doc_is_rtl = self.document_state().contains(state_bit);