1#![forbid(unsafe_code)]
6
7use crate::derives::*;
10use crate::dom::{TElement, TNode, TShadowRoot};
11use crate::properties::Importance;
12use crate::shared_lock::{SharedRwLockReadGuard, StylesheetGuards};
13use crate::stylesheets::Origin;
14
15use std::cmp::{Ord, Ordering, PartialOrd};
16
17#[repr(C)]
39#[derive(
40 Clone,
41 Copy,
42 Debug,
43 Eq,
44 Hash,
45 PartialEq,
46 Serialize,
47 Deserialize,
48 ToAnimatedValue,
49 ToResolvedValue,
50 ToShmem,
51)]
52pub struct CascadeLevel(u8);
53bitflags! {
54 impl CascadeLevel: u8 {
55 const ORIGIN_BITS = 0b00000111;
57 const IMPORTANT = 1 << 3;
59 const CASCADE_ORDER_BITS = 0b01110000;
62 const CASCADE_ORDER_SIGN = 1 << 7;
64 }
65}
66
67malloc_size_of::malloc_size_of_is_0!(CascadeLevel);
68
69#[derive(
80 Clone,
81 Copy,
82 Debug,
83 Deserialize,
84 Eq,
85 FromPrimitive,
86 Hash,
87 MallocSizeOf,
88 Ord,
89 PartialEq,
90 PartialOrd,
91 Serialize,
92 ToAnimatedValue,
93 ToResolvedValue,
94 ToShmem,
95)]
96#[repr(u8)]
97pub enum CascadeOrigin {
98 UA = 0,
100 User,
102 PresHints,
104 Author,
106 PositionFallback,
108 SMILOverride,
110 Animations,
112 Transitions,
114}
115
116impl CascadeOrigin {
117 #[inline]
119 pub fn origin(self) -> Origin {
120 match self {
121 Self::UA => Origin::UserAgent,
122 Self::User => Origin::User,
123 _ => Origin::Author,
124 }
125 }
126
127 #[inline]
129 pub fn is_author_origin(self) -> bool {
130 self > Self::User
131 }
132
133 #[inline]
135 pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
136 match *self {
137 Self::UA | Self::User => guards.ua_or_user,
138 _ => guards.author,
139 }
140 }
141}
142
143impl Ord for CascadeLevel {
144 fn cmp(&self, other: &Self) -> Ordering {
145 let self_important = self.is_important();
146 if self_important != other.is_important() {
147 return if self_important {
148 if other.origin() == CascadeOrigin::Transitions {
149 return Ordering::Less;
151 }
152 Ordering::Greater
153 } else {
154 if self.origin() == CascadeOrigin::Transitions {
155 return Ordering::Greater;
156 }
157 Ordering::Less
158 };
159 }
160 let origin_cmp = self
161 .origin()
162 .cmp(&other.origin())
163 .then_with(|| self.shadow_order().cmp(&other.shadow_order()));
164 if self_important {
165 origin_cmp.reverse()
166 } else {
167 origin_cmp
168 }
169 }
170}
171
172impl PartialOrd for CascadeLevel {
173 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
174 Some(self.cmp(other))
175 }
176}
177
178impl CascadeLevel {
179 pub const CASCADE_ORDER_SHIFT: usize = 4;
181 pub const SAME_TREE_AUTHOR_NORMAL: Self = Self(CascadeOrigin::Author as u8);
183
184 pub fn new(origin: CascadeOrigin) -> Self {
186 let bits = origin as u8;
187 debug_assert_eq!(bits & Self::ORIGIN_BITS.bits(), bits);
188 Self(bits)
189 }
190
191 #[inline]
193 pub fn origin(self) -> CascadeOrigin {
194 use num_traits::FromPrimitive;
195 let origin = (self & Self::ORIGIN_BITS).bits();
196 CascadeOrigin::from_u8(origin).unwrap()
197 }
198
199 pub fn important(self) -> Self {
201 debug_assert!(
202 matches!(
203 self.origin(),
204 CascadeOrigin::UA | CascadeOrigin::User | CascadeOrigin::Author
205 ),
206 "{self:?}"
207 );
208 let mut result = self;
209 result.insert(Self::IMPORTANT);
210 result
211 }
212
213 pub fn unimportant(self) -> Self {
215 let mut result = self;
216 result.remove(Self::IMPORTANT);
217 result
218 }
219
220 #[inline]
222 pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
223 self.origin().guard(guards)
224 }
225
226 #[inline]
229 pub fn same_tree_author_important() -> Self {
230 Self::new(CascadeOrigin::Author).important()
231 }
232
233 #[inline]
236 pub fn same_tree_author_normal() -> Self {
237 Self::new(CascadeOrigin::Author)
238 }
239
240 #[inline]
243 pub fn is_important(&self) -> bool {
244 self.intersects(Self::IMPORTANT)
245 }
246
247 #[inline]
250 pub fn importance(&self) -> Importance {
251 if self.is_important() {
252 Importance::Important
253 } else {
254 Importance::Normal
255 }
256 }
257
258 #[inline]
260 pub fn is_animation(&self) -> bool {
261 match self.origin() {
262 CascadeOrigin::SMILOverride
263 | CascadeOrigin::Animations
264 | CascadeOrigin::Transitions => true,
265 _ => false,
266 }
267 }
268
269 #[inline]
271 pub fn is_tree(self) -> bool {
272 self.origin() == CascadeOrigin::Author
273 }
274
275 #[inline]
277 pub fn shadow_order(self) -> ShadowCascadeOrder {
278 let neg = self.intersects(Self::CASCADE_ORDER_SIGN);
279 let abs = (self & Self::CASCADE_ORDER_BITS).bits() >> Self::CASCADE_ORDER_SHIFT;
280 ShadowCascadeOrder(if neg { -(abs as i8) } else { abs as i8 })
281 }
282
283 #[inline]
285 pub fn author_normal(shadow_cascade_order: ShadowCascadeOrder) -> Self {
286 let abs = (shadow_cascade_order.0.abs() as u8) << Self::CASCADE_ORDER_SHIFT;
287 let mut result = Self::new(CascadeOrigin::Author);
288 result |= Self::from_bits_truncate(abs);
289 result.set(Self::CASCADE_ORDER_SIGN, shadow_cascade_order.0 < 0);
290 result
291 }
292
293 pub fn get_shadow_root_for_scoped<E: TElement>(
295 &self,
296 element: E,
297 ) -> Option<<<E as TElement>::ConcreteNode as TNode>::ConcreteShadowRoot> {
298 let mut cascade_order = self.shadow_order().0;
299 if cascade_order < 0 {
300 let element = element.ultimate_originating_element();
301 let mut slot = element.assigned_slot();
302 while let Some(s) = slot {
303 cascade_order += 1;
304 if cascade_order == 0 {
305 return s.containing_shadow();
306 }
307 slot = s.assigned_slot();
308 }
309 if cascade_order != -1 {
310 return None;
311 }
312
313 return element.shadow_root();
314 }
315 debug_assert!(cascade_order >= 0);
316 let mut containing_shadow = element.containing_shadow();
317 while let Some(s) = containing_shadow {
318 if cascade_order == 0 {
319 break;
320 }
321 cascade_order -= 1;
322 containing_shadow = s.host().containing_shadow();
323 }
324 containing_shadow
325 }
326}
327
328#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
335#[repr(transparent)]
336pub struct ShadowCascadeOrder(i8);
337
338impl ShadowCascadeOrder {
339 const MAX: i8 = 0b111;
341 const MIN: i8 = -Self::MAX;
342
343 #[inline]
346 pub fn for_outermost_shadow_tree() -> Self {
347 Self(-1)
348 }
349
350 #[inline]
352 pub fn for_same_tree() -> Self {
353 Self(0)
354 }
355
356 #[inline]
359 pub fn for_innermost_containing_tree() -> Self {
360 Self(1)
361 }
362
363 #[inline]
365 pub fn is_in_same_or_containing_tree(&self) -> bool {
366 self.0 > 0
367 }
368
369 #[inline]
372 pub fn dec(&mut self) {
373 debug_assert!(self.0 < 0);
374 if self.0 != Self::MIN {
375 self.0 -= 1;
376 }
377 }
378
379 #[inline]
382 pub fn inc(&mut self) {
383 debug_assert_ne!(self.0, -1);
384 if self.0 != Self::MAX {
385 self.0 += 1;
386 }
387 }
388}
389
390impl std::ops::Neg for ShadowCascadeOrder {
391 type Output = Self;
392 #[inline]
393 fn neg(self) -> Self {
394 Self(self.0.neg())
395 }
396}