Bug 1166164 part 5 - Make play() throw when it should seek to the end of an infinite effect; r=jwatt, r=smaug

This commit is contained in:
Brian Birtles 2015-05-19 14:00:48 +09:00
parent a233d4f41e
commit cd6af7c82a
11 changed files with 93 additions and 25 deletions

View File

@ -260,9 +260,9 @@ Animation::Finish(ErrorResult& aRv)
}
void
Animation::Play(LimitBehavior aLimitBehavior)
Animation::Play(ErrorResult& aRv, LimitBehavior aLimitBehavior)
{
DoPlay(aLimitBehavior);
DoPlay(aRv, aLimitBehavior);
PostUpdate();
}
@ -563,16 +563,10 @@ Animation::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
// http://w3c.github.io/web-animations/#play-an-animation
void
Animation::DoPlay(LimitBehavior aLimitBehavior)
Animation::DoPlay(ErrorResult& aRv, LimitBehavior aLimitBehavior)
{
bool abortedPause = mPendingState == PendingState::PausePending;
bool reuseReadyPromise = false;
if (mPendingState != PendingState::NotPending) {
CancelPendingTasks();
reuseReadyPromise = true;
}
Nullable<TimeDuration> currentTime = GetCurrentTime();
if (mPlaybackRate > 0.0 &&
(currentTime.IsNull() ||
@ -585,11 +579,21 @@ Animation::DoPlay(LimitBehavior aLimitBehavior)
(aLimitBehavior == LimitBehavior::AutoRewind &&
(currentTime.Value().ToMilliseconds() <= 0.0 ||
currentTime.Value() > EffectEnd())))) {
if (EffectEnd() == TimeDuration::Forever()) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
mHoldTime.SetValue(TimeDuration(EffectEnd()));
} else if (mPlaybackRate == 0.0 && currentTime.IsNull()) {
mHoldTime.SetValue(TimeDuration(0));
}
bool reuseReadyPromise = false;
if (mPendingState != PendingState::NotPending) {
CancelPendingTasks();
reuseReadyPromise = true;
}
// If the hold time is null then we're either already playing normally (and
// we can ignore this call) or we aborted a pending pause operation (in which
// case, for consistency, we need to go through the motions of doing an

View File

@ -101,7 +101,7 @@ public:
virtual Promise* GetFinished(ErrorResult& aRv);
void Cancel();
virtual void Finish(ErrorResult& aRv);
virtual void Play(LimitBehavior aLimitBehavior);
virtual void Play(ErrorResult& aRv, LimitBehavior aLimitBehavior);
virtual void Pause();
bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; }
@ -117,7 +117,10 @@ public:
void SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime,
ErrorResult& aRv);
virtual AnimationPlayState PlayStateFromJS() const { return PlayState(); }
virtual void PlayFromJS() { Play(LimitBehavior::AutoRewind); }
virtual void PlayFromJS(ErrorResult& aRv)
{
Play(aRv, LimitBehavior::AutoRewind);
}
/**
* PauseFromJS is currently only here for symmetry with PlayFromJS but
* in future we will likely have to flush style in
@ -280,7 +283,7 @@ protected:
void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
void SilentlySetPlaybackRate(double aPlaybackRate);
void DoCancel();
void DoPlay(LimitBehavior aLimitBehavior);
void DoPlay(ErrorResult& aRv, LimitBehavior aLimitBehavior);
void DoPause();
void ResumeAt(const TimeDuration& aReadyTime);
void PauseAt(const TimeDuration& aReadyTime);

View File

@ -0,0 +1,35 @@
<!doctype html>
<meta charset=utf-8>
<script src="../testcommon.js"></script>
<style>
@keyframes abc {
to { transform: translate(10px) }
}
</style>
<body>
<script>
'use strict';
async_test(function(t) {
var div = addDiv(t, { style: 'animation: abc 100s infinite' });
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(function() {
// Seek to a time outside the active range so that play() will have to
// snap back to the start
animation.currentTime = -5000;
animation.playbackRate = -1;
assert_throws('InvalidStateError',
function () { animation.play(); },
'Expect InvalidStateError exception on calling play() ' +
'with a negative playbackRate and infinite-duration ' +
'animation');
t.done();
}));
}, 'play() throws when seeking an infinite-duration animation played in ' +
'reverse');
done();
</script>
</body>

View File

@ -0,0 +1,15 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
'use strict';
setup({explicit_done: true});
SpecialPowers.pushPrefEnv(
{ "set": [["dom.animations-api.core.enabled", true]]},
function() {
window.open("file_animation-play.html");
});
</script>
</html>

View File

@ -14,6 +14,8 @@ support-files = css-animations/file_animation-finish.html
support-files = css-animations/file_animation-finished.html
[css-animations/test_animation-pausing.html]
support-files = css-animations/file_animation-pausing.html
[css-animations/test_animation-play.html]
support-files = css-animations/file_animation-play.html
[css-animations/test_animation-playstate.html]
support-files = css-animations/file_animation-playstate.html
[css-animations/test_animation-ready.html]

View File

@ -80,7 +80,7 @@ function flushComputedStyle(elem) {
for (var funcName of ["async_test", "assert_not_equals", "assert_equals",
"assert_approx_equals", "assert_less_than_equal",
"assert_between_inclusive", "assert_true", "assert_false",
"test"]) {
"assert_throws", "test"]) {
window[funcName] = opener[funcName].bind(opener);
}

View File

@ -33,7 +33,7 @@ interface Animation {
void cancel ();
[Throws]
void finish ();
[BinaryName="playFromJS"]
[Throws, BinaryName="playFromJS"]
void play ();
[BinaryName="pauseFromJS"]
void pause ();

View File

@ -37,10 +37,10 @@ CSSAnimation::GetReady(ErrorResult& aRv)
}
void
CSSAnimation::Play(LimitBehavior aLimitBehavior)
CSSAnimation::Play(ErrorResult &aRv, LimitBehavior aLimitBehavior)
{
mPauseShouldStick = false;
Animation::Play(aLimitBehavior);
Animation::Play(aRv, aLimitBehavior);
}
void
@ -60,12 +60,12 @@ CSSAnimation::PlayStateFromJS() const
}
void
CSSAnimation::PlayFromJS()
CSSAnimation::PlayFromJS(ErrorResult& aRv)
{
// Note that flushing style below might trigger calls to
// PlayFromStyle()/PauseFromStyle() on this object.
FlushStyle();
Animation::PlayFromJS();
Animation::PlayFromJS(aRv);
}
void
@ -73,7 +73,10 @@ CSSAnimation::PlayFromStyle()
{
mIsStylePaused = false;
if (!mPauseShouldStick) {
DoPlay(Animation::LimitBehavior::Continue);
ErrorResult rv;
DoPlay(rv, Animation::LimitBehavior::Continue);
// play() should not throw when LimitBehavior is Continue
MOZ_ASSERT(!rv.Failed(), "Unexpected exception playing animation");
}
}

View File

@ -65,11 +65,11 @@ public:
virtual CSSAnimation* AsCSSAnimation() override { return this; }
virtual dom::Promise* GetReady(ErrorResult& aRv) override;
virtual void Play(LimitBehavior aLimitBehavior) override;
virtual void Play(ErrorResult& aRv, LimitBehavior aLimitBehavior) override;
virtual void Pause() override;
virtual dom::AnimationPlayState PlayStateFromJS() const override;
virtual void PlayFromJS() override;
virtual void PlayFromJS(ErrorResult& aRv) override;
void PlayFromStyle();
void PauseFromStyle();

View File

@ -93,10 +93,10 @@ CSSTransition::PlayStateFromJS() const
}
void
CSSTransition::PlayFromJS()
CSSTransition::PlayFromJS(ErrorResult& aRv)
{
FlushStyle();
Animation::PlayFromJS();
Animation::PlayFromJS(aRv);
}
CommonAnimationManager*

View File

@ -85,11 +85,17 @@ public:
virtual CSSTransition* AsCSSTransition() override { return this; }
virtual dom::AnimationPlayState PlayStateFromJS() const override;
virtual void PlayFromJS() override;
virtual void PlayFromJS(ErrorResult& aRv) override;
// A variant of Play() that avoids posting style updates since this method
// is expected to be called whilst already updating style.
void PlayFromStyle() { DoPlay(Animation::LimitBehavior::Continue); }
void PlayFromStyle()
{
ErrorResult rv;
DoPlay(rv, Animation::LimitBehavior::Continue);
// play() should not throw when LimitBehavior is Continue
MOZ_ASSERT(!rv.Failed(), "Unexpected exception playing transition");
}
protected:
virtual ~CSSTransition() { }