From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- servo/components/style/stylesheets/rule_list.rs | 189 ++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 servo/components/style/stylesheets/rule_list.rs (limited to 'servo/components/style/stylesheets/rule_list.rs') diff --git a/servo/components/style/stylesheets/rule_list.rs b/servo/components/style/stylesheets/rule_list.rs new file mode 100644 index 0000000000..1b9f330185 --- /dev/null +++ b/servo/components/style/stylesheets/rule_list.rs @@ -0,0 +1,189 @@ +/* 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 list of CSS rules. + +use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked}; +use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; +use crate::str::CssStringWriter; +use crate::stylesheets::loader::StylesheetLoader; +use crate::stylesheets::rule_parser::InsertRuleContext; +use crate::stylesheets::stylesheet::StylesheetContents; +use crate::stylesheets::{AllowImportRules, CssRule, CssRuleTypes, RulesMutateError}; +#[cfg(feature = "gecko")] +use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps}; +use servo_arc::Arc; +use std::fmt::{self, Write}; + +/// A list of CSS rules. +#[derive(Debug, ToShmem)] +pub struct CssRules(pub Vec); + +impl CssRules { + /// Whether this CSS rules is empty. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl DeepCloneWithLock for CssRules { + fn deep_clone_with_lock( + &self, + lock: &SharedRwLock, + guard: &SharedRwLockReadGuard, + params: &DeepCloneParams, + ) -> Self { + CssRules( + self.0 + .iter() + .map(|x| x.deep_clone_with_lock(lock, guard, params)) + .collect(), + ) + } +} + +impl CssRules { + /// Measure heap usage. + #[cfg(feature = "gecko")] + pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.0.shallow_size_of(ops); + for rule in self.0.iter() { + n += rule.size_of(guard, ops); + } + n + } + + /// Trivially construct a new set of CSS rules. + pub fn new(rules: Vec, shared_lock: &SharedRwLock) -> Arc> { + Arc::new(shared_lock.wrap(CssRules(rules))) + } + + /// Returns whether all the rules in this list are namespace or import + /// rules. + fn only_ns_or_import(&self) -> bool { + self.0.iter().all(|r| match *r { + CssRule::Namespace(..) | CssRule::Import(..) => true, + _ => false, + }) + } + + /// + pub fn remove_rule(&mut self, index: usize) -> Result<(), RulesMutateError> { + // Step 1, 2 + if index >= self.0.len() { + return Err(RulesMutateError::IndexSize); + } + + { + // Step 3 + let ref rule = self.0[index]; + + // Step 4 + if let CssRule::Namespace(..) = *rule { + if !self.only_ns_or_import() { + return Err(RulesMutateError::InvalidState); + } + } + } + + // Step 5, 6 + self.0.remove(index); + Ok(()) + } + + /// Serializes this CSSRules to CSS text as a block of rules. + /// + /// This should be speced into CSSOM spec at some point. See + /// + pub fn to_css_block( + &self, + guard: &SharedRwLockReadGuard, + dest: &mut CssStringWriter, + ) -> fmt::Result { + dest.write_str(" {")?; + self.to_css_block_without_opening(guard, dest) + } + + /// As above, but without the opening curly bracket. That's needed for nesting. + pub fn to_css_block_without_opening( + &self, + guard: &SharedRwLockReadGuard, + dest: &mut CssStringWriter, + ) -> fmt::Result { + for rule in self.0.iter() { + dest.write_str("\n ")?; + rule.to_css(guard, dest)?; + } + dest.write_str("\n}") + } +} + +/// A trait to implement helpers for `Arc>`. +pub trait CssRulesHelpers { + /// + /// + /// Written in this funky way because parsing an @import rule may cause us + /// to clone a stylesheet from the same document due to caching in the CSS + /// loader. + /// + /// TODO(emilio): We could also pass the write guard down into the loader + /// instead, but that seems overkill. + fn insert_rule( + &self, + lock: &SharedRwLock, + rule: &str, + parent_stylesheet_contents: &StylesheetContents, + index: usize, + nested: CssRuleTypes, + loader: Option<&dyn StylesheetLoader>, + allow_import_rules: AllowImportRules, + ) -> Result; +} + +impl CssRulesHelpers for Locked { + fn insert_rule( + &self, + lock: &SharedRwLock, + rule: &str, + parent_stylesheet_contents: &StylesheetContents, + index: usize, + containing_rule_types: CssRuleTypes, + loader: Option<&dyn StylesheetLoader>, + allow_import_rules: AllowImportRules, + ) -> Result { + let new_rule = { + let read_guard = lock.read(); + let rules = self.read_with(&read_guard); + + // Step 1, 2 + if index > rules.0.len() { + return Err(RulesMutateError::IndexSize); + } + + let insert_rule_context = InsertRuleContext { + rule_list: &rules.0, + index, + containing_rule_types, + }; + + // Steps 3, 4, 5, 6 + CssRule::parse( + &rule, + insert_rule_context, + parent_stylesheet_contents, + lock, + loader, + allow_import_rules, + )? + }; + + { + let mut write_guard = lock.write(); + let rules = self.write_with(&mut write_guard); + rules.0.insert(index, new_rule.clone()); + } + + Ok(new_rule) + } +} -- cgit v1.2.3