aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/rule_tree/mod.rs
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2023-06-06 16:49:13 +0200
committerOriol Brufau <obrufau@igalia.com>2023-06-09 10:22:22 +0200
commit8bb7d98f0ce2fdfa49f71c1379dd2bcde3aeac29 (patch)
tree962d77a26b4632f822381045d6d23bceaedded89 /components/style/rule_tree/mod.rs
parent26c10339e332dbfe3607be57d509e25e30267523 (diff)
downloadservo-8bb7d98f0ce2fdfa49f71c1379dd2bcde3aeac29.tar.gz
servo-8bb7d98f0ce2fdfa49f71c1379dd2bcde3aeac29.zip
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
Diffstat (limited to 'components/style/rule_tree/mod.rs')
-rw-r--r--components/style/rule_tree/mod.rs85
1 files changed, 42 insertions, 43 deletions
diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs
index e50382255ca..c8705165776 100644
--- a/components/style/rule_tree/mod.rs
+++ b/components/style/rule_tree/mod.rs
@@ -6,9 +6,10 @@
//! The rule tree.
-use crate::applicable_declarations::ApplicableDeclarationList;
+use crate::applicable_declarations::{ApplicableDeclarationList, CascadePriority};
use crate::properties::{LonghandIdSet, PropertyDeclarationBlock};
use crate::shared_lock::{Locked, StylesheetGuards};
+use crate::stylesheets::layer_rule::LayerOrder;
use servo_arc::{Arc, ArcBorrow};
use smallvec::SmallVec;
use std::io::{self, Write};
@@ -47,21 +48,22 @@ impl RuleTree {
guards: &StylesheetGuards,
) -> StrongRuleNode
where
- I: Iterator<Item = (StyleSource, CascadeLevel)>,
+ I: Iterator<Item = (StyleSource, CascadePriority)>,
{
use self::CascadeLevel::*;
let mut current = self.root().clone();
let mut found_important = false;
- let mut important_author = SmallVec::<[(StyleSource, ShadowCascadeOrder); 4]>::new();
-
- let mut important_user = SmallVec::<[StyleSource; 4]>::new();
- let mut important_ua = SmallVec::<[StyleSource; 4]>::new();
+ let mut important_author = SmallVec::<[(StyleSource, CascadePriority); 4]>::new();
+ let mut important_user = SmallVec::<[(StyleSource, CascadePriority); 4]>::new();
+ let mut important_ua = SmallVec::<[(StyleSource, CascadePriority); 4]>::new();
let mut transition = None;
- for (source, level) in iter {
+ for (source, priority) in iter {
+ let level = priority.cascade_level();
debug_assert!(!level.is_important(), "Important levels handled internally");
+
let any_important = {
let pdb = source.read(level.guard(guards));
pdb.any_important()
@@ -70,13 +72,9 @@ impl RuleTree {
if any_important {
found_important = true;
match level {
- AuthorNormal {
- shadow_cascade_order,
- } => {
- important_author.push((source.clone(), shadow_cascade_order));
- },
- UANormal => important_ua.push(source.clone()),
- UserNormal => important_user.push(source.clone()),
+ AuthorNormal { .. } => important_author.push((source.clone(), priority.important())),
+ UANormal => important_ua.push((source.clone(), priority.important())),
+ UserNormal => important_user.push((source.clone(), priority.important())),
_ => {},
};
}
@@ -98,7 +96,7 @@ impl RuleTree {
debug_assert!(transition.is_none());
transition = Some(source);
} else {
- current = current.ensure_child(self.root(), source, level);
+ current = current.ensure_child(self.root(), source, priority);
}
}
@@ -110,10 +108,8 @@ impl RuleTree {
// Insert important declarations, in order of increasing importance,
// followed by any transition rule.
//
- // Inner shadow wins over same-tree, which wins over outer-shadow.
- //
- // We negate the shadow cascade order to preserve the right PartialOrd
- // behavior.
+ // Important rules are sorted differently from unimportant ones by
+ // shadow order and cascade order.
if !important_author.is_empty() &&
important_author.first().unwrap().1 != important_author.last().unwrap().1
{
@@ -129,29 +125,27 @@ impl RuleTree {
// inside the same chunk already sorted. Seems like we could try to
// keep a SmallVec-of-SmallVecs with the chunks and just iterate the
// outer in reverse.
- important_author.sort_by_key(|&(_, order)| -order);
+ important_author.sort_by_key(|&(_, priority)| priority);
}
- for (source, shadow_cascade_order) in important_author.drain(..) {
- current = current.ensure_child(
- self.root(),
- source,
- AuthorImportant {
- shadow_cascade_order: -shadow_cascade_order,
- },
- );
+ for (source, priority) in important_author.drain(..) {
+ current = current.ensure_child(self.root(), source, priority);
}
- for source in important_user.drain(..) {
- current = current.ensure_child(self.root(), source, UserImportant);
+ for (source, priority) in important_user.drain(..) {
+ current = current.ensure_child(self.root(), source, priority);
}
- for source in important_ua.drain(..) {
- current = current.ensure_child(self.root(), source, UAImportant);
+ for (source, priority) in important_ua.drain(..) {
+ current = current.ensure_child(self.root(), source, priority);
}
if let Some(source) = transition {
- current = current.ensure_child(self.root(), source, Transitions);
+ current = current.ensure_child(
+ self.root(),
+ source,
+ CascadePriority::new(Transitions, LayerOrder::root()),
+ );
}
current
@@ -174,18 +168,18 @@ impl RuleTree {
/// return the corresponding rule node representing the last inserted one.
pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode
where
- I: Iterator<Item = (StyleSource, CascadeLevel)>,
+ I: Iterator<Item = (StyleSource, CascadePriority)>,
{
self.insert_ordered_rules_from(self.root().clone(), iter)
}
fn insert_ordered_rules_from<'a, I>(&self, from: StrongRuleNode, iter: I) -> StrongRuleNode
where
- I: Iterator<Item = (StyleSource, CascadeLevel)>,
+ I: Iterator<Item = (StyleSource, CascadePriority)>,
{
let mut current = from;
- for (source, level) in iter {
- current = current.ensure_child(self.root(), source, level);
+ for (source, priority) in iter {
+ current = current.ensure_child(self.root(), source, priority);
}
current
}
@@ -197,6 +191,7 @@ impl RuleTree {
pub fn update_rule_at_level(
&self,
level: CascadeLevel,
+ layer_order: LayerOrder,
pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
path: &StrongRuleNode,
guards: &StylesheetGuards,
@@ -209,10 +204,10 @@ impl RuleTree {
// First walk up until the first less-or-equally specific rule.
let mut children = SmallVec::<[_; 10]>::new();
- while current.cascade_level() > level {
+ while current.cascade_priority().cascade_level() > level {
children.push((
current.style_source().unwrap().clone(),
- current.cascade_level(),
+ current.cascade_priority(),
));
current = current.parent().unwrap().clone();
}
@@ -227,7 +222,7 @@ impl RuleTree {
// to special-case (isn't hard, it's just about removing the `if` and
// special cases, and replacing them for a `while` loop, avoiding the
// optimizations).
- if current.cascade_level() == level {
+ if current.cascade_priority().cascade_level() == level {
*important_rules_changed |= level.is_important();
let current_decls = current.style_source().unwrap().as_declarations();
@@ -267,7 +262,7 @@ impl RuleTree {
current = current.ensure_child(
self.root(),
StyleSource::from_declarations(pdb.clone_arc()),
- level,
+ CascadePriority::new(level, layer_order),
);
*important_rules_changed = true;
}
@@ -276,7 +271,7 @@ impl RuleTree {
current = current.ensure_child(
self.root(),
StyleSource::from_declarations(pdb.clone_arc()),
- level,
+ CascadePriority::new(level, layer_order),
);
}
}
@@ -312,7 +307,10 @@ impl RuleTree {
let mut children = SmallVec::<[_; 10]>::new();
for node in iter {
if !node.cascade_level().is_animation() {
- children.push((node.style_source().unwrap().clone(), node.cascade_level()));
+ children.push((
+ node.style_source().unwrap().clone(),
+ node.cascade_priority(),
+ ));
}
last = node;
}
@@ -336,6 +334,7 @@ impl RuleTree {
let mut dummy = false;
self.update_rule_at_level(
CascadeLevel::Transitions,
+ LayerOrder::root(),
Some(pdb.borrow_arc()),
path,
guards,