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