Bug 1214536 - Part 5: Add AnimationEffectTimingReadOnly interface. r=birtles, r=smaug
authorBoris Chiou <boris.chiou@gmail.com>
Wed, 13 Jan 2016 18:37:00 +0100
changeset 321794 941bb74fe4b9ab8eac3a87fbc6e79796ec54102f
parent 321793 03040a9d904609ab2dd710f944f50b321867eeb3
child 321795 cc73b26599341c6c0cc2da34e29e3859643e9655
push id9465
push userdmitchell@mozilla.com
push dateThu, 14 Jan 2016 21:39:58 +0000
reviewersbirtles, smaug
bugs1214536
milestone46.0a1
Bug 1214536 - Part 5: Add AnimationEffectTimingReadOnly interface. r=birtles, r=smaug 1. Add AnimationEffectTimingReadOnly.webidl. 2. Add AnimationEffectTimingReadOnly cpp files. 3. Use AnimationEffectTimingReadOnly as KeyframeEffectReadOnly::mTiming.
dom/animation/AnimationEffectReadOnly.h
dom/animation/AnimationEffectTimingReadOnly.cpp
dom/animation/AnimationEffectTimingReadOnly.h
dom/animation/ComputedTimingFunction.h
dom/animation/KeyframeEffect.cpp
dom/animation/KeyframeEffect.h
dom/animation/moz.build
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/AnimationEffectReadOnly.webidl
dom/webidl/AnimationEffectTimingReadOnly.webidl
dom/webidl/moz.build
layout/style/nsAnimationManager.h
layout/style/nsTransitionManager.cpp
--- a/dom/animation/AnimationEffectReadOnly.h
+++ b/dom/animation/AnimationEffectReadOnly.h
@@ -9,32 +9,35 @@
 
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace dom {
 
+class AnimationEffectTimingReadOnly;
 struct ComputedTimingProperties;
 
 class AnimationEffectReadOnly : public nsISupports,
                                 public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationEffectReadOnly)
 
   explicit AnimationEffectReadOnly(nsISupports* aParent)
     : mParent(aParent)
   {
   }
 
   nsISupports* GetParentObject() const { return mParent; }
 
+  virtual already_AddRefed<AnimationEffectTimingReadOnly> TimingAsObject() const = 0;
+
   virtual void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const
   {
   }
 
 protected:
   virtual ~AnimationEffectReadOnly() = default;
 
 protected:
