tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TimingParams.h (9734B)


      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 "mozilla/Maybe.h"
     12 #include "mozilla/ServoStyleConsts.h"
     13 #include "mozilla/StickyTimeDuration.h"
     14 #include "mozilla/TimeStamp.h"                   // for TimeDuration
     15 #include "mozilla/dom/AnimationEffectBinding.h"  // for FillMode
     16 #include "mozilla/dom/Nullable.h"
     17 #include "mozilla/dom/UnionTypes.h"  // For OwningUnrestrictedDoubleOrString
     18 #include "nsPrintfCString.h"
     19 #include "nsStringFwd.h"
     20 // and PlaybackDirection
     21 
     22 namespace mozilla {
     23 
     24 namespace dom {
     25 class UnrestrictedDoubleOrKeyframeEffectOptions;
     26 class UnrestrictedDoubleOrKeyframeAnimationOptions;
     27 }  // namespace dom
     28 
     29 struct TimingParams {
     30  TimingParams() = default;
     31 
     32  TimingParams(Maybe<float> aDuration, float aDelay, float aIterationCount,
     33               dom::PlaybackDirection aDirection, dom::FillMode aFillMode)
     34      : mIterations(aIterationCount), mDirection(aDirection), mFill(aFillMode) {
     35    if (aDuration) {
     36      mDuration.emplace(StickyTimeDuration::FromMilliseconds(*aDuration));
     37    }
     38    mDelay = TimeDuration::FromMilliseconds(aDelay);
     39    Update();
     40  }
     41 
     42  TimingParams(const TimeDuration& aDuration, const TimeDuration& aDelay,
     43               const TimeDuration& aEndDelay, float aIterations,
     44               float aIterationStart, dom::PlaybackDirection aDirection,
     45               dom::FillMode aFillMode,
     46               const Maybe<StyleComputedTimingFunction>& 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>
     84  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 
    102  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 
    110  static void ValidateIterations(double aIterations, ErrorResult& aRv) {
    111    if (std::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<StyleComputedTimingFunction> ParseEasing(const nsACString&,
    123                                                        ErrorResult&);
    124 
    125  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    MOZ_ASSERT(*aDuration >= zeroDuration && aIterations >= 0.0,
    136               "Both animation duration and ieration count should be greater "
    137               "than zero");
    138 
    139    StickyTimeDuration result = aDuration->MultDouble(aIterations);
    140    if (result < zeroDuration) {
    141      // If the result of multiplying above is less than zero, it's likely an
    142      // overflow happened. we consider it's +Inf here.
    143      return StickyTimeDuration::Forever();
    144    }
    145    return result;
    146  }
    147  // Return the duration of the active interval calculated by duration and
    148  // iteration count.
    149  StickyTimeDuration ActiveDuration() const {
    150    MOZ_ASSERT(CalcActiveDuration(mDuration, mIterations) == mActiveDuration,
    151               "Cached value of active duration should be up to date");
    152    return mActiveDuration;
    153  }
    154 
    155  StickyTimeDuration EndTime() const {
    156    MOZ_ASSERT(mEndTime == CalcEndTime(),
    157               "Cached value of end time should be up to date");
    158    return mEndTime;
    159  }
    160 
    161  StickyTimeDuration CalcBeforeActiveBoundary() const {
    162    static constexpr StickyTimeDuration zeroDuration;
    163    // https://drafts.csswg.org/web-animations-1/#before-active-boundary-time
    164    return std::clamp(StickyTimeDuration(mDelay), zeroDuration, mEndTime);
    165  }
    166 
    167  StickyTimeDuration CalcActiveAfterBoundary() const {
    168    if (mActiveDuration == StickyTimeDuration::Forever()) {
    169      return StickyTimeDuration::Forever();
    170    }
    171 
    172    static constexpr StickyTimeDuration zeroDuration;
    173    // https://drafts.csswg.org/web-animations-1/#active-after-boundary-time
    174    return std::max(
    175        std::min(StickyTimeDuration(mDelay + mActiveDuration), mEndTime),
    176        zeroDuration);
    177  }
    178 
    179  bool operator==(const TimingParams& aOther) const;
    180  bool operator!=(const TimingParams& aOther) const {
    181    return !(*this == aOther);
    182  }
    183 
    184  void SetDuration(Maybe<StickyTimeDuration>&& aDuration) {
    185    mDuration = std::move(aDuration);
    186    Update();
    187  }
    188  void SetDuration(const Maybe<StickyTimeDuration>& aDuration) {
    189    mDuration = aDuration;
    190    Update();
    191  }
    192  const Maybe<StickyTimeDuration>& Duration() const { return mDuration; }
    193 
    194  void SetDelay(const TimeDuration& aDelay) {
    195    mDelay = aDelay;
    196    Update();
    197  }
    198  const TimeDuration& Delay() const { return mDelay; }
    199 
    200  void SetEndDelay(const TimeDuration& aEndDelay) {
    201    mEndDelay = aEndDelay;
    202    Update();
    203  }
    204  const TimeDuration& EndDelay() const { return mEndDelay; }
    205 
    206  void SetIterations(double aIterations) {
    207    mIterations = aIterations;
    208    Update();
    209  }
    210  double Iterations() const { return mIterations; }
    211 
    212  void SetIterationStart(double aIterationStart) {
    213    mIterationStart = aIterationStart;
    214  }
    215  double IterationStart() const { return mIterationStart; }
    216 
    217  void SetDirection(dom::PlaybackDirection aDirection) {
    218    mDirection = aDirection;
    219  }
    220  dom::PlaybackDirection Direction() const { return mDirection; }
    221 
    222  void SetFill(dom::FillMode aFill) { mFill = aFill; }
    223  dom::FillMode Fill() const { return mFill; }
    224 
    225  void SetTimingFunction(Maybe<StyleComputedTimingFunction>&& aFunction) {
    226    mFunction = std::move(aFunction);
    227  }
    228  const Maybe<StyleComputedTimingFunction>& TimingFunction() const {
    229    return mFunction;
    230  }
    231 
    232  // This is called only for progress-based timeline (i.e. non-monotonic
    233  // timeline). That is, |aTimelineDuration| should be resolved already.
    234  TimingParams Normalize(const TimeDuration& aTimelineDuration) const;
    235 
    236 private:
    237  void Update() {
    238    mActiveDuration = CalcActiveDuration(mDuration, mIterations);
    239    mEndTime = CalcEndTime();
    240  }
    241 
    242  StickyTimeDuration CalcEndTime() const {
    243    if (mActiveDuration == StickyTimeDuration::Forever()) {
    244      return StickyTimeDuration::Forever();
    245    }
    246    return std::max(mDelay + mActiveDuration + mEndDelay, StickyTimeDuration());
    247  }
    248 
    249  // mDuration.isNothing() represents the "auto" value
    250  Maybe<StickyTimeDuration> mDuration;
    251  TimeDuration mDelay;  // Initializes to zero
    252  TimeDuration mEndDelay;
    253  double mIterations = 1.0;  // Can be NaN, negative, +/-Infinity
    254  double mIterationStart = 0.0;
    255  dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal;
    256  dom::FillMode mFill = dom::FillMode::Auto;
    257  Maybe<StyleComputedTimingFunction> mFunction;
    258  StickyTimeDuration mActiveDuration = StickyTimeDuration();
    259  StickyTimeDuration mEndTime = StickyTimeDuration();
    260 };
    261 
    262 }  // namespace mozilla
    263 
    264 #endif  // mozilla_TimingParams_h