mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
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:
commit
b4bea83312
9 changed files with 227 additions and 160 deletions
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
}))));
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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>>,
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue