style/stylesheets/
rule_list.rs1use crate::shared_lock::{DeepCloneWithLock, Locked};
8use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
9use crate::stylesheets::loader::StylesheetLoader;
10use crate::stylesheets::rule_parser::InsertRuleContext;
11use crate::stylesheets::stylesheet::StylesheetContents;
12use crate::stylesheets::{AllowImportRules, CssRule, CssRuleTypes, RulesMutateError};
13#[cfg(feature = "gecko")]
14use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps};
15use servo_arc::Arc;
16use std::fmt::{self, Write};
17use style_traits::CssStringWriter;
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(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self {
34 CssRules(
35 self.0
36 .iter()
37 .map(|x| x.deep_clone_with_lock(lock, guard))
38 .collect(),
39 )
40 }
41}
42
43impl CssRules {
44 #[cfg(feature = "gecko")]
46 pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
47 let mut n = self.0.shallow_size_of(ops);
48 for rule in self.0.iter() {
49 n += rule.size_of(guard, ops);
50 }
51 n
52 }
53
54 pub fn new(rules: Vec<CssRule>, shared_lock: &SharedRwLock) -> Arc<Locked<CssRules>> {
56 Arc::new(shared_lock.wrap(CssRules(rules)))
57 }
58
59 fn only_ns_or_import(&self) -> bool {
62 self.0.iter().all(|r| match *r {
63 CssRule::Namespace(..) | CssRule::Import(..) => true,
64 _ => false,
65 })
66 }
67
68 pub fn remove_rule(&mut self, index: usize) -> Result<(), RulesMutateError> {
70 if index >= self.0.len() {
72 return Err(RulesMutateError::IndexSize);
73 }
74
75 {
76 let ref rule = self.0[index];
78
79 if let CssRule::Namespace(..) = *rule {
81 if !self.only_ns_or_import() {
82 return Err(RulesMutateError::InvalidState);
83 }
84 }
85 }
86
87 self.0.remove(index);
89 Ok(())
90 }
91
92 pub fn to_css_block(
97 &self,
98 guard: &SharedRwLockReadGuard,
99 dest: &mut CssStringWriter,
100 ) -> fmt::Result {
101 dest.write_str(" {")?;
102 self.to_css_block_without_opening(guard, dest)
103 }
104
105 pub fn to_css_block_without_opening(
107 &self,
108 guard: &SharedRwLockReadGuard,
109 dest: &mut CssStringWriter,
110 ) -> fmt::Result {
111 for rule in self.0.iter() {
112 if rule.is_empty_nested_declarations(guard) {
113 continue;
114 }
115
116 dest.write_str("\n ")?;
117 let old_len = dest.len();
118 rule.to_css(guard, dest)?;
119 debug_assert_ne!(old_len, dest.len());
120 }
121 dest.write_str("\n}")
122 }
123
124 pub fn parse_rule_for_insert(
134 &self,
135 lock: &SharedRwLock,
136 rule: &str,
137 parent_stylesheet_contents: &StylesheetContents,
138 index: usize,
139 containing_rule_types: CssRuleTypes,
140 parse_relative_rule_type: Option<CssRuleType>,
141 loader: Option<&dyn StylesheetLoader>,
142 allow_import_rules: AllowImportRules,
143 ) -> Result<CssRule, RulesMutateError> {
144 if index > self.0.len() {
146 return Err(RulesMutateError::IndexSize);
147 }
148
149 let insert_rule_context = InsertRuleContext {
150 rule_list: &self.0,
151 index,
152 containing_rule_types,
153 parse_relative_rule_type,
154 };
155
156 CssRule::parse(
158 &rule,
159 insert_rule_context,
160 parent_stylesheet_contents,
161 lock,
162 loader,
163 allow_import_rules,
164 )
165 }
166}