mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Move CascadeLevel to its own rule_tree submodule
This commit is contained in:
parent
13db0c1584
commit
1ea6a0cdd4
2 changed files with 281 additions and 274 deletions
277
components/style/rule_tree/level.rs
Normal file
277
components/style/rule_tree/level.rs
Normal file
|
@ -0,0 +1,277 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use crate::properties::Importance;
|
||||
use crate::shared_lock::{SharedRwLockReadGuard, StylesheetGuards};
|
||||
use crate::stylesheets::Origin;
|
||||
|
||||
/// The cascade level these rules are relevant at, as per[1][2][3].
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd)]
|
||||
pub enum CascadeLevel {
|
||||
/// Normal User-Agent rules.
|
||||
UANormal,
|
||||
/// User normal rules.
|
||||
UserNormal,
|
||||
/// Presentational hints.
|
||||
PresHints,
|
||||
/// Shadow DOM styles from author styles.
|
||||
AuthorNormal {
|
||||
/// The order in the shadow tree hierarchy. This number is relative to
|
||||
/// the tree of the element, and thus the only invariants that need to
|
||||
/// be preserved is:
|
||||
///
|
||||
/// * Zero is the same tree as the element that matched the rule. This
|
||||
/// is important so that we can optimize style attribute insertions.
|
||||
///
|
||||
/// * The levels are ordered in accordance with
|
||||
/// https://drafts.csswg.org/css-scoping/#shadow-cascading
|
||||
shadow_cascade_order: ShadowCascadeOrder,
|
||||
},
|
||||
/// SVG SMIL animations.
|
||||
SMILOverride,
|
||||
/// CSS animations and script-generated animations.
|
||||
Animations,
|
||||
/// Author-supplied important rules.
|
||||
AuthorImportant {
|
||||
/// The order in the shadow tree hierarchy, inverted, so that PartialOrd
|
||||
/// does the right thing.
|
||||
shadow_cascade_order: ShadowCascadeOrder,
|
||||
},
|
||||
/// User important rules.
|
||||
UserImportant,
|
||||
/// User-agent important rules.
|
||||
UAImportant,
|
||||
/// Transitions
|
||||
Transitions,
|
||||
}
|
||||
|
||||
impl CascadeLevel {
|
||||
/// Pack this cascade level in a single byte.
|
||||
///
|
||||
/// We have 10 levels, which we can represent with 4 bits, and then a
|
||||
/// cascade order optionally, which we can clamp to three bits max, and
|
||||
/// represent with a fourth bit for the sign.
|
||||
///
|
||||
/// So this creates: SOOODDDD
|
||||
///
|
||||
/// Where `S` is the sign of the order (one if negative, 0 otherwise), `O`
|
||||
/// is the absolute value of the order, and `D`s are the discriminant.
|
||||
#[inline]
|
||||
pub fn to_byte_lossy(&self) -> u8 {
|
||||
let (discriminant, order) = match *self {
|
||||
Self::UANormal => (0, 0),
|
||||
Self::UserNormal => (1, 0),
|
||||
Self::PresHints => (2, 0),
|
||||
Self::AuthorNormal {
|
||||
shadow_cascade_order,
|
||||
} => (3, shadow_cascade_order.0),
|
||||
Self::SMILOverride => (4, 0),
|
||||
Self::Animations => (5, 0),
|
||||
Self::AuthorImportant {
|
||||
shadow_cascade_order,
|
||||
} => (6, shadow_cascade_order.0),
|
||||
Self::UserImportant => (7, 0),
|
||||
Self::UAImportant => (8, 0),
|
||||
Self::Transitions => (9, 0),
|
||||
};
|
||||
|
||||
debug_assert_eq!(discriminant & 0xf, discriminant);
|
||||
if order == 0 {
|
||||
return discriminant;
|
||||
}
|
||||
|
||||
let negative = order < 0;
|
||||
let value = std::cmp::min(order.abs() as u8, 0b111);
|
||||
(negative as u8) << 7 | value << 4 | discriminant
|
||||
}
|
||||
|
||||
/// Convert back from the single-byte representation of the cascade level
|
||||
/// explained above.
|
||||
#[inline]
|
||||
pub fn from_byte(b: u8) -> Self {
|
||||
let order = {
|
||||
let abs = ((b & 0b01110000) >> 4) as i8;
|
||||
let negative = b & 0b10000000 != 0;
|
||||
if negative {
|
||||
-abs
|
||||
} else {
|
||||
abs
|
||||
}
|
||||
};
|
||||
let discriminant = b & 0xf;
|
||||
let level = match discriminant {
|
||||
0 => Self::UANormal,
|
||||
1 => Self::UserNormal,
|
||||
2 => Self::PresHints,
|
||||
3 => {
|
||||
return Self::AuthorNormal {
|
||||
shadow_cascade_order: ShadowCascadeOrder(order),
|
||||
}
|
||||
},
|
||||
4 => Self::SMILOverride,
|
||||
5 => Self::Animations,
|
||||
6 => {
|
||||
return Self::AuthorImportant {
|
||||
shadow_cascade_order: ShadowCascadeOrder(order),
|
||||
}
|
||||
},
|
||||
7 => Self::UserImportant,
|
||||
8 => Self::UAImportant,
|
||||
9 => Self::Transitions,
|
||||
_ => unreachable!("Didn't expect {} as a discriminant", discriminant),
|
||||
};
|
||||
debug_assert_eq!(order, 0, "Didn't expect an order value for {:?}", level);
|
||||
level
|
||||
}
|
||||
|
||||
/// Select a lock guard for this level
|
||||
pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
|
||||
match *self {
|
||||
Self::UANormal | Self::UserNormal | Self::UserImportant | Self::UAImportant => {
|
||||
guards.ua_or_user
|
||||
},
|
||||
_ => guards.author,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the cascade level for author important declarations from the
|
||||
/// same tree as the element.
|
||||
#[inline]
|
||||
pub fn same_tree_author_important() -> Self {
|
||||
Self::AuthorImportant {
|
||||
shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the cascade level for author normal declarations from the same
|
||||
/// tree as the element.
|
||||
#[inline]
|
||||
pub fn same_tree_author_normal() -> Self {
|
||||
Self::AuthorNormal {
|
||||
shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this cascade level represents important rules of some
|
||||
/// sort.
|
||||
#[inline]
|
||||
pub fn is_important(&self) -> bool {
|
||||
match *self {
|
||||
Self::AuthorImportant { .. } | Self::UserImportant | Self::UAImportant => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the importance relevant for this rule. Pretty similar to
|
||||
/// `is_important`.
|
||||
#[inline]
|
||||
pub fn importance(&self) -> Importance {
|
||||
if self.is_important() {
|
||||
Importance::Important
|
||||
} else {
|
||||
Importance::Normal
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the cascade origin of the rule.
|
||||
#[inline]
|
||||
pub fn origin(&self) -> Origin {
|
||||
match *self {
|
||||
Self::UAImportant | Self::UANormal => Origin::UserAgent,
|
||||
Self::UserImportant | Self::UserNormal => Origin::User,
|
||||
Self::PresHints |
|
||||
Self::AuthorNormal { .. } |
|
||||
Self::AuthorImportant { .. } |
|
||||
Self::SMILOverride |
|
||||
Self::Animations |
|
||||
Self::Transitions => Origin::Author,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this cascade level represents an animation rules.
|
||||
#[inline]
|
||||
pub fn is_animation(&self) -> bool {
|
||||
match *self {
|
||||
Self::SMILOverride | Self::Animations | Self::Transitions => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
pub struct ShadowCascadeOrder(i8);
|
||||
|
||||
impl ShadowCascadeOrder {
|
||||
/// A level for the outermost shadow tree (the shadow tree we own, and the
|
||||
/// ones from the slots we're slotted in).
|
||||
#[inline]
|
||||
pub fn for_outermost_shadow_tree() -> Self {
|
||||
Self(-1)
|
||||
}
|
||||
|
||||
/// A level for the element's tree.
|
||||
#[inline]
|
||||
fn for_same_tree() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
/// A level for the innermost containing tree (the one closest to the
|
||||
/// element).
|
||||
#[inline]
|
||||
pub fn for_innermost_containing_tree() -> Self {
|
||||
Self(1)
|
||||
}
|
||||
|
||||
/// Decrement the level, moving inwards. We should only move inwards if
|
||||
/// we're traversing slots.
|
||||
#[inline]
|
||||
pub fn dec(&mut self) {
|
||||
debug_assert!(self.0 < 0);
|
||||
self.0 = self.0.saturating_sub(1);
|
||||
}
|
||||
|
||||
/// The level, moving inwards. We should only move inwards if we're
|
||||
/// traversing slots.
|
||||
#[inline]
|
||||
pub fn inc(&mut self) {
|
||||
debug_assert_ne!(self.0, -1);
|
||||
self.0 = self.0.saturating_add(1);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Neg for ShadowCascadeOrder {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn neg(self) -> Self {
|
||||
Self(self.0.neg())
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ use crate::applicable_declarations::ApplicableDeclarationList;
|
|||
use crate::hash::FxHashMap;
|
||||
use crate::properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
|
||||
use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
||||
use crate::stylesheets::{Origin, StyleRule};
|
||||
use crate::stylesheets::StyleRule;
|
||||
use crate::thread_state;
|
||||
use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
|
||||
use parking_lot::RwLock;
|
||||
|
@ -21,7 +21,10 @@ use std::mem;
|
|||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
||||
|
||||
mod level;
|
||||
mod map;
|
||||
|
||||
pub use self::level::{CascadeLevel, ShadowCascadeOrder};
|
||||
use self::map::Map;
|
||||
|
||||
/// The rule tree, the structure servo uses to preserve the results of selector
|
||||
|
@ -172,61 +175,6 @@ const FREE_LIST_SENTINEL: *mut RuleNode = 0x01 as *mut RuleNode;
|
|||
/// another thread is currently adding an entry). We spin if we find this value.
|
||||
const FREE_LIST_LOCKED: *mut RuleNode = 0x02 as *mut RuleNode;
|
||||
|
||||
/// 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)]
|
||||
pub struct ShadowCascadeOrder(i8);
|
||||
|
||||
impl ShadowCascadeOrder {
|
||||
/// A level for the outermost shadow tree (the shadow tree we own, and the
|
||||
/// ones from the slots we're slotted in).
|
||||
#[inline]
|
||||
pub fn for_outermost_shadow_tree() -> Self {
|
||||
Self(-1)
|
||||
}
|
||||
|
||||
/// A level for the element's tree.
|
||||
#[inline]
|
||||
fn for_same_tree() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
/// A level for the innermost containing tree (the one closest to the
|
||||
/// element).
|
||||
#[inline]
|
||||
pub fn for_innermost_containing_tree() -> Self {
|
||||
Self(1)
|
||||
}
|
||||
|
||||
/// Decrement the level, moving inwards. We should only move inwards if
|
||||
/// we're traversing slots.
|
||||
#[inline]
|
||||
pub fn dec(&mut self) {
|
||||
debug_assert!(self.0 < 0);
|
||||
self.0 = self.0.saturating_sub(1);
|
||||
}
|
||||
|
||||
/// The level, moving inwards. We should only move inwards if we're
|
||||
/// traversing slots.
|
||||
#[inline]
|
||||
pub fn inc(&mut self) {
|
||||
debug_assert_ne!(self.0, -1);
|
||||
self.0 = self.0.saturating_add(1);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Neg for ShadowCascadeOrder {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn neg(self) -> Self {
|
||||
Self(self.0.neg())
|
||||
}
|
||||
}
|
||||
|
||||
impl RuleTree {
|
||||
/// Construct a new rule tree.
|
||||
pub fn new() -> Self {
|
||||
|
@ -630,224 +578,6 @@ impl RuleTree {
|
|||
/// where it likely did not result from a rigorous performance analysis.)
|
||||
const RULE_TREE_GC_INTERVAL: usize = 300;
|
||||
|
||||
/// The cascade level these rules are relevant at, as per[1][2][3].
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd)]
|
||||
pub enum CascadeLevel {
|
||||
/// Normal User-Agent rules.
|
||||
UANormal,
|
||||
/// User normal rules.
|
||||
UserNormal,
|
||||
/// Presentational hints.
|
||||
PresHints,
|
||||
/// Shadow DOM styles from author styles.
|
||||
AuthorNormal {
|
||||
/// The order in the shadow tree hierarchy. This number is relative to
|
||||
/// the tree of the element, and thus the only invariants that need to
|
||||
/// be preserved is:
|
||||
///
|
||||
/// * Zero is the same tree as the element that matched the rule. This
|
||||
/// is important so that we can optimize style attribute insertions.
|
||||
///
|
||||
/// * The levels are ordered in accordance with
|
||||
/// https://drafts.csswg.org/css-scoping/#shadow-cascading
|
||||
shadow_cascade_order: ShadowCascadeOrder,
|
||||
},
|
||||
/// SVG SMIL animations.
|
||||
SMILOverride,
|
||||
/// CSS animations and script-generated animations.
|
||||
Animations,
|
||||
/// Author-supplied important rules.
|
||||
AuthorImportant {
|
||||
/// The order in the shadow tree hierarchy, inverted, so that PartialOrd
|
||||
/// does the right thing.
|
||||
shadow_cascade_order: ShadowCascadeOrder,
|
||||
},
|
||||
/// User important rules.
|
||||
UserImportant,
|
||||
/// User-agent important rules.
|
||||
UAImportant,
|
||||
/// Transitions
|
||||
Transitions,
|
||||
}
|
||||
|
||||
impl CascadeLevel {
|
||||
/// Pack this cascade level in a single byte.
|
||||
///
|
||||
/// We have 10 levels, which we can represent with 4 bits, and then a
|
||||
/// cascade order optionally, which we can clamp to three bits max, and
|
||||
/// represent with a fourth bit for the sign.
|
||||
///
|
||||
/// So this creates: SOOODDDD
|
||||
///
|
||||
/// Where `S` is the sign of the order (one if negative, 0 otherwise), `O`
|
||||
/// is the absolute value of the order, and `D`s are the discriminant.
|
||||
#[inline]
|
||||
pub fn to_byte_lossy(&self) -> u8 {
|
||||
let (discriminant, order) = match *self {
|
||||
Self::UANormal => (0, 0),
|
||||
Self::UserNormal => (1, 0),
|
||||
Self::PresHints => (2, 0),
|
||||
Self::AuthorNormal {
|
||||
shadow_cascade_order,
|
||||
} => (3, shadow_cascade_order.0),
|
||||
Self::SMILOverride => (4, 0),
|
||||
Self::Animations => (5, 0),
|
||||
Self::AuthorImportant {
|
||||
shadow_cascade_order,
|
||||
} => (6, shadow_cascade_order.0),
|
||||
Self::UserImportant => (7, 0),
|
||||
Self::UAImportant => (8, 0),
|
||||
Self::Transitions => (9, 0),
|
||||
};
|
||||
|
||||
debug_assert_eq!(discriminant & 0xf, discriminant);
|
||||
if order == 0 {
|
||||
return discriminant;
|
||||
}
|
||||
|
||||
let negative = order < 0;
|
||||
let value = std::cmp::min(order.abs() as u8, 0b111);
|
||||
(negative as u8) << 7 | value << 4 | discriminant
|
||||
}
|
||||
|
||||
/// Convert back from the single-byte representation of the cascade level
|
||||
/// explained above.
|
||||
#[inline]
|
||||
pub fn from_byte(b: u8) -> Self {
|
||||
let order = {
|
||||
let abs = ((b & 0b01110000) >> 4) as i8;
|
||||
let negative = b & 0b10000000 != 0;
|
||||
if negative {
|
||||
-abs
|
||||
} else {
|
||||
abs
|
||||
}
|
||||
};
|
||||
let discriminant = b & 0xf;
|
||||
let level = match discriminant {
|
||||
0 => Self::UANormal,
|
||||
1 => Self::UserNormal,
|
||||
2 => Self::PresHints,
|
||||
3 => {
|
||||
return Self::AuthorNormal {
|
||||
shadow_cascade_order: ShadowCascadeOrder(order),
|
||||
}
|
||||
},
|
||||
4 => Self::SMILOverride,
|
||||
5 => Self::Animations,
|
||||
6 => {
|
||||
return Self::AuthorImportant {
|
||||
shadow_cascade_order: ShadowCascadeOrder(order),
|
||||
}
|
||||
},
|
||||
7 => Self::UserImportant,
|
||||
8 => Self::UAImportant,
|
||||
9 => Self::Transitions,
|
||||
_ => unreachable!("Didn't expect {} as a discriminant", discriminant),
|
||||
};
|
||||
debug_assert_eq!(order, 0, "Didn't expect an order value for {:?}", level);
|
||||
level
|
||||
}
|
||||
|
||||
/// Select a lock guard for this level
|
||||
pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
|
||||
match *self {
|
||||
CascadeLevel::UANormal |
|
||||
CascadeLevel::UserNormal |
|
||||
CascadeLevel::UserImportant |
|
||||
CascadeLevel::UAImportant => guards.ua_or_user,
|
||||
_ => guards.author,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the cascade level for author important declarations from the
|
||||
/// same tree as the element.
|
||||
#[inline]
|
||||
pub fn same_tree_author_important() -> Self {
|
||||
CascadeLevel::AuthorImportant {
|
||||
shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the cascade level for author normal declarations from the same
|
||||
/// tree as the element.
|
||||
#[inline]
|
||||
pub fn same_tree_author_normal() -> Self {
|
||||
CascadeLevel::AuthorNormal {
|
||||
shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this cascade level represents important rules of some
|
||||
/// sort.
|
||||
#[inline]
|
||||
pub fn is_important(&self) -> bool {
|
||||
match *self {
|
||||
CascadeLevel::AuthorImportant { .. } |
|
||||
CascadeLevel::UserImportant |
|
||||
CascadeLevel::UAImportant => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the importance relevant for this rule. Pretty similar to
|
||||
/// `is_important`.
|
||||
#[inline]
|
||||
pub fn importance(&self) -> Importance {
|
||||
if self.is_important() {
|
||||
Importance::Important
|
||||
} else {
|
||||
Importance::Normal
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the cascade origin of the rule.
|
||||
#[inline]
|
||||
pub fn origin(&self) -> Origin {
|
||||
match *self {
|
||||
CascadeLevel::UAImportant | CascadeLevel::UANormal => Origin::UserAgent,
|
||||
CascadeLevel::UserImportant | CascadeLevel::UserNormal => Origin::User,
|
||||
CascadeLevel::PresHints |
|
||||
CascadeLevel::AuthorNormal { .. } |
|
||||
CascadeLevel::AuthorImportant { .. } |
|
||||
CascadeLevel::SMILOverride |
|
||||
CascadeLevel::Animations |
|
||||
CascadeLevel::Transitions => Origin::Author,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this cascade level represents an animation rules.
|
||||
#[inline]
|
||||
pub fn is_animation(&self) -> bool {
|
||||
match *self {
|
||||
CascadeLevel::SMILOverride | CascadeLevel::Animations | CascadeLevel::Transitions => {
|
||||
true
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A node in the rule tree.
|
||||
pub struct RuleNode {
|
||||
/// The root node. Only the root has no root pointer, for obvious reasons.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue