Bug 1412765 - Add Animation.pending member; r=bz,hiro

This reflects the change made to the Web Animations specification in:

  9e2053f553
  1c3415f4cc
  (I got it wrong the first time. The second commit fixes the first.)

And discussed in:

  https://github.com/w3c/web-animations/issues/196

In summary, we are splitting the "pending" play state out into a separate
boolean member so that it is possible to distinguish between "play-pending" and
"pause-pending" and because most of the time when you check for
animation.playState === 'running' you also really want to include play-pending
animations.

MozReview-Commit-ID: IJSNoZTKW2I

--HG--
extra : rebase_source : 5d17239fd087cfe3cce1c9697eff97d062b6dd4b
This commit is contained in:
Brian Birtles 2017-11-21 17:10:59 +09:00
Родитель bad7dc839d
Коммит e83e1a5e71
8 изменённых файлов: 59 добавлений и 24 удалений

Просмотреть файл

@ -386,21 +386,23 @@ Animation::SetPlaybackRate(double aPlaybackRate)
AnimationPlayState
Animation::PlayState() const
{
if (mPendingState != PendingState::NotPending) {
if (!nsContentUtils::AnimationsAPIPendingMemberEnabled() && Pending()) {
return AnimationPlayState::Pending;
}
Nullable<TimeDuration> currentTime = GetCurrentTime();
if (currentTime.IsNull()) {
if (currentTime.IsNull() && !Pending()) {
return AnimationPlayState::Idle;
}
if (mStartTime.IsNull()) {
if (mPendingState == PendingState::PausePending ||
(mStartTime.IsNull() && !Pending())) {
return AnimationPlayState::Paused;
}
if ((mPlaybackRate > 0.0 && currentTime.Value() >= EffectEnd()) ||
(mPlaybackRate < 0.0 && currentTime.Value() <= TimeDuration())) {
if (!currentTime.IsNull() &&
((mPlaybackRate > 0.0 && currentTime.Value() >= EffectEnd()) ||
(mPlaybackRate < 0.0 && currentTime.Value() <= TimeDuration()))) {
return AnimationPlayState::Finished;
}
@ -418,7 +420,7 @@ Animation::GetReady(ErrorResult& aRv)
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
if (PlayState() != AnimationPlayState::Pending) {
if (!Pending()) {
mReady->MaybeResolve(this);
}
return mReady;
@ -638,7 +640,7 @@ Animation::TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime)
// due to the handling of possibly orphaned animations in Tick(), this
// animation got started whilst still being in another document's pending
// animation map.
if (PlayState() != AnimationPlayState::Pending) {
if (!Pending()) {
return;
}
@ -654,7 +656,7 @@ Animation::TriggerNow()
// is cancelled and its rendered document can't be reached, we can end up
// with the animation still in a pending player tracker even after it is
// no longer pending.
if (PlayState() != AnimationPlayState::Pending) {
if (!Pending()) {
return;
}
@ -994,13 +996,11 @@ Animation::ComposeStyle(ComposeAnimationResult&& aComposeResult,
// immediately before updating the style rule and then restore it immediately
// afterwards. This is purely to prevent visual flicker. Other behavior
// such as dispatching events continues to rely on the regular timeline time.
AnimationPlayState playState = PlayState();
bool pending = Pending();
{
AutoRestore<Nullable<TimeDuration>> restoreHoldTime(mHoldTime);
if (playState == AnimationPlayState::Pending &&
mHoldTime.IsNull() &&
!mStartTime.IsNull()) {
if (pending && mHoldTime.IsNull() && !mStartTime.IsNull()) {
Nullable<TimeDuration> timeToUse = mPendingReadyTime;
if (timeToUse.IsNull() &&
mTimeline &&
@ -1020,8 +1020,8 @@ Animation::ComposeStyle(ComposeAnimationResult&& aComposeResult,
}
}
MOZ_ASSERT(playState == PlayState(),
"Play state should not change during the course of compositing");
MOZ_ASSERT(pending == Pending(),
"Pending state should not change during the course of compositing");
}
void

Просмотреть файл

@ -110,6 +110,7 @@ public:
double PlaybackRate() const { return mPlaybackRate; }
void SetPlaybackRate(double aPlaybackRate);
AnimationPlayState PlayState() const;
bool Pending() const { return mPendingState != PendingState::NotPending; }
virtual Promise* GetReady(ErrorResult& aRv);
virtual Promise* GetFinished(ErrorResult& aRv);
void Cancel();
@ -133,6 +134,7 @@ public:
void SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime,
ErrorResult& aRv);
virtual AnimationPlayState PlayStateFromJS() const { return PlayState(); }
virtual bool PendingFromJS() const { return Pending(); }
virtual void PlayFromJS(ErrorResult& aRv)
{
Play(aRv, LimitBehavior::AutoRewind);
@ -153,9 +155,7 @@ public:
virtual void Tick();
bool NeedsTicks() const
{
AnimationPlayState playState = PlayState();
return playState == AnimationPlayState::Running ||
playState == AnimationPlayState::Pending;
return Pending() || PlayState() == AnimationPlayState::Running;
}
/**
@ -263,6 +263,12 @@ public:
bool IsPausedOrPausing() const
{
// FIXME: Once we drop the dom.animations-api.pending-member.enabled pref we
// can simplify the following check to just:
//
// return PlayState() == AnimationPlayState::Paused;
//
// And at that point we might not need this method at all.
return PlayState() == AnimationPlayState::Paused ||
mPendingState == PendingState::PausePending;
}
@ -278,6 +284,10 @@ public:
bool IsPlaying() const
{
// FIXME: Once we drop the dom.animations-api.pending-member.enabled pref we
// can simplify the last two conditions to just:
//
// PlayState() == AnimationPlayState::Running
return mPlaybackRate != 0.0 &&
mTimeline &&
!mTimeline->GetCurrentTime().IsNull() &&

Просмотреть файл

@ -29,6 +29,8 @@ interface Animation : EventTarget {
attribute double playbackRate;
[BinaryName="playStateFromJS"]
readonly attribute AnimationPlayState playState;
[Pref="dom.animations-api.pending-member.enabled", BinaryName="pendingFromJS"]
readonly attribute boolean pending;
[Func="nsDocument::IsWebAnimationsEnabled", Throws]
readonly attribute Promise<Animation> ready;
[Func="nsDocument::IsWebAnimationsEnabled", Throws]

Просмотреть файл

@ -731,9 +731,8 @@ AddAnimationsForProperty(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
// Currently this only happens when the timeline is driven by a refresh
// driver under test control. In this case, the next time the refresh
// driver is advanced it will trigger any pending animations.
if (anim->PlayState() == AnimationPlayState::Pending &&
(anim->GetTimeline() &&
!anim->GetTimeline()->TracksWallclockTime())) {
if (anim->Pending() &&
(anim->GetTimeline() && !anim->GetTimeline()->TracksWallclockTime())) {
continue;
}

Просмотреть файл

@ -89,6 +89,15 @@ CSSAnimation::PlayStateFromJS() const
return Animation::PlayStateFromJS();
}
bool
CSSAnimation::PendingFromJS() const
{
// Flush style since, for example, if the animation-play-state was just
// changed its possible we should now be pending.
FlushStyle();
return Animation::PendingFromJS();
}
void
CSSAnimation::PlayFromJS(ErrorResult& aRv)
{

Просмотреть файл

@ -122,8 +122,9 @@ public:
// specifies that reading playState does *not* flush style (and we drop the
// following override), then we should update tabbrowser.xml to check
// the playState instead.
virtual AnimationPlayState PlayStateFromJS() const override;
virtual void PlayFromJS(ErrorResult& aRv) override;
AnimationPlayState PlayStateFromJS() const override;
bool PendingFromJS() const override;
void PlayFromJS(ErrorResult& aRv) override;
void PlayFromStyle();
void PauseFromStyle();

Просмотреть файл

@ -176,6 +176,19 @@ CSSTransition::PlayStateFromJS() const
return Animation::PlayStateFromJS();
}
bool
CSSTransition::PendingFromJS() const
{
// Transitions don't become pending again after they start running but, if
// while the transition is still pending, style is updated in such a way
// that the transition will be canceled, we need to report false here.
// Hence we need to flush, but only when we're pending.
if (Pending()) {
FlushStyle();
}
return Animation::PendingFromJS();
}
void
CSSTransition::PlayFromJS(ErrorResult& aRv)
{

Просмотреть файл

@ -139,8 +139,9 @@ public:
void GetTransitionProperty(nsString& aRetVal) const;
// Animation interface overrides
virtual AnimationPlayState PlayStateFromJS() const override;
virtual void PlayFromJS(ErrorResult& aRv) override;
AnimationPlayState PlayStateFromJS() const override;
bool PendingFromJS() const override;
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.