Auto merge of #16521 - bholley:precompute_hashes, r=emilio

Store bloom filter hashes inline in the selector

https://bugzilla.mozilla.org/show_bug.cgi?id=1357304

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16521)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-04-19 02:32:18 -05:00 committed by GitHub
commit b4bea83312
9 changed files with 227 additions and 160 deletions

View file

@ -86,7 +86,7 @@ use net_traits::request::CorsSettings;
use ref_filter_map::ref_filter_map;
use script_layout_interface::message::ReflowQueryType;
use script_thread::Runnable;
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches};
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector_list};
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
use selectors::parser::{AttrSelector, NamespaceConstraint};
use servo_atoms::Atom;
@ -2050,7 +2050,7 @@ impl ElementMethods for Element {
match SelectorParser::parse_author_origin_no_namespace(&selectors) {
Err(()) => Err(Error::Syntax),
Ok(selectors) => {
Ok(matches(&selectors.0, &Root::from_ref(self), None))
Ok(matches_selector_list(&selectors.0, &Root::from_ref(self), None))
}
}
}
@ -2068,7 +2068,7 @@ impl ElementMethods for Element {
let root = self.upcast::<Node>();
for element in root.inclusive_ancestors() {
if let Some(element) = Root::downcast::<Element>(element) {
if matches(&selectors.0, &element, None)
if matches_selector_list(&selectors.0, &element, None)
{
return Ok(Some(element));
}

View file

@ -68,7 +68,7 @@ use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddr
use script_layout_interface::message::Msg;
use script_traits::DocumentActivity;
use script_traits::UntrustedNodeAddress;
use selectors::matching::matches;
use selectors::matching::matches_selector_list;
use selectors::parser::SelectorList;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
@ -332,7 +332,7 @@ impl<'a> Iterator for QuerySelectorIterator {
// (instead of passing `None`)? Probably.
self.iterator.by_ref().filter_map(|node| {
if let Some(element) = Root::downcast(node) {
if matches(selectors, &element, None) {
if matches_selector_list(selectors, &element, None) {
return Some(Root::upcast(element));
}
}
@ -695,7 +695,7 @@ impl Node {
// Step 3.
Ok(selectors) => {
Ok(self.traverse_preorder().filter_map(Root::downcast).find(|element| {
matches(&selectors.0, element, None)
matches_selector_list(&selectors.0, element, None)
}))
}
}

View file

@ -3,8 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use bloom::BloomFilter;
use parser::{CaseSensitivity, Combinator, ComplexSelector, LocalName};
use parser::{SimpleSelector, Selector};
use precomputed_hash::PrecomputedHash;
use parser::{SimpleSelector, Selector, SelectorInner};
use std::borrow::Borrow;
use tree::Element;
@ -19,10 +18,6 @@ bitflags! {
///
/// This is used to implement efficient sharing.
pub flags StyleRelations: u16 {
/// Whether this element has matched any rule that is determined by a
/// sibling (when using the `+` or `~` combinators).
const AFFECTED_BY_SIBLINGS = 1 << 0,
/// Whether this element has matched any rule whose matching is
/// determined by its position in the tree (i.e., first-child,
/// nth-child, etc.).
@ -96,103 +91,61 @@ impl ElementSelectorFlags {
}
}
pub fn matches<E>(selector_list: &[Selector<E::Impl>],
element: &E,
parent_bf: Option<&BloomFilter>)
-> bool
pub fn matches_selector_list<E>(selector_list: &[Selector<E::Impl>],
element: &E,
parent_bf: Option<&BloomFilter>)
-> bool
where E: Element
{
selector_list.iter().any(|selector| {
selector.pseudo_element.is_none() &&
matches_complex_selector(&*selector.complex_selector,
element,
parent_bf,
&mut StyleRelations::empty(),
&mut |_, _| {})
matches_selector(&selector.inner,
element,
parent_bf,
&mut StyleRelations::empty(),
&mut |_, _| {})
})
}
fn may_match<E>(mut selector: &ComplexSelector<E::Impl>,
fn may_match<E>(sel: &SelectorInner<E::Impl>,
bf: &BloomFilter)
-> bool
where E: Element,
{
// See if the bloom filter can exclude any of the descendant selectors, and
// reject if we can.
loop {
match selector.next {
None => break,
Some((ref cs, Combinator::Child)) |
Some((ref cs, Combinator::Descendant)) => selector = &**cs,
Some((ref cs, _)) => {
selector = &**cs;
continue;
}
};
// Check against the list of precomputed hashes.
for hash in sel.ancestor_hashes.iter() {
// If we hit the 0 sentinel hash, that means the rest are zero as well.
if *hash == 0 {
break;
}
for ss in selector.compound_selector.iter() {
match *ss {
SimpleSelector::LocalName(LocalName { ref name, ref lower_name }) => {
if !bf.might_contain_hash(name.precomputed_hash()) &&
!bf.might_contain_hash(lower_name.precomputed_hash()) {
return false
}
},
SimpleSelector::Namespace(ref namespace) => {
if !bf.might_contain_hash(namespace.url.precomputed_hash()) {
return false
}
},
SimpleSelector::ID(ref id) => {
if !bf.might_contain_hash(id.precomputed_hash()) {
return false
}
},
SimpleSelector::Class(ref class) => {
if !bf.might_contain_hash(class.precomputed_hash()) {
return false
}
},
_ => {},
}
if !bf.might_contain_hash(*hash) {
return false;
}
}
// If we haven't proven otherwise, it may match.
true
}
/// Determines whether the given element matches the given complex selector.
pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
element: &E,
parent_bf: Option<&BloomFilter>,
relations: &mut StyleRelations,
flags_setter: &mut F)
-> bool
pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
element: &E,
parent_bf: Option<&BloomFilter>,
relations: &mut StyleRelations,
flags_setter: &mut F)
-> bool
where E: Element,
F: FnMut(&E, ElementSelectorFlags),
{
// Use the bloom filter to fast-reject.
if let Some(filter) = parent_bf {
if !may_match::<E>(selector, filter) {
return false;
}
}
match matches_complex_selector_internal(selector,
element,
relations,
flags_setter) {
SelectorMatchingResult::Matched => {
match selector.next {
Some((_, Combinator::NextSibling)) |
Some((_, Combinator::LaterSibling)) => *relations |= AFFECTED_BY_SIBLINGS,
_ => {}
}
true
}
_ => false
}
// Match the selector.
matches_complex_selector(&selector.complex, element, relations, flags_setter)
}
/// A result of selector matching, includes 3 failure types,
@ -245,6 +198,24 @@ enum SelectorMatchingResult {
NotMatchedGlobally,
}
/// Matches a complex selector.
pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
element: &E,
relations: &mut StyleRelations,
flags_setter: &mut F)
-> bool
where E: Element,
F: FnMut(&E, ElementSelectorFlags),
{
match matches_complex_selector_internal(selector,
element,
relations,
flags_setter) {
SelectorMatchingResult::Matched => true,
_ => false
}
}
fn matches_complex_selector_internal<E, F>(selector: &ComplexSelector<E::Impl>,
element: &E,
relations: &mut StyleRelations,

View file

@ -121,9 +121,52 @@ impl<Impl: SelectorImpl> SelectorList<Impl> {
}
}
/// Copied from Gecko, where it was noted to be unmeasured.
const NUM_ANCESTOR_HASHES: usize = 4;
/// The cores parts of a selector used for matching. This exists to make that
/// information accessibly separately from the specificity and pseudo-element
/// information that lives on |Selector| proper. We may want to refactor things
/// and move that information elsewhere, at which point we could rename this
/// to |Selector|.
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct SelectorInner<Impl: SelectorImpl> {
/// The selector data.
pub complex: Arc<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> {
pub fn new(c: Arc<ComplexSelector<Impl>>) -> Self {
let mut hashes = [0; NUM_ANCESTOR_HASHES];
{
// Compute ancestor hashes for the bloom filter.
let mut hash_iter =
iter_ancestors(&c).flat_map(|x| x.compound_selector.iter())
.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 {
complex: c,
ancestor_hashes: hashes,
}
}
}
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct Selector<Impl: SelectorImpl> {
pub complex_selector: Arc<ComplexSelector<Impl>>,
pub inner: SelectorInner<Impl>,
pub pseudo_element: Option<Impl::PseudoElement>,
pub specificity: u32,
}
@ -141,7 +184,7 @@ impl<Impl: SelectorImpl> SelectorMethods for Selector<Impl> {
fn visit<V>(&self, visitor: &mut V) -> bool
where V: SelectorVisitor<Impl = Impl>,
{
self.complex_selector.visit(visitor)
self.inner.complex.visit(visitor)
}
}
@ -225,6 +268,35 @@ pub struct ComplexSelector<Impl: SelectorImpl> {
pub next: Option<(Arc<ComplexSelector<Impl>>, Combinator)>, // c.next is left of c
}
struct AncestorIterator<'a, Impl: 'a + SelectorImpl> {
curr: Option<&'a Arc<ComplexSelector<Impl>>>,
}
impl<'a, Impl: SelectorImpl> Iterator for AncestorIterator<'a, Impl> {
type Item = &'a Arc<ComplexSelector<Impl>>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(sel) = self.curr.take() {
let (next_sel, is_ancestor) = match sel.next {
None => (None, true),
Some((ref sel, comb)) =>
(Some(sel), matches!(comb, Combinator::Child | Combinator::Descendant)),
};
self.curr = next_sel;
if is_ancestor {
break;
}
}
self.curr
}
}
fn iter_ancestors<Impl: SelectorImpl>(sel: &Arc<ComplexSelector<Impl>>) -> AncestorIterator<Impl> {
AncestorIterator {
curr: Some(sel)
}
}
#[derive(Eq, PartialEq, Clone, Copy, Debug, Hash)]
pub enum Combinator {
Child, // >
@ -270,6 +342,34 @@ pub enum SimpleSelector<Impl: SelectorImpl> {
// ...
}
impl<Impl: SelectorImpl> SimpleSelector<Impl> {
/// Compute the ancestor hash to check against the bloom filter.
fn ancestor_hash(&self) -> Option<u32> {
match *self {
SimpleSelector::LocalName(LocalName { ref name, ref lower_name }) => {
// Only insert the local-name into the filter if it's all lowercase.
// Otherwise we would need to test both hashes, and our data structures
// aren't really set up for that.
if name == lower_name {
Some(name.precomputed_hash())
} else {
None
}
},
SimpleSelector::Namespace(ref namespace) => {
Some(namespace.url.precomputed_hash())
},
SimpleSelector::ID(ref id) => {
Some(id.precomputed_hash())
},
SimpleSelector::Class(ref class) => {
Some(class.precomputed_hash())
},
_ => None,
}
}
}
#[derive(Eq, PartialEq, Clone, Hash, Copy, Debug)]
pub enum CaseSensitivity {
CaseSensitive, // Selectors spec says language-defined, but HTML says sensitive.
@ -321,6 +421,9 @@ impl<Impl: SelectorImpl> Debug for Selector<Impl> {
}
}
impl<Impl: SelectorImpl> Debug for SelectorInner<Impl> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.complex.to_css(f) }
}
impl<Impl: SelectorImpl> Debug for ComplexSelector<Impl> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) }
}
@ -353,7 +456,7 @@ impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.complex_selector.to_css(dest)?;
self.inner.complex.to_css(dest)?;
if let Some(ref pseudo) = self.pseudo_element {
pseudo.to_css(dest)?;
}
@ -672,7 +775,7 @@ fn parse_selector<P, Impl>(parser: &P, input: &mut CssParser) -> Result<Selector
parse_complex_selector_and_pseudo_element(parser, input)?;
Ok(Selector {
specificity: specificity(&complex, pseudo_element.as_ref()),
complex_selector: Arc::new(complex),
inner: SelectorInner::new(Arc::new(complex)),
pseudo_element: pseudo_element,
})
}
@ -1305,48 +1408,48 @@ pub mod tests {
assert_eq!(parse(":lang(4)"), Err(())) ;
assert_eq!(parse(":lang(en US)"), Err(())) ;
assert_eq!(parse("EeÉ"), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec!(SimpleSelector::LocalName(LocalName {
name: DummyAtom::from("EeÉ"),
lower_name: DummyAtom::from("eeÉ") })),
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(0, 0, 1),
}))));
assert_eq!(parse(".foo:lang(en-US)"), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Class(DummyAtom::from("foo")),
SimpleSelector::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned()))
],
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(0, 2, 0),
}))));
assert_eq!(parse("#bar"), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec!(SimpleSelector::ID(DummyAtom::from("bar"))),
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(1, 0, 0),
}))));
assert_eq!(parse("e.foo#bar"), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec!(SimpleSelector::LocalName(LocalName {
name: DummyAtom::from("e"),
lower_name: DummyAtom::from("e") }),
SimpleSelector::Class(DummyAtom::from("foo")),
SimpleSelector::ID(DummyAtom::from("bar"))),
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(1, 1, 1),
}))));
assert_eq!(parse("e.foo #bar"), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec!(SimpleSelector::ID(DummyAtom::from("bar"))),
next: Some((Arc::new(ComplexSelector {
compound_selector: vec!(SimpleSelector::LocalName(LocalName {
@ -1355,7 +1458,7 @@ pub mod tests {
SimpleSelector::Class(DummyAtom::from("foo"))),
next: None,
}), Combinator::Descendant)),
}),
})),
pseudo_element: None,
specificity: specificity(1, 1, 1),
}))));
@ -1363,7 +1466,7 @@ pub mod tests {
// https://github.com/mozilla/servo/pull/1652
let mut parser = DummyParser::default();
assert_eq!(parse_ns("[Foo]", &parser), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec!(SimpleSelector::AttrExists(AttrSelector {
name: DummyAtom::from("Foo"),
lower_name: DummyAtom::from("foo"),
@ -1373,14 +1476,14 @@ pub mod tests {
}),
})),
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(0, 1, 0),
}))));
assert_eq!(parse_ns("svg|circle", &parser), Err(()));
parser.ns_prefixes.insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
assert_eq!(parse_ns("svg|circle", &parser), Ok(SelectorList(vec![Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: Some(DummyAtom("svg".into())),
@ -1392,7 +1495,7 @@ pub mod tests {
})
],
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(0, 0, 1),
}])));
@ -1402,7 +1505,7 @@ pub mod tests {
// https://github.com/servo/rust-selectors/pull/82
parser.default_ns = Some(MATHML.into());
assert_eq!(parse_ns("[Foo]", &parser), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
@ -1418,13 +1521,13 @@ pub mod tests {
}),
],
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(0, 1, 0),
}))));
// Default namespace does apply to type selectors
assert_eq!(parse_ns("e", &parser), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec!(
SimpleSelector::Namespace(Namespace {
prefix: None,
@ -1435,12 +1538,12 @@ pub mod tests {
lower_name: DummyAtom::from("e") }),
),
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(0, 0, 1),
}))));
assert_eq!(parse("[attr |= \"foo\"]"), Ok(SelectorList(vec![Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::AttrDashMatch(AttrSelector {
name: DummyAtom::from("attr"),
@ -1452,23 +1555,23 @@ pub mod tests {
}, DummyAtom::from("foo"))
],
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(0, 1, 0),
}])));
// https://github.com/mozilla/servo/issues/1723
assert_eq!(parse("::before"), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec!(),
next: None,
}),
})),
pseudo_element: Some(PseudoElement::Before),
specificity: specificity(0, 0, 1),
}))));
// https://github.com/servo/servo/issues/15335
assert_eq!(parse(":: before"), Err(()));
assert_eq!(parse("div ::after"), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec!(),
next: Some((Arc::new(ComplexSelector {
compound_selector: vec!(SimpleSelector::LocalName(LocalName {
@ -1476,12 +1579,12 @@ pub mod tests {
lower_name: DummyAtom::from("div") })),
next: None,
}), Combinator::Descendant)),
}),
})),
pseudo_element: Some(PseudoElement::After),
specificity: specificity(0, 0, 2),
}))));
assert_eq!(parse("#d1 > .ok"), Ok(SelectorList(vec![Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Class(DummyAtom::from("ok")),
],
@ -1491,12 +1594,12 @@ pub mod tests {
],
next: None,
}), Combinator::Child)),
}),
})),
pseudo_element: None,
specificity: (1 << 20) + (1 << 10) + (0 << 0),
}])));
assert_eq!(parse(":not(.babybel, #provel.old)"), Ok(SelectorList(vec!(Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec!(SimpleSelector::Negation(
vec!(
Arc::new(ComplexSelector {
@ -1513,7 +1616,7 @@ pub mod tests {
)
)),
next: None,
}),
})),
pseudo_element: None,
specificity: specificity(1, 1, 0),
}))));

