diff --git a/components/selectors/builder.rs b/components/selectors/builder.rs new file mode 100644 index 00000000000..9fd751b9bb8 --- /dev/null +++ b/components/selectors/builder.rs @@ -0,0 +1,141 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use parser::{Component, SelectorImpl, SelectorIter}; +use std::cmp; +use std::ops::Add; + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct SpecificityAndFlags(pub u32); + +pub const HAS_PSEUDO_BIT: u32 = 1 << 30; + +impl SpecificityAndFlags { + pub fn specificity(&self) -> u32 { + self.0 & !HAS_PSEUDO_BIT + } + + pub fn has_pseudo_element(&self) -> bool { + (self.0 & HAS_PSEUDO_BIT) != 0 + } +} + +const MAX_10BIT: u32 = (1u32 << 10) - 1; + +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +struct Specificity { + id_selectors: u32, + class_like_selectors: u32, + element_selectors: u32, +} + +impl Add for Specificity { + type Output = Specificity; + + fn add(self, rhs: Specificity) -> Specificity { + Specificity { + id_selectors: self.id_selectors + rhs.id_selectors, + class_like_selectors: + self.class_like_selectors + rhs.class_like_selectors, + element_selectors: + self.element_selectors + rhs.element_selectors, + } + } +} + +impl Default for Specificity { + fn default() -> Specificity { + Specificity { + id_selectors: 0, + class_like_selectors: 0, + element_selectors: 0, + } + } +} + +impl From for Specificity { + fn from(value: u32) -> Specificity { + assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT); + Specificity { + id_selectors: value >> 20, + class_like_selectors: (value >> 10) & MAX_10BIT, + element_selectors: value & MAX_10BIT, + } + } +} + +impl From for u32 { + fn from(specificity: Specificity) -> u32 { + cmp::min(specificity.id_selectors, MAX_10BIT) << 20 + | cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 + | cmp::min(specificity.element_selectors, MAX_10BIT) + } +} + +pub fn specificity(iter: SelectorIter) -> u32 + where Impl: SelectorImpl +{ + complex_selector_specificity(iter).into() +} + +fn complex_selector_specificity(mut iter: SelectorIter) + -> Specificity + where Impl: SelectorImpl +{ + fn simple_selector_specificity(simple_selector: &Component, + specificity: &mut Specificity) + where Impl: SelectorImpl + { + match *simple_selector { + Component::Combinator(..) => unreachable!(), + Component::PseudoElement(..) | + Component::LocalName(..) => { + specificity.element_selectors += 1 + } + Component::ID(..) => { + specificity.id_selectors += 1 + } + Component::Class(..) | + Component::AttributeInNoNamespace { .. } | + Component::AttributeInNoNamespaceExists { .. } | + Component::AttributeOther(..) | + + Component::FirstChild | Component::LastChild | + Component::OnlyChild | Component::Root | + Component::Empty | + Component::NthChild(..) | + Component::NthLastChild(..) | + Component::NthOfType(..) | + Component::NthLastOfType(..) | + Component::FirstOfType | Component::LastOfType | + Component::OnlyOfType | + Component::NonTSPseudoClass(..) => { + specificity.class_like_selectors += 1 + } + Component::ExplicitUniversalType | + Component::ExplicitAnyNamespace | + Component::ExplicitNoNamespace | + Component::DefaultNamespace(..) | + Component::Namespace(..) => { + // Does not affect specificity + } + Component::Negation(ref negated) => { + for ss in negated.iter() { + simple_selector_specificity(&ss, specificity); + } + } + } + } + + let mut specificity = Default::default(); + loop { + for simple_selector in &mut iter { + simple_selector_specificity(&simple_selector, &mut specificity); + } + if iter.next_sequence().is_none() { + break; + } + } + specificity +} diff --git a/components/selectors/lib.rs b/components/selectors/lib.rs index bde7acef189..568e1aaba70 100644 --- a/components/selectors/lib.rs +++ b/components/selectors/lib.rs @@ -15,6 +15,7 @@ extern crate smallvec; pub mod attr; pub mod bloom; +mod builder; pub mod context; pub mod matching; pub mod parser; diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index fe1214aafa0..f61a42c51d8 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -5,6 +5,8 @@ use attr::{AttrSelectorWithNamespace, ParsedAttrSelectorOperation, AttrSelectorOperator}; use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint}; use bloom::BLOOM_HASH_MASK; +use builder::{HAS_PSEUDO_BIT, SpecificityAndFlags}; +use builder::specificity; use cssparser::{ParseError, BasicParseError, CompactCowStr}; use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter}; use precomputed_hash::PrecomputedHash; @@ -13,10 +15,8 @@ use sink::Push; use smallvec::SmallVec; use std::ascii::AsciiExt; use std::borrow::{Borrow, Cow}; -use std::cmp; use std::fmt::{self, Display, Debug, Write}; use std::iter::Rev; -use std::ops::Add; use std::slice; use visitor::SelectorVisitor; @@ -266,8 +266,6 @@ impl AncestorHashes { } } -const HAS_PSEUDO_BIT: u32 = 1 << 30; - pub trait SelectorMethods { type Impl: SelectorImpl; @@ -370,19 +368,6 @@ pub fn namespace_empty_string() -> Impl::NamespaceUrl { Impl::NamespaceUrl::default() } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -struct SpecificityAndFlags(u32); - -impl SpecificityAndFlags { - fn specificity(&self) -> u32 { - self.0 & !HAS_PSEUDO_BIT - } - - fn has_pseudo_element(&self) -> bool { - (self.0 & HAS_PSEUDO_BIT) != 0 - } -} - /// A Selector stores a sequence of simple selectors and combinators. The /// iterator classes allow callers to iterate at either the raw sequence level or /// at the level of sequences of simple selectors separated by combinators. Most @@ -920,125 +905,6 @@ fn display_to_css_identifier(x: &T, dest: &mut W) -> serialize_identifier(&string, dest) } -const MAX_10BIT: u32 = (1u32 << 10) - 1; - -#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] -struct Specificity { - id_selectors: u32, - class_like_selectors: u32, - element_selectors: u32, -} - -impl Add for Specificity { - type Output = Specificity; - - fn add(self, rhs: Specificity) -> Specificity { - Specificity { - id_selectors: self.id_selectors + rhs.id_selectors, - class_like_selectors: - self.class_like_selectors + rhs.class_like_selectors, - element_selectors: - self.element_selectors + rhs.element_selectors, - } - } -} - -impl Default for Specificity { - fn default() -> Specificity { - Specificity { - id_selectors: 0, - class_like_selectors: 0, - element_selectors: 0, - } - } -} - -impl From for Specificity { - fn from(value: u32) -> Specificity { - assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT); - Specificity { - id_selectors: value >> 20, - class_like_selectors: (value >> 10) & MAX_10BIT, - element_selectors: value & MAX_10BIT, - } - } -} - -impl From for u32 { - fn from(specificity: Specificity) -> u32 { - cmp::min(specificity.id_selectors, MAX_10BIT) << 20 - | cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 - | cmp::min(specificity.element_selectors, MAX_10BIT) - } -} - -fn specificity(iter: SelectorIter) -> u32 - where Impl: SelectorImpl -{ - complex_selector_specificity(iter).into() -} - -fn complex_selector_specificity(mut iter: SelectorIter) - -> Specificity - where Impl: SelectorImpl -{ - fn simple_selector_specificity(simple_selector: &Component, - specificity: &mut Specificity) - where Impl: SelectorImpl - { - match *simple_selector { - Component::Combinator(..) => unreachable!(), - Component::PseudoElement(..) | - Component::LocalName(..) => { - specificity.element_selectors += 1 - } - Component::ID(..) => { - specificity.id_selectors += 1 - } - Component::Class(..) | - Component::AttributeInNoNamespace { .. } | - Component::AttributeInNoNamespaceExists { .. } | - Component::AttributeOther(..) | - - Component::FirstChild | Component::LastChild | - Component::OnlyChild | Component::Root | - Component::Empty | - Component::NthChild(..) | - Component::NthLastChild(..) | - Component::NthOfType(..) | - Component::NthLastOfType(..) | - Component::FirstOfType | Component::LastOfType | - Component::OnlyOfType | - Component::NonTSPseudoClass(..) => { - specificity.class_like_selectors += 1 - } - Component::ExplicitUniversalType | - Component::ExplicitAnyNamespace | - Component::ExplicitNoNamespace | - Component::DefaultNamespace(..) | - Component::Namespace(..) => { - // Does not affect specificity - } - Component::Negation(ref negated) => { - for ss in negated.iter() { - simple_selector_specificity(&ss, specificity); - } - } - } - } - - let mut specificity = Default::default(); - loop { - for simple_selector in &mut iter { - simple_selector_specificity(&simple_selector, &mut specificity); - } - if iter.next_sequence().is_none() { - break; - } - } - specificity -} - /// We make this large because the result of parsing a selector is fed into a new /// Arc-ed allocation, so any spilled vec would be a wasted allocation. Also, /// Components are large enough that we don't have much cache locality benefit