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}