View file

@ -1150,11 +1150,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
},
NonTSPseudoClass::MozAny(ref sels) => {
sels.iter().any(|s| {
matches_complex_selector(s,
self,
None,
relations,
flags_setter)
matches_complex_selector(s, self, relations, flags_setter)
})
}
NonTSPseudoClass::MozSystemMetric(ref s) |

View file

@ -16,8 +16,8 @@ use heapsize::HeapSizeOf;
use selector_parser::{AttrValue, NonTSPseudoClass, Snapshot, SelectorImpl};
use selectors::{Element, MatchAttr};
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::matching::matches_complex_selector;
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SelectorMethods, SimpleSelector};
use selectors::matching::matches_selector;
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SelectorInner, SelectorMethods, SimpleSelector};
use selectors::visitor::SelectorVisitor;
use std::clone::Clone;
use std::sync::Arc;
@ -298,13 +298,10 @@ impl<'a, E> Element for ElementWrapper<'a, E>
// snapshot.
#[cfg(feature = "gecko")]
{
use selectors::matching::matches_complex_selector;
if let NonTSPseudoClass::MozAny(ref selectors) = *pseudo_class {
return selectors.iter().any(|s| {
matches_complex_selector(s,
self,
None,
relations,
_setter)
matches_complex_selector(s, self, relations, _setter)
})
}
}
@ -493,7 +490,7 @@ impl Sensitivities {
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
struct Dependency {
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
selector: Arc<ComplexSelector<SelectorImpl>>,
selector: SelectorInner<SelectorImpl>,
hint: RestyleHint,
sensitivities: Sensitivities,
}
@ -603,7 +600,7 @@ impl DependencySet {
self.add_dependency(Dependency {
sensitivities: sensitivities,
hint: hint,
selector: current.clone(),
selector: SelectorInner::new(current.clone()),
})
}
@ -699,13 +696,13 @@ impl DependencySet {
// We can ignore the selector flags, since they would have already been set during
// original matching for any element that might change its matching behavior here.
let matched_then =
matches_complex_selector(&dep.selector, snapshot, None,
&mut StyleRelations::empty(),
&mut |_, _| {});
matches_selector(&dep.selector, snapshot, None,
&mut StyleRelations::empty(),
&mut |_, _| {});
let matches_now =
matches_complex_selector(&dep.selector, element, None,
&mut StyleRelations::empty(),
&mut |_, _| {});
matches_selector(&dep.selector, element, None,
&mut StyleRelations::empty(),
&mut |_, _| {});
if matched_then != matches_now {
hint.insert(dep.hint);
}

View file

@ -26,8 +26,8 @@ use selectors::Element;
use selectors::bloom::BloomFilter;
use selectors::matching::{AFFECTED_BY_ANIMATIONS, AFFECTED_BY_TRANSITIONS};
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector};
use selectors::parser::{Selector, SelectorInner, SimpleSelector, LocalName as LocalNameSelector};
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use sink::Push;
use smallvec::VecLike;
@ -336,7 +336,7 @@ impl Stylist {
};
map.insert(Rule {
selector: selector.complex_selector.clone(),
selector: selector.inner.clone(),
style_rule: locked.clone(),
specificity: selector.specificity,
source_order: self.rules_source_order,
@ -346,7 +346,7 @@ impl Stylist {
for selector in &style_rule.selectors.0 {
let needs_cache_revalidation =
self.dependencies.note_selector(&selector.complex_selector);
self.dependencies.note_selector(&selector.inner.complex);
if needs_cache_revalidation {
self.selectors_for_cache_revalidation.push(selector.clone());
}
@ -826,18 +826,18 @@ impl Stylist {
F: FnMut(&E, ElementSelectorFlags)
{
use selectors::matching::StyleRelations;
use selectors::matching::matches_complex_selector;
use selectors::matching::matches_selector;
let len = self.selectors_for_cache_revalidation.len();
let mut results = BitVec::from_elem(len, false);
for (i, ref selector) in self.selectors_for_cache_revalidation
.iter().enumerate() {
results.set(i, matches_complex_selector(&selector.complex_selector,
element,
Some(bloom),
&mut StyleRelations::empty(),
flags_setter));
results.set(i, matches_selector(&selector.inner,
element,
Some(bloom),
&mut StyleRelations::empty(),
flags_setter));
}
results
@ -1081,8 +1081,8 @@ impl SelectorMap {
// correct, and also to not trigger rule tree assertions.
let mut important = vec![];
for rule in self.other_rules.iter() {
if rule.selector.compound_selector.is_empty() &&
rule.selector.next.is_none() {
if rule.selector.complex.compound_selector.is_empty() &&
rule.selector.complex.next.is_none() {
let style_rule = rule.style_rule.read_with(guard);
let block = style_rule.block.read_with(guard);
if block.any_normal() {
@ -1157,8 +1157,8 @@ impl SelectorMap {
block.any_normal()
};
if any_declaration_for_importance &&
matches_complex_selector(&*rule.selector, element, parent_bf,
relations, flags_setter) {
matches_selector(&rule.selector, element, parent_bf,
relations, flags_setter) {
matching_rules.push(
rule.to_applicable_declaration_block(cascade_level));
}
@ -1191,7 +1191,7 @@ impl SelectorMap {
/// Retrieve the first ID name in Rule, or None otherwise.
pub fn get_id_name(rule: &Rule) -> Option<Atom> {
for ss in &rule.selector.compound_selector {
for ss in &rule.selector.complex.compound_selector {
// TODO(pradeep): Implement case-sensitivity based on the
// document type and quirks mode.
if let SimpleSelector::ID(ref id) = *ss {
@ -1204,7 +1204,7 @@ impl SelectorMap {
/// Retrieve the FIRST class name in Rule, or None otherwise.
pub fn get_class_name(rule: &Rule) -> Option<Atom> {
for ss in &rule.selector.compound_selector {
for ss in &rule.selector.complex.compound_selector {
// TODO(pradeep): Implement case-sensitivity based on the
// document type and quirks mode.
if let SimpleSelector::Class(ref class) = *ss {
@ -1217,7 +1217,7 @@ impl SelectorMap {
/// Retrieve the name if it is a type selector, or None otherwise.
pub fn get_local_name(rule: &Rule) -> Option<LocalNameSelector<SelectorImpl>> {
for ss in &rule.selector.compound_selector {
for ss in &rule.selector.complex.compound_selector {
if let SimpleSelector::LocalName(ref n) = *ss {
return Some(LocalNameSelector {
name: n.name.clone(),
@ -1245,7 +1245,7 @@ pub struct Rule {
/// style rule was a generic parameter to it. It's not trivial though, due
/// to the specificity.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub selector: Arc<ComplexSelector<SelectorImpl>>,
pub selector: SelectorInner<SelectorImpl>,
/// The actual style rule.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub style_rule: Arc<Locked<StyleRule>>,

View file

@ -84,7 +84,7 @@ fn test_parse_stylesheet() {
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
@ -104,7 +104,7 @@ fn test_parse_stylesheet() {
}, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
],
next: None,
}),
})),
pseudo_element: None,
specificity: (0 << 20) + (1 << 10) + (1 << 0),
},
@ -120,7 +120,7 @@ fn test_parse_stylesheet() {
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
@ -132,12 +132,12 @@ fn test_parse_stylesheet() {
}),
],
next: None,
}),
})),
pseudo_element: None,
specificity: (0 << 20) + (0 << 10) + (1 << 0),
},
Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
@ -149,7 +149,7 @@ fn test_parse_stylesheet() {
}),
],
next: None,
}),
})),
pseudo_element: None,
specificity: (0 << 20) + (0 << 10) + (1 << 0),
},
@ -162,7 +162,7 @@ fn test_parse_stylesheet() {
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
Selector {
complex_selector: Arc::new(ComplexSelector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
@ -180,7 +180,7 @@ fn test_parse_stylesheet() {
],
next: None,
}), Combinator::Child)),
}),
})),
pseudo_element: None,
specificity: (1 << 20) + (1 << 10) + (0 << 0),
},

View file

@ -35,7 +35,7 @@ fn get_mock_rules(css_selectors: &[&str]) -> (Vec<Vec<Rule>>, SharedRwLock) {
let rule = locked.read_with(&guard);
rule.selectors.0.iter().map(|s| {
Rule {
selector: s.complex_selector.clone(),
selector: s.inner.clone(),
style_rule: locked.clone(),
specificity: s.specificity,
source_order: i,