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