Bug 1496619 - Part 1: Drop frames() timing function r=birtles
authorBoris Chiou <boris.chiou@gmail.com>
Fri, 26 Oct 2018 18:03:24 +0000
changeset 443230 b46aa2883e42b750e338707cc120cd173f128b68
parent 443229 c873b3e4041f85943506ae62e5312e435fd091fe
child 443231 e9bf605e24a2714d01d6efeaebb6a234afdf5f49
push id34944
push userncsoregi@mozilla.com
push dateSat, 27 Oct 2018 09:49:55 +0000
treeherdermozilla-central@49d47a692ca4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles
bugs1496619
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1496619 - Part 1: Drop frames() timing function r=birtles frames() timing function was removed from the spec, so we drop it. Besides, some devtool tests are removed because they use frame(). I will add them back by using new step function later. Differential Revision: https://phabricator.services.mozilla.com/D9309
devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path-02.js
devtools/client/inspector/animation/test/doc_multi_easings.html
devtools/client/inspector/animation/test/doc_multi_keyframes.html
devtools/client/inspector/animation/test/head.js
devtools/shared/css/generated/properties-db.js
dom/animation/ComputedTimingFunction.cpp
dom/animation/ComputedTimingFunction.h
gfx/layers/ipc/LayerAnimationUtils.cpp
gfx/layers/ipc/LayersMessages.ipdlh
layout/inspector/tests/test_bug877690.html
layout/painting/nsDisplayList.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleUtil.cpp
layout/style/nsStyleUtil.h
layout/style/nsTimingFunction.h
layout/style/test/property_database.js
modules/libpref/init/StaticPrefList.h
servo/components/style/animation.rs
servo/components/style/gecko_bindings/sugar/ns_timing_function.rs
servo/components/style/values/generics/transform.rs
servo/components/style/values/specified/transform.rs
testing/web-platform/meta/css/css-timing/__dir__.ini
testing/web-platform/meta/web-animations/__dir__.ini
testing/web-platform/tests/css/css-timing/frames-timing-functions-output.html
testing/web-platform/tests/css/css-timing/frames-timing-functions-syntax.html
testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-timing-function.html
testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-timing-function.html
testing/web-platform/tests/web-animations/resources/easing-tests.js
testing/web-platform/tests/web-animations/testcommon.js
testing/web-platform/tests/web-animations/timing-model/time-transformations/transformed-progress.html
--- a/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path-02.js
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path-02.js
@@ -21,37 +21,16 @@ const TEST_DATA = [
           { x: 500, y: 50 },
           { x: 750, y: 75 },
           { x: 1000, y: 100 },
         ],
       },
     ],
   },
   {
-    targetClass: "frames-keyframe",
-    properties: [
-      {
-        name: "opacity",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 199, y: 0 },
-          { x: 200, y: 25 },
-          { x: 399, y: 25 },
-          { x: 400, y: 50 },
-          { x: 599, y: 50 },
-          { x: 600, y: 75 },
-          { x: 799, y: 75 },
-          { x: 800, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-      },
-    ],
-  },
-  {
     targetClass: "narrow-offsets",
     properties: [
       {
         name: "opacity",
         computedValuePathClass: "distance-path",
         expectedPathSegments: [
           { x: 0, y: 0 },
           { x: 100, y: 100 },
--- a/devtools/client/inspector/animation/test/doc_multi_easings.html
+++ b/devtools/client/inspector/animation/test/doc_multi_easings.html
@@ -39,17 +39,17 @@
     );
 
     createAnimation(
       "effect-easing",
       [
         { opacity: 1 },
         { opacity: 0 },
       ],
-      "frames(5)"
+      "steps(5)"
     );
 
     createAnimation(
       "keyframe-easing",
       [
         { opacity: 1, easing: "steps(2)" },
         { opacity: 0 },
       ]
--- a/devtools/client/inspector/animation/test/doc_multi_keyframes.html
+++ b/devtools/client/inspector/animation/test/doc_multi_keyframes.html
@@ -145,29 +145,16 @@
         {
           opacity: 1,
         },
       ],
       "steps(2)"
     );
 
     createAnimation(
-      "frames-keyframe",
-      [
-        {
-          easing: "frames(5)",
-          opacity: 0,
-        },
-        {
-          opacity: 1,
-        },
-      ]
-    );
-
-    createAnimation(
       "narrow-offsets",
       [
         {
           opacity: 0,
         },
         {
           opacity: 1,
           easing: "steps(2)",
--- a/devtools/client/inspector/animation/test/head.js
+++ b/devtools/client/inspector/animation/test/head.js
@@ -44,28 +44,25 @@ const openAnimationInspector = async fun
  */
 const closeAnimationInspector = async function() {
   const target = await TargetFactory.forTab(gBrowser.selectedTab);
   return gDevTools.closeToolbox(target);
 };
 
 /**
  * Some animation features are not enabled by default in release/beta channels
- * yet including:
- *   * parts of the Web Animations API (Bug 1264101), and
- *   * the frames() timing function (Bug 1379582).
+ * yet including parts of the Web Animations API.
  */
 const enableAnimationFeatures = function() {
   return new Promise(resolve => {
     SpecialPowers.pushPrefEnv({"set": [
       ["dom.animations-api.core.enabled", true],
       ["dom.animations-api.getAnimations.enabled", true],
       ["dom.animations-api.implicit-keyframes.enabled", true],
       ["dom.animations-api.timelines.enabled", true],
-      ["layout.css.frames-timing.enabled", true],
     ]}, resolve);
   });
 };
 
 /**
  * Add a new test tab in the browser and load the given url.
  *
  * @param {String} url
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -36,17 +36,16 @@ exports.CSS_PROPERTIES = {
       "backwards",
       "both",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
       "forwards",
-      "frames",
       "infinite",
       "inherit",
       "initial",
       "linear",
       "none",
       "normal",
       "paused",
       "reverse",
@@ -162,17 +161,16 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
-      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -1225,17 +1223,16 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "all",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
-      "frames",
       "inherit",
       "initial",
       "linear",
       "none",
       "step-end",
       "step-start",
       "steps",
       "unset"
@@ -1288,17 +1285,16 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
-      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -1491,17 +1487,16 @@ exports.CSS_PROPERTIES = {
       "backwards",
       "both",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
       "forwards",
-      "frames",
       "infinite",
       "inherit",
       "initial",
       "linear",
       "none",
       "normal",
       "paused",
       "reverse",
@@ -1617,17 +1612,16 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
-      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -2673,17 +2667,16 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "all",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
-      "frames",
       "inherit",
       "initial",
       "linear",
       "none",
       "step-end",
       "step-start",
       "steps",
       "unset"
@@ -2736,17 +2729,16 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
-      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -3198,17 +3190,16 @@ exports.CSS_PROPERTIES = {
       "backwards",
       "both",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
       "forwards",
-      "frames",
       "infinite",
       "inherit",
       "initial",
       "linear",
       "none",
       "normal",
       "paused",
       "reverse",
@@ -3324,17 +3315,16 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
-      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -8986,17 +8976,16 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "all",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
-      "frames",
       "inherit",
       "initial",
       "linear",
       "none",
       "step-end",
       "step-start",
       "steps",
       "unset"
@@ -9049,17 +9038,16 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
-      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
--- a/dom/animation/ComputedTimingFunction.cpp
+++ b/dom/animation/ComputedTimingFunction.cpp
@@ -13,17 +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 {
-    mStepsOrFrames = aFunction.mStepsOrFrames;
+    mSteps = aFunction.mSteps;
   }
 }
 
 static inline double
 StepTiming(uint32_t aSteps,
            double aPortion,
            ComputedTimingFunction::BeforeFlag aBeforeFlag,
            nsTimingFunction::Type aType)
@@ -56,32 +56,16 @@ StepTiming(uint32_t aSteps,
     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
 {
   if (HasSpline()) {
     // Check for a linear curve.
     // (GetSplineValue(), below, also checks this but doesn't work when
@@ -123,38 +107,35 @@ ComputedTimingFunction::GetValue(
       }
       // If we can't calculate a sensible tangent, don't extrapolate at all.
       return 1.0;
     }
 
     return mTimingFunction.GetSplineValue(aPortion);
   }
 
-  return mType == nsTimingFunction::Type::Frames
-         ? FramesTiming(mStepsOrFrames, aPortion)
-         : StepTiming(mStepsOrFrames, aPortion, aBeforeFlag, mType);
+  return StepTiming(mSteps, 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 ||
-             mType == nsTimingFunction::Type::Frames) {
-    if (mStepsOrFrames != aRhs.mStepsOrFrames) {
-      return int32_t(mStepsOrFrames) - int32_t(aRhs.mStepsOrFrames);
+             mType == nsTimingFunction::Type::StepEnd) {
+    if (mSteps != aRhs.mSteps) {
+      return int32_t(mSteps) - int32_t(aRhs.mSteps);
     }
   }
 
   return 0;
 }
 
 void
 ComputedTimingFunction::AppendToString(nsAString& aResult) const
@@ -164,20 +145,17 @@ 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, mStepsOrFrames, aResult);
-      break;
-    case nsTimingFunction::Type::Frames:
-      nsStyleUtil::AppendFramesTimingFunction(mStepsOrFrames, aResult);
+      nsStyleUtil::AppendStepsTimingFunction(mType, mSteps, aResult);
       break;
     default:
       nsStyleUtil::AppendCubicBezierKeywordTimingFunction(mType, aResult);
       break;
   }
 }
 
 /* static */ int32_t
--- a/dom/animation/ComputedTimingFunction.h
+++ b/dom/animation/ComputedTimingFunction.h
@@ -30,26 +30,20 @@ public:
   {
     MOZ_ASSERT(aType == nsTimingFunction::Type::StepStart ||
                aType == nsTimingFunction::Type::StepEnd,
                "The type of timing function should be either step-start or "
                "step-end");
     MOZ_ASSERT(aSteps > 0, "The number of steps should be 1 or more");
     return ComputedTimingFunction(aType, aSteps);
   }
-  static ComputedTimingFunction
-  Frames(uint32_t aFrames)
-  {
-    MOZ_ASSERT(aFrames > 1, "The number of frames should be 2 or more");
-    return ComputedTimingFunction(nsTimingFunction::Type::Frames, aFrames);
-  }
 
   ComputedTimingFunction() = default;
   explicit ComputedTimingFunction(const nsTimingFunction& aFunction)
-    : mStepsOrFrames(0)
+    : mSteps(0)
   {
     Init(aFunction);
   }
   void Init(const nsTimingFunction& aFunction);
 
   // BeforeFlag is used in step timing function.
   // https://drafts.csswg.org/css-timing/#before-flag
   enum class BeforeFlag {
@@ -63,43 +57,38 @@ public:
     return &mTimingFunction;
   }
   nsTimingFunction::Type GetType() const { return mType; }
   bool HasSpline() const { return nsTimingFunction::IsSplineType(mType); }
   uint32_t GetSteps() const
   {
     MOZ_ASSERT(mType == nsTimingFunction::Type::StepStart ||
                mType == nsTimingFunction::Type::StepEnd);
-    return mStepsOrFrames;
-  }
-  uint32_t GetFrames() const
-  {
-    MOZ_ASSERT(mType == nsTimingFunction::Type::Frames);
-    return mStepsOrFrames;
+    return mSteps;
   }
   bool operator==(const ComputedTimingFunction& aOther) const
   {
     return mType == aOther.mType &&
            (HasSpline() ?
             mTimingFunction == aOther.mTimingFunction :
-            mStepsOrFrames == aOther.mStepsOrFrames);
+            mSteps == aOther.mSteps);
   }
   bool operator!=(const ComputedTimingFunction& aOther) const
   {
     return !(*this == aOther);
   }
   bool operator==(const nsTimingFunction& aOther) const
   {
     return mType == aOther.mType &&
            (HasSpline()
             ? mTimingFunction.X1() == aOther.mFunc.mX1 &&
               mTimingFunction.Y1() == aOther.mFunc.mY1 &&
               mTimingFunction.X2() == aOther.mFunc.mX2 &&
               mTimingFunction.Y2() == aOther.mFunc.mY2
-            : mStepsOrFrames == aOther.mStepsOrFrames);
+            : mSteps == aOther.mSteps);
   }
   bool operator!=(const nsTimingFunction& aOther) const
   {
     return !(*this == aOther);
   }
   int32_t Compare(const ComputedTimingFunction& aRhs) const;
   void AppendToString(nsAString& aResult) const;
 
@@ -111,26 +100,26 @@ public:
   }
   static int32_t Compare(const Maybe<ComputedTimingFunction>& aLhs,
                          const Maybe<ComputedTimingFunction>& aRhs);
 
 private:
   ComputedTimingFunction(double x1, double y1, double x2, double y2)
     : mType(nsTimingFunction::Type::CubicBezier)
     , mTimingFunction(x1, y1, x2, y2)
-    , mStepsOrFrames(0)
+    , mSteps(0)
   {
   }
-  ComputedTimingFunction(nsTimingFunction::Type aType, uint32_t aStepsOrFrames)
+  ComputedTimingFunction(nsTimingFunction::Type aType, uint32_t aSteps)
     : mType(aType)
-    , mStepsOrFrames(aStepsOrFrames) { }
+    , mSteps(aSteps) { }
 
   nsTimingFunction::Type mType = nsTimingFunction::Type::Linear;
   nsSMILKeySpline mTimingFunction;
-  uint32_t mStepsOrFrames;
+  uint32_t mSteps;
 };
 
 inline bool
 operator==(const Maybe<ComputedTimingFunction>& aLHS,
            const nsTimingFunction& aRHS)
 {
   if (aLHS.isNothing()) {
     return aRHS.mType == nsTimingFunction::Type::Linear;
--- a/gfx/layers/ipc/LayerAnimationUtils.cpp
+++ b/gfx/layers/ipc/LayerAnimationUtils.cpp
@@ -26,20 +26,16 @@ AnimationUtils::TimingFunctionToComputed
     }
     case TimingFunction::TStepFunction: {
       StepFunction sf = aTimingFunction.get_StepFunction();
       nsTimingFunction::Type type = sf.type() == 1 ?
         nsTimingFunction::Type::StepStart :
         nsTimingFunction::Type::StepEnd;
       return Some(ComputedTimingFunction::Steps(type, sf.steps()));
     }
-    case TimingFunction::TFramesFunction: {
-      FramesFunction ff = aTimingFunction.get_FramesFunction();
-      return Some(ComputedTimingFunction::Frames(ff.frames()));
-    }
     default:
       MOZ_ASSERT_UNREACHABLE(
         "Function must be null, bezier, step or frames");
       break;
   }
   return Nothing();
 }
 
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -95,25 +95,20 @@ struct CubicBezierFunction {
 };
 
 struct StepFunction {
   int steps;
   // 1 = nsTimingFunction::StepStart, 2 = nsTimingFunction::StepEnd
   int type;
 };
 
