Bug 1078122 part 9 - Move queuing of CSS animation events to CSSAnimationPlayer; r=dholbert
This patch moves the code for queuing CSS animation events from
nsAnimationManager to CSSAnimationPlayer. In doing so, it also moves the
mLastNotification member and associated enum values.
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -138,17 +138,16 @@ public:
nsCSSPseudoElements::Type aPseudoType,
const AnimationTiming &aTiming,
const nsSubstring& aName)
: mDocument(aDocument)
, mTarget(aTarget)
, mTiming(aTiming)
, mName(aName)
, mIsFinishedTransition(false)
- , mLastNotification(LAST_NOTIFICATION_NONE)
, mPseudoType(aPseudoType)
{
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Animation)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Animation)
@@ -249,25 +248,16 @@ public:
MOZ_ASSERT(AsTransition(),
"Calling SetIsFinishedTransition but it's not a transition");
mIsFinishedTransition = true;
}
bool IsCurrent() const;
bool IsInEffect() const;
- enum {
- LAST_NOTIFICATION_NONE = uint64_t(-1),
- LAST_NOTIFICATION_END = uint64_t(-2)
- };
- uint64_t LastNotification() const { return mLastNotification; }
- void SetLastNotification(uint64_t aLastNotification) {
- mLastNotification = aLastNotification;
- }
-
bool HasAnimationOfProperty(nsCSSProperty aProperty) const;
const InfallibleTArray<AnimationProperty>& Properties() const {
return mProperties;
}
InfallibleTArray<AnimationProperty>& Properties() {
return mProperties;
}
@@ -287,19 +277,16 @@ protected:
nsCOMPtr<Element> mTarget;
Nullable<TimeDuration> mParentTime;
AnimationTiming mTiming;
nsString mName;
// A flag to mark transitions that have finished and are due to
// be removed on the next throttle-able cycle.
bool mIsFinishedTransition;
- // One of the LAST_NOTIFICATION_* constants, or an integer for the iteration
- // whose start we last notified on.
- uint64_t mLastNotification;
nsCSSPseudoElements::Type mPseudoType;
InfallibleTArray<AnimationProperty> mProperties;
};
} // namespace dom
} // namespace mozilla
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -58,99 +58,120 @@ CSSAnimationPlayer::PauseFromStyle()
return;
}
mIsStylePaused = true;
AnimationPlayer::Pause(eNoUpdate);
}
void
+CSSAnimationPlayer::QueueEvents(EventArray& aEventsToDispatch)
+{
+ if (!mSource) {
+ return;
+ }
+
+ ComputedTiming computedTiming = mSource->GetComputedTiming();
+
+ dom::Element* target;
+ nsCSSPseudoElements::Type targetPseudoType;
+ mSource->GetTarget(target, targetPseudoType);
+
+ switch (computedTiming.mPhase) {
+ case ComputedTiming::AnimationPhase_Null:
+ case ComputedTiming::AnimationPhase_Before:
+ // Do nothing
+ break;
+
+ case ComputedTiming::AnimationPhase_Active:
+ // Dispatch 'animationstart' or 'animationiteration' when needed.
+ if (computedTiming.mCurrentIteration != mLastNotification) {
+ // Notify 'animationstart' even if a negative delay puts us
+ // past the first iteration.
+ // Note that when somebody changes the animation-duration
+ // dynamically, this will fire an extra iteration event
+ // immediately in many cases. It's not clear to me if that's the
+ // right thing to do.
+ uint32_t message = mLastNotification == LAST_NOTIFICATION_NONE
+ ? NS_ANIMATION_START
+ : NS_ANIMATION_ITERATION;
+ mLastNotification = computedTiming.mCurrentIteration;
+ TimeDuration iterationStart =
+ mSource->Timing().mIterationDuration *
+ computedTiming.mCurrentIteration;
+ TimeDuration elapsedTime =
+ std::max(iterationStart, mSource->InitialAdvance());
+ AnimationEventInfo ei(target, Name(), message,
+ StickyTimeDuration(elapsedTime),
+ PseudoTypeAsString(targetPseudoType));
+ aEventsToDispatch.AppendElement(ei);
+ }
+ break;
+
+ case ComputedTiming::AnimationPhase_After:
+ // If we skipped the animation interval entirely, dispatch
+ // 'animationstart' first
+ if (mLastNotification == LAST_NOTIFICATION_NONE) {
+ // Notifying for start of 0th iteration.
+ // (This is overwritten below but we set it here to maintain
+ // internal consistency.)
+ mLastNotification = 0;
+ StickyTimeDuration elapsedTime =
+ std::min(StickyTimeDuration(mSource->InitialAdvance()),
+ computedTiming.mActiveDuration);
+ AnimationEventInfo ei(target, Name(), NS_ANIMATION_START,
+ elapsedTime,
+ PseudoTypeAsString(targetPseudoType));
+ aEventsToDispatch.AppendElement(ei);
+ }
+ // Dispatch 'animationend' when needed.
+ if (mLastNotification != LAST_NOTIFICATION_END) {
+ mLastNotification = LAST_NOTIFICATION_END;
+ AnimationEventInfo ei(target, Name(), NS_ANIMATION_END,
+ computedTiming.mActiveDuration,
+ PseudoTypeAsString(targetPseudoType));
+ aEventsToDispatch.AppendElement(ei);
+ }
+ break;
+ }
+}
+
+/* static */ nsString
+CSSAnimationPlayer::PseudoTypeAsString(nsCSSPseudoElements::Type aPseudoType)
+{
+ switch (aPseudoType) {
+ case nsCSSPseudoElements::ePseudo_before:
+ return NS_LITERAL_STRING("::before");
+ case nsCSSPseudoElements::ePseudo_after:
+ return NS_LITERAL_STRING("::after");
+ default:
+ return EmptyString();
+ }
+}
+
+void
nsAnimationManager::UpdateStyleAndEvents(AnimationPlayerCollection*
aCollection,
TimeStamp aRefreshTime,
EnsureStyleRuleFlags aFlags)
{
aCollection->EnsureStyleRuleFor(aRefreshTime, aFlags);
- GetEventsForCurrentTime(aCollection, mPendingEvents);
+ QueueEvents(aCollection, mPendingEvents);
CheckNeedsRefresh();
}
void
-nsAnimationManager::GetEventsForCurrentTime(AnimationPlayerCollection*
- aCollection,
- EventArray& aEventsToDispatch)
+nsAnimationManager::QueueEvents(AnimationPlayerCollection* aCollection,
+ EventArray& aEventsToDispatch)
{
for (size_t playerIdx = aCollection->mPlayers.Length(); playerIdx-- != 0; ) {
- AnimationPlayer* player = aCollection->mPlayers[playerIdx];
- Animation* anim = player->GetSource();
- if (!anim) {
- continue;
- }
-
- ComputedTiming computedTiming = anim->GetComputedTiming();
-
- switch (computedTiming.mPhase) {
- case ComputedTiming::AnimationPhase_Null:
- case ComputedTiming::AnimationPhase_Before:
- // Do nothing
- break;
-
- case ComputedTiming::AnimationPhase_Active:
- // Dispatch 'animationstart' or 'animationiteration' when needed.
- if (computedTiming.mCurrentIteration != anim->LastNotification()) {
- // Notify 'animationstart' even if a negative delay puts us
- // past the first iteration.
- // Note that when somebody changes the animation-duration
- // dynamically, this will fire an extra iteration event
- // immediately in many cases. It's not clear to me if that's the
- // right thing to do.
- uint32_t message =
- anim->LastNotification() == Animation::LAST_NOTIFICATION_NONE
- ? NS_ANIMATION_START
- : NS_ANIMATION_ITERATION;
- anim->SetLastNotification(computedTiming.mCurrentIteration);
- TimeDuration iterationStart =
- anim->Timing().mIterationDuration *
- computedTiming.mCurrentIteration;
- TimeDuration elapsedTime =
- std::max(iterationStart, anim->InitialAdvance());
- AnimationEventInfo ei(aCollection->mElement, player->Name(), message,
- StickyTimeDuration(elapsedTime),
- aCollection->PseudoElement());
- aEventsToDispatch.AppendElement(ei);
- }
- break;
-
- case ComputedTiming::AnimationPhase_After:
- // If we skipped the animation interval entirely, dispatch
- // 'animationstart' first
- if (anim->LastNotification() == Animation::LAST_NOTIFICATION_NONE) {
- // Notifying for start of 0th iteration.
- // (This is overwritten below but we set it here to maintain
- // internal consistency.)
- anim->SetLastNotification(0);
- StickyTimeDuration elapsedTime =
- std::min(StickyTimeDuration(anim->InitialAdvance()),
- computedTiming.mActiveDuration);
- AnimationEventInfo ei(aCollection->mElement,
- player->Name(), NS_ANIMATION_START,
- elapsedTime, aCollection->PseudoElement());
- aEventsToDispatch.AppendElement(ei);
- }
- // Dispatch 'animationend' when needed.
- if (anim->LastNotification() != Animation::LAST_NOTIFICATION_END) {
- anim->SetLastNotification(Animation::LAST_NOTIFICATION_END);
- AnimationEventInfo ei(aCollection->mElement,
- player->Name(), NS_ANIMATION_END,
- computedTiming.mActiveDuration,
- aCollection->PseudoElement());
- aEventsToDispatch.AppendElement(ei);
- }
- break;
- }
+ CSSAnimationPlayer* player =
+ aCollection->mPlayers[playerIdx]->AsCSSAnimationPlayer();
+ MOZ_ASSERT(player, "Expected a collection of CSS Animation players");
+ player->QueueEvents(aEventsToDispatch);
}
}
AnimationPlayerCollection*
nsAnimationManager::GetAnimationPlayers(dom::Element *aElement,
nsCSSPseudoElements::Type aPseudoType,
bool aCreateIfNeeded)
{
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -51,33 +51,38 @@ typedef InfallibleTArray<AnimationEventI
class CSSAnimationPlayer MOZ_FINAL : public dom::AnimationPlayer
{
public:
explicit CSSAnimationPlayer(dom::AnimationTimeline* aTimeline)
: dom::AnimationPlayer(aTimeline)
, mIsStylePaused(false)
, mPauseShouldStick(false)
+ , mLastNotification(LAST_NOTIFICATION_NONE)
{
}
virtual CSSAnimationPlayer*
AsCSSAnimationPlayer() MOZ_OVERRIDE { return this; }
virtual void Play(UpdateFlags aUpdateFlags) MOZ_OVERRIDE;
virtual void Pause(UpdateFlags aUpdateFlags) MOZ_OVERRIDE;
void PlayFromStyle();
void PauseFromStyle();
bool IsStylePaused() const { return mIsStylePaused; }
+ void QueueEvents(EventArray& aEventsToDispatch);
+
protected:
virtual ~CSSAnimationPlayer() { }
+ static nsString PseudoTypeAsString(nsCSSPseudoElements::Type aPseudoType);
+
// When combining animation-play-state with play() / pause() the following
// behavior applies:
// 1. pause() is sticky and always overrides the underlying
// animation-play-state
// 2. If animation-play-state is 'paused', play() will temporarily override
// it until animation-play-state next becomes 'running'.
// 3. Calls to play() trigger finishing behavior but setting the
// animation-play-state to 'running' does not.
@@ -119,16 +124,24 @@ protected:
// (mIsPaused; mIsStylePaused; mPauseShouldStick)
// E. Paused by animation-play-state
// (mIsPaused; mIsStylePaused; !mPauseShouldStick)
//
// (That leaves 3 combinations of the boolean values that we never set because
// they don't represent valid states.)
bool mIsStylePaused;
bool mPauseShouldStick;
+
+ enum {
+ LAST_NOTIFICATION_NONE = uint64_t(-1),
+ LAST_NOTIFICATION_END = uint64_t(-2)
+ };
+ // One of the LAST_NOTIFICATION_* constants, or an integer for the iteration
+ // whose start we last notified on.
+ uint64_t mLastNotification;
};
} /* namespace mozilla */
class nsAnimationManager MOZ_FINAL
: public mozilla::css::CommonAnimationManager
{
public:
@@ -154,18 +167,18 @@ public:
} while ((aContent = aContent->GetParent()));
return false;
}
void UpdateStyleAndEvents(mozilla::AnimationPlayerCollection* aEA,
mozilla::TimeStamp aRefreshTime,
mozilla::EnsureStyleRuleFlags aFlags);
- void GetEventsForCurrentTime(mozilla::AnimationPlayerCollection* aEA,
- mozilla::EventArray &aEventsToDispatch);
+ void QueueEvents(mozilla::AnimationPlayerCollection* aEA,
+ mozilla::EventArray &aEventsToDispatch);
// nsIStyleRuleProcessor (parts)
virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE;
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE;
virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE;
#ifdef MOZ_XUL
virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE;
#endif