tor-browser

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

layer_rule.rs (7033B)


      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 [`@layer`][layer] rule.
      6 //!
      7 //! [layer]: https://drafts.csswg.org/css-cascade-5/#layering
      8 
      9 use crate::derives::*;
     10 use crate::parser::{Parse, ParserContext};
     11 use crate::shared_lock::{DeepCloneWithLock, Locked};
     12 use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
     13 use crate::values::AtomIdent;
     14 
     15 use super::CssRules;
     16 
     17 use cssparser::{Parser, SourceLocation, Token};
     18 use servo_arc::Arc;
     19 use smallvec::SmallVec;
     20 use std::fmt::{self, Write};
     21 use style_traits::{CssWriter, ParseError, ToCss};
     22 
     23 /// The order of a given layer. We use 16 bits so that we can pack LayerOrder
     24 /// and CascadeLevel in a single 32-bit struct. If we need more bits we can go
     25 /// back to packing CascadeLevel in a single byte as we did before.
     26 #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord)]
     27 pub struct LayerOrder(u16);
     28 
     29 impl LayerOrder {
     30    /// The order of the root layer.
     31    pub const fn root() -> Self {
     32        Self(std::u16::MAX - 1)
     33    }
     34 
     35    /// The order of the style attribute layer.
     36    pub const fn style_attribute() -> Self {
     37        Self(std::u16::MAX)
     38    }
     39 
     40    /// Returns whether this layer is for the style attribute, which behaves
     41    /// differently in terms of !important, see
     42    /// https://github.com/w3c/csswg-drafts/issues/6872
     43    ///
     44    /// (This is a bit silly, mind-you, but it's needed so that revert-layer
     45    /// behaves correctly).
     46    #[inline]
     47    pub fn is_style_attribute_layer(&self) -> bool {
     48        *self == Self::style_attribute()
     49    }
     50 
     51    /// The first cascade layer order.
     52    pub const fn first() -> Self {
     53        Self(0)
     54    }
     55 
     56    /// Increment the cascade layer order.
     57    #[inline]
     58    pub fn inc(&mut self) {
     59        if self.0 != std::u16::MAX - 1 {
     60            self.0 += 1;
     61        }
     62    }
     63 }
     64 
     65 /// A `<layer-name>`: https://drafts.csswg.org/css-cascade-5/#typedef-layer-name
     66 #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)]
     67 pub struct LayerName(pub SmallVec<[AtomIdent; 1]>);
     68 
     69 impl LayerName {
     70    /// Returns an empty layer name (which isn't a valid final state, so caller
     71    /// is responsible to fill up the name before use).
     72    pub fn new_empty() -> Self {
     73        Self(Default::default())
     74    }
     75 
     76    /// Returns a synthesized name for an anonymous layer.
     77    pub fn new_anonymous() -> Self {
     78        use std::sync::atomic::{AtomicUsize, Ordering};
     79        static NEXT_ANONYMOUS_LAYER_NAME: AtomicUsize = AtomicUsize::new(0);
     80 
     81        let mut name = SmallVec::new();
     82        let next_id = NEXT_ANONYMOUS_LAYER_NAME.fetch_add(1, Ordering::Relaxed);
     83        // The parens don't _technically_ prevent conflicts with authors, as
     84        // authors could write escaped parens as part of the identifier, I
     85        // think, but highly reduces the possibility.
     86        name.push(AtomIdent::from(&*format!("-moz-anon-layer({})", next_id)));
     87 
     88        LayerName(name)
     89    }
     90 
     91    /// Returns the names of the layers. That is, for a layer like `foo.bar`,
     92    /// it'd return [foo, bar].
     93    pub fn layer_names(&self) -> &[AtomIdent] {
     94        &self.0
     95    }
     96 }
     97 
     98 impl Parse for LayerName {
     99    fn parse<'i, 't>(
    100        _: &ParserContext,
    101        input: &mut Parser<'i, 't>,
    102    ) -> Result<Self, ParseError<'i>> {
    103        let mut result = SmallVec::new();
    104        result.push(AtomIdent::from(&**input.expect_ident()?));
    105        loop {
    106            let next_name = input.try_parse(|input| -> Result<AtomIdent, ParseError<'i>> {
    107                match input.next_including_whitespace()? {
    108                    Token::Delim('.') => {},
    109                    other => {
    110                        let t = other.clone();
    111                        return Err(input.new_unexpected_token_error(t));
    112                    },
    113                }
    114 
    115                let name = match input.next_including_whitespace()? {
    116                    Token::Ident(ref ident) => ident,
    117                    other => {
    118                        let t = other.clone();
    119                        return Err(input.new_unexpected_token_error(t));
    120                    },
    121                };
    122 
    123                Ok(AtomIdent::from(&**name))
    124            });
    125 
    126            match next_name {
    127                Ok(name) => result.push(name),
    128                Err(..) => break,
    129            }
    130        }
    131        Ok(LayerName(result))
    132    }
    133 }
    134 
    135 impl ToCss for LayerName {
    136    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    137    where
    138        W: Write,
    139    {
    140        let mut first = true;
    141        for name in self.0.iter() {
    142            if !first {
    143                dest.write_char('.')?;
    144            }
    145            first = false;
    146            name.to_css(dest)?;
    147        }
    148        Ok(())
    149    }
    150 }
    151 
    152 #[derive(Debug, ToShmem)]
    153 /// A block `@layer <name>? { ... }`
    154 /// https://drafts.csswg.org/css-cascade-5/#layer-block
    155 pub struct LayerBlockRule {
    156    /// The layer name, or `None` if anonymous.
    157    pub name: Option<LayerName>,
    158    /// The nested rules.
    159    pub rules: Arc<Locked<CssRules>>,
    160    /// The source position where this rule was found.
    161    pub source_location: SourceLocation,
    162 }
    163 
    164 impl ToCssWithGuard for LayerBlockRule {
    165    fn to_css(
    166        &self,
    167        guard: &SharedRwLockReadGuard,
    168        dest: &mut style_traits::CssStringWriter,
    169    ) -> fmt::Result {
    170        dest.write_str("@layer")?;
    171        if let Some(ref name) = self.name {
    172            dest.write_char(' ')?;
    173            name.to_css(&mut CssWriter::new(dest))?;
    174        }
    175        self.rules.read_with(guard).to_css_block(guard, dest)
    176    }
    177 }
    178 
    179 impl DeepCloneWithLock for LayerBlockRule {
    180    fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self {
    181        Self {
    182            name: self.name.clone(),
    183            rules: Arc::new(
    184                lock.wrap(
    185                    self.rules
    186                        .read_with(guard)
    187                        .deep_clone_with_lock(lock, guard),
    188                ),
    189            ),
    190            source_location: self.source_location.clone(),
    191        }
    192    }
    193 }
    194 
    195 /// A statement `@layer <name>, <name>, <name>;`
    196 ///
    197 /// https://drafts.csswg.org/css-cascade-5/#layer-empty
    198 #[derive(Clone, Debug, ToShmem)]
    199 pub struct LayerStatementRule {
    200    /// The list of layers to sort.
    201    pub names: Vec<LayerName>,
    202    /// The source position where this rule was found.
    203    pub source_location: SourceLocation,
    204 }
    205 
    206 impl ToCssWithGuard for LayerStatementRule {
    207    fn to_css(
    208        &self,
    209        _: &SharedRwLockReadGuard,
    210        dest: &mut style_traits::CssStringWriter,
    211    ) -> fmt::Result {
    212        let mut writer = CssWriter::new(dest);
    213        writer.write_str("@layer ")?;
    214        let mut first = true;
    215        for name in &*self.names {
    216            if !first {
    217                writer.write_str(", ")?;
    218            }
    219            first = false;
    220            name.to_css(&mut writer)?;
    221        }
    222        writer.write_char(';')
    223    }
    224 }