Skip to main content

style/values/generics/
animation.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//! Generic values for properties related to animations and transitions.
6
7use crate::derives::*;
8use crate::values::generics::length::GenericLengthPercentageOrAuto;
9use crate::values::specified::animation::{
10    ScrollAxis, ScrollFunction, TimelineName, TimelineRangeName,
11};
12use crate::values::specified::length::EqualsPercentage;
13use crate::Zero;
14use std::fmt::{self, Write};
15use style_traits::{CssString, CssWriter, KeywordValue, ToCss, ToTyped, TypedValue};
16use thin_vec::ThinVec;
17
18/// The `animation-duration` property.
19///
20/// https://drafts.csswg.org/css-animations-2/#animation-duration
21#[derive(
22    Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToShmem,
23)]
24#[repr(C, u8)]
25pub enum GenericAnimationDuration<T> {
26    /// The initial value. However, we serialize this as 0s if the preference is disabled.
27    Auto,
28    /// The time value, <time [0s,∞]>.
29    Time(T),
30}
31
32pub use self::GenericAnimationDuration as AnimationDuration;
33
34impl<T> AnimationDuration<T> {
35    /// Returns the `auto` value.
36    pub fn auto() -> Self {
37        Self::Auto
38    }
39
40    /// Returns true if it is `auto`.
41    pub fn is_auto(&self) -> bool {
42        matches!(*self, Self::Auto)
43    }
44}
45
46impl<T: Zero> Zero for AnimationDuration<T> {
47    fn zero() -> Self {
48        Self::Time(T::zero())
49    }
50
51    fn is_zero(&self) -> bool {
52        match *self {
53            Self::Time(ref t) => t.is_zero(),
54            _ => false,
55        }
56    }
57}
58
59impl<T: ToCss + Zero> ToCss for AnimationDuration<T> {
60    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
61    where
62        W: Write,
63    {
64        match *self {
65            Self::Auto => {
66                if static_prefs::pref!("layout.css.scroll-driven-animations.enabled") {
67                    dest.write_str("auto")
68                } else {
69                    Self::Time(T::zero()).to_css(dest)
70                }
71            },
72            Self::Time(ref t) => t.to_css(dest),
73        }
74    }
75}
76
77// TODO: Switch to ToTyped derive once the pref goes away.
78impl<T: ToTyped + Zero> ToTyped for AnimationDuration<T> {
79    fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
80        match *self {
81            Self::Auto => {
82                if static_prefs::pref!("layout.css.scroll-driven-animations.enabled") {
83                    dest.push(TypedValue::Keyword(KeywordValue(CssString::from("auto"))));
84                    Ok(())
85                } else {
86                    Self::Time(T::zero()).to_typed(dest)
87                }
88            },
89            Self::Time(ref t) => t.to_typed(dest),
90        }
91    }
92}
93
94/// The view() notation.
95/// https://drafts.csswg.org/scroll-animations-1/#view-notation
96#[derive(
97    Clone,
98    Debug,
99    MallocSizeOf,
100    PartialEq,
101    SpecifiedValueInfo,
102    ToComputedValue,
103    ToCss,
104    ToResolvedValue,
105    ToShmem,
106)]
107#[css(function = "view")]
108#[repr(C)]
109pub struct GenericViewFunction<LengthPercent> {
110    /// The axis of scrolling that drives the progress of the timeline.
111    #[css(skip_if = "ScrollAxis::is_default")]
112    pub axis: ScrollAxis,
113    /// An adjustment of the view progress visibility range.
114    #[css(skip_if = "GenericViewTimelineInset::is_auto")]
115    #[css(field_bound)]
116    pub inset: GenericViewTimelineInset<LengthPercent>,
117}
118
119pub use self::GenericViewFunction as ViewFunction;
120
121/// A value for the <single-animation-timeline>.
122///
123/// https://drafts.csswg.org/css-animations-2/#typedef-single-animation-timeline
124#[derive(
125    Clone,
126    Debug,
127    MallocSizeOf,
128    PartialEq,
129    SpecifiedValueInfo,
130    ToComputedValue,
131    ToCss,
132    ToResolvedValue,
133    ToShmem,
134    ToTyped,
135)]
136#[repr(C, u8)]
137#[typed(todo_derive_fields)]
138pub enum GenericAnimationTimeline<LengthPercent> {
139    /// Use default timeline. The animation’s timeline is a DocumentTimeline.
140    Auto,
141    /// The scroll-timeline name or view-timeline-name.
142    /// This also includes `none` value by using an empty atom.
143    /// https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-name
144    /// https://drafts.csswg.org/scroll-animations-1/#view-timeline-name
145    Timeline(TimelineName),
146    /// The scroll() notation.
147    /// https://drafts.csswg.org/scroll-animations-1/#scroll-notation
148    Scroll(ScrollFunction),
149    /// The view() notation.
150    /// https://drafts.csswg.org/scroll-animations-1/#view-notation
151    View(#[css(field_bound)] GenericViewFunction<LengthPercent>),
152}
153
154pub use self::GenericAnimationTimeline as AnimationTimeline;
155
156impl<LengthPercent> AnimationTimeline<LengthPercent> {
157    /// Returns the `auto` value.
158    pub fn auto() -> Self {
159        Self::Auto
160    }
161
162    /// Returns true if it is auto (i.e. the default value).
163    pub fn is_auto(&self) -> bool {
164        matches!(self, Self::Auto)
165    }
166}
167
168/// A generic value for the `[ [ auto | <length-percentage> ]{1,2} ]`.
169///
170/// https://drafts.csswg.org/scroll-animations-1/#view-timeline-inset
171#[derive(
172    Clone,
173    Copy,
174    Debug,
175    MallocSizeOf,
176    PartialEq,
177    SpecifiedValueInfo,
178    ToComputedValue,
179    ToResolvedValue,
180    ToShmem,
181)]
182#[repr(C)]
183pub struct GenericViewTimelineInset<LengthPercent> {
184    /// The start inset in the relevant axis.
185    pub start: GenericLengthPercentageOrAuto<LengthPercent>,
186    /// The end inset.
187    pub end: GenericLengthPercentageOrAuto<LengthPercent>,
188}
189
190pub use self::GenericViewTimelineInset as ViewTimelineInset;
191
192impl<LengthPercent> ViewTimelineInset<LengthPercent> {
193    /// Returns true if it is auto.
194    #[inline]
195    fn is_auto(&self) -> bool {
196        self.start.is_auto() && self.end.is_auto()
197    }
198}
199
200impl<LengthPercent> ToCss for ViewTimelineInset<LengthPercent>
201where
202    LengthPercent: PartialEq + ToCss,
203{
204    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
205    where
206        W: Write,
207    {
208        self.start.to_css(dest)?;
209        if self.end != self.start {
210            dest.write_char(' ')?;
211            self.end.to_css(dest)?;
212        }
213        Ok(())
214    }
215}
216
217impl<LengthPercent> ToTyped for ViewTimelineInset<LengthPercent> where
218    LengthPercent: PartialEq + ToTyped
219{
220}
221
222impl<LengthPercent> Default for ViewTimelineInset<LengthPercent> {
223    fn default() -> Self {
224        Self {
225            start: GenericLengthPercentageOrAuto::auto(),
226            end: GenericLengthPercentageOrAuto::auto(),
227        }
228    }
229}
230
231/// A value for animation-range-start or animation-range-end.
232///
233/// https://drafts.csswg.org/scroll-animations-1/#animation-range-start
234/// https://drafts.csswg.org/scroll-animations-1/#animation-range-end
235#[derive(
236    Clone,
237    Debug,
238    MallocSizeOf,
239    PartialEq,
240    SpecifiedValueInfo,
241    ToComputedValue,
242    ToResolvedValue,
243    ToShmem,
244)]
245#[repr(C)]
246pub struct GenericAnimationRangeValue<LengthPercent> {
247    /// The specific timeline range. If it is None, the animation range only has length-percentage
248    /// component.
249    pub name: TimelineRangeName,
250    /// Used to measure the specific point from the start of the named timeline.
251    pub lp: LengthPercent,
252}
253
254pub use self::GenericAnimationRangeValue as AnimationRangeValue;
255
256impl<LengthPercent> AnimationRangeValue<LengthPercent> {
257    /// Returns the "normal" value
258    #[inline]
259    pub fn normal(lp: LengthPercent) -> Self {
260        Self::new(TimelineRangeName::Normal, lp)
261    }
262
263    /// Returns Self as a LengthPercentage.
264    #[inline]
265    pub fn length_percentage(lp: LengthPercent) -> Self {
266        Self::new(TimelineRangeName::None, lp)
267    }
268
269    /// Returns Self as a tuple of TimelineRangeName range name and LengthPercentage.
270    #[inline]
271    pub fn new(name: TimelineRangeName, lp: LengthPercent) -> Self {
272        Self { name, lp }
273    }
274
275    /// Returns true if it is "normal".
276    #[inline]
277    pub fn is_normal(&self) -> bool {
278        self.name.is_normal()
279    }
280}
281
282/// A value for animation-range-start.
283///
284/// https://drafts.csswg.org/scroll-animations-1/#animation-range-start
285#[derive(
286    Clone,
287    Debug,
288    MallocSizeOf,
289    PartialEq,
290    SpecifiedValueInfo,
291    ToComputedValue,
292    ToResolvedValue,
293    ToShmem,
294    ToTyped,
295)]
296#[repr(transparent)]
297#[typed(todo_derive_fields)]
298pub struct GenericAnimationRangeStart<LengthPercent>(pub GenericAnimationRangeValue<LengthPercent>);
299
300pub use self::GenericAnimationRangeStart as AnimationRangeStart;
301
302fn to_css_with_default<LengthPercent, W>(
303    value: &AnimationRangeValue<LengthPercent>,
304    dest: &mut CssWriter<W>,
305    default: f32,
306) -> fmt::Result
307where
308    LengthPercent: ToCss + EqualsPercentage,
309    W: Write,
310{
311    if matches!(value.name, TimelineRangeName::Normal) {
312        return dest.write_str("normal");
313    }
314    if matches!(value.name, TimelineRangeName::None) {
315        return value.lp.to_css(dest);
316    }
317    // <timeline-range-name> <length-percentage>?
318    value.name.to_css(dest)?;
319    if !value.lp.equals_percentage(default) {
320        dest.write_char(' ')?;
321        value.lp.to_css(dest)?;
322    }
323    Ok(())
324}
325
326impl<LengthPercent: ToCss + EqualsPercentage> ToCss for AnimationRangeStart<LengthPercent> {
327    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
328    where
329        W: Write,
330    {
331        to_css_with_default(&self.0, dest, 0.0)
332    }
333}
334
335/// A value for animation-range-end.
336///
337/// https://drafts.csswg.org/scroll-animations-1/#animation-range-end
338#[derive(
339    Clone,
340    Debug,
341    MallocSizeOf,
342    PartialEq,
343    SpecifiedValueInfo,
344    ToComputedValue,
345    ToResolvedValue,
346    ToShmem,
347    ToTyped,
348)]
349#[repr(transparent)]
350#[typed(todo_derive_fields)]
351pub struct GenericAnimationRangeEnd<LengthPercent>(pub GenericAnimationRangeValue<LengthPercent>);
352
353pub use self::GenericAnimationRangeEnd as AnimationRangeEnd;
354
355impl<LengthPercent: ToCss + EqualsPercentage> ToCss for AnimationRangeEnd<LengthPercent> {
356    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
357    where
358        W: Write,
359    {
360        to_css_with_default(&self.0, dest, 1.0)
361    }
362}