Make note_selector more efficient.

My measurements are inconclusive as to whether this really moves the
needle, but it seems like the right way to do it in any case.

MozReview-Commit-ID: 7OuCc2aQ7jH
This commit is contained in:
Bobby Holley 2017-04-27 18:09:06 -07:00
parent b4a2e2f17c
commit a6ef89a7fe

View file

@ -525,56 +525,63 @@ impl DependencySet {
/// Adds a selector to this `DependencySet`.
pub fn note_selector(&mut self, selector: &Selector<SelectorImpl>) {
let mut is_pseudo_element = selector.pseudo_element.is_some();
let mut next = Some(selector.inner.complex.clone());
let mut combinator = None;
let mut iter = selector.inner.complex.iter();
let mut index = 0;
while let Some(current) = next.take() {
// Set up our visitor.
loop {
let sequence_start = index;
let mut visitor = SensitivitiesVisitor {
sensitivities: Sensitivities::new()
};
let mut hint = combinator_to_restyle_hint(combinator);
if is_pseudo_element {
// TODO(emilio): use more fancy restyle hints to avoid restyling
// the whole subtree when pseudos change.
// Visit all the simple selectors in this sequence.
//
// We currently need is_pseudo_element to handle eager pseudos
// (so the style the parent stores doesn't become stale), and
// restyle_descendants to handle all of them (::before and
// ::after, because we find them in the subtree, and other lazy
// pseudos for the same reason).
hint |= RESTYLE_SELF | RESTYLE_DESCENDANTS;
is_pseudo_element = false;
}
{
// Visit all the simple selectors.
let mut iter = current.iter();
let mut index = 0usize;
// Note that this works because we can't have combinators nested
// inside simple selectors (i.e. in :not() or :-moz-any()). If we
// ever support that we'll need to visit complex selectors as well.
for ss in &mut iter {
ss.visit(&mut visitor);
index += 1;
index += 1; // Account for the simple selector.
}
// 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);
}
}
// Note what we found.
// If we found a sensitivity, add an entry in the dependency set.
if !visitor.sensitivities.is_empty() {
let mut hint = combinator_to_restyle_hint(combinator);
let dep_selector;
if sequence_start == 0 {
if selector.pseudo_element.is_some() {
// TODO(emilio): use more fancy restyle hints to avoid
// restyling the whole subtree when pseudos change.
//
// We currently need is_pseudo_element to handle eager
// pseudos (so the style the parent stores doesn't
// become stale), and restyle_descendants to handle all
// of them (::before and ::after, because we find them
// in the subtree, and other lazy pseudos for the same
// reason).
hint |= RESTYLE_SELF | RESTYLE_DESCENDANTS;
}
// Reuse the bloom hashes if this is the base selector.
dep_selector = selector.inner.clone();
} else {
dep_selector = SelectorInner::new(selector.inner.complex.slice_from(sequence_start));
}
self.add_dependency(Dependency {
sensitivities: visitor.sensitivities,
hint: hint,
selector: SelectorInner::new(current),
})
selector: dep_selector,
});
}
combinator = iter.next_sequence();
if combinator.is_none() {
break;
}
index += 1; // Account for the combinator.
}
}