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/. */ 6 7 #ifndef mozilla_TimingParams_h 8 #define mozilla_TimingParams_h 9 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 20 21 #include "mozilla/dom/AnimationEffectBinding.h" // for FillMode 22 // and PlaybackDirection 23 24 namespace mozilla { 25 26 namespace dom { 27 class UnrestrictedDoubleOrKeyframeEffectOptions; 28 class UnrestrictedDoubleOrKeyframeAnimationOptions; 29 } // namespace dom 30 31 struct TimingParams { 32 constexpr TimingParams() = default; 33 TimingParamsTimingParams34 TimingParams(float aDuration, float aDelay, float aIterationCount, 35 dom::PlaybackDirection aDirection, dom::FillMode aFillMode) 36 : mIterations(aIterationCount), mDirection(aDirection), mFill(aFillMode) { 37 mDuration.emplace(StickyTimeDuration::FromMilliseconds(aDuration)); 38 mDelay = TimeDuration::FromMilliseconds(aDelay); 39 Update(); 40 } 41 TimingParamsTimingParams42 TimingParams(const TimeDuration& aDuration, const TimeDuration& aDelay, 43 const TimeDuration& aEndDelay, float aIterations, 44 float aIterationStart, dom::PlaybackDirection aDirection, 45 dom::FillMode aFillMode, 46 Maybe<ComputedTimingFunction>&& aFunction) 47 : mDelay(aDelay), 48 mEndDelay(aEndDelay), 49 mIterations(aIterations), 50 mIterationStart(aIterationStart), 51 mDirection(aDirection), 52 mFill(aFillMode), 53 mFunction(aFunction) { 54 mDuration.emplace(aDuration); 55 Update(); 56 } 57 58 template <class OptionsType> 59 static TimingParams FromOptionsType(const OptionsType& aOptions, 60 ErrorResult& aRv); 61 static TimingParams FromOptionsUnion( 62 const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions, 63 ErrorResult& aRv); 64 static TimingParams FromOptionsUnion( 65 const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions, 66 ErrorResult& aRv); 67 static TimingParams FromEffectTiming(const dom::EffectTiming& aEffectTiming, 68 ErrorResult& aRv); 69 // Returns a copy of |aSource| where each timing property in |aSource| that 70 // is also specified in |aEffectTiming| is replaced with the value from 71 // |aEffectTiming|. 72 // 73 // If any of the values in |aEffectTiming| are invalid, |aRv.Failed()| will be 74 // true and an unmodified copy of |aSource| will be returned. 75 static TimingParams MergeOptionalEffectTiming( 76 const TimingParams& aSource, 77 const dom::OptionalEffectTiming& aEffectTiming, ErrorResult& aRv); 78 79 // Range-checks and validates an UnrestrictedDoubleOrString or 80 // OwningUnrestrictedDoubleOrString object and converts to a 81 // StickyTimeDuration value or Nothing() if aDuration is "auto". 82 // Caller must check aRv.Failed(). 83 template <class DoubleOrString> ParseDurationTimingParams84 static Maybe<StickyTimeDuration> ParseDuration(DoubleOrString& aDuration, 85 ErrorResult& aRv) { 86 Maybe<StickyTimeDuration> result; 87 if (aDuration.IsUnrestrictedDouble()) { 88 double durationInMs = aDuration.GetAsUnrestrictedDouble(); 89 if (durationInMs >= 0) { 90 result.emplace(StickyTimeDuration::FromMilliseconds(durationInMs)); 91 } else { 92 nsPrintfCString err("Duration (%g) must be nonnegative", durationInMs); 93 aRv.ThrowTypeError(err); 94 } 95 } else if (!aDuration.GetAsString().EqualsLiteral("auto")) { 96 aRv.ThrowTypeError<dom::MSG_INVALID_DURATION_ERROR>( 97 NS_ConvertUTF16toUTF8(aDuration.GetAsString())); 98 } 99 return result; 100 } 101 ValidateIterationStartTimingParams102 static void ValidateIterationStart(double aIterationStart, ErrorResult& aRv) { 103 if (aIterationStart < 0) { 104 nsPrintfCString err("Iteration start (%g) must not be negative", 105 aIterationStart); 106 aRv.ThrowTypeError(err); 107 } 108 } 109 ValidateIterationsTimingParams110 static void ValidateIterations(double aIterations, ErrorResult& aRv) { 111 if (IsNaN(aIterations)) { 112 aRv.ThrowTypeError("Iterations must not be NaN"); 113 return; 114 } 115 116 if (aIterations < 0) { 117 nsPrintfCString err("Iterations (%g) must not be negative", aIterations); 118 aRv.ThrowTypeError(err); 119 } 120 } 121 122 static Maybe<ComputedTimingFunction> ParseEasing(const nsACString& aEasing, 123 ErrorResult& aRv); 124 CalcActiveDurationTimingParams125 static StickyTimeDuration CalcActiveDuration( 126 const Maybe<StickyTimeDuration>& aDuration, double aIterations) { 127 // If either the iteration duration or iteration count is zero, 128 // Web Animations says that the active duration is zero. This is to 129 // ensure that the result is defined when the other argument is Infinity. 130 static const StickyTimeDuration zeroDuration; 131 if (!aDuration || aDuration->IsZero() || aIterations == 0.0) { 132 return zeroDuration; 133 } 134 135 return aDuration->MultDouble(aIterations); 136 } 137 // Return the duration of the active interval calculated by duration and 138 // iteration count. ActiveDurationTimingParams139 StickyTimeDuration ActiveDuration() const { 140 MOZ_ASSERT(CalcActiveDuration(mDuration, mIterations) == mActiveDuration, 141 "Cached value of active duration should be up to date"); 142 return mActiveDuration; 143 } 144 EndTimeTimingParams145 StickyTimeDuration EndTime() const { 146 MOZ_ASSERT(mEndTime == std::max(mDelay + ActiveDuration() + mEndDelay, 147 StickyTimeDuration()), 148 "Cached value of end time should be up to date"); 149 return mEndTime; 150 } 151 152 bool operator==(const TimingParams& aOther) const; 153 bool operator!=(const TimingParams& aOther) const { 154 return !(*this == aOther); 155 } 156 SetDurationTimingParams157 void SetDuration(Maybe<StickyTimeDuration>&& aDuration) { 158 mDuration = std::move(aDuration); 159 Update(); 160 } SetDurationTimingParams161 void SetDuration(const Maybe<StickyTimeDuration>& aDuration) { 162 mDuration = aDuration; 163 Update(); 164 } DurationTimingParams165 const Maybe<StickyTimeDuration>& Duration() const { return mDuration; } 166 SetDelayTimingParams167 void SetDelay(const TimeDuration& aDelay) { 168 mDelay = aDelay; 169 Update(); 170 } DelayTimingParams171 const TimeDuration& Delay() const { return mDelay; } 172 SetEndDelayTimingParams173 void SetEndDelay(const TimeDuration& aEndDelay) { 174 mEndDelay = aEndDelay; 175 Update(); 176 } EndDelayTimingParams177 const TimeDuration& EndDelay() const { return mEndDelay; } 178 SetIterationsTimingParams179 void SetIterations(double aIterations) { 180 mIterations = aIterations; 181 Update(); 182 } IterationsTimingParams183 double Iterations() const { return mIterations; } 184 SetIterationStartTimingParams185 void SetIterationStart(double aIterationStart) { 186 mIterationStart = aIterationStart; 187 } IterationStartTimingParams188 double IterationStart() const { return mIterationStart; } 189 SetDirectionTimingParams190 void SetDirection(dom::PlaybackDirection aDirection) { 191 mDirection = aDirection; 192 } DirectionTimingParams193 dom::PlaybackDirection Direction() const { return mDirection; } 194 SetFillTimingParams195 void SetFill(dom::FillMode aFill) { mFill = aFill; } FillTimingParams196 dom::FillMode Fill() const { return mFill; } 197 SetTimingFunctionTimingParams198 void SetTimingFunction(Maybe<ComputedTimingFunction>&& aFunction) { 199 mFunction = std::move(aFunction); 200 } TimingFunctionTimingParams201 const Maybe<ComputedTimingFunction>& TimingFunction() const { 202 return mFunction; 203 } 204 205 private: UpdateTimingParams206 void Update() { 207 mActiveDuration = CalcActiveDuration(mDuration, mIterations); 208 209 mEndTime = 210 std::max(mDelay + mActiveDuration + mEndDelay, StickyTimeDuration()); 211 } 212 213 // mDuration.isNothing() represents the "auto" value 214 Maybe<StickyTimeDuration> mDuration; 215 TimeDuration mDelay; // Initializes to zero 216 TimeDuration mEndDelay; 217 double mIterations = 1.0; // Can be NaN, negative, +/-Infinity 218 double mIterationStart = 0.0; 219 dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal; 220 dom::FillMode mFill = dom::FillMode::Auto; 221 Maybe<ComputedTimingFunction> mFunction; 222 StickyTimeDuration mActiveDuration = StickyTimeDuration(); 223 StickyTimeDuration mEndTime = StickyTimeDuration(); 224 }; 225 226 } // namespace mozilla 227 228 #endif // mozilla_TimingParams_h 229