aboutsummaryrefslogtreecommitdiffstats
path: root/components/style
diff options
context:
space:
mode:
Diffstat (limited to 'components/style')
-rw-r--r--components/style/error_reporting.rs10
-rw-r--r--components/style/gecko/arc_types.rs8
-rw-r--r--components/style/invalidation/stylesheets.rs7
-rw-r--r--components/style/properties_and_values/mod.rs1
-rw-r--r--components/style/properties_and_values/rule.rs245
-rw-r--r--components/style/stylesheets/mod.rs15
-rw-r--r--components/style/stylesheets/property_rule.rs5
-rw-r--r--components/style/stylesheets/rule_parser.rs18
-rw-r--r--components/style/stylesheets/rules_iterator.rs1
-rw-r--r--components/style/stylesheets/stylesheet.rs1
-rw-r--r--components/style/stylist.rs2
11 files changed, 310 insertions, 3 deletions
diff --git a/components/style/error_reporting.rs b/components/style/error_reporting.rs
index 042838f3394..258c7c44ef4 100644
--- a/components/style/error_reporting.rs
+++ b/components/style/error_reporting.rs
@@ -22,6 +22,8 @@ pub enum ContextualParseError<'a> {
ParseError<'a>,
Option<&'a SelectorList<SelectorImpl>>,
),
+ /// A property descriptor was not recognized.
+ UnsupportedPropertyDescriptor(&'a str, ParseError<'a>),
/// A font face descriptor was not recognized.
UnsupportedFontFaceDescriptor(&'a str, ParseError<'a>),
/// A font feature values descriptor was not recognized.
@@ -135,6 +137,14 @@ impl<'a> fmt::Display for ContextualParseError<'a> {
write!(f, "Unsupported property declaration: '{}', ", decl)?;
parse_error_to_str(err, f)
},
+ ContextualParseError::UnsupportedPropertyDescriptor(decl, ref err) => {
+ write!(
+ f,
+ "Unsupported @property descriptor declaration: '{}', ",
+ decl
+ )?;
+ parse_error_to_str(err, f)
+ },
ContextualParseError::UnsupportedFontFaceDescriptor(decl, ref err) => {
write!(
f,
diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs
index b2835abdfd0..707266d2bec 100644
--- a/components/style/gecko/arc_types.rs
+++ b/components/style/gecko/arc_types.rs
@@ -16,7 +16,7 @@ use crate::stylesheets::keyframes_rule::Keyframe;
use crate::stylesheets::{
ContainerRule, CounterStyleRule, CssRules, DocumentRule, FontFaceRule, FontFeatureValuesRule,
FontPaletteValuesRule, ImportRule, KeyframesRule, LayerBlockRule, LayerStatementRule,
- MediaRule, NamespaceRule, PageRule, StyleRule, StylesheetContents, SupportsRule,
+ MediaRule, NamespaceRule, PageRule, PropertyRule, StyleRule, StylesheetContents, SupportsRule,
};
use servo_arc::Arc;
@@ -115,6 +115,12 @@ impl_locked_arc_ffi!(
Servo_PageRule_Release
);
impl_locked_arc_ffi!(
+ PropertyRule,
+ LockedPropertyRule,
+ Servo_PropertyRule_AddRef,
+ Servo_PropertyRule_Release
+);
+impl_locked_arc_ffi!(
SupportsRule,
LockedSupportsRule,
Servo_SupportsRule_AddRef,
diff --git a/components/style/invalidation/stylesheets.rs b/components/style/invalidation/stylesheets.rs
index f18fe7942c5..5fc8ec4b764 100644
--- a/components/style/invalidation/stylesheets.rs
+++ b/components/style/invalidation/stylesheets.rs
@@ -550,6 +550,7 @@ impl StylesheetInvalidationSet {
},
CounterStyle(..) |
Page(..) |
+ Property(..) |
Viewport(..) |
FontFeatureValues(..) |
FontPaletteValues(..) |
@@ -633,7 +634,11 @@ impl StylesheetInvalidationSet {
// existing elements.
}
},
- CounterStyle(..) | Page(..) | Viewport(..) | FontFeatureValues(..) |
+ CounterStyle(..) |
+ Page(..) |
+ Property(..) |
+ Viewport(..) |
+ FontFeatureValues(..) |
FontPaletteValues(..) => {
debug!(
" > Found unsupported rule, marking the whole subtree \
diff --git a/components/style/properties_and_values/mod.rs b/components/style/properties_and_values/mod.rs
index 3590d1279cc..00f7ac98f75 100644
--- a/components/style/properties_and_values/mod.rs
+++ b/components/style/properties_and_values/mod.rs
@@ -6,4 +6,5 @@
//!
//! https://drafts.css-houdini.org/css-properties-values-api-1/
+pub mod rule;
pub mod syntax;
diff --git a/components/style/properties_and_values/rule.rs b/components/style/properties_and_values/rule.rs
new file mode 100644
index 00000000000..3392e68124b
--- /dev/null
+++ b/components/style/properties_and_values/rule.rs
@@ -0,0 +1,245 @@
+/* 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/. */
+
+//! The [`@property`] at-rule.
+//!
+//! https://drafts.css-houdini.org/css-properties-values-api-1/#at-property-rule
+
+use crate::custom_properties::{Name as CustomPropertyName, SpecifiedValue};
+use crate::error_reporting::ContextualParseError;
+use crate::parser::{Parse, ParserContext};
+use crate::properties_and_values::syntax::Descriptor as SyntaxDescriptor;
+use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
+use crate::str::CssStringWriter;
+use crate::values::serialize_atom_name;
+use cssparser::{
+ AtRuleParser, CowRcStr, DeclarationParser, ParseErrorKind, Parser, QualifiedRuleParser,
+ RuleBodyItemParser, RuleBodyParser, SourceLocation,
+};
+use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
+use selectors::parser::SelectorParseErrorKind;
+use servo_arc::Arc;
+use std::fmt::{self, Write};
+use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
+use to_shmem::{SharedMemoryBuilder, ToShmem};
+
+/// Parse the block inside a `@property` rule.
+///
+/// Valid `@property` rules result in a registered custom property, as if `registerProperty()` had
+/// been called with equivalent parameters.
+pub fn parse_property_block(
+ context: &ParserContext,
+ input: &mut Parser,
+ name: PropertyRuleName,
+ location: SourceLocation,
+) -> PropertyRuleData {
+ let mut rule = PropertyRuleData::empty(name, location);
+ let mut parser = PropertyRuleParser {
+ context,
+ rule: &mut rule,
+ };
+ let mut iter = RuleBodyParser::new(input, &mut parser);
+ while let Some(declaration) = iter.next() {
+ if !context.error_reporting_enabled() {
+ continue;
+ }
+ if let Err((error, slice)) = declaration {
+ let location = error.location;
+ let error = if matches!(
+ error.kind,
+ ParseErrorKind::Custom(StyleParseErrorKind::PropertySyntaxField(_))
+ ) {
+ ContextualParseError::UnsupportedValue(slice, error)
+ } else {
+ ContextualParseError::UnsupportedPropertyDescriptor(slice, error)
+ };
+ context.log_css_error(location, error);
+ }
+ }
+ rule
+}
+
+struct PropertyRuleParser<'a, 'b: 'a> {
+ context: &'a ParserContext<'b>,
+ rule: &'a mut PropertyRuleData,
+}
+
+/// Default methods reject all at rules.
+impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyRuleParser<'a, 'b> {
+ type Prelude = ();
+ type AtRule = ();
+ type Error = StyleParseErrorKind<'i>;
+}
+
+impl<'a, 'b, 'i> QualifiedRuleParser<'i> for PropertyRuleParser<'a, 'b> {
+ type Prelude = ();
+ type QualifiedRule = ();
+ type Error = StyleParseErrorKind<'i>;
+}
+
+impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>>
+ for PropertyRuleParser<'a, 'b>
+{
+ fn parse_qualified(&self) -> bool {
+ false
+ }
+ fn parse_declarations(&self) -> bool {
+ true
+ }
+}
+
+macro_rules! property_descriptors {
+ (
+ $( #[$doc: meta] $name: tt $ident: ident: $ty: ty, )*
+ ) => {
+ /// Data inside a `@property` rule.
+ ///
+ /// <https://drafts.css-houdini.org/css-properties-values-api-1/#at-property-rule>
+ #[derive(Clone, Debug, PartialEq)]
+ pub struct PropertyRuleData {
+ /// The custom property name.
+ pub name: PropertyRuleName,
+
+ $(
+ #[$doc]
+ pub $ident: Option<$ty>,
+ )*
+
+ /// Line and column of the @property rule source code.
+ pub source_location: SourceLocation,
+ }
+
+ impl PropertyRuleData {
+ /// Create an empty property rule
+ pub fn empty(name: PropertyRuleName, source_location: SourceLocation) -> Self {
+ PropertyRuleData {
+ name,
+ $(
+ $ident: None,
+ )*
+ source_location,
+ }
+ }
+
+ /// Serialization of declarations in PropertyRuleData
+ pub fn decl_to_css(&self, dest: &mut CssStringWriter) -> fmt::Result {
+ $(
+ if let Some(ref value) = self.$ident {
+ dest.write_str(concat!($name, ": "))?;
+ value.to_css(&mut CssWriter::new(dest))?;
+ dest.write_str("; ")?;
+ }
+ )*
+ Ok(())
+ }
+ }
+
+ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyRuleParser<'a, 'b> {
+ type Declaration = ();
+ type Error = StyleParseErrorKind<'i>;
+
+ fn parse_value<'t>(
+ &mut self,
+ name: CowRcStr<'i>,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<(), ParseError<'i>> {
+ match_ignore_ascii_case! { &*name,
+ $(
+ $name => {
+ // DeclarationParser also calls parse_entirely so we’d normally not need
+ // to, but in this case we do because we set the value as a side effect
+ // rather than returning it.
+ let value = input.parse_entirely(|i| Parse::parse(self.context, i))?;
+ self.rule.$ident = Some(value)
+ },
+ )*
+ _ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))),
+ }
+ Ok(())
+ }
+ }
+ }
+}
+
+#[cfg(feature = "gecko")]
+property_descriptors! {
+ /// <https://drafts.css-houdini.org/css-properties-values-api-1/#the-syntax-descriptor>
+ "syntax" syntax: SyntaxDescriptor,
+
+ /// <https://drafts.css-houdini.org/css-properties-values-api-1/#inherits-descriptor>
+ "inherits" inherits: Inherits,
+
+ /// <https://drafts.css-houdini.org/css-properties-values-api-1/#initial-value-descriptor>
+ "initial-value" initial_value: InitialValue,
+}
+
+impl PropertyRuleData {
+ /// Measure heap usage.
+ #[cfg(feature = "gecko")]
+ pub fn size_of(&self, _guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
+ self.name.0.size_of(ops) +
+ self.syntax.size_of(ops) +
+ self.inherits.size_of(ops) +
+ if let Some(ref initial_value) = self.initial_value {
+ initial_value.size_of(ops)
+ } else {
+ 0
+ }
+ }
+}
+
+impl ToCssWithGuard for PropertyRuleData {
+ /// <https://drafts.css-houdini.org/css-properties-values-api-1/#serialize-a-csspropertyrule>
+ fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
+ dest.write_str("@property ")?;
+ self.name.to_css(&mut CssWriter::new(dest))?;
+ dest.write_str(" { ")?;
+ self.decl_to_css(dest)?;
+ dest.write_char('}')
+ }
+}
+
+impl ToShmem for PropertyRuleData {
+ fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
+ Err(String::from(
+ "ToShmem failed for PropertyRule: cannot handle @property rules",
+ ))
+ }
+}
+
+/// A custom property name wrapper that includes the `--` prefix in its serialization
+#[derive(Clone, Debug, PartialEq)]
+pub struct PropertyRuleName(pub Arc<CustomPropertyName>);
+
+impl ToCss for PropertyRuleName {
+ fn to_css<W: Write>(&self, dest: &mut CssWriter<W>) -> fmt::Result {
+ dest.write_str("--")?;
+ serialize_atom_name(&self.0, dest)
+ }
+}
+
+/// <https://drafts.css-houdini.org/css-properties-values-api-1/#inherits-descriptor>
+#[derive(Clone, Debug, MallocSizeOf, Parse, PartialEq, ToCss)]
+pub enum Inherits {
+ /// `true` value for the `inherits` descriptor
+ True,
+ /// `false` value for the `inherits` descriptor
+ False,
+}
+
+/// Specifies the initial value of the custom property registration represented by the @property
+/// rule, controlling the property’s initial value.
+///
+/// The SpecifiedValue is wrapped in an Arc to avoid copying when using it.
+pub type InitialValue = Arc<SpecifiedValue>;
+
+impl Parse for InitialValue {
+ fn parse<'i, 't>(
+ _context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ input.skip_whitespace();
+ SpecifiedValue::parse(input)
+ }
+}
diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs
index 4c6027219ba..c5d2ec8b8e8 100644
--- a/components/style/stylesheets/mod.rs
+++ b/components/style/stylesheets/mod.rs
@@ -19,6 +19,7 @@ mod media_rule;
mod namespace_rule;
pub mod origin;
mod page_rule;
+mod property_rule;
mod rule_list;
mod rule_parser;
mod rules_iterator;
@@ -61,6 +62,7 @@ pub use self::media_rule::MediaRule;
pub use self::namespace_rule::NamespaceRule;
pub use self::origin::{Origin, OriginSet, OriginSetIterator, PerOrigin, PerOriginIter};
pub use self::page_rule::{PageRule, PageSelector, PageSelectors};
+pub use self::property_rule::PropertyRule;
pub use self::rule_list::{CssRules, CssRulesHelpers};
pub use self::rule_parser::{InsertRuleContext, State, TopLevelRuleParser};
pub use self::rules_iterator::{AllRules, EffectiveRules};
@@ -261,6 +263,7 @@ pub enum CssRule {
Keyframes(Arc<Locked<KeyframesRule>>),
Supports(Arc<Locked<SupportsRule>>),
Page(Arc<Locked<PageRule>>),
+ Property(Arc<Locked<PropertyRule>>),
Document(Arc<Locked<DocumentRule>>),
LayerBlock(Arc<Locked<LayerBlockRule>>),
LayerStatement(Arc<Locked<LayerStatementRule>>),
@@ -306,6 +309,10 @@ impl CssRule {
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
},
+ CssRule::Property(ref lock) => {
+ lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
+ },
+
CssRule::Document(ref lock) => {
lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops)
},
@@ -350,6 +357,8 @@ pub enum CssRuleType {
LayerStatement = 17,
Container = 18,
FontPaletteValues = 19,
+ // 20 is an arbitrary number to use for Property.
+ Property = 20,
}
impl CssRuleType {
@@ -413,6 +422,7 @@ impl CssRule {
CssRule::Viewport(_) => CssRuleType::Viewport,
CssRule::Supports(_) => CssRuleType::Supports,
CssRule::Page(_) => CssRuleType::Page,
+ CssRule::Property(_) => CssRuleType::Property,
CssRule::Document(_) => CssRuleType::Document,
CssRule::LayerBlock(_) => CssRuleType::LayerBlock,
CssRule::LayerStatement(_) => CssRuleType::LayerStatement,
@@ -545,6 +555,10 @@ impl DeepCloneWithLock for CssRule {
lock.wrap(rule.deep_clone_with_lock(lock, guard, params)),
))
},
+ CssRule::Property(ref arc) => {
+ let rule = arc.read_with(guard);
+ CssRule::Property(Arc::new(lock.wrap(rule.clone())))
+ },
CssRule::Document(ref arc) => {
let rule = arc.read_with(guard);
CssRule::Document(Arc::new(
@@ -583,6 +597,7 @@ impl ToCssWithGuard for CssRule {
CssRule::Media(ref lock) => lock.read_with(guard).to_css(guard, dest),
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::Property(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Document(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::LayerBlock(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::LayerStatement(ref lock) => lock.read_with(guard).to_css(guard, dest),
diff --git a/components/style/stylesheets/property_rule.rs b/components/style/stylesheets/property_rule.rs
new file mode 100644
index 00000000000..1d1c1c982e9
--- /dev/null
+++ b/components/style/stylesheets/property_rule.rs
@@ -0,0 +1,5 @@
+/* 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/. */
+
+pub use crate::properties_and_values::rule::PropertyRuleData as PropertyRule;
diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs
index 1e51e2b65b9..f1bd4c13fe0 100644
--- a/components/style/stylesheets/rule_parser.rs
+++ b/components/style/stylesheets/rule_parser.rs
@@ -5,6 +5,7 @@
//! Parsing of the stylesheet contents.
use crate::counter_style::{parse_counter_style_body, parse_counter_style_name_definition};
+use crate::custom_properties::parse_name as parse_custom_property_name;
use crate::error_reporting::ContextualParseError;
use crate::font_face::parse_font_face_block;
use crate::media_queries::MediaList;
@@ -12,6 +13,7 @@ use crate::parser::{Parse, ParserContext};
use crate::properties::declaration_block::{
parse_property_declaration_list, DeclarationParserState, PropertyDeclarationBlock,
};
+use crate::properties_and_values::rule::{parse_property_block, PropertyRuleName};
use crate::selector_parser::{SelectorImpl, SelectorParser};
use crate::shared_lock::{Locked, SharedRwLock};
use crate::str::starts_with_ignore_ascii_case;
@@ -30,7 +32,7 @@ use crate::stylesheets::{
};
use crate::values::computed::font::FamilyName;
use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName};
-use crate::{Namespace, Prefix};
+use crate::{Atom, Namespace, Prefix};
use cssparser::{
AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr, DeclarationParser, Parser,
ParserState, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation,
@@ -201,6 +203,8 @@ pub enum AtRulePrelude {
Keyframes(KeyframesName, Option<VendorPrefix>),
/// A @page rule prelude, with its page name if it exists.
Page(PageSelectors),
+ /// A @property rule prelude.
+ Property(PropertyRuleName),
/// A @document rule, with its conditional.
Document(DocumentCondition),
/// A @import rule prelude.
@@ -600,6 +604,13 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b, 'i> {
input.try_parse(|i| PageSelectors::parse(self.context, i)).unwrap_or_default()
)
},
+ "property" if static_prefs::pref!("layout.css.properties-and-values.enabled") => {
+ let name = input.expect_ident_cloned()?;
+ let name = parse_custom_property_name(&name).map_err(|_| {
+ input.new_custom_error(StyleParseErrorKind::UnexpectedIdent(name.clone()))
+ })?;
+ AtRulePrelude::Property(PropertyRuleName(Arc::new(Atom::from(name))))
+ },
"-moz-document" if cfg!(feature = "gecko") => {
let cond = DocumentCondition::parse(self.context, input)?;
AtRulePrelude::Document(cond)
@@ -704,6 +715,11 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b, 'i> {
source_location: start.source_location(),
})))
},
+ AtRulePrelude::Property(name) => self.nest_for_rule(CssRuleType::Property, |p| {
+ CssRule::Property(Arc::new(p.shared_lock.wrap(
+ parse_property_block(&p.context, input, name, start.source_location()),
+ )))
+ }),
AtRulePrelude::Document(condition) => {
if !cfg!(feature = "gecko") {
unreachable!()
diff --git a/components/style/stylesheets/rules_iterator.rs b/components/style/stylesheets/rules_iterator.rs
index 59736ab09e0..ec0ceb7398e 100644
--- a/components/style/stylesheets/rules_iterator.rs
+++ b/components/style/stylesheets/rules_iterator.rs
@@ -68,6 +68,7 @@ where
CssRule::Viewport(_) |
CssRule::Keyframes(_) |
CssRule::Page(_) |
+ CssRule::Property(_) |
CssRule::LayerStatement(_) |
CssRule::FontFeatureValues(_) |
CssRule::FontPaletteValues(_) => None,
diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs
index 2089468c3de..2ca75f3c86d 100644
--- a/components/style/stylesheets/stylesheet.rs
+++ b/components/style/stylesheets/stylesheet.rs
@@ -377,6 +377,7 @@ impl SanitizationKind {
CssRule::Keyframes(..) |
CssRule::Page(..) |
+ CssRule::Property(..) |
CssRule::FontFeatureValues(..) |
CssRule::FontPaletteValues(..) |
CssRule::Viewport(..) |
diff --git a/components/style/stylist.rs b/components/style/stylist.rs
index 8f90c09925d..04a6a27e920 100644
--- a/components/style/stylist.rs
+++ b/components/style/stylist.rs
@@ -2849,6 +2849,7 @@ impl CascadeData {
self.extra_data
.add_page(guard, rule, containing_rule_state.layer_id)?;
},
+ // TODO: Handle CssRule::Property
CssRule::Viewport(..) => {},
_ => {
handled = false;
@@ -3090,6 +3091,7 @@ impl CascadeData {
CssRule::Supports(..) |
CssRule::Keyframes(..) |
CssRule::Page(..) |
+ CssRule::Property(..) |
CssRule::Viewport(..) |
CssRule::Document(..) |
CssRule::LayerBlock(..) |