diff options
Diffstat (limited to 'servo/components/style/values/resolved')
-rw-r--r-- | servo/components/style/values/resolved/color.rs | 48 | ||||
-rw-r--r-- | servo/components/style/values/resolved/counters.rs | 51 | ||||
-rw-r--r-- | servo/components/style/values/resolved/mod.rs | 274 |
3 files changed, 373 insertions, 0 deletions
diff --git a/servo/components/style/values/resolved/color.rs b/servo/components/style/values/resolved/color.rs new file mode 100644 index 0000000000..79dfd8685f --- /dev/null +++ b/servo/components/style/values/resolved/color.rs @@ -0,0 +1,48 @@ +/* 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 color values. + +use super::{Context, ToResolvedValue}; + +use crate::color::AbsoluteColor; +use crate::values::computed::color as computed; +use crate::values::generics::color as generics; + +impl ToResolvedValue for computed::Color { + // A resolved color value is an rgba color, with currentcolor resolved. + type ResolvedValue = AbsoluteColor; + + #[inline] + fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { + context.style.resolve_color(self) + } + + #[inline] + fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { + generics::Color::Absolute(resolved) + } +} + +impl ToResolvedValue for computed::CaretColor { + // A resolved caret-color value is an rgba color, with auto resolving to + // currentcolor. + type ResolvedValue = AbsoluteColor; + + #[inline] + fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue { + let color = match self.0 { + generics::ColorOrAuto::Color(color) => color, + generics::ColorOrAuto::Auto => generics::Color::currentcolor(), + }; + color.to_resolved_value(context) + } + + #[inline] + fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { + generics::CaretColor(generics::ColorOrAuto::Color( + computed::Color::from_resolved_value(resolved), + )) + } +} diff --git a/servo/components/style/values/resolved/counters.rs b/servo/components/style/values/resolved/counters.rs new file mode 100644 index 0000000000..c1332449ad --- /dev/null +++ b/servo/components/style/values/resolved/counters.rs @@ -0,0 +1,51 @@ +/* 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 for counter properties + +use super::{Context, ToResolvedValue}; +use crate::values::computed; + +/// https://drafts.csswg.org/css-content/#content-property +/// +/// We implement this at resolved value time because otherwise it causes us to +/// allocate a bunch of useless initial structs for ::before / ::after, which is +/// a bit unfortunate. +/// +/// Though these should be temporary, mostly, so if this causes complexity in +/// other places, it should be fine to move to `StyleAdjuster`. +/// +/// See https://github.com/w3c/csswg-drafts/issues/4632 for where some related +/// issues are being discussed. +impl ToResolvedValue for computed::Content { + type ResolvedValue = Self; + + #[inline] + fn to_resolved_value(self, context: &Context) -> Self { + let (is_pseudo, is_before_or_after, is_marker) = match context.style.pseudo() { + Some(ref pseudo) => (true, pseudo.is_before_or_after(), pseudo.is_marker()), + None => (false, false, false), + }; + match self { + Self::Normal if is_before_or_after => Self::None, + // For now, make `content: none` compute to `normal` for pseudos + // other than ::before, ::after and ::marker, as we don't respect it. + // https://github.com/w3c/csswg-drafts/issues/6124 + // Ditto for non-pseudo elements if the pref is disabled. + Self::None + if (is_pseudo && !is_before_or_after && !is_marker) || + (!is_pseudo && + !static_prefs::pref!("layout.css.element-content-none.enabled")) => + { + Self::Normal + }, + other => other, + } + } + + #[inline] + fn from_resolved_value(resolved: Self) -> Self { + resolved + } +} diff --git a/servo/components/style/values/resolved/mod.rs b/servo/components/style/values/resolved/mod.rs new file mode 100644 index 0000000000..31ef2de44b --- /dev/null +++ b/servo/components/style/values/resolved/mod.rs @@ -0,0 +1,274 @@ +/* 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 crate::media_queries::Device; +use crate::properties::ComputedValues; +use crate::ArcSlice; +use servo_arc::Arc; +use smallvec::SmallVec; + +mod color; +mod counters; + +use crate::values::computed; + +/// Element-specific information needed to resolve property values. +pub struct ResolvedElementInfo<'a> { + /// Element we're resolving line-height against. + #[cfg(feature = "gecko")] + 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. + pub device: &'a Device, + /// The element-specific information to resolve the value. + 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<str>); +trivial_to_resolved_value!(crate::OwnedStr); +trivial_to_resolved_value!(crate::color::AbsoluteColor); +trivial_to_resolved_value!(crate::Atom); +trivial_to_resolved_value!(crate::values::AtomIdent); +trivial_to_resolved_value!(app_units::Au); +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!(computed::LengthPercentage); +trivial_to_resolved_value!(style_traits::values::specified::AllowedNumericType); +trivial_to_resolved_value!(computed::TimingFunction); + +impl<A, B> ToResolvedValue for (A, B) +where + A: ToResolvedValue, + B: ToResolvedValue, +{ + type ResolvedValue = ( + <A as ToResolvedValue>::ResolvedValue, + <B as ToResolvedValue>::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<T> ToResolvedValue for Option<T> +where + T: ToResolvedValue, +{ + type ResolvedValue = Option<<T as ToResolvedValue>::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<T> ToResolvedValue for SmallVec<[T; 1]> +where + T: ToResolvedValue, +{ + type ResolvedValue = SmallVec<[<T as ToResolvedValue>::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<T> ToResolvedValue for Vec<T> +where + T: ToResolvedValue, +{ + type ResolvedValue = Vec<<T as ToResolvedValue>::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<T> ToResolvedValue for Box<T> +where + T: ToResolvedValue, +{ + type ResolvedValue = Box<<T as ToResolvedValue>::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<T> ToResolvedValue for Box<[T]> +where + T: ToResolvedValue, +{ + type ResolvedValue = Box<[<T as ToResolvedValue>::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<T> ToResolvedValue for crate::OwnedSlice<T> +where + T: ToResolvedValue, +{ + type ResolvedValue = crate::OwnedSlice<<T as ToResolvedValue>::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<T> ToResolvedValue for Arc<T> +where + T: ToResolvedValue<ResolvedValue = T>, +{ + 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<T> ToResolvedValue for ArcSlice<T> +where + T: ToResolvedValue<ResolvedValue = T>, +{ + type ResolvedValue = Self; + + #[inline] + fn to_resolved_value(self, _: &Context) -> Self { + self + } + + #[inline] + fn from_resolved_value(resolved: Self) -> Self { + resolved + } +} |