From aade91b13a50ee4f246016fa8d8d1561f58f80ee Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Wed, 14 Mar 2018 11:45:38 +0100 Subject: moebius#89: DOM - implement animationcancel event Issue #55 --- layout/style/AnimationCommon.h | 20 ++++++++++ layout/style/nsAnimationManager.cpp | 75 ++++++++++++++++++++++-------------- layout/style/nsAnimationManager.h | 15 ++++++-- layout/style/nsTransitionManager.cpp | 21 +--------- layout/style/nsTransitionManager.h | 17 +------- 5 files changed, 79 insertions(+), 69 deletions(-) (limited to 'layout/style') diff --git a/layout/style/AnimationCommon.h b/layout/style/AnimationCommon.h index 37030411c..025c034a4 100644 --- a/layout/style/AnimationCommon.h +++ b/layout/style/AnimationCommon.h @@ -251,6 +251,26 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, aField.Traverse(&aCallback, aName); } +// Return the TransitionPhase or AnimationPhase to use when the animation +// doesn't have a target effect. +template +PhaseType GetAnimationPhaseWithoutEffect(const dom::Animation& aAnimation) +{ + MOZ_ASSERT(!aAnimation.GetEffect(), + "Should only be called when we do not have an effect"); + + Nullable 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) */ diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index 8d4e8fcee..aa1b6fe78 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -158,12 +158,8 @@ CSSAnimation::HasLowerCompositeOrderThan(const CSSAnimation& aOther) const } 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) { @@ -198,39 +194,60 @@ CSSAnimation::QueueEvents() } nsAnimationManager* manager = presContext->AnimationManager(); - ComputedTiming computedTiming = mEffect->GetComputedTiming(); - - ComputedTiming::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 iterationBoundary = mPreviousIteration > currentIteration - ? currentIteration + 1 - : currentIteration; - StickyTimeDuration iterationStartTime = - computedTiming.mDuration.MultDouble( - (iterationBoundary - computedTiming.mIterationStart)); + uint64_t currentIteration = 0; + ComputedTiming::AnimationPhase currentPhase; + StickyTimeDuration intervalStartTime; + StickyTimeDuration intervalEndTime; + StickyTimeDuration iterationStartTime; + + if (!mEffect) { + currentPhase = GetAnimationPhaseWithoutEffect + (*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 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::Null: + case AnimationPhase::Idle: case AnimationPhase::Before: if (currentPhase == AnimationPhase::Active) { events.AppendElement(AnimationEventParams{ eAnimationStart, diff --git a/layout/style/nsAnimationManager.h b/layout/style/nsAnimationManager.h index 868d4bb42..d838d090a 100644 --- a/layout/style/nsAnimationManager.h +++ b/layout/style/nsAnimationManager.h @@ -76,7 +76,7 @@ public: , mIsStylePaused(false) , mPauseShouldStick(false) , mNeedsNewAnimationIndexWhenRun(false) - , mPreviousPhase(ComputedTiming::AnimationPhase::Null) + , mPreviousPhase(ComputedTiming::AnimationPhase::Idle) , mPreviousIteration(0) { // We might need to drop this assertion once we add a script-accessible @@ -110,8 +110,6 @@ public: void PauseFromStyle(); void CancelFromStyle() override { - mOwningElement = OwningElementRef(); - // When an animation is disassociated with style it enters an odd state // where its composite order is undefined until it first transitions // out of the idle state. @@ -126,10 +124,15 @@ public: mNeedsNewAnimationIndexWhenRun = true; Animation::CancelFromStyle(); + + // 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; } @@ -158,6 +161,10 @@ public: // reflect changes to that markup. bool IsTiedToMarkup() const { return mOwningElement.IsSet(); } + void MaybeQueueCancelEvent(StickyTimeDuration aActiveTime) override { + QueueEvents(aActiveTime); + } + protected: virtual ~CSSAnimation() { diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index abb9e2311..118702e8f 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -46,8 +46,6 @@ using mozilla::dom::KeyframeEffectReadOnly; using namespace mozilla; using namespace mozilla::css; -typedef mozilla::ComputedTiming::AnimationPhase AnimationPhase; - namespace { struct TransitionEventParams { EventMessage mMessage; @@ -203,7 +201,7 @@ CSSTransition::QueueEvents(StickyTimeDuration aActiveTime) StickyTimeDuration intervalEndTime; if (!mEffect) { - currentPhase = GetTransitionPhaseWithoutEffect(); + currentPhase = GetAnimationPhaseWithoutEffect(*this); intervalStartTime = zeroDuration; intervalEndTime = zeroDuration; } else { @@ -329,23 +327,6 @@ CSSTransition::QueueEvents(StickyTimeDuration aActiveTime) } } -CSSTransition::TransitionPhase -CSSTransition::GetTransitionPhaseWithoutEffect() const -{ - MOZ_ASSERT(!mEffect, "Should only be called when we do not have an effect"); - - Nullable 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() { diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index e2f198a40..1c48cc8cd 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -162,18 +162,6 @@ 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. @@ -245,9 +233,6 @@ protected: 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). @@ -272,7 +257,7 @@ protected: // to be queued on this tick. // See: https://drafts.csswg.org/css-transitions-2/#transition-phase enum class TransitionPhase { - Idle = static_cast(ComputedTiming::AnimationPhase::Null), + Idle = static_cast(ComputedTiming::AnimationPhase::Idle), Before = static_cast(ComputedTiming::AnimationPhase::Before), Active = static_cast(ComputedTiming::AnimationPhase::Active), After = static_cast(ComputedTiming::AnimationPhase::After), -- cgit v1.2.3