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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Boris Chiou 2018-10-26 18:03:24 +00:00
parent 185c47a7b2
commit adff31eff9
31 changed files with 38 additions and 481 deletions

View File

@ -25,27 +25,6 @@ const TEST_DATA = [
},
],
},
{
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: [

View File

@ -44,7 +44,7 @@
{ opacity: 1 },
{ opacity: 0 },
],
"frames(5)"
"steps(5)"
);
createAnimation(

View File

@ -149,19 +149,6 @@
"steps(2)"
);
createAnimation(
"frames-keyframe",
[
{
easing: "frames(5)",
opacity: 0,
},
{
opacity: 1,
},
]
);
createAnimation(
"narrow-offsets",
[

View File

@ -49,9 +49,7 @@ const closeAnimationInspector = async function() {
/**
* 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 => {
@ -60,7 +58,6 @@ const enableAnimationFeatures = function() {
["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);
});
};

View File

@ -41,7 +41,6 @@ exports.CSS_PROPERTIES = {
"ease-in-out",
"ease-out",
"forwards",
"frames",
"infinite",
"inherit",
"initial",
@ -167,7 +166,6 @@ exports.CSS_PROPERTIES = {
"ease-in",
"ease-in-out",
"ease-out",
"frames",
"inherit",
"initial",
"linear",
@ -1230,7 +1228,6 @@ exports.CSS_PROPERTIES = {
"ease-in",
"ease-in-out",
"ease-out",
"frames",
"inherit",
"initial",
"linear",
@ -1293,7 +1290,6 @@ exports.CSS_PROPERTIES = {
"ease-in",
"ease-in-out",
"ease-out",
"frames",
"inherit",
"initial",
"linear",
@ -1496,7 +1492,6 @@ exports.CSS_PROPERTIES = {
"ease-in-out",
"ease-out",
"forwards",
"frames",
"infinite",
"inherit",
"initial",
@ -1622,7 +1617,6 @@ exports.CSS_PROPERTIES = {
"ease-in",
"ease-in-out",
"ease-out",
"frames",
"inherit",
"initial",
"linear",
@ -2678,7 +2672,6 @@ exports.CSS_PROPERTIES = {
"ease-in",
"ease-in-out",
"ease-out",
"frames",
"inherit",
"initial",
"linear",
@ -2741,7 +2734,6 @@ exports.CSS_PROPERTIES = {
"ease-in",
"ease-in-out",
"ease-out",
"frames",
"inherit",
"initial",
"linear",
@ -3203,7 +3195,6 @@ exports.CSS_PROPERTIES = {
"ease-in-out",
"ease-out",
"forwards",
"frames",
"infinite",
"inherit",
"initial",
@ -3329,7 +3320,6 @@ exports.CSS_PROPERTIES = {
"ease-in",
"ease-in-out",
"ease-out",
"frames",
"inherit",
"initial",
"linear",
@ -8991,7 +8981,6 @@ exports.CSS_PROPERTIES = {
"ease-in",
"ease-in-out",
"ease-out",
"frames",
"inherit",
"initial",
"linear",
@ -9054,7 +9043,6 @@ exports.CSS_PROPERTIES = {
"ease-in",
"ease-in-out",
"ease-out",
"frames",
"inherit",
"initial",
"linear",

View File

@ -18,7 +18,7 @@ ComputedTimingFunction::Init(const nsTimingFunction &aFunction)
mTimingFunction.Init(aFunction.mFunc.mX1, aFunction.mFunc.mY1,
aFunction.mFunc.mX2, aFunction.mFunc.mY2);
} else {
mStepsOrFrames = aFunction.mStepsOrFrames;
mSteps = aFunction.mSteps;
}
}
@ -61,22 +61,6 @@ StepTiming(uint32_t aSteps,
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,
@ -128,9 +112,7 @@ ComputedTimingFunction::GetValue(
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
@ -146,10 +128,9 @@ ComputedTimingFunction::Compare(const ComputedTimingFunction& aRhs) const
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);
}
}
@ -169,10 +150,7 @@ ComputedTimingFunction::AppendToString(nsAString& aResult) const
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);

View File

@ -35,16 +35,10 @@ public:
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);
}
@ -68,19 +62,14 @@ public:
{
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
{
@ -94,7 +83,7 @@ public:
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
{
@ -116,16 +105,16 @@ 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

View File

@ -31,10 +31,6 @@ AnimationUtils::TimingFunctionToComputedTimingFunction(
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");

View File

@ -100,15 +100,10 @@ struct StepFunction {
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

View File

@ -121,7 +121,7 @@ function do_test() {
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.");

View File

@ -420,10 +420,6 @@ ToTimingFunction(const Maybe<ComputedTimingFunction>& aCTF)
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));
}

View File

@ -4594,13 +4594,9 @@ nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList,
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);

View File

@ -3324,13 +3324,13 @@ 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:

View File

@ -291,15 +291,6 @@ nsStyleUtil::AppendStepsTimingFunction(nsTimingFunction::Type aType,
}
}
/* 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,

View File

@ -79,8 +79,6 @@ public:
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);

View File

@ -20,16 +20,13 @@ struct nsTimingFunction
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(
@ -51,14 +48,12 @@ struct nsTimingFunction
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)
@ -75,7 +70,7 @@ struct nsTimingFunction
float mY2;
} mFunc;
struct {
uint32_t mStepsOrFrames;
uint32_t mSteps;
};
};
@ -94,7 +89,7 @@ struct nsTimingFunction
mFunc.mX2 = aOther.mFunc.mX2;
mFunc.mY2 = aOther.mFunc.mY2;
} else {
mStepsOrFrames = aOther.mStepsOrFrames;
mSteps = aOther.mSteps;
}
return *this;
@ -109,7 +104,7 @@ struct nsTimingFunction
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

View File

@ -6439,14 +6439,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.font-variations.enabled")) {
.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",

View File

@ -678,19 +678,6 @@ VARCACHE_PREF(
)
#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",

View File

@ -369,22 +369,6 @@ impl PropertyAnimation {
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)

View File

@ -22,17 +22,7 @@ impl nsTimingFunction {
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;
}
}
@ -74,10 +64,6 @@ impl From<TimingFunction> for nsTimingFunction {
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,
@ -105,7 +91,7 @@ impl From<nsTimingFunction> for ComputedTimingFunction {
.__bindgen_anon_1
.__bindgen_anon_1
.as_ref()
.mStepsOrFrames
.mSteps
},
StepPosition::Start,
),
@ -115,17 +101,10 @@ impl From<nsTimingFunction> for ComputedTimingFunction {
.__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),

View File

@ -92,7 +92,7 @@ pub struct TransformOrigin<H, V, 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> {
@ -111,9 +111,6 @@ pub enum TimingFunction<Integer, Number> {
#[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)]

View File

@ -350,19 +350,6 @@ impl<S> OriginComponent<S> {
}
}
#[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,
@ -406,14 +393,6 @@ impl Parse for TimingFunction {
}).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()))
@ -440,9 +419,6 @@ impl ToComputedValue for TimingFunction {
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)
},
}
}
@ -465,9 +441,6 @@ impl ToComputedValue for TimingFunction {
Integer::from_computed_value(&(steps as i32)),
position,
),
generic::TimingFunction::Frames(frames) => {
generic::TimingFunction::Frames(Integer::from_computed_value(&(frames as i32)))
},
}
}
}

View File

@ -1 +1 @@
prefs: [dom.animations-api.core.enabled:true, layout.css.frames-timing.enabled:true]
prefs: [dom.animations-api.core.enabled:true]

View File

@ -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]

View File

@ -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>

View File

@ -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>

View File

@ -24,7 +24,7 @@ runListValuedPropertyTests('animation-timing-function', [
]);
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>

View File

@ -24,7 +24,7 @@ runListValuedPropertyTests('transition-timing-function', [
]);
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>

View File

@ -40,11 +40,6 @@ const gEasingTests = [
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)
@ -111,14 +106,6 @@ const gInvalidEasings = [
'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
@ -131,5 +118,4 @@ const gRoundtripEasings = [
'cubic-bezier(0.1, 5, 0.23, 0)',
'steps(3, start)',
'steps(3)',
'frames(3)',
];

View File

@ -150,13 +150,6 @@ function stepStart(nsteps) {
};
}
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() {

View File

@ -32,10 +32,9 @@ for (const params of gEasingTests) {
}, `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: {
@ -254,44 +253,9 @@ const gStepAndFramesTimingFunctionTests = [
{ 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);