1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_TimingParams_h
8 #define mozilla_TimingParams_h
10 #include "X11UndefineNone.h"
11 #include "nsPrintfCString.h"
12 #include "nsStringFwd.h"
13 #include "nsPrintfCString.h"
14 #include "mozilla/dom/Nullable.h"
15 #include "mozilla/dom/UnionTypes.h" // For OwningUnrestrictedDoubleOrString
16 #include "mozilla/Maybe.h"
17 #include "mozilla/StickyTimeDuration.h"
18 #include "mozilla/TimeStamp.h" // for TimeDuration
19 #include "mozilla/ServoStyleConsts.h"
21 #include "mozilla/dom/AnimationEffectBinding.h" // for FillMode
22 // and PlaybackDirection
27 class UnrestrictedDoubleOrKeyframeEffectOptions
;
28 class UnrestrictedDoubleOrKeyframeAnimationOptions
;
32 TimingParams() = default;
34 TimingParams(Maybe
<float> aDuration
, float aDelay
, float aIterationCount
,
35 dom::PlaybackDirection aDirection
, dom::FillMode aFillMode
)
36 : mIterations(aIterationCount
), mDirection(aDirection
), mFill(aFillMode
) {
38 mDuration
.emplace(StickyTimeDuration::FromMilliseconds(*aDuration
));
40 mDelay
= TimeDuration::FromMilliseconds(aDelay
);
44 TimingParams(const TimeDuration
& aDuration
, const TimeDuration
& aDelay
,
45 const TimeDuration
& aEndDelay
, float aIterations
,
46 float aIterationStart
, dom::PlaybackDirection aDirection
,
47 dom::FillMode aFillMode
,
48 const Maybe
<StyleComputedTimingFunction
>& aFunction
)
51 mIterations(aIterations
),
52 mIterationStart(aIterationStart
),
53 mDirection(aDirection
),
55 mFunction(aFunction
) {
56 mDuration
.emplace(aDuration
);
60 template <class OptionsType
>
61 static TimingParams
FromOptionsType(const OptionsType
& aOptions
,
63 static TimingParams
FromOptionsUnion(
64 const dom::UnrestrictedDoubleOrKeyframeEffectOptions
& aOptions
,
66 static TimingParams
FromOptionsUnion(
67 const dom::UnrestrictedDoubleOrKeyframeAnimationOptions
& aOptions
,
69 static TimingParams
FromEffectTiming(const dom::EffectTiming
& aEffectTiming
,
71 // Returns a copy of |aSource| where each timing property in |aSource| that
72 // is also specified in |aEffectTiming| is replaced with the value from
75 // If any of the values in |aEffectTiming| are invalid, |aRv.Failed()| will be
76 // true and an unmodified copy of |aSource| will be returned.
77 static TimingParams
MergeOptionalEffectTiming(
78 const TimingParams
& aSource
,
79 const dom::OptionalEffectTiming
& aEffectTiming
, ErrorResult
& aRv
);
81 // Range-checks and validates an UnrestrictedDoubleOrString or
82 // OwningUnrestrictedDoubleOrString object and converts to a
83 // StickyTimeDuration value or Nothing() if aDuration is "auto".
84 // Caller must check aRv.Failed().
85 template <class DoubleOrString
>
86 static Maybe
<StickyTimeDuration
> ParseDuration(DoubleOrString
& aDuration
,
88 Maybe
<StickyTimeDuration
> result
;
89 if (aDuration
.IsUnrestrictedDouble()) {
90 double durationInMs
= aDuration
.GetAsUnrestrictedDouble();
91 if (durationInMs
>= 0) {
92 result
.emplace(StickyTimeDuration::FromMilliseconds(durationInMs
));
94 nsPrintfCString
err("Duration (%g) must be nonnegative", durationInMs
);
95 aRv
.ThrowTypeError(err
);
97 } else if (!aDuration
.GetAsString().EqualsLiteral("auto")) {
98 aRv
.ThrowTypeError
<dom::MSG_INVALID_DURATION_ERROR
>(
99 NS_ConvertUTF16toUTF8(aDuration
.GetAsString()));
104 static void ValidateIterationStart(double aIterationStart
, ErrorResult
& aRv
) {
105 if (aIterationStart
< 0) {
106 nsPrintfCString
err("Iteration start (%g) must not be negative",
108 aRv
.ThrowTypeError(err
);
112 static void ValidateIterations(double aIterations
, ErrorResult
& aRv
) {
113 if (std::isnan(aIterations
)) {
114 aRv
.ThrowTypeError("Iterations must not be NaN");
118 if (aIterations
< 0) {
119 nsPrintfCString
err("Iterations (%g) must not be negative", aIterations
);
120 aRv
.ThrowTypeError(err
);
124 static Maybe
<StyleComputedTimingFunction
> ParseEasing(const nsACString
&,
127 static StickyTimeDuration
CalcActiveDuration(
128 const Maybe
<StickyTimeDuration
>& aDuration
, double aIterations
) {
129 // If either the iteration duration or iteration count is zero,
130 // Web Animations says that the active duration is zero. This is to
131 // ensure that the result is defined when the other argument is Infinity.
132 static const StickyTimeDuration zeroDuration
;
133 if (!aDuration
|| aDuration
->IsZero() || aIterations
== 0.0) {
137 MOZ_ASSERT(*aDuration
>= zeroDuration
&& aIterations
>= 0.0,
138 "Both animation duration and ieration count should be greater "
141 StickyTimeDuration result
= aDuration
->MultDouble(aIterations
);
142 if (result
< zeroDuration
) {
143 // If the result of multiplying above is less than zero, it's likely an
144 // overflow happened. we consider it's +Inf here.
145 return StickyTimeDuration::Forever();
149 // Return the duration of the active interval calculated by duration and
151 StickyTimeDuration
ActiveDuration() const {
152 MOZ_ASSERT(CalcActiveDuration(mDuration
, mIterations
) == mActiveDuration
,
153 "Cached value of active duration should be up to date");
154 return mActiveDuration
;
157 StickyTimeDuration
EndTime() const {
158 MOZ_ASSERT(mEndTime
== CalcEndTime(),
159 "Cached value of end time should be up to date");
163 StickyTimeDuration
CalcBeforeActiveBoundary() const {
164 static constexpr StickyTimeDuration zeroDuration
;
165 // https://drafts.csswg.org/web-animations-1/#before-active-boundary-time
166 return std::clamp(StickyTimeDuration(mDelay
), zeroDuration
, mEndTime
);
169 StickyTimeDuration
CalcActiveAfterBoundary() const {
170 if (mActiveDuration
== StickyTimeDuration::Forever()) {
171 return StickyTimeDuration::Forever();
174 static constexpr StickyTimeDuration zeroDuration
;
175 // https://drafts.csswg.org/web-animations-1/#active-after-boundary-time
177 std::min(StickyTimeDuration(mDelay
+ mActiveDuration
), mEndTime
),
181 bool operator==(const TimingParams
& aOther
) const;
182 bool operator!=(const TimingParams
& aOther
) const {
183 return !(*this == aOther
);
186 void SetDuration(Maybe
<StickyTimeDuration
>&& aDuration
) {
187 mDuration
= std::move(aDuration
);
190 void SetDuration(const Maybe
<StickyTimeDuration
>& aDuration
) {
191 mDuration
= aDuration
;
194 const Maybe
<StickyTimeDuration
>& Duration() const { return mDuration
; }
196 void SetDelay(const TimeDuration
& aDelay
) {
200 const TimeDuration
& Delay() const { return mDelay
; }
202 void SetEndDelay(const TimeDuration
& aEndDelay
) {
203 mEndDelay
= aEndDelay
;
206 const TimeDuration
& EndDelay() const { return mEndDelay
; }
208 void SetIterations(double aIterations
) {
209 mIterations
= aIterations
;
212 double Iterations() const { return mIterations
; }
214 void SetIterationStart(double aIterationStart
) {
215 mIterationStart
= aIterationStart
;
217 double IterationStart() const { return mIterationStart
; }
219 void SetDirection(dom::PlaybackDirection aDirection
) {
220 mDirection
= aDirection
;
222 dom::PlaybackDirection
Direction() const { return mDirection
; }
224 void SetFill(dom::FillMode aFill
) { mFill
= aFill
; }
225 dom::FillMode
Fill() const { return mFill
; }
227 void SetTimingFunction(Maybe
<StyleComputedTimingFunction
>&& aFunction
) {
228 mFunction
= std::move(aFunction
);
230 const Maybe
<StyleComputedTimingFunction
>& TimingFunction() const {
234 // This is called only for progress-based timeline (i.e. non-monotonic
235 // timeline). That is, |aTimelineDuration| should be resolved already.
236 TimingParams
Normalize(const TimeDuration
& aTimelineDuration
) const;
240 mActiveDuration
= CalcActiveDuration(mDuration
, mIterations
);
241 mEndTime
= CalcEndTime();
244 StickyTimeDuration
CalcEndTime() const {
245 if (mActiveDuration
== StickyTimeDuration::Forever()) {
246 return StickyTimeDuration::Forever();
248 return std::max(mDelay
+ mActiveDuration
+ mEndDelay
, StickyTimeDuration());
251 // mDuration.isNothing() represents the "auto" value
252 Maybe
<StickyTimeDuration
> mDuration
;
253 TimeDuration mDelay
; // Initializes to zero
254 TimeDuration mEndDelay
;
255 double mIterations
= 1.0; // Can be NaN, negative, +/-Infinity
256 double mIterationStart
= 0.0;
257 dom::PlaybackDirection mDirection
= dom::PlaybackDirection::Normal
;
258 dom::FillMode mFill
= dom::FillMode::Auto
;
259 Maybe
<StyleComputedTimingFunction
> mFunction
;
260 StickyTimeDuration mActiveDuration
= StickyTimeDuration();
261 StickyTimeDuration mEndTime
= StickyTimeDuration();
264 } // namespace mozilla
266 #endif // mozilla_TimingParams_h