Bug 1244635 - Part1 Add enddelay implementation in dom/animation/AnimationEffectTiming.cpp r=hiro r=bz draft
authorRyo Motozawa <motozawa@mozilla-japan.org>
Tue, 08 Mar 2016 10:31:10 +0900
changeset 337570 77e877a31b29c551961eb31d4091ba7218cad9fa
parent 337411 be593a64d7c6a826260514fe758ef32a6ee580f7
child 337571 5f43fe24f921dcecf3a091e4c37feabd38a3e2b5
push id12400
push userbmo:motoryo1@gmail.com
push dateTue, 08 Mar 2016 01:36:13 +0000
reviewershiro, bz
bugs1244635
milestone48.0a1
Bug 1244635 - Part1 Add enddelay implementation in dom/animation/AnimationEffectTiming.cpp r=hiro r=bz MozReview-Commit-ID: 7t1fm0zB3V
dom/animation/AnimationEffectTiming.cpp
dom/animation/AnimationEffectTiming.h
dom/animation/AnimationEffectTimingReadOnly.cpp
dom/animation/AnimationEffectTimingReadOnly.h
dom/animation/KeyframeEffect.cpp
dom/webidl/AnimationEffectTiming.webidl
--- a/dom/animation/AnimationEffectTiming.cpp
+++ b/dom/animation/AnimationEffectTiming.cpp
@@ -14,16 +14,36 @@ namespace dom {
 
 JSObject*
 AnimationEffectTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return AnimationEffectTimingBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
+AnimationEffectTiming::NotifyTimingUpdate()
+{
+  if (mEffect) {
+    mEffect->NotifySpecifiedTimingUpdated();
+  }
+}
+
+void
+AnimationEffectTiming::SetEndDelay(double aEndDelay)
+{
+  TimeDuration endDelay = TimeDuration::FromMilliseconds(aEndDelay);
+  if (mTiming.mEndDelay == endDelay) {
+    return;
+  }
+  mTiming.mEndDelay = endDelay;
+
+  NotifyTimingUpdate();
+}
+
+void
 AnimationEffectTiming::SetDuration(const UnrestrictedDoubleOrString& aDuration)
 {
   if (mTiming.mDuration.IsUnrestrictedDouble() &&
       aDuration.IsUnrestrictedDouble() &&
       mTiming.mDuration.GetAsUnrestrictedDouble() ==
         aDuration.GetAsUnrestrictedDouble()) {
     return;
   }
@@ -35,15 +55,13 @@ AnimationEffectTiming::SetDuration(const
 
   if (aDuration.IsUnrestrictedDouble()) {
     mTiming.mDuration.SetAsUnrestrictedDouble() =
       aDuration.GetAsUnrestrictedDouble();
   } else {
     mTiming.mDuration.SetAsString() = aDuration.GetAsString();
   }
 
-  if (mEffect) {
-    mEffect->NotifySpecifiedTimingUpdated();
-  }
+  NotifyTimingUpdate();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/animation/AnimationEffectTiming.h
+++ b/dom/animation/AnimationEffectTiming.h
@@ -19,18 +19,20 @@ public:
   AnimationEffectTiming(const TimingParams& aTiming, KeyframeEffect* aEffect)
     : AnimationEffectTimingReadOnly(aTiming)
     , mEffect(aEffect) { }
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void Unlink() override { mEffect = nullptr; }
 
+  void SetEndDelay(double aEndDelay);
   void SetDuration(const UnrestrictedDoubleOrString& aDuration);
 
 private:
+  void NotifyTimingUpdate();
   KeyframeEffect* MOZ_NON_OWNING_REF mEffect;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_AnimationEffectTiming_h
--- a/dom/animation/AnimationEffectTimingReadOnly.cpp
+++ b/dom/animation/AnimationEffectTimingReadOnly.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/dom/KeyframeEffectBinding.h"
 
 namespace mozilla {
 
 TimingParams::TimingParams(const dom::AnimationEffectTimingProperties& aRhs,
                            const dom::Element* aTarget)
   : mDuration(aRhs.mDuration)
   , mDelay(TimeDuration::FromMilliseconds(aRhs.mDelay))
+  , mEndDelay(TimeDuration::FromMilliseconds(aRhs.mEndDelay))
   , mIterations(aRhs.mIterations)
   , mIterationStart(aRhs.mIterationStart)
   , mDirection(aRhs.mDirection)
   , mFill(aRhs.mFill)
 {
   mFunction = AnimationUtils::ParseEasing(aTarget, aRhs.mEasing);
 }
 
--- a/dom/animation/AnimationEffectTimingReadOnly.h
+++ b/dom/animation/AnimationEffectTimingReadOnly.h
@@ -45,16 +45,17 @@ struct TimingParams
   static TimingParams FromOptionsUnion(
     const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
     const Nullable<dom::ElementOrCSSPseudoElement>& aTarget);
 
   // The unitialized state of mDuration represents "auto".
   // Bug 1237173: We will replace this with Maybe<TimeDuration>.
   dom::OwningUnrestrictedDoubleOrString mDuration;
   TimeDuration mDelay;      // Initializes to zero
+  TimeDuration mEndDelay;
   double mIterations = 1.0; // Can be NaN, negative, +/-Infinity
   double mIterationStart = 0.0;
   dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal;
   dom::FillMode mFill = dom::FillMode::Auto;
   Maybe<ComputedTimingFunction> mFunction;
 
   bool operator==(const TimingParams& aOther) const;
   bool operator!=(const TimingParams& aOther) const
@@ -79,17 +80,17 @@ public:
 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; }
+  double EndDelay() const { return mTiming.mEndDelay.ToMilliseconds(); }
   FillMode Fill() const { return mTiming.mFill; }
   double IterationStart() const { return mTiming.mIterationStart; }
   double Iterations() const { return mTiming.mIterations; }
   void GetDuration(OwningUnrestrictedDoubleOrString& aRetVal) const
   {
     aRetVal = mTiming.mDuration;
   }
   PlaybackDirection Direction() const { return mTiming.mDirection; }
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -29,16 +29,17 @@ namespace mozilla {
 static void
 GetComputedTimingDictionary(const ComputedTiming& aComputedTiming,
                             const Nullable<TimeDuration>& aLocalTime,
                             const TimingParams& aTiming,
                             dom::ComputedTimingProperties& aRetVal)
 {
   // AnimationEffectTimingProperties
   aRetVal.mDelay = aTiming.mDelay.ToMilliseconds();
+  aRetVal.mEndDelay = aTiming.mEndDelay.ToMilliseconds();
   aRetVal.mFill = aComputedTiming.mFill;
   aRetVal.mIterations = aComputedTiming.mIterations;
   aRetVal.mIterationStart = aComputedTiming.mIterationStart;
   aRetVal.mDuration.SetAsUnrestrictedDouble() =
     aComputedTiming.mDuration.ToMilliseconds();
   aRetVal.mDirection = aTiming.mDirection;
 
   // ComputedTimingProperties
@@ -244,18 +245,18 @@ KeyframeEffectReadOnly::GetComputedTimin
     }
   }
   result.mIterations = IsNaN(aTiming.mIterations) || aTiming.mIterations < 0.0f ?
                        1.0f :
                        aTiming.mIterations;
   result.mIterationStart = std::max(aTiming.mIterationStart, 0.0);
 
   result.mActiveDuration = ActiveDuration(result.mDuration, result.mIterations);
-  // Bug 1244635: Add endDelay to the end time calculation
-  result.mEndTime = aTiming.mDelay + result.mActiveDuration;
+  result.mEndTime = aTiming.mDelay + result.mActiveDuration +
+                    aTiming.mEndDelay;
   result.mFill = aTiming.mFill == dom::FillMode::Auto ?
                  dom::FillMode::None :
                  aTiming.mFill;
 
   // The default constructor for ComputedTiming sets all other members to
   // values consistent with an animation that has not been sampled.
   if (aLocalTime.IsNull()) {
     return result;
@@ -264,30 +265,33 @@ KeyframeEffectReadOnly::GetComputedTimin
 
   // When we finish exactly at the end of an iteration we need to report
   // the end of the final iteration and not the start of the next iteration
   // so we set up a flag for that case.
   bool isEndOfFinalIteration = false;
 
   // Get the normalized time within the active interval.
   StickyTimeDuration activeTime;
-  if (localTime >= aTiming.mDelay + result.mActiveDuration) {
+  if (localTime >=
+        std::min(StickyTimeDuration(aTiming.mDelay + result.mActiveDuration),
+                 result.mEndTime)) {
     result.mPhase = ComputedTiming::AnimationPhase::After;
     if (!result.FillsForwards()) {
       // The animation isn't active or filling at this time.
       result.mProgress.SetNull();
       return result;
     }
     activeTime = result.mActiveDuration;
     double finiteProgress =
       (IsInfinite(result.mIterations) ? 0.0 : result.mIterations)
       + result.mIterationStart;
     isEndOfFinalIteration = result.mIterations != 0.0 &&
                             fmod(finiteProgress, 1.0) == 0;
-  } else if (localTime < aTiming.mDelay) {
+  } else if (localTime <
+               std::min(StickyTimeDuration(aTiming.mDelay), result.mEndTime)) {
     result.mPhase = ComputedTiming::AnimationPhase::Before;
     if (!result.FillsBackwards()) {
       // The animation isn't active or filling at this time.
       result.mProgress.SetNull();
       return result;
     }
     // activeTime is zero
   } else {
--- a/dom/webidl/AnimationEffectTiming.webidl
+++ b/dom/webidl/AnimationEffectTiming.webidl
@@ -9,18 +9,17 @@
  * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [Func="nsDocument::IsWebAnimationsEnabled"]
 interface AnimationEffectTiming : AnimationEffectTimingReadOnly {
    //Bug 1244633 - implement AnimationEffectTiming delay
    //inherit attribute double                             delay;
-   //Bug 1244635 - implement AnimationEffectTiming endDelay
-   //inherit attribute double                             endDelay;
+   inherit attribute double                             endDelay;
    //Bug 1244637 - implement AnimationEffectTiming fill
    //inherit attribute FillMode                           fill;
    //Bug 1244638 - implement AnimationEffectTiming iterationStart
    //inherit attribute double                             iterationStart;
    //Bug 1244640 - implement AnimationEffectTiming iterations
    //inherit attribute unrestricted double                iterations;
    inherit attribute (unrestricted double or DOMString) duration;
    //Bug 1244642 - implement AnimationEffectTiming direction