diff options
Diffstat (limited to 'components/style')
-rw-r--r-- | components/style/dom.rs | 53 | ||||
-rw-r--r-- | components/style/traversal.rs | 4 |
2 files changed, 55 insertions, 2 deletions
diff --git a/components/style/dom.rs b/components/style/dom.rs index 9d25013b15e..ab6ed9aed30 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -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 diff --git a/components/style/traversal.rs b/components/style/traversal.rs index df70c29664c..b37b10ef94f 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -9,7 +9,7 @@ use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext}; use data::{ElementData, ElementStyles, StoredRestyleHint}; -use dom::{NodeInfo, TElement, TNode}; +use dom::{DirtyDescendants, NodeInfo, TElement, TNode}; use matching::{MatchMethods, MatchResults}; use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_SELF}; use selector_parser::RestyleDamage; @@ -388,7 +388,7 @@ fn resolve_style_internal<E, F>(context: &mut StyleContext<E>, // Conservatively mark us as having dirty descendants, since there might // be other unstyled siblings we miss when walking straight up the parent // chain. - unsafe { element.set_dirty_descendants() }; + unsafe { element.note_descendants::<DirtyDescendants>() }; } // If we're display:none and none of our ancestors are, we're the root |