servo/components/style/sequential.rs
Bobby Holley 3a56954069 Bug 1322945 - Change skip_root to unstyled_children_only and use StyleNewChildren in more places. r=heycam
I noticed that our current behavior in ContentRangeInserted is incorrect. Unlike
ContentInserted (where this code lived originally), ContentRangeInserted takes a
start and end element. I'm not sure if we ever take that path for new content that
needs style, but it seemed sketchy. And generally, it seems nice to just always
style new content the same way (though we still need to style NAC by the subtree
root, since it hasn't been attached to the parent yet).

For situations where there is indeed only one unstyled child, the traversal
overhead should be neglible, since we special-case the single-element in
parallel.rs to avoid calling into rayon.

Being more explicit about what we want here also makes us more robust against
the other handful of callpaths that can take us into
nsCSSFrameConstructor::{ContentRangeInserted,ContentAppended}. Currently we
can call StyleNewSubtree on an already-styled element via RecreateFramesForContent,
which triggers an assertion in the servo traversal.

MozReview-Commit-ID: DqCGh90deHH
2016-12-12 18:50:33 -08:00

57 lines
1.9 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.
use dom::{TElement, TNode};
use traversal::{DomTraversalContext, PerLevelTraversalData, PreTraverseToken};
pub fn traverse_dom<N, C>(root: N::ConcreteElement,
shared: &C::SharedContext,
token: PreTraverseToken)
where N: TNode,
C: DomTraversalContext<N>
{
debug_assert!(token.should_traverse());
fn doit<'a, N, C>(context: &'a C, node: N, data: &mut PerLevelTraversalData)
where N: TNode,
C: DomTraversalContext<N>
{
context.process_preorder(node, data);
if let Some(el) = node.as_element() {
if let Some(ref mut depth) = data.current_dom_depth {
*depth += 1;
}
C::traverse_children(el, |kid| doit::<N, C>(context, kid, data));
if let Some(ref mut depth) = data.current_dom_depth {
*depth -= 1;
}
}
if C::needs_postorder_traversal() {
context.process_postorder(node);
}
}
let mut data = PerLevelTraversalData {
current_dom_depth: None,
};
let context = C::new(shared, root.as_node().opaque());
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::<N, C>(&context, kid, &mut data);
}
}
} else {
doit::<N, C>(&context, root.as_node(), &mut data);
}
// Clear the local LRU cache since we store stateful elements inside.
context.local_context().style_sharing_candidate_cache.borrow_mut().clear();
}