Auto merge of #18097 - bholley:avoid_recursion_clear_descendant_data, r=emilio

Avoid recursion in clear_descendant_data

This will allow us to have a tight stack limit in https://bugzilla.mozilla.org/show_bug.cgi?id=1376883

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18097)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-08-16 04:22:23 -05:00 committed by GitHub
commit 467316e35b

View file

@ -509,7 +509,7 @@ where
if data.styles.is_display_none() {
debug!("{:?} style is display:none - clearing data from descendants.",
element);
clear_descendant_data(element)
unsafe { clear_descendant_data(element); }
}
// Inform any paint worklets of changed style, to speculatively
@ -829,26 +829,30 @@ where
}
}
/// Clear style data for all the subtree under `el`.
pub fn clear_descendant_data<E>(el: E)
/// Clear style data for all the subtree under `root` (but not for root itself).
///
/// We use a list to avoid unbounded recursion, which we need to avoid in the
/// parallel traversal because the rayon stacks are small.
pub unsafe fn clear_descendant_data<E>(root: E)
where
E: TElement,
{
for kid in el.as_node().traversal_children() {
if let Some(kid) = kid.as_element() {
// We maintain an invariant that, if an element has data, all its
// ancestors have data as well.
//
// By consequence, any element without data has no descendants with
// data.
if kid.get_data().is_some() {
unsafe { kid.clear_data() };
clear_descendant_data(kid);
let mut parents = SmallVec::<[E; 32]>::new();
parents.push(root);
while let Some(p) = parents.pop() {
for kid in p.as_node().traversal_children() {
if let Some(kid) = kid.as_element() {
// We maintain an invariant that, if an element has data, all its
// ancestors have data as well.
//
// By consequence, any element without data has no descendants with
// data.
if kid.get_data().is_some() {
kid.clear_data();
parents.push(kid);
}
}
}
}
unsafe {
el.clear_descendants_bits();
p.clear_descendants_bits();
}
}