tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

rule_list.rs (5222B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 //! A list of CSS rules.
      6 
      7 use crate::derives::*;
      8 use crate::shared_lock::{DeepCloneWithLock, Locked};
      9 use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
     10 use crate::stylesheets::loader::StylesheetLoader;
     11 use crate::stylesheets::rule_parser::InsertRuleContext;
     12 use crate::stylesheets::stylesheet::StylesheetContents;
     13 use crate::stylesheets::{AllowImportRules, CssRule, CssRuleTypes, RulesMutateError};
     14 #[cfg(feature = "gecko")]
     15 use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps};
     16 use servo_arc::Arc;
     17 use std::fmt::{self, Write};
     18 use style_traits::CssStringWriter;
     19 
     20 use super::CssRuleType;
     21 
     22 /// A list of CSS rules.
     23 #[derive(Debug, ToShmem)]
     24 pub struct CssRules(pub Vec<CssRule>);
     25 
     26 impl CssRules {
     27    /// Whether this CSS rules is empty.
     28    pub fn is_empty(&self) -> bool {
     29        self.0.is_empty()
     30    }
     31 }
     32 
     33 impl 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 
     44 impl CssRules {
     45    /// Measure heap usage.
     46    #[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    /// Trivially construct a new set of CSS rules.
     56    pub fn new(rules: Vec<CssRule>, shared_lock: &SharedRwLock) -> Arc<Locked<CssRules>> {
     57        Arc::new(shared_lock.wrap(CssRules(rules)))
     58    }
     59 
     60    /// Returns whether all the rules in this list are namespace or import
     61    /// rules.
     62    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    /// <https://drafts.csswg.org/cssom/#remove-a-css-rule>
     70    pub fn remove_rule(&mut self, index: usize) -> Result<(), RulesMutateError> {
     71        // Step 1, 2
     72        if index >= self.0.len() {
     73            return Err(RulesMutateError::IndexSize);
     74        }
     75 
     76        {
     77            // Step 3
     78            let ref rule = self.0[index];
     79 
     80            // Step 4
     81            if let CssRule::Namespace(..) = *rule {
     82                if !self.only_ns_or_import() {
     83                    return Err(RulesMutateError::InvalidState);
     84                }
     85            }
     86        }
     87 
     88        // Step 5, 6
     89        self.0.remove(index);
     90        Ok(())
     91    }
     92 
     93    /// Serializes this CSSRules to CSS text as a block of rules.
     94    ///
     95    /// This should be speced into CSSOM spec at some point. See
     96    /// <https://github.com/w3c/csswg-drafts/issues/1985>
     97    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    /// As above, but without the opening curly bracket. That's needed for nesting.
    107    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    /// Parses a rule for <https://drafts.csswg.org/cssom/#insert-a-css-rule>. Caller is
    126    /// responsible for calling insert() afterwards.
    127    ///
    128    /// Written in this funky way because parsing an @import rule may cause us
    129    /// to clone a stylesheet from the same document due to caching in the CSS
    130    /// loader.
    131    ///
    132    /// TODO(emilio): We could also pass the write guard down into the loader
    133    /// instead, but that seems overkill.
    134    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        // Step 1, 2
    146        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        // Steps 3, 4, 5, 6
    158        CssRule::parse(
    159            &rule,
    160            insert_rule_context,
    161            parent_stylesheet_contents,
    162            lock,
    163            loader,
    164            allow_import_rules,
    165        )
    166    }
    167 }