mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
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:
parent
1748150497
commit
0ea58d1ffa
9 changed files with 161 additions and 312 deletions
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue