diff options
-rw-r--r-- | components/layout/traversal.rs | 2 | ||||
-rw-r--r-- | components/layout_thread/lib.rs | 3 | ||||
-rw-r--r-- | components/style/bloom.rs | 26 | ||||
-rw-r--r-- | components/style/dom.rs | 12 | ||||
-rw-r--r-- | components/style/gecko/traversal.rs | 2 | ||||
-rw-r--r-- | components/style/parallel.rs | 10 | ||||
-rw-r--r-- | components/style/sequential.rs | 58 | ||||
-rw-r--r-- | components/style/traversal.rs | 22 | ||||
-rw-r--r-- | ports/geckolib/glue.rs | 3 |
9 files changed, 63 insertions, 75 deletions
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 3c0c1763d0c..844a61527b6 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -56,7 +56,7 @@ impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a> { type ThreadLocalContext = ScopedThreadLocalLayoutContext<E>; - fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData, + fn process_preorder(&self, traversal_data: &PerLevelTraversalData, thread_local: &mut Self::ThreadLocalContext, node: E::ConcreteNode) { // FIXME(pcwalton): Stop allocating here. Ideally this should just be // done by the HTML parser. diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 2d9b921391f..9822d7eef0b 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -1146,7 +1146,6 @@ impl LayoutThread { }; let traversal = RecalcStyleAndConstructFlows::new(layout_context, traversal_driver); - let dom_depth = Some(0); // This is always the root node. let token = { let stylist = &<RecalcStyleAndConstructFlows as DomTraversal<ServoLayoutElement>>::shared_context(&traversal).stylist; @@ -1165,7 +1164,7 @@ impl LayoutThread { let pool = self.parallel_traversal.as_mut().unwrap(); // Parallel mode parallel::traverse_dom::<ServoLayoutElement, RecalcStyleAndConstructFlows>( - &traversal, element, dom_depth, token, pool); + &traversal, element, token, pool); } else { // Sequential mode sequential::traverse_dom::<ServoLayoutElement, RecalcStyleAndConstructFlows>( diff --git a/components/style/bloom.rs b/components/style/bloom.rs index aba2d9fa5b8..e8ba95aeb94 100644 --- a/components/style/bloom.rs +++ b/components/style/bloom.rs @@ -99,7 +99,7 @@ impl<E: TElement> StyleBloom<E> { } /// Rebuilds the bloom filter up to the parent of the given element. - pub fn rebuild(&mut self, mut element: E) -> usize { + pub fn rebuild(&mut self, mut element: E) { self.clear(); while let Some(parent) = element.parent_element() { @@ -110,7 +110,6 @@ impl<E: TElement> StyleBloom<E> { // Put them in the order we expect, from root to `element`'s parent. self.elements.reverse(); - return self.elements.len(); } /// In debug builds, asserts that all the parents of `element` are in the @@ -139,12 +138,12 @@ impl<E: TElement> StyleBloom<E> { /// responsible to keep around if it wants to get an effective filter. pub fn insert_parents_recovering(&mut self, element: E, - element_depth: Option<usize>) - -> usize + element_depth: usize) { // Easy case, we're in a different restyle, or we're empty. if self.elements.is_empty() { - return self.rebuild(element); + self.rebuild(element); + return; } let parent_element = match element.parent_element() { @@ -152,23 +151,19 @@ impl<E: TElement> StyleBloom<E> { None => { // Yay, another easy case. self.clear(); - return 0; + return; } }; if self.elements.last().map(|el| **el) == Some(parent_element) { // Ta da, cache hit, we're all done. - return self.elements.len(); + return; } - let element_depth = match element_depth { - Some(depth) => depth, - // If we don't know the depth of `element`, we'd rather don't try - // fixing up the bloom filter, since it's quadratic. - None => { - return self.rebuild(element); - } - }; + if element_depth == 0 { + self.clear(); + return; + } // We should've early exited above. debug_assert!(element_depth != 0, @@ -250,6 +245,5 @@ impl<E: TElement> StyleBloom<E> { debug_assert_eq!(self.elements.len(), element_depth); // We're done! Easy. - return self.elements.len(); } } diff --git a/components/style/dom.rs b/components/style/dom.rs index 602401530ca..bd201683afe 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -281,6 +281,18 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre /// Get this element as a node. fn as_node(&self) -> Self::ConcreteNode; + /// Returns the depth of this element in the DOM. + fn depth(&self) -> usize { + let mut depth = 0; + let mut curr = *self; + while let Some(parent) = curr.parent_element() { + depth += 1; + curr = parent; + } + + depth + } + /// While doing a reflow, the element at the root has no parent, as far as we're /// concerned. This method returns `None` at the reflow root. fn layout_parent_element(self, reflow_root: OpaqueNode) -> Option<Self> { diff --git a/components/style/gecko/traversal.rs b/components/style/gecko/traversal.rs index 7a68f66c75f..eb7f52ad269 100644 --- a/components/style/gecko/traversal.rs +++ b/components/style/gecko/traversal.rs @@ -32,7 +32,7 @@ impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc> type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'le>>; fn process_preorder(&self, - traversal_data: &mut PerLevelTraversalData, + traversal_data: &PerLevelTraversalData, thread_local: &mut Self::ThreadLocalContext, node: GeckoNode<'le>) { diff --git a/components/style/parallel.rs b/components/style/parallel.rs index ebc08429d09..2b39eb461d0 100644 --- a/components/style/parallel.rs +++ b/components/style/parallel.rs @@ -39,7 +39,6 @@ pub const CHUNK_SIZE: usize = 64; #[allow(unsafe_code)] pub fn traverse_dom<E, D>(traversal: &D, root: E, - known_root_dom_depth: Option<usize>, token: PreTraverseToken, queue: &rayon::ThreadPool) where E: TElement, @@ -60,9 +59,9 @@ pub fn traverse_dom<E, D>(traversal: &D, children.push(unsafe { SendNode::new(kid) }); } } - (children, known_root_dom_depth.map(|x| x + 1)) + (children, root.depth() + 1) } else { - (vec![unsafe { SendNode::new(root.as_node()) }], known_root_dom_depth) + (vec![unsafe { SendNode::new(root.as_node()) }], root.depth()) }; let traversal_data = PerLevelTraversalData { @@ -126,10 +125,7 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>], } } - if let Some(ref mut depth) = traversal_data.current_dom_depth { - *depth += 1; - } - + traversal_data.current_dom_depth += 1; traverse_nodes(discovered_child_nodes, root, traversal_data, scope, traversal, tls); } diff --git a/components/style/sequential.rs b/components/style/sequential.rs index 0cb068e6f03..38ea519e474 100644 --- a/components/style/sequential.rs +++ b/components/style/sequential.rs @@ -9,9 +9,12 @@ use context::TraversalStatistics; use dom::{TElement, TNode}; use std::borrow::BorrowMut; +use std::collections::VecDeque; use time; use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken}; +struct WorkItem<N: TNode>(N, usize); + /// Do a sequential DOM traversal for layout or styling, generic over `D`. pub fn traverse_dom<E, D>(traversal: &D, root: E, @@ -25,44 +28,37 @@ pub fn traverse_dom<E, D>(traversal: &D, debug_assert!(!traversal.is_parallel()); debug_assert!(token.should_traverse()); - fn doit<E, D>(traversal: &D, traversal_data: &mut PerLevelTraversalData, - thread_local: &mut D::ThreadLocalContext, node: E::ConcreteNode) - where E: TElement, - D: DomTraversal<E> - { - traversal.process_preorder(traversal_data, thread_local, node); - if let Some(el) = node.as_element() { - if let Some(ref mut depth) = traversal_data.current_dom_depth { - *depth += 1; - } - - traversal.traverse_children(thread_local, el, |tlc, kid| { - doit(traversal, traversal_data, tlc, kid) - }); - - if let Some(ref mut depth) = traversal_data.current_dom_depth { - *depth -= 1; - } - } - - if D::needs_postorder_traversal() { - traversal.process_postorder(thread_local, node); - } - } - - let mut traversal_data = PerLevelTraversalData { - current_dom_depth: None, - }; - + let mut discovered = VecDeque::<WorkItem<E::ConcreteNode>>::with_capacity(16); let mut tlc = traversal.create_thread_local_context(); + let root_depth = root.depth(); + if token.traverse_unstyled_children_only() { for kid in root.as_node().children() { if kid.as_element().map_or(false, |el| el.get_data().is_none()) { - doit(traversal, &mut traversal_data, &mut tlc, kid); + discovered.push_back(WorkItem(kid, root_depth + 1)); } } } else { - doit(traversal, &mut traversal_data, &mut tlc, root.as_node()); + discovered.push_back(WorkItem(root.as_node(), root_depth)); + } + + // Process the nodes breadth-first, just like the parallel traversal does. + // This helps keep similar traversal characteristics for the style sharing + // cache. + while let Some(WorkItem(node, depth)) = discovered.pop_front() { + let mut children_to_process = 0isize; + let traversal_data = PerLevelTraversalData { current_dom_depth: depth }; + traversal.process_preorder(&traversal_data, &mut tlc, node); + + if let Some(el) = node.as_element() { + traversal.traverse_children(&mut tlc, el, |_tlc, kid| { + children_to_process += 1; + discovered.push_back(WorkItem(kid, depth + 1)) + }); + } + + traversal.handle_postorder_traversal(&mut tlc, root.as_node().opaque(), + node, children_to_process); } // Dump statistics to stdout if requested. diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 2e35c37904e..f5be141cb66 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -23,11 +23,11 @@ use stylist::Stylist; /// NB: Keep this as small as possible, please! #[derive(Clone, Debug)] pub struct PerLevelTraversalData { - /// The current dom depth, if known, or `None` otherwise. + /// The current dom depth. /// /// This is kept with cooperation from the traversal code and the bloom /// filter. - pub current_dom_depth: Option<usize>, + pub current_dom_depth: usize, } bitflags! { @@ -119,7 +119,7 @@ pub trait DomTraversal<E: TElement> : Sync { type ThreadLocalContext: Send + BorrowMut<ThreadLocalStyleContext<E>>; /// Process `node` on the way down, before its children have been processed. - fn process_preorder(&self, data: &mut PerLevelTraversalData, + fn process_preorder(&self, data: &PerLevelTraversalData, thread_local: &mut Self::ThreadLocalContext, node: E::ConcreteNode); @@ -521,7 +521,7 @@ pub fn resolve_style<E, F, G, H>(context: &mut StyleContext<E>, element: E, #[inline] #[allow(unsafe_code)] pub fn recalc_style_at<E, D>(traversal: &D, - traversal_data: &mut PerLevelTraversalData, + traversal_data: &PerLevelTraversalData, context: &mut StyleContext<E>, element: E, mut data: &mut AtomicRefMut<ElementData>) @@ -619,7 +619,7 @@ pub fn recalc_style_at<E, D>(traversal: &D, } fn compute_style<E, D>(_traversal: &D, - traversal_data: &mut PerLevelTraversalData, + traversal_data: &PerLevelTraversalData, context: &mut StyleContext<E>, element: E, mut data: &mut AtomicRefMut<ElementData>) @@ -650,16 +650,8 @@ fn compute_style<E, D>(_traversal: &D, match kind { MatchAndCascade => { // Ensure the bloom filter is up to date. - let dom_depth = - context.thread_local.bloom_filter - .insert_parents_recovering(element, - traversal_data.current_dom_depth); - - // Update the dom depth with the up-to-date dom depth. - // - // Note that this is always the same than the pre-existing depth, - // but it can change from unknown to known at this step. - traversal_data.current_dom_depth = Some(dom_depth); + context.thread_local.bloom_filter + .insert_parents_recovering(element, traversal_data.current_dom_depth); context.thread_local.bloom_filter.assert_complete(element); context.thread_local.statistics.elements_matched += 1; diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 94f03ebbb4e..62c0294f202 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -193,9 +193,8 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed, }; let traversal = RecalcStyleOnly::new(shared_style_context, traversal_driver); - let known_depth = None; if traversal_driver.is_parallel() { - parallel::traverse_dom(&traversal, element, known_depth, token, + parallel::traverse_dom(&traversal, element, token, global_style_data.style_thread_pool.as_ref().unwrap()); } else { sequential::traverse_dom(&traversal, element, token); |