Bug 1166164 part 6 - Make pausing from idle set the current time; r=jwatt, r=smaug

As proposed:

  https://lists.w3.org/Archives/Public/public-fx/2015AprJun/0013.html (item g)

And agreed upon here:

  https://lists.w3.org/Archives/Public/public-fx/2015AprJun/0031.html
This commit is contained in:
Brian Birtles 2015-05-19 14:55:26 +09:00
parent 640db05e68
commit 8295d11320
6 changed files with 92 additions and 12 deletions

View File

@ -267,9 +267,9 @@ Animation::Play(ErrorResult& aRv, LimitBehavior aLimitBehavior)
}
void
Animation::Pause()
Animation::Pause(ErrorResult& aRv)
{
DoPause();
DoPause(aRv);
PostUpdate();
}
@ -639,12 +639,25 @@ Animation::DoPlay(ErrorResult& aRv, LimitBehavior aLimitBehavior)
// http://w3c.github.io/web-animations/#pause-an-animation
void
Animation::DoPause()
Animation::DoPause(ErrorResult& aRv)
{
if (IsPausedOrPausing()) {
return;
}
// If we are transitioning from idle, fill in the current time
if (GetCurrentTime().IsNull()) {
if (mPlaybackRate >= 0.0) {
mHoldTime.SetValue(TimeDuration(0));
} else {
if (EffectEnd() == TimeDuration::Forever()) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
mHoldTime.SetValue(TimeDuration(EffectEnd()));
}
}
bool reuseReadyPromise = false;
if (mPendingState == PendingState::PlayPending) {
CancelPendingTasks();

View File

@ -102,7 +102,7 @@ public:
void Cancel();
virtual void Finish(ErrorResult& aRv);
virtual void Play(ErrorResult& aRv, LimitBehavior aLimitBehavior);
virtual void Pause();
virtual void Pause(ErrorResult& aRv);
bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; }
// Wrapper functions for Animation DOM methods when called
@ -126,7 +126,7 @@ public:
* in future we will likely have to flush style in
* CSSAnimation::PauseFromJS so we leave it for now.
*/
void PauseFromJS() { Pause(); }
void PauseFromJS(ErrorResult& aRv) { Pause(aRv); }
// Wrapper functions for Animation DOM methods when called from style.
//
// Typically these DOM methods also notify style of changes but when
@ -284,7 +284,7 @@ protected:
void SilentlySetPlaybackRate(double aPlaybackRate);
void DoCancel();
void DoPlay(ErrorResult& aRv, LimitBehavior aLimitBehavior);
void DoPause();
void DoPause(ErrorResult& aRv);
void ResumeAt(const TimeDuration& aReadyTime);
void PauseAt(const TimeDuration& aReadyTime);
void FinishPendingAt(const TimeDuration& aReadyTime)
@ -337,7 +337,7 @@ protected:
Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
double mPlaybackRate;
// A Promise that is replaced on each call to Play() (and in future Pause())
// A Promise that is replaced on each call to Play()
// and fulfilled when Play() is successfully completed.
// This object is lazily created by GetReady.
// See http://w3c.github.io/web-animations/#current-ready-promise

View File

@ -203,6 +203,60 @@ async_test(function(t) {
}));
}, 'Setting the current time completes a pending pause');
async_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 1000s' });
var animation = div.getAnimations()[0];
// Go to idle state then pause
animation.cancel();
animation.pause();
assert_equals(animation.currentTime, 0, 'currentTime is set to 0');
assert_equals(animation.startTime, null, 'startTime is not set');
assert_equals(animation.playState, 'pending', 'initially pause-pending');
// Check it still resolves as expected
animation.ready.then(t.step_func(function() {
assert_equals(animation.playState, 'paused',
'resolves to paused state asynchronously');
assert_equals(animation.currentTime, 0,
'keeps the initially set currentTime');
t.done();
}));
}, 'pause() from idle');
async_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 1000s' });
var animation = div.getAnimations()[0];
animation.cancel();
animation.playbackRate = -1;
animation.pause();
assert_equals(animation.currentTime, 1000 * 1000,
'currentTime is set to the effect end');
animation.ready.then(t.step_func(function() {
assert_equals(animation.currentTime, 1000 * 1000,
'keeps the initially set currentTime');
t.done();
}));
}, 'pause() from idle with a negative playbackRate');
test(function(t) {
var div = addDiv(t, { style: 'animation: anim 1000s infinite' });
var animation = div.getAnimations()[0];
animation.cancel();
animation.playbackRate = -1;
assert_throws('InvalidStateError',
function () { animation.pause(); },
'Expect InvalidStateError exception on calling pause() ' +
'from idle with a negative playbackRate and ' +
'infinite-duration animation');
}, 'pause() from idle with a negative playbackRate and endless effect');
done();
</script>
</body>

View File

@ -35,7 +35,7 @@ interface Animation {
void finish ();
[Throws, BinaryName="playFromJS"]
void play ();
[BinaryName="pauseFromJS"]
[Throws, BinaryName="pauseFromJS"]
void pause ();
/*
void reverse ();

View File

@ -44,10 +44,10 @@ CSSAnimation::Play(ErrorResult &aRv, LimitBehavior aLimitBehavior)
}
void
CSSAnimation::Pause()
CSSAnimation::Pause(ErrorResult& aRv)
{
mPauseShouldStick = true;
Animation::Pause();
Animation::Pause(aRv);
}
AnimationPlayState
@ -89,7 +89,20 @@ CSSAnimation::PauseFromStyle()
}
mIsStylePaused = true;
DoPause();
ErrorResult rv;
DoPause(rv);
// pause() should only throw when *all* of the following conditions are true:
// - we are in the idle state, and
// - we have a negative playback rate, and
// - we have an infinitely repeating animation
// The first two conditions will never happen under regular style processing
// but could happen if an author made modifications to the Animation object
// and then updated animation-play-state. It's an unusual case and there's
// no obvious way to pass on the exception information so we just silently
// fail for now.
if (rv.Failed()) {
NS_WARNING("Unexpected exception pausing animation - silently failing");
}
}
void

View File

@ -66,7 +66,7 @@ public:
virtual dom::Promise* GetReady(ErrorResult& aRv) override;
virtual void Play(ErrorResult& aRv, LimitBehavior aLimitBehavior) override;
virtual void Pause() override;
virtual void Pause(ErrorResult& aRv) override;
virtual dom::AnimationPlayState PlayStateFromJS() const override;
virtual void PlayFromJS(ErrorResult& aRv) override;