Bug 1302648 part 5 - Queue animationcancel when animation status is idle. r?birtles
MozReview-Commit-ID: DRjWboQwR0A
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -246,11 +246,31 @@ inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
DelayedEventDispatcher<EventInfo>& aField,
const char* aName,
uint32_t aFlags = 0)
{
aField.Traverse(&aCallback, aName);
}
+// Return the TransitionPhase or AnimationPhase to use when the animation
+// doesn't have a target effect.
+template <typename PhaseType>
+PhaseType GetAnimationPhaseWithoutEffect(const dom::Animation& aAnimation)
+{
+ MOZ_ASSERT(!aAnimation.GetEffect(),
+ "Should only be called when we do not have an effect");
+
+ Nullable<TimeDuration> currentTime = aAnimation.GetCurrentTime();
+ if (currentTime.IsNull()) {
+ return PhaseType::Idle;
+ }
+
+ // If we don't have a target effect, the duration will be zero so the phase is
+ // 'before' if the current time is less than zero.
+ return currentTime.Value() < TimeDuration()
+ ? PhaseType::Before
+ : PhaseType::After;
+};
+
} // namespace mozilla
#endif /* !defined(mozilla_css_AnimationCommon_h) */
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -154,22 +154,18 @@ CSSAnimation::HasLowerCompositeOrderThan
return mOwningElement.LessThan(aOther.mOwningElement);
}
// 2. (Same element and pseudo): Sort by position in animation-name
return mAnimationIndex < aOther.mAnimationIndex;
}
void
-CSSAnimation::QueueEvents()
+CSSAnimation::QueueEvents(StickyTimeDuration aActiveTime)
{
- if (!mEffect) {
- return;
- }
-
// If the animation is pending, we ignore animation events until we finish
// pending.
if (mPendingState != PendingState::NotPending) {
return;
}
// CSS animations dispatch events at their owning element. This allows
// script to repurpose a CSS animation to target a different element,
@@ -193,47 +189,68 @@ CSSAnimation::QueueEvents()
MOZ_ASSERT(owningElement, "Owning element should be set");
// Get the nsAnimationManager so we can queue events on it
nsPresContext* presContext = mOwningElement.GetRenderedPresContext();
if (!presContext) {
return;
}
nsAnimationManager* manager = presContext->AnimationManager();
- ComputedTiming computedTiming = mEffect->GetComputedTiming();
-
- AnimationPhase currentPhase = computedTiming.mPhase;
- uint64_t currentIteration = computedTiming.mCurrentIteration;
- if (currentPhase == mPreviousPhase &&
- currentIteration == mPreviousIteration) {
- return;
- }
const StickyTimeDuration zeroDuration;
- StickyTimeDuration intervalStartTime =
- std::max(std::min(StickyTimeDuration(-mEffect->SpecifiedTiming().mDelay),
- computedTiming.mActiveDuration),
- zeroDuration);
- StickyTimeDuration intervalEndTime =
- std::max(std::min((EffectEnd() - mEffect->SpecifiedTiming().mDelay),
- computedTiming.mActiveDuration),
- zeroDuration);
+ uint64_t currentIteration = 0;
+ ComputedTiming::AnimationPhase currentPhase;
+ StickyTimeDuration intervalStartTime;
+ StickyTimeDuration intervalEndTime;
+ StickyTimeDuration iterationStartTime;
- uint64_t iterationBoundary = mPreviousIteration > currentIteration
- ? currentIteration + 1
- : currentIteration;
- StickyTimeDuration iterationStartTime =
- computedTiming.mDuration.MultDouble(
- (iterationBoundary - computedTiming.mIterationStart));
+ if (!mEffect) {
+ currentPhase = GetAnimationPhaseWithoutEffect
+ <ComputedTiming::AnimationPhase>(*this);
+ } else {
+ ComputedTiming computedTiming = mEffect->GetComputedTiming();
+ currentPhase = computedTiming.mPhase;
+ currentIteration = computedTiming.mCurrentIteration;
+ if (currentPhase == mPreviousPhase &&
+ currentIteration == mPreviousIteration) {
+ return;
+ }
+ intervalStartTime =
+ std::max(std::min(StickyTimeDuration(-mEffect->SpecifiedTiming().mDelay),
+ computedTiming.mActiveDuration),
+ zeroDuration);
+ intervalEndTime =
+ std::max(std::min((EffectEnd() - mEffect->SpecifiedTiming().mDelay),
+ computedTiming.mActiveDuration),
+ zeroDuration);
+
+ uint64_t iterationBoundary = mPreviousIteration > currentIteration
+ ? currentIteration + 1
+ : currentIteration;
+ iterationStartTime =
+ computedTiming.mDuration.MultDouble(
+ (iterationBoundary - computedTiming.mIterationStart));
+ }
TimeStamp startTimeStamp = ElapsedTimeToTimeStamp(intervalStartTime);
TimeStamp endTimeStamp = ElapsedTimeToTimeStamp(intervalEndTime);
TimeStamp iterationTimeStamp = ElapsedTimeToTimeStamp(iterationStartTime);
AutoTArray<AnimationEventParams, 2> events;
+
+ // Handle cancel event first
+ if ((mPreviousPhase != AnimationPhase::Idle &&
+ mPreviousPhase != AnimationPhase::After) &&
+ currentPhase == AnimationPhase::Idle) {
+ TimeStamp activeTimeStamp = ElapsedTimeToTimeStamp(aActiveTime);
+ events.AppendElement(AnimationEventParams{ eAnimationCancel,
+ aActiveTime,
+ activeTimeStamp });
+ }
+
switch (mPreviousPhase) {
case AnimationPhase::Idle:
case AnimationPhase::Before:
if (currentPhase == AnimationPhase::Active) {
events.AppendElement(AnimationEventParams{ eAnimationStart,
intervalStartTime,
startTimeStamp });
} else if (currentPhase == AnimationPhase::After) {
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -127,17 +127,17 @@ public:
// We need to do this *after* calling CancelFromStyle() since
// CancelFromStyle might synchronously trigger a cancel event for which
// we need an owning element to target the event at.
mOwningElement = OwningElementRef();
}
void Tick() override;
- void QueueEvents();
+ void QueueEvents(StickyTimeDuration aActiveTime = StickyTimeDuration());
bool IsStylePaused() const { return mIsStylePaused; }
bool HasLowerCompositeOrderThan(const CSSAnimation& aOther) const;
void SetAnimationIndex(uint64_t aIndex)
{
MOZ_ASSERT(IsTiedToMarkup());
@@ -156,16 +156,20 @@ public:
void SetOwningElement(const OwningElementRef& aElement)
{
mOwningElement = aElement;
}
// True for animations that are generated from CSS markup and continue to
// reflect changes to that markup.
bool IsTiedToMarkup() const { return mOwningElement.IsSet(); }
+ void MaybeQueueCancelEvent(StickyTimeDuration aActiveTime) override {
+ QueueEvents(aActiveTime);
+ }
+
protected:
virtual ~CSSAnimation()
{
MOZ_ASSERT(!mOwningElement.IsSet(), "Owning element should be cleared "
"before a CSS animation is destroyed");
}
// Animation overrides
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -196,17 +196,17 @@ CSSTransition::QueueEvents(StickyTimeDur
const StickyTimeDuration zeroDuration = StickyTimeDuration();
TransitionPhase currentPhase;
StickyTimeDuration intervalStartTime;
StickyTimeDuration intervalEndTime;
if (!mEffect) {
- currentPhase = GetTransitionPhaseWithoutEffect();
+ currentPhase = GetAnimationPhaseWithoutEffect<TransitionPhase>(*this);
} else {
ComputedTiming computedTiming = mEffect->GetComputedTiming();
currentPhase = static_cast<TransitionPhase>(computedTiming.mPhase);
intervalStartTime =
std::max(std::min(StickyTimeDuration(-mEffect->SpecifiedTiming().mDelay),
computedTiming.mActiveDuration), zeroDuration);
intervalEndTime =
@@ -321,33 +321,16 @@ CSSTransition::QueueEvents(StickyTimeDur
evt.mMessage,
TransitionProperty(),
evt.mElapsedTime,
evt.mTimeStamp,
this));
}
}
-CSSTransition::TransitionPhase
-CSSTransition::GetTransitionPhaseWithoutEffect() const
-{
- MOZ_ASSERT(!mEffect, "Should only be called when we do not have an effect");
-
- Nullable<TimeDuration> currentTime = GetCurrentTime();
- if (currentTime.IsNull()) {
- return TransitionPhase::Idle;
- }
-
- // If we don't have a target effect, the duration will be zero so the phase is
- // 'before' if the current time is less than zero.
- return currentTime.Value() < TimeDuration()
- ? TransitionPhase::Before
- : TransitionPhase::After;
-}
-
void
CSSTransition::Tick()
{
Animation::Tick();
QueueEvents();
}
nsCSSPropertyID
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -228,19 +228,16 @@ protected:
// Animation overrides
void UpdateTiming(SeekFlag aSeekFlag,
SyncNotifyFlag aSyncNotifyFlag) override;
void QueueEvents(StickyTimeDuration activeTime = StickyTimeDuration());
enum class TransitionPhase;
- // Return the TransitionPhase to use when the transition doesn't have a target
- // effect.
- TransitionPhase GetTransitionPhaseWithoutEffect() const;
// The (pseudo-)element whose computed transition-property refers to this
// transition (if any).
//
// This is used for determining the relative composite order of transitions
// generated from CSS markup.
//
// Typically this will be the same as the target element of the keyframe