servo/components/style/sequential.rs
Bobby Holley 3f52052cf9 Do the sequential traversal breadth-first.
While we're at it, we also eliminate the 'unknown' dom depth for the
bloom filter. Computing depth has negligible cost relative to the
amount of work we do setting up the bloom filter at a given depth.
Doing it once per traversal should be totally fine.

I originally separated the elimination of unknown dom depth from the
traversal changes, but I got bloom filter crashes on the intermediate
patch, presumably because I didn't properly fix the sequential traversal
for this case. Given that the final state is green, I just decided to
squash and move on.
2017-04-09 14:52:49 +08:00

70 lines
2.5 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Implements sequential traversal over the DOM tree.
#![deny(missing_docs)]
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,
token: PreTraverseToken)
where E: TElement,
D: DomTraversal<E>,
{
let dump_stats = TraversalStatistics::should_dump();
let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };
debug_assert!(!traversal.is_parallel());
debug_assert!(token.should_traverse());
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()) {
discovered.push_back(WorkItem(kid, root_depth + 1));
}
}
} else {
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.
if dump_stats {
let tlsc = tlc.borrow_mut();
tlsc.statistics.finish(traversal, start_time.unwrap());
println!("{}", tlsc.statistics);
}
}