-struct FramesFunction {
-  int frames;
-};
-
 union TimingFunction {
   null_t;
   CubicBezierFunction;
   StepFunction;
-  FramesFunction;
 };
 
 // Send the angle with units rather than sending all angles in radians
 // to avoid having floating point error introduced by unit switching.
 struct CSSAngle {
   float value;
   int unit; // an nsCSSUnit that is valid for angles
 };
--- a/layout/inspector/tests/test_bug877690.html
+++ b/layout/inspector/tests/test_bug877690.html
@@ -116,17 +116,17 @@ function do_test() {
   var values = InspectorUtils.getCSSValuesForProperty(prop);
   var expected = [ "initial", "inherit", "unset", "italic", "normal", "oblique" ];
   ok(testValues(values, expected), "property font-style's values.");
 
   // Test property with "cubic-bezier" and "step".
   var prop = "-moz-transition";
   var values = InspectorUtils.getCSSValuesForProperty(prop);
   var expected = [ "initial", "all", "unset", "cubic-bezier", "ease", "ease-in", "ease-in-out",
-                   "ease-out", "frames", "inherit", "linear", "none", "step-end", "step-start",
+                   "ease-out", "inherit", "linear", "none", "step-end", "step-start",
                    "steps" ];
   ok(testValues(values, expected), "property -moz-transition's values.");
 
   // test invalid property
   var prop = "invalidProperty";
   try {
     InspectorUtils.getCSSValuesForProperty(prop);
     ok(false, "invalid property should throw an exception");
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -415,20 +415,16 @@ ToTimingFunction(const Maybe<ComputedTim
   }
 
   if (aCTF->HasSpline()) {
     const nsSMILKeySpline* spline = aCTF->GetFunction();
     return TimingFunction(CubicBezierFunction(
       spline->X1(), spline->Y1(), spline->X2(), spline->Y2()));
   }
 
-  if (aCTF->GetType() == nsTimingFunction::Type::Frames) {
-    return TimingFunction(FramesFunction(aCTF->GetFrames()));
-  }
-
   uint32_t type = aCTF->GetType() == nsTimingFunction::Type::StepStart ? 1 : 2;
   return TimingFunction(StepFunction(aCTF->GetSteps(), type));
 }
 
 static void
 SetAnimatable(nsCSSPropertyID aProperty,
               const AnimationValue& aAnimationValue,
               nsIFrame* aFrame,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -4589,23 +4589,19 @@ nsComputedDOMStyle::AppendTimingFunction
                                                    aTimingFunction.mFunc.mY1,
                                                    aTimingFunction.mFunc.mX2,
                                                    aTimingFunction.mFunc.mY2,
                                                    tmp);
       break;
     case nsTimingFunction::Type::StepStart:
     case nsTimingFunction::Type::StepEnd:
       nsStyleUtil::AppendStepsTimingFunction(aTimingFunction.mType,
-                                             aTimingFunction.mStepsOrFrames,
+                                             aTimingFunction.mSteps,
                                              tmp);
       break;
-    case nsTimingFunction::Type::Frames:
-      nsStyleUtil::AppendFramesTimingFunction(aTimingFunction.mStepsOrFrames,
-                                              tmp);
-      break;
     default:
       nsStyleUtil::AppendCubicBezierKeywordTimingFunction(aTimingFunction.mType,
                                                           tmp);
       break;
   }
   timingFunction->SetString(tmp);
   aValueList->AppendCSSValue(timingFunction.forget());
 }
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3319,23 +3319,23 @@ nsStyleBackground::IsTransparent(mozilla
 }
 
 void
 nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType)
 {
   switch (aTimingFunctionType) {
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START:
       mType = Type::StepStart;
-      mStepsOrFrames = 1;
+      mSteps = 1;
       return;
     default:
       MOZ_FALLTHROUGH_ASSERT("aTimingFunctionType must be a keyword value");
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END:
       mType = Type::StepEnd;
-      mStepsOrFrames = 1;
+      mSteps = 1;
       return;
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE:
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR:
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN:
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT:
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT:
       mType = static_cast<Type>(aTimingFunctionType);
       break;
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -287,25 +287,16 @@ nsStyleUtil::AppendStepsTimingFunction(n
   if (aType == nsTimingFunction::Type::StepStart) {
     aResult.AppendLiteral(", start)");
   } else {
     aResult.AppendLiteral(")");
   }
 }
 
 /* static */ void
-nsStyleUtil::AppendFramesTimingFunction(uint32_t aFrames,
-                                        nsAString& aResult)
-{
-  aResult.AppendLiteral("frames(");
-  aResult.AppendInt(aFrames);
-  aResult.AppendLiteral(")");
-}
-
-/* static */ void
 nsStyleUtil::AppendCubicBezierTimingFunction(float aX1, float aY1,
                                              float aX2, float aY2,
                                              nsAString& aResult)
 {
   // set the value from the cubic-bezier control points
   // (We could try to regenerate the keywords if we want.)
   aResult.AppendLiteral("cubic-bezier(");
   aResult.AppendFloat(aX1);
--- a/layout/style/nsStyleUtil.h
+++ b/layout/style/nsStyleUtil.h
@@ -74,18 +74,16 @@ public:
   static void AppendCSSNumber(float aNumber, nsAString& aResult)
   {
     aResult.AppendFloat(aNumber);
   }
 
   static void AppendStepsTimingFunction(nsTimingFunction::Type aType,
                                         uint32_t aSteps,
                                         nsAString& aResult);
-  static void AppendFramesTimingFunction(uint32_t aFrames,
-                                         nsAString& aResult);
   static void AppendCubicBezierTimingFunction(float aX1, float aY1,
                                               float aX2, float aY2,
                                               nsAString& aResult);
   static void AppendCubicBezierKeywordTimingFunction(
       nsTimingFunction::Type aType,
       nsAString& aResult);
 
   /*
--- a/layout/style/nsTimingFunction.h
+++ b/layout/style/nsTimingFunction.h
@@ -15,26 +15,23 @@ struct nsTimingFunction
     Ease,         // ease
     Linear,       // linear
     EaseIn,       // ease-in
     EaseOut,      // ease-out
     EaseInOut,    // ease-in-out
     StepStart,    // step-start and steps(..., start)
     StepEnd,      // step-end, steps(..., end) and steps(...)
     CubicBezier,  // cubic-bezier()
-    Frames,       // frames()
   };
 
   // Whether the timing function type is represented by a spline,
   // and thus will have mFunc filled in.
   static bool IsSplineType(Type aType)
   {
-    return aType != Type::StepStart &&
-           aType != Type::StepEnd &&
-           aType != Type::Frames;
+    return aType != Type::StepStart && aType != Type::StepEnd;
   }
 
   explicit nsTimingFunction(
     int32_t aTimingFunctionType = NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE)
     : mType(Type::Ease)
     , mFunc{}
   {
     AssignFromKeyword(aTimingFunctionType);
@@ -46,41 +43,39 @@ struct nsTimingFunction
     mFunc.mX1 = x1;
     mFunc.mY1 = y1;
     mFunc.mX2 = x2;
     mFunc.mY2 = y2;
   }
 
   enum class Keyword { Implicit, Explicit };
 
-  nsTimingFunction(Type aType, uint32_t aStepsOrFrames)
+  nsTimingFunction(Type aType, uint32_t aSteps)
     : mType(aType)
   {
-    MOZ_ASSERT(mType == Type::StepStart ||
-               mType == Type::StepEnd ||
-               mType == Type::Frames,
+    MOZ_ASSERT(mType == Type::StepStart || mType == Type::StepEnd,
                "wrong type");
-    mStepsOrFrames = aStepsOrFrames;
+    mSteps = aSteps;
   }
 
   nsTimingFunction(const nsTimingFunction& aOther)
   {
     *this = aOther;
   }
 
   Type mType;
   union {
     struct {
       float mX1;
       float mY1;
       float mX2;
       float mY2;
     } mFunc;
     struct {
-      uint32_t mStepsOrFrames;
+      uint32_t mSteps;
     };
   };
 
   nsTimingFunction&
   operator=(const nsTimingFunction& aOther)
   {
     if (&aOther == this) {
       return *this;
@@ -89,32 +84,32 @@ struct nsTimingFunction
     mType = aOther.mType;
 
     if (HasSpline()) {
       mFunc.mX1 = aOther.mFunc.mX1;
       mFunc.mY1 = aOther.mFunc.mY1;
       mFunc.mX2 = aOther.mFunc.mX2;
       mFunc.mY2 = aOther.mFunc.mY2;
     } else {
-      mStepsOrFrames = aOther.mStepsOrFrames;
+      mSteps = aOther.mSteps;
     }
 
     return *this;
   }
 
   bool operator==(const nsTimingFunction& aOther) const
   {
     if (mType != aOther.mType) {
       return false;
     }
     if (HasSpline()) {
       return mFunc.mX1 == aOther.mFunc.mX1 && mFunc.mY1 == aOther.mFunc.mY1 &&
              mFunc.mX2 == aOther.mFunc.mX2 && mFunc.mY2 == aOther.mFunc.mY2;
     }
-    return mStepsOrFrames == aOther.mStepsOrFrames;
+    return mSteps == aOther.mSteps;
   }
 
   bool operator!=(const nsTimingFunction& aOther) const
   {
     return !(*this == aOther);
   }
 
   bool HasSpline() const { return IsSplineType(mType); }
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -6434,24 +6434,16 @@ if (IsCSSPropertyPrefEnabled("layout.css
     other_values: [ "none" ],
     invalid_values: [ "on" ]
   };
   gCSSProperties["font"].subproperties.push("font-optical-sizing");
   gCSSProperties["font-variation-settings"].other_values
     .push("'vert' calc(2.5)");
 }
 
-if (IsCSSPropertyPrefEnabled("layout.css.frames-timing.enabled")) {
-  gCSSProperties["animation-timing-function"].other_values.push(
-    "frames(2)", "frames(1000)", "frames( 2 )");
-  gCSSProperties["animation-timing-function"].invalid_values.push(
-    "frames(1)", "frames(-2)", "frames", "frames()", "frames(,)",
-    "frames(a)", "frames(2.0)", "frames(2.5)", "frames(2 3)");
-}
-
 if (IsCSSPropertyPrefEnabled("svg.transform-box.enabled")) {
   gCSSProperties["transform-box"] = {
     domProp: "transformBox",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "border-box" ],
     other_values: [ "fill-box", "view-box" ],
     invalid_values: ["content-box", "padding-box", "stroke-box", "margin-box"]
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -673,29 +673,16 @@ VARCACHE_PREF(
 #endif
 VARCACHE_PREF(
   "layout.css.control-characters.visible",
    layout_css_control_characters_visible,
   bool, PREF_VALUE
 )
 #undef PREF_VALUE
 
-// Is support for the frames() timing function enabled?
-#ifdef RELEASE_OR_BETA
-# define PREF_VALUE false
-#else
-# define PREF_VALUE true
-#endif
-VARCACHE_PREF(
-  "layout.css.frames-timing.enabled",
-   layout_css_frames_timing_enabled,
-  bool, PREF_VALUE
-)
-#undef PREF_VALUE
-
 // Should the :visited selector ever match (otherwise :link matches instead)?
 VARCACHE_PREF(
   "layout.css.visited_links_enabled",
    layout_css_visited_links_enabled,
   bool, true
 )
 
 // Is the '-webkit-appearance' alias for '-moz-appearance' enabled?
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -364,32 +364,16 @@ impl PropertyAnimation {
                 Bezier::new(x1, y1, x2, y2).solve(time, epsilon)
             },
             GenericTimingFunction::Steps(steps, StepPosition::Start) => {
                 (time * (steps as f64)).ceil() / (steps as f64)
             },
             GenericTimingFunction::Steps(steps, StepPosition::End) => {
                 (time * (steps as f64)).floor() / (steps as f64)
             },
-            GenericTimingFunction::Frames(frames) => {
-                // https://drafts.csswg.org/css-timing/#frames-timing-functions
-                let mut out = (time * (frames as f64)).floor() / ((frames - 1) as f64);
-                if out > 1.0 {
-                    // FIXME: Basically, during the animation sampling process, the input progress
-                    // should be in the range of [0, 1]. However, |time| is not accurate enough
-                    // here, which means |time| could be larger than 1.0 in the last animation
-                    // frame. (It should be equal to 1.0 exactly.) This makes the output of frames
-                    // timing function jumps to the next frame/level.
-                    // However, this solution is still not correct because |time| is possible
-                    // outside the range of [0, 1] after introducing Web Animations. We should fix
-                    // this problem when implementing web animations.
-                    out = 1.0;
-                }
-                out
-            },
             GenericTimingFunction::Keyword(keyword) => {
                 let (x1, x2, y1, y2) = keyword.to_bezier();
                 Bezier::new(x1, x2, y1, y2).solve(time, epsilon)
             },
         };
 
         self.property.update(style, progress);
     }
--- a/servo/components/style/gecko_bindings/sugar/ns_timing_function.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_timing_function.rs
@@ -17,27 +17,17 @@ impl nsTimingFunction {
                 function_type == nsTimingFunction_Type::StepEnd,
             "function_type should be step-start or step-end"
         );
         self.mType = function_type;
         unsafe {
             self.__bindgen_anon_1
                 .__bindgen_anon_1
                 .as_mut()
-                .mStepsOrFrames = steps;
-        }
-    }
-
-    fn set_as_frames(&mut self, frames: u32) {
-        self.mType = nsTimingFunction_Type::Frames;
-        unsafe {
-            self.__bindgen_anon_1
-                .__bindgen_anon_1
-                .as_mut()
-                .mStepsOrFrames = frames;
+                .mSteps = steps;
         }
     }
 
     fn set_as_bezier(
         &mut self,
         function_type: nsTimingFunction_Type,
         x1: f32,
         y1: f32,
@@ -69,20 +59,16 @@ impl From<TimingFunction> for nsTimingFu
             GenericTimingFunction::Steps(steps, StepPosition::Start) => {
                 debug_assert!(steps.value() >= 0);
                 tf.set_as_step(nsTimingFunction_Type::StepStart, steps.value() as u32);
             },
             GenericTimingFunction::Steps(steps, StepPosition::End) => {
                 debug_assert!(steps.value() >= 0);
                 tf.set_as_step(nsTimingFunction_Type::StepEnd, steps.value() as u32);
             },
-            GenericTimingFunction::Frames(frames) => {
-                debug_assert!(frames.value() >= 2);
-                tf.set_as_frames(frames.value() as u32);
-            },
             GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => {
                 tf.set_as_bezier(
                     nsTimingFunction_Type::CubicBezier,
                     x1.get(),
                     y1.get(),
                     x2.get(),
                     y2.get(),
                 );
@@ -100,37 +86,30 @@ impl From<nsTimingFunction> for Computed
     fn from(function: nsTimingFunction) -> ComputedTimingFunction {
         match function.mType {
             nsTimingFunction_Type::StepStart => GenericTimingFunction::Steps(
                 unsafe {
                     function
                         .__bindgen_anon_1
                         .__bindgen_anon_1
                         .as_ref()
-                        .mStepsOrFrames
+                        .mSteps
                 },
                 StepPosition::Start,
             ),
             nsTimingFunction_Type::StepEnd => GenericTimingFunction::Steps(
                 unsafe {
                     function
                         .__bindgen_anon_1
                         .__bindgen_anon_1
                         .as_ref()
-                        .mStepsOrFrames
+                        .mSteps
                 },
                 StepPosition::End,
             ),
-            nsTimingFunction_Type::Frames => GenericTimingFunction::Frames(unsafe {
-                function
-                    .__bindgen_anon_1
-                    .__bindgen_anon_1
-                    .as_ref()
-                    .mStepsOrFrames
-            }),
             nsTimingFunction_Type::Ease => GenericTimingFunction::Keyword(TimingKeyword::Ease),
             nsTimingFunction_Type::Linear => GenericTimingFunction::Keyword(TimingKeyword::Linear),
             nsTimingFunction_Type::EaseIn => GenericTimingFunction::Keyword(TimingKeyword::EaseIn),
             nsTimingFunction_Type::EaseOut => {
                 GenericTimingFunction::Keyword(TimingKeyword::EaseOut)
             },
             nsTimingFunction_Type::EaseInOut => {
                 GenericTimingFunction::Keyword(TimingKeyword::EaseInOut)
--- a/servo/components/style/values/generics/transform.rs
+++ b/servo/components/style/values/generics/transform.rs
@@ -87,17 +87,17 @@ pub struct TransformOrigin<H, V, Depth> 
     /// The vertical origin.
     pub vertical: V,
     /// The depth.
     pub depth: Depth,
 }
 
 /// A generic timing function.
 ///
-/// <https://drafts.csswg.org/css-timing-1/#single-timing-function-production>
+/// https://drafts.csswg.org/css-easing-1/#timing-functions
 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
 #[value_info(ty = "TIMING_FUNCTION")]
 pub enum TimingFunction<Integer, Number> {
     /// `linear | ease | ease-in | ease-out | ease-in-out`
     Keyword(TimingKeyword),
     /// `cubic-bezier(<number>, <number>, <number>, <number>)`
     #[allow(missing_docs)]
     #[css(comma, function)]
@@ -106,19 +106,16 @@ pub enum TimingFunction<Integer, Number>
         y1: Number,
         x2: Number,
         y2: Number,
     },
     /// `step-start | step-end | steps(<integer>, [ start | end ]?)`
     #[css(comma, function)]
     #[value_info(other_values = "step-start,step-end")]
     Steps(Integer, #[css(skip_if = "is_end")] StepPosition),
-    /// `frames(<integer>)`
-    #[css(comma, function)]
-    Frames(Integer),
 }
 
 #[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 #[derive(
     Clone,
     Copy,
     Debug,
--- a/servo/components/style/values/specified/transform.rs
+++ b/servo/components/style/values/specified/transform.rs
@@ -345,29 +345,16 @@ where
 
 impl<S> OriginComponent<S> {
     /// `0%`
     pub fn zero() -> Self {
         OriginComponent::Length(LengthOrPercentage::Percentage(ComputedPercentage::zero()))
     }
 }
 
-#[cfg(feature = "gecko")]
-#[inline]
-fn allow_frames_timing() -> bool {
-    use gecko_bindings::structs::mozilla;
-    unsafe { mozilla::StaticPrefs_sVarCache_layout_css_frames_timing_enabled }
-}
-
-#[cfg(feature = "servo")]
-#[inline]
-fn allow_frames_timing() -> bool {
-    true
-}
-
 impl Parse for TimingFunction {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         if let Ok(keyword) = input.try(TimingKeyword::parse) {
             return Ok(generic::TimingFunction::Keyword(keyword));
         }
@@ -401,24 +388,16 @@ impl Parse for TimingFunction {
                 "steps" => {
                     let steps = Integer::parse_positive(context, i)?;
                     let position = i.try(|i| {
                         i.expect_comma()?;
                         StepPosition::parse(i)
                     }).unwrap_or(StepPosition::End);
                     Ok(generic::TimingFunction::Steps(steps, position))
                 },
-                "frames" => {
-                    if allow_frames_timing() {
-                        let frames = Integer::parse_with_minimum(context, i, 2)?;
-                        Ok(generic::TimingFunction::Frames(frames))
-                    } else {
-                        Err(())
-                    }
-                },
                 _ => Err(()),
             }).map_err(|()| {
                 location.new_custom_error(StyleParseErrorKind::UnexpectedFunction(function.clone()))
             })
         })
     }
 }
 
@@ -435,19 +414,16 @@ impl ToComputedValue for TimingFunction 
                     y1: y1.to_computed_value(context),
                     x2: x2.to_computed_value(context),
                     y2: y2.to_computed_value(context),
                 }
             },
             generic::TimingFunction::Steps(steps, position) => {
                 generic::TimingFunction::Steps(steps.to_computed_value(context) as u32, position)
             },
-            generic::TimingFunction::Frames(frames) => {
-                generic::TimingFunction::Frames(frames.to_computed_value(context) as u32)
-            },
         }
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         match *computed {
             generic::TimingFunction::Keyword(keyword) => generic::TimingFunction::Keyword(keyword),
             generic::TimingFunction::CubicBezier {
@@ -460,19 +436,16 @@ impl ToComputedValue for TimingFunction 
                 y1: Number::from_computed_value(y1),
                 x2: Number::from_computed_value(x2),
                 y2: Number::from_computed_value(y2),
             },
             generic::TimingFunction::Steps(steps, position) => generic::TimingFunction::Steps(
                 Integer::from_computed_value(&(steps as i32)),
                 position,
             ),
-            generic::TimingFunction::Frames(frames) => {
-                generic::TimingFunction::Frames(Integer::from_computed_value(&(frames as i32)))
-            },
         }
     }
 }
 
 /// A specified CSS `rotate`
 pub type Rotate = generic::Rotate<Number, Angle>;
 
 impl Parse for Rotate {
--- a/testing/web-platform/meta/css/css-timing/__dir__.ini
+++ b/testing/web-platform/meta/css/css-timing/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [dom.animations-api.core.enabled:true, layout.css.frames-timing.enabled:true]
+prefs: [dom.animations-api.core.enabled:true]
--- a/testing/web-platform/meta/web-animations/__dir__.ini
+++ b/testing/web-platform/meta/web-animations/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true, layout.css.frames-timing.enabled:true]
+prefs: [dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true]
deleted file mode 100644
--- a/testing/web-platform/tests/css/css-timing/frames-timing-functions-output.html
+++ /dev/null
@@ -1,152 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<meta name="assert"
-content="This test checks the output of frame timing functions with different frame numbers" />
-<title>Frames timing function output tests</title>
-<link rel="help"
-href="https://drafts.csswg.org/css-timing/#frames-timing-functions">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="testcommon.js"></script>
-<style>
-@keyframes anim {
-  from { left: 0px; }
-  to   { left: 100px; }
-}
-</style>
-<body>
-<div id="log"></div>
-<script>
-"use strict";
-
-test(function(t) {
-  const div = createDiv(t);
-  div.style.animation = 'anim 10s frames(2) forwards';
-  assert_equals(getComputedStyle(div).left, '0px');
-}, 'For an input progress of 0.0, the output of a frames timing function is ' +
-   'the first frame');
-
-test(function(t) {
-  const div = createDiv(t);
-  div.style.animation = 'anim 10s frames(2) forwards';
-
-  div.style.animationDelay = '-4999ms';
-  assert_equals(getComputedStyle(div).left, '0px');
-  div.style.animationDelay = '-5000ms';
-  assert_equals(getComputedStyle(div).left, '100px');
-}, 'At a frame boundary, the output of a frames timing function is the next ' +
-   'frame');
-
-test(function(t) {
-  const div = createDiv(t);
-  div.style.animation = 'anim 10s frames(2) forwards';
-
-  div.style.animationDelay = '-10s';
-  assert_equals(getComputedStyle(div).left, '100px');
-}, 'For an input progress of 1.0, the output of a frames timing function is ' +
-   'the final frame');
-
-test(function(t) {
-  const div = createDiv(t);
-  div.style.animation = 'anim 11s frames(11) forwards';
-
-  // We have 11 frames in 11s, so the first step happens at 1.0.
-  div.style.animationDelay = '-999ms';
-  assert_equals(getComputedStyle(div).left, '0px');
-  div.style.animationDelay = '-1000ms';
-  assert_equals(getComputedStyle(div).left, '10px');
-}, 'The number of frames is correctly reflected in the frames timing ' +
-   'function output');
-
-test(function(t) {
-  const div = createDiv(t);
-  div.style.transition = 'left 11s frames(11)';
-
-  // We have 11 frames in 11s, so the first step happens at 1.0.
-  div.style.left = '0px';
-  div.style.transitionDelay = '-999ms';
-  getComputedStyle(div).left;
-  div.style.left = '100px';
-  assert_equals(getComputedStyle(div).left, '0px');
-
-  div.style.left = '0px';
-  div.style.transitionDelay = '-1000ms';
-  getComputedStyle(div).left;
-  div.style.left = '100px';
-  assert_equals(getComputedStyle(div).left, '10px');
-}, 'The number of frames is correctly reflected in the frames timing ' +
-   'function output on CSS Transitions');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'frames(2)' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
-
-  // The bezier function produces values between 0.5 and 1 in
-  // (~0.0442, 0.23368), and values between 1 and 2 in (0.23368794, 1).
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 45;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 230;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 250;
-  assert_equals(getComputedStyle(target).left, '200px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'frames easing with input progress greater than 1');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'frames(2)' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, 3, 1, 3)' });
-
-  // The bezier funciton produces values:
-  // Input           ->  Output
-  // 0.0                 0.0
-  // 0.114 ~ 0.245       1.5~2.0, so frames(2) is 3.0
-  // 0.245 ~ 0.6         2.0~2.4, so frames(2) is 4.0
-  // 0.6   ~ 0.882       2.4~2.0, so frames(2) is 4.0
-  // 0.882 ~ 0.976       2.0~1.5, so frames(2) is 3.0
-  // 1.0                 1.0
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 114;
-  assert_equals(getComputedStyle(target).left, '300px');
-  anim.currentTime = 500;
-  assert_equals(getComputedStyle(target).left, '400px');
-  anim.currentTime = 900;
-  assert_equals(getComputedStyle(target).left, '300px');
-}, 'frames easing with input progress greater than 1.5');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'frames(2)' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
-
-  // The bezier function produces negative values (but always greater than -0.5)
-  // in (0, 0.766312060).
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 750;
-  assert_equals(getComputedStyle(target).left, '-100px');
-  anim.currentTime = 800;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'frames easing with input progress less than 0');
-
-</script>
-</body>
deleted file mode 100644
--- a/testing/web-platform/tests/css/css-timing/frames-timing-functions-syntax.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<meta name="assert"
-content="This test checks the syntax output of frame timing functions" />
-<title>Frames timing function syntax tests</title>
-<link rel="help"
-href="https://drafts.csswg.org/css-timing/#frames-timing-functions">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-"use strict";
-
-test(function(t) {
-  const div = createDiv(t);
-  div.style.animation = 'abc 1s ease-in';
-  div.style.animationTimingFunction = 'frames(1)';
-  assert_equals(getComputedStyle(div).animationTimingFunction, 'ease-in');
-}, 'The number of frames must be a positive integer greater than 1, or we ' +
-   'fallback to the previously-set easing');
-
-test(function(t) {
-  const div = createDiv(t);
-  div.style.animation = 'abc 1s frames(  2 )';
-  assert_equals(getComputedStyle(div).animationTimingFunction, 'frames(2)');
-}, 'The serialization of frames is \'frames(n)\', n is the number of frames');
-
-</script>
-</body>
--- a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-timing-function.html
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-timing-function.html
@@ -19,12 +19,12 @@ runListValuedPropertyTests('animation-ti
   { syntax: 'ease-in' },
   { syntax: 'ease-out' },
   { syntax: 'ease-in-out' },
   { syntax: 'step-start' },
   { syntax: 'step-end' },
 ]);
 
 runUnsupportedPropertyTests('animation-timing-function', [
-  'cubic-bezier(0.1, 0.7, 1.0, 0.1)', 'steps(4, end)', 'frames(10)'
+  'cubic-bezier(0.1, 0.7, 1.0, 0.1)', 'steps(4, end)'
 ]);
 
 </script>
--- a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-timing-function.html
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-timing-function.html
@@ -19,12 +19,12 @@ runListValuedPropertyTests('transition-t
   { syntax: 'ease-in' },
   { syntax: 'ease-out' },
   { syntax: 'ease-in-out' },
   { syntax: 'step-start' },
   { syntax: 'step-end' },
 ]);
 
 runUnsupportedPropertyTests('transition-timing-function', [
-  'cubic-bezier(0.1, 0.7, 1.0, 0.1)', 'steps(4, end)', 'frames(10)'
+  'cubic-bezier(0.1, 0.7, 1.0, 0.1)', 'steps(4, end)'
 ]);
 
 </script>
--- a/testing/web-platform/tests/web-animations/resources/easing-tests.js
+++ b/testing/web-platform/tests/web-animations/resources/easing-tests.js
@@ -36,21 +36,16 @@ const gEasingTests = [
   },
   {
     desc: 'steps(2, end) function',
     easing: 'steps(2, end)',
     easingFunction: stepEnd(2),
     serialization: 'steps(2)'
   },
   {
-    desc: 'frames function',
-    easing: 'frames(5)',
-    easingFunction: framesTiming(5)
-  },
-  {
     desc: 'linear function',
     easing: 'linear', // cubic-bezier(0, 0, 1.0, 1.0)
     easingFunction: cubicBezier(0, 0, 1.0, 1.0)
   },
   {
     desc: 'ease function',
     easing: 'ease', // cubic-bezier(0.25, 0.1, 0.25, 1.0)
     easingFunction: cubicBezier(0.25, 0.1, 0.25, 1.0)
@@ -106,30 +101,21 @@ const gInvalidEasings = [
   'cubic-bezier(0.1, 0, 4, 0.4)',
   'steps(-1, start)',
   'steps(0.1, start)',
   'steps(3, nowhere)',
   'steps(-3, end)',
   'function (a){return a}',
   'function (x){return x}',
   'function(x, y){return 0.3}',
-  'frames(1)',
-  'frames',
-  'frames()',
-  'frames(,)',
-  'frames(a)',
-  'frames(2.0)',
-  'frames(2.5)',
-  'frames(2 3)',
 ];
 
 // Easings that should serialize to the same string
 const gRoundtripEasings = [
   'ease',
   'linear',
   'ease-in',
   'ease-out',
   'ease-in-out',
   'cubic-bezier(0.1, 5, 0.23, 0)',
   'steps(3, start)',
   'steps(3)',
-  'frames(3)',
 ];
--- a/testing/web-platform/tests/web-animations/testcommon.js
+++ b/testing/web-platform/tests/web-animations/testcommon.js
@@ -145,23 +145,16 @@ function stepEnd(nsteps) {
 
 function stepStart(nsteps) {
   return x => {
     const result = Math.floor(x * nsteps + 1.0) / nsteps;
     return (result > 1.0) ? 1.0 : result;
   };
 }
 
-function framesTiming(nframes) {
-  return x => {
-    const result = Math.floor(x * nframes) / (nframes - 1);
-    return (result > 1.0 && x <= 1.0) ? 1.0 : result;
-  };
-}
-
 function waitForAnimationFrames(frameCount) {
   return new Promise(resolve => {
     function handleFrame() {
       if (--frameCount <= 0) {
         resolve();
       } else {
         window.requestAnimationFrame(handleFrame); // wait another frame
       }
--- a/testing/web-platform/tests/web-animations/timing-model/time-transformations/transformed-progress.html
+++ b/testing/web-platform/tests/web-animations/timing-model/time-transformations/transformed-progress.html
@@ -27,20 +27,19 @@ for (const params of gEasingTests) {
                            expectedProgress,
                            0.01,
                            'The progress should be approximately ' +
                            `${expectedProgress} at ${sampleTime}ms`);
     }
   }, `Transformed progress for ${params.desc}`);
 }
 
-// Additional tests for various boundary conditions of step timing functions and
-// frames timing functions.
+// Additional tests for various boundary conditions of step timing functions.
 
-const gStepAndFramesTimingFunctionTests = [
+const gStepTimingFunctionTests = [
   {
     description: 'Test bounds point of step-start easing',
     effect:     {
                   delay: 1000,
                   duration: 1000,
                   fill: 'both',
                   easing: 'steps(2, start)'
                 },
@@ -249,54 +248,19 @@ const gStepAndFramesTimingFunctionTests 
                   { currentTime: 1249, progress: 0.5 },
                   { currentTime: 1250, progress: 0 },
                   { currentTime: 1749, progress: 0 },
                   { currentTime: 1750, progress: 0.5 },
                   { currentTime: 2000, progress: 0.5 },
                   { currentTime: 2500, progress: 0.5 },
                 ]
   },
-  {
-    description: 'Test bounds point of frames easing',
-    effect:     {
-                  delay: 1000,
-                  duration: 1000,
-                  fill: 'both',
-                  easing: 'frames(2)'
-                },
-    conditions: [
-                  { currentTime: 0,    progress: 0 },
-                  { currentTime: 1000, progress: 0 },
-                  { currentTime: 1499, progress: 0 },
-                  { currentTime: 1500, progress: 1 },
-                  { currentTime: 2000, progress: 1 }
-                ]
-  },
-  {
-    description: 'Test bounds point of frames easing ' +
-                 'with iterationStart and delay',
-    effect:     {
-                  delay: 1000,
-                  duration: 1000,
-                  fill: 'both',
-                  iterationStart: 0.5,
-                  easing: 'frames(2)'
-                },
-    conditions: [
-                  { currentTime: 0,    progress: 1 },
-                  { currentTime: 1000, progress: 1 },
-                  { currentTime: 1499, progress: 1 },
-                  { currentTime: 1500, progress: 0 },
-                  { currentTime: 1999, progress: 0 },
-                  { currentTime: 2000, progress: 1 }
-                ]
-  }
 ];
 
-for (const options of gStepAndFramesTimingFunctionTests) {
+for (const options of gStepTimingFunctionTests) {
   test(t => {
     const target = createDiv(t);
     const animation = target.animate(null, options.effect);
     for (const condition of options.conditions) {
       animation.currentTime = condition.currentTime;
       assert_equals(animation.effect.getComputedTiming().progress,
                     condition.progress,
                     `Progress at ${animation.currentTime}ms`);