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 guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
130 match *self {
131 Self::UA | Self::User => guards.ua_or_user,
132 _ => guards.author,
133 }
134 }
135}
136
137impl Ord for CascadeLevel {
138 fn cmp(&self, other: &Self) -> Ordering {
139 let self_important = self.is_important();
140 if self_important != other.is_important() {
141 return if self_important {
142 if other.origin() == CascadeOrigin::Transitions {
143 return Ordering::Less;
145 }
146 Ordering::Greater
147 } else {
148 if self.origin() == CascadeOrigin::Transitions {
149 return Ordering::Greater;
150 }
151 Ordering::Less
152 };
153 }
154 let origin_cmp = self
155 .origin()
156 .cmp(&other.origin())
157 .then_with(|| self.shadow_order().cmp(&other.shadow_order()));
158 if self_important {
159 origin_cmp.reverse()
160 } else {
161 origin_cmp
162 }
163 }
164}
165
166impl PartialOrd for CascadeLevel {
167 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
168 Some(self.cmp(other))
169 }
170}
171
172impl CascadeLevel {
173 pub const CASCADE_ORDER_SHIFT: usize = 4;
175 pub const SAME_TREE_AUTHOR_NORMAL: Self = Self(CascadeOrigin::Author as u8);
177
178 pub fn new(origin: CascadeOrigin) -> Self {
180 let bits = origin as u8;
181 debug_assert_eq!(bits & Self::ORIGIN_BITS.bits(), bits);
182 Self(bits)
183 }
184
185 #[inline]
187 pub fn origin(self) -> CascadeOrigin {
188 use num_traits::FromPrimitive;
189 let origin = (self & Self::ORIGIN_BITS).bits();
190 CascadeOrigin::from_u8(origin).unwrap()
191 }
192
193 pub fn important(self) -> Self {
195 debug_assert!(
196 matches!(
197 self.origin(),
198 CascadeOrigin::UA | CascadeOrigin::User | CascadeOrigin::Author
199 ),
200 "{self:?}"
201 );
202 let mut result = self;
203 result.insert(Self::IMPORTANT);
204 result
205 }
206
207 pub fn unimportant(self) -> Self {
209 let mut result = self;
210 result.remove(Self::IMPORTANT);
211 result
212 }
213
214 #[inline]
216 pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
217 self.origin().guard(guards)
218 }
219
220 #[inline]
223 pub fn same_tree_author_important() -> Self {
224 Self::new(CascadeOrigin::Author).important()
225 }
226
227 #[inline]
230 pub fn same_tree_author_normal() -> Self {
231 Self::new(CascadeOrigin::Author)
232 }
233
234 #[inline]
237 pub fn is_important(&self) -> bool {
238 self.intersects(Self::IMPORTANT)
239 }
240
241 #[inline]
244 pub fn importance(&self) -> Importance {
245 if self.is_important() {
246 Importance::Important
247 } else {
248 Importance::Normal
249 }
250 }
251
252 #[inline]
254 pub fn is_animation(&self) -> bool {
255 match self.origin() {
256 CascadeOrigin::SMILOverride
257 | CascadeOrigin::Animations
258 | CascadeOrigin::Transitions => true,
259 _ => false,
260 }
261 }
262
263 #[inline]
265 pub fn is_tree(self) -> bool {
266 self.origin() == CascadeOrigin::Author
267 }
268
269 #[inline]
271 pub fn shadow_order(self) -> ShadowCascadeOrder {
272 let neg = self.intersects(Self::CASCADE_ORDER_SIGN);
273 let abs = (self & Self::CASCADE_ORDER_BITS).bits() >> Self::CASCADE_ORDER_SHIFT;
274 ShadowCascadeOrder(if neg { -(abs as i8) } else { abs as i8 })
275 }
276
277 #[inline]
279 pub fn author_normal(shadow_cascade_order: ShadowCascadeOrder) -> Self {
280 let abs = shadow_cascade_order.0.unsigned_abs() << Self::CASCADE_ORDER_SHIFT;
281 let mut result = Self::new(CascadeOrigin::Author);
282 result |= Self::from_bits_truncate(abs);
283 result.set(Self::CASCADE_ORDER_SIGN, shadow_cascade_order.0 < 0);
284 result
285 }
286
287 pub fn get_shadow_root_for_scoped<E: TElement>(
289 &self,
290 element: E,
291 ) -> Option<<<E as TElement>::ConcreteNode as TNode>::ConcreteShadowRoot> {
292 let mut cascade_order = self.shadow_order().0;
293 if cascade_order < 0 {
294 let element = element.ultimate_originating_element();
295 let mut slot = element.assigned_slot();
296 while let Some(s) = slot {
297 cascade_order += 1;
298 if cascade_order == 0 {
299 return s.containing_shadow();
300 }
301 slot = s.assigned_slot();
302 }
303 if cascade_order != -1 {
304 return None;
305 }
306
307 return element.shadow_root();
308 }
309 debug_assert!(cascade_order >= 0);
310 let mut containing_shadow = element.containing_shadow();
311 while let Some(s) = containing_shadow {
312 if cascade_order == 0 {
313 break;
314 }
315 cascade_order -= 1;
316 containing_shadow = s.host().containing_shadow();
317 }
318 containing_shadow
319 }
320}
321
322#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
329#[repr(transparent)]
330pub struct ShadowCascadeOrder(i8);
331
332impl ShadowCascadeOrder {
333 const MAX: i8 = 0b111;
335 const MIN: i8 = -Self::MAX;
336
337 #[inline]
340 pub fn for_outermost_shadow_tree() -> Self {
341 Self(-1)
342 }
343
344 #[inline]
346 pub fn for_same_tree() -> Self {
347 Self(0)
348 }
349
350 #[inline]
353 pub fn for_innermost_containing_tree() -> Self {
354 Self(1)
355 }
356
357 #[inline]
359 pub fn is_in_same_or_containing_tree(&self) -> bool {
360 self.0 > 0
361 }
362
363 #[inline]
366 pub fn dec(&mut self) {
367 debug_assert!(self.0 < 0);
368 if self.0 != Self::MIN {
369 self.0 -= 1;
370 }
371 }
372
373 #[inline]
376 pub fn inc(&mut self) {
377 debug_assert_ne!(self.0, -1);
378 if self.0 != Self::MAX {
379 self.0 += 1;
380 }
381 }
382}
383
384impl std::ops::Neg for ShadowCascadeOrder {
385 type Output = Self;
386 #[inline]
387 fn neg(self) -> Self {
388 Self(self.0.neg())
389 }
390}