style/values/resolved/
mod.rs

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//! Resolved values. These are almost always computed values, but in some cases
6//! there are used values.
7
8#[cfg(feature = "gecko")]
9use crate::media_queries::Device;
10use crate::properties::{ComputedValues, LonghandId, NonCustomPropertyId};
11use crate::ArcSlice;
12use app_units::Au;
13use servo_arc::Arc;
14use smallvec::SmallVec;
15
16mod animation;
17mod color;
18mod counters;
19
20use crate::values::computed::{self, Length};
21
22/// Element-specific information needed to resolve property values.
23#[cfg(feature = "gecko")]
24pub struct ResolvedElementInfo<'a> {
25    /// Element we're resolving line-height against.
26    pub element: crate::gecko::wrapper::GeckoElement<'a>,
27}
28
29/// Information needed to resolve a given value.
30pub struct Context<'a> {
31    /// The style we're resolving for. This is useful to resolve currentColor.
32    pub style: &'a ComputedValues,
33    /// The device / document we're resolving style for. Useful to do font metrics stuff needed for
34    /// line-height.
35    #[cfg(feature = "gecko")]
36    pub device: &'a Device,
37    /// The element-specific information to resolve the value.
38    #[cfg(feature = "gecko")]
39    pub element_info: ResolvedElementInfo<'a>,
40    /// The property we're resolving the value for over-all (might be a shorthand).
41    pub for_property: NonCustomPropertyId,
42    /// The current (physical) longhand we're resolving the value for. Guaranteed to be `Some()`
43    /// inside `ToResolvedValue` implementations.
44    pub current_longhand: Option<LonghandId>,
45}
46
47/// A trait to represent the conversion between resolved and resolved values.
48///
49/// This trait is derivable with `#[derive(ToResolvedValue)]`.
50///
51/// The deriving code assumes that if the type isn't generic, then the trait can
52/// be implemented as simple move. This means that a manual implementation with
53/// `ResolvedValue = Self` is bogus if it returns anything else than a clone.
54pub trait ToResolvedValue {
55    /// The resolved value type we're going to be converted to.
56    type ResolvedValue;
57
58    /// Convert a resolved value to a resolved value.
59    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue;
60
61    /// Convert a resolved value to resolved value form.
62    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self;
63}
64
65macro_rules! trivial_to_resolved_value {
66    ($ty:ty) => {
67        impl $crate::values::resolved::ToResolvedValue for $ty {
68            type ResolvedValue = Self;
69
70            #[inline]
71            fn to_resolved_value(self, _: &Context) -> Self {
72                self
73            }
74
75            #[inline]
76            fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
77                resolved
78            }
79        }
80    };
81}
82
83trivial_to_resolved_value!(());
84trivial_to_resolved_value!(bool);
85trivial_to_resolved_value!(f32);
86trivial_to_resolved_value!(u8);
87trivial_to_resolved_value!(i8);
88trivial_to_resolved_value!(u16);
89trivial_to_resolved_value!(i16);
90trivial_to_resolved_value!(u32);
91trivial_to_resolved_value!(i32);
92trivial_to_resolved_value!(usize);
93trivial_to_resolved_value!(String);
94trivial_to_resolved_value!(Box<str>);
95trivial_to_resolved_value!(crate::OwnedStr);
96trivial_to_resolved_value!(crate::color::AbsoluteColor);
97trivial_to_resolved_value!(crate::values::generics::color::ColorMixFlags);
98trivial_to_resolved_value!(crate::Atom);
99trivial_to_resolved_value!(crate::values::AtomIdent);
100trivial_to_resolved_value!(crate::custom_properties::VariableValue);
101trivial_to_resolved_value!(crate::stylesheets::UrlExtraData);
102trivial_to_resolved_value!(computed::url::ComputedUrl);
103#[cfg(feature = "servo")]
104trivial_to_resolved_value!(crate::Namespace);
105#[cfg(feature = "servo")]
106trivial_to_resolved_value!(crate::Prefix);
107trivial_to_resolved_value!(style_traits::values::specified::AllowedNumericType);
108trivial_to_resolved_value!(computed::TimingFunction);
109
110impl ToResolvedValue for Au {
111    type ResolvedValue = Length;
112
113    #[inline]
114    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
115        Length::new(self.to_f32_px()).to_resolved_value(context)
116    }
117
118    #[inline]
119    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
120        Au::from_f32_px(Length::from_resolved_value(resolved).px())
121    }
122}
123
124impl<A, B> ToResolvedValue for (A, B)
125where
126    A: ToResolvedValue,
127    B: ToResolvedValue,
128{
129    type ResolvedValue = (
130        <A as ToResolvedValue>::ResolvedValue,
131        <B as ToResolvedValue>::ResolvedValue,
132    );
133
134    #[inline]
135    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
136        (
137            self.0.to_resolved_value(context),
138            self.1.to_resolved_value(context),
139        )
140    }
141
142    #[inline]
143    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
144        (
145            A::from_resolved_value(resolved.0),
146            B::from_resolved_value(resolved.1),
147        )
148    }
149}
150
151impl<T> ToResolvedValue for Option<T>
152where
153    T: ToResolvedValue,
154{
155    type ResolvedValue = Option<<T as ToResolvedValue>::ResolvedValue>;
156
157    #[inline]
158    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
159        self.map(|item| item.to_resolved_value(context))
160    }
161
162    #[inline]
163    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
164        resolved.map(T::from_resolved_value)
165    }
166}
167
168impl<T> ToResolvedValue for SmallVec<[T; 1]>
169where
170    T: ToResolvedValue,
171{
172    type ResolvedValue = SmallVec<[<T as ToResolvedValue>::ResolvedValue; 1]>;
173
174    #[inline]
175    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
176        self.into_iter()
177            .map(|item| item.to_resolved_value(context))
178            .collect()
179    }
180
181    #[inline]
182    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
183        resolved.into_iter().map(T::from_resolved_value).collect()
184    }
185}
186
187impl<T> ToResolvedValue for Vec<T>
188where
189    T: ToResolvedValue,
190{
191    type ResolvedValue = Vec<<T as ToResolvedValue>::ResolvedValue>;
192
193    #[inline]
194    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
195        self.into_iter()
196            .map(|item| item.to_resolved_value(context))
197            .collect()
198    }
199
200    #[inline]
201    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
202        resolved.into_iter().map(T::from_resolved_value).collect()
203    }
204}
205
206impl<T> ToResolvedValue for thin_vec::ThinVec<T>
207where
208    T: ToResolvedValue,
209{
210    type ResolvedValue = thin_vec::ThinVec<<T as ToResolvedValue>::ResolvedValue>;
211
212    #[inline]
213    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
214        self.into_iter()
215            .map(|item| item.to_resolved_value(context))
216            .collect()
217    }
218
219    #[inline]
220    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
221        resolved.into_iter().map(T::from_resolved_value).collect()
222    }
223}
224
225impl<T> ToResolvedValue for Box<T>
226where
227    T: ToResolvedValue,
228{
229    type ResolvedValue = Box<<T as ToResolvedValue>::ResolvedValue>;
230
231    #[inline]
232    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
233        Box::new(T::to_resolved_value(*self, context))
234    }
235
236    #[inline]
237    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
238        Box::new(T::from_resolved_value(*resolved))
239    }
240}
241
242impl<T> ToResolvedValue for Box<[T]>
243where
244    T: ToResolvedValue,
245{
246    type ResolvedValue = Box<[<T as ToResolvedValue>::ResolvedValue]>;
247
248    #[inline]
249    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
250        Vec::from(self)
251            .to_resolved_value(context)
252            .into_boxed_slice()
253    }
254
255    #[inline]
256    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
257        Vec::from_resolved_value(Vec::from(resolved)).into_boxed_slice()
258    }
259}
260
261impl<T> ToResolvedValue for crate::OwnedSlice<T>
262where
263    T: ToResolvedValue,
264{
265    type ResolvedValue = crate::OwnedSlice<<T as ToResolvedValue>::ResolvedValue>;
266
267    #[inline]
268    fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
269        self.into_box().to_resolved_value(context).into()
270    }
271
272    #[inline]
273    fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
274        Self::from(Box::from_resolved_value(resolved.into_box()))
275    }
276}
277
278// NOTE(emilio): This is implementable more generically, but it's unlikely what
279// you want there, as it forces you to have an extra allocation.
280//
281// We could do that if needed, ideally with specialization for the case where
282// ResolvedValue = T. But we don't need it for now.
283impl<T> ToResolvedValue for Arc<T>
284where
285    T: ToResolvedValue<ResolvedValue = T>,
286{
287    type ResolvedValue = Self;
288
289    #[inline]
290    fn to_resolved_value(self, _: &Context) -> Self {
291        self
292    }
293
294    #[inline]
295    fn from_resolved_value(resolved: Self) -> Self {
296        resolved
297    }
298}
299
300// Same caveat as above applies.
301impl<T> ToResolvedValue for ArcSlice<T>
302where
303    T: ToResolvedValue<ResolvedValue = T>,
304{
305    type ResolvedValue = Self;
306
307    #[inline]
308    fn to_resolved_value(self, _: &Context) -> Self {
309        self
310    }
311
312    #[inline]
313    fn from_resolved_value(resolved: Self) -> Self {
314        resolved
315    }
316}