summaryrefslogtreecommitdiffstats
path: root/layout/style/nsAnimationManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/style/nsAnimationManager.cpp')
-rw-r--r--layout/style/nsAnimationManager.cpp179
1 files changed, 109 insertions, 70 deletions
diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp
index ed2b5afc7..aa1b6fe78 100644
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -33,11 +33,15 @@ using mozilla::dom::AnimationPlayState;
using mozilla::dom::KeyframeEffectReadOnly;
using mozilla::dom::CSSAnimation;
+typedef mozilla::ComputedTiming::AnimationPhase AnimationPhase;
+
namespace {
-// Pair of an event message and elapsed time used when determining the set of
-// events to queue.
-typedef Pair<EventMessage, StickyTimeDuration> EventPair;
+struct AnimationEventParams {
+ EventMessage mMessage;
+ StickyTimeDuration mElapsedTime;
+ TimeStamp mTimeStamp;
+};
} // anonymous namespace
@@ -154,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) {
@@ -194,77 +194,116 @@ CSSAnimation::QueueEvents()
}
nsAnimationManager* manager = presContext->AnimationManager();
- ComputedTiming computedTiming = mEffect->GetComputedTiming();
- if (computedTiming.mPhase == ComputedTiming::AnimationPhase::Null) {
- return; // do nothing
+ const StickyTimeDuration zeroDuration;
+ uint64_t currentIteration = 0;
+ ComputedTiming::AnimationPhase currentPhase;
+ StickyTimeDuration intervalStartTime;
+ StickyTimeDuration intervalEndTime;
+ StickyTimeDuration iterationStartTime;
+
+ 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));
}
- // Note that script can change the start time, so we have to handle moving
- // backwards through the animation as well as forwards. An 'animationstart'
- // is dispatched if we enter the active phase (regardless if that is from
- // before or after the animation's active phase). An 'animationend' is
- // dispatched if we leave the active phase (regardless if that is to before
- // or after the animation's active phase).
-
- bool wasActive = mPreviousPhaseOrIteration != PREVIOUS_PHASE_BEFORE &&
- mPreviousPhaseOrIteration != PREVIOUS_PHASE_AFTER;
- bool isActive =
- computedTiming.mPhase == ComputedTiming::AnimationPhase::Active;
- bool isSameIteration =
- computedTiming.mCurrentIteration == mPreviousPhaseOrIteration;
- bool skippedActivePhase =
- (mPreviousPhaseOrIteration == PREVIOUS_PHASE_BEFORE &&
- computedTiming.mPhase == ComputedTiming::AnimationPhase::After) ||
- (mPreviousPhaseOrIteration == PREVIOUS_PHASE_AFTER &&
- computedTiming.mPhase == ComputedTiming::AnimationPhase::Before);
- bool skippedFirstIteration =
- isActive &&
- mPreviousPhaseOrIteration == PREVIOUS_PHASE_BEFORE &&
- computedTiming.mCurrentIteration > 0;
-
- MOZ_ASSERT(!skippedActivePhase || (!isActive && !wasActive),
- "skippedActivePhase only makes sense if we were & are inactive");
-
- if (computedTiming.mPhase == ComputedTiming::AnimationPhase::Before) {
- mPreviousPhaseOrIteration = PREVIOUS_PHASE_BEFORE;
- } else if (computedTiming.mPhase == ComputedTiming::AnimationPhase::Active) {
- mPreviousPhaseOrIteration = computedTiming.mCurrentIteration;
- } else if (computedTiming.mPhase == ComputedTiming::AnimationPhase::After) {
- mPreviousPhaseOrIteration = PREVIOUS_PHASE_AFTER;
+ 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 });
}
- AutoTArray<EventPair, 2> events;
- StickyTimeDuration initialAdvance = StickyTimeDuration(InitialAdvance());
- StickyTimeDuration iterationStart = computedTiming.mDuration *
- computedTiming.mCurrentIteration;
- const StickyTimeDuration& activeDuration = computedTiming.mActiveDuration;
-
- if (skippedFirstIteration) {
- // Notify animationstart and animationiteration in same tick.
- events.AppendElement(EventPair(eAnimationStart, initialAdvance));
- events.AppendElement(EventPair(eAnimationIteration,
- std::max(iterationStart, initialAdvance)));
- } else if (!wasActive && isActive) {
- events.AppendElement(EventPair(eAnimationStart, initialAdvance));
- } else if (wasActive && !isActive) {
- events.AppendElement(EventPair(eAnimationEnd, activeDuration));
- } else if (wasActive && isActive && !isSameIteration) {
- events.AppendElement(EventPair(eAnimationIteration, iterationStart));
- } else if (skippedActivePhase) {
- events.AppendElement(EventPair(eAnimationStart,
- std::min(initialAdvance, activeDuration)));
- events.AppendElement(EventPair(eAnimationEnd, activeDuration));
- } else {
- return; // No events need to be sent
+ switch (mPreviousPhase) {
+ case AnimationPhase::Idle:
+ case AnimationPhase::Before:
+ if (currentPhase == AnimationPhase::Active) {
+ events.AppendElement(AnimationEventParams{ eAnimationStart,
+ intervalStartTime,
+ startTimeStamp });
+ } else if (currentPhase == AnimationPhase::After) {
+ events.AppendElement(AnimationEventParams{ eAnimationStart,
+ intervalStartTime,
+ startTimeStamp });
+ events.AppendElement(AnimationEventParams{ eAnimationEnd,
+ intervalEndTime,
+ endTimeStamp });
+ }
+ break;
+ case AnimationPhase::Active:
+ if (currentPhase == AnimationPhase::Before) {
+ events.AppendElement(AnimationEventParams{ eAnimationEnd,
+ intervalStartTime,
+ startTimeStamp });
+ } else if (currentPhase == AnimationPhase::Active) {
+ // The currentIteration must have changed or element we would have
+ // returned early above.
+ MOZ_ASSERT(currentIteration != mPreviousIteration);
+ events.AppendElement(AnimationEventParams{ eAnimationIteration,
+ iterationStartTime,
+ iterationTimeStamp });
+ } else if (currentPhase == AnimationPhase::After) {
+ events.AppendElement(AnimationEventParams{ eAnimationEnd,
+ intervalEndTime,
+ endTimeStamp });
+ }
+ break;
+ case AnimationPhase::After:
+ if (currentPhase == AnimationPhase::Before) {
+ events.AppendElement(AnimationEventParams{ eAnimationStart,
+ intervalEndTime,
+ startTimeStamp});
+ events.AppendElement(AnimationEventParams{ eAnimationEnd,
+ intervalStartTime,
+ endTimeStamp });
+ } else if (currentPhase == AnimationPhase::Active) {
+ events.AppendElement(AnimationEventParams{ eAnimationStart,
+ intervalEndTime,
+ endTimeStamp });
+ }
+ break;
}
- for (const EventPair& pair : events){
+ mPreviousPhase = currentPhase;
+ mPreviousIteration = currentIteration;
+
+ for (const AnimationEventParams& event : events){
manager->QueueEvent(
AnimationEventInfo(owningElement, owningPseudoType,
- pair.first(), mAnimationName,
- pair.second(),
- ElapsedTimeToTimeStamp(pair.second()),
+ event.mMessage, mAnimationName,
+ event.mElapsedTime, event.mTimeStamp,
this));
}
}