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