tor-browser

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

applicable_declarations.rs (9817B)


      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 //! Applicable declarations management.
      6 
      7 use crate::derives::*;
      8 use crate::properties::PropertyDeclarationBlock;
      9 use crate::rule_tree::{CascadeLevel, StyleSource};
     10 use crate::shared_lock::Locked;
     11 use crate::stylesheets::layer_rule::LayerOrder;
     12 use servo_arc::Arc;
     13 use smallvec::SmallVec;
     14 
     15 /// List of applicable declarations. This is a transient structure that shuttles
     16 /// declarations between selector matching and inserting into the rule tree, and
     17 /// therefore we want to avoid heap-allocation where possible.
     18 ///
     19 /// In measurements on wikipedia, we pretty much never have more than 8 applicable
     20 /// declarations, so we could consider making this 8 entries instead of 16.
     21 /// However, it may depend a lot on workload, and stack space is cheap.
     22 pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>;
     23 
     24 /// Blink uses 18 bits to store source order, and does not check overflow [1].
     25 /// That's a limit that could be reached in realistic webpages, so we use
     26 /// 24 bits and enforce defined behavior in the overflow case.
     27 ///
     28 /// Note that right now this restriction could be lifted if wanted (because we
     29 /// no longer stash the cascade level in the remaining bits), but we keep it in
     30 /// place in case we come up with a use-case for them, lacking reports of the
     31 /// current limit being too small.
     32 ///
     33 /// [1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/
     34 ///     RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3
     35 const SOURCE_ORDER_BITS: usize = 24;
     36 const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
     37 const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX;
     38 
     39 /// The cascade-level+layer order of this declaration.
     40 #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
     41 pub struct CascadePriority {
     42    cascade_level: CascadeLevel,
     43    layer_order: LayerOrder,
     44 }
     45 
     46 const_assert_eq!(
     47    std::mem::size_of::<CascadePriority>(),
     48    std::mem::size_of::<u32>()
     49 );
     50 
     51 impl PartialOrd for CascadePriority {
     52    #[inline]
     53    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
     54        Some(self.cmp(other))
     55    }
     56 }
     57 
     58 impl Ord for CascadePriority {
     59    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
     60        self.cascade_level.cmp(&other.cascade_level).then_with(|| {
     61            let ordering = self.layer_order.cmp(&other.layer_order);
     62            if ordering == std::cmp::Ordering::Equal {
     63                return ordering;
     64            }
     65            // https://drafts.csswg.org/css-cascade-5/#cascade-layering
     66            //
     67            //     Cascade layers (like declarations) are ordered by order
     68            //     of appearance. When comparing declarations that belong to
     69            //     different layers, then for normal rules the declaration
     70            //     whose cascade layer is last wins, and for important rules
     71            //     the declaration whose cascade layer is first wins.
     72            //
     73            // But the style attribute layer for some reason is special.
     74            if self.cascade_level.is_important()
     75                && !self.layer_order.is_style_attribute_layer()
     76                && !other.layer_order.is_style_attribute_layer()
     77            {
     78                ordering.reverse()
     79            } else {
     80                ordering
     81            }
     82        })
     83    }
     84 }
     85 
     86 impl CascadePriority {
     87    /// Construct a new CascadePriority for a given (level, order) pair.
     88    pub fn new(cascade_level: CascadeLevel, layer_order: LayerOrder) -> Self {
     89        Self {
     90            cascade_level,
     91            layer_order,
     92        }
     93    }
     94 
     95    /// Returns the layer order.
     96    #[inline]
     97    pub fn layer_order(&self) -> LayerOrder {
     98        self.layer_order
     99    }
    100 
    101    /// Returns the cascade level.
    102    #[inline]
    103    pub fn cascade_level(&self) -> CascadeLevel {
    104        self.cascade_level
    105    }
    106 
    107    /// Whether this declaration should be allowed if `revert` or `revert-layer`
    108    /// have been specified on a given origin.
    109    ///
    110    /// `self` is the priority at which the `revert` or `revert-layer` keyword
    111    /// have been specified.
    112    pub fn allows_when_reverted(&self, other: &Self, origin_revert: bool) -> bool {
    113        if origin_revert {
    114            other.cascade_level.origin() < self.cascade_level.origin()
    115        } else {
    116            other.unimportant() < self.unimportant()
    117        }
    118    }
    119 
    120    /// Convert this priority from "important" to "non-important", if needed.
    121    pub fn unimportant(&self) -> Self {
    122        Self::new(self.cascade_level().unimportant(), self.layer_order())
    123    }
    124 
    125    /// Convert this priority from "non-important" to "important", if needed.
    126    pub fn important(&self) -> Self {
    127        Self::new(self.cascade_level().important(), self.layer_order())
    128    }
    129 
    130    /// The same tree, in author origin, at the root layer.
    131    pub fn same_tree_author_normal_at_root_layer() -> Self {
    132        Self::new(CascadeLevel::same_tree_author_normal(), LayerOrder::root())
    133    }
    134 }
    135 
    136 /// Proximity to the scope root.
    137 ///
    138 /// https://drafts.csswg.org/css-cascade-6/#cascade-proximity
    139 #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
    140 pub struct ScopeProximity(u16);
    141 
    142 impl PartialOrd for ScopeProximity {
    143    #[inline]
    144    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
    145        Some(self.cmp(other))
    146    }
    147 }
    148 
    149 impl Ord for ScopeProximity {
    150    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
    151        // Lower proximity to scope root wins
    152        other.0.cmp(&self.0)
    153    }
    154 }
    155 
    156 /// Sacrifice the largest possible value for infinity. This makes the comparison
    157 /// trivial.
    158 const PROXIMITY_INFINITY: u16 = u16::MAX;
    159 
    160 impl ScopeProximity {
    161    /// Construct a new scope proximity.
    162    pub fn new(proximity: usize) -> Self {
    163        if cfg!(debug_assertions) && proximity >= PROXIMITY_INFINITY as usize {
    164            warn!("Proximity out of bounds");
    165        }
    166        Self(proximity.clamp(0, (PROXIMITY_INFINITY - 1) as usize) as u16)
    167    }
    168 
    169    /// Create a scope proximity for delcarations outside of any scope root.
    170    pub fn infinity() -> Self {
    171        Self(PROXIMITY_INFINITY)
    172    }
    173 
    174    /// If the proximity is finite, get the value.
    175    pub fn get(&self) -> Option<u16> {
    176        (self.0 != PROXIMITY_INFINITY).then(|| self.0)
    177    }
    178 }
    179 
    180 /// A property declaration together with its precedence among rules of equal
    181 /// specificity so that we can sort them.
    182 ///
    183 /// This represents the declarations in a given declaration block for a given
    184 /// importance.
    185 #[derive(Clone, Debug, MallocSizeOf, PartialEq)]
    186 pub struct ApplicableDeclarationBlock {
    187    /// The style source, either a style rule, or a property declaration block.
    188    #[ignore_malloc_size_of = "Arc"]
    189    pub source: StyleSource,
    190    /// Order of appearance in which this rule appears - Set to 0 if not relevant
    191    /// (e.g. Declaration from `style="/*...*/"`, presentation hints, animations
    192    /// - See `CascadePriority` instead).
    193    source_order: u32,
    194    /// The specificity of the selector.
    195    pub specificity: u32,
    196    /// The proximity to the scope root.
    197    pub scope_proximity: ScopeProximity,
    198    /// The cascade priority of the rule.
    199    pub cascade_priority: CascadePriority,
    200 }
    201 
    202 impl ApplicableDeclarationBlock {
    203    /// Constructs an applicable declaration block from a given property
    204    /// declaration block and importance.
    205    #[inline]
    206    pub fn from_declarations(
    207        declarations: Arc<Locked<PropertyDeclarationBlock>>,
    208        level: CascadeLevel,
    209        layer_order: LayerOrder,
    210    ) -> Self {
    211        ApplicableDeclarationBlock {
    212            source: StyleSource::from_declarations(declarations),
    213            source_order: 0,
    214            specificity: 0,
    215            scope_proximity: ScopeProximity::infinity(),
    216            cascade_priority: CascadePriority::new(level, layer_order),
    217        }
    218    }
    219 
    220    /// Constructs an applicable declaration block from the given components.
    221    #[inline]
    222    pub fn new(
    223        source: StyleSource,
    224        source_order: u32,
    225        level: CascadeLevel,
    226        specificity: u32,
    227        layer_order: LayerOrder,
    228        scope_proximity: ScopeProximity,
    229    ) -> Self {
    230        ApplicableDeclarationBlock {
    231            source,
    232            source_order: source_order & SOURCE_ORDER_MASK,
    233            specificity,
    234            scope_proximity,
    235            cascade_priority: CascadePriority::new(level, layer_order),
    236        }
    237    }
    238 
    239    /// Returns the source order of the block.
    240    #[inline]
    241    pub fn source_order(&self) -> u32 {
    242        self.source_order
    243    }
    244 
    245    /// Returns the cascade level of the block.
    246    #[inline]
    247    pub fn level(&self) -> CascadeLevel {
    248        self.cascade_priority.cascade_level()
    249    }
    250 
    251    /// Returns the cascade level of the block.
    252    #[inline]
    253    pub fn layer_order(&self) -> LayerOrder {
    254        self.cascade_priority.layer_order()
    255    }
    256 
    257    /// Returns the scope proximity of the block.
    258    #[inline]
    259    pub fn scope_proximity(&self) -> ScopeProximity {
    260        self.scope_proximity
    261    }
    262 
    263    /// Convenience method to consume self and return the right thing for the
    264    /// rule tree to iterate over.
    265    #[inline]
    266    pub fn for_rule_tree(self) -> (StyleSource, CascadePriority) {
    267        (self.source, self.cascade_priority)
    268    }
    269 
    270    /// Return the key used to sort applicable declarations.
    271    #[inline]
    272    pub fn sort_key(&self) -> (LayerOrder, u32, ScopeProximity, u32) {
    273        (
    274            self.layer_order(),
    275            self.specificity,
    276            self.scope_proximity(),
    277            self.source_order(),
    278        )
    279    }
    280 }
    281 
    282 // Size of this struct determines sorting and selector-matching performance.
    283 size_of_test!(ApplicableDeclarationBlock, 24);