summaryrefslogtreecommitdiffstats
path: root/servo/components/style/stylesheets/scope_rule.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
commitd8bbc7858622b6d9c278469aab701ca0b609cddf (patch)
treeeff41dc61d9f714852212739e6b3738b82a2af87 /servo/components/style/stylesheets/scope_rule.rs
parentReleasing progress-linux version 125.0.3-1~progress7.99u1. (diff)
downloadfirefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz
firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'servo/components/style/stylesheets/scope_rule.rs')
-rw-r--r--servo/components/style/stylesheets/scope_rule.rs161
1 files changed, 161 insertions, 0 deletions
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 }
+ }
+}