style/stylesheets/
rule_list.rs1use crate::shared_lock::{DeepCloneWithLock, Locked};
8use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
9use crate::str::CssStringWriter;
10use crate::stylesheets::loader::StylesheetLoader;
11use crate::stylesheets::rule_parser::InsertRuleContext;
12use crate::stylesheets::stylesheet::StylesheetContents;
13use crate::stylesheets::{AllowImportRules, CssRule, CssRuleTypes, RulesMutateError};
14#[cfg(feature = "gecko")]
15use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps};
16use servo_arc::Arc;
17use std::fmt::{self, Write};
18
19use super::CssRuleType;
20
21#[derive(Debug, ToShmem)]
23pub struct CssRules(pub Vec<CssRule>);
24
25impl CssRules {
26 pub fn is_empty(&self) -> bool {
28 self.0.is_empty()
29 }
30}
31
32impl DeepCloneWithLock for CssRules {
33 fn deep_clone_with_lock(
34 &self,
35 lock: &SharedRwLock,
36 guard: &SharedRwLockReadGuard,
37 ) -> Self {
38 CssRules(
39 self.0
40 .iter()
41 .map(|x| x.deep_clone_with_lock(lock, guard))
42 .collect(),
43 )
44 }
45}
46
47impl CssRules {
48 #[cfg(feature = "gecko")]
50 pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
51 let mut n = self.0.shallow_size_of(ops);
52 for rule in self.0.iter() {
53 n += rule.size_of(guard, ops);
54 }
55 n
56 }
57
58 pub fn new(rules: Vec<CssRule>, shared_lock: &SharedRwLock) -> Arc<Locked<CssRules>> {
60 Arc::new(shared_lock.wrap(CssRules(rules)))
61 }
62
63 fn only_ns_or_import(&self) -> bool {
66 self.0.iter().all(|r| match *r {
67 CssRule::Namespace(..) | CssRule::Import(..) => true,
68 _ => false,
69 })
70 }
71
72 pub fn remove_rule(&mut self, index: usize) -> Result<(), RulesMutateError> {
74 if index >= self.0.len() {
76 return Err(RulesMutateError::IndexSize);
77 }
78
79 {
80 let ref rule = self.0[index];
82
83 if let CssRule::Namespace(..) = *rule {
85 if !self.only_ns_or_import() {
86 return Err(RulesMutateError::InvalidState);
87 }
88 }
89 }
90
91 self.0.remove(index);
93 Ok(())
94 }
95
96 pub fn to_css_block(
101 &self,
102 guard: &SharedRwLockReadGuard,
103 dest: &mut CssStringWriter,
104 ) -> fmt::Result {
105 dest.write_str(" {")?;
106 self.to_css_block_without_opening(guard, dest)
107 }
108
109 pub fn to_css_block_without_opening(
111 &self,
112 guard: &SharedRwLockReadGuard,
113 dest: &mut CssStringWriter,
114 ) -> fmt::Result {
115 for rule in self.0.iter() {
116 if rule.is_empty_nested_declarations(guard) {
117 continue;
118 }
119
120 dest.write_str("\n ")?;
121 let old_len = dest.len();
122 rule.to_css(guard, dest)?;
123 debug_assert_ne!(old_len, dest.len());
124 }
125 dest.write_str("\n}")
126 }
127}
128
129pub trait CssRulesHelpers {
131 fn insert_rule(
140 &self,
141 lock: &SharedRwLock,
142 rule: &str,
143 parent_stylesheet_contents: &StylesheetContents,
144 index: usize,
145 nested: CssRuleTypes,
146 parse_relative_rule_type: Option<CssRuleType>,
147 loader: Option<&dyn StylesheetLoader>,
148 allow_import_rules: AllowImportRules,
149 ) -> Result<CssRule, RulesMutateError>;
150}
151
152impl CssRulesHelpers for Locked<CssRules> {
153 fn insert_rule(
154 &self,
155 lock: &SharedRwLock,
156 rule: &str,
157 parent_stylesheet_contents: &StylesheetContents,
158 index: usize,
159 containing_rule_types: CssRuleTypes,
160 parse_relative_rule_type: Option<CssRuleType>,
161 loader: Option<&dyn StylesheetLoader>,
162 allow_import_rules: AllowImportRules,
163 ) -> Result<CssRule, RulesMutateError> {
164 let new_rule = {
165 let read_guard = lock.read();
166 let rules = self.read_with(&read_guard);
167
168 if index > rules.0.len() {
170 return Err(RulesMutateError::IndexSize);
171 }
172
173 let insert_rule_context = InsertRuleContext {
174 rule_list: &rules.0,
175 index,
176 containing_rule_types,
177 parse_relative_rule_type,
178 };
179
180 CssRule::parse(
182 &rule,
183 insert_rule_context,
184 parent_stylesheet_contents,
185 lock,
186 loader,
187 allow_import_rules,
188 )?
189 };
190
191 {
192 let mut write_guard = lock.write();
193 let rules = self.write_with(&mut write_guard);
194 rules.0.insert(index, new_rule.clone());
195 }
196
197 Ok(new_rule)
198 }
199}