mirror of
https://github.com/servo/servo.git
synced 2025-07-13 18:33:40 +01:00
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
57 lines
1.9 KiB
Rust
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();
|
|
}
|