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.
This commit is contained in:
Brian Birtles 2014-10-20 13:55:47 +09:00
parent ce354c28fb
commit f71c3c8dee
3 changed files with 107 additions and 86 deletions

View File

@ -143,7 +143,6 @@ public:
, mTiming(aTiming)
, mName(aName)
, mIsFinishedTransition(false)
, mLastNotification(LAST_NOTIFICATION_NONE)
, mPseudoType(aPseudoType)
{
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
@ -254,15 +253,6 @@ public:
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;
@ -292,9 +282,6 @@ protected:
// 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;

View File

@ -62,6 +62,91 @@ CSSAnimationPlayer::PauseFromStyle()
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,
@ -69,83 +154,19 @@ nsAnimationManager::UpdateStyleAndEvents(AnimationPlayerCollection*
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);
}
}

View File

@ -56,6 +56,7 @@ public:
: dom::AnimationPlayer(aTimeline)
, mIsStylePaused(false)
, mPauseShouldStick(false)
, mLastNotification(LAST_NOTIFICATION_NONE)
{
}
@ -70,9 +71,13 @@ public:
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
@ -124,6 +129,14 @@ protected:
// 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 */
@ -159,8 +172,8 @@ public:
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;