Skip to main content

style/rule_tree/
level.rs

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#![forbid(unsafe_code)]
6
7//! The cascade level and shadow cascade order for tracking shadow tree rules.
8
9use crate::derives::*;
10use crate::properties::Importance;
11use crate::shared_lock::{SharedRwLockReadGuard, StylesheetGuards};
12use crate::stylesheets::Origin;
13use crate::values::animated::ToAnimatedValue;
14
15/// The cascade level these rules are relevant at, as per[1][2][3].
16///
17/// Presentational hints for SVG and HTML are in the "author-level
18/// zero-specificity" level, that is, right after user rules, and before author
19/// rules.
20///
21/// The order of variants declared here is significant, and must be in
22/// _ascending_ order of precedence.
23///
24/// See also [4] for the Shadow DOM bits. We rely on the invariant that rules
25/// from outside the tree the element is in can't affect the element.
26///
27/// The opposite is not true (i.e., :host and ::slotted) from an "inner" shadow
28/// tree may affect an element connected to the document or an "outer" shadow
29/// tree.
30///
31/// [1]: https://drafts.csswg.org/css-cascade/#cascade-origin
32/// [2]: https://drafts.csswg.org/css-cascade/#preshint
33/// [3]: https://html.spec.whatwg.org/multipage/#presentational-hints
34/// [4]: https://drafts.csswg.org/css-scoping/#shadow-cascading
35#[derive(
36    Clone,
37    Copy,
38    Debug,
39    Eq,
40    Hash,
41    MallocSizeOf,
42    Ord,
43    PartialEq,
44    PartialOrd,
45    SpecifiedValueInfo,
46    ToAnimatedValue,
47    ToComputedValue,
48    ToResolvedValue,
49    ToShmem,
50    Serialize,
51    Deserialize,
52)]
53#[repr(C, u8)]
54pub enum CascadeLevel {
55    /// Normal User-Agent rules.
56    UANormal,
57    /// User normal rules.
58    UserNormal,
59    /// Presentational hints.
60    PresHints,
61    /// Shadow DOM styles from author styles.
62    AuthorNormal {
63        /// The order in the shadow tree hierarchy. This number is relative to
64        /// the tree of the element, and thus the only invariants that need to
65        /// be preserved is:
66        ///
67        ///  * Zero is the same tree as the element that matched the rule. This
68        ///    is important so that we can optimize style attribute insertions.
69        ///
70        ///  * The levels are ordered in accordance with
71        ///    https://drafts.csswg.org/css-scoping/#shadow-cascading
72        shadow_cascade_order: ShadowCascadeOrder,
73    },
74    /// https://drafts.csswg.org/css-anchor-position-1/#position-fallback-origin
75    PositionFallback,
76    /// SVG SMIL animations.
77    SMILOverride,
78    /// CSS animations and script-generated animations.
79    Animations,
80    /// Author-supplied important rules.
81    AuthorImportant {
82        /// The order in the shadow tree hierarchy, inverted, so that PartialOrd
83        /// does the right thing.
84        shadow_cascade_order: ShadowCascadeOrder,
85    },
86    /// User important rules.
87    UserImportant,
88    /// User-agent important rules.
89    UAImportant,
90    /// Transitions
91    Transitions,
92}
93
94impl CascadeLevel {
95    /// Convert this level from "unimportant" to "important".
96    pub fn important(&self) -> Self {
97        match *self {
98            Self::UANormal => Self::UAImportant,
99            Self::UserNormal => Self::UserImportant,
100            Self::AuthorNormal {
101                shadow_cascade_order,
102            } => Self::AuthorImportant {
103                shadow_cascade_order: -shadow_cascade_order,
104            },
105            Self::PresHints
106            | Self::PositionFallback
107            | Self::SMILOverride
108            | Self::Animations
109            | Self::AuthorImportant { .. }
110            | Self::UserImportant
111            | Self::UAImportant
112            | Self::Transitions => *self,
113        }
114    }
115
116    /// Convert this level from "important" to "non-important".
117    pub fn unimportant(&self) -> Self {
118        match *self {
119            Self::UAImportant => Self::UANormal,
120            Self::UserImportant => Self::UserNormal,
121            Self::AuthorImportant {
122                shadow_cascade_order,
123            } => Self::AuthorNormal {
124                shadow_cascade_order: -shadow_cascade_order,
125            },
126            Self::PresHints
127            | Self::PositionFallback
128            | Self::SMILOverride
129            | Self::Animations
130            | Self::AuthorNormal { .. }
131            | Self::UserNormal
132            | Self::UANormal
133            | Self::Transitions => *self,
134        }
135    }
136
137    /// Select a lock guard for this level
138    pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
139        match *self {
140            Self::UANormal | Self::UserNormal | Self::UserImportant | Self::UAImportant => {
141                guards.ua_or_user
142            },
143            _ => guards.author,
144        }
145    }
146
147    /// Returns the cascade level for author important declarations from the
148    /// same tree as the element.
149    #[inline]
150    pub fn same_tree_author_important() -> Self {
151        Self::AuthorImportant {
152            shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
153        }
154    }
155
156    /// Returns the cascade level for author normal declarations from the same
157    /// tree as the element.
158    #[inline]
159    pub fn same_tree_author_normal() -> Self {
160        Self::AuthorNormal {
161            shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
162        }
163    }
164
165    /// Returns whether this cascade level represents important rules of some
166    /// sort.
167    #[inline]
168    pub fn is_important(&self) -> bool {
169        match *self {
170            Self::AuthorImportant { .. } | Self::UserImportant | Self::UAImportant => true,
171            _ => false,
172        }
173    }
174
175    /// Returns the importance relevant for this rule. Pretty similar to
176    /// `is_important`.
177    #[inline]
178    pub fn importance(&self) -> Importance {
179        if self.is_important() {
180            Importance::Important
181        } else {
182            Importance::Normal
183        }
184    }
185
186    /// Returns the cascade origin of the rule.
187    #[inline]
188    pub fn origin(&self) -> Origin {
189        match *self {
190            Self::UAImportant | Self::UANormal => Origin::UserAgent,
191            Self::UserImportant | Self::UserNormal => Origin::User,
192            Self::PresHints
193            | Self::PositionFallback { .. }
194            | Self::AuthorNormal { .. }
195            | Self::AuthorImportant { .. }
196            | Self::SMILOverride
197            | Self::Animations
198            | Self::Transitions => Origin::Author,
199        }
200    }
201
202    /// Returns whether this cascade level represents an animation rules.
203    #[inline]
204    pub fn is_animation(&self) -> bool {
205        match *self {
206            Self::SMILOverride | Self::Animations | Self::Transitions => true,
207            _ => false,
208        }
209    }
210
211    /// Returns whether this cascade level is tree.
212    #[inline]
213    pub fn is_tree(&self) -> bool {
214        matches!(
215            *self,
216            Self::AuthorImportant { .. } | Self::AuthorNormal { .. }
217        )
218    }
219}
220
221/// A counter to track how many shadow root rules deep we are. This is used to
222/// handle:
223///
224/// https://drafts.csswg.org/css-scoping/#shadow-cascading
225///
226/// See the static functions for the meaning of different values.
227#[derive(
228    Clone,
229    Copy,
230    Debug,
231    Eq,
232    Hash,
233    MallocSizeOf,
234    Ord,
235    PartialEq,
236    PartialOrd,
237    SpecifiedValueInfo,
238    ToComputedValue,
239    ToResolvedValue,
240    ToShmem,
241    Serialize,
242    Deserialize,
243)]
244#[repr(transparent)]
245pub struct ShadowCascadeOrder(i8);
246
247impl ShadowCascadeOrder {
248    /// We keep a maximum of 3 bits of order as a limit so that we can pack
249    /// CascadeLevel in one byte by using half of it for the order, if that ends
250    /// up being necessary.
251    const MAX: i8 = 0b111;
252    const MIN: i8 = -Self::MAX;
253
254    /// A level for the outermost shadow tree (the shadow tree we own, and the
255    /// ones from the slots we're slotted in).
256    #[inline]
257    pub fn for_outermost_shadow_tree() -> Self {
258        Self(-1)
259    }
260
261    /// A level for the element's tree.
262    #[inline]
263    pub fn for_same_tree() -> Self {
264        Self(0)
265    }
266
267    /// A level for the innermost containing tree (the one closest to the
268    /// element).
269    #[inline]
270    pub fn for_innermost_containing_tree() -> Self {
271        Self(1)
272    }
273
274    /// Decrement the level, moving inwards. We should only move inwards if
275    /// we're traversing slots.
276    #[inline]
277    pub fn dec(&mut self) {
278        debug_assert!(self.0 < 0);
279        if self.0 != Self::MIN {
280            self.0 -= 1;
281        }
282    }
283
284    /// The level, moving inwards. We should only move inwards if we're
285    /// traversing slots.
286    #[inline]
287    pub fn inc(&mut self) {
288        debug_assert_ne!(self.0, -1);
289        if self.0 != Self::MAX {
290            self.0 += 1;
291        }
292    }
293}
294
295impl std::ops::Neg for ShadowCascadeOrder {
296    type Output = Self;
297    #[inline]
298    fn neg(self) -> Self {
299        Self(self.0.neg())
300    }
301}
302
303impl ToAnimatedValue for ShadowCascadeOrder {
304    type AnimatedValue = ShadowCascadeOrder;
305
306    #[inline]
307    fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
308        self
309    }
310
311    #[inline]
312    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
313        animated
314    }
315}