summaryrefslogtreecommitdiffstats
path: root/servo/components/style/stylesheets
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/stylesheets')
-rw-r--r--servo/components/style/stylesheets/container_rule.rs2
-rw-r--r--servo/components/style/stylesheets/import_rule.rs2
-rw-r--r--servo/components/style/stylesheets/mod.rs41
-rw-r--r--servo/components/style/stylesheets/page_rule.rs2
-rw-r--r--servo/components/style/stylesheets/rule_list.rs5
-rw-r--r--servo/components/style/stylesheets/rule_parser.rs71
-rw-r--r--servo/components/style/stylesheets/rules_iterator.rs2
-rw-r--r--servo/components/style/stylesheets/scope_rule.rs161
-rw-r--r--servo/components/style/stylesheets/starting_style_rule.rs57
-rw-r--r--servo/components/style/stylesheets/stylesheet.rs6
10 files changed, 327 insertions, 22 deletions
diff --git a/servo/components/style/stylesheets/container_rule.rs b/servo/components/style/stylesheets/container_rule.rs
index 28c387fde2..77dfa0e179 100644
--- a/servo/components/style/stylesheets/container_rule.rs
+++ b/servo/components/style/stylesheets/container_rule.rs
@@ -11,7 +11,6 @@ use crate::dom::TElement;
use crate::logical_geometry::{LogicalSize, WritingMode};
use crate::parser::ParserContext;
use crate::properties::ComputedValues;
-use crate::queries::condition::KleeneValue;
use crate::queries::feature::{AllowsRanges, Evaluator, FeatureFlags, QueryFeatureDescription};
use crate::queries::values::Orientation;
use crate::queries::{FeatureType, QueryCondition};
@@ -31,6 +30,7 @@ use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use servo_arc::Arc;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss};
+use selectors::kleene_value::KleeneValue;
/// A container rule.
#[derive(Debug, ToShmem)]
diff --git a/servo/components/style/stylesheets/import_rule.rs b/servo/components/style/stylesheets/import_rule.rs
index e96134b436..d539471590 100644
--- a/servo/components/style/stylesheets/import_rule.rs
+++ b/servo/components/style/stylesheets/import_rule.rs
@@ -20,7 +20,7 @@ use crate::values::CssUrl;
use cssparser::{Parser, SourceLocation};
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
-use to_shmem::{self, SharedMemoryBuilder, ToShmem};
+use to_shmem::{SharedMemoryBuilder, ToShmem};
/// A sheet that is held from an import rule.
#[cfg(feature = "gecko")]
diff --git a/servo/components/style/stylesheets/mod.rs b/servo/components/style/stylesheets/mod.rs
index 2bf75565de..6bb8e19fb4 100644
--- a/servo/components/style/stylesheets/mod.rs
+++ b/servo/components/style/stylesheets/mod.rs
@@ -23,15 +23,17 @@ mod property_rule;
mod rule_list;
mod rule_parser;
mod rules_iterator;
+mod starting_style_rule;
mod style_rule;
mod stylesheet;
pub mod supports_rule;
+mod scope_rule;
#[cfg(feature = "gecko")]
use crate::gecko_bindings::sugar::refptr::RefCounted;
#[cfg(feature = "gecko")]
use crate::gecko_bindings::{bindings, structs};
-use crate::parser::ParserContext;
+use crate::parser::{NestingContext, ParserContext};
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use crate::str::CssStringWriter;
@@ -45,7 +47,7 @@ use std::fmt;
use std::mem::{self, ManuallyDrop};
use style_traits::ParsingMode;
#[cfg(feature = "gecko")]
-use to_shmem::{self, SharedMemoryBuilder, ToShmem};
+use to_shmem::{SharedMemoryBuilder, ToShmem};
pub use self::container_rule::ContainerRule;
pub use self::counter_style_rule::CounterStyleRule;
@@ -69,7 +71,9 @@ pub use self::rules_iterator::{AllRules, EffectiveRules};
pub use self::rules_iterator::{
EffectiveRulesIterator, NestedRuleIterationCondition, RulesIterator,
};
+pub use self::starting_style_rule::StartingStyleRule;
pub use self::style_rule::StyleRule;
+pub use self::scope_rule::ScopeRule;
pub use self::stylesheet::{AllowImportRules, SanitizationData, SanitizationKind};
pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet};
pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
@@ -132,7 +136,11 @@ impl Drop for UrlExtraData {
impl ToShmem for UrlExtraData {
fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
if self.0 & 1 == 0 {
- let shared_extra_datas = unsafe { &structs::URLExtraData_sShared };
+ let shared_extra_datas = unsafe {
+ std::ptr::addr_of!(structs::URLExtraData_sShared)
+ .as_ref()
+ .unwrap()
+ };
let self_ptr = self.as_ref() as *const _ as *mut _;
let sheet_id = shared_extra_datas
.iter()
@@ -265,6 +273,8 @@ pub enum CssRule {
Document(Arc<DocumentRule>),
LayerBlock(Arc<LayerBlockRule>),
LayerStatement(Arc<LayerStatementRule>),
+ Scope(Arc<ScopeRule>),
+ StartingStyle(Arc<StartingStyleRule>),
}
impl CssRule {
@@ -309,8 +319,14 @@ impl CssRule {
CssRule::Document(ref arc) => {
arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
},
+ CssRule::StartingStyle(ref arc) => {
+ arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
+ }
// TODO(emilio): Add memory reporting for these rules.
CssRule::LayerBlock(_) | CssRule::LayerStatement(_) => 0,
+ CssRule::Scope(ref rule) => {
+ rule.unconditional_shallow_size_of(ops) + rule.size_of(guard, ops)
+ }
}
}
}
@@ -349,6 +365,9 @@ pub enum CssRuleType {
FontPaletteValues = 19,
// 20 is an arbitrary number to use for Property.
Property = 20,
+ Scope = 21,
+ // https://drafts.csswg.org/css-transitions-2/#the-cssstartingstylerule-interface
+ StartingStyle = 22,
}
impl CssRuleType {
@@ -436,6 +455,8 @@ impl CssRule {
CssRule::LayerBlock(_) => CssRuleType::LayerBlock,
CssRule::LayerStatement(_) => CssRuleType::LayerStatement,
CssRule::Container(_) => CssRuleType::Container,
+ CssRule::Scope(_) => CssRuleType::Scope,
+ CssRule::StartingStyle(_) => CssRuleType::StartingStyle,
}
}
@@ -464,7 +485,11 @@ impl CssRule {
None,
None,
);
- context.rule_types = insert_rule_context.containing_rule_types;
+ // Override the nesting context with existing data.
+ context.nesting_context = NestingContext::new(
+ insert_rule_context.containing_rule_types,
+ insert_rule_context.parse_relative_rule_type
+ );
let state = if !insert_rule_context.containing_rule_types.is_empty() {
State::Body
@@ -567,6 +592,12 @@ impl DeepCloneWithLock for CssRule {
CssRule::LayerBlock(ref arc) => {
CssRule::LayerBlock(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
},
+ CssRule::Scope(ref arc) => {
+ CssRule::Scope(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
+ },
+ CssRule::StartingStyle(ref arc) => {
+ CssRule::StartingStyle(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
+ },
}
}
}
@@ -592,6 +623,8 @@ impl ToCssWithGuard for CssRule {
CssRule::LayerBlock(ref rule) => rule.to_css(guard, dest),
CssRule::LayerStatement(ref rule) => rule.to_css(guard, dest),
CssRule::Container(ref rule) => rule.to_css(guard, dest),
+ CssRule::Scope(ref rule) => rule.to_css(guard, dest),
+ CssRule::StartingStyle(ref rule) => rule.to_css(guard, dest),
}
}
}
diff --git a/servo/components/style/stylesheets/page_rule.rs b/servo/components/style/stylesheets/page_rule.rs
index a1618309a3..cdcfe0b8a7 100644
--- a/servo/components/style/stylesheets/page_rule.rs
+++ b/servo/components/style/stylesheets/page_rule.rs
@@ -221,7 +221,7 @@ impl Parse for PageSelector {
) -> Result<Self, ParseError<'i>> {
let name = input
.try_parse(parse_page_name)
- .unwrap_or(AtomIdent(atom!("")));
+ .unwrap_or(AtomIdent::new(atom!("")));
let mut pseudos = PagePseudoClasses::default();
while let Ok(pc) = input.try_parse(PagePseudoClass::parse) {
pseudos.push(pc);
diff --git a/servo/components/style/stylesheets/rule_list.rs b/servo/components/style/stylesheets/rule_list.rs
index 1b9f330185..9fb7629d3d 100644
--- a/servo/components/style/stylesheets/rule_list.rs
+++ b/servo/components/style/stylesheets/rule_list.rs
@@ -16,6 +16,8 @@ use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps};
use servo_arc::Arc;
use std::fmt::{self, Write};
+use super::CssRuleType;
+
/// A list of CSS rules.
#[derive(Debug, ToShmem)]
pub struct CssRules(pub Vec<CssRule>);
@@ -136,6 +138,7 @@ pub trait CssRulesHelpers {
parent_stylesheet_contents: &StylesheetContents,
index: usize,
nested: CssRuleTypes,
+ parse_relative_rule_type: Option<CssRuleType>,
loader: Option<&dyn StylesheetLoader>,
allow_import_rules: AllowImportRules,
) -> Result<CssRule, RulesMutateError>;
@@ -149,6 +152,7 @@ impl CssRulesHelpers for Locked<CssRules> {
parent_stylesheet_contents: &StylesheetContents,
index: usize,
containing_rule_types: CssRuleTypes,
+ parse_relative_rule_type: Option<CssRuleType>,
loader: Option<&dyn StylesheetLoader>,
allow_import_rules: AllowImportRules,
) -> Result<CssRule, RulesMutateError> {
@@ -165,6 +169,7 @@ impl CssRulesHelpers for Locked<CssRules> {
rule_list: &rules.0,
index,
containing_rule_types,
+ parse_relative_rule_type,
};
// Steps 3, 4, 5, 6
diff --git a/servo/components/style/stylesheets/rule_parser.rs b/servo/components/style/stylesheets/rule_parser.rs
index 742ad5d250..634f7c1af3 100644
--- a/servo/components/style/stylesheets/rule_parser.rs
+++ b/servo/components/style/stylesheets/rule_parser.rs
@@ -23,6 +23,8 @@ use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
use crate::stylesheets::import_rule::{ImportLayer, ImportRule, ImportSupportsCondition};
use crate::stylesheets::keyframes_rule::parse_keyframe_list;
use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule};
+use crate::stylesheets::scope_rule::{ScopeBounds, ScopeRule};
+use crate::stylesheets::starting_style_rule::StartingStyleRule;
use crate::stylesheets::supports_rule::SupportsCondition;
use crate::stylesheets::{
AllowImportRules, CorsMode, CssRule, CssRuleType, CssRuleTypes, CssRules, DocumentRule,
@@ -50,6 +52,8 @@ pub struct InsertRuleContext<'a> {
pub index: usize,
/// The containing rule types of our ancestors.
pub containing_rule_types: CssRuleTypes,
+ /// Rule type determining if and how we parse relative selector syntax.
+ pub parse_relative_rule_type: Option<CssRuleType>,
}
impl<'a> InsertRuleContext<'a> {
@@ -231,6 +235,10 @@ pub enum AtRulePrelude {
Namespace(Option<Prefix>, Namespace),
/// A @layer rule prelude.
Layer(Vec<LayerName>),
+ /// A @scope rule prelude.
+ Scope(ScopeBounds),
+ /// A @starting-style prelude.
+ StartingStyle,
}
impl AtRulePrelude {
@@ -251,6 +259,8 @@ impl AtRulePrelude {
Self::Margin(..) => "margin",
Self::Namespace(..) => "namespace",
Self::Layer(..) => "layer",
+ Self::Scope(..) => "scope",
+ Self::StartingStyle => "starting-style",
}
}
}
@@ -483,18 +493,29 @@ impl NestedParseResult {
impl<'a, 'i> NestedRuleParser<'a, 'i> {
#[inline]
fn in_style_rule(&self) -> bool {
- self.context.rule_types.contains(CssRuleType::Style)
+ self.context
+ .nesting_context
+ .rule_types
+ .contains(CssRuleType::Style)
}
#[inline]
fn in_page_rule(&self) -> bool {
- self.context.rule_types.contains(CssRuleType::Page)
+ self.context
+ .nesting_context
+ .rule_types
+ .contains(CssRuleType::Page)
}
#[inline]
fn in_style_or_page_rule(&self) -> bool {
let types = CssRuleTypes::from_bits(CssRuleType::Style.bit() | CssRuleType::Page.bit());
- self.context.rule_types.intersects(types)
+ self.context.nesting_context.rule_types.intersects(types)
+ }
+
+ #[inline]
+ fn parse_relative(&self) -> ParseRelative {
+ self.context.nesting_context.parse_relative
}
// https://drafts.csswg.org/css-nesting/#conditionals
@@ -507,7 +528,9 @@ impl<'a, 'i> NestedRuleParser<'a, 'i> {
AtRulePrelude::Supports(..) |
AtRulePrelude::Container(..) |
AtRulePrelude::Document(..) |
- AtRulePrelude::Layer(..) => true,
+ AtRulePrelude::Layer(..) |
+ AtRulePrelude::Scope(..) |
+ AtRulePrelude::StartingStyle => true,
AtRulePrelude::Namespace(..) |
AtRulePrelude::FontFace |
@@ -523,10 +546,9 @@ impl<'a, 'i> NestedRuleParser<'a, 'i> {
}
fn nest_for_rule<R>(&mut self, rule_type: CssRuleType, cb: impl FnOnce(&mut Self) -> R) -> R {
- let old_rule_types = self.context.rule_types;
- self.context.rule_types.insert(rule_type);
+ let old = self.context.nesting_context.save(rule_type);
let r = cb(self);
- self.context.rule_types = old_rule_types;
+ self.context.nesting_context.restore(old);
r
}
@@ -701,6 +723,13 @@ impl<'a, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'i> {
let cond = DocumentCondition::parse(&self.context, input)?;
AtRulePrelude::Document(cond)
},
+ "scope" if static_prefs::pref!("layout.css.at-scope.enabled") => {
+ let bounds = ScopeBounds::parse(&self.context, input, self.in_style_rule());
+ AtRulePrelude::Scope(bounds)
+ },
+ "starting-style" if static_prefs::pref!("layout.css.starting-style-at-rules.enabled") => {
+ AtRulePrelude::StartingStyle
+ },
_ => {
if static_prefs::pref!("layout.css.margin-rules.enabled") {
if let Some(margin_rule_type) = MarginRuleType::match_name(&name) {
@@ -862,11 +891,30 @@ impl<'a, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'i> {
block: Arc::new(self.shared_lock.wrap(declarations)),
source_location: start.source_location(),
}))
- }
+ },
AtRulePrelude::Import(..) | AtRulePrelude::Namespace(..) => {
// These rules don't have blocks.
return Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock));
},
+ AtRulePrelude::Scope(bounds) => {
+ let source_location = start.source_location();
+ CssRule::Scope(Arc::new(ScopeRule {
+ bounds,
+ rules: self
+ .parse_nested(input, CssRuleType::Scope)
+ .into_rules(self.shared_lock, source_location),
+ source_location,
+ }))
+ },
+ AtRulePrelude::StartingStyle => {
+ let source_location = start.source_location();
+ CssRule::StartingStyle(Arc::new(StartingStyleRule {
+ rules: self
+ .parse_nested(input, CssRuleType::StartingStyle)
+ .into_rules(self.shared_lock, source_location),
+ source_location,
+ }))
+ },
};
self.rules.push(rule);
Ok(())
@@ -913,12 +961,7 @@ impl<'a, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'i> {
url_data: self.context.url_data,
for_supports_rule: false,
};
- let parse_relative = if self.in_style_rule() {
- ParseRelative::ForNesting
- } else {
- ParseRelative::No
- };
- SelectorList::parse(&selector_parser, input, parse_relative)
+ SelectorList::parse(&selector_parser, input, self.parse_relative())
}
fn parse_block<'t>(
diff --git a/servo/components/style/stylesheets/rules_iterator.rs b/servo/components/style/stylesheets/rules_iterator.rs
index 76d41c8184..60f3df1ea9 100644
--- a/servo/components/style/stylesheets/rules_iterator.rs
+++ b/servo/components/style/stylesheets/rules_iterator.rs
@@ -116,6 +116,8 @@ where
Some(supports_rule.rules.read_with(guard).0.iter())
},
CssRule::LayerBlock(ref layer_rule) => Some(layer_rule.rules.read_with(guard).0.iter()),
+ CssRule::Scope(ref rule) => Some(rule.rules.read_with(guard).0.iter()),
+ CssRule::StartingStyle(ref rule) => Some(rule.rules.read_with(guard).0.iter()),
}
}
}
diff --git a/servo/components/style/stylesheets/scope_rule.rs b/servo/components/style/stylesheets/scope_rule.rs
new file mode 100644
index 0000000000..6816c433a7
--- /dev/null
+++ b/servo/components/style/stylesheets/scope_rule.rs
@@ -0,0 +1,161 @@
+/* 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 [`@scope`][scope] rule.
+//!
+//! [scope]: https://drafts.csswg.org/css-cascade-6/#scoped-styles
+
+use crate::parser::ParserContext;
+use crate::selector_parser::{SelectorImpl, SelectorParser};
+use crate::shared_lock::{
+ DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard,
+};
+use crate::str::CssStringWriter;
+use crate::stylesheets::CssRules;
+use cssparser::{Parser, SourceLocation, ToCss};
+#[cfg(feature = "gecko")]
+use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalSizeOf, MallocUnconditionalShallowSizeOf};
+use selectors::parser::{ParseRelative, SelectorList};
+use servo_arc::Arc;
+use std::fmt::{self, Write};
+use style_traits::CssWriter;
+
+/// A scoped rule.
+#[derive(Debug, ToShmem)]
+pub struct ScopeRule {
+ /// Bounds at which this rule applies.
+ pub bounds: ScopeBounds,
+ /// The nested rules inside the block.
+ pub rules: Arc<Locked<CssRules>>,
+ /// The source position where this rule was found.
+ pub source_location: SourceLocation,
+}
+
+impl DeepCloneWithLock for ScopeRule {
+ fn deep_clone_with_lock(
+ &self,
+ lock: &SharedRwLock,
+ guard: &SharedRwLockReadGuard,
+ params: &DeepCloneParams,
+ ) -> Self {
+ let rules = self.rules.read_with(guard);
+ Self {
+ bounds: self.bounds.clone(),
+ rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard, params))),
+ source_location: self.source_location.clone(),
+ }
+ }
+}
+
+impl ToCssWithGuard for ScopeRule {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
+ dest.write_str("@scope")?;
+ {
+ let mut writer = CssWriter::new(dest);
+ if let Some(start) = self.bounds.start.as_ref() {
+ writer.write_str(" (")?;
+ start.to_css(&mut writer)?;
+ writer.write_char(')')?;
+ }
+ if let Some(end) = self.bounds.end.as_ref() {
+ writer.write_str(" to (")?;
+ end.to_css(&mut writer)?;
+ writer.write_char(')')?;
+ }
+ }
+ self.rules.read_with(guard).to_css_block(guard, dest)
+ }
+}
+
+impl ScopeRule {
+ /// Measure heap usage.
+ #[cfg(feature = "gecko")]
+ pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
+ self.rules.unconditional_shallow_size_of(ops) +
+ self.rules.read_with(guard).size_of(guard, ops) +
+ self.bounds.size_of(ops)
+ }
+}
+
+/// Bounds of the scope.
+#[derive(Debug, Clone, ToShmem)]
+pub struct ScopeBounds {
+ /// Start of the scope.
+ pub start: Option<SelectorList<SelectorImpl>>,
+ /// End of the scope.
+ pub end: Option<SelectorList<SelectorImpl>>,
+}
+
+impl ScopeBounds {
+ #[cfg(feature = "gecko")]
+ fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+ fn bound_size_of(bound: &Option<SelectorList<SelectorImpl>>, ops: &mut MallocSizeOfOps) -> usize {
+ bound.as_ref().map(|list| list.unconditional_size_of(ops)).unwrap_or(0)
+ }
+ bound_size_of(&self.start, ops) + bound_size_of(&self.end, ops)
+ }
+}
+
+fn parse_scope<'a>(
+ context: &ParserContext,
+ input: &mut Parser<'a, '_>,
+ in_style_rule: bool,
+ for_end: bool
+) -> Option<SelectorList<SelectorImpl>> {
+ input.try_parse(|input| {
+ if for_end {
+ input.expect_ident_matching("to")?;
+ }
+ input.expect_parenthesis_block()?;
+ input.parse_nested_block(|input| {
+ if input.is_exhausted() {
+ return Ok(None);
+ }
+ let selector_parser = SelectorParser {
+ stylesheet_origin: context.stylesheet_origin,
+ namespaces: &context.namespaces,
+ url_data: context.url_data,
+ for_supports_rule: false,
+ };
+ let parse_relative = if for_end {
+ ParseRelative::ForScope
+ } else if in_style_rule {
+ ParseRelative::ForNesting
+ } else {
+ ParseRelative::No
+ };
+ Ok(Some(SelectorList::parse_forgiving(
+ &selector_parser,
+ input,
+ parse_relative,
+ )?))
+ })
+ })
+ .ok()
+ .flatten()
+}
+
+impl ScopeBounds {
+ /// Parse a container condition.
+ pub fn parse<'a>(
+ context: &ParserContext,
+ input: &mut Parser<'a, '_>,
+ in_style_rule: bool,
+ ) -> Self {
+ let start = parse_scope(
+ context,
+ input,
+ in_style_rule,
+ false
+ );
+
+ let end = parse_scope(
+ context,
+ input,
+ in_style_rule,
+ true
+ );
+ Self { start, end }
+ }
+}
diff --git a/servo/components/style/stylesheets/starting_style_rule.rs b/servo/components/style/stylesheets/starting_style_rule.rs
new file mode 100644
index 0000000000..3c2627582b
--- /dev/null
+++ b/servo/components/style/stylesheets/starting_style_rule.rs
@@ -0,0 +1,57 @@
+/* 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/. */
+
+//! before-change style: the `@starting-style` rules.
+//! https://drafts.csswg.org/css-transitions-2/#defining-before-change-style
+
+use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
+use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
+use crate::str::CssStringWriter;
+use crate::stylesheets::CssRules;
+use cssparser::SourceLocation;
+use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
+use servo_arc::Arc;
+use std::fmt::{self, Debug, Write};
+
+/// A [`@starting-style`][starting-style] rule.
+///
+/// [starting-style]: https://drafts.csswg.org/css-transitions-2/#at-ruledef-starting-style
+#[derive(Debug, ToShmem)]
+pub struct StartingStyleRule {
+ /// The nested rules to this starting-style rule.
+ pub rules: Arc<Locked<CssRules>>,
+ /// The source position where this starting-style rule was found.
+ pub source_location: SourceLocation,
+}
+
+impl StartingStyleRule {
+ /// Measure heap usage.
+ #[cfg(feature = "gecko")]
+ pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
+ self.rules.unconditional_shallow_size_of(ops) +
+ self.rules.read_with(guard).size_of(guard, ops)
+ }
+}
+
+impl ToCssWithGuard for StartingStyleRule {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
+ dest.write_str("@starting-style")?;
+ self.rules.read_with(guard).to_css_block(guard, dest)
+ }
+}
+
+impl DeepCloneWithLock for StartingStyleRule {
+ fn deep_clone_with_lock(
+ &self,
+ lock: &SharedRwLock,
+ guard: &SharedRwLockReadGuard,
+ params: &DeepCloneParams,
+ ) -> Self {
+ let rules = self.rules.read_with(guard);
+ StartingStyleRule {
+ rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard, params))),
+ source_location: self.source_location.clone(),
+ }
+ }
+}
diff --git a/servo/components/style/stylesheets/stylesheet.rs b/servo/components/style/stylesheets/stylesheet.rs
index 1604022871..84d84b0d46 100644
--- a/servo/components/style/stylesheets/stylesheet.rs
+++ b/servo/components/style/stylesheets/stylesheet.rs
@@ -333,7 +333,11 @@ impl SanitizationKind {
// TODO(emilio): Perhaps Layer should not be always sanitized? But
// we sanitize @media and co, so this seems safer for now.
CssRule::LayerStatement(..) |
- CssRule::LayerBlock(..) => false,
+ CssRule::LayerBlock(..) |
+ // TODO(dshin): Same comment as Layer applies - shouldn't give away
+ // something like display size - erring on the side of "safe" for now.
+ CssRule::Scope(..) |
+ CssRule::StartingStyle(..) => false,
CssRule::FontFace(..) | CssRule::Namespace(..) | CssRule::Style(..) => true,