style: Stop special-casing a few attributes for style sharing, and use a visitor to track dependencies.

Also, simplify all the pre-snapshot attribute hacks in the script and style
code.

MozReview-Commit-ID: 6c9ipeb7Tnr
Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
This commit is contained in:
Emilio Cobos Álvarez 2017-04-07 03:17:29 +02:00
parent 1748150497
commit 0ea58d1ffa
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
9 changed files with 161 additions and 312 deletions

View file

@ -18,6 +18,7 @@ use selectors::{Element, MatchAttr};
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::matching::matches_complex_selector;
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SimpleSelector};
use selectors::visitor::SelectorVisitor;
use std::clone::Clone;
use std::sync::Arc;
@ -399,6 +400,22 @@ fn is_attr_selector(sel: &SimpleSelector<SelectorImpl>) -> bool {
}
}
fn is_sibling_affecting_selector(sel: &SimpleSelector<SelectorImpl>) -> bool {
match *sel {
SimpleSelector::FirstChild |
SimpleSelector::LastChild |
SimpleSelector::OnlyChild |
SimpleSelector::NthChild(..) |
SimpleSelector::NthLastChild(..) |
SimpleSelector::NthOfType(..) |
SimpleSelector::NthLastOfType(..) |
SimpleSelector::FirstOfType |
SimpleSelector::LastOfType |
SimpleSelector::OnlyOfType => true,
_ => false,
}
}
fn combinator_to_restyle_hint(combinator: Option<Combinator>) -> RestyleHint {
match combinator {
None => RESTYLE_SELF,
@ -458,6 +475,74 @@ struct Dependency {
sensitivities: Sensitivities,
}
/// A visitor struct that collects information for a given selector.
///
/// This is the struct responsible of adding dependencies for a given complex
/// selector.
pub struct SelectorDependencyVisitor<'a> {
dependency_set: &'a mut DependencySet,
affects_siblings: bool,
affected_by_attribute: bool,
}
impl<'a> SelectorDependencyVisitor<'a> {
/// Create a new `SelectorDependencyVisitor`.
pub fn new(dependency_set: &'a mut DependencySet) -> Self {
SelectorDependencyVisitor {
dependency_set: dependency_set,
affects_siblings: false,
affected_by_attribute: false,
}
}
/// Returns whether this visitor has known of a sibling-dependent selector.
pub fn affects_siblings(&self) -> bool {
self.affects_siblings
}
/// Returns whether this visitor has known of a attribute-dependent
/// selector.
pub fn affected_by_attribute(&self) -> bool {
self.affected_by_attribute
}
}
impl<'a> SelectorVisitor for SelectorDependencyVisitor<'a> {
type Impl = SelectorImpl;
fn visit_complex_selector(&mut self,
selector: &Arc<ComplexSelector<SelectorImpl>>,
combinator: Option<Combinator>)
-> bool
{
let mut sensitivities = Sensitivities::new();
for s in &selector.compound_selector {
sensitivities.states.insert(selector_to_state(s));
if !self.affects_siblings {
self.affects_siblings = is_sibling_affecting_selector(s);
}
if !sensitivities.attrs {
sensitivities.attrs = is_attr_selector(s);
}
}
let hint = combinator_to_restyle_hint(combinator);
self.affected_by_attribute |= sensitivities.attrs;
self.affects_siblings |= hint.intersects(RESTYLE_LATER_SIBLINGS);
if !sensitivities.is_empty() {
self.dependency_set.add_dependency(Dependency {
selector: selector.clone(),
hint: hint,
sensitivities: sensitivities,
});
}
true
}
}
/// A set of dependencies for a given stylist.
///
/// Note that there are measurable perf wins from storing them separately
@ -476,12 +561,12 @@ pub struct DependencySet {
impl DependencySet {
fn add_dependency(&mut self, dep: Dependency) {
let affects_attrs = dep.sensitivities.attrs;
let affected_by_attribute = dep.sensitivities.attrs;
let affects_states = !dep.sensitivities.states.is_empty();
if affects_attrs && affects_states {
if affected_by_attribute && affects_states {
self.common_deps.push(dep)
} else if affects_attrs {
} else if affected_by_attribute {
self.attr_deps.push(dep)
} else {
self.state_deps.push(dep)
@ -502,46 +587,6 @@ impl DependencySet {
self.common_deps.len() + self.attr_deps.len() + self.state_deps.len()
}
/// Create the needed dependencies that a given selector creates, and add
/// them to the set.
pub fn note_selector(&mut self, selector: &Arc<ComplexSelector<SelectorImpl>>) {
let mut cur = selector;
let mut combinator: Option<Combinator> = None;
loop {
let mut sensitivities = Sensitivities::new();
for s in &cur.compound_selector {
sensitivities.states.insert(selector_to_state(s));
if !sensitivities.attrs {
sensitivities.attrs = is_attr_selector(s);
}
// NOTE(emilio): I haven't thought this thoroughly, but we may
// not need to do anything for combinators inside negations.
//
// Or maybe we do, and need to call note_selector recursively
// here to account for them correctly, but keep the
// sensitivities of the parent?
//
// In any case, perhaps we should just drop it, see bug 1348802.
}
if !sensitivities.is_empty() {
self.add_dependency(Dependency {
selector: cur.clone(),
hint: combinator_to_restyle_hint(combinator),
sensitivities: sensitivities,
});
}
cur = match cur.next {
Some((ref sel, comb)) => {
combinator = Some(comb);
sel
}
None => break,
}
}
}
/// Clear this dependency set.
pub fn clear(&mut self) {
self.common_deps.clear();