summaryrefslogtreecommitdiffstats
path: root/servo/components/style/values/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/values/mod.rs')
-rw-r--r--servo/components/style/values/mod.rs796
1 files changed, 796 insertions, 0 deletions
diff --git a/servo/components/style/values/mod.rs b/servo/components/style/values/mod.rs
new file mode 100644
index 0000000000..6138d5a2ab
--- /dev/null
+++ b/servo/components/style/values/mod.rs
@@ -0,0 +1,796 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+//! Common [values][values] used in CSS.
+//!
+//! [values]: https://drafts.csswg.org/css-values/
+
+#![deny(missing_docs)]
+
+use crate::parser::{Parse, ParserContext};
+use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
+use crate::Atom;
+pub use cssparser::{serialize_identifier, serialize_name, CowRcStr, Parser};
+pub use cssparser::{SourceLocation, Token};
+use precomputed_hash::PrecomputedHash;
+use selectors::parser::SelectorParseErrorKind;
+use std::fmt::{self, Debug, Write};
+use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
+use to_shmem::impl_trivial_to_shmem;
+
+#[cfg(feature = "gecko")]
+pub use crate::gecko::url::CssUrl;
+#[cfg(feature = "servo")]
+pub use crate::servo::url::CssUrl;
+
+pub mod animated;
+pub mod computed;
+pub mod distance;
+pub mod generics;
+pub mod resolved;
+pub mod specified;
+
+/// A CSS float value.
+pub type CSSFloat = f32;
+
+/// Normalizes a float value to zero after a set of operations that might turn
+/// it into NaN.
+#[inline]
+pub fn normalize(v: CSSFloat) -> CSSFloat {
+ if v.is_nan() {
+ 0.0
+ } else {
+ v
+ }
+}
+
+/// A CSS integer value.
+pub type CSSInteger = i32;
+
+/// Serialize an identifier which is represented as an atom.
+#[cfg(feature = "gecko")]
+pub fn serialize_atom_identifier<W>(ident: &Atom, dest: &mut W) -> fmt::Result
+where
+ W: Write,
+{
+ ident.with_str(|s| serialize_identifier(s, dest))
+}
+
+/// Serialize an identifier which is represented as an atom.
+#[cfg(feature = "servo")]
+pub fn serialize_atom_identifier<Static, W>(
+ ident: &::string_cache::Atom<Static>,
+ dest: &mut W,
+) -> fmt::Result
+where
+ Static: string_cache::StaticAtomSet,
+ W: Write,
+{
+ serialize_identifier(&ident, dest)
+}
+
+/// Serialize a name which is represented as an Atom.
+#[cfg(feature = "gecko")]
+pub fn serialize_atom_name<W>(ident: &Atom, dest: &mut W) -> fmt::Result
+where
+ W: Write,
+{
+ ident.with_str(|s| serialize_name(s, dest))
+}
+
+/// Serialize a name which is represented as an Atom.
+#[cfg(feature = "servo")]
+pub fn serialize_atom_name<Static, W>(
+ ident: &::string_cache::Atom<Static>,
+ dest: &mut W,
+) -> fmt::Result
+where
+ Static: string_cache::StaticAtomSet,
+ W: Write,
+{
+ serialize_name(&ident, dest)
+}
+
+/// Serialize a number with calc, and NaN/infinity handling (if enabled)
+pub fn serialize_number<W>(v: f32, was_calc: bool, dest: &mut CssWriter<W>) -> fmt::Result
+where
+ W: Write,
+{
+ serialize_specified_dimension(v, "", was_calc, dest)
+}
+
+/// Serialize a specified dimension with unit, calc, and NaN/infinity handling (if enabled)
+pub fn serialize_specified_dimension<W>(
+ v: f32,
+ unit: &str,
+ was_calc: bool,
+ dest: &mut CssWriter<W>,
+) -> fmt::Result
+where
+ W: Write,
+{
+ if was_calc {
+ dest.write_str("calc(")?;
+ }
+
+ if !v.is_finite() {
+ // https://drafts.csswg.org/css-values/#calc-error-constants:
+ // "While not technically numbers, these keywords act as numeric values,
+ // similar to e and pi. Thus to get an infinite length, for example,
+ // requires an expression like calc(infinity * 1px)."
+
+ if v.is_nan() {
+ dest.write_str("NaN")?;
+ } else if v == f32::INFINITY {
+ dest.write_str("infinity")?;
+ } else if v == f32::NEG_INFINITY {
+ dest.write_str("-infinity")?;
+ }
+
+ if !unit.is_empty() {
+ dest.write_str(" * 1")?;
+ }
+ } else {
+ v.to_css(dest)?;
+ }
+
+ dest.write_str(unit)?;
+
+ if was_calc {
+ dest.write_char(')')?;
+ }
+ Ok(())
+}
+
+/// A CSS string stored as an `Atom`.
+#[repr(transparent)]
+#[derive(
+ Clone,
+ Debug,
+ Default,
+ Deref,
+ Eq,
+ Hash,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+pub struct AtomString(pub Atom);
+
+#[cfg(feature = "servo")]
+impl AsRef<str> for AtomString {
+ fn as_ref(&self) -> &str {
+ &*self.0
+ }
+}
+
+impl cssparser::ToCss for AtomString {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+ where
+ W: Write,
+ {
+ // Wrap in quotes to form a string literal
+ dest.write_char('"')?;
+ #[cfg(feature = "servo")]
+ {
+ cssparser::CssStringWriter::new(dest).write_str(self.as_ref())?;
+ }
+ #[cfg(feature = "gecko")]
+ {
+ self.0
+ .with_str(|s| cssparser::CssStringWriter::new(dest).write_str(s))?;
+ }
+ dest.write_char('"')
+ }
+}
+
+impl style_traits::ToCss for AtomString {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ cssparser::ToCss::to_css(self, dest)
+ }
+}
+
+impl PrecomputedHash for AtomString {
+ #[inline]
+ fn precomputed_hash(&self) -> u32 {
+ self.0.precomputed_hash()
+ }
+}
+
+impl<'a> From<&'a str> for AtomString {
+ #[inline]
+ fn from(string: &str) -> Self {
+ Self(Atom::from(string))
+ }
+}
+
+/// A generic CSS `<ident>` stored as an `Atom`.
+#[cfg(feature = "servo")]
+#[repr(transparent)]
+#[derive(Deref)]
+pub struct GenericAtomIdent<Set>(pub string_cache::Atom<Set>)
+where
+ Set: string_cache::StaticAtomSet;
+
+/// A generic CSS `<ident>` stored as an `Atom`, for the default atom set.
+#[cfg(feature = "servo")]
+pub type AtomIdent = GenericAtomIdent<servo_atoms::AtomStaticSet>;
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> style_traits::SpecifiedValueInfo for GenericAtomIdent<Set> {}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> Default for GenericAtomIdent<Set> {
+ fn default() -> Self {
+ Self(string_cache::Atom::default())
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> std::fmt::Debug for GenericAtomIdent<Set> {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> std::hash::Hash for GenericAtomIdent<Set> {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.0.hash(state)
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> Eq for GenericAtomIdent<Set> {}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> PartialEq for GenericAtomIdent<Set> {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> Clone for GenericAtomIdent<Set> {
+ fn clone(&self) -> Self {
+ Self(self.0.clone())
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> to_shmem::ToShmem for GenericAtomIdent<Set> {
+ fn to_shmem(&self, builder: &mut to_shmem::SharedMemoryBuilder) -> to_shmem::Result<Self> {
+ use std::mem::ManuallyDrop;
+
+ let atom = self.0.to_shmem(builder)?;
+ Ok(ManuallyDrop::new(Self(ManuallyDrop::into_inner(atom))))
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> malloc_size_of::MallocSizeOf for GenericAtomIdent<Set> {
+ fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
+ self.0.size_of(ops)
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> cssparser::ToCss for GenericAtomIdent<Set> {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+ where
+ W: Write,
+ {
+ serialize_atom_identifier(&self.0, dest)
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> PrecomputedHash for GenericAtomIdent<Set> {
+ #[inline]
+ fn precomputed_hash(&self) -> u32 {
+ self.0.precomputed_hash()
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<'a, Set: string_cache::StaticAtomSet> From<&'a str> for GenericAtomIdent<Set> {
+ #[inline]
+ fn from(string: &str) -> Self {
+ Self(string_cache::Atom::from(string))
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> std::borrow::Borrow<string_cache::Atom<Set>>
+ for GenericAtomIdent<Set>
+{
+ #[inline]
+ fn borrow(&self) -> &string_cache::Atom<Set> {
+ &self.0
+ }
+}
+
+#[cfg(feature = "servo")]
+impl<Set: string_cache::StaticAtomSet> GenericAtomIdent<Set> {
+ /// Constructs a new GenericAtomIdent.
+ #[inline]
+ pub fn new(atom: string_cache::Atom<Set>) -> Self {
+ Self(atom)
+ }
+
+ /// Cast an atom ref to an AtomIdent ref.
+ #[inline]
+ pub fn cast<'a>(atom: &'a string_cache::Atom<Set>) -> &'a Self {
+ let ptr = atom as *const _ as *const Self;
+ // safety: repr(transparent)
+ unsafe { &*ptr }
+ }
+}
+
+/// A CSS `<ident>` stored as an `Atom`.
+#[cfg(feature = "gecko")]
+#[repr(transparent)]
+#[derive(
+ Clone, Debug, Default, Deref, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem,
+)]
+pub struct AtomIdent(pub Atom);
+
+#[cfg(feature = "gecko")]
+impl cssparser::ToCss for AtomIdent {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+ where
+ W: Write,
+ {
+ serialize_atom_identifier(&self.0, dest)
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl style_traits::ToCss for AtomIdent {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ cssparser::ToCss::to_css(self, dest)
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl PrecomputedHash for AtomIdent {
+ #[inline]
+ fn precomputed_hash(&self) -> u32 {
+ self.0.precomputed_hash()
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl<'a> From<&'a str> for AtomIdent {
+ #[inline]
+ fn from(string: &str) -> Self {
+ Self(Atom::from(string))
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl AtomIdent {
+ /// Constructs a new AtomIdent.
+ #[inline]
+ pub fn new(atom: Atom) -> Self {
+ Self(atom)
+ }
+
+ /// Like `Atom::with` but for `AtomIdent`.
+ pub unsafe fn with<F, R>(ptr: *const crate::gecko_bindings::structs::nsAtom, callback: F) -> R
+ where
+ F: FnOnce(&Self) -> R,
+ {
+ Atom::with(ptr, |atom: &Atom| {
+ // safety: repr(transparent)
+ let atom = atom as *const Atom as *const AtomIdent;
+ callback(&*atom)
+ })
+ }
+
+ /// Cast an atom ref to an AtomIdent ref.
+ #[inline]
+ pub fn cast<'a>(atom: &'a Atom) -> &'a Self {
+ let ptr = atom as *const _ as *const Self;
+ // safety: repr(transparent)
+ unsafe { &*ptr }
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl std::borrow::Borrow<crate::gecko_string_cache::WeakAtom> for AtomIdent {
+ #[inline]
+ fn borrow(&self) -> &crate::gecko_string_cache::WeakAtom {
+ self.0.borrow()
+ }
+}
+
+/// Serialize a value into percentage.
+pub fn serialize_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result
+where
+ W: Write,
+{
+ serialize_specified_dimension(value * 100., "%", /* was_calc = */ false, dest)
+}
+
+/// Serialize a value into normalized (no NaN/inf serialization) percentage.
+pub fn serialize_normalized_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result
+where
+ W: Write,
+{
+ (value * 100.).to_css(dest)?;
+ dest.write_char('%')
+}
+
+/// Convenience void type to disable some properties and values through types.
+#[cfg_attr(feature = "servo", derive(Deserialize, MallocSizeOf, Serialize))]
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+)]
+pub enum Impossible {}
+
+// FIXME(nox): This should be derived but the derive code cannot cope
+// with uninhabited enums.
+impl ComputeSquaredDistance for Impossible {
+ #[inline]
+ fn compute_squared_distance(&self, _other: &Self) -> Result<SquaredDistance, ()> {
+ match *self {}
+ }
+}
+
+impl_trivial_to_shmem!(Impossible);
+
+impl Parse for Impossible {
+ fn parse<'i, 't>(
+ _context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ }
+}
+
+/// A struct representing one of two kinds of values.
+#[derive(
+ Animate,
+ Clone,
+ ComputeSquaredDistance,
+ Copy,
+ MallocSizeOf,
+ PartialEq,
+ Parse,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToAnimatedZero,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+pub enum Either<A, B> {
+ /// The first value.
+ First(A),
+ /// The second kind of value.
+ Second(B),
+}
+
+impl<A: Debug, B: Debug> Debug for Either<A, B> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Either::First(ref v) => v.fmt(f),
+ Either::Second(ref v) => v.fmt(f),
+ }
+ }
+}
+
+/// <https://drafts.csswg.org/css-values-4/#custom-idents>
+#[derive(
+ Clone,
+ Debug,
+ Default,
+ Eq,
+ Hash,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(C)]
+pub struct CustomIdent(pub Atom);
+
+impl CustomIdent {
+ /// Parse a <custom-ident>
+ ///
+ /// TODO(zrhoffman, bug 1844501): Use CustomIdent::parse in more places instead of
+ /// CustomIdent::from_ident.
+ pub fn parse<'i, 't>(
+ input: &mut Parser<'i, 't>,
+ invalid: &[&str],
+ ) -> Result<Self, ParseError<'i>> {
+ let location = input.current_source_location();
+ let ident = input.expect_ident()?;
+ CustomIdent::from_ident(location, ident, invalid)
+ }
+
+ /// Parse an already-tokenizer identifier
+ pub fn from_ident<'i>(
+ location: SourceLocation,
+ ident: &CowRcStr<'i>,
+ excluding: &[&str],
+ ) -> Result<Self, ParseError<'i>> {
+ if !Self::is_valid(ident, excluding) {
+ return Err(
+ location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
+ );
+ }
+ if excluding.iter().any(|s| ident.eq_ignore_ascii_case(s)) {
+ Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ } else {
+ Ok(CustomIdent(Atom::from(ident.as_ref())))
+ }
+ }
+
+ fn is_valid(ident: &str, excluding: &[&str]) -> bool {
+ use crate::properties::CSSWideKeyword;
+ // https://drafts.csswg.org/css-values-4/#custom-idents:
+ //
+ // The CSS-wide keywords are not valid <custom-ident>s. The default
+ // keyword is reserved and is also not a valid <custom-ident>.
+ if CSSWideKeyword::from_ident(ident).is_ok() || ident.eq_ignore_ascii_case("default") {
+ return false;
+ }
+
+ // https://drafts.csswg.org/css-values-4/#custom-idents:
+ //
+ // Excluded keywords are excluded in all ASCII case permutations.
+ !excluding.iter().any(|s| ident.eq_ignore_ascii_case(s))
+ }
+}
+
+impl ToCss for CustomIdent {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ serialize_atom_identifier(&self.0, dest)
+ }
+}
+
+/// <https://www.w3.org/TR/css-values-4/#dashed-idents>
+/// This is simply an Atom, but will only parse if the identifier starts with "--".
+#[repr(transparent)]
+#[derive(
+ Clone,
+ Debug,
+ Eq,
+ Hash,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+pub struct DashedIdent(pub Atom);
+
+impl Parse for DashedIdent {
+ fn parse<'i, 't>(
+ _: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ let location = input.current_source_location();
+ let ident = input.expect_ident()?;
+ if ident.starts_with("--") {
+ Ok(Self(Atom::from(ident.as_ref())))
+ } else {
+ Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())))
+ }
+ }
+}
+
+impl ToCss for DashedIdent {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ serialize_atom_identifier(&self.0, dest)
+ }
+}
+
+/// The <timeline-name> or <keyframes-name>.
+/// The definition of these two names are the same, so we use the same type for them.
+///
+/// <https://drafts.csswg.org/css-animations-2/#typedef-timeline-name>
+/// <https://drafts.csswg.org/css-animations/#typedef-keyframes-name>
+///
+/// We use a single atom for these. Empty atom represents `none` animation.
+#[repr(transparent)]
+#[derive(
+ Clone,
+ Debug,
+ Hash,
+ PartialEq,
+ MallocSizeOf,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+pub struct TimelineOrKeyframesName(Atom);
+
+impl TimelineOrKeyframesName {
+ /// <https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name>
+ pub fn from_ident(value: &str) -> Self {
+ Self(Atom::from(value))
+ }
+
+ /// Returns the `none` value.
+ pub fn none() -> Self {
+ Self(atom!(""))
+ }
+
+ /// Returns whether this is the special `none` value.
+ pub fn is_none(&self) -> bool {
+ self.0 == atom!("")
+ }
+
+ /// Create a new TimelineOrKeyframesName from Atom.
+ #[cfg(feature = "gecko")]
+ pub fn from_atom(atom: Atom) -> Self {
+ Self(atom)
+ }
+
+ /// The name as an Atom
+ pub fn as_atom(&self) -> &Atom {
+ &self.0
+ }
+
+ fn parse<'i, 't>(input: &mut Parser<'i, 't>, invalid: &[&str]) -> Result<Self, ParseError<'i>> {
+ debug_assert!(invalid.contains(&"none"));
+ let location = input.current_source_location();
+ Ok(match *input.next()? {
+ Token::Ident(ref s) => Self(CustomIdent::from_ident(location, s, invalid)?.0),
+ Token::QuotedString(ref s) => Self(Atom::from(s.as_ref())),
+ ref t => return Err(location.new_unexpected_token_error(t.clone())),
+ })
+ }
+
+ fn to_css<W>(&self, dest: &mut CssWriter<W>, invalid: &[&str]) -> fmt::Result
+ where
+ W: Write,
+ {
+ debug_assert!(invalid.contains(&"none"));
+
+ if self.0 == atom!("") {
+ return dest.write_str("none");
+ }
+
+ self.0.with_str(|s| {
+ if CustomIdent::is_valid(s, invalid) {
+ serialize_identifier(s, dest)
+ } else {
+ s.to_css(dest)
+ }
+ })
+ }
+}
+
+impl Eq for TimelineOrKeyframesName {}
+
+/// The typedef of <timeline-name>.
+#[repr(transparent)]
+#[derive(
+ Clone,
+ Debug,
+ Deref,
+ Hash,
+ Eq,
+ PartialEq,
+ MallocSizeOf,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+pub struct TimelineName(TimelineOrKeyframesName);
+
+impl TimelineName {
+ /// Create a new TimelineName from Atom.
+ #[cfg(feature = "gecko")]
+ pub fn from_atom(atom: Atom) -> Self {
+ Self(TimelineOrKeyframesName::from_atom(atom))
+ }
+
+ /// Returns the `none` value.
+ pub fn none() -> Self {
+ Self(TimelineOrKeyframesName::none())
+ }
+}
+
+impl Parse for TimelineName {
+ fn parse<'i, 't>(
+ _: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ Ok(Self(TimelineOrKeyframesName::parse(
+ input,
+ &["none", "auto"],
+ )?))
+ }
+}
+
+impl ToCss for TimelineName {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ self.0.to_css(dest, &["none", "auto"])
+ }
+}
+
+/// The typedef of <keyframes-name>.
+#[repr(transparent)]
+#[derive(
+ Clone,
+ Debug,
+ Deref,
+ Hash,
+ Eq,
+ PartialEq,
+ MallocSizeOf,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+pub struct KeyframesName(TimelineOrKeyframesName);
+
+impl KeyframesName {
+ /// Create a new KeyframesName from Atom.
+ #[cfg(feature = "gecko")]
+ pub fn from_atom(atom: Atom) -> Self {
+ Self(TimelineOrKeyframesName::from_atom(atom))
+ }
+
+ /// Returns the `none` value.
+ pub fn none() -> Self {
+ Self(TimelineOrKeyframesName::none())
+ }
+}
+
+impl Parse for KeyframesName {
+ fn parse<'i, 't>(
+ _: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ Ok(Self(TimelineOrKeyframesName::parse(input, &["none"])?))
+ }
+}
+
+impl ToCss for KeyframesName {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ self.0.to_css(dest, &["none"])
+ }
+}