style/stylesheets/
rule_list.rs1use crate::derives::*;
8use crate::shared_lock::{DeepCloneWithLock, Locked};
9use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
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};
18use style_traits::CssStringWriter;
19
20use super::CssRuleType;
21
22#[derive(Debug, ToShmem)]
24pub struct CssRules(pub Vec<CssRule>);
25
26impl CssRules {
27 pub fn is_empty(&self) -> bool {
29 self.0.is_empty()
30 }
31}
32
33impl DeepCloneWithLock for CssRules {
34 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self {
35 CssRules(
36 self.0
37 .iter()
38 .map(|x| x.deep_clone_with_lock(lock, guard))
39 .collect(),
40 )
41 }
42}
43
44impl CssRules {
45 #[cfg(feature = "gecko")]
47 pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
48 let mut n = self.0.shallow_size_of(ops);
49 for rule in self.0.iter() {
50 n += rule.size_of(guard, ops);
51 }
52 n
53 }
54
55 pub fn new(rules: Vec<CssRule>, shared_lock: &SharedRwLock) -> Arc<Locked<CssRules>> {
57 Arc::new(shared_lock.wrap(CssRules(rules)))
58 }
59
60 fn only_ns_or_import(&self) -> bool {
63 self.0.iter().all(|r| match *r {
64 CssRule::Namespace(..) | CssRule::Import(..) => true,
65 _ => false,
66 })
67 }
68
69 pub fn remove_rule(&mut self, index: usize) -> Result<(), RulesMutateError> {
71 if index >= self.0.len() {
73 return Err(RulesMutateError::IndexSize);
74 }
75
76 {
77 let ref rule = self.0[index];
79
80 if let CssRule::Namespace(..) = *rule {
82 if !self.only_ns_or_import() {
83 return Err(RulesMutateError::InvalidState);
84 }
85 }
86 }
87
88 self.0.remove(index);
90 Ok(())
91 }
92
93 pub fn to_css_block(
98 &self,
99 guard: &SharedRwLockReadGuard,
100 dest: &mut CssStringWriter,
101 ) -> fmt::Result {
102 dest.write_str(" {")?;
103 self.to_css_block_without_opening(guard, dest)
104 }
105
106 pub fn to_css_block_without_opening(
108 &self,
109 guard: &SharedRwLockReadGuard,
110 dest: &mut CssStringWriter,
111 ) -> fmt::Result {
112 for rule in self.0.iter() {
113 if rule.is_empty_nested_declarations(guard) {
114 continue;
115 }
116
117 dest.write_str("\n ")?;
118 let old_len = dest.len();
119 rule.to_css(guard, dest)?;
120 debug_assert_ne!(old_len, dest.len());
121 }
122 dest.write_str("\n}")
123 }
124
125 pub fn parse_rule_for_insert(
135 &self,
136 lock: &SharedRwLock,
137 rule: &str,
138 parent_stylesheet_contents: &StylesheetContents,
139 index: usize,
140 containing_rule_types: CssRuleTypes,
141 parse_relative_rule_type: Option<CssRuleType>,
142 loader: Option<&dyn StylesheetLoader>,
143 allow_import_rules: AllowImportRules,
144 ) -> Result<CssRule, RulesMutateError> {
145 if index > self.0.len() {
147 return Err(RulesMutateError::IndexSize);
148 }
149
150 let insert_rule_context = InsertRuleContext {
151 rule_list: &self.0,
152 index,
153 containing_rule_types,
154 parse_relative_rule_type,
155 };
156
157 CssRule::parse(
159 &rule,
160 insert_rule_context,
161 parent_stylesheet_contents,
162 lock,
163 loader,
164 allow_import_rules,
165 )
166 }
167}