diff options
-rw-r--r-- | components/style/data.rs | 22 | ||||
-rw-r--r-- | components/style/restyle_hints.rs | 91 | ||||
-rw-r--r-- | components/style/traversal.rs | 40 |
3 files changed, 120 insertions, 33 deletions
diff --git a/components/style/data.rs b/components/style/data.rs index b16f918f949..2cf5bd56eb1 100644 --- a/components/style/data.rs +++ b/components/style/data.rs @@ -367,6 +367,11 @@ impl StoredRestyleHint { StoredRestyleHint(RestyleHint::subtree_and_later_siblings()) } + /// Creates a restyle hint that indicates the element must be recascaded. + pub fn recascade_self() -> Self { + StoredRestyleHint(RestyleHint::recascade_self()) + } + /// Returns true if the hint indicates that our style may be invalidated. pub fn has_self_invalidations(&self) -> bool { self.0.affects_self() @@ -402,6 +407,12 @@ impl StoredRestyleHint { pub fn has_animation_hint(&self) -> bool { self.0.has_animation_hint() } + + /// Returns true if the hint indicates the current element must be + /// recascaded. + pub fn has_recascade_self(&self) -> bool { + self.0.has_recascade_self() + } } impl Default for StoredRestyleHint { @@ -425,10 +436,6 @@ pub struct RestyleData { /// for this element, its children, and its descendants. pub hint: StoredRestyleHint, - /// Whether we need to recascade. - /// FIXME(bholley): This should eventually become more fine-grained. - pub recascade: bool, - /// The restyle damage, indicating what kind of layout changes are required /// afte restyling. pub damage: RestyleDamage, @@ -447,7 +454,7 @@ pub struct RestyleData { impl RestyleData { /// Returns true if this RestyleData might invalidate the current style. pub fn has_invalidations(&self) -> bool { - self.hint.has_self_invalidations() || self.recascade + self.hint.has_self_invalidations() } /// Returns true if this RestyleData might invalidate sibling styles. @@ -598,12 +605,11 @@ impl ElementData { return RestyleKind::MatchAndCascade; } - if !hint.is_empty() { + if hint.has_replacements() { return RestyleKind::CascadeWithReplacements(hint.replacements); } - debug_assert!(restyle_data.recascade, - "We definitely need to do something!"); + debug_assert!(hint.has_recascade_self(), "We definitely need to do something!"); return RestyleKind::CascadeOnly; } diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs index 9e5dc9ad3e4..c9b8918b33c 100644 --- a/components/style/restyle_hints.rs +++ b/components/style/restyle_hints.rs @@ -45,6 +45,9 @@ pub struct RestyleHint { /// of their descendants. match_later_siblings: bool, + /// Whether the current element and/or all descendants must be recascade. + recascade: CascadeHint, + /// Levels of the cascade whose rule nodes should be recomputed and /// replaced. pub replacements: RestyleReplacements, @@ -155,6 +158,37 @@ impl RestyleDepths { } } +bitflags! { + /// Flags representing whether the current element or its descendants + /// must be recascaded. + /// + /// FIXME(bholley): This should eventually become more fine-grained. + pub flags CascadeHint: u8 { + /// Recascade the current element. + const RECASCADE_SELF = 0x01, + /// Recascade all descendant elements. + const RECASCADE_DESCENDANTS = 0x02, + } +} + +impl CascadeHint { + /// Creates a new `CascadeHint` indicating that the current element and all + /// its descendants must be recascaded. + fn subtree() -> CascadeHint { + RECASCADE_SELF | RECASCADE_DESCENDANTS + } + + /// Returns a new `CascadeHint` appropriate for children of the current + /// element. + fn propagate(&self) -> Self { + if self.contains(RECASCADE_DESCENDANTS) { + CascadeHint::subtree() + } else { + CascadeHint::empty() + } + } +} + /// Asserts that all RestyleReplacements have a matching nsRestyleHint value. #[cfg(feature = "gecko")] #[inline] @@ -191,6 +225,7 @@ impl RestyleHint { RestyleHint { match_under_self: RestyleDepths::empty(), match_later_siblings: false, + recascade: CascadeHint::empty(), replacements: RestyleReplacements::empty(), } } @@ -202,6 +237,7 @@ impl RestyleHint { RestyleHint { match_under_self: RestyleDepths::for_self(), match_later_siblings: false, + recascade: CascadeHint::empty(), replacements: RestyleReplacements::empty(), } } @@ -213,6 +249,7 @@ impl RestyleHint { RestyleHint { match_under_self: RestyleDepths::for_descendants(), match_later_siblings: false, + recascade: CascadeHint::empty(), replacements: RestyleReplacements::empty(), } } @@ -226,6 +263,7 @@ impl RestyleHint { RestyleHint { match_under_self: RestyleDepths::for_depth(depth), match_later_siblings: false, + recascade: CascadeHint::empty(), replacements: RestyleReplacements::empty(), } } @@ -237,6 +275,7 @@ impl RestyleHint { RestyleHint { match_under_self: RestyleDepths::empty(), match_later_siblings: true, + recascade: CascadeHint::empty(), replacements: RestyleReplacements::empty(), } } @@ -248,6 +287,7 @@ impl RestyleHint { RestyleHint { match_under_self: RestyleDepths::for_self_and_descendants(), match_later_siblings: false, + recascade: CascadeHint::empty(), replacements: RestyleReplacements::empty(), } } @@ -260,6 +300,7 @@ impl RestyleHint { RestyleHint { match_under_self: RestyleDepths::for_self_and_descendants(), match_later_siblings: true, + recascade: CascadeHint::empty(), replacements: RestyleReplacements::empty(), } } @@ -271,10 +312,22 @@ impl RestyleHint { RestyleHint { match_under_self: RestyleDepths::empty(), match_later_siblings: false, + recascade: CascadeHint::empty(), replacements: replacements, } } + /// Creates a new `RestyleHint` that indicates the element must be + /// recascaded. + pub fn recascade_self() -> Self { + RestyleHint { + match_under_self: RestyleDepths::empty(), + match_later_siblings: false, + recascade: RECASCADE_SELF, + replacements: RestyleReplacements::empty(), + } + } + /// Returns whether this `RestyleHint` represents no needed restyle work. #[inline] pub fn is_empty(&self) -> bool { @@ -287,6 +340,7 @@ impl RestyleHint { pub fn is_maximum(&self) -> bool { self.match_under_self.is_self_and_descendants() && self.match_later_siblings && + self.recascade.is_all() && self.replacements.is_all() } @@ -294,7 +348,13 @@ impl RestyleHint { /// the current element. #[inline] pub fn affects_self(&self) -> bool { - self.match_self() || !self.replacements.is_empty() + self.match_self() || self.has_recascade_self() || !self.replacements.is_empty() + } + + /// Returns whether the hint specifies that the currently element must be + /// recascaded. + pub fn has_recascade_self(&self) -> bool { + self.recascade.contains(RECASCADE_SELF) } /// Returns whether the hint specifies that later siblings must be restyled. @@ -315,6 +375,7 @@ impl RestyleHint { #[inline] pub fn has_non_animation_hint(&self) -> bool { self.match_under_self.is_any() || self.match_later_siblings || + !self.recascade.is_empty() || self.replacements.contains(RESTYLE_STYLE_ATTRIBUTE) } @@ -325,6 +386,13 @@ impl RestyleHint { self.match_under_self.has_self() } + /// Returns whether the hint specifies that some cascade levels must be + /// replaced. + #[inline] + pub fn has_replacements(&self) -> bool { + !self.replacements.is_empty() + } + /// Returns a new `RestyleHint` appropriate for children of the current /// element. #[inline] @@ -332,6 +400,7 @@ impl RestyleHint { RestyleHint { match_under_self: self.match_under_self.propagate(), match_later_siblings: false, + recascade: self.recascade.propagate(), replacements: RestyleReplacements::empty(), } } @@ -340,6 +409,17 @@ impl RestyleHint { #[inline] pub fn remove_animation_hints(&mut self) { self.replacements.remove(RestyleReplacements::for_animations()); + + // While RECASCADE_SELF is not animation-specific, we only ever add and + // process it during traversal. If we are here, removing animation + // hints, then we are in an animation-only traversal, and we know that + // any RECASCADE_SELF flag must have been set due to changes in + // inherited values after restyling for animations, and thus we + // want to remove it so that we don't later try to restyle the element + // during a normal restyle. (We could have separate + // RECASCADE_SELF_NORMAL and RECASCADE_SELF_ANIMATIONS flags to make it + // clear, but this isn't currently necessary.) + self.recascade.remove(RECASCADE_SELF); } /// Removes the later siblings hint, and returns whether it was present. @@ -354,6 +434,7 @@ impl RestyleHint { pub fn insert_from(&mut self, other: &Self) { self.match_under_self.insert(other.match_under_self); self.match_later_siblings |= other.match_later_siblings; + self.recascade.insert(other.recascade); self.replacements.insert(other.replacements); } @@ -371,6 +452,7 @@ impl RestyleHint { pub fn contains(&self, other: &Self) -> bool { self.match_under_self.contains(other.match_under_self) && (self.match_later_siblings & other.match_later_siblings) == other.match_later_siblings && + self.recascade.contains(other.recascade) && self.replacements.contains(other.replacements) } } @@ -393,6 +475,7 @@ impl From<nsRestyleHint> for RestyleReplacements { #[cfg(feature = "gecko")] impl From<nsRestyleHint> for RestyleHint { fn from(raw: nsRestyleHint) -> Self { + use gecko_bindings::structs::nsRestyleHint_eRestyle_ForceDescendants as eRestyle_ForceDescendants; use gecko_bindings::structs::nsRestyleHint_eRestyle_LaterSiblings as eRestyle_LaterSiblings; use gecko_bindings::structs::nsRestyleHint_eRestyle_Self as eRestyle_Self; use gecko_bindings::structs::nsRestyleHint_eRestyle_SomeDescendants as eRestyle_SomeDescendants; @@ -406,9 +489,15 @@ impl From<nsRestyleHint> for RestyleHint { match_under_self.insert(RestyleDepths::for_descendants()); } + let mut recascade = CascadeHint::empty(); + if (raw.0 & eRestyle_ForceDescendants.0) != 0 { + recascade.insert(CascadeHint::subtree()) + } + RestyleHint { match_under_self: match_under_self, match_later_siblings: (raw.0 & eRestyle_LaterSiblings.0) != 0, + recascade: recascade, replacements: raw.into(), } } diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 60df72ffeba..30f9da0567a 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -351,7 +351,8 @@ pub trait DomTraversal<E: TElement> : Sync { None => return false, }; return data.get_restyle() - .map_or(false, |r| r.hint.has_animation_hint() || r.recascade); + .map_or(false, |r| r.hint.has_animation_hint() || + r.hint.has_recascade_self()); } // If the dirty descendants bit is set, we need to traverse no @@ -381,7 +382,7 @@ pub trait DomTraversal<E: TElement> : Sync { // since that can return true even if we have a restyle hint // indicating that the element's descendants (but not necessarily // the element) need restyling. - if !r.hint.is_empty() || r.recascade { + if !r.hint.is_empty() { return true; } } @@ -696,17 +697,23 @@ pub fn recalc_style_at<E, D>(traversal: &D, // Now that matching and cascading is done, clear the bits corresponding to // those operations and compute the propagated restyle hint. - let propagated_hint = match data.get_restyle_mut() { + let mut propagated_hint = match data.get_restyle_mut() { None => StoredRestyleHint::empty(), Some(r) => { debug_assert!(context.shared.traversal_flags.for_animation_only() || !r.hint.has_animation_hint(), "animation restyle hint should be handled during \ animation-only restyles"); - r.recascade = false; r.hint.propagate(&context.shared.traversal_flags) }, }; + + if inherited_style_changed { + // FIXME(bholley): Need to handle explicitly-inherited reset properties + // somewhere. + propagated_hint.insert(StoredRestyleHint::recascade_self()); + } + trace!("propagated_hint={:?}, inherited_style_changed={:?}, \ is_display_none={:?}, implementing_pseudo={:?}", propagated_hint, inherited_style_changed, @@ -730,8 +737,7 @@ pub fn recalc_style_at<E, D>(traversal: &D, &data, DontLog) && (has_dirty_descendants_for_this_restyle || - !propagated_hint.is_empty() || - inherited_style_changed) { + !propagated_hint.is_empty()) { let damage_handled = data.get_restyle().map_or(RestyleDamage::empty(), |r| { r.damage_handled() | r.damage.handled_for_descendants() }); @@ -740,8 +746,7 @@ pub fn recalc_style_at<E, D>(traversal: &D, traversal_data, element, propagated_hint, - damage_handled, - inherited_style_changed); + damage_handled); } // If we are in a restyle for reconstruction, drop the existing restyle @@ -844,8 +849,7 @@ fn preprocess_children<E, D>(context: &mut StyleContext<E>, parent_traversal_data: &PerLevelTraversalData, element: E, mut propagated_hint: StoredRestyleHint, - damage_handled: RestyleDamage, - parent_inherited_style_changed: bool) + damage_handled: RestyleDamage) where E: TElement, D: DomTraversal<E>, { @@ -888,17 +892,14 @@ fn preprocess_children<E, D>(context: &mut StyleContext<E>, // If the child doesn't have pre-existing RestyleData and we don't have // any reason to create one, avoid the useless allocation and move on to // the next child. - if propagated_hint.is_empty() && !parent_inherited_style_changed && - damage_handled.is_empty() && !child_data.has_restyle() { + if propagated_hint.is_empty() && damage_handled.is_empty() && !child_data.has_restyle() { continue; } let mut restyle_data = child_data.ensure_restyle(); // Propagate the parent and sibling restyle hint. - if !propagated_hint.is_empty() { - restyle_data.hint.insert_from(&propagated_hint); - } + restyle_data.hint.insert_from(&propagated_hint); if later_siblings { propagated_hint.insert(RestyleHint::subtree().into()); @@ -906,15 +907,6 @@ fn preprocess_children<E, D>(context: &mut StyleContext<E>, // Store the damage already handled by ancestors. restyle_data.set_damage_handled(damage_handled); - - // If properties that we inherited from the parent changed, we need to - // recascade. - // - // FIXME(bholley): Need to handle explicitly-inherited reset properties - // somewhere. - if parent_inherited_style_changed { - restyle_data.recascade = true; - } } } |