mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Centralize note_dirty_descendants implementation, and fully propagate dirty_descendants in resolve_style.
The current code can leave the tree in an inconsistent state, with the dirty descendants bit not fully propagated. MozReview-Commit-ID: ALI6etmlrDa
This commit is contained in:
parent
185d31f086
commit
7c58483aff
4 changed files with 68 additions and 27 deletions
|
@ -22,6 +22,7 @@ use std::fmt::Debug;
|
|||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use stylist::ApplicableDeclarationBlock;
|
||||
use thread_state;
|
||||
|
||||
pub use style_traits::UnsafeNode;
|
||||
|
||||
|
@ -305,6 +306,36 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
|
|||
/// Only safe to call with exclusive access to the element.
|
||||
unsafe fn set_dirty_descendants(&self);
|
||||
|
||||
/// Flag that this element has a descendant for style processing, propagating
|
||||
/// the bit up to the root as needed.
|
||||
///
|
||||
/// This is _not_ safe to call during the parallel traversal.
|
||||
unsafe fn note_descendants<B: DescendantsBit<Self>>(&self) {
|
||||
debug_assert!(!thread_state::get().is_worker());
|
||||
let mut curr = Some(*self);
|
||||
while curr.is_some() && !B::has(curr.unwrap()) {
|
||||
B::set(curr.unwrap());
|
||||
curr = curr.unwrap().parent_element();
|
||||
}
|
||||
|
||||
// Note: We disable this assertion on servo because of bugs. See the
|
||||
// comment around note_dirty_descendant in layout/wrapper.rs.
|
||||
if cfg!(feature = "gecko") {
|
||||
debug_assert!(self.descendants_bit_is_propagated::<B>());
|
||||
}
|
||||
}
|
||||
|
||||
/// Debug helper to be sure the bit is propagated.
|
||||
fn descendants_bit_is_propagated<B: DescendantsBit<Self>>(&self) -> bool {
|
||||
let mut current = Some(*self);
|
||||
while let Some(el) = current {
|
||||
if !B::has(el) { return false; }
|
||||
current = el.parent_element();
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Flag that this element has no descendant for style processing.
|
||||
///
|
||||
/// Only safe to call with exclusive access to the element.
|
||||
|
@ -391,6 +422,28 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
|
|||
}
|
||||
}
|
||||
|
||||
/// Trait abstracting over different kinds of dirty-descendants bits.
|
||||
pub trait DescendantsBit<E: TElement> {
|
||||
/// Returns true if the Element has the bit.
|
||||
fn has(el: E) -> bool;
|
||||
/// Sets the bit on the Element.
|
||||
unsafe fn set(el: E);
|
||||
}
|
||||
|
||||
/// Implementation of DescendantsBit for the regular dirty descendants bit.
|
||||
pub struct DirtyDescendants;
|
||||
impl<E: TElement> DescendantsBit<E> for DirtyDescendants {
|
||||
fn has(el: E) -> bool { el.has_dirty_descendants() }
|
||||
unsafe fn set(el: E) { el.set_dirty_descendants(); }
|
||||
}
|
||||
|
||||
/// Implementation of DescendantsBit for the animation-only dirty descendants bit.
|
||||
pub struct AnimationOnlyDirtyDescendants;
|
||||
impl<E: TElement> DescendantsBit<E> for AnimationOnlyDirtyDescendants {
|
||||
fn has(el: E) -> bool { el.has_animation_only_dirty_descendants() }
|
||||
unsafe fn set(el: E) { el.set_animation_only_dirty_descendants(); }
|
||||
}
|
||||
|
||||
/// TNode and TElement aren't Send because we want to be careful and explicit
|
||||
/// about our parallel traversal. However, there are certain situations
|
||||
/// (including but not limited to the traversal) where we need to send DOM
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue