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}