style: Simplify selector flags setup even more

In my investigation for bug 1766439, I am digging into why selector
matching regressed.

It doesn't help that the selector-matching code is instantiated a
gazillion times (so there's a ton of copies of the relevant functions).

This was needed in the past because we had different ways of setting the
selector flags on elements, but I unified that recently and now we only
need to either set them or not. That is the kind of thing that
MatchingContext is really good for, so pass that instead on
MatchingContext creation.

Differential Revision: https://phabricator.services.mozilla.com/D145428
This commit is contained in:
Emilio Cobos Álvarez 2023-08-12 00:26:15 +02:00 committed by Martin Robinson
parent db53845694
commit 4878422c93
14 changed files with 176 additions and 211 deletions

View file

@ -68,6 +68,14 @@ impl VisitedHandlingMode {
} }
} }
/// Whether we need to set selector invalidation flags on elements for this
/// match request.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum NeedsSelectorFlags {
No,
Yes,
}
/// Which quirks mode is this document in. /// Which quirks mode is this document in.
/// ///
/// See: https://quirks.spec.whatwg.org/ /// See: https://quirks.spec.whatwg.org/
@ -140,6 +148,7 @@ where
pub extra_data: Impl::ExtraMatchingData, pub extra_data: Impl::ExtraMatchingData,
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
needs_selector_flags: NeedsSelectorFlags,
classes_and_ids_case_sensitivity: CaseSensitivity, classes_and_ids_case_sensitivity: CaseSensitivity,
_impl: ::std::marker::PhantomData<Impl>, _impl: ::std::marker::PhantomData<Impl>,
} }
@ -154,6 +163,7 @@ where
bloom_filter: Option<&'a BloomFilter>, bloom_filter: Option<&'a BloomFilter>,
nth_index_cache: Option<&'a mut NthIndexCache>, nth_index_cache: Option<&'a mut NthIndexCache>,
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
needs_selector_flags: NeedsSelectorFlags,
) -> Self { ) -> Self {
Self::new_for_visited( Self::new_for_visited(
matching_mode, matching_mode,
@ -161,6 +171,7 @@ where
nth_index_cache, nth_index_cache,
VisitedHandlingMode::AllLinksUnvisited, VisitedHandlingMode::AllLinksUnvisited,
quirks_mode, quirks_mode,
needs_selector_flags,
) )
} }
@ -171,6 +182,7 @@ where
nth_index_cache: Option<&'a mut NthIndexCache>, nth_index_cache: Option<&'a mut NthIndexCache>,
visited_handling: VisitedHandlingMode, visited_handling: VisitedHandlingMode,
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
needs_selector_flags: NeedsSelectorFlags,
) -> Self { ) -> Self {
Self { Self {
matching_mode, matching_mode,
@ -179,6 +191,7 @@ where
nth_index_cache, nth_index_cache,
quirks_mode, quirks_mode,
classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(), classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
needs_selector_flags,
scope_element: None, scope_element: None,
current_host: None, current_host: None,
nesting_level: 0, nesting_level: 0,
@ -213,6 +226,12 @@ where
self.matching_mode self.matching_mode
} }
/// Whether we need to set selector flags.
#[inline]
pub fn needs_selector_flags(&self) -> bool {
self.needs_selector_flags == NeedsSelectorFlags::Yes
}
/// The case-sensitivity for class and ID selectors /// The case-sensitivity for class and ID selectors
#[inline] #[inline]
pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity { pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity {

View file

@ -78,8 +78,7 @@ where
// This is pretty much any(..) but manually inlined because the compiler // This is pretty much any(..) but manually inlined because the compiler
// refuses to do so from querySelector / querySelectorAll. // refuses to do so from querySelector / querySelectorAll.
for selector in &selector_list.0 { for selector in &selector_list.0 {
let matches = matches_selector(selector, 0, None, element, context, &mut |_, _| {}); let matches = matches_selector(selector, 0, None, element, context);
if matches { if matches {
return true; return true;
} }
@ -184,17 +183,15 @@ enum MatchesHoverAndActiveQuirk {
/// unncessary cache miss for cases when we can fast-reject with AncestorHashes /// unncessary cache miss for cases when we can fast-reject with AncestorHashes
/// (which the caller can store inline with the selector pointer). /// (which the caller can store inline with the selector pointer).
#[inline(always)] #[inline(always)]
pub fn matches_selector<E, F>( pub fn matches_selector<E>(
selector: &Selector<E::Impl>, selector: &Selector<E::Impl>,
offset: usize, offset: usize,
hashes: Option<&AncestorHashes>, hashes: Option<&AncestorHashes>,
element: &E, element: &E,
context: &mut MatchingContext<E::Impl>, context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
) -> bool ) -> bool
where where
E: Element, E: Element,
F: FnMut(&E, ElementSelectorFlags),
{ {
// Use the bloom filter to fast-reject. // Use the bloom filter to fast-reject.
if let Some(hashes) = hashes { if let Some(hashes) = hashes {
@ -205,7 +202,7 @@ where
} }
} }
matches_complex_selector(selector.iter_from(offset), element, context, flags_setter) matches_complex_selector(selector.iter_from(offset), element, context)
} }
/// Whether a compound selector matched, and whether it was the rightmost /// Whether a compound selector matched, and whether it was the rightmost
@ -277,7 +274,7 @@ where
); );
for component in iter { for component in iter {
if !matches_simple_selector(component, element, &mut local_context, &mut |_, _| {}) { if !matches_simple_selector(component, element, &mut local_context) {
return CompoundSelectorMatchingResult::NotMatched; return CompoundSelectorMatchingResult::NotMatched;
} }
} }
@ -293,15 +290,13 @@ where
/// Matches a complex selector. /// Matches a complex selector.
#[inline(always)] #[inline(always)]
pub fn matches_complex_selector<E, F>( pub fn matches_complex_selector<E>(
mut iter: SelectorIter<E::Impl>, mut iter: SelectorIter<E::Impl>,
element: &E, element: &E,
context: &mut MatchingContext<E::Impl>, context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
) -> bool ) -> bool
where where
E: Element, E: Element,
F: FnMut(&E, ElementSelectorFlags),
{ {
// 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.
@ -334,7 +329,7 @@ where
} }
let result = let result =
matches_complex_selector_internal(iter, element, context, flags_setter, Rightmost::Yes); matches_complex_selector_internal(iter, element, context, Rightmost::Yes);
matches!(result, SelectorMatchingResult::Matched) matches!(result, SelectorMatchingResult::Matched)
} }
@ -458,16 +453,14 @@ where
} }
} }
fn matches_complex_selector_internal<E, F>( fn matches_complex_selector_internal<E>(
mut selector_iter: SelectorIter<E::Impl>, mut selector_iter: SelectorIter<E::Impl>,
element: &E, element: &E,
context: &mut MatchingContext<E::Impl>, context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
rightmost: Rightmost, rightmost: Rightmost,
) -> SelectorMatchingResult ) -> SelectorMatchingResult
where where
E: Element, E: Element,
F: FnMut(&E, ElementSelectorFlags),
{ {
debug!( debug!(
"Matching complex selector {:?} for {:?}", "Matching complex selector {:?} for {:?}",
@ -478,16 +471,16 @@ where
&mut selector_iter, &mut selector_iter,
element, element,
context, context,
flags_setter,
rightmost, rightmost,
); );
let combinator = selector_iter.next_sequence(); let combinator = selector_iter.next_sequence();
if combinator.map_or(false, |c| c.is_sibling()) { if combinator.map_or(false, |c| c.is_sibling()) {
flags_setter( if context.needs_selector_flags() {
element, element.apply_selector_flags(
ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS, ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
); );
}
} }
if !matches_compound_selector { if !matches_compound_selector {
@ -532,7 +525,6 @@ where
selector_iter.clone(), selector_iter.clone(),
&element, &element,
context, context,
flags_setter,
Rightmost::No, Rightmost::No,
) )
}); });
@ -595,16 +587,14 @@ where
/// Determines whether the given element matches the given compound selector. /// Determines whether the given element matches the given compound selector.
#[inline] #[inline]
fn matches_compound_selector<E, F>( fn matches_compound_selector<E>(
selector_iter: &mut SelectorIter<E::Impl>, selector_iter: &mut SelectorIter<E::Impl>,
element: &E, element: &E,
context: &mut MatchingContext<E::Impl>, context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
rightmost: Rightmost, rightmost: Rightmost,
) -> bool ) -> bool
where where
E: Element, E: Element,
F: FnMut(&E, ElementSelectorFlags),
{ {
let matches_hover_and_active_quirk = let matches_hover_and_active_quirk =
matches_hover_and_active_quirk(&selector_iter, context, rightmost); matches_hover_and_active_quirk(&selector_iter, context, rightmost);
@ -643,19 +633,17 @@ where
}; };
iter::once(selector) iter::once(selector)
.chain(selector_iter) .chain(selector_iter)
.all(|simple| matches_simple_selector(simple, element, &mut local_context, flags_setter)) .all(|simple| matches_simple_selector(simple, element, &mut local_context))
} }
/// Determines whether the given element matches the given single selector. /// Determines whether the given element matches the given single selector.
fn matches_simple_selector<E, F>( fn matches_simple_selector<E>(
selector: &Component<E::Impl>, selector: &Component<E::Impl>,
element: &E, element: &E,
context: &mut LocalMatchingContext<E::Impl>, context: &mut LocalMatchingContext<E::Impl>,
flags_setter: &mut F,
) -> bool ) -> bool
where where
E: Element, E: Element,
F: FnMut(&E, ElementSelectorFlags),
{ {
debug_assert!(context.shared.is_nested() || !context.shared.in_negation()); debug_assert!(context.shared.is_nested() || !context.shared.in_negation());
@ -703,7 +691,7 @@ where
// <slots> are never flattened tree slottables. // <slots> are never flattened tree slottables.
!element.is_html_slot_element() && !element.is_html_slot_element() &&
context.shared.nest(|context| { context.shared.nest(|context| {
matches_complex_selector(selector.iter(), element, context, flags_setter) matches_complex_selector(selector.iter(), element, context)
}) })
}, },
Component::PseudoElement(ref pseudo) => { Component::PseudoElement(ref pseudo) => {
@ -795,16 +783,18 @@ where
return false; return false;
} }
element.match_non_ts_pseudo_class(pc, &mut context.shared, flags_setter) element.match_non_ts_pseudo_class(pc, &mut context.shared)
}, },
Component::FirstChild => matches_first_child(element, flags_setter), Component::FirstChild => matches_first_child(element, context.shared),
Component::LastChild => matches_last_child(element, flags_setter), Component::LastChild => matches_last_child(element, context.shared),
Component::OnlyChild => { Component::OnlyChild => {
matches_first_child(element, flags_setter) && matches_last_child(element, flags_setter) matches_first_child(element, context.shared) && matches_last_child(element, context.shared)
}, },
Component::Root => element.is_root(), Component::Root => element.is_root(),
Component::Empty => { Component::Empty => {
flags_setter(element, ElementSelectorFlags::HAS_EMPTY_SELECTOR); if context.shared.needs_selector_flags() {
element.apply_selector_flags(ElementSelectorFlags::HAS_EMPTY_SELECTOR);
}
element.is_empty() element.is_empty()
}, },
Component::Host(ref selector) => { Component::Host(ref selector) => {
@ -814,7 +804,7 @@ where
.map_or(false, |host| host == element.opaque()) && .map_or(false, |host| host == element.opaque()) &&
selector.as_ref().map_or(true, |selector| { selector.as_ref().map_or(true, |selector| {
context.shared.nest(|context| { context.shared.nest(|context| {
matches_complex_selector(selector.iter(), element, context, flags_setter) matches_complex_selector(selector.iter(), element, context)
}) })
}) })
}, },
@ -823,30 +813,30 @@ where
None => element.is_root(), None => element.is_root(),
}, },
Component::NthChild(a, b) => { Component::NthChild(a, b) => {
matches_generic_nth_child(element, context, a, b, false, false, flags_setter) matches_generic_nth_child(element, context.shared, a, b, false, false)
}, },
Component::NthLastChild(a, b) => { Component::NthLastChild(a, b) => {
matches_generic_nth_child(element, context, a, b, false, true, flags_setter) matches_generic_nth_child(element, context.shared, a, b, false, true)
}, },
Component::NthOfType(a, b) => { Component::NthOfType(a, b) => {
matches_generic_nth_child(element, context, a, b, true, false, flags_setter) matches_generic_nth_child(element, context.shared, a, b, true, false)
}, },
Component::NthLastOfType(a, b) => { Component::NthLastOfType(a, b) => {
matches_generic_nth_child(element, context, a, b, true, true, flags_setter) matches_generic_nth_child(element, context.shared, a, b, true, true)
}, },
Component::FirstOfType => { Component::FirstOfType => {
matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter) matches_generic_nth_child(element, context.shared, 0, 1, true, false)
}, },
Component::LastOfType => { Component::LastOfType => {
matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter) matches_generic_nth_child(element, context.shared, 0, 1, true, true)
}, },
Component::OnlyOfType => { Component::OnlyOfType => {
matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter) && matches_generic_nth_child(element, context.shared, 0, 1, true, false) &&
matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter) matches_generic_nth_child(element, context.shared, 0, 1, true, true)
}, },
Component::Is(ref list) | Component::Where(ref list) => context.shared.nest(|context| { Component::Is(ref list) | Component::Where(ref list) => context.shared.nest(|context| {
for selector in &**list { for selector in &**list {
if matches_complex_selector(selector.iter(), element, context, flags_setter) { if matches_complex_selector(selector.iter(), element, context) {
return true; return true;
} }
} }
@ -854,7 +844,7 @@ where
}), }),
Component::Negation(ref list) => context.shared.nest_for_negation(|context| { Component::Negation(ref list) => context.shared.nest_for_negation(|context| {
for selector in &**list { for selector in &**list {
if matches_complex_selector(selector.iter(), element, context, flags_setter) { if matches_complex_selector(selector.iter(), element, context) {
return false; return false;
} }
} }
@ -873,35 +863,31 @@ fn select_name<'a, T>(is_html: bool, local_name: &'a T, local_name_lower: &'a T)
} }
#[inline] #[inline]
fn matches_generic_nth_child<E, F>( fn matches_generic_nth_child<E>(
element: &E, element: &E,
context: &mut LocalMatchingContext<E::Impl>, context: &mut MatchingContext<E::Impl>,
a: i32, a: i32,
b: i32, b: i32,
is_of_type: bool, is_of_type: bool,
is_from_end: bool, is_from_end: bool,
flags_setter: &mut F,
) -> bool ) -> bool
where where
E: Element, E: Element,
F: FnMut(&E, ElementSelectorFlags),
{ {
if element.ignores_nth_child_selectors() { if element.ignores_nth_child_selectors() {
return false; return false;
} }
flags_setter( if context.needs_selector_flags() {
element, element.apply_selector_flags(if is_from_end {
if is_from_end {
ElementSelectorFlags::HAS_SLOW_SELECTOR ElementSelectorFlags::HAS_SLOW_SELECTOR
} else { } else {
ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
}, });
); }
// Grab a reference to the appropriate cache. // Grab a reference to the appropriate cache.
let mut cache = context let mut cache = context
.shared
.nth_index_cache .nth_index_cache
.as_mut() .as_mut()
.map(|c| c.get(is_of_type, is_from_end)); .map(|c| c.get(is_of_type, is_from_end));
@ -992,21 +978,23 @@ where
} }
#[inline] #[inline]
fn matches_first_child<E, F>(element: &E, flags_setter: &mut F) -> bool fn matches_first_child<E>(element: &E, context: &MatchingContext<E::Impl>) -> bool
where where
E: Element, E: Element,
F: FnMut(&E, ElementSelectorFlags),
{ {
flags_setter(element, ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR); if context.needs_selector_flags() {
element.apply_selector_flags(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR);
}
element.prev_sibling_element().is_none() element.prev_sibling_element().is_none()
} }
#[inline] #[inline]
fn matches_last_child<E, F>(element: &E, flags_setter: &mut F) -> bool fn matches_last_child<E>(element: &E, context: &MatchingContext<E::Impl>) -> bool
where where
E: Element, E: Element,
F: FnMut(&E, ElementSelectorFlags),
{ {
flags_setter(element, ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR); if context.needs_selector_flags() {
element.apply_selector_flags(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR);
}
element.next_sibling_element().is_none() element.next_sibling_element().is_none()
} }

View file

@ -77,14 +77,11 @@ pub trait Element: Sized + Clone + Debug {
operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>, operation: &AttrSelectorOperation<&<Self::Impl as SelectorImpl>::AttrValue>,
) -> bool; ) -> bool;
fn match_non_ts_pseudo_class<F>( fn match_non_ts_pseudo_class(
&self, &self,
pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass, pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
context: &mut MatchingContext<Self::Impl>, context: &mut MatchingContext<Self::Impl>,
flags_setter: &mut F, ) -> bool;
) -> bool
where
F: FnMut(&Self, ElementSelectorFlags);
fn match_pseudo_element( fn match_pseudo_element(
&self, &self,
@ -92,6 +89,30 @@ pub trait Element: Sized + Clone + Debug {
context: &mut MatchingContext<Self::Impl>, context: &mut MatchingContext<Self::Impl>,
) -> bool; ) -> bool;
/// Sets selector flags, which indicate what kinds of selectors may have
/// matched on this element and therefore what kind of work may need to
/// be performed when DOM state changes.
///
/// You probably don't want to use this directly and want to use
/// apply_selector_flags, since that sets flags on the parent as needed.
fn set_selector_flags(&self, flags: ElementSelectorFlags);
fn apply_selector_flags(&self, flags: ElementSelectorFlags) {
// Handle flags that apply to the element.
let self_flags = flags.for_self();
if !self_flags.is_empty() {
self.set_selector_flags(self_flags);
}
// Handle flags that apply to the parent.
let parent_flags = flags.for_parent();
if !parent_flags.is_empty() {
if let Some(p) = self.parent_element() {
p.set_selector_flags(parent_flags);
}
}
}
/// Whether this element is a `link`. /// Whether this element is a `link`.
fn is_link(&self) -> bool; fn is_link(&self) -> bool;

View file

@ -22,7 +22,7 @@ use crate::traversal_flags::TraversalFlags;
use crate::values::AtomIdent; use crate::values::AtomIdent;
use crate::{LocalName, Namespace, WeakAtom}; use crate::{LocalName, Namespace, WeakAtom};
use atomic_refcell::{AtomicRef, AtomicRefMut}; use atomic_refcell::{AtomicRef, AtomicRefMut};
use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode}; use selectors::matching::{QuirksMode, VisitedHandlingMode};
use selectors::sink::Push; use selectors::sink::Push;
use selectors::Element as SelectorsElement; use selectors::Element as SelectorsElement;
use servo_arc::{Arc, ArcBorrow}; use servo_arc::{Arc, ArcBorrow};
@ -734,31 +734,6 @@ pub trait TElement:
/// native anonymous content can opt out of this style fixup.) /// native anonymous content can opt out of this style fixup.)
fn skip_item_display_fixup(&self) -> bool; fn skip_item_display_fixup(&self) -> bool;
/// Sets selector flags, which indicate what kinds of selectors may have
/// matched on this element and therefore what kind of work may need to
/// be performed when DOM state changes.
///
/// You probably don't want to use this directly and want to use
/// apply_selector_flags, since that sets flags on the parent as needed.
fn set_selector_flags(&self, flags: ElementSelectorFlags);
/// Applies selector flags to an element and its parent as needed.
fn apply_selector_flags(&self, flags: ElementSelectorFlags) {
// Handle flags that apply to the element.
let self_flags = flags.for_self();
if !self_flags.is_empty() {
self.set_selector_flags(self_flags);
}
// Handle flags that apply to the parent.
let parent_flags = flags.for_parent();
if !parent_flags.is_empty() {
if let Some(p) = self.parent_element() {
p.set_selector_flags(parent_flags);
}
}
}
/// In Gecko, element has a flag that represents the element may have /// In Gecko, element has a flag that represents the element may have
/// any type of animations or not to bail out animation stuff early. /// any type of animations or not to bail out animation stuff early.
/// Whereas Servo doesn't have such flag. /// Whereas Servo doesn't have such flag.

View file

@ -12,7 +12,7 @@ use crate::invalidation::element::invalidator::{DescendantInvalidationLists, Inv
use crate::invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector}; use crate::invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector};
use crate::values::AtomIdent; use crate::values::AtomIdent;
use selectors::attr::CaseSensitivity; use selectors::attr::CaseSensitivity;
use selectors::matching::{self, MatchingContext, MatchingMode}; use selectors::matching::{self, MatchingContext, MatchingMode, NeedsSelectorFlags};
use selectors::parser::{Combinator, Component, LocalName, SelectorImpl}; use selectors::parser::{Combinator, Component, LocalName, SelectorImpl};
use selectors::{Element, NthIndexCache, SelectorList}; use selectors::{Element, NthIndexCache, SelectorList};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -26,7 +26,13 @@ pub fn element_matches<E>(
where where
E: Element, E: Element,
{ {
let mut context = MatchingContext::new(MatchingMode::Normal, None, None, quirks_mode); let mut context = MatchingContext::new(
MatchingMode::Normal,
None,
None,
quirks_mode,
NeedsSelectorFlags::No,
);
context.scope_element = Some(element.opaque()); context.scope_element = Some(element.opaque());
context.current_host = element.containing_shadow_host().map(|e| e.opaque()); context.current_host = element.containing_shadow_host().map(|e| e.opaque());
matching::matches_selector_list(selector_list, element, &mut context) matching::matches_selector_list(selector_list, element, &mut context)
@ -48,6 +54,7 @@ where
None, None,
Some(&mut nth_index_cache), Some(&mut nth_index_cache),
quirks_mode, quirks_mode,
NeedsSelectorFlags::No,
); );
context.scope_element = Some(element.opaque()); context.scope_element = Some(element.opaque());
context.current_host = element.containing_shadow_host().map(|e| e.opaque()); context.current_host = element.containing_shadow_host().map(|e| e.opaque());
@ -618,8 +625,8 @@ pub fn query_selector<E, Q>(
None, None,
Some(&mut nth_index_cache), Some(&mut nth_index_cache),
quirks_mode, quirks_mode,
NeedsSelectorFlags::No,
); );
let root_element = root.as_element(); let root_element = root.as_element();
matching_context.scope_element = root_element.map(|e| e.opaque()); matching_context.scope_element = root_element.map(|e| e.opaque());
matching_context.current_host = match root_element { matching_context.current_host = match root_element {

View file

@ -1393,11 +1393,6 @@ impl<'le> TElement for GeckoElement<'le> {
self.is_root_of_native_anonymous_subtree() self.is_root_of_native_anonymous_subtree()
} }
fn set_selector_flags(&self, flags: ElementSelectorFlags) {
debug_assert!(!flags.is_empty());
self.set_flags(selector_flags_to_node_flags(flags));
}
#[inline] #[inline]
fn may_have_animations(&self) -> bool { fn may_have_animations(&self) -> bool {
if let Some(pseudo) = self.implemented_pseudo_element() { if let Some(pseudo) = self.implemented_pseudo_element() {
@ -1827,6 +1822,11 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
None None
} }
fn set_selector_flags(&self, flags: ElementSelectorFlags) {
debug_assert!(!flags.is_empty());
self.set_flags(selector_flags_to_node_flags(flags));
}
fn attr_matches( fn attr_matches(
&self, &self,
ns: &NamespaceConstraint<&Namespace>, ns: &NamespaceConstraint<&Namespace>,
@ -1939,15 +1939,11 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
self.local_name() == other.local_name() && self.namespace() == other.namespace() self.local_name() == other.local_name() && self.namespace() == other.namespace()
} }
fn match_non_ts_pseudo_class<F>( fn match_non_ts_pseudo_class(
&self, &self,
pseudo_class: &NonTSPseudoClass, pseudo_class: &NonTSPseudoClass,
context: &mut MatchingContext<Self::Impl>, context: &mut MatchingContext<Self::Impl>,
flags_setter: &mut F, ) -> bool {
) -> bool
where
F: FnMut(&Self, ElementSelectorFlags),
{
use selectors::matching::*; use selectors::matching::*;
match *pseudo_class { match *pseudo_class {
NonTSPseudoClass::Autofill | NonTSPseudoClass::Autofill |
@ -2003,7 +1999,9 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
self.is_link() && context.visited_handling().matches_visited() self.is_link() && context.visited_handling().matches_visited()
}, },
NonTSPseudoClass::MozFirstNode => { NonTSPseudoClass::MozFirstNode => {
flags_setter(self, ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR); if context.needs_selector_flags() {
self.apply_selector_flags(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR);
}
let mut elem = self.as_node(); let mut elem = self.as_node();
while let Some(prev) = elem.prev_sibling() { while let Some(prev) = elem.prev_sibling() {
if prev.contains_non_whitespace_content() { if prev.contains_non_whitespace_content() {
@ -2014,7 +2012,9 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
true true
}, },
NonTSPseudoClass::MozLastNode => { NonTSPseudoClass::MozLastNode => {
flags_setter(self, ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR); if context.needs_selector_flags() {
self.apply_selector_flags(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR);
}
let mut elem = self.as_node(); let mut elem = self.as_node();
while let Some(next) = elem.next_sibling() { while let Some(next) = elem.next_sibling() {
if next.contains_non_whitespace_content() { if next.contains_non_whitespace_content() {
@ -2025,7 +2025,9 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
true true
}, },
NonTSPseudoClass::MozOnlyWhitespace => { NonTSPseudoClass::MozOnlyWhitespace => {
flags_setter(self, ElementSelectorFlags::HAS_EMPTY_SELECTOR); if context.needs_selector_flags() {
self.apply_selector_flags(ElementSelectorFlags::HAS_EMPTY_SELECTOR);
}
if self if self
.as_node() .as_node()
.dom_children() .dom_children()

View file

@ -11,7 +11,7 @@ use crate::invalidation::element::invalidator::{DescendantInvalidationLists, Inv
use crate::invalidation::element::invalidator::{Invalidation, InvalidationProcessor}; use crate::invalidation::element::invalidator::{Invalidation, InvalidationProcessor};
use crate::invalidation::element::state_and_attributes; use crate::invalidation::element::state_and_attributes;
use crate::stylist::CascadeData; use crate::stylist::CascadeData;
use selectors::matching::{MatchingContext, MatchingMode, QuirksMode, VisitedHandlingMode}; use selectors::matching::{MatchingContext, MatchingMode, QuirksMode, VisitedHandlingMode, NeedsSelectorFlags};
/// A struct holding the members necessary to invalidate document state /// A struct holding the members necessary to invalidate document state
/// selectors. /// selectors.
@ -47,6 +47,7 @@ impl<'a, E: TElement, I> DocumentStateInvalidationProcessor<'a, E, I> {
None, None,
VisitedHandlingMode::AllLinksVisitedAndUnvisited, VisitedHandlingMode::AllLinksVisitedAndUnvisited,
quirks_mode, quirks_mode,
NeedsSelectorFlags::No,
); );
matching_context.extra_data = InvalidationMatchingData { matching_context.extra_data = InvalidationMatchingData {

View file

@ -166,15 +166,11 @@ where
{ {
type Impl = SelectorImpl; type Impl = SelectorImpl;
fn match_non_ts_pseudo_class<F>( fn match_non_ts_pseudo_class(
&self, &self,
pseudo_class: &NonTSPseudoClass, pseudo_class: &NonTSPseudoClass,
context: &mut MatchingContext<Self::Impl>, context: &mut MatchingContext<Self::Impl>,
_setter: &mut F, ) -> bool {
) -> bool
where
F: FnMut(&Self, ElementSelectorFlags),
{
// Some pseudo-classes need special handling to evaluate them against // Some pseudo-classes need special handling to evaluate them against
// the snapshot. // the snapshot.
match *pseudo_class { match *pseudo_class {
@ -232,16 +228,20 @@ where
if flag.is_empty() { if flag.is_empty() {
return self return self
.element .element
.match_non_ts_pseudo_class(pseudo_class, context, &mut |_, _| {}); .match_non_ts_pseudo_class(pseudo_class, context);
} }
match self.snapshot().and_then(|s| s.state()) { match self.snapshot().and_then(|s| s.state()) {
Some(snapshot_state) => snapshot_state.intersects(flag), Some(snapshot_state) => snapshot_state.intersects(flag),
None => self None => self
.element .element
.match_non_ts_pseudo_class(pseudo_class, context, &mut |_, _| {}), .match_non_ts_pseudo_class(pseudo_class, context),
} }
} }
fn set_selector_flags(&self, _flags: ElementSelectorFlags) {
debug_assert!(false, "Shouldn't need selector flags for invalidation");
}
fn match_pseudo_element( fn match_pseudo_element(
&self, &self,
pseudo_element: &PseudoElement, pseudo_element: &PseudoElement,

View file

@ -19,8 +19,7 @@ use crate::selector_parser::Snapshot;
use crate::stylesheets::origin::OriginSet; use crate::stylesheets::origin::OriginSet;
use crate::{Atom, WeakAtom}; use crate::{Atom, WeakAtom};
use selectors::attr::CaseSensitivity; use selectors::attr::CaseSensitivity;
use selectors::matching::matches_selector; use selectors::matching::{matches_selector, MatchingContext, MatchingMode, VisitedHandlingMode, NeedsSelectorFlags};
use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode};
use selectors::NthIndexCache; use selectors::NthIndexCache;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -67,6 +66,7 @@ impl<'a, 'b: 'a, E: TElement + 'b> StateAndAttrInvalidationProcessor<'a, 'b, E>
Some(nth_index_cache), Some(nth_index_cache),
VisitedHandlingMode::AllLinksVisitedAndUnvisited, VisitedHandlingMode::AllLinksVisitedAndUnvisited,
shared_context.quirks_mode(), shared_context.quirks_mode(),
NeedsSelectorFlags::No,
); );
Self { Self {
@ -84,7 +84,7 @@ pub fn check_dependency<E, W>(
dependency: &Dependency, dependency: &Dependency,
element: &E, element: &E,
wrapper: &W, wrapper: &W,
mut context: &mut MatchingContext<'_, E::Impl>, context: &mut MatchingContext<'_, E::Impl>,
) -> bool ) -> bool
where where
E: TElement, E: TElement,
@ -95,8 +95,7 @@ where
dependency.selector_offset, dependency.selector_offset,
None, None,
element, element,
&mut context, context,
&mut |_, _| {},
); );
let matched_then = matches_selector( let matched_then = matches_selector(
@ -104,8 +103,7 @@ where
dependency.selector_offset, dependency.selector_offset,
None, None,
wrapper, wrapper,
&mut context, context,
&mut |_, _| {},
); );
matched_then != matches_now matched_then != matches_now

View file

@ -13,7 +13,7 @@ use crate::selector_parser::PseudoElement;
use crate::shared_lock::Locked; use crate::shared_lock::Locked;
use crate::stylesheets::{layer_rule::LayerOrder, Origin}; use crate::stylesheets::{layer_rule::LayerOrder, Origin};
use crate::stylist::{AuthorStylesEnabled, CascadeData, Rule, RuleInclusion, Stylist}; use crate::stylist::{AuthorStylesEnabled, CascadeData, Rule, RuleInclusion, Stylist};
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode}; use selectors::matching::{MatchingContext, MatchingMode};
use servo_arc::ArcBorrow; use servo_arc::ArcBorrow;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -59,7 +59,7 @@ pub fn containing_shadow_ignoring_svg_use<E: TElement>(
/// ///
/// This is done basically to be able to organize the cascade in smaller /// This is done basically to be able to organize the cascade in smaller
/// functions, and be able to reason about it easily. /// functions, and be able to reason about it easily.
pub struct RuleCollector<'a, 'b: 'a, E, F: 'a> pub struct RuleCollector<'a, 'b: 'a, E>
where where
E: TElement, E: TElement,
{ {
@ -73,16 +73,14 @@ where
rule_inclusion: RuleInclusion, rule_inclusion: RuleInclusion,
rules: &'a mut ApplicableDeclarationList, rules: &'a mut ApplicableDeclarationList,
context: &'a mut MatchingContext<'b, E::Impl>, context: &'a mut MatchingContext<'b, E::Impl>,
flags_setter: &'a mut F,
matches_user_and_author_rules: bool, matches_user_and_author_rules: bool,
matches_document_author_rules: bool, matches_document_author_rules: bool,
in_sort_scope: bool, in_sort_scope: bool,
} }
impl<'a, 'b: 'a, E, F: 'a> RuleCollector<'a, 'b, E, F> impl<'a, 'b: 'a, E> RuleCollector<'a, 'b, E>
where where
E: TElement, E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{ {
/// Trivially construct a new collector. /// Trivially construct a new collector.
pub fn new( pub fn new(
@ -95,7 +93,6 @@ where
rule_inclusion: RuleInclusion, rule_inclusion: RuleInclusion,
rules: &'a mut ApplicableDeclarationList, rules: &'a mut ApplicableDeclarationList,
context: &'a mut MatchingContext<'b, E::Impl>, context: &'a mut MatchingContext<'b, E::Impl>,
flags_setter: &'a mut F,
) -> Self { ) -> Self {
// When we're matching with matching_mode = // When we're matching with matching_mode =
// `ForStatelessPseudoeElement`, the "target" for the rule hash is the // `ForStatelessPseudoeElement`, the "target" for the rule hash is the
@ -125,7 +122,6 @@ where
animation_declarations, animation_declarations,
rule_inclusion, rule_inclusion,
context, context,
flags_setter,
rules, rules,
matches_user_and_author_rules, matches_user_and_author_rules,
matches_document_author_rules: matches_user_and_author_rules, matches_document_author_rules: matches_user_and_author_rules,
@ -227,7 +223,6 @@ where
part_rules, part_rules,
&mut self.rules, &mut self.rules,
&mut self.context, &mut self.context,
&mut self.flags_setter,
cascade_level, cascade_level,
cascade_data, cascade_data,
); );
@ -246,7 +241,6 @@ where
self.rule_hash_target, self.rule_hash_target,
&mut self.rules, &mut self.rules,
&mut self.context, &mut self.context,
&mut self.flags_setter,
cascade_level, cascade_level,
cascade_data, cascade_data,
); );

View file

@ -14,7 +14,7 @@ use crate::stylist::{CascadeData, Rule};
use crate::AllocErr; use crate::AllocErr;
use crate::{Atom, LocalName, Namespace, ShrinkIfNeeded, WeakAtom}; use crate::{Atom, LocalName, Namespace, ShrinkIfNeeded, WeakAtom};
use precomputed_hash::PrecomputedHash; use precomputed_hash::PrecomputedHash;
use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext}; use selectors::matching::{matches_selector, MatchingContext};
use selectors::parser::{Combinator, Component, SelectorIter}; use selectors::parser::{Combinator, Component, SelectorIter};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::collections::hash_map; use std::collections::hash_map;
@ -186,18 +186,16 @@ impl SelectorMap<Rule> {
/// ///
/// Extract matching rules as per element's ID, classes, tag name, etc.. /// Extract matching rules as per element's ID, classes, tag name, etc..
/// Sort the Rules at the end to maintain cascading order. /// Sort the Rules at the end to maintain cascading order.
pub fn get_all_matching_rules<E, F>( pub fn get_all_matching_rules<E>(
&self, &self,
element: E, element: E,
rule_hash_target: E, rule_hash_target: E,
matching_rules_list: &mut ApplicableDeclarationList, matching_rules_list: &mut ApplicableDeclarationList,
context: &mut MatchingContext<E::Impl>, context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
cascade_level: CascadeLevel, cascade_level: CascadeLevel,
cascade_data: &CascadeData, cascade_data: &CascadeData,
) where ) where
E: TElement, E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{ {
if self.is_empty() { if self.is_empty() {
return; return;
@ -211,7 +209,6 @@ impl SelectorMap<Rule> {
&self.root, &self.root,
matching_rules_list, matching_rules_list,
context, context,
flags_setter,
cascade_level, cascade_level,
cascade_data, cascade_data,
); );
@ -224,7 +221,6 @@ impl SelectorMap<Rule> {
rules, rules,
matching_rules_list, matching_rules_list,
context, context,
flags_setter,
cascade_level, cascade_level,
cascade_data, cascade_data,
) )
@ -238,7 +234,6 @@ impl SelectorMap<Rule> {
rules, rules,
matching_rules_list, matching_rules_list,
context, context,
flags_setter,
cascade_level, cascade_level,
cascade_data, cascade_data,
) )
@ -253,7 +248,6 @@ impl SelectorMap<Rule> {
rules, rules,
matching_rules_list, matching_rules_list,
context, context,
flags_setter,
cascade_level, cascade_level,
cascade_data, cascade_data,
) )
@ -267,7 +261,6 @@ impl SelectorMap<Rule> {
rules, rules,
matching_rules_list, matching_rules_list,
context, context,
flags_setter,
cascade_level, cascade_level,
cascade_data, cascade_data,
) )
@ -279,7 +272,6 @@ impl SelectorMap<Rule> {
rules, rules,
matching_rules_list, matching_rules_list,
context, context,
flags_setter,
cascade_level, cascade_level,
cascade_data, cascade_data,
) )
@ -290,24 +282,21 @@ impl SelectorMap<Rule> {
&self.other, &self.other,
matching_rules_list, matching_rules_list,
context, context,
flags_setter,
cascade_level, cascade_level,
cascade_data, cascade_data,
); );
} }
/// Adds rules in `rules` that match `element` to the `matching_rules` list. /// Adds rules in `rules` that match `element` to the `matching_rules` list.
pub(crate) fn get_matching_rules<E, F>( pub(crate) fn get_matching_rules<E>(
element: E, element: E,
rules: &[Rule], rules: &[Rule],
matching_rules: &mut ApplicableDeclarationList, matching_rules: &mut ApplicableDeclarationList,
context: &mut MatchingContext<E::Impl>, context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
cascade_level: CascadeLevel, cascade_level: CascadeLevel,
cascade_data: &CascadeData, cascade_data: &CascadeData,
) where ) where
E: TElement, E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{ {
for rule in rules { for rule in rules {
if matches_selector( if matches_selector(
@ -316,7 +305,6 @@ impl SelectorMap<Rule> {
Some(&rule.hashes), Some(&rule.hashes),
&element, &element,
context, context,
flags_setter,
) { ) {
matching_rules matching_rules
.push(rule.to_applicable_declaration_block(cascade_level, cascade_data)); .push(rule.to_applicable_declaration_block(cascade_level, cascade_data));

View file

@ -75,7 +75,7 @@ use crate::stylist::Stylist;
use crate::values::AtomIdent; use crate::values::AtomIdent;
use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use atomic_refcell::{AtomicRefCell, AtomicRefMut};
use owning_ref::OwningHandle; use owning_ref::OwningHandle;
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode}; use selectors::matching::{VisitedHandlingMode, NeedsSelectorFlags};
use selectors::NthIndexCache; use selectors::NthIndexCache;
use servo_arc::Arc; use servo_arc::Arc;
use smallbitvec::SmallBitVec; use smallbitvec::SmallBitVec;
@ -222,18 +222,17 @@ impl ValidationData {
/// Computes the revalidation results if needed, and returns it. /// Computes the revalidation results if needed, and returns it.
/// Inline so we know at compile time what bloom_known_valid is. /// Inline so we know at compile time what bloom_known_valid is.
#[inline] #[inline]
fn revalidation_match_results<E, F>( fn revalidation_match_results<E>(
&mut self, &mut self,
element: E, element: E,
stylist: &Stylist, stylist: &Stylist,
bloom: &StyleBloom<E>, bloom: &StyleBloom<E>,
nth_index_cache: &mut NthIndexCache, nth_index_cache: &mut NthIndexCache,
bloom_known_valid: bool, bloom_known_valid: bool,
flags_setter: &mut F, needs_selector_flags: NeedsSelectorFlags,
) -> &SmallBitVec ) -> &SmallBitVec
where where
E: TElement, E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{ {
self.revalidation_match_results.get_or_insert_with(|| { self.revalidation_match_results.get_or_insert_with(|| {
// The bloom filter may already be set up for our element. // The bloom filter may already be set up for our element.
@ -256,7 +255,7 @@ impl ValidationData {
element, element,
bloom_to_use, bloom_to_use,
nth_index_cache, nth_index_cache,
flags_setter, needs_selector_flags,
) )
}) })
} }
@ -326,7 +325,9 @@ impl<E: TElement> StyleSharingCandidate<E> {
bloom, bloom,
nth_index_cache, nth_index_cache,
/* bloom_known_valid = */ false, /* bloom_known_valid = */ false,
&mut |_, _| {}, // The candidate must already have the right bits already, if
// needed.
NeedsSelectorFlags::No,
) )
} }
} }
@ -399,17 +400,13 @@ impl<E: TElement> StyleSharingTarget<E> {
// The style sharing cache will get a hit for the second span. When the // The style sharing cache will get a hit for the second span. When the
// child span is subsequently removed from the DOM, missing selector // child span is subsequently removed from the DOM, missing selector
// flags would cause us to miss the restyle on the second span. // flags would cause us to miss the restyle on the second span.
let mut set_selector_flags = |el: &E, flags: ElementSelectorFlags| {
el.apply_selector_flags(flags);
};
self.validation_data.revalidation_match_results( self.validation_data.revalidation_match_results(
self.element, self.element,
stylist, stylist,
bloom, bloom,
nth_index_cache, nth_index_cache,
/* bloom_known_valid = */ true, /* bloom_known_valid = */ true,
&mut set_selector_flags, NeedsSelectorFlags::Yes,
) )
} }

View file

@ -15,7 +15,7 @@ use crate::rule_tree::StrongRuleNode;
use crate::selector_parser::{PseudoElement, SelectorImpl}; use crate::selector_parser::{PseudoElement, SelectorImpl};
use crate::stylist::RuleInclusion; use crate::stylist::RuleInclusion;
use log::Level::Trace; use log::Level::Trace;
use selectors::matching::{ElementSelectorFlags, MatchingContext}; use selectors::matching::{NeedsSelectorFlags, MatchingContext};
use selectors::matching::{MatchingMode, VisitedHandlingMode}; use selectors::matching::{MatchingMode, VisitedHandlingMode};
use servo_arc::Arc; use servo_arc::Arc;
@ -459,28 +459,22 @@ where
Some(nth_index_cache), Some(nth_index_cache),
visited_handling, visited_handling,
self.context.shared.quirks_mode(), self.context.shared.quirks_mode(),
NeedsSelectorFlags::Yes,
); );
let stylist = &self.context.shared.stylist; let stylist = &self.context.shared.stylist;
let implemented_pseudo = self.element.implemented_pseudo_element(); let implemented_pseudo = self.element.implemented_pseudo_element();
{ // Compute the primary rule node.
let mut set_selector_flags = |element: &E, flags: ElementSelectorFlags| { stylist.push_applicable_declarations(
element.apply_selector_flags(flags); self.element,
}; implemented_pseudo.as_ref(),
self.element.style_attribute(),
// Compute the primary rule node. self.element.smil_override(),
stylist.push_applicable_declarations( self.element.animation_declarations(self.context.shared),
self.element, self.rule_inclusion,
implemented_pseudo.as_ref(), &mut applicable_declarations,
self.element.style_attribute(), &mut matching_context,
self.element.smil_override(), );
self.element.animation_declarations(self.context.shared),
self.rule_inclusion,
&mut applicable_declarations,
&mut matching_context,
&mut set_selector_flags,
);
}
// FIXME(emilio): This is a hack for animations, and should go away. // FIXME(emilio): This is a hack for animations, and should go away.
self.element.unset_dirty_style_attribute(); self.element.unset_dirty_style_attribute();
@ -538,12 +532,9 @@ where
Some(nth_index_cache), Some(nth_index_cache),
visited_handling, visited_handling,
self.context.shared.quirks_mode(), self.context.shared.quirks_mode(),
NeedsSelectorFlags::Yes,
); );
let mut set_selector_flags = |element: &E, flags: ElementSelectorFlags| {
element.apply_selector_flags(flags);
};
// NB: We handle animation rules for ::before and ::after when // NB: We handle animation rules for ::before and ::after when
// traversing them. // traversing them.
stylist.push_applicable_declarations( stylist.push_applicable_declarations(
@ -555,7 +546,6 @@ where
self.rule_inclusion, self.rule_inclusion,
&mut applicable_declarations, &mut applicable_declarations,
&mut matching_context, &mut matching_context,
&mut set_selector_flags,
); );
if applicable_declarations.is_empty() { if applicable_declarations.is_empty() {

View file

@ -48,7 +48,7 @@ use malloc_size_of::MallocUnconditionalShallowSizeOf;
use selectors::attr::{CaseSensitivity, NamespaceConstraint}; use selectors::attr::{CaseSensitivity, NamespaceConstraint};
use selectors::bloom::BloomFilter; use selectors::bloom::BloomFilter;
use selectors::matching::VisitedHandlingMode; use selectors::matching::VisitedHandlingMode;
use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext, MatchingMode}; use selectors::matching::{matches_selector, MatchingContext, MatchingMode, NeedsSelectorFlags};
use selectors::parser::{AncestorHashes, Combinator, Component, Selector, SelectorIter}; use selectors::parser::{AncestorHashes, Combinator, Component, Selector, SelectorIter};
use selectors::visitor::SelectorVisitor; use selectors::visitor::SelectorVisitor;
use selectors::NthIndexCache; use selectors::NthIndexCache;
@ -1072,22 +1072,12 @@ impl Stylist {
{ {
debug_assert!(pseudo.is_lazy()); debug_assert!(pseudo.is_lazy());
// Apply the selector flags. We should be in sequential mode // No need to bother setting the selector flags when we're computing
// already, so we can directly apply the parent flags. // default styles.
let mut set_selector_flags = |element: &E, flags: ElementSelectorFlags| { let needs_selector_flags = if rule_inclusion == RuleInclusion::DefaultOnly {
if cfg!(feature = "servo") { NeedsSelectorFlags::No
// Servo calls this function from the worker, but only for internal } else {
// pseudos, so we should never generate selector flags here. NeedsSelectorFlags::Yes
unreachable!("internal pseudo generated slow selector flags?");
}
// No need to bother setting the selector flags when we're computing
// default styles.
if rule_inclusion == RuleInclusion::DefaultOnly {
return;
}
element.apply_selector_flags(flags);
}; };
let mut declarations = ApplicableDeclarationList::new(); let mut declarations = ApplicableDeclarationList::new();
@ -1096,6 +1086,7 @@ impl Stylist {
None, None,
None, None,
self.quirks_mode, self.quirks_mode,
needs_selector_flags,
); );
matching_context.pseudo_element_matching_fn = matching_fn; matching_context.pseudo_element_matching_fn = matching_fn;
@ -1109,7 +1100,6 @@ impl Stylist {
rule_inclusion, rule_inclusion,
&mut declarations, &mut declarations,
&mut matching_context, &mut matching_context,
&mut set_selector_flags,
); );
if declarations.is_empty() && is_probe { if declarations.is_empty() && is_probe {
@ -1127,6 +1117,7 @@ impl Stylist {
None, None,
VisitedHandlingMode::RelevantLinkVisited, VisitedHandlingMode::RelevantLinkVisited,
self.quirks_mode, self.quirks_mode,
needs_selector_flags,
); );
matching_context.pseudo_element_matching_fn = matching_fn; matching_context.pseudo_element_matching_fn = matching_fn;
@ -1139,7 +1130,6 @@ impl Stylist {
rule_inclusion, rule_inclusion,
&mut declarations, &mut declarations,
&mut matching_context, &mut matching_context,
&mut set_selector_flags,
); );
if !declarations.is_empty() { if !declarations.is_empty() {
let rule_node = self.rule_tree.insert_ordered_rules_with_important( let rule_node = self.rule_tree.insert_ordered_rules_with_important(
@ -1252,7 +1242,7 @@ impl Stylist {
} }
/// Returns the applicable CSS declarations for the given element. /// Returns the applicable CSS declarations for the given element.
pub fn push_applicable_declarations<E, F>( pub fn push_applicable_declarations<E>(
&self, &self,
element: E, element: E,
pseudo_element: Option<&PseudoElement>, pseudo_element: Option<&PseudoElement>,
@ -1262,10 +1252,8 @@ impl Stylist {
rule_inclusion: RuleInclusion, rule_inclusion: RuleInclusion,
applicable_declarations: &mut ApplicableDeclarationList, applicable_declarations: &mut ApplicableDeclarationList,
context: &mut MatchingContext<E::Impl>, context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
) where ) where
E: TElement, E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{ {
RuleCollector::new( RuleCollector::new(
self, self,
@ -1277,7 +1265,6 @@ impl Stylist {
rule_inclusion, rule_inclusion,
applicable_declarations, applicable_declarations,
context, context,
flags_setter,
) )
.collect_all(); .collect_all();
} }
@ -1357,16 +1344,15 @@ impl Stylist {
/// Computes the match results of a given element against the set of /// Computes the match results of a given element against the set of
/// revalidation selectors. /// revalidation selectors.
pub fn match_revalidation_selectors<E, F>( pub fn match_revalidation_selectors<E>(
&self, &self,
element: E, element: E,
bloom: Option<&BloomFilter>, bloom: Option<&BloomFilter>,
nth_index_cache: &mut NthIndexCache, nth_index_cache: &mut NthIndexCache,
flags_setter: &mut F, needs_selector_flags: NeedsSelectorFlags,
) -> SmallBitVec ) -> SmallBitVec
where where
E: TElement, E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{ {
// NB: `MatchingMode` doesn't really matter, given we don't share style // NB: `MatchingMode` doesn't really matter, given we don't share style
// between pseudos. // between pseudos.
@ -1375,6 +1361,7 @@ impl Stylist {
bloom, bloom,
Some(nth_index_cache), Some(nth_index_cache),
self.quirks_mode, self.quirks_mode,
needs_selector_flags,
); );
// Note that, by the time we're revalidating, we're guaranteed that the // Note that, by the time we're revalidating, we're guaranteed that the
@ -1397,7 +1384,6 @@ impl Stylist {
Some(&selector_and_hashes.hashes), Some(&selector_and_hashes.hashes),
&element, &element,
matching_context, matching_context,
flags_setter,
)); ));
true true
}, },
@ -1420,7 +1406,6 @@ impl Stylist {
Some(&selector_and_hashes.hashes), Some(&selector_and_hashes.hashes),
&element, &element,
&mut matching_context, &mut matching_context,
flags_setter,
)); ));
true true
}, },