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::generics::Optional;
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::{CssWriter, ToCss};
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/// The view() notation.
78/// https://drafts.csswg.org/scroll-animations-1/#view-notation
79#[derive(
80    Clone,
81    Debug,
82    MallocSizeOf,
83    PartialEq,
84    SpecifiedValueInfo,
85    ToComputedValue,
86    ToCss,
87    ToResolvedValue,
88    ToShmem,
89)]
90#[css(function = "view")]
91#[repr(C)]
92pub struct GenericViewFunction<LengthPercent> {
93    /// The axis of scrolling that drives the progress of the timeline.
94    #[css(skip_if = "ScrollAxis::is_default")]
95    pub axis: ScrollAxis,
96    /// An adjustment of the view progress visibility range.
97    #[css(skip_if = "GenericViewTimelineInset::is_auto")]
98    #[css(field_bound)]
99    pub inset: GenericViewTimelineInset<LengthPercent>,
100}
101
102pub use self::GenericViewFunction as ViewFunction;
103
104/// A value for the <single-animation-timeline>.
105///
106/// https://drafts.csswg.org/css-animations-2/#typedef-single-animation-timeline
107#[derive(
108    Clone,
109    Debug,
110    MallocSizeOf,
111    PartialEq,
112    SpecifiedValueInfo,
113    ToComputedValue,
114    ToCss,
115    ToResolvedValue,
116    ToShmem,
117)]
118#[repr(C, u8)]
119pub enum GenericAnimationTimeline<LengthPercent> {
120    /// Use default timeline. The animation’s timeline is a DocumentTimeline.
121    Auto,
122    /// The scroll-timeline name or view-timeline-name.
123    /// This also includes `none` value by using an empty atom.
124    /// https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-name
125    /// https://drafts.csswg.org/scroll-animations-1/#view-timeline-name
126    Timeline(TimelineName),
127    /// The scroll() notation.
128    /// https://drafts.csswg.org/scroll-animations-1/#scroll-notation
129    Scroll(ScrollFunction),
130    /// The view() notation.
131    /// https://drafts.csswg.org/scroll-animations-1/#view-notation
132    View(#[css(field_bound)] GenericViewFunction<LengthPercent>),
133}
134
135pub use self::GenericAnimationTimeline as AnimationTimeline;
136
137impl<LengthPercent> AnimationTimeline<LengthPercent> {
138    /// Returns the `auto` value.
139    pub fn auto() -> Self {
140        Self::Auto
141    }
142
143    /// Returns true if it is auto (i.e. the default value).
144    pub fn is_auto(&self) -> bool {
145        matches!(self, Self::Auto)
146    }
147}
148
149/// A generic value for the `[ [ auto | <length-percentage> ]{1,2} ]`.
150///
151/// https://drafts.csswg.org/scroll-animations-1/#view-timeline-inset
152#[derive(
153    Clone,
154    Copy,
155    Debug,
156    MallocSizeOf,
157    PartialEq,
158    SpecifiedValueInfo,
159    ToComputedValue,
160    ToResolvedValue,
161    ToShmem,
162)]
163#[repr(C)]
164pub struct GenericViewTimelineInset<LengthPercent> {
165    /// The start inset in the relevant axis.
166    pub start: GenericLengthPercentageOrAuto<LengthPercent>,
167    /// The end inset.
168    pub end: GenericLengthPercentageOrAuto<LengthPercent>,
169}
170
171pub use self::GenericViewTimelineInset as ViewTimelineInset;
172
173impl<LengthPercent> ViewTimelineInset<LengthPercent> {
174    /// Returns true if it is auto.
175    #[inline]
176    fn is_auto(&self) -> bool {
177        self.start.is_auto() && self.end.is_auto()
178    }
179}
180
181impl<LengthPercent> ToCss for ViewTimelineInset<LengthPercent>
182where
183    LengthPercent: PartialEq + ToCss,
184{
185    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
186    where
187        W: Write,
188    {
189        self.start.to_css(dest)?;
190        if self.end != self.start {
191            dest.write_char(' ')?;
192            self.end.to_css(dest)?;
193        }
194        Ok(())
195    }
196}
197
198impl<LengthPercent> Default for ViewTimelineInset<LengthPercent> {
199    fn default() -> Self {
200        Self {
201            start: GenericLengthPercentageOrAuto::auto(),
202            end: GenericLengthPercentageOrAuto::auto(),
203        }
204    }
205}
206
207/// A value for animation-range-start or animation-range-end.
208///
209/// https://drafts.csswg.org/scroll-animations-1/#animation-range-start
210/// https://drafts.csswg.org/scroll-animations-1/#animation-range-end
211#[derive(
212    Clone,
213    Debug,
214    MallocSizeOf,
215    PartialEq,
216    SpecifiedValueInfo,
217    ToComputedValue,
218    ToResolvedValue,
219    ToShmem,
220)]
221#[repr(C)]
222pub struct GenericAnimationRangeValue<LengthPercent> {
223    /// The specific timeline range. If it is None, the animation range only has length-percentage
224    /// component.
225    pub name: TimelineRangeName,
226    /// Used to measure the specific point from the start of the named timeline. This is set to
227    /// None only for `normal` keyword. Otherwise, we should always set it to Some().
228    pub lp: Optional<LengthPercent>,
229}
230
231pub use self::GenericAnimationRangeValue as AnimationRangeValue;
232
233impl<LengthPercent> Default for AnimationRangeValue<LengthPercent> {
234    fn default() -> Self {
235        Self {
236            name: TimelineRangeName::None,
237            lp: Optional::None,
238        }
239    }
240}
241
242impl<LengthPercent> AnimationRangeValue<LengthPercent> {
243    /// Returns Self as a LengthPercentage.
244    #[inline]
245    pub fn length_percentage(lp: LengthPercent) -> Self {
246        Self {
247            name: TimelineRangeName::None,
248            lp: Optional::Some(lp),
249        }
250    }
251
252    /// Returns Self as a tuple of TimelineRangeName range name and LengthPercentage.
253    #[inline]
254    pub fn timeline_range(name: TimelineRangeName, lp: LengthPercent) -> Self {
255        Self {
256            name,
257            lp: Optional::Some(lp),
258        }
259    }
260}
261
262/// A value for animation-range-start.
263///
264/// https://drafts.csswg.org/scroll-animations-1/#animation-range-start
265#[derive(
266    Clone,
267    Debug,
268    MallocSizeOf,
269    PartialEq,
270    SpecifiedValueInfo,
271    ToComputedValue,
272    ToResolvedValue,
273    ToShmem,
274)]
275#[repr(C)]
276pub struct GenericAnimationRangeStart<LengthPercent>(pub GenericAnimationRangeValue<LengthPercent>);
277
278pub use self::GenericAnimationRangeStart as AnimationRangeStart;
279
280impl<LengthPercent> Default for AnimationRangeStart<LengthPercent> {
281    fn default() -> Self {
282        Self(AnimationRangeValue::default())
283    }
284}
285
286fn to_css_with_default<LengthPercent, W>(
287    value: &AnimationRangeValue<LengthPercent>,
288    dest: &mut CssWriter<W>,
289    default: crate::values::CSSFloat,
290) -> fmt::Result
291where
292    LengthPercent: ToCss + EqualsPercentage,
293    W: Write,
294{
295    if matches!(value.name, TimelineRangeName::None) {
296        return match value.lp {
297            // `normal`
298            Optional::None => dest.write_str("normal"),
299            // <length-percentage>
300            Optional::Some(ref lp) => lp.to_css(dest),
301        };
302    }
303
304    // <timeline-range-name> <length-percentage>?
305    value.name.to_css(dest)?;
306    match value.lp {
307        Optional::Some(ref lp) if !lp.equals_percentage(default) => {
308            dest.write_char(' ')?;
309            lp.to_css(dest)
310        },
311        _ => Ok(()),
312    }
313}
314
315impl<LengthPercent: ToCss + EqualsPercentage> ToCss for AnimationRangeStart<LengthPercent> {
316    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
317    where
318        W: Write,
319    {
320        to_css_with_default(&self.0, dest, 0.0)
321    }
322}
323
324/// A value for animation-range-end.
325///
326/// https://drafts.csswg.org/scroll-animations-1/#animation-range-end
327#[derive(
328    Clone,
329    Debug,
330    MallocSizeOf,
331    PartialEq,
332    SpecifiedValueInfo,
333    ToComputedValue,
334    ToResolvedValue,
335    ToShmem,
336)]
337#[repr(C)]
338pub struct GenericAnimationRangeEnd<LengthPercent>(pub GenericAnimationRangeValue<LengthPercent>);
339
340pub use self::GenericAnimationRangeEnd as AnimationRangeEnd;
341
342impl<LengthPercent> Default for AnimationRangeEnd<LengthPercent> {
343    fn default() -> Self {
344        Self(AnimationRangeValue::default())
345    }
346}
347
348impl<LengthPercent: ToCss + EqualsPercentage> ToCss for AnimationRangeEnd<LengthPercent> {
349    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
350    where
351        W: Write,
352    {
353        to_css_with_default(&self.0, dest, 1.0)
354    }
355}