Auto merge of #18589 - bholley:nth_index_plumbing, r=emilio

Plumbing for the nth-index cache

https://bugzilla.mozilla.org/show_bug.cgi?id=1334730
This commit is contained in:
bors-servo 2017-09-21 01:24:01 -05:00 committed by GitHub
commit 39f8fce453
18 changed files with 168 additions and 65 deletions

9
Cargo.lock generated
View file

@ -1704,6 +1704,13 @@ name = "log"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lru_cache"
version = "0.0.1"
dependencies = [
"arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lzw"
version = "0.10.0"
@ -2712,6 +2719,7 @@ dependencies = [
"cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lru_cache 0.0.1",
"malloc_size_of 0.0.1",
"malloc_size_of_derive 0.0.1",
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3128,6 +3136,7 @@ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lru_cache 0.0.1",
"malloc_size_of 0.0.1",
"malloc_size_of_derive 0.0.1",
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -0,0 +1,13 @@
[package]
name = "lru_cache"
version = "0.0.1"
authors = ["The Servo Project Developers"]
license = "MPL-2.0"
publish = false # We should publish this at some point
[lib]
name = "lru_cache"
path = "lib.rs"
[dependencies]
arrayvec = "0.3.20"

View file

@ -4,6 +4,8 @@
//! A simple LRU cache.
extern crate arrayvec;
use arrayvec::{Array, ArrayVec};
/// A LRU cache using a statically-sized array for storage.
@ -31,9 +33,8 @@ pub struct Entry<T> {
next: u16,
}
impl<T, A: Array<Item=Entry<T>>> LRUCache<T, A> {
/// Create an empty LRU cache.
pub fn new() -> Self {
impl<T, A: Array<Item=Entry<T>>> Default for LRUCache<T, A> {
fn default() -> Self {
let cache = LRUCache {
entries: ArrayVec::new(),
head: 0,
@ -42,7 +43,9 @@ impl<T, A: Array<Item=Entry<T>>> LRUCache<T, A> {
assert!(cache.entries.capacity() < u16::max_value() as usize, "Capacity overflow");
cache
}
}
impl<T, A: Array<Item=Entry<T>>> LRUCache<T, A> {
/// Returns the number of elements in the cache.
pub fn num_entries(&self) -> usize {
self.entries.len()
@ -86,6 +89,31 @@ impl<T, A: Array<Item=Entry<T>>> LRUCache<T, A> {
}
}
/// Performs a lookup on the cache with the given test routine. Touches
/// the result on a hit.
pub fn lookup<F, R>(&mut self, mut test_one: F) -> Option<R>
where
F: FnMut(&mut T) -> Option<R>
{
let mut result = None;
for (i, candidate) in self.iter_mut() {
if let Some(r) = test_one(candidate) {
result = Some((i, r));
break;
}
};
match result {
None => None,
Some((i, r)) => {
self.touch(i);
let front = self.front_mut().unwrap();
debug_assert!(test_one(front).is_some());
Some(r)
}
}
}
/// Insert a given key in the cache.
pub fn insert(&mut self, val: T) {
let entry = Entry { val, prev: 0, next: 0 };

View file

@ -2188,7 +2188,8 @@ impl ElementMethods for Element {
Err(_) => Err(Error::Syntax),
Ok(selectors) => {
let quirks_mode = document_from_node(self).quirks_mode();
let mut ctx = MatchingContext::new(MatchingMode::Normal, None,
// FIXME(bholley): Consider an nth-index cache here.
let mut ctx = MatchingContext::new(MatchingMode::Normal, None, None,
quirks_mode);
Ok(matches_selector_list(&selectors, &Root::from_ref(self), &mut ctx))
}
@ -2209,7 +2210,8 @@ impl ElementMethods for Element {
for element in root.inclusive_ancestors() {
if let Some(element) = Root::downcast::<Element>(element) {
let quirks_mode = document_from_node(self).quirks_mode();
let mut ctx = MatchingContext::new(MatchingMode::Normal, None,
// FIXME(bholley): Consider an nth-index cache here.
let mut ctx = MatchingContext::new(MatchingMode::Normal, None, None,
quirks_mode);
if matches_selector_list(&selectors, &element, &mut ctx) {
return Ok(Some(element));

View file

@ -363,7 +363,9 @@ impl<'a> Iterator for QuerySelectorIterator {
self.iterator.by_ref().filter_map(|node| {
// TODO(cgaebel): Is it worth it to build a bloom filter here
// (instead of passing `None`)? Probably.
let mut ctx = MatchingContext::new(MatchingMode::Normal, None,
//
// FIXME(bholley): Consider an nth-index cache here.
let mut ctx = MatchingContext::new(MatchingMode::Normal, None, None,
node.owner_doc().quirks_mode());
if let Some(element) = Root::downcast(node) {
if matches_selector_list(selectors, &element, &mut ctx) {
@ -754,7 +756,8 @@ impl Node {
Err(_) => Err(Error::Syntax),
// Step 3.
Ok(selectors) => {
let mut ctx = MatchingContext::new(MatchingMode::Normal, None,
// FIXME(bholley): Consider an nth-index cache here.
let mut ctx = MatchingContext::new(MatchingMode::Normal, None, None,
self.owner_doc().quirks_mode());
Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
matches_selector_list(&selectors, element, &mut ctx)

View file

@ -30,6 +30,7 @@ log = "0.3"
fnv = "1.0"
malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
lru_cache = { path = "../lru_cache" }
phf = "0.7.18"
precomputed-hash = "0.1"
servo_arc = { path = "../servo_arc" }

View file

@ -69,15 +69,22 @@ impl QuirksMode {
}
}
/// A cache to speed up matching of nth-index-like selectors.
///
/// NB: This is just a dummy type right now, it will be fleshed out in later patches.
#[derive(Default)]
pub struct NthIndexCache(usize);
/// Data associated with the matching process for a element. This context is
/// used across many selectors for an element, so it's not appropriate for
/// transient data that applies to only a single selector.
#[derive(Clone)]
pub struct MatchingContext<'a> {
/// Input with the matching mode we should use when matching selectors.
pub matching_mode: MatchingMode,
/// Input with the bloom filter used to fast-reject selectors.
pub bloom_filter: Option<&'a BloomFilter>,
/// An optional cache to speed up nth-index-like selectors.
nth_index_cache: Option<&'a mut NthIndexCache>,
/// Input that controls how matching for links is handled.
pub visited_handling: VisitedHandlingMode,
/// Output that records whether we encountered a "relevant link" while
@ -94,12 +101,14 @@ impl<'a> MatchingContext<'a> {
/// Constructs a new `MatchingContext`.
pub fn new(matching_mode: MatchingMode,
bloom_filter: Option<&'a BloomFilter>,
nth_index_cache: Option<&'a mut NthIndexCache>,
quirks_mode: QuirksMode)
-> Self
{
Self {
matching_mode: matching_mode,
bloom_filter: bloom_filter,
nth_index_cache: nth_index_cache,
visited_handling: VisitedHandlingMode::AllLinksUnvisited,
relevant_link_found: false,
quirks_mode: quirks_mode,
@ -110,6 +119,7 @@ impl<'a> MatchingContext<'a> {
/// Constructs a new `MatchingContext` for use in visited matching.
pub fn new_for_visited(matching_mode: MatchingMode,
bloom_filter: Option<&'a BloomFilter>,
nth_index_cache: Option<&'a mut NthIndexCache>,
visited_handling: VisitedHandlingMode,
quirks_mode: QuirksMode)
-> Self
@ -119,6 +129,7 @@ impl<'a> MatchingContext<'a> {
bloom_filter: bloom_filter,
visited_handling: visited_handling,
relevant_link_found: false,
nth_index_cache: nth_index_cache,
quirks_mode: quirks_mode,
classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
}

View file

@ -10,6 +10,7 @@
#[macro_use] extern crate log;
#[macro_use] extern crate matches;
extern crate fnv;
extern crate lru_cache;
extern crate malloc_size_of;
#[macro_use] extern crate malloc_size_of_derive;
extern crate phf;

View file

@ -724,26 +724,26 @@ fn matches_simple_selector<E, F>(
element.is_empty()
}
Component::NthChild(a, b) => {
matches_generic_nth_child(element, a, b, false, false, flags_setter)
matches_generic_nth_child(element, context, a, b, false, false, flags_setter)
}
Component::NthLastChild(a, b) => {
matches_generic_nth_child(element, a, b, false, true, flags_setter)
matches_generic_nth_child(element, context, a, b, false, true, flags_setter)
}
Component::NthOfType(a, b) => {
matches_generic_nth_child(element, a, b, true, false, flags_setter)
matches_generic_nth_child(element, context, a, b, true, false, flags_setter)
}
Component::NthLastOfType(a, b) => {
matches_generic_nth_child(element, a, b, true, true, flags_setter)
matches_generic_nth_child(element, context, a, b, true, true, flags_setter)
}
Component::FirstOfType => {
matches_generic_nth_child(element, 0, 1, true, false, flags_setter)
matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter)
}
Component::LastOfType => {
matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter)
}
Component::OnlyOfType => {
matches_generic_nth_child(element, 0, 1, true, false, flags_setter) &&
matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter) &&
matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter)
}
Component::Negation(ref negated) => {
context.nesting_level += 1;
@ -767,6 +767,7 @@ fn select_name<'a, T>(is_html: bool, local_name: &'a T, local_name_lower: &'a T)
#[inline]
fn matches_generic_nth_child<E, F>(element: &E,
context: &mut LocalMatchingContext<E::Impl>,
a: i32,
b: i32,
is_of_type: bool,
@ -786,6 +787,27 @@ fn matches_generic_nth_child<E, F>(element: &E,
HAS_SLOW_SELECTOR_LATER_SIBLINGS
});
let index = nth_child_index(element, is_of_type, is_from_end);
// Is there a non-negative integer n such that An+B=index?
match index.checked_sub(b) {
None => false,
Some(an) => match an.checked_div(a) {
Some(n) => n >= 0 && a * n == an,
None /* a == 0 */ => an == 0,
},
}
}
#[inline]
fn nth_child_index<E>(
element: &E,
is_of_type: bool,
is_from_end: bool,
) -> i32
where
E: Element,
{
let mut index: i32 = 1;
let mut next_sibling = if is_from_end {
element.next_sibling_element()
@ -814,14 +836,7 @@ fn matches_generic_nth_child<E, F>(element: &E,
};
}
// Is there a non-negative integer n such that An+B=index?
match index.checked_sub(b) {
None => false,
Some(an) => match an.checked_div(a) {
Some(n) => n >= 0 && a * n == an,
None /* a == 0 */ => an == 0,
},
}
index
}
#[inline]

View file

@ -48,6 +48,7 @@ itertools = "0.5"
itoa = "0.3"
html5ever = {version = "0.19", optional = true}
lazy_static = "0.2"
lru_cache = { path = "../lru_cache" }
log = "0.3"
malloc_size_of = { path = "../malloc_size_of", optional=true }
malloc_size_of_derive = { path = "../malloc_size_of_derive", optional=true }

View file

@ -8,13 +8,13 @@
#[cfg(feature = "servo")] use animation::PropertyAnimation;
use app_units::Au;
use bloom::StyleBloom;
use cache::{Entry, LRUCache};
use data::{EagerPseudoStyles, ElementData};
use dom::{OpaqueNode, TNode, TElement, SendElement};
use euclid::ScaleFactor;
use euclid::Size2D;
use fnv::FnvHashMap;
use font_metrics::FontMetricsProvider;
use lru_cache::{Entry, LRUCache};
#[cfg(feature = "gecko")] use gecko_bindings::structs;
use parallel::{STACK_SAFETY_MARGIN_KB, STYLE_THREAD_STACK_SIZE_KB};
#[cfg(feature = "servo")] use parking_lot::RwLock;
@ -23,6 +23,7 @@ use properties::ComputedValues;
use rule_cache::RuleCache;
use rule_tree::StrongRuleNode;
use selector_parser::{EAGER_PSEUDO_COUNT, SnapshotMap};
use selectors::context::NthIndexCache;
use selectors::matching::ElementSelectorFlags;
use servo_arc::Arc;
#[cfg(feature = "servo")] use servo_atoms::Atom;
@ -546,7 +547,7 @@ impl<E: TElement> SelectorFlagsMap<E> {
pub fn new() -> Self {
SelectorFlagsMap {
map: FnvHashMap::default(),
cache: LRUCache::new(),
cache: LRUCache::default(),
}
}
@ -719,6 +720,8 @@ pub struct ThreadLocalStyleContext<E: TElement> {
/// A checker used to ensure that parallel.rs does not recurse indefinitely
/// even on arbitrarily deep trees. See Gecko bug 1376883.
pub stack_limit_checker: StackLimitChecker,
/// A cache for nth-index-like selectors.
pub nth_index_cache: NthIndexCache,
}
impl<E: TElement> ThreadLocalStyleContext<E> {
@ -737,6 +740,7 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
font_metrics_provider: E::FontMetricsProvider::create_from(shared),
stack_limit_checker: StackLimitChecker::new(
(STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024),
nth_index_cache: NthIndexCache::default(),
}
}
@ -754,6 +758,7 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
font_metrics_provider: E::FontMetricsProvider::create_from(shared),
stack_limit_checker: StackLimitChecker::new(
(STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024),
nth_index_cache: NthIndexCache::default(),
}
}

View file

@ -633,10 +633,12 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})",
self.element, invalidation, invalidation_kind);
// FIXME(bholley): Consider passing an nth-index cache here.
let mut context =
MatchingContext::new_for_visited(
MatchingMode::Normal,
None,
None,
VisitedHandlingMode::AllLinksVisitedAndUnvisited,
self.shared_context.quirks_mode(),
);
@ -946,12 +948,14 @@ impl<'a, 'b: 'a, E> InvalidationCollector<'a, 'b, E>
// whether any parent had a snapshot, and whether those snapshots were
// taken due to an element class/id change, but it's not clear it'd be
// worth it.
//
// FIXME(bholley): Consider passing an nth-index cache here.
let mut now_context =
MatchingContext::new_for_visited(MatchingMode::Normal, None,
MatchingContext::new_for_visited(MatchingMode::Normal, None, None,
VisitedHandlingMode::AllLinksUnvisited,
self.shared_context.quirks_mode());
let mut then_context =
MatchingContext::new_for_visited(MatchingMode::Normal, None,
MatchingContext::new_for_visited(MatchingMode::Normal, None, None,
VisitedHandlingMode::AllLinksUnvisited,
self.shared_context.quirks_mode());

View file

@ -59,6 +59,7 @@ extern crate itoa;
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate lru_cache;
#[cfg(feature = "gecko")] #[macro_use] extern crate malloc_size_of;
#[cfg(feature = "gecko")] #[macro_use] extern crate malloc_size_of_derive;
#[allow(unused_extern_crates)]
@ -102,7 +103,6 @@ pub mod applicable_declarations;
#[cfg(feature = "servo")] pub mod attr;
pub mod bezier;
pub mod bloom;
pub mod cache;
pub mod context;
pub mod counter_style;
pub mod custom_properties;

View file

@ -10,6 +10,7 @@ use Atom;
use bloom::StyleBloom;
use context::{SelectorFlagsMap, SharedStyleContext};
use dom::TElement;
use selectors::context::NthIndexCache;
use sharing::{StyleSharingCandidate, StyleSharingTarget};
/// Determines whether a target and a candidate have compatible parents for sharing.
@ -99,16 +100,25 @@ pub fn revalidate<E>(target: &mut StyleSharingTarget<E>,
candidate: &mut StyleSharingCandidate<E>,
shared_context: &SharedStyleContext,
bloom: &StyleBloom<E>,
nth_index_cache: &mut NthIndexCache,
selector_flags_map: &mut SelectorFlagsMap<E>)
-> bool
where E: TElement,
{
let stylist = &shared_context.stylist;
let for_element =
target.revalidation_match_results(stylist, bloom, selector_flags_map);
let for_element = target.revalidation_match_results(
stylist,
bloom,
nth_index_cache,
selector_flags_map,
);
let for_candidate = candidate.revalidation_match_results(stylist, bloom);
let for_candidate = candidate.revalidation_match_results(
stylist,
bloom,
nth_index_cache,
);
// This assert "ensures", to some extent, that the two candidates have
// matched the same rulehash buckets, and as such, that the bits we're

View file

@ -68,13 +68,14 @@ use Atom;
use applicable_declarations::ApplicableDeclarationBlock;
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
use bloom::StyleBloom;
use cache::{LRUCache, Entry};
use context::{SelectorFlagsMap, SharedStyleContext, StyleContext};
use dom::{TElement, SendElement};
use lru_cache::{LRUCache, Entry};
use matching::MatchMethods;
use owning_ref::OwningHandle;
use properties::ComputedValues;
use rule_tree::StrongRuleNode;
use selectors::context::NthIndexCache;
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
use servo_arc::{Arc, NonZeroPtrMut};
use smallbitvec::SmallBitVec;
@ -203,6 +204,7 @@ impl ValidationData {
element: E,
stylist: &Stylist,
bloom: &StyleBloom<E>,
nth_index_cache: &mut NthIndexCache,
bloom_known_valid: bool,
flags_setter: &mut F
) -> &SmallBitVec
@ -230,6 +232,7 @@ impl ValidationData {
self.revalidation_match_results =
Some(stylist.match_revalidation_selectors(&element,
bloom_to_use,
nth_index_cache,
flags_setter));
}
@ -289,11 +292,13 @@ impl<E: TElement> StyleSharingCandidate<E> {
&mut self,
stylist: &Stylist,
bloom: &StyleBloom<E>,
nth_index_cache: &mut NthIndexCache,
) -> &SmallBitVec {
self.validation_data.revalidation_match_results(
self.element,
stylist,
bloom,
nth_index_cache,
/* bloom_known_valid = */ false,
&mut |_, _| {})
}
@ -346,6 +351,7 @@ impl<E: TElement> StyleSharingTarget<E> {
&mut self,
stylist: &Stylist,
bloom: &StyleBloom<E>,
nth_index_cache: &mut NthIndexCache,
selector_flags_map: &mut SelectorFlagsMap<E>
) -> &SmallBitVec {
// It's important to set the selector flags. Otherwise, if we succeed in
@ -372,6 +378,7 @@ impl<E: TElement> StyleSharingTarget<E> {
self.element,
stylist,
bloom,
nth_index_cache,
/* bloom_known_valid = */ true,
&mut set_selector_flags)
}
@ -385,6 +392,7 @@ impl<E: TElement> StyleSharingTarget<E> {
let shared_context = &context.shared;
let selector_flags_map = &mut context.thread_local.selector_flags;
let bloom_filter = &context.thread_local.bloom_filter;
let nth_index_cache = &mut context.thread_local.nth_index_cache;
if cache.dom_depth != bloom_filter.matching_depth() {
debug!("Can't share style, because DOM depth changed from {:?} to {:?}, element: {:?}",
@ -398,6 +406,7 @@ impl<E: TElement> StyleSharingTarget<E> {
shared_context,
selector_flags_map,
bloom_filter,
nth_index_cache,
self
)
}
@ -415,7 +424,7 @@ struct SharingCacheBase<Candidate> {
impl<Candidate> Default for SharingCacheBase<Candidate> {
fn default() -> Self {
Self {
entries: LRUCache::new(),
entries: LRUCache::default(),
}
}
}
@ -442,29 +451,6 @@ impl<E: TElement> SharingCache<E> {
};
self.entries.insert(StyleSharingCandidate { element, validation_data });
}
fn lookup<F, R>(&mut self, mut test_one: F) -> Option<R>
where
F: FnMut(&mut StyleSharingCandidate<E>) -> Option<R>
{
let mut result = None;
for (i, candidate) in self.entries.iter_mut() {
if let Some(r) = test_one(candidate) {
result = Some((i, r));
break;
}
};
match result {
None => None,
Some((i, r)) => {
self.entries.touch(i);
let front = self.entries.front_mut().unwrap();
debug_assert!(test_one(front).is_some());
Some(r)
}
}
}
}
/// Style sharing caches are are large allocations, so we store them in thread-local
@ -619,6 +605,7 @@ impl<E: TElement> StyleSharingCache<E> {
shared_context: &SharedStyleContext,
selector_flags_map: &mut SelectorFlagsMap<E>,
bloom_filter: &StyleBloom<E>,
nth_index_cache: &mut NthIndexCache,
target: &mut StyleSharingTarget<E>,
) -> Option<ResolvedElementStyles> {
if shared_context.options.disable_style_sharing_cache {
@ -638,12 +625,13 @@ impl<E: TElement> StyleSharingCache<E> {
return None;
}
self.cache_mut().lookup(|candidate| {
self.cache_mut().entries.lookup(|candidate| {
Self::test_candidate(
target,
candidate,
&shared_context,
bloom_filter,
nth_index_cache,
selector_flags_map
)
})
@ -654,6 +642,7 @@ impl<E: TElement> StyleSharingCache<E> {
candidate: &mut StyleSharingCandidate<E>,
shared: &SharedStyleContext,
bloom: &StyleBloom<E>,
nth_index_cache: &mut NthIndexCache,
selector_flags_map: &mut SelectorFlagsMap<E>
) -> Option<ResolvedElementStyles> {
// Check that we have the same parent, or at least that the parents
@ -728,7 +717,7 @@ impl<E: TElement> StyleSharingCache<E> {
}
if !checks::revalidate(target, candidate, shared, bloom,
selector_flags_map) {
nth_index_cache, selector_flags_map) {
trace!("Miss: Revalidation");
return None;
}
@ -755,7 +744,7 @@ impl<E: TElement> StyleSharingCache<E> {
return None;
}
self.cache_mut().lookup(|candidate| {
self.cache_mut().entries.lookup(|candidate| {
debug_assert_ne!(candidate.element, target);
if !candidate.parent_style_identity().eq(inherited) {
return None;

View file

@ -413,10 +413,12 @@ where
let map = &mut self.context.thread_local.selector_flags;
let bloom_filter = self.context.thread_local.bloom_filter.filter();
let nth_index_cache = &mut self.context.thread_local.nth_index_cache;
let mut matching_context =
MatchingContext::new_for_visited(
MatchingMode::Normal,
Some(bloom_filter),
Some(nth_index_cache),
visited_handling,
self.context.shared.quirks_mode(),
);
@ -486,11 +488,13 @@ where
}
let bloom_filter = self.context.thread_local.bloom_filter.filter();
let nth_index_cache = &mut self.context.thread_local.nth_index_cache;
let mut matching_context =
MatchingContext::new_for_visited(
MatchingMode::ForStatelessPseudoElement,
Some(bloom_filter),
Some(nth_index_cache),
visited_handling,
self.context.shared.quirks_mode(),
);

View file

@ -30,7 +30,7 @@ use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
use selectors::attr::NamespaceConstraint;
use selectors::bloom::{BloomFilter, NonCountingBloomFilter};
use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode};
use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode, NthIndexCache};
use selectors::matching::VisitedHandlingMode;
use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
use selectors::parser::{SelectorIter, SelectorMethods};
@ -1027,6 +1027,7 @@ impl Stylist {
let mut declarations = ApplicableDeclarationList::new();
let mut matching_context =
MatchingContext::new(MatchingMode::ForStatelessPseudoElement,
None,
None,
self.quirks_mode);
@ -1061,6 +1062,7 @@ impl Stylist {
MatchingContext::new_for_visited(
MatchingMode::ForStatelessPseudoElement,
None,
None,
VisitedHandlingMode::RelevantLinkVisited,
self.quirks_mode,
);
@ -1203,7 +1205,7 @@ impl Stylist {
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
{
let mut matching_context =
MatchingContext::new(MatchingMode::Normal, None, self.quirks_mode);
MatchingContext::new(MatchingMode::Normal, None, None, self.quirks_mode);
let mut dummy_flag_setter = |_: &E, _: ElementSelectorFlags| {};
let rule_hash_target = element.rule_hash_target();
@ -1427,6 +1429,7 @@ impl Stylist {
&self,
element: &E,
bloom: Option<&BloomFilter>,
nth_index_cache: &mut NthIndexCache,
flags_setter: &mut F
) -> SmallBitVec
where
@ -1435,8 +1438,12 @@ impl Stylist {
{
// NB: `MatchingMode` doesn't really matter, given we don't share style
// between pseudos.
let mut matching_context =
MatchingContext::new(MatchingMode::Normal, bloom, self.quirks_mode);
let mut matching_context = MatchingContext::new(
MatchingMode::Normal,
bloom,
Some(nth_index_cache),
self.quirks_mode
);
// Note that, by the time we're revalidating, we're guaranteed that the
// candidate and the entry have the same id, classes, and local name.

View file

@ -1503,7 +1503,7 @@ pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(rule: RawServoStyleRule
};
let element = GeckoElement(element);
let mut ctx = MatchingContext::new(matching_mode, None, element.owner_document_quirks_mode());
let mut ctx = MatchingContext::new(matching_mode, None, None, element.owner_document_quirks_mode());
matches_selector(selector, 0, None, &element, &mut ctx, &mut |_, _| {})
})
}