mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
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:
commit
39f8fce453
18 changed files with 168 additions and 65 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -1704,6 +1704,13 @@ name = "log"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "lzw"
|
name = "lzw"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -2712,6 +2719,7 @@ dependencies = [
|
||||||
"cssparser 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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 0.0.1",
|
||||||
"malloc_size_of_derive 0.0.1",
|
"malloc_size_of_derive 0.0.1",
|
||||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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 0.0.1",
|
||||||
"malloc_size_of_derive 0.0.1",
|
"malloc_size_of_derive 0.0.1",
|
||||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
13
components/lru_cache/Cargo.toml
Normal file
13
components/lru_cache/Cargo.toml
Normal 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"
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
//! A simple LRU cache.
|
//! A simple LRU cache.
|
||||||
|
|
||||||
|
extern crate arrayvec;
|
||||||
|
|
||||||
use arrayvec::{Array, ArrayVec};
|
use arrayvec::{Array, ArrayVec};
|
||||||
|
|
||||||
/// A LRU cache using a statically-sized array for storage.
|
/// A LRU cache using a statically-sized array for storage.
|
||||||
|
@ -31,9 +33,8 @@ pub struct Entry<T> {
|
||||||
next: u16,
|
next: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A: Array<Item=Entry<T>>> LRUCache<T, A> {
|
impl<T, A: Array<Item=Entry<T>>> Default for LRUCache<T, A> {
|
||||||
/// Create an empty LRU cache.
|
fn default() -> Self {
|
||||||
pub fn new() -> Self {
|
|
||||||
let cache = LRUCache {
|
let cache = LRUCache {
|
||||||
entries: ArrayVec::new(),
|
entries: ArrayVec::new(),
|
||||||
head: 0,
|
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");
|
assert!(cache.entries.capacity() < u16::max_value() as usize, "Capacity overflow");
|
||||||
cache
|
cache
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, A: Array<Item=Entry<T>>> LRUCache<T, A> {
|
||||||
/// Returns the number of elements in the cache.
|
/// Returns the number of elements in the cache.
|
||||||
pub fn num_entries(&self) -> usize {
|
pub fn num_entries(&self) -> usize {
|
||||||
self.entries.len()
|
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.
|
/// Insert a given key in the cache.
|
||||||
pub fn insert(&mut self, val: T) {
|
pub fn insert(&mut self, val: T) {
|
||||||
let entry = Entry { val, prev: 0, next: 0 };
|
let entry = Entry { val, prev: 0, next: 0 };
|
|
@ -2188,7 +2188,8 @@ impl ElementMethods for Element {
|
||||||
Err(_) => Err(Error::Syntax),
|
Err(_) => Err(Error::Syntax),
|
||||||
Ok(selectors) => {
|
Ok(selectors) => {
|
||||||
let quirks_mode = document_from_node(self).quirks_mode();
|
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);
|
quirks_mode);
|
||||||
Ok(matches_selector_list(&selectors, &Root::from_ref(self), &mut ctx))
|
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() {
|
for element in root.inclusive_ancestors() {
|
||||||
if let Some(element) = Root::downcast::<Element>(element) {
|
if let Some(element) = Root::downcast::<Element>(element) {
|
||||||
let quirks_mode = document_from_node(self).quirks_mode();
|
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);
|
quirks_mode);
|
||||||
if matches_selector_list(&selectors, &element, &mut ctx) {
|
if matches_selector_list(&selectors, &element, &mut ctx) {
|
||||||
return Ok(Some(element));
|
return Ok(Some(element));
|
||||||
|
|
|
@ -363,7 +363,9 @@ impl<'a> Iterator for QuerySelectorIterator {
|
||||||
self.iterator.by_ref().filter_map(|node| {
|
self.iterator.by_ref().filter_map(|node| {
|
||||||
// TODO(cgaebel): Is it worth it to build a bloom filter here
|
// TODO(cgaebel): Is it worth it to build a bloom filter here
|
||||||
// (instead of passing `None`)? Probably.
|
// (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());
|
node.owner_doc().quirks_mode());
|
||||||
if let Some(element) = Root::downcast(node) {
|
if let Some(element) = Root::downcast(node) {
|
||||||
if matches_selector_list(selectors, &element, &mut ctx) {
|
if matches_selector_list(selectors, &element, &mut ctx) {
|
||||||
|
@ -754,7 +756,8 @@ impl Node {
|
||||||
Err(_) => Err(Error::Syntax),
|
Err(_) => Err(Error::Syntax),
|
||||||
// Step 3.
|
// Step 3.
|
||||||
Ok(selectors) => {
|
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());
|
self.owner_doc().quirks_mode());
|
||||||
Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
|
Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
|
||||||
matches_selector_list(&selectors, element, &mut ctx)
|
matches_selector_list(&selectors, element, &mut ctx)
|
||||||
|
|
|
@ -30,6 +30,7 @@ log = "0.3"
|
||||||
fnv = "1.0"
|
fnv = "1.0"
|
||||||
malloc_size_of = { path = "../malloc_size_of" }
|
malloc_size_of = { path = "../malloc_size_of" }
|
||||||
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
||||||
|
lru_cache = { path = "../lru_cache" }
|
||||||
phf = "0.7.18"
|
phf = "0.7.18"
|
||||||
precomputed-hash = "0.1"
|
precomputed-hash = "0.1"
|
||||||
servo_arc = { path = "../servo_arc" }
|
servo_arc = { path = "../servo_arc" }
|
||||||
|
|
|
@ -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
|
/// 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
|
/// used across many selectors for an element, so it's not appropriate for
|
||||||
/// transient data that applies to only a single selector.
|
/// transient data that applies to only a single selector.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct MatchingContext<'a> {
|
pub struct MatchingContext<'a> {
|
||||||
/// Input with the matching mode we should use when matching selectors.
|
/// Input with the matching mode we should use when matching selectors.
|
||||||
pub matching_mode: MatchingMode,
|
pub matching_mode: MatchingMode,
|
||||||
/// Input with the bloom filter used to fast-reject selectors.
|
/// Input with the bloom filter used to fast-reject selectors.
|
||||||
pub bloom_filter: Option<&'a BloomFilter>,
|
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.
|
/// Input that controls how matching for links is handled.
|
||||||
pub visited_handling: VisitedHandlingMode,
|
pub visited_handling: VisitedHandlingMode,
|
||||||
/// Output that records whether we encountered a "relevant link" while
|
/// Output that records whether we encountered a "relevant link" while
|
||||||
|
@ -94,12 +101,14 @@ impl<'a> MatchingContext<'a> {
|
||||||
/// Constructs a new `MatchingContext`.
|
/// Constructs a new `MatchingContext`.
|
||||||
pub fn new(matching_mode: MatchingMode,
|
pub fn new(matching_mode: MatchingMode,
|
||||||
bloom_filter: Option<&'a BloomFilter>,
|
bloom_filter: Option<&'a BloomFilter>,
|
||||||
|
nth_index_cache: Option<&'a mut NthIndexCache>,
|
||||||
quirks_mode: QuirksMode)
|
quirks_mode: QuirksMode)
|
||||||
-> Self
|
-> Self
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
matching_mode: matching_mode,
|
matching_mode: matching_mode,
|
||||||
bloom_filter: bloom_filter,
|
bloom_filter: bloom_filter,
|
||||||
|
nth_index_cache: nth_index_cache,
|
||||||
visited_handling: VisitedHandlingMode::AllLinksUnvisited,
|
visited_handling: VisitedHandlingMode::AllLinksUnvisited,
|
||||||
relevant_link_found: false,
|
relevant_link_found: false,
|
||||||
quirks_mode: quirks_mode,
|
quirks_mode: quirks_mode,
|
||||||
|
@ -110,6 +119,7 @@ impl<'a> MatchingContext<'a> {
|
||||||
/// Constructs a new `MatchingContext` for use in visited matching.
|
/// Constructs a new `MatchingContext` for use in visited matching.
|
||||||
pub fn new_for_visited(matching_mode: MatchingMode,
|
pub fn new_for_visited(matching_mode: MatchingMode,
|
||||||
bloom_filter: Option<&'a BloomFilter>,
|
bloom_filter: Option<&'a BloomFilter>,
|
||||||
|
nth_index_cache: Option<&'a mut NthIndexCache>,
|
||||||
visited_handling: VisitedHandlingMode,
|
visited_handling: VisitedHandlingMode,
|
||||||
quirks_mode: QuirksMode)
|
quirks_mode: QuirksMode)
|
||||||
-> Self
|
-> Self
|
||||||
|
@ -119,6 +129,7 @@ impl<'a> MatchingContext<'a> {
|
||||||
bloom_filter: bloom_filter,
|
bloom_filter: bloom_filter,
|
||||||
visited_handling: visited_handling,
|
visited_handling: visited_handling,
|
||||||
relevant_link_found: false,
|
relevant_link_found: false,
|
||||||
|
nth_index_cache: nth_index_cache,
|
||||||
quirks_mode: quirks_mode,
|
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(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate matches;
|
#[macro_use] extern crate matches;
|
||||||
extern crate fnv;
|
extern crate fnv;
|
||||||
|
extern crate lru_cache;
|
||||||
extern crate malloc_size_of;
|
extern crate malloc_size_of;
|
||||||
#[macro_use] extern crate malloc_size_of_derive;
|
#[macro_use] extern crate malloc_size_of_derive;
|
||||||
extern crate phf;
|
extern crate phf;
|
||||||
|
|
|
@ -724,26 +724,26 @@ fn matches_simple_selector<E, F>(
|
||||||
element.is_empty()
|
element.is_empty()
|
||||||
}
|
}
|
||||||
Component::NthChild(a, b) => {
|
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) => {
|
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) => {
|
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) => {
|
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 => {
|
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 => {
|
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 => {
|
Component::OnlyOfType => {
|
||||||
matches_generic_nth_child(element, 0, 1, true, false, flags_setter) &&
|
matches_generic_nth_child(element, context, 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, true, flags_setter)
|
||||||
}
|
}
|
||||||
Component::Negation(ref negated) => {
|
Component::Negation(ref negated) => {
|
||||||
context.nesting_level += 1;
|
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]
|
#[inline]
|
||||||
fn matches_generic_nth_child<E, F>(element: &E,
|
fn matches_generic_nth_child<E, F>(element: &E,
|
||||||
|
context: &mut LocalMatchingContext<E::Impl>,
|
||||||
a: i32,
|
a: i32,
|
||||||
b: i32,
|
b: i32,
|
||||||
is_of_type: bool,
|
is_of_type: bool,
|
||||||
|
@ -786,6 +787,27 @@ fn matches_generic_nth_child<E, F>(element: &E,
|
||||||
HAS_SLOW_SELECTOR_LATER_SIBLINGS
|
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 index: i32 = 1;
|
||||||
let mut next_sibling = if is_from_end {
|
let mut next_sibling = if is_from_end {
|
||||||
element.next_sibling_element()
|
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?
|
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]
|
#[inline]
|
||||||
|
|
|
@ -48,6 +48,7 @@ itertools = "0.5"
|
||||||
itoa = "0.3"
|
itoa = "0.3"
|
||||||
html5ever = {version = "0.19", optional = true}
|
html5ever = {version = "0.19", optional = true}
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
|
lru_cache = { path = "../lru_cache" }
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
malloc_size_of = { path = "../malloc_size_of", optional=true }
|
malloc_size_of = { path = "../malloc_size_of", optional=true }
|
||||||
malloc_size_of_derive = { path = "../malloc_size_of_derive", optional=true }
|
malloc_size_of_derive = { path = "../malloc_size_of_derive", optional=true }
|
||||||
|
|
|
@ -8,13 +8,13 @@
|
||||||
#[cfg(feature = "servo")] use animation::PropertyAnimation;
|
#[cfg(feature = "servo")] use animation::PropertyAnimation;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use bloom::StyleBloom;
|
use bloom::StyleBloom;
|
||||||
use cache::{Entry, LRUCache};
|
|
||||||
use data::{EagerPseudoStyles, ElementData};
|
use data::{EagerPseudoStyles, ElementData};
|
||||||
use dom::{OpaqueNode, TNode, TElement, SendElement};
|
use dom::{OpaqueNode, TNode, TElement, SendElement};
|
||||||
use euclid::ScaleFactor;
|
use euclid::ScaleFactor;
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
|
use lru_cache::{Entry, LRUCache};
|
||||||
#[cfg(feature = "gecko")] use gecko_bindings::structs;
|
#[cfg(feature = "gecko")] use gecko_bindings::structs;
|
||||||
use parallel::{STACK_SAFETY_MARGIN_KB, STYLE_THREAD_STACK_SIZE_KB};
|
use parallel::{STACK_SAFETY_MARGIN_KB, STYLE_THREAD_STACK_SIZE_KB};
|
||||||
#[cfg(feature = "servo")] use parking_lot::RwLock;
|
#[cfg(feature = "servo")] use parking_lot::RwLock;
|
||||||
|
@ -23,6 +23,7 @@ use properties::ComputedValues;
|
||||||
use rule_cache::RuleCache;
|
use rule_cache::RuleCache;
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
use selector_parser::{EAGER_PSEUDO_COUNT, SnapshotMap};
|
use selector_parser::{EAGER_PSEUDO_COUNT, SnapshotMap};
|
||||||
|
use selectors::context::NthIndexCache;
|
||||||
use selectors::matching::ElementSelectorFlags;
|
use selectors::matching::ElementSelectorFlags;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
#[cfg(feature = "servo")] use servo_atoms::Atom;
|
#[cfg(feature = "servo")] use servo_atoms::Atom;
|
||||||
|
@ -546,7 +547,7 @@ impl<E: TElement> SelectorFlagsMap<E> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SelectorFlagsMap {
|
SelectorFlagsMap {
|
||||||
map: FnvHashMap::default(),
|
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
|
/// A checker used to ensure that parallel.rs does not recurse indefinitely
|
||||||
/// even on arbitrarily deep trees. See Gecko bug 1376883.
|
/// even on arbitrarily deep trees. See Gecko bug 1376883.
|
||||||
pub stack_limit_checker: StackLimitChecker,
|
pub stack_limit_checker: StackLimitChecker,
|
||||||
|
/// A cache for nth-index-like selectors.
|
||||||
|
pub nth_index_cache: NthIndexCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: TElement> ThreadLocalStyleContext<E> {
|
impl<E: TElement> ThreadLocalStyleContext<E> {
|
||||||
|
@ -737,6 +740,7 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
|
||||||
font_metrics_provider: E::FontMetricsProvider::create_from(shared),
|
font_metrics_provider: E::FontMetricsProvider::create_from(shared),
|
||||||
stack_limit_checker: StackLimitChecker::new(
|
stack_limit_checker: StackLimitChecker::new(
|
||||||
(STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024),
|
(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),
|
font_metrics_provider: E::FontMetricsProvider::create_from(shared),
|
||||||
stack_limit_checker: StackLimitChecker::new(
|
stack_limit_checker: StackLimitChecker::new(
|
||||||
(STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024),
|
(STYLE_THREAD_STACK_SIZE_KB - STACK_SAFETY_MARGIN_KB) * 1024),
|
||||||
|
nth_index_cache: NthIndexCache::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -633,10 +633,12 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
||||||
debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})",
|
debug!("TreeStyleInvalidator::process_invalidation({:?}, {:?}, {:?})",
|
||||||
self.element, invalidation, invalidation_kind);
|
self.element, invalidation, invalidation_kind);
|
||||||
|
|
||||||
|
// FIXME(bholley): Consider passing an nth-index cache here.
|
||||||
let mut context =
|
let mut context =
|
||||||
MatchingContext::new_for_visited(
|
MatchingContext::new_for_visited(
|
||||||
MatchingMode::Normal,
|
MatchingMode::Normal,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
VisitedHandlingMode::AllLinksVisitedAndUnvisited,
|
VisitedHandlingMode::AllLinksVisitedAndUnvisited,
|
||||||
self.shared_context.quirks_mode(),
|
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
|
// 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
|
// taken due to an element class/id change, but it's not clear it'd be
|
||||||
// worth it.
|
// worth it.
|
||||||
|
//
|
||||||
|
// FIXME(bholley): Consider passing an nth-index cache here.
|
||||||
let mut now_context =
|
let mut now_context =
|
||||||
MatchingContext::new_for_visited(MatchingMode::Normal, None,
|
MatchingContext::new_for_visited(MatchingMode::Normal, None, None,
|
||||||
VisitedHandlingMode::AllLinksUnvisited,
|
VisitedHandlingMode::AllLinksUnvisited,
|
||||||
self.shared_context.quirks_mode());
|
self.shared_context.quirks_mode());
|
||||||
let mut then_context =
|
let mut then_context =
|
||||||
MatchingContext::new_for_visited(MatchingMode::Normal, None,
|
MatchingContext::new_for_visited(MatchingMode::Normal, None, None,
|
||||||
VisitedHandlingMode::AllLinksUnvisited,
|
VisitedHandlingMode::AllLinksUnvisited,
|
||||||
self.shared_context.quirks_mode());
|
self.shared_context.quirks_mode());
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ extern crate itoa;
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
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;
|
||||||
#[cfg(feature = "gecko")] #[macro_use] extern crate malloc_size_of_derive;
|
#[cfg(feature = "gecko")] #[macro_use] extern crate malloc_size_of_derive;
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
|
@ -102,7 +103,6 @@ pub mod applicable_declarations;
|
||||||
#[cfg(feature = "servo")] pub mod attr;
|
#[cfg(feature = "servo")] pub mod attr;
|
||||||
pub mod bezier;
|
pub mod bezier;
|
||||||
pub mod bloom;
|
pub mod bloom;
|
||||||
pub mod cache;
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod counter_style;
|
pub mod counter_style;
|
||||||
pub mod custom_properties;
|
pub mod custom_properties;
|
||||||
|
|
|
@ -10,6 +10,7 @@ use Atom;
|
||||||
use bloom::StyleBloom;
|
use bloom::StyleBloom;
|
||||||
use context::{SelectorFlagsMap, SharedStyleContext};
|
use context::{SelectorFlagsMap, SharedStyleContext};
|
||||||
use dom::TElement;
|
use dom::TElement;
|
||||||
|
use selectors::context::NthIndexCache;
|
||||||
use sharing::{StyleSharingCandidate, StyleSharingTarget};
|
use sharing::{StyleSharingCandidate, StyleSharingTarget};
|
||||||
|
|
||||||
/// Determines whether a target and a candidate have compatible parents for sharing.
|
/// 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>,
|
candidate: &mut StyleSharingCandidate<E>,
|
||||||
shared_context: &SharedStyleContext,
|
shared_context: &SharedStyleContext,
|
||||||
bloom: &StyleBloom<E>,
|
bloom: &StyleBloom<E>,
|
||||||
|
nth_index_cache: &mut NthIndexCache,
|
||||||
selector_flags_map: &mut SelectorFlagsMap<E>)
|
selector_flags_map: &mut SelectorFlagsMap<E>)
|
||||||
-> bool
|
-> bool
|
||||||
where E: TElement,
|
where E: TElement,
|
||||||
{
|
{
|
||||||
let stylist = &shared_context.stylist;
|
let stylist = &shared_context.stylist;
|
||||||
|
|
||||||
let for_element =
|
let for_element = target.revalidation_match_results(
|
||||||
target.revalidation_match_results(stylist, bloom, selector_flags_map);
|
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
|
// This assert "ensures", to some extent, that the two candidates have
|
||||||
// matched the same rulehash buckets, and as such, that the bits we're
|
// matched the same rulehash buckets, and as such, that the bits we're
|
||||||
|
|
|
@ -68,13 +68,14 @@ use Atom;
|
||||||
use applicable_declarations::ApplicableDeclarationBlock;
|
use applicable_declarations::ApplicableDeclarationBlock;
|
||||||
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
||||||
use bloom::StyleBloom;
|
use bloom::StyleBloom;
|
||||||
use cache::{LRUCache, Entry};
|
|
||||||
use context::{SelectorFlagsMap, SharedStyleContext, StyleContext};
|
use context::{SelectorFlagsMap, SharedStyleContext, StyleContext};
|
||||||
use dom::{TElement, SendElement};
|
use dom::{TElement, SendElement};
|
||||||
|
use lru_cache::{LRUCache, Entry};
|
||||||
use matching::MatchMethods;
|
use matching::MatchMethods;
|
||||||
use owning_ref::OwningHandle;
|
use owning_ref::OwningHandle;
|
||||||
use properties::ComputedValues;
|
use properties::ComputedValues;
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
|
use selectors::context::NthIndexCache;
|
||||||
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
||||||
use servo_arc::{Arc, NonZeroPtrMut};
|
use servo_arc::{Arc, NonZeroPtrMut};
|
||||||
use smallbitvec::SmallBitVec;
|
use smallbitvec::SmallBitVec;
|
||||||
|
@ -203,6 +204,7 @@ impl ValidationData {
|
||||||
element: E,
|
element: E,
|
||||||
stylist: &Stylist,
|
stylist: &Stylist,
|
||||||
bloom: &StyleBloom<E>,
|
bloom: &StyleBloom<E>,
|
||||||
|
nth_index_cache: &mut NthIndexCache,
|
||||||
bloom_known_valid: bool,
|
bloom_known_valid: bool,
|
||||||
flags_setter: &mut F
|
flags_setter: &mut F
|
||||||
) -> &SmallBitVec
|
) -> &SmallBitVec
|
||||||
|
@ -230,6 +232,7 @@ impl ValidationData {
|
||||||
self.revalidation_match_results =
|
self.revalidation_match_results =
|
||||||
Some(stylist.match_revalidation_selectors(&element,
|
Some(stylist.match_revalidation_selectors(&element,
|
||||||
bloom_to_use,
|
bloom_to_use,
|
||||||
|
nth_index_cache,
|
||||||
flags_setter));
|
flags_setter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,11 +292,13 @@ impl<E: TElement> StyleSharingCandidate<E> {
|
||||||
&mut self,
|
&mut self,
|
||||||
stylist: &Stylist,
|
stylist: &Stylist,
|
||||||
bloom: &StyleBloom<E>,
|
bloom: &StyleBloom<E>,
|
||||||
|
nth_index_cache: &mut NthIndexCache,
|
||||||
) -> &SmallBitVec {
|
) -> &SmallBitVec {
|
||||||
self.validation_data.revalidation_match_results(
|
self.validation_data.revalidation_match_results(
|
||||||
self.element,
|
self.element,
|
||||||
stylist,
|
stylist,
|
||||||
bloom,
|
bloom,
|
||||||
|
nth_index_cache,
|
||||||
/* bloom_known_valid = */ false,
|
/* bloom_known_valid = */ false,
|
||||||
&mut |_, _| {})
|
&mut |_, _| {})
|
||||||
}
|
}
|
||||||
|
@ -346,6 +351,7 @@ impl<E: TElement> StyleSharingTarget<E> {
|
||||||
&mut self,
|
&mut self,
|
||||||
stylist: &Stylist,
|
stylist: &Stylist,
|
||||||
bloom: &StyleBloom<E>,
|
bloom: &StyleBloom<E>,
|
||||||
|
nth_index_cache: &mut NthIndexCache,
|
||||||
selector_flags_map: &mut SelectorFlagsMap<E>
|
selector_flags_map: &mut SelectorFlagsMap<E>
|
||||||
) -> &SmallBitVec {
|
) -> &SmallBitVec {
|
||||||
// It's important to set the selector flags. Otherwise, if we succeed in
|
// It's important to set the selector flags. Otherwise, if we succeed in
|
||||||
|
@ -372,6 +378,7 @@ impl<E: TElement> StyleSharingTarget<E> {
|
||||||
self.element,
|
self.element,
|
||||||
stylist,
|
stylist,
|
||||||
bloom,
|
bloom,
|
||||||
|
nth_index_cache,
|
||||||
/* bloom_known_valid = */ true,
|
/* bloom_known_valid = */ true,
|
||||||
&mut set_selector_flags)
|
&mut set_selector_flags)
|
||||||
}
|
}
|
||||||
|
@ -385,6 +392,7 @@ impl<E: TElement> StyleSharingTarget<E> {
|
||||||
let shared_context = &context.shared;
|
let shared_context = &context.shared;
|
||||||
let selector_flags_map = &mut context.thread_local.selector_flags;
|
let selector_flags_map = &mut context.thread_local.selector_flags;
|
||||||
let bloom_filter = &context.thread_local.bloom_filter;
|
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() {
|
if cache.dom_depth != bloom_filter.matching_depth() {
|
||||||
debug!("Can't share style, because DOM depth changed from {:?} to {:?}, element: {:?}",
|
debug!("Can't share style, because DOM depth changed from {:?} to {:?}, element: {:?}",
|
||||||
|
@ -398,6 +406,7 @@ impl<E: TElement> StyleSharingTarget<E> {
|
||||||
shared_context,
|
shared_context,
|
||||||
selector_flags_map,
|
selector_flags_map,
|
||||||
bloom_filter,
|
bloom_filter,
|
||||||
|
nth_index_cache,
|
||||||
self
|
self
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -415,7 +424,7 @@ struct SharingCacheBase<Candidate> {
|
||||||
impl<Candidate> Default for SharingCacheBase<Candidate> {
|
impl<Candidate> Default for SharingCacheBase<Candidate> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
entries: LRUCache::new(),
|
entries: LRUCache::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,29 +451,6 @@ impl<E: TElement> SharingCache<E> {
|
||||||
};
|
};
|
||||||
self.entries.insert(StyleSharingCandidate { element, validation_data });
|
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
|
/// 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,
|
shared_context: &SharedStyleContext,
|
||||||
selector_flags_map: &mut SelectorFlagsMap<E>,
|
selector_flags_map: &mut SelectorFlagsMap<E>,
|
||||||
bloom_filter: &StyleBloom<E>,
|
bloom_filter: &StyleBloom<E>,
|
||||||
|
nth_index_cache: &mut NthIndexCache,
|
||||||
target: &mut StyleSharingTarget<E>,
|
target: &mut StyleSharingTarget<E>,
|
||||||
) -> Option<ResolvedElementStyles> {
|
) -> Option<ResolvedElementStyles> {
|
||||||
if shared_context.options.disable_style_sharing_cache {
|
if shared_context.options.disable_style_sharing_cache {
|
||||||
|
@ -638,12 +625,13 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cache_mut().lookup(|candidate| {
|
self.cache_mut().entries.lookup(|candidate| {
|
||||||
Self::test_candidate(
|
Self::test_candidate(
|
||||||
target,
|
target,
|
||||||
candidate,
|
candidate,
|
||||||
&shared_context,
|
&shared_context,
|
||||||
bloom_filter,
|
bloom_filter,
|
||||||
|
nth_index_cache,
|
||||||
selector_flags_map
|
selector_flags_map
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -654,6 +642,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
candidate: &mut StyleSharingCandidate<E>,
|
candidate: &mut StyleSharingCandidate<E>,
|
||||||
shared: &SharedStyleContext,
|
shared: &SharedStyleContext,
|
||||||
bloom: &StyleBloom<E>,
|
bloom: &StyleBloom<E>,
|
||||||
|
nth_index_cache: &mut NthIndexCache,
|
||||||
selector_flags_map: &mut SelectorFlagsMap<E>
|
selector_flags_map: &mut SelectorFlagsMap<E>
|
||||||
) -> Option<ResolvedElementStyles> {
|
) -> Option<ResolvedElementStyles> {
|
||||||
// Check that we have the same parent, or at least that the parents
|
// 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,
|
if !checks::revalidate(target, candidate, shared, bloom,
|
||||||
selector_flags_map) {
|
nth_index_cache, selector_flags_map) {
|
||||||
trace!("Miss: Revalidation");
|
trace!("Miss: Revalidation");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -755,7 +744,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cache_mut().lookup(|candidate| {
|
self.cache_mut().entries.lookup(|candidate| {
|
||||||
debug_assert_ne!(candidate.element, target);
|
debug_assert_ne!(candidate.element, target);
|
||||||
if !candidate.parent_style_identity().eq(inherited) {
|
if !candidate.parent_style_identity().eq(inherited) {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -413,10 +413,12 @@ where
|
||||||
|
|
||||||
let map = &mut self.context.thread_local.selector_flags;
|
let map = &mut self.context.thread_local.selector_flags;
|
||||||
let bloom_filter = self.context.thread_local.bloom_filter.filter();
|
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 =
|
let mut matching_context =
|
||||||
MatchingContext::new_for_visited(
|
MatchingContext::new_for_visited(
|
||||||
MatchingMode::Normal,
|
MatchingMode::Normal,
|
||||||
Some(bloom_filter),
|
Some(bloom_filter),
|
||||||
|
Some(nth_index_cache),
|
||||||
visited_handling,
|
visited_handling,
|
||||||
self.context.shared.quirks_mode(),
|
self.context.shared.quirks_mode(),
|
||||||
);
|
);
|
||||||
|
@ -486,11 +488,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
let bloom_filter = self.context.thread_local.bloom_filter.filter();
|
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 =
|
let mut matching_context =
|
||||||
MatchingContext::new_for_visited(
|
MatchingContext::new_for_visited(
|
||||||
MatchingMode::ForStatelessPseudoElement,
|
MatchingMode::ForStatelessPseudoElement,
|
||||||
Some(bloom_filter),
|
Some(bloom_filter),
|
||||||
|
Some(nth_index_cache),
|
||||||
visited_handling,
|
visited_handling,
|
||||||
self.context.shared.quirks_mode(),
|
self.context.shared.quirks_mode(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -30,7 +30,7 @@ use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
|
||||||
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
|
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
|
||||||
use selectors::attr::NamespaceConstraint;
|
use selectors::attr::NamespaceConstraint;
|
||||||
use selectors::bloom::{BloomFilter, NonCountingBloomFilter};
|
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::matching::VisitedHandlingMode;
|
||||||
use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
|
use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
|
||||||
use selectors::parser::{SelectorIter, SelectorMethods};
|
use selectors::parser::{SelectorIter, SelectorMethods};
|
||||||
|
@ -1027,6 +1027,7 @@ impl Stylist {
|
||||||
let mut declarations = ApplicableDeclarationList::new();
|
let mut declarations = ApplicableDeclarationList::new();
|
||||||
let mut matching_context =
|
let mut matching_context =
|
||||||
MatchingContext::new(MatchingMode::ForStatelessPseudoElement,
|
MatchingContext::new(MatchingMode::ForStatelessPseudoElement,
|
||||||
|
None,
|
||||||
None,
|
None,
|
||||||
self.quirks_mode);
|
self.quirks_mode);
|
||||||
|
|
||||||
|
@ -1061,6 +1062,7 @@ impl Stylist {
|
||||||
MatchingContext::new_for_visited(
|
MatchingContext::new_for_visited(
|
||||||
MatchingMode::ForStatelessPseudoElement,
|
MatchingMode::ForStatelessPseudoElement,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
VisitedHandlingMode::RelevantLinkVisited,
|
VisitedHandlingMode::RelevantLinkVisited,
|
||||||
self.quirks_mode,
|
self.quirks_mode,
|
||||||
);
|
);
|
||||||
|
@ -1203,7 +1205,7 @@ impl Stylist {
|
||||||
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
|
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
|
||||||
{
|
{
|
||||||
let mut matching_context =
|
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 mut dummy_flag_setter = |_: &E, _: ElementSelectorFlags| {};
|
||||||
|
|
||||||
let rule_hash_target = element.rule_hash_target();
|
let rule_hash_target = element.rule_hash_target();
|
||||||
|
@ -1427,6 +1429,7 @@ impl Stylist {
|
||||||
&self,
|
&self,
|
||||||
element: &E,
|
element: &E,
|
||||||
bloom: Option<&BloomFilter>,
|
bloom: Option<&BloomFilter>,
|
||||||
|
nth_index_cache: &mut NthIndexCache,
|
||||||
flags_setter: &mut F
|
flags_setter: &mut F
|
||||||
) -> SmallBitVec
|
) -> SmallBitVec
|
||||||
where
|
where
|
||||||
|
@ -1435,8 +1438,12 @@ impl Stylist {
|
||||||
{
|
{
|
||||||
// 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.
|
||||||
let mut matching_context =
|
let mut matching_context = MatchingContext::new(
|
||||||
MatchingContext::new(MatchingMode::Normal, bloom, self.quirks_mode);
|
MatchingMode::Normal,
|
||||||
|
bloom,
|
||||||
|
Some(nth_index_cache),
|
||||||
|
self.quirks_mode
|
||||||
|
);
|
||||||
|
|
||||||
// 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
|
||||||
// candidate and the entry have the same id, classes, and local name.
|
// candidate and the entry have the same id, classes, and local name.
|
||||||
|
|
|
@ -1503,7 +1503,7 @@ pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(rule: RawServoStyleRule
|
||||||
};
|
};
|
||||||
|
|
||||||
let element = GeckoElement(element);
|
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 |_, _| {})
|
matches_selector(selector, 0, None, &element, &mut ctx, &mut |_, _| {})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue