level.rs (8336B)
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 7 use crate::derives::*; 8 use crate::properties::Importance; 9 use crate::shared_lock::{SharedRwLockReadGuard, StylesheetGuards}; 10 use 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)] 34 pub 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 74 impl 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)] 199 pub struct ShadowCascadeOrder(i8); 200 201 impl 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 249 impl std::ops::Neg for ShadowCascadeOrder { 250 type Output = Self; 251 #[inline] 252 fn neg(self) -> Self { 253 Self(self.0.neg()) 254 } 255 }