tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

restyle_hints.rs (7267B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 //! Restyle hints: an optimization to avoid unnecessarily matching selectors.
      6 
      7 use crate::traversal_flags::TraversalFlags;
      8 
      9 bitflags! {
     10    /// The kind of restyle we need to do for a given element.
     11    #[repr(C)]
     12    #[derive(Clone, Copy, Debug)]
     13    pub struct RestyleHint: u16 {
     14        /// Do a selector match of the element.
     15        const RESTYLE_SELF = 1 << 0;
     16 
     17        /// Do a selector match of the element's pseudo-elements. Always to be combined with
     18        /// RESTYLE_SELF.
     19        const RESTYLE_PSEUDOS = 1 << 1;
     20 
     21        /// Do a selector match if the element is a pseudo-element.
     22        const RESTYLE_SELF_IF_PSEUDO = 1 << 2;
     23 
     24        /// Do a selector match of the element's descendants.
     25        const RESTYLE_DESCENDANTS = 1 << 3;
     26 
     27        /// Recascade the current element.
     28        const RECASCADE_SELF = 1 << 4;
     29 
     30        /// Recascade the current element if it inherits any reset style.
     31        const RECASCADE_SELF_IF_INHERIT_RESET_STYLE = 1 << 5;
     32 
     33        /// Recascade all descendant elements.
     34        const RECASCADE_DESCENDANTS = 1 << 6;
     35 
     36        /// Replace the style data coming from CSS transitions without updating
     37        /// any other style data. This hint is only processed in animation-only
     38        /// traversal which is prior to normal traversal.
     39        const RESTYLE_CSS_TRANSITIONS = 1 << 7;
     40 
     41        /// Replace the style data coming from CSS animations without updating
     42        /// any other style data. This hint is only processed in animation-only
     43        /// traversal which is prior to normal traversal.
     44        const RESTYLE_CSS_ANIMATIONS = 1 << 8;
     45 
     46        /// Don't re-run selector-matching on the element, only the style
     47        /// attribute has changed, and this change didn't have any other
     48        /// dependencies.
     49        const RESTYLE_STYLE_ATTRIBUTE = 1 << 9;
     50 
     51        /// Replace the style data coming from SMIL animations without updating
     52        /// any other style data. This hint is only processed in animation-only
     53        /// traversal which is prior to normal traversal.
     54        const RESTYLE_SMIL = 1 << 10;
     55    }
     56 }
     57 
     58 impl RestyleHint {
     59    /// Creates a new `RestyleHint` indicating that the current element and all
     60    /// its descendants must be fully restyled.
     61    #[inline]
     62    pub fn restyle_subtree() -> Self {
     63        RestyleHint::RESTYLE_SELF | RestyleHint::RESTYLE_DESCENDANTS
     64    }
     65 
     66    /// Creates a new `RestyleHint` indicating that the current element and all
     67    /// its descendants must be recascaded.
     68    #[inline]
     69    pub fn recascade_subtree() -> Self {
     70        RestyleHint::RECASCADE_SELF | RestyleHint::RECASCADE_DESCENDANTS
     71    }
     72 
     73    /// Returns whether this hint invalidates the element and all its
     74    /// descendants.
     75    #[inline]
     76    pub fn contains_subtree(&self) -> bool {
     77        self.contains(Self::restyle_subtree())
     78    }
     79 
     80    /// Returns whether we'll recascade all of the descendants.
     81    #[inline]
     82    pub fn will_recascade_subtree(&self) -> bool {
     83        self.contains_subtree() || self.contains(Self::recascade_subtree())
     84    }
     85 
     86    /// Returns whether we need to restyle this element.
     87    pub fn has_non_animation_invalidations(&self) -> bool {
     88        !(*self & !Self::for_animations()).is_empty()
     89    }
     90 
     91    /// Propagates this restyle hint to a child element.
     92    pub fn propagate(&mut self, traversal_flags: &TraversalFlags) -> Self {
     93        use std::mem;
     94 
     95        // In the middle of an animation only restyle, we don't need to
     96        // propagate any restyle hints, and we need to remove ourselves.
     97        if traversal_flags.for_animation_only() {
     98            self.remove_animation_hints();
     99            return Self::empty();
    100        }
    101 
    102        debug_assert!(
    103            !self.has_animation_hint(),
    104            "There should not be any animation restyle hints \
    105             during normal traversal"
    106        );
    107 
    108        // Else we should clear ourselves, and return the propagated hint.
    109        mem::replace(self, Self::empty()).propagate_for_non_animation_restyle()
    110    }
    111 
    112    /// Returns a new `RestyleHint` appropriate for children of the current element.
    113    fn propagate_for_non_animation_restyle(&self) -> Self {
    114        if self.contains(RestyleHint::RESTYLE_DESCENDANTS) {
    115            return Self::restyle_subtree();
    116        }
    117        let mut result = Self::empty();
    118        if self.contains(RestyleHint::RESTYLE_PSEUDOS) {
    119            result |= Self::RESTYLE_SELF_IF_PSEUDO;
    120        }
    121        if self.contains(RestyleHint::RECASCADE_DESCENDANTS) {
    122            result |= Self::recascade_subtree();
    123        }
    124        result
    125    }
    126 
    127    /// Returns a hint that contains all the replacement hints.
    128    pub fn replacements() -> Self {
    129        RestyleHint::RESTYLE_STYLE_ATTRIBUTE | Self::for_animations()
    130    }
    131 
    132    /// The replacements for the animation cascade levels.
    133    #[inline]
    134    pub fn for_animations() -> Self {
    135        RestyleHint::RESTYLE_SMIL
    136            | RestyleHint::RESTYLE_CSS_ANIMATIONS
    137            | RestyleHint::RESTYLE_CSS_TRANSITIONS
    138    }
    139 
    140    /// Returns whether the hint specifies that an animation cascade level must
    141    /// be replaced.
    142    #[inline]
    143    pub fn has_animation_hint(&self) -> bool {
    144        self.intersects(Self::for_animations())
    145    }
    146 
    147    /// Returns whether the hint specifies that an animation cascade level must
    148    /// be replaced.
    149    #[inline]
    150    pub fn has_animation_hint_or_recascade(&self) -> bool {
    151        self.intersects(
    152            Self::for_animations()
    153                | Self::RECASCADE_SELF
    154                | Self::RECASCADE_SELF_IF_INHERIT_RESET_STYLE,
    155        )
    156    }
    157 
    158    /// Returns whether the hint specifies some restyle work other than an
    159    /// animation cascade level replacement.
    160    #[inline]
    161    pub fn has_non_animation_hint(&self) -> bool {
    162        !(*self & !Self::for_animations()).is_empty()
    163    }
    164 
    165    /// Returns whether the hint specifies that some cascade levels must be
    166    /// replaced.
    167    #[inline]
    168    pub fn has_replacements(&self) -> bool {
    169        self.intersects(Self::replacements())
    170    }
    171 
    172    /// Removes all of the animation-related hints.
    173    #[inline]
    174    pub fn remove_animation_hints(&mut self) {
    175        self.remove(Self::for_animations());
    176 
    177        // While RECASCADE_SELF is not animation-specific, we only ever add and process it during
    178        // traversal.  If we are here, removing animation hints, then we are in an animation-only
    179        // traversal, and we know that any RECASCADE_SELF flag must have been set due to changes in
    180        // inherited values after restyling for animations, and thus we want to remove it so that
    181        // we don't later try to restyle the element during a normal restyle.
    182        // (We could have separate RECASCADE_SELF_NORMAL and RECASCADE_SELF_ANIMATIONS flags to
    183        // make it clear, but this isn't currently necessary.)
    184        self.remove(Self::RECASCADE_SELF | Self::RECASCADE_SELF_IF_INHERIT_RESET_STYLE);
    185    }
    186 }
    187 
    188 impl Default for RestyleHint {
    189    fn default() -> Self {
    190        Self::empty()
    191    }
    192 }
    193 
    194 #[cfg(feature = "servo")]
    195 malloc_size_of::malloc_size_of_is_0!(RestyleHint);