diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /servo/components/style/values/mod.rs | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | servo/components/style/values/mod.rs | 425 |
1 files changed, 425 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..9587b52648 --- /dev/null +++ b/servo/components/style/values/mod.rs @@ -0,0 +1,425 @@ +/* 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, RGBA}; +use precomputed_hash::PrecomputedHash; +use selectors::parser::SelectorParseErrorKind; +use std::fmt::{self, Debug, Write}; +use std::hash; +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; + +define_keyword_type!(None_, "none"); +define_keyword_type!(Auto, "auto"); + +/// 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) +} + +/// 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); + +impl cssparser::ToCss for AtomString { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result + where + W: Write, + { + self.0 + .with_str(|s| cssparser::CssStringWriter::new(dest).write_str(s)) + } +} + +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 CSS `<ident>` stored as an `Atom`. +#[repr(transparent)] +#[derive( + Clone, + Debug, + Default, + Deref, + Eq, + Hash, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] +pub struct AtomIdent(pub Atom); + +impl cssparser::ToCss for AtomIdent { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result + where + W: Write, + { + serialize_atom_identifier(&self.0, dest) + } +} + +impl PrecomputedHash for AtomIdent { + #[inline] + fn precomputed_hash(&self) -> u32 { + self.0.precomputed_hash() + } +} + +impl<'a> From<&'a str> for AtomIdent { + #[inline] + fn from(string: &str) -> Self { + Self(Atom::from(string)) + } +} + +impl AtomIdent { + /// Like `Atom::with` but for `AtomIdent`. + #[cfg(feature = "gecko")] + 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) + }) + } +} + +#[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 normalized value into percentage. +pub fn serialize_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result +where + W: Write, +{ + (value * 100.).to_css(dest)?; + dest.write_str("%") +} + +/// 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, + Eq, + Hash, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] +#[repr(C)] +pub struct CustomIdent(pub Atom); + +impl CustomIdent { + /// Parse an already-tokenizer identifier + pub fn from_ident<'i>( + location: SourceLocation, + ident: &CowRcStr<'i>, + excluding: &[&str], + ) -> Result<Self, ParseError<'i>> { + let valid = match_ignore_ascii_case! { ident, + "initial" | "inherit" | "unset" | "default" | "revert" => false, + _ => true + }; + if !valid { + 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()))) + } + } +} + +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://drafts.csswg.org/css-animations/#typedef-keyframes-name> +#[derive( + Clone, Debug, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem, +)] +pub enum KeyframesName { + /// <custom-ident> + Ident(CustomIdent), + /// <string> + QuotedString(Atom), +} + +impl KeyframesName { + /// <https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name> + pub fn from_ident(value: &str) -> Self { + let location = SourceLocation { line: 0, column: 0 }; + let custom_ident = CustomIdent::from_ident(location, &value.into(), &["none"]).ok(); + match custom_ident { + Some(ident) => KeyframesName::Ident(ident), + None => KeyframesName::QuotedString(value.into()), + } + } + + /// Create a new KeyframesName from Atom. + #[cfg(feature = "gecko")] + pub fn from_atom(atom: Atom) -> Self { + debug_assert_ne!(atom, atom!("")); + + // FIXME: We might want to preserve <string>, but currently Gecko + // stores both of <custom-ident> and <string> into nsAtom, so + // we can't tell it. + KeyframesName::Ident(CustomIdent(atom)) + } + + /// The name as an Atom + pub fn as_atom(&self) -> &Atom { + match *self { + KeyframesName::Ident(ref ident) => &ident.0, + KeyframesName::QuotedString(ref atom) => atom, + } + } +} + +impl Eq for KeyframesName {} + +/// A trait that returns whether a given type is the `auto` value or not. So far +/// only needed for background-size serialization, which special-cases `auto`. +pub trait IsAuto { + /// Returns whether the value is the `auto` value. + fn is_auto(&self) -> bool; +} + +impl PartialEq for KeyframesName { + fn eq(&self, other: &Self) -> bool { + self.as_atom() == other.as_atom() + } +} + +impl hash::Hash for KeyframesName { + fn hash<H>(&self, state: &mut H) + where + H: hash::Hasher, + { + self.as_atom().hash(state) + } +} + +impl Parse for KeyframesName { + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result<Self, ParseError<'i>> { + let location = input.current_source_location(); + match *input.next()? { + Token::Ident(ref s) => Ok(KeyframesName::Ident(CustomIdent::from_ident( + location, + s, + &["none"], + )?)), + Token::QuotedString(ref s) => Ok(KeyframesName::QuotedString(Atom::from(s.as_ref()))), + ref t => Err(location.new_unexpected_token_error(t.clone())), + } + } +} + +impl ToCss for KeyframesName { + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result + where + W: Write, + { + match *self { + KeyframesName::Ident(ref ident) => ident.to_css(dest), + KeyframesName::QuotedString(ref atom) => atom.to_string().to_css(dest), + } + } +} |