new file mode 100644
--- /dev/null
+++ b/dom/animation/AnimationEffectTimingReadOnly.cpp
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/AnimationEffectTimingReadOnly.h"
+#include "mozilla/dom/AnimationEffectTimingReadOnlyBinding.h"
+
+namespace mozilla {
+
+bool
+AnimationTiming::operator==(const AnimationTiming& aOther) const
+{
+  bool durationEqual;
+  if (mDuration.IsUnrestrictedDouble()) {
+    durationEqual = aOther.mDuration.IsUnrestrictedDouble() &&
+                    (mDuration.GetAsUnrestrictedDouble() ==
+                     aOther.mDuration.GetAsUnrestrictedDouble());
+  } else if (mDuration.IsString()) {
+    durationEqual = aOther.mDuration.IsString() &&
+                    (mDuration.GetAsString() ==
+                     aOther.mDuration.GetAsString());
+  } else {
+    // Check if both are uninitialized
+    durationEqual = !aOther.mDuration.IsUnrestrictedDouble() &&
+                    !aOther.mDuration.IsString();
+  }
+  return durationEqual &&
+         mDelay == aOther.mDelay &&
+         mIterations == aOther.mIterations &&
+         mDirection == aOther.mDirection &&
+         mFill == aOther.mFill;
+}
+
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationEffectTimingReadOnly, mParent)
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AnimationEffectTimingReadOnly, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnimationEffectTimingReadOnly, Release)
+
+JSObject*
+AnimationEffectTimingReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return AnimationEffectTimingReadOnlyBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/animation/AnimationEffectTimingReadOnly.h
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_AnimationEffectTimingReadOnly_h
+#define mozilla_dom_AnimationEffectTimingReadOnly_h
+
+#include "js/TypeDecls.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/UnionTypes.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
+
+// X11 has a #define for None
+#ifdef None
+#undef None
+#endif
+#include "mozilla/dom/AnimationEffectReadOnlyBinding.h"  // for FillMode
+                                                         // and PlaybackDirection
+
+namespace mozilla {
+
+struct AnimationTiming
+{
+  // The unitialized state of mDuration represents "auto".
+  // Bug 1237173: We will replace this with Maybe<TimeDuration>.
+  dom::OwningUnrestrictedDoubleOrString mDuration;
+  TimeDuration mDelay;      // Initializes to zero
+  double mIterations = 1.0; // Can be NaN, negative, +/-Infinity
+  dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal;
+  dom::FillMode mFill = dom::FillMode::Auto;
+
+  bool operator==(const AnimationTiming& aOther) const;
+  bool operator!=(const AnimationTiming& aOther) const
+  {
+    return !(*this == aOther);
+  }
+};
+
+
+namespace dom {
+
+class AnimationEffectTimingReadOnly : public nsWrapperCache
+{
+public:
+  AnimationEffectTimingReadOnly() = default;
+  explicit AnimationEffectTimingReadOnly(const AnimationTiming& aTiming)
+    : mTiming(aTiming) { }
+
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnimationEffectTimingReadOnly)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AnimationEffectTimingReadOnly)
+
+protected:
+  virtual ~AnimationEffectTimingReadOnly() = default;
+
+public:
+  nsISupports* GetParentObject() const { return mParent; }
+  JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  double Delay() const { return mTiming.mDelay.ToMilliseconds(); }
+  double EndDelay() const { return 0.0; }
+  FillMode Fill() const { return mTiming.mFill; }
+  double IterationStart() const { return 0.0; }
+  double Iterations() const { return mTiming.mIterations; }
+  void GetDuration(OwningUnrestrictedDoubleOrString& aRetVal) const
+  {
+    aRetVal = mTiming.mDuration;
+  }
+  PlaybackDirection Direction() const { return mTiming.mDirection; }
+  void GetEasing(nsString& aRetVal) const { aRetVal.AssignLiteral("linear"); }
+
+  const AnimationTiming& Timing() const { return mTiming; }
+  void SetTiming(const AnimationTiming& aTiming) { mTiming = aTiming; }
+
+protected:
+  nsCOMPtr<nsISupports> mParent;
+  AnimationTiming mTiming;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_AnimationEffectTimingReadOnly_h
--- a/dom/animation/ComputedTimingFunction.h
+++ b/dom/animation/ComputedTimingFunction.h
@@ -45,9 +45,9 @@ private:
   nsTimingFunction::Type mType;
   nsSMILKeySpline mTimingFunction;
   uint32_t mSteps;
   nsTimingFunction::StepSyntax mStepSyntax;
 };
 
 } // namespace mozilla
 
-#endif // mozilla_dom_AnimationEffectReadOnly_h
+#endif // mozilla_ComputedTimingFunction_h
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -73,21 +73,22 @@ NS_IMPL_RELEASE_INHERITED(KeyframeEffect
 
 KeyframeEffectReadOnly::KeyframeEffectReadOnly(
   nsIDocument* aDocument,
   Element* aTarget,
   nsCSSPseudoElements::Type aPseudoType,
   const AnimationTiming& aTiming)
   : AnimationEffectReadOnly(aDocument)
   , mTarget(aTarget)
-  , mTiming(aTiming)
   , mPseudoType(aPseudoType)
   , mInEffectOnLastAnimationTimingUpdate(false)
 {
   MOZ_ASSERT(aTarget, "null animation target is not yet supported");
+
+  mTiming = new AnimationEffectTimingReadOnly(aTiming);
 }
 
 JSObject*
 KeyframeEffectReadOnly::WrapObject(JSContext* aCx,
                                    JS::Handle<JSObject*> aGivenProto)
 {
   return KeyframeEffectReadOnlyBinding::Wrap(aCx, this, aGivenProto);
 }
@@ -99,23 +100,30 @@ KeyframeEffectReadOnly::IterationComposi
 }
 
 CompositeOperation
 KeyframeEffectReadOnly::Composite() const
 {
   return CompositeOperation::Replace;
 }
 
