style: Add support for the revert-layer keyword

This patch looks bigger than it is, but it's mostly because
of plumbing.

To implement revert-layer we need not only the cascade origin of the
declaration, but the whole cascade level, plus also the layer order.

In order to do this, encapsulate these two things inside a 32-bit
`CascadePriority` struct and plumb it through the rule tree and so on.
This allows us to remove the packing and unpacking of CascadeLevel,
though I kept the ShadowCascadeOrder limit for now in case we need to
reintroduce it.

Fix `!important` behavior of layers while at it (implementing it in
`CascadeLevel::cmp`, spec quote included since it was tricky to find)
since some revert-layer tests were depending on it.

The style attribute test is failing now, but follow-up commit fixes
it, see spec issue.

In terms of the actual keyword implementation, it's sort of
straight-forward: We implement revert and revert-layer in a shared
way, by storing the cascade priority that reverted it.

Differential Revision: https://phabricator.services.mozilla.com/D133372
This commit is contained in:
Emilio Cobos Álvarez 2023-06-06 16:49:13 +02:00 committed by Oriol Brufau
parent 26c10339e3
commit 8bb7d98f0c
17 changed files with 354 additions and 251 deletions

View file

@ -4,8 +4,9 @@
#![allow(unsafe_code)]
use crate::properties::Importance;
use crate::applicable_declarations::CascadePriority;
use crate::shared_lock::StylesheetGuards;
use crate::stylesheets::layer_rule::LayerOrder;
use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
use parking_lot::RwLock;
use smallvec::SmallVec;
@ -66,7 +67,7 @@ impl MallocSizeOf for RuleTree {
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct ChildKey(CascadeLevel, ptr::NonNull<()>);
struct ChildKey(CascadePriority, ptr::NonNull<()>);
unsafe impl Send for ChildKey {}
unsafe impl Sync for ChildKey {}
@ -219,8 +220,8 @@ struct RuleNode {
/// None for the root node.
source: Option<StyleSource>,
/// The cascade level this rule is positioned at.
level: CascadeLevel,
/// The cascade level + layer order this rule is positioned at.
cascade_priority: CascadePriority,
/// The refcount of this node.
///
@ -316,14 +317,14 @@ impl RuleNode {
root: WeakRuleNode,
parent: StrongRuleNode,
source: StyleSource,
level: CascadeLevel,
cascade_priority: CascadePriority,
) -> Self {
debug_assert!(root.p.parent.is_none());
RuleNode {
root: Some(root),
parent: Some(parent),
source: Some(source),
level: level,
cascade_priority,
refcount: AtomicUsize::new(1),
children: Default::default(),
approximate_free_count: AtomicUsize::new(0),
@ -336,7 +337,7 @@ impl RuleNode {
root: None,
parent: None,
source: None,
level: CascadeLevel::UANormal,
cascade_priority: CascadePriority::new(CascadeLevel::UANormal, LayerOrder::root()),
refcount: AtomicUsize::new(1),
approximate_free_count: AtomicUsize::new(0),
children: Default::default(),
@ -346,7 +347,7 @@ impl RuleNode {
fn key(&self) -> ChildKey {
ChildKey(
self.level,
self.cascade_priority,
self.source
.as_ref()
.expect("Called key() on the root node")
@ -554,20 +555,20 @@ impl StrongRuleNode {
&self,
root: &StrongRuleNode,
source: StyleSource,
level: CascadeLevel,
cascade_priority: CascadePriority,
) -> StrongRuleNode {
use parking_lot::RwLockUpgradableReadGuard;
debug_assert!(
self.p.level <= level,
self.p.cascade_priority <= cascade_priority,
"Should be ordered (instead {:?} > {:?}), from {:?} and {:?}",
self.p.level,
level,
self.p.cascade_priority,
cascade_priority,
self.p.source,
source,
);
let key = ChildKey(level, source.key());
let key = ChildKey(cascade_priority, source.key());
let children = self.p.children.upgradable_read();
if let Some(child) = children.get(&key, |node| node.p.key()) {
// Sound to call because we read-locked the parent's children.
@ -584,7 +585,7 @@ impl StrongRuleNode {
root.downgrade(),
self.clone(),
source,
level,
cascade_priority,
)));
// Sound to call because we still own a strong reference to
// this node, through the `node` variable itself that we are
@ -602,14 +603,22 @@ impl StrongRuleNode {
self.p.source.as_ref()
}
/// The cascade level for this node
pub fn cascade_level(&self) -> CascadeLevel {
self.p.level
/// The cascade priority.
#[inline]
pub fn cascade_priority(&self) -> CascadePriority {
self.p.cascade_priority
}
/// Get the importance that this rule node represents.
pub fn importance(&self) -> Importance {
self.p.level.importance()
/// The cascade level.
#[inline]
pub fn cascade_level(&self) -> CascadeLevel {
self.cascade_priority().cascade_level()
}
/// The importance.
#[inline]
pub fn importance(&self) -> crate::properties::Importance {
self.cascade_level().importance()
}
/// Returns whether this node has any child, only intended for testing