Bug 1334583 - Pass a separate timeOrigin and startTime for compositor animations; r=hiro

By passing the startTime as a TimeDuration we are able to represent times in the
distant past (and with the same range as we can represent on the main thread so
that if we do encounter range errors in future, they should not differ between
the main thread and the compositor).

This patch includes a crashtest. I have verified that, without the code changes
included in this patch, this crashtest fails on debug builds on OSX.

MozReview-Commit-ID: EDuKLzfEC0K

--HG--
extra : rebase_source : 1883080fdfac8c33f70698145f21e67cbdfdd4f2
This commit is contained in:
Brian Birtles 2017-05-02 16:49:51 +09:00
parent ec43d6df6d
commit 5267613207
6 changed files with 51 additions and 18 deletions

View File

@ -0,0 +1,9 @@
<div style="width: 200px; height: 200px; background: purple" id=div>
</div>
<script>
const animation = div.animate(
[ { transform: "scale(1)" },
{ transform: "scale(2)" } ],
{ iterations: Infinity, duration: 512 } );
animation.currentTime = 2147483647;
</script>

View File

@ -25,5 +25,6 @@ pref(dom.animations-api.core.enabled,true) load 1330513-1.html
pref(dom.animations-api.core.enabled,true) load 1333539-1.html
pref(dom.animations-api.core.enabled,true) load 1333539-2.html
pref(dom.animations-api.core.enabled,true) load 1333418-1.html
pref(dom.animations-api.core.enabled,true) load 1334583-1.html
pref(dom.animations-api.core.enabled,true) load 1343589-1.html
pref(dom.animations-api.core.enabled,true) load 1359658-1.html

View File

@ -159,15 +159,18 @@ AnimationHelper::SampleAnimationForEachNode(TimeStamp aTime,
activeAnimations = true;
MOZ_ASSERT(!animation.startTime().IsNull() ||
MOZ_ASSERT((!animation.originTime().IsNull() &&
animation.startTime().type() != MaybeTimeDuration::Tnull_t) ||
animation.isNotPlaying(),
"Failed to resolve start time of play-pending animations");
"If we are playing, we should have an origin time and a start"
" time");
// If the animation is not currently playing , e.g. paused or
// finished, then use the hold time to stay at the same position.
TimeDuration elapsedDuration = animation.isNotPlaying()
? animation.holdTime()
: (aTime - animation.startTime())
.MultDouble(animation.playbackRate());
: (aTime - animation.originTime() -
animation.startTime().get_TimeDuration())
.MultDouble(animation.playbackRate());
TimingParams timing;
timing.mDuration.emplace(animation.duration());
timing.mDelay = animation.delay();

View File

@ -293,12 +293,15 @@ Layer::StartPendingAnimations(const TimeStamp& aReadyTime)
// If the animation is play-pending, resolve the start time.
// This mirrors the calculation in Animation::StartTimeFromReadyTime.
if (anim.startTime().IsNull() && !anim.isNotPlaying()) {
if (anim.startTime().type() == MaybeTimeDuration::Tnull_t &&
!anim.originTime().IsNull() &&
!anim.isNotPlaying()) {
TimeDuration readyTime = aReadyTime - anim.originTime();
anim.startTime() =
anim.playbackRate() == 0
? aReadyTime
: aReadyTime - anim.holdTime().MultDouble(1.0 /
anim.playbackRate());
? readyTime
: readyTime - anim.holdTime().MultDouble(1.0 /
anim.playbackRate());
updated = true;
}
}

View File

@ -162,6 +162,11 @@ union TransformFunction {
TransformMatrix;
};
union MaybeTimeDuration {
null_t;
TimeDuration;
};
union Animatable {
null_t;
float;
@ -195,15 +200,20 @@ union AnimationData {
};
struct Animation {
TimeStamp startTime;
// The zero time of this Animation's timeline. May be null if isNotPlaying is
// true.
TimeStamp originTime;
// The start time is relative to the originTime. This allows us to represent
// start times in the distant past that cannot be expressed using a TimeStamp.
MaybeTimeDuration startTime;
TimeDuration delay;
TimeDuration endDelay;
// The value of the animation's current time at the moment it was sent to the
// compositor. This value will be used for below cases:
// 1) Animations that are play-pending. Initially these animations will have a
// null |startTime|. Once the animation is read to start (i.e. painting has
// finished), we calculate an appropriate value of |startTime| such that
// playback begins from |holdTime|.
// null |startTime|. Once the animation is ready to start (i.e. painting
// has finished), we calculate an appropriate value of |startTime| such
// that playback begins from |holdTime|.
// 2) Not playing animations (e.g. paused and finished animations). In this
// case the |holdTime| represents the current time the animation will
// maintain.

View File

@ -526,15 +526,22 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
UpdateStartValueFromReplacedTransition();
}
const ComputedTiming computedTiming =
aAnimation->GetEffect()->GetComputedTiming();
animation->originTime() = !aAnimation->GetTimeline()
? TimeStamp()
: aAnimation->GetTimeline()->
ToTimeStamp(TimeDuration());
Nullable<TimeDuration> startTime = aAnimation->GetCurrentOrPendingStartTime();
animation->startTime() = startTime.IsNull() || !aAnimation->GetTimeline()
? TimeStamp()
: aAnimation->GetTimeline()->
ToTimeStamp(startTime.Value());
if (startTime.IsNull()) {
animation->startTime() = null_t();
} else {
animation->startTime() = startTime.Value();
}
animation->holdTime() = aAnimation->GetCurrentTime().Value();
const ComputedTiming computedTiming =
aAnimation->GetEffect()->GetComputedTiming();
animation->delay() = timing.mDelay;
animation->endDelay() = timing.mEndDelay;
animation->duration() = computedTiming.mDuration;