+already_AddRefed<AnimationEffectTimingReadOnly>
+KeyframeEffectReadOnly::TimingAsObject() const
+{
+  RefPtr<AnimationEffectTimingReadOnly> temp(mTiming);
+  return temp.forget();
+}
+
 void
 KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming)
 {
-  if (mTiming == aTiming) {
+  if (mTiming->Timing() == aTiming) {
     return;
   }
-  mTiming = aTiming;
+  mTiming->SetTiming(aTiming);
   if (mAnimation) {
     mAnimation->NotifyEffectTimingUpdated();
   }
   // NotifyEffectTimingUpdated will eventually cause
   // NotifyAnimationTimingUpdated to be called on this object which will
   // update our registration with the target element.
 }
 
@@ -186,19 +194,19 @@ KeyframeEffectReadOnly::GetLocalTime() c
   }
   return result;
 }
 
 void
 KeyframeEffectReadOnly::GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const
 {
   const Nullable<TimeDuration> currentTime = GetLocalTime();
-  GetComputedTimingDictionary(GetComputedTimingAt(currentTime, mTiming),
+  GetComputedTimingDictionary(GetComputedTimingAt(currentTime, Timing()),
                               currentTime,
-                              mTiming,
+                              Timing(),
                               aRetVal);
 }
 
 ComputedTiming
 KeyframeEffectReadOnly::GetComputedTimingAt(
                           const Nullable<TimeDuration>& aLocalTime,
                           const AnimationTiming& aTiming)
 {
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -10,30 +10,26 @@
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCSSPseudoElements.h"
 #include "nsIDocument.h"
 #include "nsWrapperCache.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction
 #include "mozilla/LayerAnimationInfo.h"     // LayerAnimations::kRecords
+#include "mozilla/OwningNonNull.h"          // OwningNonNull<...>
 #include "mozilla/StickyTimeDuration.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/AnimationEffectReadOnly.h"
+#include "mozilla/dom/AnimationEffectTimingReadOnly.h" // AnimationTiming
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/KeyframeBinding.h"
 #include "mozilla/dom/Nullable.h"
-#include "mozilla/dom/UnionTypes.h"
 
-// Fix X11 header brain damage that conflicts with dom::FillMode::None
-#ifdef None
-#undef None
-#endif
-#include "mozilla/dom/AnimationEffectReadOnlyBinding.h"
 
 struct JSContext;
 class nsCSSPropertySet;
 class nsIContent;
 class nsIDocument;
 class nsIFrame;
 class nsPresContext;
 
@@ -44,57 +40,16 @@ class AnimValuesStyleRule;
 
 namespace dom {
 class UnrestrictedDoubleOrKeyframeEffectOptions;
 enum class IterationCompositeOperation : uint32_t;
 enum class CompositeOperation : uint32_t;
 }
 
 /**
- * Input timing parameters.
- *
- * Eventually this will represent all the input timing parameters specified
- * by content but for now it encapsulates just the subset of those
- * parameters passed to GetPositionInIteration.
- */
-struct AnimationTiming
-{
-  dom::OwningUnrestrictedDoubleOrString mDuration;
-  TimeDuration mDelay;
-  double mIterations; // Can be NaN, negative, +/-Infinity
-  dom::PlaybackDirection mDirection;
-  dom::FillMode mFill;
-
-  bool operator==(const AnimationTiming& aOther) const {
-    bool durationEqual;
-    if (mDuration.IsUnrestrictedDouble()) {
-      durationEqual = aOther.mDuration.IsUnrestrictedDouble() &&
-                      (mDuration.GetAsUnrestrictedDouble() ==
-                       aOther.mDuration.GetAsUnrestrictedDouble());
-    } else if (mDuration.IsString()) {
-      durationEqual = aOther.mDuration.IsString() &&
-                      (mDuration.GetAsString() ==
-                       aOther.mDuration.GetAsString());
-    } else {
-      // Check if both are uninitialized
-      durationEqual = !aOther.mDuration.IsUnrestrictedDouble() &&
-                      !aOther.mDuration.IsString();
-    }
-    return durationEqual &&
-           mDelay == aOther.mDelay &&
-           mIterations == aOther.mIterations &&
-           mDirection == aOther.mDirection &&
-           mFill == aOther.mFill;
-  }
-  bool operator!=(const AnimationTiming& aOther) const {
-    return !(*this == aOther);
-  }
-};
-
-/**
  * Stores the results of calculating the timing properties of an animation
  * at a given sample time.
  */
 struct ComputedTiming
 {
   // The total duration of the animation including all iterations.
   // Will equal StickyTimeDuration::Forever() if the animation repeats
   // indefinitely.
@@ -259,19 +214,19 @@ public:
   }
 
   IterationCompositeOperation IterationComposite() const;
   CompositeOperation Composite() const;
   void GetSpacing(nsString& aRetVal) const {
     aRetVal.AssignLiteral("distribute");
   }
 
-  const AnimationTiming& Timing() const { return mTiming; }
-  AnimationTiming& Timing() { return mTiming; }
+  const AnimationTiming& Timing() const { return mTiming->Timing(); }
   void SetTiming(const AnimationTiming& aTiming);
+  already_AddRefed<AnimationEffectTimingReadOnly> TimingAsObject() const override;
   void NotifyAnimationTimingUpdated();
 
   Nullable<TimeDuration> GetLocalTime() const;
 
   // This function takes as input the timing parameters of an animation and
   // returns the computed timing at the specified local time.
   //
   // The local time may be null in which case only static parameters such as the
@@ -285,17 +240,17 @@ public:
   GetComputedTimingAt(const Nullable<TimeDuration>& aLocalTime,
                       const AnimationTiming& aTiming);
 
   // Shortcut for that gets the computed timing using the current local time as
   // calculated from the timeline time.
   ComputedTiming
   GetComputedTiming(const AnimationTiming* aTiming = nullptr) const
   {
-    return GetComputedTimingAt(GetLocalTime(), aTiming ? *aTiming : mTiming);
+    return GetComputedTimingAt(GetLocalTime(), aTiming ? *aTiming : Timing());
   }
 
   void
   GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const override;
 
   // Return the duration of the active interval for the given duration and
   // iteration count.
   static StickyTimeDuration
@@ -381,17 +336,17 @@ protected:
     Element* aTarget,
     const Optional<JS::Handle<JSObject*>>& aFrames,
     InfallibleTArray<AnimationProperty>& aResult,
     ErrorResult& aRv);
 
   nsCOMPtr<Element> mTarget;
   RefPtr<Animation> mAnimation;
 
-  AnimationTiming mTiming;
+  OwningNonNull<AnimationEffectTimingReadOnly> mTiming;
   nsCSSPseudoElements::Type mPseudoType;
 
   InfallibleTArray<AnimationProperty> mProperties;
 
   // The computed progress last time we composed the style rule. This is
   // used to detect when the progress is not changing (e.g. due to a step
   // timing function) so we can avoid unnecessary style updates.
   Nullable<double> mProgressOnLastCompose;
--- a/dom/animation/moz.build
+++ b/dom/animation/moz.build
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 EXPORTS.mozilla.dom += [
     'Animation.h',
     'AnimationEffectReadOnly.h',
+    'AnimationEffectTimingReadOnly.h',
     'AnimationTimeline.h',
     'DocumentTimeline.h',
     'KeyframeEffect.h',
 ]
 
 EXPORTS.mozilla += [
     'AnimationComparator.h',
     'AnimationUtils.h',
@@ -24,16 +25,17 @@ EXPORTS.mozilla += [
     'EffectSet.h',
     'PendingAnimationTracker.h',
     'PseudoElementHashEntry.h',
 ]
 
 UNIFIED_SOURCES += [
     'Animation.cpp',
     'AnimationEffectReadOnly.cpp',
+    'AnimationEffectTimingReadOnly.cpp',
     'AnimationTimeline.cpp',
     'AnimationUtils.cpp',
     'AnimValuesStyleRule.cpp',
     'ComputedTimingFunction.cpp',
     'DocumentTimeline.cpp',
     'EffectCompositor.cpp',
     'EffectSet.cpp',
     'KeyframeEffect.cpp',
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -124,16 +124,18 @@ var interfaceNamesInGlobalScope =
     {name: "AlarmsManager", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AnalyserNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Animation", release: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "AnimationEffectReadOnly", release: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "AnimationEffectTimingReadOnly", release: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "AnimationEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "AnimationPlaybackEvent", release: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "AnimationTimeline", release: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Attr",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/AnimationEffectReadOnly.webidl
+++ b/dom/webidl/AnimationEffectReadOnly.webidl
@@ -41,14 +41,13 @@ dictionary ComputedTimingProperties : An
   unrestricted double   activeDuration = 0.0;
   double?               localTime = null;
   unrestricted double?  progress = null;
   unrestricted double?  currentIteration = null;
 };
 
 [Func="nsDocument::IsWebAnimationsEnabled"]
 interface AnimationEffectReadOnly {
-  // Not yet implemented:
-  // readonly attribute AnimationEffectTimingReadOnly timing;
-
+  [Cached, Constant, BinaryName="timingAsObject"]
+  readonly attribute AnimationEffectTimingReadOnly timing;
   [BinaryName="getComputedTimingAsDict"]
   ComputedTimingProperties getComputedTiming();
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/AnimationEffectTimingReadOnly.webidl
@@ -0,0 +1,23 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://w3c.github.io/web-animations/#animationeffecttimingreadonly
+ *
+ * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[Func="nsDocument::IsWebAnimationsEnabled"]
+interface AnimationEffectTimingReadOnly {
+  readonly attribute double                             delay;
+  readonly attribute double                             endDelay;
+  readonly attribute FillMode                           fill;
+  readonly attribute double                             iterationStart;
+  readonly attribute unrestricted double                iterations;
+  readonly attribute (unrestricted double or DOMString) duration;
+  readonly attribute PlaybackDirection                  direction;
+  readonly attribute DOMString                          easing;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -19,16 +19,17 @@ WEBIDL_FILES = [
     'AbortablePromise.webidl',
     'AbstractWorker.webidl',
     'ActivityRequestHandler.webidl',
     'AlarmsManager.webidl',
     'AnalyserNode.webidl',
     'Animatable.webidl',
     'Animation.webidl',
     'AnimationEffectReadOnly.webidl',
+    'AnimationEffectTimingReadOnly.webidl',
     'AnimationEvent.webidl',
     'AnimationTimeline.webidl',
     'AnonymousContent.webidl',
     'AppInfo.webidl',
     'AppNotificationServiceOptions.webidl',
     'Apps.webidl',
     'APZTestData.webidl',
     'ArchiveReader.webidl',
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -164,17 +164,17 @@ protected:
 
   // Animation overrides
   void UpdateTiming(SeekFlag aSeekFlag,
                     SyncNotifyFlag aSyncNotifyFlag) override;
 
   // Returns the duration from the start of the animation's source effect's
   // active interval to the point where the animation actually begins playback.
   // This is zero unless the animation's source effect has a negative delay in
-  // which // case it is the absolute value of that delay.
+  // which case it is the absolute value of that delay.
   // This is used for setting the elapsedTime member of CSS AnimationEvents.
   TimeDuration InitialAdvance() const {
     return mEffect ?
            std::max(TimeDuration(), mEffect->Timing().mDelay * -1) :
            TimeDuration();
   }
   // Converts an AnimationEvent's elapsedTime value to an equivalent TimeStamp
   // that can be used to sort events by when they occurred.
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -50,17 +50,17 @@ ElementPropertyTransition::CurrentValueP
              "sampled");
 
   // Transitions use a fill mode of 'backwards' so GetComputedTiming will
   // never return a null time progress due to being *before* the animation
   // interval. However, it might be possible that we're behind on flushing
   // causing us to get called *after* the animation interval. So, just in
   // case, we override the fill mode to 'both' to ensure the progress
   // is never null.
-  AnimationTiming timingToUse = mTiming;
+  AnimationTiming timingToUse = Timing();
   timingToUse.mFill = dom::FillMode::Both;
   ComputedTiming computedTiming = GetComputedTiming(&timingToUse);
 
   MOZ_ASSERT(!computedTiming.mProgress.IsNull(),
              "Got a null progress for a fill mode of 'both'");
   MOZ_ASSERT(mProperties.Length() == 1,
              "Should have one animation property for a transition");
   MOZ_ASSERT(mProperties[0].mSegments.Length() == 1,