diff options
author | Bobby Holley <bobbyholley@gmail.com> | 2017-04-27 18:09:06 -0700 |
---|---|---|
committer | Bobby Holley <bobbyholley@gmail.com> | 2017-04-29 16:07:44 -0700 |
commit | a6ef89a7fee2e168f46722df452f44d1fc6b3d1e (patch) | |
tree | 1ebd4456c6c5722a7bbae88a699f088dcb429fc6 | |
parent | b4a2e2f17c4618f03cfe7d6654c3332b1309a426 (diff) | |
download | servo-a6ef89a7fee2e168f46722df452f44d1fc6b3d1e.tar.gz servo-a6ef89a7fee2e168f46722df452f44d1fc6b3d1e.zip |
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
-rw-r--r-- | components/style/restyle_hints.rs | 79 |
1 files changed, 43 insertions, 36 deletions
diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs index 8710e590421..193b7e82a9d 100644 --- a/components/style/restyle_hints.rs +++ b/components/style/restyle_hints.rs @@ -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. - // - // 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; - 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); - } + // Visit all the simple selectors in this sequence. + // + // 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; // Account for the simple selector. } - // 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. } } |