/* 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/. */ //! Resolved values. These are almost always computed values, but in some cases //! there are used values. use app_units::Au; #[cfg(feature = "gecko")] use crate::media_queries::Device; use crate::properties::ComputedValues; use crate::ArcSlice; use servo_arc::Arc; use smallvec::SmallVec; mod animation; mod color; mod counters; use crate::values::computed::{self, Length}; /// Element-specific information needed to resolve property values. #[cfg(feature = "gecko")] pub struct ResolvedElementInfo<'a> { /// Element we're resolving line-height against. pub element: crate::gecko::wrapper::GeckoElement<'a>, } /// Information needed to resolve a given value. pub struct Context<'a> { /// The style we're resolving for. This is useful to resolve currentColor. pub style: &'a ComputedValues, /// The device / document we're resolving style for. Useful to do font metrics stuff needed for /// line-height. #[cfg(feature = "gecko")] pub device: &'a Device, /// The element-specific information to resolve the value. #[cfg(feature = "gecko")] pub element_info: ResolvedElementInfo<'a>, } /// A trait to represent the conversion between resolved and resolved values. /// /// This trait is derivable with `#[derive(ToResolvedValue)]`. /// /// The deriving code assumes that if the type isn't generic, then the trait can /// be implemented as simple move. This means that a manual implementation with /// `ResolvedValue = Self` is bogus if it returns anything else than a clone. pub trait ToResolvedValue { /// The resolved value type we're going to be converted to. type ResolvedValue; /// Convert a resolved value to a resolved value. fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue; /// Convert a resolved value to resolved value form. fn from_resolved_value(resolved: Self::ResolvedValue) -> Self; } macro_rules! trivial_to_resolved_value { ($ty:ty) => { impl $crate::values::resolved::ToResolvedValue for $ty { type ResolvedValue = Self; #[inline] fn to_resolved_value(self, _: &Context) -> Self { self } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { resolved } } }; } trivial_to_resolved_value!(()); trivial_to_resolved_value!(bool); trivial_to_resolved_value!(f32); trivial_to_resolved_value!(u8); trivial_to_resolved_value!(i8); trivial_to_resolved_value!(u16); trivial_to_resolved_value!(i16); trivial_to_resolved_value!(u32); trivial_to_resolved_value!(i32); trivial_to_resolved_value!(usize); trivial_to_resolved_value!(String); trivial_to_resolved_value!(Box); trivial_to_resolved_value!(crate::OwnedStr); trivial_to_resolved_value!(crate::color::AbsoluteColor); trivial_to_resolved_value!(crate::values::generics::color::ColorMixFlags); trivial_to_resolved_value!(crate::Atom); trivial_to_resolved_value!(crate::values::AtomIdent); trivial_to_resolved_value!(crate::custom_properties::VariableValue); trivial_to_resolved_value!(crate::stylesheets::UrlExtraData); trivial_to_resolved_value!(computed::url::ComputedUrl); #[cfg(feature = "gecko")] trivial_to_resolved_value!(computed::url::ComputedImageUrl); #[cfg(feature = "servo")] trivial_to_resolved_value!(crate::Namespace); #[cfg(feature = "servo")] trivial_to_resolved_value!(crate::Prefix); trivial_to_resolved_value!(style_traits::values::specified::AllowedNumericType); trivial_to_resolved_value!(computed::TimingFunction); impl ToResolvedValue for Au { type ResolvedValue = Length; #[inline] fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { Length::new(self.to_f32_px()).to_resolved_value(context) } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { Au::from_f32_px(Length::from_resolved_value(resolved).px()) } } impl ToResolvedValue for (A, B) where A: ToResolvedValue, B: ToResolvedValue, { type ResolvedValue = ( ::ResolvedValue, ::ResolvedValue, ); #[inline] fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { ( self.0.to_resolved_value(context), self.1.to_resolved_value(context), ) } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { ( A::from_resolved_value(resolved.0), B::from_resolved_value(resolved.1), ) } } impl ToResolvedValue for Option where T: ToResolvedValue, { type ResolvedValue = Option<::ResolvedValue>; #[inline] fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { self.map(|item| item.to_resolved_value(context)) } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { resolved.map(T::from_resolved_value) } } impl ToResolvedValue for SmallVec<[T; 1]> where T: ToResolvedValue, { type ResolvedValue = SmallVec<[::ResolvedValue; 1]>; #[inline] fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { self.into_iter() .map(|item| item.to_resolved_value(context)) .collect() } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { resolved.into_iter().map(T::from_resolved_value).collect() } } impl ToResolvedValue for Vec where T: ToResolvedValue, { type ResolvedValue = Vec<::ResolvedValue>; #[inline] fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { self.into_iter() .map(|item| item.to_resolved_value(context)) .collect() } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { resolved.into_iter().map(T::from_resolved_value).collect() } } impl ToResolvedValue for thin_vec::ThinVec where T: ToResolvedValue, { type ResolvedValue = thin_vec::ThinVec<::ResolvedValue>; #[inline] fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { self.into_iter() .map(|item| item.to_resolved_value(context)) .collect() } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { resolved.into_iter().map(T::from_resolved_value).collect() } } impl ToResolvedValue for Box where T: ToResolvedValue, { type ResolvedValue = Box<::ResolvedValue>; #[inline] fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { Box::new(T::to_resolved_value(*self, context)) } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { Box::new(T::from_resolved_value(*resolved)) } } impl ToResolvedValue for Box<[T]> where T: ToResolvedValue, { type ResolvedValue = Box<[::ResolvedValue]>; #[inline] fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { Vec::from(self) .to_resolved_value(context) .into_boxed_slice() } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { Vec::from_resolved_value(Vec::from(resolved)).into_boxed_slice() } } impl ToResolvedValue for crate::OwnedSlice where T: ToResolvedValue, { type ResolvedValue = crate::OwnedSlice<::ResolvedValue>; #[inline] fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { self.into_box().to_resolved_value(context).into() } #[inline] fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { Self::from(Box::from_resolved_value(resolved.into_box())) } } // NOTE(emilio): This is implementable more generically, but it's unlikely what // you want there, as it forces you to have an extra allocation. // // We could do that if needed, ideally with specialization for the case where // ResolvedValue = T. But we don't need it for now. impl ToResolvedValue for Arc where T: ToResolvedValue, { type ResolvedValue = Self; #[inline] fn to_resolved_value(self, _: &Context) -> Self { self } #[inline] fn from_resolved_value(resolved: Self) -> Self { resolved } } // Same caveat as above applies. impl ToResolvedValue for ArcSlice where T: ToResolvedValue, { type ResolvedValue = Self; #[inline] fn to_resolved_value(self, _: &Context) -> Self { self } #[inline] fn from_resolved_value(resolved: Self) -> Self { resolved } }