aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/style/animation.rs2
-rw-r--r--components/style/applicable_declarations.rs139
-rw-r--r--components/style/custom_properties.rs19
-rw-r--r--components/style/matching.rs10
-rw-r--r--components/style/properties/cascade.rs97
-rw-r--r--components/style/properties/declaration_block.rs6
-rw-r--r--components/style/properties/helpers.mako.rs1
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs8
-rw-r--r--components/style/properties/properties.mako.rs24
-rw-r--r--components/style/rule_collector.rs2
-rw-r--r--components/style/rule_tree/core.rs47
-rw-r--r--components/style/rule_tree/level.rs118
-rw-r--r--components/style/rule_tree/mod.rs85
-rw-r--r--components/style/stylesheets/layer_rule.rs14
-rw-r--r--components/style/stylesheets/origin.rs2
-rw-r--r--components/style/stylist.rs18
-rw-r--r--components/style/values/mod.rs17
17 files changed, 356 insertions, 253 deletions
diff --git a/components/style/animation.rs b/components/style/animation.rs
index 57ce98141a7..7f0c7e6a588 100644
--- a/components/style/animation.rs
+++ b/components/style/animation.rs
@@ -24,6 +24,7 @@ use crate::selector_parser::PseudoElement;
use crate::shared_lock::{Locked, SharedRwLock};
use crate::style_resolver::StyleResolverForElement;
use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
+use crate::stylesheets::layer_rule::LayerOrder;
use crate::values::animated::{Animate, Procedure};
use crate::values::computed::{Time, TimingFunction};
use crate::values::generics::box_::AnimationIterationCount;
@@ -290,6 +291,7 @@ impl IntermediateComputedKeyframe {
let rule_node = base_style.rules().clone();
let new_node = context.stylist.rule_tree().update_rule_at_level(
CascadeLevel::Animations,
+ LayerOrder::root(),
Some(locked_block.borrow_arc()),
&rule_node,
&context.guards,
diff --git a/components/style/applicable_declarations.rs b/components/style/applicable_declarations.rs
index 7f2d3928d2d..cdb78d05405 100644
--- a/components/style/applicable_declarations.rs
+++ b/components/style/applicable_declarations.rs
@@ -24,36 +24,102 @@ pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>;
/// That's a limit that could be reached in realistic webpages, so we use
/// 24 bits and enforce defined behavior in the overflow case.
///
+/// Note that right now this restriction could be lifted if wanted (because we
+/// no longer stash the cascade level in the remaining bits), but we keep it in
+/// place in case we come up with a use-case for them, lacking reports of the
+/// current limit being too small.
+///
/// [1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/
/// RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3
-const SOURCE_ORDER_SHIFT: usize = 0;
const SOURCE_ORDER_BITS: usize = 24;
const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
-const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX << SOURCE_ORDER_SHIFT;
-
-/// We pack the cascade level in a single byte, see CascadeLevel::to_byte_lossy
-/// for the different trade-offs there.
-const CASCADE_LEVEL_SHIFT: usize = SOURCE_ORDER_BITS;
-
-/// Stores the source order of a block, the cascade level it belongs to, and the
-/// counter needed to handle Shadow DOM cascade order properly.
-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
-struct ApplicableDeclarationBits(u32);
-
-impl ApplicableDeclarationBits {
- fn new(source_order: u32, cascade_level: CascadeLevel) -> Self {
- Self(
- (source_order & SOURCE_ORDER_MASK) |
- ((cascade_level.to_byte_lossy() as u32) << CASCADE_LEVEL_SHIFT),
- )
+const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX;
+
+/// The cascade-level+layer order of this declaration.
+#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
+pub struct CascadePriority {
+ cascade_level: CascadeLevel,
+ layer_order: LayerOrder,
+}
+
+#[allow(dead_code)]
+fn size_assert() {
+ #[allow(unsafe_code)]
+ unsafe { std::mem::transmute::<u32, CascadePriority>(0u32) };
+}
+
+impl PartialOrd for CascadePriority {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for CascadePriority {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.cascade_level
+ .cmp(&other.cascade_level)
+ .then_with(|| {
+ let ordering = self.layer_order.cmp(&other.layer_order);
+ // https://drafts.csswg.org/css-cascade-5/#cascade-layering
+ //
+ // Cascade layers (like declarations) are ordered by order
+ // of appearance. When comparing declarations that belong to
+ // different layers, then for normal rules the declaration
+ // whose cascade layer is last wins, and for important rules
+ // the declaration whose cascade layer is first wins.
+ //
+ // FIXME: This creates somewhat surprising behavior for the
+ // style attribute, see
+ // https://github.com/w3c/csswg-drafts/issues/6872
+ if self.cascade_level.is_important() {
+ ordering.reverse()
+ } else {
+ ordering
+ }
+ })
+ }
+}
+
+impl CascadePriority {
+ /// Construct a new CascadePriority for a given (level, order) pair.
+ pub fn new(cascade_level: CascadeLevel, layer_order: LayerOrder) -> Self {
+ Self { cascade_level, layer_order }
}
- fn source_order(&self) -> u32 {
- self.0 & SOURCE_ORDER_MASK
+ /// Returns the layer order.
+ #[inline]
+ pub fn layer_order(&self) -> LayerOrder {
+ self.layer_order
+ }
+
+ /// Returns the cascade level.
+ #[inline]
+ pub fn cascade_level(&self) -> CascadeLevel {
+ self.cascade_level
+ }
+
+ /// Whether this declaration should be allowed if `revert` or `revert-layer`
+ /// have been specified on a given origin.
+ ///
+ /// `self` is the priority at which the `revert` or `revert-layer` keyword
+ /// have been specified.
+ pub fn allows_when_reverted(&self, other: &Self, origin_revert: bool) -> bool {
+ if origin_revert {
+ other.cascade_level.origin() < self.cascade_level.origin()
+ } else {
+ other.unimportant() < self.unimportant()
+ }
}
- fn level(&self) -> CascadeLevel {
- CascadeLevel::from_byte((self.0 >> CASCADE_LEVEL_SHIFT) as u8)
+ /// Convert this priority from "important" to "non-important", if needed.
+ pub fn unimportant(&self) -> Self {
+ Self::new(self.cascade_level().unimportant(), self.layer_order())
+ }
+
+ /// Convert this priority from "non-important" to "important", if needed.
+ pub fn important(&self) -> Self {
+ Self::new(self.cascade_level().important(), self.layer_order())
}
}
@@ -69,11 +135,11 @@ pub struct ApplicableDeclarationBlock {
pub source: StyleSource,
/// The bits containing the source order, cascade level, and shadow cascade
/// order.
- bits: ApplicableDeclarationBits,
+ source_order: u32,
/// The specificity of the selector.
pub specificity: u32,
- /// The layer order of the selector.
- pub layer_order: LayerOrder,
+ /// The cascade priority of the rule.
+ pub cascade_priority: CascadePriority,
}
impl ApplicableDeclarationBlock {
@@ -86,9 +152,9 @@ impl ApplicableDeclarationBlock {
) -> Self {
ApplicableDeclarationBlock {
source: StyleSource::from_declarations(declarations),
- bits: ApplicableDeclarationBits::new(0, level),
+ source_order: 0,
specificity: 0,
- layer_order: LayerOrder::root(),
+ cascade_priority: CascadePriority::new(level, LayerOrder::root()),
}
}
@@ -103,29 +169,34 @@ impl ApplicableDeclarationBlock {
) -> Self {
ApplicableDeclarationBlock {
source,
- bits: ApplicableDeclarationBits::new(source_order, level),
+ source_order: source_order & SOURCE_ORDER_MASK,
specificity,
- layer_order,
+ cascade_priority: CascadePriority::new(level, layer_order),
}
}
/// Returns the source order of the block.
#[inline]
pub fn source_order(&self) -> u32 {
- self.bits.source_order()
+ self.source_order
}
/// Returns the cascade level of the block.
#[inline]
pub fn level(&self) -> CascadeLevel {
- self.bits.level()
+ self.cascade_priority.cascade_level()
+ }
+
+ /// Returns the cascade level of the block.
+ #[inline]
+ pub fn layer_order(&self) -> LayerOrder {
+ self.cascade_priority.layer_order()
}
/// Convenience method to consume self and return the right thing for the
/// rule tree to iterate over.
#[inline]
- pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel) {
- let level = self.level();
- (self.source, level)
+ pub fn for_rule_tree(self) -> (StyleSource, CascadePriority) {
+ (self.source, self.cascade_priority)
}
}
diff --git a/components/style/custom_properties.rs b/components/style/custom_properties.rs
index 427fe03439c..de887396c55 100644
--- a/components/style/custom_properties.rs
+++ b/components/style/custom_properties.rs
@@ -6,11 +6,11 @@
//!
//! [custom]: https://drafts.csswg.org/css-variables/
+use crate::applicable_declarations::CascadePriority;
use crate::hash::map::Entry;
use crate::media_queries::Device;
use crate::properties::{CSSWideKeyword, CustomDeclaration, CustomDeclarationValue};
use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, PrecomputedHasher};
-use crate::stylesheets::{Origin, PerOrigin};
use crate::Atom;
use cssparser::{
CowRcStr, Delimiter, Parser, ParserInput, SourcePosition, Token, TokenSerializationType,
@@ -599,10 +599,10 @@ fn parse_env_function<'i, 't>(
/// properties.
pub struct CustomPropertiesBuilder<'a> {
seen: PrecomputedHashSet<&'a Name>,
- reverted: PerOrigin<PrecomputedHashSet<&'a Name>>,
may_have_cycles: bool,
custom_properties: Option<CustomPropertiesMap>,
inherited: Option<&'a Arc<CustomPropertiesMap>>,
+ reverted: PrecomputedHashMap<&'a Name, (CascadePriority, bool)>,
device: &'a Device,
}
@@ -620,14 +620,16 @@ impl<'a> CustomPropertiesBuilder<'a> {
}
/// Cascade a given custom property declaration.
- pub fn cascade(&mut self, declaration: &'a CustomDeclaration, origin: Origin) {
+ pub fn cascade(&mut self, declaration: &'a CustomDeclaration, priority: CascadePriority) {
let CustomDeclaration {
ref name,
ref value,
} = *declaration;
- if self.reverted.borrow_for_origin(&origin).contains(&name) {
- return;
+ if let Some(&(reverted_priority, is_origin_revert)) = self.reverted.get(&name) {
+ if !reverted_priority.allows_when_reverted(&priority, is_origin_revert) {
+ return;
+ }
}
let was_already_present = !self.seen.insert(name);
@@ -670,11 +672,10 @@ impl<'a> CustomPropertiesBuilder<'a> {
map.insert(name.clone(), value);
},
CustomDeclarationValue::CSSWideKeyword(keyword) => match keyword {
- CSSWideKeyword::Revert => {
+ CSSWideKeyword::RevertLayer | CSSWideKeyword::Revert => {
+ let origin_revert = keyword == CSSWideKeyword::Revert;
self.seen.remove(name);
- for origin in origin.following_including() {
- self.reverted.borrow_mut_for_origin(&origin).insert(name);
- }
+ self.reverted.insert(name, (priority, origin_revert));
},
CSSWideKeyword::Initial => {
map.remove(name);
diff --git a/components/style/matching.rs b/components/style/matching.rs
index 9b267cd8b46..92fdee3f97b 100644
--- a/components/style/matching.rs
+++ b/components/style/matching.rs
@@ -23,6 +23,7 @@ use crate::selector_parser::{PseudoElement, RestyleDamage};
use crate::shared_lock::Locked;
use crate::style_resolver::ResolvedElementStyles;
use crate::style_resolver::{PseudoElementResolution, StyleResolverForElement};
+use crate::stylesheets::layer_rule::LayerOrder;
use crate::stylist::RuleInclusion;
use crate::traversal_flags::TraversalFlags;
use selectors::matching::ElementSelectorFlags;
@@ -92,6 +93,7 @@ trait PrivateMatchMethods: TElement {
fn replace_single_rule_node(
context: &SharedStyleContext,
level: CascadeLevel,
+ layer_order: LayerOrder,
pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
path: &mut StrongRuleNode,
) -> bool {
@@ -101,6 +103,7 @@ trait PrivateMatchMethods: TElement {
let mut important_rules_changed = false;
let new_node = stylist.rule_tree().update_rule_at_level(
level,
+ layer_order,
pdb,
path,
guards,
@@ -145,12 +148,14 @@ trait PrivateMatchMethods: TElement {
result |= Self::replace_single_rule_node(
context.shared,
CascadeLevel::same_tree_author_normal(),
+ LayerOrder::root(),
style_attribute,
primary_rules,
);
result |= Self::replace_single_rule_node(
context.shared,
CascadeLevel::same_tree_author_important(),
+ LayerOrder::root(),
style_attribute,
primary_rules,
);
@@ -172,6 +177,7 @@ trait PrivateMatchMethods: TElement {
Self::replace_single_rule_node(
context.shared,
CascadeLevel::SMILOverride,
+ LayerOrder::root(),
self.smil_override(),
primary_rules,
);
@@ -181,6 +187,7 @@ trait PrivateMatchMethods: TElement {
Self::replace_single_rule_node(
context.shared,
CascadeLevel::Transitions,
+ LayerOrder::root(),
self.transition_rule(&context.shared)
.as_ref()
.map(|a| a.borrow_arc()),
@@ -192,6 +199,7 @@ trait PrivateMatchMethods: TElement {
Self::replace_single_rule_node(
context.shared,
CascadeLevel::Animations,
+ LayerOrder::root(),
self.animation_rule(&context.shared)
.as_ref()
.map(|a| a.borrow_arc()),
@@ -589,12 +597,14 @@ trait PrivateMatchMethods: TElement {
Self::replace_single_rule_node(
&context.shared,
CascadeLevel::Transitions,
+ LayerOrder::root(),
declarations.transitions.as_ref().map(|a| a.borrow_arc()),
&mut rule_node,
);
Self::replace_single_rule_node(
&context.shared,
CascadeLevel::Animations,
+ LayerOrder::root(),
declarations.animations.as_ref().map(|a| a.borrow_arc()),
&mut rule_node,
);
diff --git a/components/style/properties/cascade.rs b/components/style/properties/cascade.rs
index 6b8c4cf4d37..dfdb2a2b1c8 100644
--- a/components/style/properties/cascade.rs
+++ b/components/style/properties/cascade.rs
@@ -4,6 +4,7 @@
//! The main cascading algorithm of the style system.
+use crate::applicable_declarations::CascadePriority;
use crate::context::QuirksMode;
use crate::custom_properties::CustomPropertiesBuilder;
use crate::dom::TElement;
@@ -15,12 +16,13 @@ use crate::properties::{
ShorthandsWithPropertyReferencesCache, StyleBuilder, CASCADE_PROPERTY,
};
use crate::rule_cache::{RuleCache, RuleCacheConditions};
-use crate::rule_tree::StrongRuleNode;
+use crate::rule_tree::{StrongRuleNode, CascadeLevel};
use crate::selector_parser::PseudoElement;
use crate::shared_lock::StylesheetGuards;
use crate::style_adjuster::StyleAdjuster;
-use crate::stylesheets::{Origin, PerOrigin};
+use crate::stylesheets::{Origin, layer_rule::LayerOrder};
use crate::values::{computed, specified};
+use fxhash::FxHashMap;
use servo_arc::Arc;
use smallvec::SmallVec;
use std::borrow::Cow;
@@ -115,6 +117,7 @@ struct DeclarationIterator<'a> {
declarations: DeclarationImportanceIterator<'a>,
origin: Origin,
importance: Importance,
+ priority: CascadePriority,
}
impl<'a> DeclarationIterator<'a> {
@@ -128,8 +131,9 @@ impl<'a> DeclarationIterator<'a> {
let mut iter = Self {
guards,
current_rule_node: Some(rule_node),
- origin: Origin::Author,
+ origin: Origin::UserAgent,
importance: Importance::Normal,
+ priority: CascadePriority::new(CascadeLevel::UANormal, LayerOrder::root()),
declarations: DeclarationImportanceIterator::default(),
restriction,
};
@@ -138,10 +142,11 @@ impl<'a> DeclarationIterator<'a> {
}
fn update_for_node(&mut self, node: &'a StrongRuleNode) {
- let origin = node.cascade_level().origin();
- self.origin = origin;
- self.importance = node.importance();
- let guard = match origin {
+ self.priority = node.cascade_priority();
+ let level = self.priority.cascade_level();
+ self.origin = level.origin();
+ self.importance = level.importance();
+ let guard = match self.origin {
Origin::Author => self.guards.author,
Origin::User | Origin::UserAgent => self.guards.ua_or_user,
};
@@ -153,7 +158,7 @@ impl<'a> DeclarationIterator<'a> {
}
impl<'a> Iterator for DeclarationIterator<'a> {
- type Item = (&'a PropertyDeclaration, Origin);
+ type Item = (&'a PropertyDeclaration, CascadePriority);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
@@ -163,20 +168,19 @@ impl<'a> Iterator for DeclarationIterator<'a> {
continue;
}
- let origin = self.origin;
if let Some(restriction) = self.restriction {
// decl.id() is either a longhand or a custom
// property. Custom properties are always allowed, but
// longhands are only allowed if they have our
// restriction flag set.
if let PropertyDeclarationId::Longhand(id) = decl.id() {
- if !id.flags().contains(restriction) && origin != Origin::UserAgent {
+ if !id.flags().contains(restriction) && self.origin != Origin::UserAgent {
continue;
}
}
}
- return Some((decl, origin));
+ return Some((decl, self.priority));
}
let next_node = self.current_rule_node.take()?.parent()?;
@@ -259,7 +263,7 @@ pub fn apply_declarations<'a, E, I>(
) -> Arc<ComputedValues>
where
E: TElement,
- I: Iterator<Item = (&'a PropertyDeclaration, Origin)>,
+ I: Iterator<Item = (&'a PropertyDeclaration, CascadePriority)>,
{
debug_assert!(layout_parent_style.is_none() || parent_style.is_some());
debug_assert_eq!(
@@ -278,14 +282,14 @@ where
let inherited_style = parent_style.unwrap_or(device.default_computed_values());
- let mut declarations = SmallVec::<[(&_, Origin); 32]>::new();
+ let mut declarations = SmallVec::<[(&_, CascadePriority); 32]>::new();
let custom_properties = {
let mut builder = CustomPropertiesBuilder::new(inherited_style.custom_properties(), device);
- for (declaration, origin) in iter {
- declarations.push((declaration, origin));
+ for (declaration, priority) in iter {
+ declarations.push((declaration, priority));
if let PropertyDeclaration::Custom(ref declaration) = *declaration {
- builder.cascade(declaration, origin);
+ builder.cascade(declaration, priority);
}
}
@@ -494,7 +498,8 @@ struct Cascade<'a, 'b: 'a> {
cascade_mode: CascadeMode<'a>,
seen: LonghandIdSet,
author_specified: LonghandIdSet,
- reverted: PerOrigin<LonghandIdSet>,
+ reverted_set: LonghandIdSet,
+ reverted: FxHashMap<LonghandId, (CascadePriority, bool)>,
}
impl<'a, 'b: 'a> Cascade<'a, 'b> {
@@ -504,6 +509,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
cascade_mode,
seen: LonghandIdSet::default(),
author_specified: LonghandIdSet::default(),
+ reverted_set: Default::default(),
reverted: Default::default(),
}
}
@@ -575,7 +581,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
mut shorthand_cache: &mut ShorthandsWithPropertyReferencesCache,
) where
Phase: CascadePhase,
- I: Iterator<Item = (&'decls PropertyDeclaration, Origin)>,
+ I: Iterator<Item = (&'decls PropertyDeclaration, CascadePriority)>,
{
let apply_reset = apply_reset == ApplyResetProperties::Yes;
@@ -589,7 +595,9 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
let ignore_colors = !self.context.builder.device.use_document_colors();
let mut declarations_to_apply_unless_overriden = DeclarationsToApplyUnlessOverriden::new();
- for (declaration, origin) in declarations {
+ for (declaration, priority) in declarations {
+ let origin = priority.cascade_level().origin();
+
let declaration_id = declaration.id();
let longhand_id = match declaration_id {
PropertyDeclarationId::Longhand(id) => id,
@@ -616,12 +624,12 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
continue;
}
- if self
- .reverted
- .borrow_for_origin(&origin)
- .contains(physical_longhand_id)
- {
- continue;
+ if self.reverted_set.contains(physical_longhand_id) {
+ if let Some(&(reverted_priority, is_origin_revert)) = self.reverted.get(&physical_longhand_id) {
+ if !reverted_priority.allows_when_reverted(&priority, is_origin_revert) {
+ continue;
+ }
+ }
}
// Only a few properties are allowed to depend on the visited state
@@ -653,32 +661,31 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
);
}
- let css_wide_keyword = declaration.get_css_wide_keyword();
- if let Some(CSSWideKeyword::Revert) = css_wide_keyword {
- // We intentionally don't want to insert it into `self.seen`,
- // `reverted` takes care of rejecting other declarations as
- // needed.
- for origin in origin.following_including() {
- self.reverted
- .borrow_mut_for_origin(&origin)
- .insert(physical_longhand_id);
- }
- continue;
- }
+ let is_unset = match declaration.get_css_wide_keyword() {
+ Some(keyword) => match keyword {
+ CSSWideKeyword::RevertLayer |
+ CSSWideKeyword::Revert => {
+ let origin_revert = keyword == CSSWideKeyword::Revert;
+ // We intentionally don't want to insert it into
+ // `self.seen`, `reverted` takes care of rejecting other
+ // declarations as needed.
+ self.reverted_set.insert(physical_longhand_id);
+ self.reverted.insert(physical_longhand_id, (priority, origin_revert));
+ continue;
+ },
+ CSSWideKeyword::Unset => true,
+ CSSWideKeyword::Inherit => inherited,
+ CSSWideKeyword::Initial => !inherited,
+ },
+ None => false,
+ };
self.seen.insert(physical_longhand_id);
if origin == Origin::Author {
self.author_specified.insert(physical_longhand_id);
}
- let unset = css_wide_keyword.map_or(false, |css_wide_keyword| match css_wide_keyword {
- CSSWideKeyword::Unset => true,
- CSSWideKeyword::Inherit => inherited,
- CSSWideKeyword::Initial => !inherited,
- CSSWideKeyword::Revert => unreachable!(),
- });
-
- if unset {
+ if is_unset {
continue;
}
diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs
index 980d3de11ff..01b390f0fca 100644
--- a/components/style/properties/declaration_block.rs
+++ b/components/style/properties/declaration_block.rs
@@ -7,15 +7,17 @@
#![deny(missing_docs)]
use super::*;
+use crate::applicable_declarations::CascadePriority;
use crate::context::QuirksMode;
use crate::custom_properties::CustomPropertiesBuilder;
use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
use crate::parser::ParserContext;
use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
+use crate::rule_tree::CascadeLevel;
use crate::selector_parser::SelectorImpl;
use crate::shared_lock::Locked;
use crate::str::{CssString, CssStringWriter};
-use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
+use crate::stylesheets::{CssRuleType, Origin, UrlExtraData, layer_rule::LayerOrder};
use crate::values::computed::Context;
use cssparser::{parse_important, CowRcStr, DeclarationListParser, ParserInput};
use cssparser::{AtRuleParser, DeclarationParser, Delimiter, ParseErrorKind, Parser};
@@ -898,7 +900,7 @@ impl PropertyDeclarationBlock {
for declaration in self.normal_declaration_iter() {
if let PropertyDeclaration::Custom(ref declaration) = *declaration {
- builder.cascade(declaration, Origin::Author);
+ builder.cascade(declaration, CascadePriority::new(CascadeLevel::same_tree_author_normal(), LayerOrder::root()));
}
}
diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs
index e46024feba1..91be2d6011b 100644
--- a/components/style/properties/helpers.mako.rs
+++ b/components/style/properties/helpers.mako.rs
@@ -476,6 +476,7 @@
context.builder.inherit_${property.ident}();
% endif
}
+ CSSWideKeyword::RevertLayer |
CSSWideKeyword::Revert => unreachable!("Should never get here"),
}
return;
diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs
index 2f9e692f740..f9067c0e9a8 100644
--- a/components/style/properties/helpers/animated_properties.mako.rs
+++ b/components/style/properties/helpers/animated_properties.mako.rs
@@ -311,9 +311,9 @@ impl AnimationValue {
% for prop in data.longhands:
% if prop.animatable:
LonghandId::${prop.camel_case} => {
- // FIXME(emilio, bug 1533327): I think
- // CSSWideKeyword::Revert handling is not fine here, but
- // what to do instead?
+ // FIXME(emilio, bug 1533327): I think revert (and
+ // revert-layer) handling is not fine here, but what to
+ // do instead?
//
// Seems we'd need the computed value as if it was
// revert, somehow. Treating it as `unset` seems fine
@@ -321,6 +321,7 @@ impl AnimationValue {
let style_struct = match declaration.keyword {
% if not prop.style_struct.inherited:
CSSWideKeyword::Revert |
+ CSSWideKeyword::RevertLayer |
CSSWideKeyword::Unset |
% endif
CSSWideKeyword::Initial => {
@@ -328,6 +329,7 @@ impl AnimationValue {
},
% if prop.style_struct.inherited:
CSSWideKeyword::Revert |
+ CSSWideKeyword::RevertLayer |
CSSWideKeyword::Unset |
% endif
CSSWideKeyword::Inherit => {
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index 4ee388dfe6c..cdecfaae895 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -1051,6 +1051,8 @@ pub enum CSSWideKeyword {
Unset,
/// The `revert` keyword.
Revert,
+ /// The `revert-layer` keyword.
+ RevertLayer,
}
impl CSSWideKeyword {
@@ -1060,22 +1062,28 @@ impl CSSWideKeyword {
CSSWideKeyword::Inherit => "inherit",
CSSWideKeyword::Unset => "unset",
CSSWideKeyword::Revert => "revert",
+ CSSWideKeyword::RevertLayer => "revert-layer",
}
}
}
impl CSSWideKeyword {
+ /// Parses a CSS wide keyword from a CSS identifier.
+ pub fn from_ident(ident: &str) -> Result<Self, ()> {
+ Ok(match_ignore_ascii_case! { ident,
+ "initial" => CSSWideKeyword::Initial,
+ "inherit" => CSSWideKeyword::Inherit,
+ "unset" => CSSWideKeyword::Unset,
+ "revert" => CSSWideKeyword::Revert,
+ "revert-layer" if static_prefs::pref!("layout.css.cascade-layers.enabled") => CSSWideKeyword::RevertLayer,
+ _ => return Err(()),
+ })
+ }
+
fn parse(input: &mut Parser) -> Result<Self, ()> {
let keyword = {
let ident = input.expect_ident().map_err(|_| ())?;
- match_ignore_ascii_case! { ident,
- // If modifying this set of keyword, also update values::CustomIdent::from_ident
- "initial" => CSSWideKeyword::Initial,
- "inherit" => CSSWideKeyword::Inherit,
- "unset" => CSSWideKeyword::Unset,
- "revert" => CSSWideKeyword::Revert,
- _ => return Err(()),
- }
+ Self::from_ident(ident)?
};
input.expect_exhausted().map_err(|_| ())?;
Ok(keyword)
diff --git a/components/style/rule_collector.rs b/components/style/rule_collector.rs
index 021c0176416..513c2d91566 100644
--- a/components/style/rule_collector.rs
+++ b/components/style/rule_collector.rs
@@ -148,7 +148,7 @@ where
f(self);
if start != self.rules.len() {
self.rules[start..].sort_unstable_by_key(|block| {
- (block.layer_order, block.specificity, block.source_order())
+ (block.layer_order(), block.specificity, block.source_order())
});
}
self.context.current_host = old_host;
diff --git a/components/style/rule_tree/core.rs b/components/style/rule_tree/core.rs
index ae1ba7bed94..fe1214faf65 100644
--- a/components/style/rule_tree/core.rs
+++ b/components/style/rule_tree/core.rs
@@ -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
+ /// The cascade priority.
+ #[inline]
+ pub fn cascade_priority(&self) -> CascadePriority {
+ self.p.cascade_priority
+ }
+
+ /// The cascade level.
+ #[inline]
pub fn cascade_level(&self) -> CascadeLevel {
- self.p.level
+ self.cascade_priority().cascade_level()
}
- /// Get the importance that this rule node represents.
- pub fn importance(&self) -> Importance {
- self.p.level.importance()
+ /// 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
diff --git a/components/style/rule_tree/level.rs b/components/style/rule_tree/level.rs
index c46e63796ad..b8cbe55ed9c 100644
--- a/components/style/rule_tree/level.rs
+++ b/components/style/rule_tree/level.rs
@@ -29,7 +29,7 @@ use crate::stylesheets::Origin;
/// [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)]
+#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
pub enum CascadeLevel {
/// Normal User-Agent rules.
UANormal,
@@ -69,82 +69,44 @@ pub enum CascadeLevel {
}
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),
+ /// Convert this level from "unimportant" to "important".
+ pub fn important(&self) -> Self {
+ match *self {
+ Self::UANormal => Self::UAImportant,
+ Self::UserNormal => Self::UserImportant,
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;
+ } => Self::AuthorImportant {
+ shadow_cascade_order: -shadow_cascade_order,
+ },
+ Self::PresHints |
+ Self::SMILOverride |
+ Self::Animations |
+ Self::AuthorImportant { .. } |
+ Self::UserImportant |
+ Self::UAImportant |
+ Self::Transitions => *self,
}
-
- 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),
- }
+ /// Convert this level from "important" to "non-important".
+ pub fn unimportant(&self) -> Self {
+ match *self {
+ Self::UAImportant => Self::UANormal,
+ Self::UserImportant => Self::UserNormal,
+ Self::AuthorImportant {
+ shadow_cascade_order,
+ } => Self::AuthorNormal {
+ shadow_cascade_order: -shadow_cascade_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
+ Self::PresHints |
+ Self::SMILOverride |
+ Self::Animations |
+ Self::AuthorNormal { .. } |
+ Self::UserNormal |
+ Self::UANormal |
+ Self::Transitions => *self,
+ }
}
/// Select a lock guard for this level
@@ -231,6 +193,12 @@ impl CascadeLevel {
pub struct ShadowCascadeOrder(i8);
impl ShadowCascadeOrder {
+ /// We keep a maximum of 3 bits of order as a limit so that we can pack
+ /// CascadeLevel in one byte by using half of it for the order, if that ends
+ /// up being necessary.
+ 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]
@@ -256,7 +224,9 @@ impl ShadowCascadeOrder {
#[inline]
pub fn dec(&mut self) {
debug_assert!(self.0 < 0);
- self.0 = self.0.saturating_sub(1);
+ if self.0 != Self::MIN {
+ self.0 -= 1;
+ }
}
/// The level, moving inwards. We should only move inwards if we're
@@ -264,7 +234,9 @@ impl ShadowCascadeOrder {
#[inline]
pub fn inc(&mut self) {
debug_assert_ne!(self.0, -1);
- self.0 = self.0.saturating_add(1);
+ if self.0 != Self::MAX {
+ self.0 += 1;
+ }
}
}
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,
diff --git a/components/style/stylesheets/layer_rule.rs b/components/style/stylesheets/layer_rule.rs
index ee066d813e2..1b7b0cb169e 100644
--- a/components/style/stylesheets/layer_rule.rs
+++ b/components/style/stylesheets/layer_rule.rs
@@ -19,14 +19,16 @@ use smallvec::SmallVec;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss};
-/// The order of a given layer.
-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord)]
-pub struct LayerOrder(u32);
+/// The order of a given layer. We use 16 bits so that we can pack LayerOrder
+/// and CascadeLevel in a single 32-bit struct. If we need more bits we can go
+/// back to packing CascadeLevel in a single byte as we did before.
+#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord)]
+pub struct LayerOrder(u16);
impl LayerOrder {
/// The order of the root layer.
pub const fn root() -> Self {
- Self(std::u32::MAX)
+ Self(std::u16::MAX)
}
/// The first cascade layer order.
@@ -37,7 +39,9 @@ impl LayerOrder {
/// Increment the cascade layer order.
#[inline]
pub fn inc(&mut self) {
- self.0 += 1;
+ if self.0 != std::u16::MAX {
+ self.0 += 1;
+ }
}
}
diff --git a/components/style/stylesheets/origin.rs b/components/style/stylesheets/origin.rs
index a65b61fca13..27ad3fa184a 100644
--- a/components/style/stylesheets/origin.rs
+++ b/components/style/stylesheets/origin.rs
@@ -10,7 +10,7 @@ use std::ops::BitOrAssign;
/// Each style rule has an origin, which determines where it enters the cascade.
///
/// <https://drafts.csswg.org/css-cascade/#cascading-origins>
-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)]
+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem, PartialOrd, Ord)]
#[repr(u8)]
pub enum Origin {
/// <https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent>
diff --git a/components/style/stylist.rs b/components/style/stylist.rs
index a48a7103f84..c0cc2f238bb 100644
--- a/components/style/stylist.rs
+++ b/components/style/stylist.rs
@@ -4,7 +4,9 @@
//! Selector matching.
-use crate::applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
+use crate::applicable_declarations::{
+ ApplicableDeclarationBlock, ApplicableDeclarationList, CascadePriority,
+};
use crate::context::{CascadeInputs, QuirksMode};
use crate::dom::{TElement, TShadowRoot};
use crate::element_state::{DocumentState, ElementState};
@@ -1474,9 +1476,15 @@ impl Stylist {
/* pseudo = */ None,
self.rule_tree.root(),
guards,
- block
- .declaration_importance_iter()
- .map(|(declaration, _)| (declaration, Origin::Author)),
+ block.declaration_importance_iter().map(|(declaration, _)| {
+ (
+ declaration,
+ CascadePriority::new(
+ CascadeLevel::same_tree_author_normal(),
+ LayerOrder::root(),
+ ),
+ )
+ }),
Some(parent_style),
Some(parent_style),
Some(parent_style),
@@ -1582,7 +1590,7 @@ impl ExtraStyleData {
&mut self,
guard: &SharedRwLockReadGuard,
rule: &Arc<Locked<ScrollTimelineRule>>,
- )-> Result<(), FailedAllocationError> {
+ ) -> Result<(), FailedAllocationError> {
let name = rule.read_with(guard).name.as_atom().clone();
self.scroll_timelines
.try_insert(name, rule.clone())
diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs
index 626fc32ff18..ad09320c42b 100644
--- a/components/style/values/mod.rs
+++ b/components/style/values/mod.rs
@@ -438,15 +438,22 @@ impl CustomIdent {
ident: &CowRcStr<'i>,
excluding: &[&str],
) -> Result<Self, ParseError<'i>> {
- let valid = match_ignore_ascii_case! { ident,
- "initial" | "inherit" | "unset" | "default" | "revert" => false,
- _ => true
- };
- if !valid {
+ use crate::properties::CSSWideKeyword;
+ // https://drafts.csswg.org/css-values-4/#custom-idents:
+ //
+ // The CSS-wide keywords are not valid <custom-ident>s. The default
+ // keyword is reserved and is also not a valid <custom-ident>.
+ //
+ if CSSWideKeyword::from_ident(ident).is_ok() || ident.eq_ignore_ascii_case("default") {
return Err(
location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
);
}
+
+ // https://drafts.csswg.org/css-values-4/#custom-idents:
+ //
+ // Excluded keywords are excluded in all ASCII case permutations.
+ //
if excluding.iter().any(|s| ident.eq_ignore_ascii_case(s)) {
Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
} else {