diff options
author | Bobby Holley <bobbyholley@gmail.com> | 2017-04-09 04:58:52 +0800 |
---|---|---|
committer | Bobby Holley <bobbyholley@gmail.com> | 2017-04-09 12:35:58 +0800 |
commit | 1b363ac9094594110908793c0e2af12cd011e55e (patch) | |
tree | f453d26b4b82c4d5da0c10efefa0b4a372cf1bee | |
parent | 63988b910357fd7180819c46a4585f9d0138c42c (diff) | |
download | servo-1b363ac9094594110908793c0e2af12cd011e55e.tar.gz servo-1b363ac9094594110908793c0e2af12cd011e55e.zip |
Factor out the bottom-up postorder traversal logic.
-rw-r--r-- | components/style/parallel.rs | 56 | ||||
-rw-r--r-- | components/style/traversal.rs | 52 |
2 files changed, 53 insertions, 55 deletions
diff --git a/components/style/parallel.rs b/components/style/parallel.rs index 7f69ce9a01b..ebc08429d09 100644 --- a/components/style/parallel.rs +++ b/components/style/parallel.rs @@ -121,18 +121,8 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>], }); } - // Reset the count of children if we need to do a bottom-up traversal - // after the top up. - if D::needs_postorder_traversal() { - if children_to_process == 0 { - // If there were no more children, start walking back up. - bottom_up_dom(traversal, &mut *tlc, root, node) - } else { - // Otherwise record the number of children to process when the - // time comes. - node.as_element().unwrap().store_children_to_process(children_to_process); - } - } + traversal.handle_postorder_traversal(&mut *tlc, root, node, + children_to_process); } } @@ -173,45 +163,3 @@ fn traverse_nodes<'a, 'scope, E, D>(nodes: Vec<SendNode<E::ConcreteNode>>, root: }) } } - -/// Process current node and potentially traverse its ancestors. -/// -/// If we are the last child that finished processing, recursively process -/// our parent. Else, stop. Also, stop at the root. -/// -/// Thus, if we start with all the leaves of a tree, we end up traversing -/// the whole tree bottom-up because each parent will be processed exactly -/// once (by the last child that finishes processing). -/// -/// The only communication between siblings is that they both -/// fetch-and-subtract the parent's children count. -fn bottom_up_dom<E, D>(traversal: &D, - thread_local: &mut D::ThreadLocalContext, - root: OpaqueNode, - mut node: E::ConcreteNode) - where E: TElement, - D: DomTraversal<E>, -{ - loop { - // Perform the appropriate operation. - traversal.process_postorder(thread_local, node); - - if node.opaque() == root { - break; - } - - let parent = match node.parent_element() { - None => unreachable!("How can this happen after the break above?"), - Some(parent) => parent, - }; - - let remaining = parent.did_process_child(); - if remaining != 0 { - // Get out of here and find another node to work on. - break - } - - // We were the last child of our parent. Construct flows for our parent. - node = parent.as_node(); - } -} diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 37e52eafb8f..2e35c37904e 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -9,7 +9,7 @@ use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext}; use data::{ElementData, ElementStyles, StoredRestyleHint}; -use dom::{DirtyDescendants, NodeInfo, TElement, TNode}; +use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode}; use matching::{MatchMethods, StyleSharingBehavior}; use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_SELF}; use selector_parser::RestyleDamage; @@ -136,6 +136,56 @@ pub trait DomTraversal<E: TElement> : Sync { /// If it's false, then process_postorder has no effect at all. fn needs_postorder_traversal() -> bool { true } + /// Handles the postorder step of the traversal, if it exists, by bubbling + /// up the parent chain. + /// + /// If we are the last child that finished processing, recursively process + /// our parent. Else, stop. Also, stop at the root. + /// + /// Thus, if we start with all the leaves of a tree, we end up traversing + /// the whole tree bottom-up because each parent will be processed exactly + /// once (by the last child that finishes processing). + /// + /// The only communication between siblings is that they both + /// fetch-and-subtract the parent's children count. This makes it safe to + /// call durign the parallel traversal. + fn handle_postorder_traversal(&self, + thread_local: &mut Self::ThreadLocalContext, + root: OpaqueNode, + mut node: E::ConcreteNode, + children_to_process: isize) + { + // If the postorder step is a no-op, don't bother. + if !Self::needs_postorder_traversal() { + return; + } + + if children_to_process == 0 { + // We are a leaf. Walk up the chain. + loop { + self.process_postorder(thread_local, node); + if node.opaque() == root { + break; + } + let parent = node.parent_element().unwrap(); + let remaining = parent.did_process_child(); + if remaining != 0 { + // The parent has other unprocessed descendants. We only + // perform postorder processing after the last descendant + // has been processed. + break + } + + node = parent.as_node(); + } + } else { + // Otherwise record the number of children to process when the + // time comes. + node.as_element().unwrap() + .store_children_to_process(children_to_process); + } + } + /// Must be invoked before traversing the root element to determine whether /// a traversal is needed. Returns a token that allows the caller to prove /// that the call happened. |