/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#![forbid(unsafe_code)]
//! The cascade level and shadow cascade order for tracking shadow tree rules.
/// The cascade level these rules are relevant at, as per[1][2][3]. /// /// We store them as a bitfield with: /// /// * Shadow cascade order (4 bits). See ShadowCascadeOrder for details. /// * Importance bit. Whether the declaration was !important or not. /// * The CascadeOrigin of the declaration as per [1]. /// /// Presentational hints for SVG and HTML are in the "author-level zero-specificity" level, that /// is, right after user rules, and before author rules. /// /// See also [4] for the Shadow DOM bits. We rely on the invariant that rules /// from outside the tree the element is in can't affect the element. /// /// The opposite is not true (i.e., :host and ::slotted) from an "inner" shadow tree may affect an /// element connected to the document or an "outer" shadow tree. /// /// [1]: https://drafts.csswg.org/css-cascade/#cascade-origin /// [2]: https://drafts.csswg.org/css-cascade/#preshint /// [3]: https://html.spec.whatwg.org/multipage/#presentational-hints /// [4]: https://drafts.csswg.org/css-scoping/#shadow-cascading #[repr(C)] #[derive(
Clone,
Copy,
Debug,
Eq,
Hash,
PartialEq,
Serialize,
Deserialize,
ToAnimatedValue,
ToResolvedValue,
ToShmem,
)] pubstruct CascadeLevel(u8);
bitflags! { impl CascadeLevel: u8 { /// The three bits that represent the CascadeOrigin. const ORIGIN_BITS = 0b00000111; /// Whether the declarations are `!important` or not. const IMPORTANT = 1 << 3; /// The three bits for cascade order absolute value. If you change this, please change /// CASCADE_ORDER_SHIFT accordingly. const CASCADE_ORDER_BITS = 0b01110000; /// The bit for the sign. const CASCADE_ORDER_SIGN = 1 << 7;
}
}
/// The cascade origin of rules. /// /// Presentational hints for SVG and HTML are in the "author-level zero-specificity" level, that /// is, right after user rules, and before author rules. /// /// The order of variants declared here is significant, and must be in _ascending_ order of /// precedence. /// /// [1]: https://drafts.csswg.org/css-cascade/#cascade-origin /// [2]: https://drafts.csswg.org/css-cascade/#cascade-origin #[derive(
Clone,
Copy,
Debug,
Deserialize,
Eq,
FromPrimitive,
Hash,
MallocSizeOf,
Ord,
PartialEq,
PartialOrd,
Serialize,
ToAnimatedValue,
ToResolvedValue,
ToShmem,
)] #[repr(u8)] pubenum CascadeOrigin { /// Normal User-Agent rules.
UA = 0, /// User normal rules.
User, /// Presentational hints.
PresHints, /// Styles from author styles.
Author, /// https://drafts.csswg.org/css-anchor-position-1/#position-fallback-origin
PositionFallback, /// SVG SMIL animations.
SMILOverride, /// CSS animations and script-generated animations.
Animations, /// CSS Transitions
Transitions,
}
/// Returns whether this is an "author" origin (in the "simplified" sense of the word). #[inline] pubfn is_author_origin(self) -> bool { self > Self::User
}
/// Select a lock guard for this origin. #[inline] pubfn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> { match *self { Self::UA | Self::User => guards.ua_or_user,
_ => guards.author,
}
}
}
impl Ord for CascadeLevel { fn cmp(&self, other: &Self) -> Ordering { let self_important = self.is_important(); if self_important != other.is_important() { returnif self_important { if other.origin() == CascadeOrigin::Transitions { // Transitions override all important rules. return Ordering::Less;
}
Ordering::Greater
} else { ifself.origin() == CascadeOrigin::Transitions { return Ordering::Greater;
}
Ordering::Less
};
} let origin_cmp = self
.origin()
.cmp(&other.origin())
.then_with(|| self.shadow_order().cmp(&other.shadow_order())); if self_important {
origin_cmp.reverse()
} else {
origin_cmp
}
}
}
impl CascadeLevel { /// The shift that we apply to the cascade order. pubconst CASCADE_ORDER_SHIFT: usize = 4; /// The author level at the same tree. Here for convenience to avoid duplicating it from C++. pubconst SAME_TREE_AUTHOR_NORMAL: Self = Self(CascadeOrigin::Author as u8);
/// Returns a cascade level with a given origin. pubfn new(origin: CascadeOrigin) -> Self { let bits = origin as u8;
debug_assert_eq!(bits & Self::ORIGIN_BITS.bits(), bits); Self(bits)
}
/// Returns the cascade origin. #[inline] pubfn origin(self) -> CascadeOrigin { use num_traits::FromPrimitive; let origin = (self & Self::ORIGIN_BITS).bits();
CascadeOrigin::from_u8(origin).unwrap()
}
/// Convert this level from "unimportant" to "important". pubfn important(self) -> Self {
debug_assert!(
matches!( self.origin(),
CascadeOrigin::UA | CascadeOrigin::User | CascadeOrigin::Author
), "{self:?}"
); letmut result = self;
result.insert(Self::IMPORTANT);
result
}
/// Convert this level from "important" to "non-important". pubfn unimportant(self) -> Self { letmut result = self;
result.remove(Self::IMPORTANT);
result
}
/// Select a lock guard for this level #[inline] pubfn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> { self.origin().guard(guards)
}
/// Returns the cascade level for author important declarations from the /// same tree as the element. #[inline] pubfn same_tree_author_important() -> Self { Self::new(CascadeOrigin::Author).important()
}
/// Returns the cascade level for author normal declarations from the same /// tree as the element. #[inline] pubfn same_tree_author_normal() -> Self { Self::new(CascadeOrigin::Author)
}
/// Returns whether this cascade level represents important rules of some /// sort. #[inline] pubfn is_important(&self) -> bool { self.intersects(Self::IMPORTANT)
}
/// Returns the importance relevant for this rule. Pretty similar to /// `is_important`. #[inline] pubfn importance(&self) -> Importance { ifself.is_important() {
Importance::Important
} else {
Importance::Normal
}
}
/// Returns whether this cascade level is tree. #[inline] pubfn is_tree(self) -> bool { self.origin() == CascadeOrigin::Author
}
/// Returns the shadow tree order. #[inline] pubfn shadow_order(self) -> ShadowCascadeOrder { let neg = self.intersects(Self::CASCADE_ORDER_SIGN); let abs = (self & Self::CASCADE_ORDER_BITS).bits() >> Self::CASCADE_ORDER_SHIFT;
ShadowCascadeOrder(if neg { -(abs as i8) } else { abs as i8 })
}
/// Returns an author normal cascade level with the given shadow cascade order. #[inline] pubfn author_normal(shadow_cascade_order: ShadowCascadeOrder) -> Self { let abs = (shadow_cascade_order.0.abs() as u8) << Self::CASCADE_ORDER_SHIFT; letmut result = Self::new(CascadeOrigin::Author);
result |= Self::from_bits_truncate(abs);
result.set(Self::CASCADE_ORDER_SIGN, shadow_cascade_order.0 < 0);
result
}
/// Get the shadow root corresponding to the shadow cascade order, from the given element. pubfn get_shadow_root_for_scoped<E: TElement>(
&self,
element: E,
) -> Option<<<E as TElement>::ConcreteNode as TNode>::ConcreteShadowRoot> { letmut cascade_order = self.shadow_order().0; if cascade_order < 0 { let element = element.ultimate_originating_element(); letmut slot = element.assigned_slot(); whilelet Some(s) = slot {
cascade_order += 1; if cascade_order == 0 { return s.containing_shadow();
}
slot = s.assigned_slot();
} if cascade_order != -1 { return None;
}
/// A counter to track how many shadow root rules deep we are. This is used to /// handle: /// /// https://drafts.csswg.org/css-scoping/#shadow-cascading /// /// See the static functions for the meaning of different values. #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)] #[repr(transparent)] pubstruct ShadowCascadeOrder(i8);
impl ShadowCascadeOrder { /// We keep a maximum of 3 bits of order as a limit so that we can pack CascadeLevel in 1 byte. const MAX: i8 = 0b111; const MIN: i8 = -Self::MAX;
/// A level for the outermost shadow tree (the shadow tree we own, and the /// ones from the slots we're slotted in). #[inline] pubfn for_outermost_shadow_tree() -> Self { Self(-1)
}
/// A level for the element's tree. #[inline] pubfn for_same_tree() -> Self { Self(0)
}
/// A level for the innermost containing tree (the one closest to the /// element). #[inline] pubfn for_innermost_containing_tree() -> Self { Self(1)
}
/// Returns true if the level is in the same or a containing shadow tree. #[inline] pubfn is_in_same_or_containing_tree(&self) -> bool { self.0 > 0
}
/// Decrement the level, moving inwards. We should only move inwards if /// we're traversing slots. #[inline] pubfn dec(&mutself) {
debug_assert!(self.0 < 0); ifself.0 != Self::MIN { self.0 -= 1;
}
}
/// The level, moving inwards. We should only move inwards if we're /// traversing slots. #[inline] pubfn inc(&mutself) {
debug_assert_ne!(self.0, -1); ifself.0 != Self::MAX { self.0 += 1;
}
}
}
impl std::ops::Neg for ShadowCascadeOrder { type Output = Self; #[inline] fn neg(self) -> Self { Self(self.0.neg())
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.