diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs index 33ec686320d..ce38c3f89ef 100644 --- a/components/style/restyle_hints.rs +++ b/components/style/restyle_hints.rs @@ -37,11 +37,8 @@ use stylist::SelectorMap; /// unnecessary. #[derive(Debug, Clone, PartialEq)] pub struct RestyleHint { - /// Rerun selector matching on the element. - match_self: bool, - - /// Rerun selector matching on all of the element's descendants. - match_descendants: bool, + /// Depths at which selector matching must be re-run. + match_under_self: RestyleDepths, /// Rerun selector matching on all later siblings of the element and all /// of their descendants. @@ -82,6 +79,75 @@ bitflags! { } } +/// Eight bit wide bitfield representing depths of a DOM subtree's descendants, +/// used to represent which elements must have selector matching re-run on them. +/// +/// The least significant bit indicates that selector matching must be re-run +/// for the element itself, the second least significant bit for the element's +/// children, the third its grandchildren, and so on. If the most significant +/// bit it set, it indicates that that selector matching must be re-run for +/// elements at that depth and all of their descendants. +#[derive(Debug, Clone, Copy, PartialEq)] +struct RestyleDepths(u8); + +impl RestyleDepths { + /// Returns a `RestyleDepths` representing no element depths. + fn empty() -> Self { + RestyleDepths(0) + } + + /// Returns a `RestyleDepths` representing the current element depth. + fn for_self() -> Self { + RestyleDepths(0x01) + } + + /// Returns a `RestyleDepths` representing the depths of all descendants of + /// the current element. + fn for_descendants() -> Self { + RestyleDepths(0xfe) + } + + /// Returns a `RestyleDepths` representing the current element depth and the + /// depths of all the current element's descendants. + fn for_self_and_descendants() -> Self { + RestyleDepths(0xff) + } + + /// Returns whether this `RestyleDepths` represents the current element + /// depth and the depths of all the current element's descendants. + fn is_self_and_descendants(&self) -> bool { + self.0 == 0xff + } + + /// Returns whether this `RestyleDepths` includes any element depth. + fn is_any(&self) -> bool { + self.0 != 0 + } + + /// Returns whether this `RestyleDepths` includes the current element depth. + fn has_self(&self) -> bool { + (self.0 & 0x01) != 0 + } + + /// Returns a new `RestyleDepths` with all depth values represented by this + /// `RestyleDepths` reduced by one. + fn propagate(&self) -> Self { + RestyleDepths((self.0 >> 1) | (self.0 & 0x80)) + } + + /// Returns a new `RestyleDepths` that represents the union of the depths + /// from `self` and `other`. + fn insert(&mut self, other: RestyleDepths) { + self.0 |= other.0; + } + + /// Returns whether this `RestyleDepths` includes all depths represented + /// by `other`. + fn contains(&self, other: RestyleDepths) -> bool { + (self.0 & other.0) == other.0 + } +} + /// Asserts that all RestyleReplacements have a matching nsRestyleHint value. #[cfg(feature = "gecko")] #[inline] @@ -116,8 +182,7 @@ impl RestyleHint { #[inline] pub fn empty() -> Self { RestyleHint { - match_self: false, - match_descendants: false, + match_under_self: RestyleDepths::empty(), match_later_siblings: false, replacements: RestyleReplacements::empty(), } @@ -128,8 +193,7 @@ impl RestyleHint { #[inline] pub fn for_self() -> Self { RestyleHint { - match_self: true, - match_descendants: false, + match_under_self: RestyleDepths::for_self(), match_later_siblings: false, replacements: RestyleReplacements::empty(), } @@ -140,8 +204,7 @@ impl RestyleHint { #[inline] pub fn descendants() -> Self { RestyleHint { - match_self: false, - match_descendants: true, + match_under_self: RestyleDepths::for_descendants(), match_later_siblings: false, replacements: RestyleReplacements::empty(), } @@ -152,8 +215,7 @@ impl RestyleHint { #[inline] pub fn later_siblings() -> Self { RestyleHint { - match_self: false, - match_descendants: false, + match_under_self: RestyleDepths::empty(), match_later_siblings: true, replacements: RestyleReplacements::empty(), } @@ -164,8 +226,7 @@ impl RestyleHint { #[inline] pub fn subtree() -> Self { RestyleHint { - match_self: true, - match_descendants: true, + match_under_self: RestyleDepths::for_self_and_descendants(), match_later_siblings: false, replacements: RestyleReplacements::empty(), } @@ -177,8 +238,7 @@ impl RestyleHint { #[inline] pub fn subtree_and_later_siblings() -> Self { RestyleHint { - match_self: true, - match_descendants: true, + match_under_self: RestyleDepths::for_self_and_descendants(), match_later_siblings: true, replacements: RestyleReplacements::empty(), } @@ -189,8 +249,7 @@ impl RestyleHint { #[inline] pub fn for_replacements(replacements: RestyleReplacements) -> Self { RestyleHint { - match_self: false, - match_descendants: false, + match_under_self: RestyleDepths::empty(), match_later_siblings: false, replacements: replacements, } @@ -206,14 +265,16 @@ impl RestyleHint { /// restyle work, and thus any `insert()` calls will have no effect. #[inline] pub fn is_maximum(&self) -> bool { - self.match_self && self.match_descendants && self.match_later_siblings && self.replacements.is_all() + self.match_under_self.is_self_and_descendants() && + self.match_later_siblings && + self.replacements.is_all() } /// Returns whether the hint specifies that some work must be performed on /// the current element. #[inline] pub fn affects_self(&self) -> bool { - self.match_self || !self.replacements.is_empty() + self.match_self() || !self.replacements.is_empty() } /// Returns whether the hint specifies that later siblings must be restyled. @@ -233,7 +294,7 @@ impl RestyleHint { /// animation cascade level replacement. #[inline] pub fn has_non_animation_hint(&self) -> bool { - self.match_self || self.match_descendants || self.match_later_siblings || + self.match_under_self.is_any() || self.match_later_siblings || self.replacements.contains(RESTYLE_STYLE_ATTRIBUTE) } @@ -241,17 +302,17 @@ impl RestyleHint { /// for the element. #[inline] pub fn match_self(&self) -> bool { - self.match_self + self.match_under_self.has_self() } /// Returns a new `RestyleHint` appropriate for children of the current /// element. #[inline] pub fn propagate_for_non_animation_restyle(&self) -> Self { - if self.match_descendants { - Self::subtree() - } else { - Self::empty() + RestyleHint { + match_under_self: self.match_under_self.propagate(), + match_later_siblings: false, + replacements: RestyleReplacements::empty(), } } @@ -271,8 +332,7 @@ impl RestyleHint { /// Unions the specified `RestyleHint` into this one. #[inline] pub fn insert_from(&mut self, other: &Self) { - self.match_self |= other.match_self; - self.match_descendants |= other.match_descendants; + self.match_under_self.insert(other.match_under_self); self.match_later_siblings |= other.match_later_siblings; self.replacements.insert(other.replacements); } @@ -289,9 +349,8 @@ impl RestyleHint { /// work as the specified one. #[inline] pub fn contains(&mut self, other: &Self) -> bool { - !(other.match_self && !self.match_self) && - !(other.match_descendants && !self.match_descendants) && - !(other.match_later_siblings && !self.match_later_siblings) && + self.match_under_self.contains(other.match_under_self) && + (self.match_later_siblings & other.match_later_siblings) == other.match_later_siblings && self.replacements.contains(other.replacements) } } @@ -319,9 +378,16 @@ impl From for RestyleHint { use gecko_bindings::structs::nsRestyleHint_eRestyle_SomeDescendants as eRestyle_SomeDescendants; use gecko_bindings::structs::nsRestyleHint_eRestyle_Subtree as eRestyle_Subtree; + let mut match_under_self = RestyleDepths::empty(); + if (raw.0 & (eRestyle_Self.0 | eRestyle_Subtree.0)) != 0 { + match_under_self.insert(RestyleDepths::for_self()); + } + if (raw.0 & (eRestyle_Subtree.0 | eRestyle_SomeDescendants.0)) != 0 { + match_under_self.insert(RestyleDepths::for_descendants()); + } + RestyleHint { - match_self: (raw.0 & (eRestyle_Self.0 | eRestyle_Subtree.0)) != 0, - match_descendants: (raw.0 & (eRestyle_Subtree.0 | eRestyle_SomeDescendants.0)) != 0, + match_under_self: match_under_self, match_later_siblings: (raw.0 & eRestyle_LaterSiblings.0) != 0, replacements: raw.into(), }