mirror of
https://github.com/servo/servo.git
synced 2025-08-09 07:25:35 +01:00
Store selectors and combinators inline in a single sequence.
This improves cache locality and reduces allocations during parsing. Note that this reverses the iteration order within a sequence of simple selectors, but that shouldn't matter.
This commit is contained in:
parent
93fa0ae1e3
commit
6d66ec5e11
10 changed files with 703 additions and 330 deletions
|
@ -14,7 +14,6 @@ use selectors::visitor::SelectorVisitor;
|
|||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||
|
||||
/// A representation of a CSS pseudo-element.
|
||||
|
@ -218,7 +217,7 @@ macro_rules! pseudo_class_name {
|
|||
///
|
||||
/// TODO(emilio): We disallow combinators and pseudos here, so we
|
||||
/// should use SimpleSelector instead
|
||||
MozAny(Vec<Arc<ComplexSelector<SelectorImpl>>>),
|
||||
MozAny(Vec<ComplexSelector<SelectorImpl>>),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -396,10 +395,10 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
|
|||
}, )*
|
||||
"-moz-any" => {
|
||||
let selectors = parser.parse_comma_separated(|input| {
|
||||
ComplexSelector::parse(self, input).map(Arc::new)
|
||||
ComplexSelector::parse(self, input)
|
||||
})?;
|
||||
// Selectors inside `:-moz-any` may not include combinators.
|
||||
if selectors.iter().any(|s| s.next.is_some()) {
|
||||
if selectors.iter().flat_map(|x| x.iter_raw()).any(|s| s.is_combinator()) {
|
||||
return Err(())
|
||||
}
|
||||
NonTSPseudoClass::MozAny(selectors)
|
||||
|
|
|
@ -17,10 +17,10 @@ use selector_parser::{AttrValue, NonTSPseudoClass, Snapshot, SelectorImpl};
|
|||
use selectors::{Element, MatchAttr};
|
||||
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
||||
use selectors::matching::matches_selector;
|
||||
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SelectorInner, SelectorMethods, SimpleSelector};
|
||||
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SelectorInner, SelectorIter};
|
||||
use selectors::parser::{SelectorMethods, SimpleSelector};
|
||||
use selectors::visitor::SelectorVisitor;
|
||||
use std::clone::Clone;
|
||||
use std::sync::Arc;
|
||||
|
||||
bitflags! {
|
||||
/// When the ElementState of an element (like IN_HOVER_STATE) changes,
|
||||
|
@ -509,7 +509,7 @@ impl SelectorVisitor for SensitivitiesVisitor {
|
|||
type Impl = SelectorImpl;
|
||||
|
||||
fn visit_complex_selector(&mut self,
|
||||
_: &ComplexSelector<SelectorImpl>,
|
||||
_: SelectorIter<SelectorImpl>,
|
||||
combinator: Option<Combinator>) -> bool {
|
||||
self.hint |= combinator_to_restyle_hint(combinator);
|
||||
self.needs_revalidation |= self.hint.contains(RESTYLE_LATER_SIBLINGS);
|
||||
|
@ -567,50 +567,47 @@ impl DependencySet {
|
|||
/// cache revalidation, that is, whether two siblings of the same "shape"
|
||||
/// may have different style due to this selector.
|
||||
pub fn note_selector(&mut self,
|
||||
selector: &Arc<ComplexSelector<SelectorImpl>>)
|
||||
base: &ComplexSelector<SelectorImpl>)
|
||||
-> bool
|
||||
{
|
||||
let mut next = Some(base.clone());
|
||||
let mut combinator = None;
|
||||
let mut current = selector;
|
||||
|
||||
let mut needs_revalidation = false;
|
||||
|
||||
loop {
|
||||
let mut sensitivities_visitor = SensitivitiesVisitor {
|
||||
while let Some(current) = next.take() {
|
||||
// Set up our visitor.
|
||||
let mut visitor = SensitivitiesVisitor {
|
||||
sensitivities: Sensitivities::new(),
|
||||
hint: RestyleHint::empty(),
|
||||
hint: combinator_to_restyle_hint(combinator),
|
||||
needs_revalidation: false,
|
||||
};
|
||||
|
||||
for ss in ¤t.compound_selector {
|
||||
ss.visit(&mut sensitivities_visitor);
|
||||
{
|
||||
// Visit all the simple selectors.
|
||||
let mut iter = current.iter();
|
||||
let mut index = 0usize;
|
||||
for ss in &mut iter {
|
||||
ss.visit(&mut visitor);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
// Prepare the next sequence of simple selectors.
|
||||
if let Some(next_combinator) = iter.next_sequence() {
|
||||
next = Some(current.slice_from(index + 1));
|
||||
combinator = Some(next_combinator);
|
||||
}
|
||||
}
|
||||
|
||||
needs_revalidation |= sensitivities_visitor.needs_revalidation;
|
||||
|
||||
let SensitivitiesVisitor {
|
||||
sensitivities,
|
||||
mut hint,
|
||||
..
|
||||
} = sensitivities_visitor;
|
||||
|
||||
hint |= combinator_to_restyle_hint(combinator);
|
||||
|
||||
if !sensitivities.is_empty() {
|
||||
// Note what we found.
|
||||
needs_revalidation |= visitor.needs_revalidation;
|
||||
if !visitor.sensitivities.is_empty() {
|
||||
self.add_dependency(Dependency {
|
||||
sensitivities: sensitivities,
|
||||
hint: hint,
|
||||
selector: SelectorInner::new(current.clone()),
|
||||
sensitivities: visitor.sensitivities,
|
||||
hint: visitor.hint,
|
||||
selector: SelectorInner::new(current),
|
||||
})
|
||||
}
|
||||
|
||||
match current.next {
|
||||
Some((ref next, next_combinator)) => {
|
||||
current = next;
|
||||
combinator = Some(next_combinator);
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
needs_revalidation
|
||||
|
@ -729,7 +726,7 @@ fn smoke_restyle_hints() {
|
|||
let mut dependencies = DependencySet::new();
|
||||
|
||||
let mut p = Parser::new(":not(:active) ~ label");
|
||||
let selector = Arc::new(ComplexSelector::parse(&parser, &mut p).unwrap());
|
||||
let selector = ComplexSelector::parse(&parser, &mut p).unwrap();
|
||||
dependencies.note_selector(&selector);
|
||||
assert_eq!(dependencies.len(), 1);
|
||||
assert_eq!(dependencies.state_deps.len(), 1);
|
||||
|
|
|
@ -1070,8 +1070,7 @@ 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.complex.compound_selector.is_empty() &&
|
||||
rule.selector.complex.next.is_none() {
|
||||
if rule.selector.complex.iter_raw().next().is_none() {
|
||||
let style_rule = rule.style_rule.read_with(guard);
|
||||
let block = style_rule.block.read_with(guard);
|
||||
if block.any_normal() {
|
||||
|
@ -1180,7 +1179,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.complex.compound_selector {
|
||||
for ss in rule.selector.complex.iter() {
|
||||
// TODO(pradeep): Implement case-sensitivity based on the
|
||||
// document type and quirks mode.
|
||||
if let SimpleSelector::ID(ref id) = *ss {
|
||||
|
@ -1193,7 +1192,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.complex.compound_selector {
|
||||
for ss in rule.selector.complex.iter() {
|
||||
// TODO(pradeep): Implement case-sensitivity based on the
|
||||
// document type and quirks mode.
|
||||
if let SimpleSelector::Class(ref class) = *ss {
|
||||
|
@ -1206,7 +1205,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.complex.compound_selector {
|
||||
for ss in rule.selector.complex.iter() {
|
||||
if let SimpleSelector::LocalName(ref n) = *ss {
|
||||
return Some(LocalNameSelector {
|
||||
name: n.name.clone(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue