aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBobby Holley <bobbyholley@gmail.com>2017-04-09 04:58:52 +0800
committerBobby Holley <bobbyholley@gmail.com>2017-04-09 12:35:58 +0800
commit1b363ac9094594110908793c0e2af12cd011e55e (patch)
treef453d26b4b82c4d5da0c10efefa0b4a372cf1bee
parent63988b910357fd7180819c46a4585f9d0138c42c (diff)
downloadservo-1b363ac9094594110908793c0e2af12cd011e55e.tar.gz
servo-1b363ac9094594110908793c0e2af12cd011e55e.zip
Factor out the bottom-up postorder traversal logic.
-rw-r--r--components/style/parallel.rs56
-rw-r--r--components/style/traversal.rs52
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.