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/ComputedTimingFunction.h"
17 #include "mozilla/Maybe.h"
18 #include "mozilla/StickyTimeDuration.h"
19 #include "mozilla/TimeStamp.h" // for TimeDuration
21 #include "mozilla/dom/AnimationEffectBinding.h" // for FillMode
22 // and PlaybackDirection
24 #define PROGRESS_TIMELINE_DURATION_MILLISEC 100000
29 class UnrestrictedDoubleOrKeyframeEffectOptions
;
30 class UnrestrictedDoubleOrKeyframeAnimationOptions
;
34 TimingParams() = default;
36 TimingParams(float aDuration
, float aDelay
, float aIterationCount
,
37 dom::PlaybackDirection aDirection
, dom::FillMode aFillMode
)
38 : mIterations(aIterationCount
), mDirection(aDirection
), mFill(aFillMode
) {
39 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 Maybe
<ComputedTimingFunction
>&& 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 (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
<ComputedTimingFunction
> ParseEasing(const nsACString
& aEasing
,
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 return aDuration
->MultDouble(aIterations
);
139 // Return the duration of the active interval calculated by duration and
141 StickyTimeDuration
ActiveDuration() const {
142 MOZ_ASSERT(CalcActiveDuration(mDuration
, mIterations
) == mActiveDuration
,
143 "Cached value of active duration should be up to date");
144 return mActiveDuration
;
147 StickyTimeDuration
EndTime() const {
148 MOZ_ASSERT(mEndTime
== std::max(mDelay
+ ActiveDuration() + mEndDelay
,
149 StickyTimeDuration()),
150 "Cached value of end time should be up to date");
154 bool operator==(const TimingParams
& aOther
) const;
155 bool operator!=(const TimingParams
& aOther
) const {
156 return !(*this == aOther
);
159 void SetDuration(Maybe
<StickyTimeDuration
>&& aDuration
) {
160 mDuration
= std::move(aDuration
);
163 void SetDuration(const Maybe
<StickyTimeDuration
>& aDuration
) {
164 mDuration
= aDuration
;
167 const Maybe
<StickyTimeDuration
>& Duration() const { return mDuration
; }
169 void SetDelay(const TimeDuration
& aDelay
) {
173 const TimeDuration
& Delay() const { return mDelay
; }
175 void SetEndDelay(const TimeDuration
& aEndDelay
) {
176 mEndDelay
= aEndDelay
;
179 const TimeDuration
& EndDelay() const { return mEndDelay
; }
181 void SetIterations(double aIterations
) {
182 mIterations
= aIterations
;
185 double Iterations() const { return mIterations
; }
187 void SetIterationStart(double aIterationStart
) {
188 mIterationStart
= aIterationStart
;
190 double IterationStart() const { return mIterationStart
; }
192 void SetDirection(dom::PlaybackDirection aDirection
) {
193 mDirection
= aDirection
;
195 dom::PlaybackDirection
Direction() const { return mDirection
; }
197 void SetFill(dom::FillMode aFill
) { mFill
= aFill
; }
198 dom::FillMode
Fill() const { return mFill
; }
200 void SetTimingFunction(Maybe
<ComputedTimingFunction
>&& aFunction
) {
201 mFunction
= std::move(aFunction
);
203 const Maybe
<ComputedTimingFunction
>& TimingFunction() const {
211 mActiveDuration
= CalcActiveDuration(mDuration
, mIterations
);
214 std::max(mDelay
+ mActiveDuration
+ mEndDelay
, StickyTimeDuration());
217 // mDuration.isNothing() represents the "auto" value
218 Maybe
<StickyTimeDuration
> mDuration
;
219 TimeDuration mDelay
; // Initializes to zero
220 TimeDuration mEndDelay
;
221 double mIterations
= 1.0; // Can be NaN, negative, +/-Infinity
222 double mIterationStart
= 0.0;
223 dom::PlaybackDirection mDirection
= dom::PlaybackDirection::Normal
;
224 dom::FillMode mFill
= dom::FillMode::Auto
;
225 Maybe
<ComputedTimingFunction
> mFunction
;
226 StickyTimeDuration mActiveDuration
= StickyTimeDuration();
227 StickyTimeDuration mEndTime
= StickyTimeDuration();
230 } // namespace mozilla
232 #endif // mozilla_TimingParams_h