Bug 1029370 part 1 - Move active duration calculation to GetComputedTimingAt; r=dholbert

This patch makes the active duration a property of the ComputedTiming struct and
returns this as part of calculating GetComputedTimingAt. GetComputedTimingAt was
already calling the method to calculate the ActiveDuration and the only other
callers of ActiveDuration() were also calling GetComputedTimingAt so this
doesn't make us do any unnecessary calculation.

I've left ActiveDuration as a public method on ElementAnimation for now since
it's a struct and just about everything there is public. At some point in the
future we'll probably make this more class-like to hide some details but that
can happen as a separate step. This patch does, however, move the definition of
ActiveDuration inside the .cpp file.

In tidying up GetComputedTimingAt we also replace all the references to
TimeDuration() and TimeDuration(0) with a single local variable representing
zero duration. This should be easier to read and possibly a little faster.

We don't use a function static variable since this method is called from
different threads and the initialization of function statics is not guaranteed
to be thread-safe until C++0x.
This commit is contained in:
Brian Birtles 2014-06-25 09:42:19 +09:00
parent 51cf0526d8
commit c5a2510c5f
3 changed files with 35 additions and 26 deletions

View File

@ -447,18 +447,20 @@ ComputedTiming
ElementAnimation::GetComputedTimingAt(TimeDuration aLocalTime,
const AnimationTiming& aTiming)
{
const TimeDuration zeroDuration;
// Currently we expect negative durations to be picked up during CSS
// parsing but when we start receiving timing parameters from other sources
// we will need to clamp negative durations here.
// For now, if we're hitting this it probably means we've overflowing
// integer arithmetic in mozilla::TimeStamp.
MOZ_ASSERT(aTiming.mIterationDuration >= TimeDuration(0),
MOZ_ASSERT(aTiming.mIterationDuration >= zeroDuration,
"Expecting iteration duration >= 0");
// Always return the same object to benefit from return-value optimization.
ComputedTiming result;
TimeDuration activeDuration = ActiveDuration(aTiming);
result.mActiveDuration = ActiveDuration(aTiming);
// When we finish exactly at the end of an iteration we need to report
// the end of the final iteration and not the start of the next iteration
@ -467,14 +469,14 @@ ElementAnimation::GetComputedTimingAt(TimeDuration aLocalTime,
// Get the normalized time within the active interval.
TimeDuration activeTime;
if (aLocalTime >= aTiming.mDelay + activeDuration) {
if (aLocalTime >= aTiming.mDelay + result.mActiveDuration) {
result.mPhase = ComputedTiming::AnimationPhase_After;
if (!aTiming.FillsForwards()) {
// The animation isn't active or filling at this time.
result.mTimeFraction = ComputedTiming::kNullTimeFraction;
return result;
}
activeTime = activeDuration;
activeTime = result.mActiveDuration;
// Note that infinity == floor(infinity) so this will also be true when we
// have finished an infinitely repeating animation of zero duration.
isEndOfFinalIteration =
@ -489,7 +491,7 @@ ElementAnimation::GetComputedTimingAt(TimeDuration aLocalTime,
}
// activeTime is zero
} else {
MOZ_ASSERT(activeDuration != TimeDuration(),
MOZ_ASSERT(result.mActiveDuration != zeroDuration,
"How can we be in the middle of a zero-duration interval?");
result.mPhase = ComputedTiming::AnimationPhase_Active;
activeTime = aLocalTime - aTiming.mDelay;
@ -497,7 +499,7 @@ ElementAnimation::GetComputedTimingAt(TimeDuration aLocalTime,
// Get the position within the current iteration.
TimeDuration iterationTime;
if (aTiming.mIterationDuration != TimeDuration()) {
if (aTiming.mIterationDuration != zeroDuration) {
iterationTime = isEndOfFinalIteration
? aTiming.mIterationDuration
: activeTime % aTiming.mIterationDuration;
@ -510,7 +512,7 @@ ElementAnimation::GetComputedTimingAt(TimeDuration aLocalTime,
? UINT64_MAX // FIXME: When we return this via the API we'll need
// to make sure it ends up being infinity.
: static_cast<uint64_t>(aTiming.mIterationCount) - 1;
} else if (activeTime == TimeDuration(0)) {
} else if (activeTime == zeroDuration) {
// If the active time is zero we're either in the first iteration
// (including filling backwards) or we have finished an animation with an
// iteration duration of zero that is filling forwards (but we're not at
@ -533,7 +535,7 @@ ElementAnimation::GetComputedTimingAt(TimeDuration aLocalTime,
: fmod(aTiming.mIterationCount, 1.0f);
} else {
// We are in the active phase so the iteration duration can't be zero.
MOZ_ASSERT(aTiming.mIterationDuration != TimeDuration(0),
MOZ_ASSERT(aTiming.mIterationDuration != zeroDuration,
"In the active phase of a zero-duration animation?");
result.mTimeFraction =
aTiming.mIterationDuration == TimeDuration::Forever()
@ -563,6 +565,21 @@ ElementAnimation::GetComputedTimingAt(TimeDuration aLocalTime,
return result;
}
TimeDuration
ElementAnimation::ActiveDuration(const AnimationTiming& aTiming)
{
if (aTiming.mIterationCount == mozilla::PositiveInfinity<float>()) {
// An animation that repeats forever has an infinite active duration
// unless its iteration duration is zero, in which case it has a zero
// active duration.
const TimeDuration zeroDuration;
return aTiming.mIterationDuration == zeroDuration
? zeroDuration
: TimeDuration::Forever();
}
return aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount);
}
namespace css {
bool

View File

@ -273,6 +273,10 @@ struct ComputedTiming
static const double kNullTimeFraction;
// The total duration of the animation including all iterations.
// Will equal TimeDuration::Forever() if the animation repeats indefinitely.
TimeDuration mActiveDuration;
// Will be kNullTimeFraction if the animation is neither animating nor
// filling at the sampled time.
double mTimeFraction;
@ -345,20 +349,6 @@ public:
return (IsPaused() ? mPauseStart : aTime) - mStartTime;
}
// Return the duration of the active interval for the given timing parameters.
static mozilla::TimeDuration ActiveDuration(const AnimationTiming& aTiming) {
if (aTiming.mIterationCount == mozilla::PositiveInfinity<float>()) {
// An animation that repeats forever has an infinite active duration
// unless its iteration duration is zero, in which case it has a zero
// active duration.
const TimeDuration zeroDuration;
return aTiming.mIterationDuration == zeroDuration
? zeroDuration
: mozilla::TimeDuration::Forever();
}
return aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount);
}
// Return the duration from the start the active interval to the point where
// the animation begins playback. This is zero unless the animation has
// a negative delay in which case it is the absolute value of the delay.
@ -376,6 +366,9 @@ public:
static ComputedTiming GetComputedTimingAt(TimeDuration aLocalTime,
const AnimationTiming& aTiming);
// Return the duration of the active interval for the given timing parameters.
static mozilla::TimeDuration ActiveDuration(const AnimationTiming& aTiming);
nsString mName; // empty string for 'none'
AnimationTiming mTiming;
// The beginning of the delay period. This is also set to a null

View File

@ -77,8 +77,6 @@ nsAnimationManager::GetEventsAt(CommonElementAnimationData* aEA,
break;
case ComputedTiming::AnimationPhase_After:
TimeDuration activeDuration =
ElementAnimation::ActiveDuration(anim->mTiming);
// If we skipped the animation interval entirely, dispatch
// 'animationstart' first
if (anim->mLastNotification ==
@ -88,7 +86,7 @@ nsAnimationManager::GetEventsAt(CommonElementAnimationData* aEA,
// internal consistency.)
anim->mLastNotification = 0;
TimeDuration elapsedTime =
std::min(anim->InitialAdvance(), activeDuration);
std::min(anim->InitialAdvance(), computedTiming.mActiveDuration);
AnimationEventInfo ei(aEA->mElement, anim->mName, NS_ANIMATION_START,
elapsedTime, aEA->PseudoElement());
aEventsToDispatch.AppendElement(ei);
@ -98,7 +96,8 @@ nsAnimationManager::GetEventsAt(CommonElementAnimationData* aEA,
ElementAnimation::LAST_NOTIFICATION_END) {
anim->mLastNotification = ElementAnimation::LAST_NOTIFICATION_END;
AnimationEventInfo ei(aEA->mElement, anim->mName, NS_ANIMATION_END,
activeDuration, aEA->PseudoElement());
computedTiming.mActiveDuration,
aEA->PseudoElement());
aEventsToDispatch.AppendElement(ei);
}
break;