mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Move the ancestor hashes out of Selector.
MozReview-Commit-ID: 5mipXnjgSED
This commit is contained in:
parent
e3d3c5a7b2
commit
713c9a63f6
8 changed files with 153 additions and 79 deletions
|
@ -2061,7 +2061,7 @@ impl ElementMethods for Element {
|
||||||
Err(()) => Err(Error::Syntax),
|
Err(()) => Err(Error::Syntax),
|
||||||
Ok(selectors) => {
|
Ok(selectors) => {
|
||||||
let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
||||||
Ok(matches_selector_list(&selectors.0, &Root::from_ref(self), &mut ctx))
|
Ok(matches_selector_list(&selectors, &Root::from_ref(self), &mut ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2080,7 +2080,7 @@ 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 mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
||||||
if matches_selector_list(&selectors.0, &element, &mut ctx) {
|
if matches_selector_list(&selectors, &element, &mut ctx) {
|
||||||
return Ok(Some(element));
|
return Ok(Some(element));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,7 +345,7 @@ impl<'a> Iterator for QuerySelectorIterator {
|
||||||
type Item = Root<Node>;
|
type Item = Root<Node>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Root<Node>> {
|
fn next(&mut self) -> Option<Root<Node>> {
|
||||||
let selectors = &self.selectors.0;
|
let selectors = &self.selectors;
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -722,7 +722,7 @@ impl Node {
|
||||||
Ok(selectors) => {
|
Ok(selectors) => {
|
||||||
let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
|
||||||
Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
|
Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
|
||||||
matches_selector_list(&selectors.0, element, &mut ctx)
|
matches_selector_list(&selectors, element, &mut ctx)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
|
use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
|
||||||
use bloom::BloomFilter;
|
use bloom::BloomFilter;
|
||||||
use parser::{Combinator, ComplexSelector, Component, LocalName};
|
use parser::{AncestorHashes, Combinator, ComplexSelector, Component, LocalName};
|
||||||
use parser::{Selector, SelectorInner, SelectorIter};
|
use parser::{SelectorInner, SelectorIter, SelectorList};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use tree::Element;
|
use tree::Element;
|
||||||
|
|
||||||
|
@ -152,27 +152,29 @@ impl<'a> MatchingContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches_selector_list<E>(selector_list: &[Selector<E::Impl>],
|
pub fn matches_selector_list<E>(selector_list: &SelectorList<E::Impl>,
|
||||||
element: &E,
|
element: &E,
|
||||||
context: &mut MatchingContext)
|
context: &mut MatchingContext)
|
||||||
-> bool
|
-> bool
|
||||||
where E: Element
|
where E: Element
|
||||||
{
|
{
|
||||||
selector_list.iter().any(|selector| {
|
selector_list.0.iter().any(|selector_and_hashes| {
|
||||||
matches_selector(&selector.inner,
|
matches_selector(&selector_and_hashes.selector.inner,
|
||||||
|
&selector_and_hashes.hashes,
|
||||||
element,
|
element,
|
||||||
context,
|
context,
|
||||||
&mut |_, _| {})
|
&mut |_, _| {})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn may_match<E>(sel: &SelectorInner<E::Impl>,
|
#[inline(always)]
|
||||||
|
fn may_match<E>(hashes: &AncestorHashes,
|
||||||
bf: &BloomFilter)
|
bf: &BloomFilter)
|
||||||
-> bool
|
-> bool
|
||||||
where E: Element,
|
where E: Element,
|
||||||
{
|
{
|
||||||
// Check against the list of precomputed hashes.
|
// Check against the list of precomputed hashes.
|
||||||
for hash in sel.ancestor_hashes.iter() {
|
for hash in hashes.0.iter() {
|
||||||
// If we hit the 0 sentinel hash, that means the rest are zero as well.
|
// If we hit the 0 sentinel hash, that means the rest are zero as well.
|
||||||
if *hash == 0 {
|
if *hash == 0 {
|
||||||
break;
|
break;
|
||||||
|
@ -330,8 +332,10 @@ enum SelectorMatchingResult {
|
||||||
NotMatchedGlobally,
|
NotMatchedGlobally,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches an inner selector.
|
/// Matches a selector, fast-rejecting against a bloom filter.
|
||||||
|
#[inline(always)]
|
||||||
pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
|
pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
|
||||||
|
hashes: &AncestorHashes,
|
||||||
element: &E,
|
element: &E,
|
||||||
context: &mut MatchingContext,
|
context: &mut MatchingContext,
|
||||||
flags_setter: &mut F)
|
flags_setter: &mut F)
|
||||||
|
@ -341,7 +345,7 @@ pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
|
||||||
{
|
{
|
||||||
// Use the bloom filter to fast-reject.
|
// Use the bloom filter to fast-reject.
|
||||||
if let Some(filter) = context.bloom_filter {
|
if let Some(filter) = context.bloom_filter {
|
||||||
if !may_match::<E>(&selector, filter) {
|
if !may_match::<E>(hashes, filter) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,27 @@ pub trait Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct SelectorList<Impl: SelectorImpl>(pub Vec<Selector<Impl>>);
|
pub struct SelectorAndHashes<Impl: SelectorImpl> {
|
||||||
|
pub selector: Selector<Impl>,
|
||||||
|
pub hashes: AncestorHashes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Impl: SelectorImpl> SelectorAndHashes<Impl> {
|
||||||
|
pub fn new(selector: Selector<Impl>) -> Self {
|
||||||
|
let hashes = AncestorHashes::new(&selector);
|
||||||
|
Self::new_with_hashes(selector, hashes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_hashes(selector: Selector<Impl>, hashes: AncestorHashes) -> Self {
|
||||||
|
SelectorAndHashes {
|
||||||
|
selector: selector,
|
||||||
|
hashes: hashes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
pub struct SelectorList<Impl: SelectorImpl>(pub Vec<SelectorAndHashes<Impl>>);
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> SelectorList<Impl> {
|
impl<Impl: SelectorImpl> SelectorList<Impl> {
|
||||||
/// Parse a comma-separated list of Selectors.
|
/// Parse a comma-separated list of Selectors.
|
||||||
|
@ -139,14 +159,41 @@ impl<Impl: SelectorImpl> SelectorList<Impl> {
|
||||||
/// Return the Selectors or Err if there is an invalid selector.
|
/// Return the Selectors or Err if there is an invalid selector.
|
||||||
pub fn parse<P>(parser: &P, input: &mut CssParser) -> Result<Self, ()>
|
pub fn parse<P>(parser: &P, input: &mut CssParser) -> Result<Self, ()>
|
||||||
where P: Parser<Impl=Impl> {
|
where P: Parser<Impl=Impl> {
|
||||||
input.parse_comma_separated(|input| parse_selector(parser, input))
|
input.parse_comma_separated(|input| parse_selector(parser, input).map(SelectorAndHashes::new))
|
||||||
.map(SelectorList)
|
.map(SelectorList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copied from Gecko, where it was noted to be unmeasured.
|
/// Copied from Gecko, who copied it from WebKit. Note that increasing the
|
||||||
|
/// number of hashes here will adversely affect the cache hit when fast-
|
||||||
|
/// rejecting long lists of Rules with inline hashes.
|
||||||
const NUM_ANCESTOR_HASHES: usize = 4;
|
const NUM_ANCESTOR_HASHES: usize = 4;
|
||||||
|
|
||||||
|
/// Ancestor hashes for the bloom filter. We precompute these and store them
|
||||||
|
/// inline with selectors to optimize cache performance during matching.
|
||||||
|
/// This matters a lot.
|
||||||
|
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||||
|
pub struct AncestorHashes(pub [u32; NUM_ANCESTOR_HASHES]);
|
||||||
|
|
||||||
|
impl AncestorHashes {
|
||||||
|
pub fn new<Impl: SelectorImpl>(c: &Selector<Impl>) -> Self {
|
||||||
|
let mut hashes = [0; NUM_ANCESTOR_HASHES];
|
||||||
|
// Compute ancestor hashes for the bloom filter.
|
||||||
|
let mut hash_iter = c.inner.complex.iter_ancestors()
|
||||||
|
.map(|x| x.ancestor_hash())
|
||||||
|
.filter(|x| x.is_some())
|
||||||
|
.map(|x| x.unwrap());
|
||||||
|
for i in 0..NUM_ANCESTOR_HASHES {
|
||||||
|
hashes[i] = match hash_iter.next() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AncestorHashes(hashes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The cores parts of a selector used for matching. This exists to make that
|
/// The cores parts of a selector used for matching. This exists to make that
|
||||||
/// information accessibly separately from the specificity and pseudo-element
|
/// information accessibly separately from the specificity and pseudo-element
|
||||||
/// information that lives on |Selector| proper. We may want to refactor things
|
/// information that lives on |Selector| proper. We may want to refactor things
|
||||||
|
@ -156,32 +203,12 @@ const NUM_ANCESTOR_HASHES: usize = 4;
|
||||||
pub struct SelectorInner<Impl: SelectorImpl> {
|
pub struct SelectorInner<Impl: SelectorImpl> {
|
||||||
/// The selector data.
|
/// The selector data.
|
||||||
pub complex: ComplexSelector<Impl>,
|
pub complex: ComplexSelector<Impl>,
|
||||||
/// Ancestor hashes for the bloom filter. We precompute these and store
|
|
||||||
/// them inline to optimize cache performance during selector matching.
|
|
||||||
/// This matters a lot.
|
|
||||||
pub ancestor_hashes: [u32; NUM_ANCESTOR_HASHES],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> SelectorInner<Impl> {
|
impl<Impl: SelectorImpl> SelectorInner<Impl> {
|
||||||
pub fn new(c: ComplexSelector<Impl>) -> Self {
|
pub fn new(c: ComplexSelector<Impl>) -> Self {
|
||||||
let mut hashes = [0; NUM_ANCESTOR_HASHES];
|
|
||||||
{
|
|
||||||
// Compute ancestor hashes for the bloom filter.
|
|
||||||
let mut hash_iter = c.iter_ancestors()
|
|
||||||
.map(|x| x.ancestor_hash())
|
|
||||||
.filter(|x| x.is_some())
|
|
||||||
.map(|x| x.unwrap());
|
|
||||||
for i in 0..NUM_ANCESTOR_HASHES {
|
|
||||||
hashes[i] = match hash_iter.next() {
|
|
||||||
Some(x) => x,
|
|
||||||
None => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectorInner {
|
SelectorInner {
|
||||||
complex: c,
|
complex: c,
|
||||||
ancestor_hashes: hashes,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,7 +617,7 @@ pub enum Component<Impl: SelectorImpl> {
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> Component<Impl> {
|
impl<Impl: SelectorImpl> Component<Impl> {
|
||||||
/// Compute the ancestor hash to check against the bloom filter.
|
/// Compute the ancestor hash to check against the bloom filter.
|
||||||
fn ancestor_hash(&self) -> Option<u32> {
|
pub fn ancestor_hash(&self) -> Option<u32> {
|
||||||
match *self {
|
match *self {
|
||||||
Component::LocalName(LocalName { ref name, ref lower_name }) => {
|
Component::LocalName(LocalName { ref name, ref lower_name }) => {
|
||||||
// Only insert the local-name into the filter if it's all lowercase.
|
// Only insert the local-name into the filter if it's all lowercase.
|
||||||
|
@ -665,10 +692,10 @@ impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
|
||||||
let mut iter = self.0.iter();
|
let mut iter = self.0.iter();
|
||||||
let first = iter.next()
|
let first = iter.next()
|
||||||
.expect("Empty SelectorList, should contain at least one selector");
|
.expect("Empty SelectorList, should contain at least one selector");
|
||||||
first.to_css(dest)?;
|
first.selector.to_css(dest)?;
|
||||||
for selector in iter {
|
for selector_and_hashes in iter {
|
||||||
dest.write_str(", ")?;
|
dest.write_str(", ")?;
|
||||||
selector.to_css(dest)?;
|
selector_and_hashes.selector.to_css(dest)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,8 +262,8 @@ impl StylesheetInvalidationSet {
|
||||||
match *rule {
|
match *rule {
|
||||||
Style(ref lock) => {
|
Style(ref lock) => {
|
||||||
let style_rule = lock.read_with(guard);
|
let style_rule = lock.read_with(guard);
|
||||||
for selector in &style_rule.selectors.0 {
|
for selector_and_hashes in &style_rule.selectors.0 {
|
||||||
self.collect_scopes(selector);
|
self.collect_scopes(&selector_and_hashes.selector);
|
||||||
if self.fully_invalid {
|
if self.fully_invalid {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,8 @@ use selectors::Element;
|
||||||
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
|
||||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
||||||
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode, matches_selector};
|
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode, matches_selector};
|
||||||
use selectors::parser::{Combinator, Component, Selector, SelectorInner, SelectorMethods};
|
use selectors::parser::{AncestorHashes, Combinator, Component};
|
||||||
|
use selectors::parser::{Selector, SelectorAndHashes, SelectorInner, SelectorMethods};
|
||||||
use selectors::visitor::SelectorVisitor;
|
use selectors::visitor::SelectorVisitor;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -867,7 +868,9 @@ impl Sensitivities {
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct Dependency {
|
pub struct Dependency {
|
||||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||||
selector: SelectorInner<SelectorImpl>,
|
selector: Selector<SelectorImpl>,
|
||||||
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "No heap data")]
|
||||||
|
hashes: AncestorHashes,
|
||||||
/// The hint associated with this dependency.
|
/// The hint associated with this dependency.
|
||||||
pub hint: RestyleHint,
|
pub hint: RestyleHint,
|
||||||
/// The sensitivities associated with this dependency.
|
/// The sensitivities associated with this dependency.
|
||||||
|
@ -875,9 +878,13 @@ pub struct Dependency {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectorMapEntry for Dependency {
|
impl SelectorMapEntry for Dependency {
|
||||||
fn selector(&self) -> &SelectorInner<SelectorImpl> {
|
fn selector(&self) -> &Selector<SelectorImpl> {
|
||||||
&self.selector
|
&self.selector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hashes(&self) -> &AncestorHashes {
|
||||||
|
&self.hashes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The following visitor visits all the simple selectors for a given complex
|
/// The following visitor visits all the simple selectors for a given complex
|
||||||
|
@ -940,9 +947,9 @@ pub enum HintComputationContext<'a, E: 'a>
|
||||||
|
|
||||||
impl DependencySet {
|
impl DependencySet {
|
||||||
/// Adds a selector to this `DependencySet`.
|
/// Adds a selector to this `DependencySet`.
|
||||||
pub fn note_selector(&mut self, selector: &Selector<SelectorImpl>) {
|
pub fn note_selector(&mut self, selector_and_hashes: &SelectorAndHashes<SelectorImpl>) {
|
||||||
let mut combinator = None;
|
let mut combinator = None;
|
||||||
let mut iter = selector.inner.complex.iter();
|
let mut iter = selector_and_hashes.selector.inner.complex.iter();
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
let mut child_combinators_seen = 0;
|
let mut child_combinators_seen = 0;
|
||||||
let mut saw_descendant_combinator = false;
|
let mut saw_descendant_combinator = false;
|
||||||
|
@ -992,17 +999,25 @@ impl DependencySet {
|
||||||
None => RestyleHint::for_self(),
|
None => RestyleHint::for_self(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let dep_selector = if sequence_start == 0 {
|
let (dep_selector, hashes) = if sequence_start == 0 {
|
||||||
// Reuse the bloom hashes if this is the base selector.
|
// Reuse the bloom hashes if this is the base selector.
|
||||||
selector.inner.clone()
|
(selector_and_hashes.selector.clone(),
|
||||||
|
selector_and_hashes.hashes.clone())
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
SelectorInner::new(selector.inner.complex.slice_from(sequence_start))
|
let inner = SelectorInner::new(selector_and_hashes.selector
|
||||||
|
.inner
|
||||||
|
.complex.slice_from(sequence_start));
|
||||||
|
let selector = Selector { inner: inner };
|
||||||
|
let hashes = AncestorHashes::new(&selector);
|
||||||
|
(selector, hashes)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.dependencies.insert(Dependency {
|
self.dependencies.insert(Dependency {
|
||||||
sensitivities: visitor.sensitivities,
|
sensitivities: visitor.sensitivities,
|
||||||
hint: hint,
|
hint: hint,
|
||||||
selector: dep_selector,
|
selector: dep_selector,
|
||||||
|
hashes: hashes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1130,14 +1145,18 @@ impl DependencySet {
|
||||||
MatchingContext::new_for_visited(MatchingMode::Normal, None,
|
MatchingContext::new_for_visited(MatchingMode::Normal, None,
|
||||||
VisitedHandlingMode::AllLinksUnvisited);
|
VisitedHandlingMode::AllLinksUnvisited);
|
||||||
let matched_then =
|
let matched_then =
|
||||||
matches_selector(&dep.selector, &snapshot_el,
|
matches_selector(&dep.selector.inner,
|
||||||
|
&dep.hashes,
|
||||||
|
&snapshot_el,
|
||||||
&mut then_context,
|
&mut then_context,
|
||||||
&mut |_, _| {});
|
&mut |_, _| {});
|
||||||
let mut now_context =
|
let mut now_context =
|
||||||
MatchingContext::new_for_visited(MatchingMode::Normal, bloom_filter,
|
MatchingContext::new_for_visited(MatchingMode::Normal, bloom_filter,
|
||||||
VisitedHandlingMode::AllLinksUnvisited);
|
VisitedHandlingMode::AllLinksUnvisited);
|
||||||
let matches_now =
|
let matches_now =
|
||||||
matches_selector(&dep.selector, el,
|
matches_selector(&dep.selector.inner,
|
||||||
|
&dep.hashes,
|
||||||
|
el,
|
||||||
&mut now_context,
|
&mut now_context,
|
||||||
&mut |_, _| {});
|
&mut |_, _| {});
|
||||||
|
|
||||||
|
@ -1162,12 +1181,16 @@ impl DependencySet {
|
||||||
dep.sensitivities.states.intersects(IN_VISITED_OR_UNVISITED_STATE) {
|
dep.sensitivities.states.intersects(IN_VISITED_OR_UNVISITED_STATE) {
|
||||||
then_context.visited_handling = VisitedHandlingMode::RelevantLinkVisited;
|
then_context.visited_handling = VisitedHandlingMode::RelevantLinkVisited;
|
||||||
let matched_then =
|
let matched_then =
|
||||||
matches_selector(&dep.selector, &snapshot_el,
|
matches_selector(&dep.selector.inner,
|
||||||
|
&dep.hashes,
|
||||||
|
&snapshot_el,
|
||||||
&mut then_context,
|
&mut then_context,
|
||||||
&mut |_, _| {});
|
&mut |_, _| {});
|
||||||
now_context.visited_handling = VisitedHandlingMode::RelevantLinkVisited;
|
now_context.visited_handling = VisitedHandlingMode::RelevantLinkVisited;
|
||||||
let matches_now =
|
let matches_now =
|
||||||
matches_selector(&dep.selector, el,
|
matches_selector(&dep.selector.inner,
|
||||||
|
&dep.hashes,
|
||||||
|
el,
|
||||||
&mut now_context,
|
&mut now_context,
|
||||||
&mut |_, _| {});
|
&mut |_, _| {});
|
||||||
if matched_then != matches_now {
|
if matched_then != matches_now {
|
||||||
|
|
|
@ -12,7 +12,7 @@ use pdqsort::sort_by;
|
||||||
use rule_tree::CascadeLevel;
|
use rule_tree::CascadeLevel;
|
||||||
use selector_parser::SelectorImpl;
|
use selector_parser::SelectorImpl;
|
||||||
use selectors::matching::{matches_selector, MatchingContext, ElementSelectorFlags};
|
use selectors::matching::{matches_selector, MatchingContext, ElementSelectorFlags};
|
||||||
use selectors::parser::{Component, Combinator, SelectorInner};
|
use selectors::parser::{AncestorHashes, Component, Combinator, Selector, SelectorAndHashes};
|
||||||
use selectors::parser::LocalName as LocalNameSelector;
|
use selectors::parser::LocalName as LocalNameSelector;
|
||||||
use smallvec::VecLike;
|
use smallvec::VecLike;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
@ -22,13 +22,20 @@ use stylist::{ApplicableDeclarationBlock, Rule};
|
||||||
|
|
||||||
/// A trait to abstract over a given selector map entry.
|
/// A trait to abstract over a given selector map entry.
|
||||||
pub trait SelectorMapEntry : Sized + Clone {
|
pub trait SelectorMapEntry : Sized + Clone {
|
||||||
/// Get the selector we should use to index in the selector map.
|
/// Gets the selector we should use to index in the selector map.
|
||||||
fn selector(&self) -> &SelectorInner<SelectorImpl>;
|
fn selector(&self) -> &Selector<SelectorImpl>;
|
||||||
|
|
||||||
|
/// Gets the ancestor hashes associated with the selector.
|
||||||
|
fn hashes(&self) -> &AncestorHashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectorMapEntry for SelectorInner<SelectorImpl> {
|
impl SelectorMapEntry for SelectorAndHashes<SelectorImpl> {
|
||||||
fn selector(&self) -> &SelectorInner<SelectorImpl> {
|
fn selector(&self) -> &Selector<SelectorImpl> {
|
||||||
self
|
&self.selector
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hashes(&self) -> &AncestorHashes {
|
||||||
|
&self.hashes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +232,7 @@ impl SelectorMap<Rule> {
|
||||||
{
|
{
|
||||||
for rule in rules {
|
for rule in rules {
|
||||||
if matches_selector(&rule.selector.inner,
|
if matches_selector(&rule.selector.inner,
|
||||||
|
&rule.hashes,
|
||||||
element,
|
element,
|
||||||
context,
|
context,
|
||||||
flags_setter) {
|
flags_setter) {
|
||||||
|
@ -390,12 +398,12 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
///
|
///
|
||||||
/// Effectively, pseudo-elements are ignored, given only state pseudo-classes
|
/// Effectively, pseudo-elements are ignored, given only state pseudo-classes
|
||||||
/// may appear before them.
|
/// may appear before them.
|
||||||
fn find_from_right<F, R>(selector: &SelectorInner<SelectorImpl>,
|
fn find_from_right<F, R>(selector: &Selector<SelectorImpl>,
|
||||||
mut f: F)
|
mut f: F)
|
||||||
-> Option<R>
|
-> Option<R>
|
||||||
where F: FnMut(&Component<SelectorImpl>) -> Option<R>,
|
where F: FnMut(&Component<SelectorImpl>) -> Option<R>,
|
||||||
{
|
{
|
||||||
let mut iter = selector.complex.iter();
|
let mut iter = selector.inner.complex.iter();
|
||||||
for ss in &mut iter {
|
for ss in &mut iter {
|
||||||
if let Some(r) = f(ss) {
|
if let Some(r) = f(ss) {
|
||||||
return Some(r)
|
return Some(r)
|
||||||
|
@ -414,7 +422,7 @@ fn find_from_right<F, R>(selector: &SelectorInner<SelectorImpl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the first ID name in the selector, or None otherwise.
|
/// Retrieve the first ID name in the selector, or None otherwise.
|
||||||
pub fn get_id_name(selector: &SelectorInner<SelectorImpl>)
|
pub fn get_id_name(selector: &Selector<SelectorImpl>)
|
||||||
-> Option<Atom> {
|
-> Option<Atom> {
|
||||||
find_from_right(selector, |ss| {
|
find_from_right(selector, |ss| {
|
||||||
// TODO(pradeep): Implement case-sensitivity based on the
|
// TODO(pradeep): Implement case-sensitivity based on the
|
||||||
|
@ -427,7 +435,7 @@ pub fn get_id_name(selector: &SelectorInner<SelectorImpl>)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the FIRST class name in the selector, or None otherwise.
|
/// Retrieve the FIRST class name in the selector, or None otherwise.
|
||||||
pub fn get_class_name(selector: &SelectorInner<SelectorImpl>)
|
pub fn get_class_name(selector: &Selector<SelectorImpl>)
|
||||||
-> Option<Atom> {
|
-> Option<Atom> {
|
||||||
find_from_right(selector, |ss| {
|
find_from_right(selector, |ss| {
|
||||||
// TODO(pradeep): Implement case-sensitivity based on the
|
// TODO(pradeep): Implement case-sensitivity based on the
|
||||||
|
@ -440,7 +448,7 @@ pub fn get_class_name(selector: &SelectorInner<SelectorImpl>)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the name if it is a type selector, or None otherwise.
|
/// Retrieve the name if it is a type selector, or None otherwise.
|
||||||
pub fn get_local_name(selector: &SelectorInner<SelectorImpl>)
|
pub fn get_local_name(selector: &Selector<SelectorImpl>)
|
||||||
-> Option<LocalNameSelector<SelectorImpl>> {
|
-> Option<LocalNameSelector<SelectorImpl>> {
|
||||||
find_from_right(selector, |ss| {
|
find_from_right(selector, |ss| {
|
||||||
if let Component::LocalName(ref n) = *ss {
|
if let Component::LocalName(ref n) = *ss {
|
||||||
|
|
|
@ -28,7 +28,8 @@ use selectors::attr::NamespaceConstraint;
|
||||||
use selectors::bloom::BloomFilter;
|
use selectors::bloom::BloomFilter;
|
||||||
use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode};
|
use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode};
|
||||||
use selectors::matching::AFFECTED_BY_PRESENTATIONAL_HINTS;
|
use selectors::matching::AFFECTED_BY_PRESENTATIONAL_HINTS;
|
||||||
use selectors::parser::{Combinator, Component, Selector, SelectorInner, SelectorIter, SelectorMethods};
|
use selectors::parser::{AncestorHashes, Combinator, Component, Selector, SelectorAndHashes};
|
||||||
|
use selectors::parser::{SelectorIter, SelectorMethods};
|
||||||
use selectors::visitor::SelectorVisitor;
|
use selectors::visitor::SelectorVisitor;
|
||||||
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
||||||
use sink::Push;
|
use sink::Push;
|
||||||
|
@ -159,7 +160,7 @@ pub struct Stylist {
|
||||||
/// on state that is not otherwise visible to the cache, like attributes or
|
/// on state that is not otherwise visible to the cache, like attributes or
|
||||||
/// tree-structural state like child index and pseudos).
|
/// tree-structural state like child index and pseudos).
|
||||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||||
selectors_for_cache_revalidation: SelectorMap<SelectorInner<SelectorImpl>>,
|
selectors_for_cache_revalidation: SelectorMap<SelectorAndHashes<SelectorImpl>>,
|
||||||
|
|
||||||
/// The total number of selectors.
|
/// The total number of selectors.
|
||||||
num_selectors: usize,
|
num_selectors: usize,
|
||||||
|
@ -454,10 +455,10 @@ impl Stylist {
|
||||||
CssRule::Style(ref locked) => {
|
CssRule::Style(ref locked) => {
|
||||||
let style_rule = locked.read_with(&guard);
|
let style_rule = locked.read_with(&guard);
|
||||||
self.num_declarations += style_rule.block.read_with(&guard).len();
|
self.num_declarations += style_rule.block.read_with(&guard).len();
|
||||||
for selector in &style_rule.selectors.0 {
|
for selector_and_hashes in &style_rule.selectors.0 {
|
||||||
self.num_selectors += 1;
|
self.num_selectors += 1;
|
||||||
|
|
||||||
let map = if let Some(pseudo) = selector.pseudo_element() {
|
let map = if let Some(pseudo) = selector_and_hashes.selector.pseudo_element() {
|
||||||
self.pseudos_map
|
self.pseudos_map
|
||||||
.entry(pseudo.canonical())
|
.entry(pseudo.canonical())
|
||||||
.or_insert_with(PerPseudoElementSelectorMap::new)
|
.or_insert_with(PerPseudoElementSelectorMap::new)
|
||||||
|
@ -466,20 +467,21 @@ impl Stylist {
|
||||||
self.element_map.borrow_for_origin(&stylesheet.origin)
|
self.element_map.borrow_for_origin(&stylesheet.origin)
|
||||||
};
|
};
|
||||||
|
|
||||||
map.insert(Rule::new(selector.clone(),
|
map.insert(Rule::new(selector_and_hashes.selector.clone(),
|
||||||
|
selector_and_hashes.hashes.clone(),
|
||||||
locked.clone(),
|
locked.clone(),
|
||||||
self.rules_source_order));
|
self.rules_source_order));
|
||||||
|
|
||||||
self.dependencies.note_selector(selector);
|
self.dependencies.note_selector(selector_and_hashes);
|
||||||
if needs_revalidation(selector) {
|
if needs_revalidation(&selector_and_hashes.selector) {
|
||||||
self.selectors_for_cache_revalidation.insert(selector.inner.clone());
|
self.selectors_for_cache_revalidation.insert(selector_and_hashes.clone());
|
||||||
}
|
}
|
||||||
selector.visit(&mut AttributeAndStateDependencyVisitor {
|
selector_and_hashes.selector.visit(&mut AttributeAndStateDependencyVisitor {
|
||||||
attribute_dependencies: &mut self.attribute_dependencies,
|
attribute_dependencies: &mut self.attribute_dependencies,
|
||||||
style_attribute_dependency: &mut self.style_attribute_dependency,
|
style_attribute_dependency: &mut self.style_attribute_dependency,
|
||||||
state_dependencies: &mut self.state_dependencies,
|
state_dependencies: &mut self.state_dependencies,
|
||||||
});
|
});
|
||||||
selector.visit(&mut MappedIdVisitor {
|
selector_and_hashes.selector.visit(&mut MappedIdVisitor {
|
||||||
mapped_ids: &mut self.mapped_ids,
|
mapped_ids: &mut self.mapped_ids,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1130,8 +1132,9 @@ impl Stylist {
|
||||||
// the lookups, which means that the bitvecs are comparable. We verify
|
// the lookups, which means that the bitvecs are comparable. We verify
|
||||||
// this in the caller by asserting that the bitvecs are same-length.
|
// this in the caller by asserting that the bitvecs are same-length.
|
||||||
let mut results = BitVec::new();
|
let mut results = BitVec::new();
|
||||||
self.selectors_for_cache_revalidation.lookup(*element, &mut |selector| {
|
self.selectors_for_cache_revalidation.lookup(*element, &mut |selector_and_hashes| {
|
||||||
results.push(matches_selector(selector,
|
results.push(matches_selector(&selector_and_hashes.selector.inner,
|
||||||
|
&selector_and_hashes.hashes,
|
||||||
element,
|
element,
|
||||||
&mut matching_context,
|
&mut matching_context,
|
||||||
flags_setter));
|
flags_setter));
|
||||||
|
@ -1410,6 +1413,9 @@ pub struct Rule {
|
||||||
/// can ruin performance when there are a lot of rules.
|
/// can ruin performance when there are a lot of rules.
|
||||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||||
pub selector: Selector<SelectorImpl>,
|
pub selector: Selector<SelectorImpl>,
|
||||||
|
/// The ancestor hashes associated with the selector.
|
||||||
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "No heap data")]
|
||||||
|
pub hashes: AncestorHashes,
|
||||||
/// The actual style rule.
|
/// The actual style rule.
|
||||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||||
pub style_rule: Arc<Locked<StyleRule>>,
|
pub style_rule: Arc<Locked<StyleRule>>,
|
||||||
|
@ -1418,8 +1424,12 @@ pub struct Rule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectorMapEntry for Rule {
|
impl SelectorMapEntry for Rule {
|
||||||
fn selector(&self) -> &SelectorInner<SelectorImpl> {
|
fn selector(&self) -> &Selector<SelectorImpl> {
|
||||||
&self.selector.inner
|
&self.selector
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hashes(&self) -> &AncestorHashes {
|
||||||
|
&self.hashes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1444,12 +1454,14 @@ impl Rule {
|
||||||
|
|
||||||
/// Creates a new Rule.
|
/// Creates a new Rule.
|
||||||
pub fn new(selector: Selector<SelectorImpl>,
|
pub fn new(selector: Selector<SelectorImpl>,
|
||||||
|
hashes: AncestorHashes,
|
||||||
style_rule: Arc<Locked<StyleRule>>,
|
style_rule: Arc<Locked<StyleRule>>,
|
||||||
source_order: usize)
|
source_order: usize)
|
||||||
-> Self
|
-> Self
|
||||||
{
|
{
|
||||||
Rule {
|
Rule {
|
||||||
selector: selector,
|
selector: selector,
|
||||||
|
hashes: hashes,
|
||||||
style_rule: style_rule,
|
style_rule: style_rule,
|
||||||
source_order: source_order,
|
source_order: source_order,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue