aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/style/invalidation/stylesheets.rs4
-rw-r--r--components/style/stylesheets/layer_rule.rs171
-rw-r--r--components/style/stylesheets/mod.rs23
-rw-r--r--components/style/stylesheets/rules_iterator.rs9
-rw-r--r--components/style/stylesheets/stylesheet.rs5
-rw-r--r--components/style/stylist.rs1
6 files changed, 208 insertions, 5 deletions
diff --git a/components/style/invalidation/stylesheets.rs b/components/style/invalidation/stylesheets.rs
index edecc3fc243..f4dc0c5a443 100644
--- a/components/style/invalidation/stylesheets.rs
+++ b/components/style/invalidation/stylesheets.rs
@@ -555,7 +555,7 @@ impl StylesheetInvalidationSet {
self.collect_invalidations_for_rule(rule, guard, device, quirks_mode)
},
- Document(..) | Import(..) | Media(..) | Supports(..) => {
+ Document(..) | Import(..) | Media(..) | Supports(..) | Layer(..) => {
if !is_generic_change &&
!EffectiveRules::is_effective(guard, device, quirks_mode, rule)
{
@@ -596,7 +596,7 @@ impl StylesheetInvalidationSet {
}
}
},
- Document(..) | Namespace(..) | Import(..) | Media(..) | Supports(..) => {
+ Document(..) | Namespace(..) | Import(..) | Media(..) | Supports(..) | Layer(..) => {
// Do nothing, relevant nested rules are visited as part of the
// iteration.
},
diff --git a/components/style/stylesheets/layer_rule.rs b/components/style/stylesheets/layer_rule.rs
new file mode 100644
index 00000000000..873c9e1275c
--- /dev/null
+++ b/components/style/stylesheets/layer_rule.rs
@@ -0,0 +1,171 @@
+/* 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/. */
+
+//! A [`@layer`][layer] urle.
+//!
+//! [layer]: https://drafts.csswg.org/css-cascade-5/#layering
+
+use crate::parser::{Parse, ParserContext};
+use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
+use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
+use crate::values::AtomIdent;
+
+use super::CssRules;
+
+use cssparser::{Parser, SourceLocation, ToCss as CssParserToCss, Token};
+use servo_arc::Arc;
+use smallvec::SmallVec;
+use std::fmt::{self, Write};
+use style_traits::{CssWriter, ParseError, ToCss};
+
+/// A `<layer-name>`: https://drafts.csswg.org/css-cascade-5/#typedef-layer-name
+#[derive(Clone, Debug, ToShmem)]
+pub struct LayerName(SmallVec<[AtomIdent; 1]>);
+
+impl Parse for LayerName {
+ fn parse<'i, 't>(
+ _: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ let mut result = SmallVec::new();
+ result.push(AtomIdent::from(&**input.expect_ident()?));
+ loop {
+ let next_name = input.try_parse(|input| -> Result<AtomIdent, ParseError<'i>> {
+ match input.next_including_whitespace()? {
+ Token::Delim('.') => {},
+ other => {
+ let t = other.clone();
+ return Err(input.new_unexpected_token_error(t));
+ },
+ }
+
+ let name = match input.next_including_whitespace()? {
+ Token::Ident(ref ident) => ident,
+ other => {
+ let t = other.clone();
+ return Err(input.new_unexpected_token_error(t));
+ },
+ };
+
+ Ok(AtomIdent::from(&**name))
+ });
+
+ match next_name {
+ Ok(name) => result.push(name),
+ Err(..) => break,
+ }
+ }
+ Ok(LayerName(result))
+ }
+}
+
+impl ToCss for LayerName {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ let mut first = true;
+ for name in self.0.iter() {
+ if !first {
+ dest.write_char('.')?;
+ }
+ first = false;
+ name.to_css(dest)?;
+ }
+ Ok(())
+ }
+}
+
+/// The kind of layer rule this is.
+#[derive(Debug, ToShmem)]
+pub enum LayerRuleKind {
+ /// A block `@layer <name>? { ... }`
+ Block {
+ /// The layer name, or `None` if anonymous.
+ name: Option<LayerName>,
+ /// The nested rules.
+ rules: Arc<Locked<CssRules>>,
+ },
+ /// A statement `@layer <name>, <name>, <name>;`
+ Statement {
+ /// The list of layers to sort.
+ names: SmallVec<[LayerName; 3]>,
+ },
+}
+
+/// A [`@layer`][layer] urle.
+///
+/// [layer]: https://drafts.csswg.org/css-cascade-5/#layering
+#[derive(Debug, ToShmem)]
+pub struct LayerRule {
+ /// The kind of layer rule we are.
+ pub kind: LayerRuleKind,
+ /// The source position where this media rule was found.
+ pub source_location: SourceLocation,
+}
+
+impl ToCssWithGuard for LayerRule {
+ fn to_css(
+ &self,
+ guard: &SharedRwLockReadGuard,
+ dest: &mut crate::str::CssStringWriter,
+ ) -> fmt::Result {
+ dest.write_str("@layer ")?;
+ match self.kind {
+ LayerRuleKind::Block {
+ ref name,
+ ref rules,
+ } => {
+ if let Some(ref name) = *name {
+ name.to_css(&mut CssWriter::new(dest))?;
+ dest.write_char(' ')?;
+ }
+ rules.read_with(guard).to_css_block(guard, dest)
+ },
+ LayerRuleKind::Statement { ref names } => {
+ let mut writer = CssWriter::new(dest);
+ let mut first = true;
+ for name in &**names {
+ if !first {
+ writer.write_str(", ")?;
+ }
+ first = false;
+ name.to_css(&mut writer)?;
+ }
+ dest.write_char(';')
+ },
+ }
+ }
+}
+
+impl DeepCloneWithLock for LayerRule {
+ fn deep_clone_with_lock(
+ &self,
+ lock: &SharedRwLock,
+ guard: &SharedRwLockReadGuard,
+ params: &DeepCloneParams,
+ ) -> Self {
+ Self {
+ kind: match self.kind {
+ LayerRuleKind::Block {
+ ref name,
+ ref rules,
+ } => LayerRuleKind::Block {
+ name: name.clone(),
+ rules: Arc::new(
+ lock.wrap(
+ rules
+ .read_with(guard)
+ .deep_clone_with_lock(lock, guard, params),
+ ),
+ ),
+ },
+ LayerRuleKind::Statement { ref names } => LayerRuleKind::Statement {
+ names: names.clone(),
+ },
+ },
+ source_location: self.source_location.clone(),
+ }
+ }
+}
diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs
index fd9be56b5b5..dbb42667b60 100644
--- a/components/style/stylesheets/mod.rs
+++ b/components/style/stylesheets/mod.rs
@@ -11,6 +11,7 @@ mod font_face_rule;
pub mod font_feature_values_rule;
pub mod import_rule;
pub mod keyframes_rule;
+mod layer_rule;
mod loader;
mod media_rule;
mod namespace_rule;
@@ -49,6 +50,7 @@ pub use self::font_face_rule::FontFaceRule;
pub use self::font_feature_values_rule::FontFeatureValuesRule;
pub use self::import_rule::ImportRule;
pub use self::keyframes_rule::KeyframesRule;
+pub use self::layer_rule::LayerRule;
pub use self::loader::StylesheetLoader;
pub use self::media_rule::MediaRule;
pub use self::namespace_rule::NamespaceRule;
@@ -257,6 +259,7 @@ pub enum CssRule {
Supports(Arc<Locked<SupportsRule>>),
Page(Arc<Locked<PageRule>>),
Document(Arc<Locked<DocumentRule>>),
+ Layer(Arc<Locked<LayerRule>>),
}
impl CssRule {
@@ -297,11 +300,14 @@ impl CssRule {
CssRule::Document(ref lock) => {
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
},
+
+ // TODO(emilio): Add memory reporting for @layer rules.
+ CssRule::Layer(_) => 0,
}
}
}
-#[allow(missing_docs)]
+/// https://drafts.csswg.org/cssom-1/#dom-cssrule-type
#[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq)]
pub enum CssRuleType {
// https://drafts.csswg.org/cssom/#the-cssrule-interface
@@ -323,10 +329,13 @@ pub enum CssRuleType {
Supports = 12,
// https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#extentions-to-cssrule-interface
Document = 13,
- // https://drafts.csswg.org/css-fonts-3/#om-fontfeaturevalues
+ // https://drafts.csswg.org/css-fonts/#om-fontfeaturevalues
FontFeatureValues = 14,
// https://drafts.csswg.org/css-device-adapt/#css-rule-interface
Viewport = 15,
+ // After viewport, all rules should return 0 from the API, but we still need
+ // a constant somewhere.
+ Layer = 16,
}
#[allow(missing_docs)]
@@ -353,6 +362,7 @@ impl CssRule {
CssRule::Supports(_) => CssRuleType::Supports,
CssRule::Page(_) => CssRuleType::Page,
CssRule::Document(_) => CssRuleType::Document,
+ CssRule::Layer(_) => CssRuleType::Layer,
}
}
@@ -361,6 +371,8 @@ impl CssRule {
// CssRule::Charset(..) => State::Start,
CssRule::Import(..) => State::Imports,
CssRule::Namespace(..) => State::Namespaces,
+ // TODO(emilio): We'll need something here for non-block layer
+ // rules.
_ => State::Body,
}
}
@@ -485,6 +497,12 @@ impl DeepCloneWithLock for CssRule {
lock.wrap(rule.deep_clone_with_lock(lock, guard, params)),
))
},
+ CssRule::Layer(ref arc) => {
+ let rule = arc.read_with(guard);
+ CssRule::Layer(Arc::new(
+ lock.wrap(rule.deep_clone_with_lock(lock, guard, params)),
+ ))
+ }
}
}
}
@@ -505,6 +523,7 @@ impl ToCssWithGuard for CssRule {
CssRule::Supports(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Page(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Document(ref lock) => lock.read_with(guard).to_css(guard, dest),
+ CssRule::Layer(ref lock) => lock.read_with(guard).to_css(guard, dest),
}
}
}
diff --git a/components/style/stylesheets/rules_iterator.rs b/components/style/stylesheets/rules_iterator.rs
index a7010ff066e..b1921e63e07 100644
--- a/components/style/stylesheets/rules_iterator.rs
+++ b/components/style/stylesheets/rules_iterator.rs
@@ -105,6 +105,15 @@ where
}
Some(supports_rule.rules.read_with(guard).0.iter())
},
+ CssRule::Layer(ref lock) => {
+ use crate::stylesheets::layer_rule::LayerRuleKind;
+
+ let layer_rule = lock.read_with(guard);
+ match layer_rule.kind {
+ LayerRuleKind::Block { ref rules, .. } => Some(rules.read_with(guard).0.iter()),
+ LayerRuleKind::Statement { .. } => None,
+ }
+ }
}
}
diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs
index b8e7f246c19..91a407f5c32 100644
--- a/components/style/stylesheets/stylesheet.rs
+++ b/components/style/stylesheets/stylesheet.rs
@@ -367,7 +367,10 @@ impl SanitizationKind {
CssRule::Document(..) |
CssRule::Media(..) |
CssRule::Supports(..) |
- CssRule::Import(..) => false,
+ CssRule::Import(..) |
+ // TODO(emilio): Perhaps Layer should not be always sanitized? But
+ // we sanitize @media and co, so this seems safer for now.
+ CssRule::Layer(..) => false,
CssRule::FontFace(..) | CssRule::Namespace(..) | CssRule::Style(..) => true,
diff --git a/components/style/stylist.rs b/components/style/stylist.rs
index fb7334d3600..643a1454e00 100644
--- a/components/style/stylist.rs
+++ b/components/style/stylist.rs
@@ -2348,6 +2348,7 @@ impl CascadeData {
CssRule::Page(..) |
CssRule::Viewport(..) |
CssRule::Document(..) |
+ CssRule::Layer(..) |
CssRule::FontFeatureValues(..) => {
// Not affected by device changes.
continue;