mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Hoist specificity computation into a new private builder module.
This patch doesn't modify any of the code because making a few things pub. I did this first to make the next patch easier to audit. MozReview-Commit-ID: 7PYxoS5bVGN
This commit is contained in:
parent
1d242ad760
commit
1fc1d64e80
3 changed files with 144 additions and 136 deletions
|
@ -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: SelectorImpl>() -> 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<T: Display, W: fmt::Write>(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<u32> 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<Specificity> 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<Impl>(iter: SelectorIter<Impl>) -> u32
|
||||
where Impl: SelectorImpl
|
||||
{
|
||||
complex_selector_specificity(iter).into()
|
||||
}
|
||||
|
||||
fn complex_selector_specificity<Impl>(mut iter: SelectorIter<Impl>)
|
||||
-> Specificity
|
||||
where Impl: SelectorImpl
|
||||
{
|
||||
fn simple_selector_specificity<Impl>(simple_selector: &Component<Impl>,
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue