Bug 1248340 - Part 2: Implement Frames in ComputedTimingFunction. r=birtles draft
authorBoris Chiou <boris.chiou@gmail.com>
Fri, 24 Feb 2017 16:59:02 +0800
changeset 495025 abe5d7f924313be89e3790c502403e2301142fe0
parent 495024 b549b283ecdf98788b8de3b47b52299e0504abe3
child 495026 546b4060e723e7df29fde9d17a025216998f06cf
push id48204
push userbmo:boris.chiou@gmail.com
push dateWed, 08 Mar 2017 05:44:16 +0000
reviewersbirtles
bugs1248340
milestone55.0a1
Bug 1248340 - Part 2: Implement Frames in ComputedTimingFunction. r=birtles MozReview-Commit-ID: 92MAv3OD8Tu
dom/animation/ComputedTimingFunction.cpp
dom/animation/ComputedTimingFunction.h
--- a/dom/animation/ComputedTimingFunction.cpp
+++ b/dom/animation/ComputedTimingFunction.cpp
@@ -13,20 +13,17 @@ namespace mozilla {
 void
 ComputedTimingFunction::Init(const nsTimingFunction &aFunction)
 {
   mType = aFunction.mType;
   if (nsTimingFunction::IsSplineType(mType)) {
     mTimingFunction.Init(aFunction.mFunc.mX1, aFunction.mFunc.mY1,
                          aFunction.mFunc.mX2, aFunction.mFunc.mY2);
   } else {
-    // TODO: Support Frames
-    MOZ_ASSERT(nsTimingFunction::Type::StepStart ||
-               nsTimingFunction::Type::StepEnd);
-    mSteps = aFunction.mStepsOrFrames;
+    mStepsOrFrames = aFunction.mStepsOrFrames;
   }
 }
 
 static inline double
 StepTiming(uint32_t aSteps,
            double aPortion,
            ComputedTimingFunction::BeforeFlag aBeforeFlag,
            nsTimingFunction::Type aType)
@@ -56,17 +53,32 @@ StepTiming(uint32_t aSteps,
   // input outside that range. This takes care of steps that would otherwise
   // occur at boundaries.
   if (result < 0.0 && aPortion >= 0.0) {
     return 0.0;
   }
   if (result > 1.0 && aPortion <= 1.0) {
     return 1.0;
   }
+  return result;
+}
 
+static inline double
+FramesTiming(uint32_t aFrames, double aPortion)
+{
+  MOZ_ASSERT(aFrames > 1, "the number of frames must be greater than 1");
+  int32_t currentFrame = floor(aPortion * aFrames);
+  double result = double(currentFrame) / double(aFrames - 1);
+
+  // Don't overshoot the natural range of the animation (by producing an output
+  // progress greater than 1.0) when we are at the exact end of its interval
+  // (i.e. the input progress is 1.0).
+  if (result > 1.0 && aPortion <= 1.0) {
+    return 1.0;
+  }
   return result;
 }
 
 double
 ComputedTimingFunction::GetValue(
     double aPortion,
     ComputedTimingFunction::BeforeFlag aBeforeFlag) const
 {
@@ -111,35 +123,38 @@ ComputedTimingFunction::GetValue(
       }
       // If we can't calculate a sensible tangent, don't extrapolate at all.
       return 1.0;
     }
 
     return mTimingFunction.GetSplineValue(aPortion);
   }
 
-  return StepTiming(mSteps, aPortion, aBeforeFlag, mType);
+  return mType == nsTimingFunction::Type::Frames
+         ? FramesTiming(mStepsOrFrames, aPortion)
+         : StepTiming(mStepsOrFrames, aPortion, aBeforeFlag, mType);
 }
 
 int32_t
 ComputedTimingFunction::Compare(const ComputedTimingFunction& aRhs) const
 {
   if (mType != aRhs.mType) {
     return int32_t(mType) - int32_t(aRhs.mType);
   }
 
   if (mType == nsTimingFunction::Type::CubicBezier) {
     int32_t order = mTimingFunction.Compare(aRhs.mTimingFunction);
     if (order != 0) {
       return order;
     }
   } else if (mType == nsTimingFunction::Type::StepStart ||
-             mType == nsTimingFunction::Type::StepEnd) {
-    if (mSteps != aRhs.mSteps) {
-      return int32_t(mSteps) - int32_t(aRhs.mSteps);
+             mType == nsTimingFunction::Type::StepEnd ||
+             mType == nsTimingFunction::Type::Frames) {
+    if (mStepsOrFrames != aRhs.mStepsOrFrames) {
+      return int32_t(mStepsOrFrames) - int32_t(aRhs.mStepsOrFrames);
     }
   }
 
   return 0;
 }
 
 void
 ComputedTimingFunction::AppendToString(nsAString& aResult) const
@@ -149,17 +164,20 @@ ComputedTimingFunction::AppendToString(n
       nsStyleUtil::AppendCubicBezierTimingFunction(mTimingFunction.X1(),
                                                    mTimingFunction.Y1(),
                                                    mTimingFunction.X2(),
                                                    mTimingFunction.Y2(),
                                                    aResult);
       break;
     case nsTimingFunction::Type::StepStart:
     case nsTimingFunction::Type::StepEnd:
-      nsStyleUtil::AppendStepsTimingFunction(mType, mSteps, aResult);
+      nsStyleUtil::AppendStepsTimingFunction(mType, mStepsOrFrames, aResult);
+      break;
+    case nsTimingFunction::Type::Frames:
+      // TODO: Serialize Frames timing function.
       break;
     default:
       nsStyleUtil::AppendCubicBezierKeywordTimingFunction(mType, aResult);
       break;
   }
 }
 
 /* static */ int32_t
--- a/dom/animation/ComputedTimingFunction.h
+++ b/dom/animation/ComputedTimingFunction.h
@@ -25,23 +25,28 @@ public:
   double GetValue(double aPortion, BeforeFlag aBeforeFlag) const;
   const nsSMILKeySpline* GetFunction() const
   {
     NS_ASSERTION(HasSpline(), "Type mismatch");
     return &mTimingFunction;
   }
   nsTimingFunction::Type GetType() const { return mType; }
   bool HasSpline() const { return nsTimingFunction::IsSplineType(mType); }
-  uint32_t GetSteps() const { return mSteps; }
+  uint32_t GetSteps() const
+  {
+    MOZ_ASSERT(mType == nsTimingFunction::Type::StepStart ||
+               mType == nsTimingFunction::Type::StepEnd);
+    return mStepsOrFrames;
+  }
   bool operator==(const ComputedTimingFunction& aOther) const
   {
     return mType == aOther.mType &&
            (HasSpline() ?
             mTimingFunction == aOther.mTimingFunction :
-            mSteps == aOther.mSteps);
+            mStepsOrFrames == aOther.mStepsOrFrames);
   }
   bool operator!=(const ComputedTimingFunction& aOther) const
   {
     return !(*this == aOther);
   }
   int32_t Compare(const ComputedTimingFunction& aRhs) const;
   void AppendToString(nsAString& aResult) const;
 
@@ -52,14 +57,14 @@ public:
     return aFunction ? aFunction->GetValue(aPortion, aBeforeFlag) : aPortion;
   }
   static int32_t Compare(const Maybe<ComputedTimingFunction>& aLhs,
                          const Maybe<ComputedTimingFunction>& aRhs);
 
 private:
   nsTimingFunction::Type mType;
   nsSMILKeySpline mTimingFunction;
-  uint32_t mSteps;
+  uint32_t mStepsOrFrames;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ComputedTimingFunction_h