summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dom/animation/Animation.cpp23
-rw-r--r--dom/animation/Animation.h10
-rw-r--r--layout/style/nsTransitionManager.cpp9
-rw-r--r--layout/style/nsTransitionManager.h18
4 files changed, 53 insertions, 7 deletions
diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp
index 6dd583ed1e..cefdbb76d4 100644
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -230,6 +230,10 @@ Animation::SetTimelineNoUpdate(AnimationTimeline* aTimeline)
return;
}
+ StickyTimeDuration activeTime = mEffect
+ ? mEffect->GetComputedTiming().mActiveTime
+ : StickyTimeDuration();
+
RefPtr<AnimationTimeline> oldTimeline = mTimeline;
if (oldTimeline) {
oldTimeline->RemoveAnimation(this);
@@ -240,6 +244,9 @@ Animation::SetTimelineNoUpdate(AnimationTimeline* aTimeline)
mHoldTime.SetNull();
}
+ if (!aTimeline) {
+ MaybeQueueCancelEvent(activeTime);
+ }
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
}
@@ -771,6 +778,10 @@ Animation::CancelNoUpdate()
DispatchPlaybackEvent(NS_LITERAL_STRING("cancel"));
+ StickyTimeDuration activeTime = mEffect
+ ? mEffect->GetComputedTiming().mActiveTime
+ : StickyTimeDuration();
+
mHoldTime.SetNull();
mStartTime.SetNull();
@@ -779,6 +790,7 @@ Animation::CancelNoUpdate()
if (mTimeline) {
mTimeline->RemoveAnimation(this);
}
+ MaybeQueueCancelEvent(activeTime);
}
void
@@ -819,6 +831,17 @@ Animation::HasLowerCompositeOrderThan(const Animation& aOther) const
return thisTransition->HasLowerCompositeOrderThan(*otherTransition);
}
if (thisTransition || otherTransition) {
+ // Cancelled transitions no longer have an owning element. To be strictly
+ // correct we should store a strong reference to the owning element
+ // so that if we arrive here while sorting cancel events, we can sort
+ // them in the correct order.
+ //
+ // However, given that cancel events are almost always queued
+ // synchronously in some deterministic manner, we can be fairly sure
+ // that cancel events will be dispatched in a deterministic order
+ // (which is our only hard requirement until specs say otherwise).
+ // Furthermore, we only reach here when we have events with equal
+ // timestamps so this is an edge case we can probably ignore for now.
return thisTransition;
}
}
diff --git a/dom/animation/Animation.h b/dom/animation/Animation.h
index c59d7d6ce0..3263b30c44 100644
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -326,6 +326,16 @@ public:
void NotifyEffectTimingUpdated();
+ /**
+ * Used by subclasses to synchronously queue a cancel event in situations
+ * where the Animation may have been cancelled.
+ *
+ * We need to do this synchronously because after a CSS animation/transition
+ * is canceled, it will be released by its owning element and may not still
+ * exist when we would normally go to queue events on the next tick.
+ */
+ virtual void MaybeQueueCancelEvent(StickyTimeDuration aActiveTime) {};
+
protected:
void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
void SilentlySetPlaybackRate(double aPlaybackRate);
diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp
index 4a5ecdef6d..da12a0ecdb 100644
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -180,7 +180,7 @@ CSSTransition::UpdateTiming(SeekFlag aSeekFlag, SyncNotifyFlag aSyncNotifyFlag)
}
void
-CSSTransition::QueueEvents()
+CSSTransition::QueueEvents(StickyTimeDuration aActiveTime)
{
if (!mEffect ||
!mOwningElement.IsSet()) {
@@ -230,12 +230,9 @@ CSSTransition::QueueEvents()
// Handle cancel events firts
if (mPreviousTransitionPhase != TransitionPhase::Idle &&
currentPhase == TransitionPhase::Idle) {
- // FIXME: bug 1264125: We will need to get active time when cancelling
- // the transition.
- StickyTimeDuration activeTime(0);
- TimeStamp activeTimeStamp = ElapsedTimeToTimeStamp(activeTime);
+ TimeStamp activeTimeStamp = ElapsedTimeToTimeStamp(aActiveTime);
events.AppendElement(TransitionEventParams{ eTransitionCancel,
- activeTime,
+ aActiveTime,
activeTimeStamp });
}
diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h
index 56ec61572b..80042adcdf 100644
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -162,6 +162,18 @@ public:
Animation::CancelFromStyle();
+ // The above call to Animation::CancelFromStyle may cause a transitioncancel
+ // event to be queued. However, it will also remove the transition from its
+ // timeline. If this transition was the last animation attached to
+ // the timeline, the timeline will stop observing the refresh driver and
+ // there may be no subsequent tick fro dispatching animation events.
+ //
+ // To ensure the cancel event is dispatched we tell the timeline it needs to
+ // observe the refresh driver for at least one more tick.
+ if (mTimeline) {
+ mTimeline->NotifyAnimationUpdated(*this);
+ }
+
// It is important we do this *after* calling CancelFromStyle().
// This is because CancelFromStyle() will end up posting a restyle and
// that restyle should target the *transitions* level of the cascade.
@@ -214,6 +226,10 @@ public:
const TimeDuration& aStartTime,
double aPlaybackRate);
+ void MaybeQueueCancelEvent(StickyTimeDuration aActiveTime) override {
+ QueueEvents(aActiveTime);
+ }
+
protected:
virtual ~CSSTransition()
{
@@ -225,7 +241,7 @@ protected:
void UpdateTiming(SeekFlag aSeekFlag,
SyncNotifyFlag aSyncNotifyFlag) override;
- void QueueEvents();
+ void QueueEvents(StickyTimeDuration activeTime = StickyTimeDuration());
// The (pseudo-)element whose computed transition-property refers to this
// transition (if any).