diff options
-rw-r--r-- | components/style/invalidation/stylesheets.rs | 4 | ||||
-rw-r--r-- | components/style/stylesheets/layer_rule.rs | 171 | ||||
-rw-r--r-- | components/style/stylesheets/mod.rs | 23 | ||||
-rw-r--r-- | components/style/stylesheets/rules_iterator.rs | 9 | ||||
-rw-r--r-- | components/style/stylesheets/stylesheet.rs | 5 | ||||
-rw-r--r-- | components/style/stylist.rs | 1 |
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; |