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]
276 fn shadow_order(self) -> ShadowCascadeOrder {
277 let neg = self.intersects(Self::CASCADE_ORDER_SIGN);
278 let abs = (self & Self::CASCADE_ORDER_BITS).bits() >> Self::CASCADE_ORDER_SHIFT;
279 ShadowCascadeOrder(if neg { -(abs as i8) } else { abs as i8 })
280 }
281
282 #[inline]
284 pub fn author_normal(shadow_cascade_order: ShadowCascadeOrder) -> Self {
285 let abs = (shadow_cascade_order.0.abs() as u8) << Self::CASCADE_ORDER_SHIFT;
286 let mut result = Self::new(CascadeOrigin::Author);
287 result |= Self::from_bits_truncate(abs);
288 result.set(Self::CASCADE_ORDER_SIGN, shadow_cascade_order.0 < 0);
289 result
290 }
291
292 pub fn get_shadow_root_for_scoped<E: TElement>(
294 &self,
295 element: E,
296 ) -> Option<<<E as TElement>::ConcreteNode as TNode>::ConcreteShadowRoot> {
297 let mut cascade_order = self.shadow_order().0;
298 if cascade_order < 0 {
299 let element = element.ultimate_originating_element();
300 let mut slot = element.assigned_slot();
301 while let Some(s) = slot {
302 cascade_order += 1;
303 if cascade_order == 0 {
304 return s.containing_shadow();
305 }
306 slot = s.assigned_slot();
307 }
308 if cascade_order != -1 {
309 return None;
310 }
311
312 return element.shadow_root();
313 }
314 debug_assert!(cascade_order >= 0);
315 let mut containing_shadow = element.containing_shadow();
316 while let Some(s) = containing_shadow {
317 if cascade_order == 0 {
318 break;
319 }
320 cascade_order -= 1;
321 containing_shadow = s.host().containing_shadow();
322 }
323 containing_shadow
324 }
325}
326
327#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
334#[repr(transparent)]
335pub struct ShadowCascadeOrder(i8);
336
337impl ShadowCascadeOrder {
338 const MAX: i8 = 0b111;
340 const MIN: i8 = -Self::MAX;
341
342 #[inline]
345 pub fn for_outermost_shadow_tree() -> Self {
346 Self(-1)
347 }
348
349 #[inline]
351 pub fn for_same_tree() -> Self {
352 Self(0)
353 }
354
355 #[inline]
358 pub fn for_innermost_containing_tree() -> Self {
359 Self(1)
360 }
361
362 #[inline]
365 pub fn dec(&mut self) {
366 debug_assert!(self.0 < 0);
367 if self.0 != Self::MIN {
368 self.0 -= 1;
369 }
370 }
371
372 #[inline]
375 pub fn inc(&mut self) {
376 debug_assert_ne!(self.0, -1);
377 if self.0 != Self::MAX {
378 self.0 += 1;
379 }
380 }
381}
382
383impl std::ops::Neg for ShadowCascadeOrder {
384 type Output = Self;
385 #[inline]
386 fn neg(self) -> Self {
387 Self(self.0.neg())
388 }
389}