tor-browser

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

mod.rs (19312B)


      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 //! Common [values][values] used in CSS.
      6 //!
      7 //! [values]: https://drafts.csswg.org/css-values/
      8 
      9 #![deny(missing_docs)]
     10 
     11 use crate::derives::*;
     12 use crate::parser::{Parse, ParserContext};
     13 use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
     14 use crate::Atom;
     15 pub use cssparser::{serialize_identifier, serialize_name, CowRcStr, Parser};
     16 pub use cssparser::{SourceLocation, Token};
     17 use precomputed_hash::PrecomputedHash;
     18 use selectors::parser::SelectorParseErrorKind;
     19 use std::fmt::{self, Debug, Write};
     20 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
     21 use to_shmem::impl_trivial_to_shmem;
     22 
     23 #[cfg(feature = "gecko")]
     24 pub use crate::gecko::url::CssUrl;
     25 #[cfg(feature = "servo")]
     26 pub use crate::servo::url::CssUrl;
     27 
     28 pub mod animated;
     29 pub mod computed;
     30 pub mod distance;
     31 pub mod generics;
     32 pub mod resolved;
     33 pub mod specified;
     34 
     35 /// A CSS float value.
     36 pub type CSSFloat = f32;
     37 
     38 /// Normalizes a float value to zero after a set of operations that might turn
     39 /// it into NaN.
     40 #[inline]
     41 pub fn normalize(v: CSSFloat) -> CSSFloat {
     42    if v.is_nan() {
     43        0.0
     44    } else {
     45        v
     46    }
     47 }
     48 
     49 /// A CSS integer value.
     50 pub type CSSInteger = i32;
     51 
     52 /// Serialize an identifier which is represented as an atom.
     53 #[cfg(feature = "gecko")]
     54 pub fn serialize_atom_identifier<W>(ident: &Atom, dest: &mut W) -> fmt::Result
     55 where
     56    W: Write,
     57 {
     58    ident.with_str(|s| serialize_identifier(s, dest))
     59 }
     60 
     61 /// Serialize an identifier which is represented as an atom.
     62 #[cfg(feature = "servo")]
     63 pub fn serialize_atom_identifier<Static, W>(
     64    ident: &::string_cache::Atom<Static>,
     65    dest: &mut W,
     66 ) -> fmt::Result
     67 where
     68    Static: string_cache::StaticAtomSet,
     69    W: Write,
     70 {
     71    serialize_identifier(&ident, dest)
     72 }
     73 
     74 /// Serialize a name which is represented as an Atom.
     75 #[cfg(feature = "gecko")]
     76 pub fn serialize_atom_name<W>(ident: &Atom, dest: &mut W) -> fmt::Result
     77 where
     78    W: Write,
     79 {
     80    ident.with_str(|s| serialize_name(s, dest))
     81 }
     82 
     83 /// Serialize a name which is represented as an Atom.
     84 #[cfg(feature = "servo")]
     85 pub fn serialize_atom_name<Static, W>(
     86    ident: &::string_cache::Atom<Static>,
     87    dest: &mut W,
     88 ) -> fmt::Result
     89 where
     90    Static: string_cache::StaticAtomSet,
     91    W: Write,
     92 {
     93    serialize_name(&ident, dest)
     94 }
     95 
     96 /// Serialize a number with calc, and NaN/infinity handling (if enabled)
     97 pub fn serialize_number<W>(v: f32, was_calc: bool, dest: &mut CssWriter<W>) -> fmt::Result
     98 where
     99    W: Write,
    100 {
    101    serialize_specified_dimension(v, "", was_calc, dest)
    102 }
    103 
    104 /// Serialize a specified dimension with unit, calc, and NaN/infinity handling (if enabled)
    105 pub fn serialize_specified_dimension<W>(
    106    v: f32,
    107    unit: &str,
    108    was_calc: bool,
    109    dest: &mut CssWriter<W>,
    110 ) -> fmt::Result
    111 where
    112    W: Write,
    113 {
    114    if was_calc {
    115        dest.write_str("calc(")?;
    116    }
    117 
    118    if !v.is_finite() {
    119        // https://drafts.csswg.org/css-values/#calc-error-constants:
    120        // "While not technically numbers, these keywords act as numeric values,
    121        // similar to e and pi. Thus to get an infinite length, for example,
    122        // requires an expression like calc(infinity * 1px)."
    123 
    124        if v.is_nan() {
    125            dest.write_str("NaN")?;
    126        } else if v == f32::INFINITY {
    127            dest.write_str("infinity")?;
    128        } else if v == f32::NEG_INFINITY {
    129            dest.write_str("-infinity")?;
    130        }
    131 
    132        if !unit.is_empty() {
    133            dest.write_str(" * 1")?;
    134        }
    135    } else {
    136        v.to_css(dest)?;
    137    }
    138 
    139    dest.write_str(unit)?;
    140 
    141    if was_calc {
    142        dest.write_char(')')?;
    143    }
    144    Ok(())
    145 }
    146 
    147 /// A CSS string stored as an `Atom`.
    148 #[repr(transparent)]
    149 #[derive(
    150    Clone,
    151    Debug,
    152    Default,
    153    Deref,
    154    Eq,
    155    Hash,
    156    MallocSizeOf,
    157    PartialEq,
    158    SpecifiedValueInfo,
    159    ToComputedValue,
    160    ToResolvedValue,
    161    ToShmem,
    162 )]
    163 pub struct AtomString(pub Atom);
    164 
    165 #[cfg(feature = "servo")]
    166 impl AsRef<str> for AtomString {
    167    fn as_ref(&self) -> &str {
    168        &*self.0
    169    }
    170 }
    171 
    172 impl Parse for AtomString {
    173    fn parse<'i>(_: &ParserContext, input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
    174        Ok(Self(Atom::from(input.expect_string()?.as_ref())))
    175    }
    176 }
    177 
    178 impl cssparser::ToCss for AtomString {
    179    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
    180    where
    181        W: Write,
    182    {
    183        // Wrap in quotes to form a string literal
    184        dest.write_char('"')?;
    185        #[cfg(feature = "servo")]
    186        {
    187            cssparser::CssStringWriter::new(dest).write_str(self.as_ref())?;
    188        }
    189        #[cfg(feature = "gecko")]
    190        {
    191            self.0
    192                .with_str(|s| cssparser::CssStringWriter::new(dest).write_str(s))?;
    193        }
    194        dest.write_char('"')
    195    }
    196 }
    197 
    198 impl style_traits::ToCss for AtomString {
    199    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    200    where
    201        W: Write,
    202    {
    203        cssparser::ToCss::to_css(self, dest)
    204    }
    205 }
    206 
    207 impl PrecomputedHash for AtomString {
    208    #[inline]
    209    fn precomputed_hash(&self) -> u32 {
    210        self.0.precomputed_hash()
    211    }
    212 }
    213 
    214 impl<'a> From<&'a str> for AtomString {
    215    #[inline]
    216    fn from(string: &str) -> Self {
    217        Self(Atom::from(string))
    218    }
    219 }
    220 
    221 /// A generic CSS `<ident>` stored as an `Atom`.
    222 #[cfg(feature = "servo")]
    223 #[repr(transparent)]
    224 #[derive(Deref)]
    225 pub struct GenericAtomIdent<Set>(pub string_cache::Atom<Set>)
    226 where
    227    Set: string_cache::StaticAtomSet;
    228 
    229 /// A generic CSS `<ident>` stored as an `Atom`, for the default atom set.
    230 #[cfg(feature = "servo")]
    231 pub type AtomIdent = GenericAtomIdent<stylo_atoms::AtomStaticSet>;
    232 
    233 #[cfg(feature = "servo")]
    234 impl<Set: string_cache::StaticAtomSet> style_traits::SpecifiedValueInfo for GenericAtomIdent<Set> {}
    235 
    236 #[cfg(feature = "servo")]
    237 impl<Set: string_cache::StaticAtomSet> Default for GenericAtomIdent<Set> {
    238    fn default() -> Self {
    239        Self(string_cache::Atom::default())
    240    }
    241 }
    242 
    243 #[cfg(feature = "servo")]
    244 impl<Set: string_cache::StaticAtomSet> std::fmt::Debug for GenericAtomIdent<Set> {
    245    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    246        self.0.fmt(f)
    247    }
    248 }
    249 
    250 #[cfg(feature = "servo")]
    251 impl<Set: string_cache::StaticAtomSet> std::hash::Hash for GenericAtomIdent<Set> {
    252    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
    253        self.0.hash(state)
    254    }
    255 }
    256 
    257 #[cfg(feature = "servo")]
    258 impl<Set: string_cache::StaticAtomSet> Eq for GenericAtomIdent<Set> {}
    259 
    260 #[cfg(feature = "servo")]
    261 impl<Set: string_cache::StaticAtomSet> PartialEq for GenericAtomIdent<Set> {
    262    fn eq(&self, other: &Self) -> bool {
    263        self.0 == other.0
    264    }
    265 }
    266 
    267 #[cfg(feature = "servo")]
    268 impl<Set: string_cache::StaticAtomSet> Clone for GenericAtomIdent<Set> {
    269    fn clone(&self) -> Self {
    270        Self(self.0.clone())
    271    }
    272 }
    273 
    274 #[cfg(feature = "servo")]
    275 impl<Set: string_cache::StaticAtomSet> to_shmem::ToShmem for GenericAtomIdent<Set> {
    276    fn to_shmem(&self, builder: &mut to_shmem::SharedMemoryBuilder) -> to_shmem::Result<Self> {
    277        use std::mem::ManuallyDrop;
    278 
    279        let atom = self.0.to_shmem(builder)?;
    280        Ok(ManuallyDrop::new(Self(ManuallyDrop::into_inner(atom))))
    281    }
    282 }
    283 
    284 #[cfg(feature = "servo")]
    285 impl<Set: string_cache::StaticAtomSet> malloc_size_of::MallocSizeOf for GenericAtomIdent<Set> {
    286    fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
    287        self.0.size_of(ops)
    288    }
    289 }
    290 
    291 #[cfg(feature = "servo")]
    292 impl<Set: string_cache::StaticAtomSet> cssparser::ToCss for GenericAtomIdent<Set> {
    293    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
    294    where
    295        W: Write,
    296    {
    297        serialize_atom_identifier(&self.0, dest)
    298    }
    299 }
    300 
    301 #[cfg(feature = "servo")]
    302 impl<Set: string_cache::StaticAtomSet> style_traits::ToCss for GenericAtomIdent<Set> {
    303    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    304    where
    305        W: Write,
    306    {
    307        serialize_atom_identifier(&self.0, dest)
    308    }
    309 }
    310 
    311 #[cfg(feature = "servo")]
    312 impl<Set: string_cache::StaticAtomSet> PrecomputedHash for GenericAtomIdent<Set> {
    313    #[inline]
    314    fn precomputed_hash(&self) -> u32 {
    315        self.0.precomputed_hash()
    316    }
    317 }
    318 
    319 #[cfg(feature = "servo")]
    320 impl<'a, Set: string_cache::StaticAtomSet> From<&'a str> for GenericAtomIdent<Set> {
    321    #[inline]
    322    fn from(string: &str) -> Self {
    323        Self(string_cache::Atom::from(string))
    324    }
    325 }
    326 
    327 #[cfg(feature = "servo")]
    328 impl<Set: string_cache::StaticAtomSet> std::borrow::Borrow<string_cache::Atom<Set>>
    329    for GenericAtomIdent<Set>
    330 {
    331    #[inline]
    332    fn borrow(&self) -> &string_cache::Atom<Set> {
    333        &self.0
    334    }
    335 }
    336 
    337 #[cfg(feature = "servo")]
    338 impl<Set: string_cache::StaticAtomSet> GenericAtomIdent<Set> {
    339    /// Constructs a new GenericAtomIdent.
    340    #[inline]
    341    pub fn new(atom: string_cache::Atom<Set>) -> Self {
    342        Self(atom)
    343    }
    344 
    345    /// Cast an atom ref to an AtomIdent ref.
    346    #[inline]
    347    pub fn cast<'a>(atom: &'a string_cache::Atom<Set>) -> &'a Self {
    348        let ptr = atom as *const _ as *const Self;
    349        // safety: repr(transparent)
    350        unsafe { &*ptr }
    351    }
    352 }
    353 
    354 /// A CSS `<ident>` stored as an `Atom`.
    355 #[cfg(feature = "gecko")]
    356 #[repr(transparent)]
    357 #[derive(
    358    Clone, Debug, Default, Deref, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem,
    359 )]
    360 pub struct AtomIdent(pub Atom);
    361 
    362 #[cfg(feature = "gecko")]
    363 impl cssparser::ToCss for AtomIdent {
    364    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
    365    where
    366        W: Write,
    367    {
    368        serialize_atom_identifier(&self.0, dest)
    369    }
    370 }
    371 
    372 #[cfg(feature = "gecko")]
    373 impl style_traits::ToCss for AtomIdent {
    374    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    375    where
    376        W: Write,
    377    {
    378        cssparser::ToCss::to_css(self, dest)
    379    }
    380 }
    381 
    382 #[cfg(feature = "gecko")]
    383 impl PrecomputedHash for AtomIdent {
    384    #[inline]
    385    fn precomputed_hash(&self) -> u32 {
    386        self.0.precomputed_hash()
    387    }
    388 }
    389 
    390 #[cfg(feature = "gecko")]
    391 impl<'a> From<&'a str> for AtomIdent {
    392    #[inline]
    393    fn from(string: &str) -> Self {
    394        Self(Atom::from(string))
    395    }
    396 }
    397 
    398 #[cfg(feature = "gecko")]
    399 impl AtomIdent {
    400    /// Constructs a new AtomIdent.
    401    #[inline]
    402    pub fn new(atom: Atom) -> Self {
    403        Self(atom)
    404    }
    405 
    406    /// Like `Atom::with` but for `AtomIdent`.
    407    pub unsafe fn with<F, R>(ptr: *const crate::gecko_bindings::structs::nsAtom, callback: F) -> R
    408    where
    409        F: FnOnce(&Self) -> R,
    410    {
    411        Atom::with(ptr, |atom: &Atom| {
    412            // safety: repr(transparent)
    413            let atom = atom as *const Atom as *const AtomIdent;
    414            callback(&*atom)
    415        })
    416    }
    417 
    418    /// Cast an atom ref to an AtomIdent ref.
    419    #[inline]
    420    pub fn cast<'a>(atom: &'a Atom) -> &'a Self {
    421        let ptr = atom as *const _ as *const Self;
    422        // safety: repr(transparent)
    423        unsafe { &*ptr }
    424    }
    425 }
    426 
    427 #[cfg(feature = "gecko")]
    428 impl std::borrow::Borrow<crate::gecko_string_cache::WeakAtom> for AtomIdent {
    429    #[inline]
    430    fn borrow(&self) -> &crate::gecko_string_cache::WeakAtom {
    431        self.0.borrow()
    432    }
    433 }
    434 
    435 /// Serialize a value into percentage.
    436 pub fn serialize_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result
    437 where
    438    W: Write,
    439 {
    440    serialize_specified_dimension(value * 100., "%", /* was_calc = */ false, dest)
    441 }
    442 
    443 /// Serialize a value into normalized (no NaN/inf serialization) percentage.
    444 pub fn serialize_normalized_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result
    445 where
    446    W: Write,
    447 {
    448    (value * 100.).to_css(dest)?;
    449    dest.write_char('%')
    450 }
    451 
    452 /// Convenience void type to disable some properties and values through types.
    453 #[cfg_attr(feature = "servo", derive(Deserialize, MallocSizeOf, Serialize))]
    454 #[derive(
    455    Clone,
    456    Copy,
    457    Debug,
    458    PartialEq,
    459    SpecifiedValueInfo,
    460    ToAnimatedValue,
    461    ToComputedValue,
    462    ToCss,
    463    ToResolvedValue,
    464 )]
    465 pub enum Impossible {}
    466 
    467 // FIXME(nox): This should be derived but the derive code cannot cope
    468 // with uninhabited enums.
    469 impl ComputeSquaredDistance for Impossible {
    470    #[inline]
    471    fn compute_squared_distance(&self, _other: &Self) -> Result<SquaredDistance, ()> {
    472        match *self {}
    473    }
    474 }
    475 
    476 impl_trivial_to_shmem!(Impossible);
    477 
    478 impl Parse for Impossible {
    479    fn parse<'i, 't>(
    480        _context: &ParserContext,
    481        input: &mut Parser<'i, 't>,
    482    ) -> Result<Self, ParseError<'i>> {
    483        Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
    484    }
    485 }
    486 
    487 /// A struct representing one of two kinds of values.
    488 #[derive(
    489    Animate,
    490    Clone,
    491    ComputeSquaredDistance,
    492    Copy,
    493    MallocSizeOf,
    494    PartialEq,
    495    Parse,
    496    SpecifiedValueInfo,
    497    ToAnimatedValue,
    498    ToAnimatedZero,
    499    ToComputedValue,
    500    ToCss,
    501    ToResolvedValue,
    502    ToShmem,
    503 )]
    504 pub enum Either<A, B> {
    505    /// The first value.
    506    First(A),
    507    /// The second kind of value.
    508    Second(B),
    509 }
    510 
    511 impl<A: Debug, B: Debug> Debug for Either<A, B> {
    512    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    513        match *self {
    514            Either::First(ref v) => v.fmt(f),
    515            Either::Second(ref v) => v.fmt(f),
    516        }
    517    }
    518 }
    519 
    520 /// <https://drafts.csswg.org/css-values-4/#custom-idents>
    521 #[derive(
    522    Clone,
    523    Debug,
    524    Default,
    525    Eq,
    526    Hash,
    527    MallocSizeOf,
    528    PartialEq,
    529    SpecifiedValueInfo,
    530    ToAnimatedValue,
    531    ToComputedValue,
    532    ToResolvedValue,
    533    ToShmem,
    534 )]
    535 #[repr(C)]
    536 pub struct CustomIdent(pub Atom);
    537 
    538 impl CustomIdent {
    539    /// Parse a <custom-ident>
    540    ///
    541    /// TODO(zrhoffman, bug 1844501): Use CustomIdent::parse in more places instead of
    542    /// CustomIdent::from_ident.
    543    pub fn parse<'i, 't>(
    544        input: &mut Parser<'i, 't>,
    545        invalid: &[&str],
    546    ) -> Result<Self, ParseError<'i>> {
    547        let location = input.current_source_location();
    548        let ident = input.expect_ident()?;
    549        CustomIdent::from_ident(location, ident, invalid)
    550    }
    551 
    552    /// Parse an already-tokenizer identifier
    553    pub fn from_ident<'i>(
    554        location: SourceLocation,
    555        ident: &CowRcStr<'i>,
    556        excluding: &[&str],
    557    ) -> Result<Self, ParseError<'i>> {
    558        if !Self::is_valid(ident, excluding) {
    559            return Err(
    560                location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
    561            );
    562        }
    563        if excluding.iter().any(|s| ident.eq_ignore_ascii_case(s)) {
    564            Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
    565        } else {
    566            Ok(CustomIdent(Atom::from(ident.as_ref())))
    567        }
    568    }
    569 
    570    fn is_valid(ident: &str, excluding: &[&str]) -> bool {
    571        use crate::properties::CSSWideKeyword;
    572        // https://drafts.csswg.org/css-values-4/#custom-idents:
    573        //
    574        //     The CSS-wide keywords are not valid <custom-ident>s. The default
    575        //     keyword is reserved and is also not a valid <custom-ident>.
    576        if CSSWideKeyword::from_ident(ident).is_ok() || ident.eq_ignore_ascii_case("default") {
    577            return false;
    578        }
    579 
    580        // https://drafts.csswg.org/css-values-4/#custom-idents:
    581        //
    582        //     Excluded keywords are excluded in all ASCII case permutations.
    583        !excluding.iter().any(|s| ident.eq_ignore_ascii_case(s))
    584    }
    585 }
    586 
    587 impl ToCss for CustomIdent {
    588    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    589    where
    590        W: Write,
    591    {
    592        serialize_atom_identifier(&self.0, dest)
    593    }
    594 }
    595 
    596 /// <https://www.w3.org/TR/css-values-4/#dashed-idents>
    597 /// This is simply an Atom, but will only parse if the identifier starts with "--".
    598 #[repr(transparent)]
    599 #[derive(
    600    Clone,
    601    Debug,
    602    Eq,
    603    Hash,
    604    MallocSizeOf,
    605    PartialEq,
    606    SpecifiedValueInfo,
    607    ToAnimatedValue,
    608    ToComputedValue,
    609    ToResolvedValue,
    610    ToShmem,
    611    Serialize,
    612    Deserialize,
    613 )]
    614 pub struct DashedIdent(pub Atom);
    615 
    616 impl DashedIdent {
    617    /// Parse an already-tokenizer identifier
    618    pub fn from_ident<'i>(
    619        location: SourceLocation,
    620        ident: &CowRcStr<'i>,
    621    ) -> Result<Self, ParseError<'i>> {
    622        if !ident.starts_with("--") {
    623            return Err(
    624                location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
    625            );
    626        }
    627        Ok(Self(Atom::from(ident.as_ref())))
    628    }
    629 
    630    /// Special value for internal use. Useful where we can't use Option<>.
    631    pub fn empty() -> Self {
    632        Self(atom!(""))
    633    }
    634 
    635    /// Check for special internal value.
    636    pub fn is_empty(&self) -> bool {
    637        self.0 == atom!("")
    638    }
    639 }
    640 
    641 impl Parse for DashedIdent {
    642    fn parse<'i, 't>(
    643        _: &ParserContext,
    644        input: &mut Parser<'i, 't>,
    645    ) -> Result<Self, ParseError<'i>> {
    646        let location = input.current_source_location();
    647        let ident = input.expect_ident()?;
    648        Self::from_ident(location, ident)
    649    }
    650 }
    651 
    652 impl ToCss for DashedIdent {
    653    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    654    where
    655        W: Write,
    656    {
    657        serialize_atom_identifier(&self.0, dest)
    658    }
    659 }
    660 
    661 /// The <keyframes-name>.
    662 ///
    663 /// <https://drafts.csswg.org/css-animations/#typedef-keyframes-name>
    664 ///
    665 /// We use a single atom for this. Empty atom represents `none` animation.
    666 #[repr(transparent)]
    667 #[derive(
    668    Clone,
    669    Debug,
    670    Eq,
    671    Hash,
    672    PartialEq,
    673    MallocSizeOf,
    674    SpecifiedValueInfo,
    675    ToComputedValue,
    676    ToResolvedValue,
    677    ToShmem,
    678 )]
    679 pub struct KeyframesName(Atom);
    680 
    681 impl KeyframesName {
    682    /// <https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name>
    683    pub fn from_ident(value: &str) -> Self {
    684        Self(Atom::from(value))
    685    }
    686 
    687    /// Returns the `none` value.
    688    pub fn none() -> Self {
    689        Self(atom!(""))
    690    }
    691 
    692    /// Returns whether this is the special `none` value.
    693    pub fn is_none(&self) -> bool {
    694        self.0 == atom!("")
    695    }
    696 
    697    /// Create a new KeyframesName from Atom.
    698    #[cfg(feature = "gecko")]
    699    pub fn from_atom(atom: Atom) -> Self {
    700        Self(atom)
    701    }
    702 
    703    /// The name as an Atom
    704    pub fn as_atom(&self) -> &Atom {
    705        &self.0
    706    }
    707 }
    708 
    709 impl Parse for KeyframesName {
    710    fn parse<'i, 't>(
    711        _: &ParserContext,
    712        input: &mut Parser<'i, 't>,
    713    ) -> Result<Self, ParseError<'i>> {
    714        let location = input.current_source_location();
    715        Ok(match *input.next()? {
    716            Token::Ident(ref s) => Self(CustomIdent::from_ident(location, s, &["none"])?.0),
    717            Token::QuotedString(ref s) => Self(Atom::from(s.as_ref())),
    718            ref t => return Err(location.new_unexpected_token_error(t.clone())),
    719        })
    720    }
    721 }
    722 
    723 impl ToCss for KeyframesName {
    724    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    725    where
    726        W: Write,
    727    {
    728        if self.is_none() {
    729            return dest.write_str("none");
    730        }
    731 
    732        fn serialize<W: Write>(string: &str, dest: &mut CssWriter<W>) -> fmt::Result {
    733            if CustomIdent::is_valid(string, &["none"]) {
    734                serialize_identifier(string, dest)
    735            } else {
    736                string.to_css(dest)
    737            }
    738        }
    739 
    740        #[cfg(feature = "gecko")]
    741        return self.0.with_str(|s| serialize(s, dest));
    742 
    743        #[cfg(feature = "servo")]
    744        return serialize(self.0.as_ref(), dest);
    745    }
    746 }