Bug 1223658 - Part 2: Pass delay property to compositor. r=birtles

The check of negative elapsedDuration is basically no longer valid since
animation delay is not factored into start time any more.  But still we have
somtimes met negative elapsedDuration sice we use a previous vsync time stamp
for async animations to make the animations more sync.  This is not a problem
in most cases but makes two reftests intermitent failure because both of them
used steps(1, start), the steps(1, start) composed different results in the
before phase and in the active phase. To avoid this difference this patch
replace the steps(1, start) with steps(1, end).

Once we incorpolate playbackRate into GetCurrentOrPendingStartTime, we don't
need to call AnimationTimeToTimeStamp for deviding delay by playbackRate since
the time passed to AnimationTimeToTimeStamp does not contain delay any more.

MozReview-Commit-ID: IVE2IFfNgm0

--HG--
extra : rebase_source : 7cb42e57067c21451706bd89284016d996dc8b12
This commit is contained in:
Hiroyuki Ikezoe 2016-10-14 19:14:01 +09:00
Родитель ac47637175
Коммит d8ec730df8
7 изменённых файлов: 49 добавлений и 36 удалений

Просмотреть файл

@ -664,12 +664,22 @@ Animation::GetCurrentOrPendingStartTime() const
}
// Calculate the equivalent start time from the pending ready time.
// This is the same as the calculation performed in ResumeAt and will
// need to incorporate the playbackRate when implemented (bug 1127380).
result.SetValue(mPendingReadyTime.Value() - mHoldTime.Value());
result = StartTimeFromReadyTime(mPendingReadyTime.Value());
return result;
}
TimeDuration
Animation::StartTimeFromReadyTime(const TimeDuration& aReadyTime) const
{
MOZ_ASSERT(!mHoldTime.IsNull(), "Hold time should be set in order to"
" convert a ready time to a start time");
if (mPlaybackRate == 0) {
return aReadyTime;
}
return aReadyTime - mHoldTime.Value().MultDouble(1 / mPlaybackRate);
}
TimeStamp
Animation::AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const
{
@ -1066,12 +1076,9 @@ Animation::ResumeAt(const TimeDuration& aReadyTime)
// If we aborted a pending pause operation we will already have a start time
// we should use. In all other cases, we resolve it from the ready time.
if (mStartTime.IsNull()) {
mStartTime = StartTimeFromReadyTime(aReadyTime);
if (mPlaybackRate != 0) {
mStartTime.SetValue(aReadyTime -
(mHoldTime.Value().MultDouble(1 / mPlaybackRate)));
mHoldTime.SetNull();
} else {
mStartTime.SetValue(aReadyTime);
}
}
mPendingState = PendingState::NotPending;

Просмотреть файл

@ -239,6 +239,13 @@ public:
*/
Nullable<TimeDuration> GetCurrentOrPendingStartTime() const;
/**
* Calculates the corresponding start time to use for an animation that is
* currently pending with current time |mHoldTime| but should behave
* as if it began or resumed playback at timeline time |aReadyTime|.
*/
TimeDuration StartTimeFromReadyTime(const TimeDuration& aReadyTime) const;
/**
* Converts a time in the timescale of this Animation's currentTime, to a
* TimeStamp. Returns a null TimeStamp if the conversion cannot be performed

Просмотреть файл

@ -673,24 +673,9 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint)
"Failed to resolve start time of pending animations");
TimeDuration elapsedDuration =
(aPoint - animation.startTime()).MultDouble(animation.playbackRate());
// Skip animations that are yet to start.
//
// Currently, this should only happen when the refresh driver is under test
// control and is made to produce a time in the past or is restored from
// test control causing it to jump backwards in time.
//
// Since activeAnimations is true, this could mean we keep compositing
// unnecessarily during the delay, but so long as this only happens while
// the refresh driver is under test control that should be ok.
if (elapsedDuration.ToSeconds() < 0) {
continue;
}
TimingParams timing;
timing.mDuration.emplace(animation.duration());
// Currently animations run on the compositor have their delay factored
// into their start time, hence the delay is effectively zero.
timing.mDelay = TimeDuration(0);
timing.mDelay = animation.delay();
timing.mIterations = animation.iterations();
timing.mIterationStart = animation.iterationStart();
timing.mDirection =
@ -709,8 +694,9 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint)
Nullable<TimeDuration>(elapsedDuration), timing,
animation.playbackRate());
MOZ_ASSERT(!computedTiming.mProgress.IsNull(),
"iteration progress should not be null");
if (computedTiming.mProgress.IsNull()) {
continue;
}
uint32_t segmentIndex = 0;
size_t segmentSize = animation.segments().Length();

Просмотреть файл

@ -178,10 +178,8 @@ union AnimationData {
};
struct Animation {
// Unlike in nsAnimationManager, this start time is at the end of the
// delay. If the delay is changed dynamically, the layer's data will
// be updated.
TimeStamp startTime;
TimeDuration delay;
// The value of the animation's current time at the moment it was created.
// For animations that are waiting to start, their startTime will be null.
// Once the animation is ready to start, we calculate an appropriate value

Просмотреть файл

@ -422,10 +422,11 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
Nullable<TimeDuration> startTime = aAnimation->GetCurrentOrPendingStartTime();
animation->startTime() = startTime.IsNull()
? TimeStamp()
: aAnimation->AnimationTimeToTimeStamp(
StickyTimeDuration(timing.mDelay));
: aAnimation->GetTimeline()->
ToTimeStamp(startTime.Value());
animation->initialCurrentTime() = aAnimation->GetCurrentTime().Value()
- timing.mDelay;
animation->delay() = timing.mDelay;
animation->duration() = computedTiming.mDuration;
animation->iterations() = computedTiming.mIterations;
animation->iterationStart() = computedTiming.mIterationStart;

Просмотреть файл

@ -14,8 +14,15 @@ span {
#test {
width: 100px; height: 100px;
background: blue;
transition: opacity 100s steps(1, start);
opacity: 0 ! important;
/*
* On the compositor we use a previous vsync time stamp rather than the
* current time stamp, as a result sometimes transition may be still in
* before phase after waiting a frame. To compose the same opacity value
* regardless of whether the transition is in before or active phase, we use
* steps(1, end) here.
*/
transition: opacity 100s steps(1, end);
opacity: 1 ! important;
}
</style>
<span></span>
@ -25,7 +32,7 @@ window.addEventListener("load", () => {
var target = document.getElementById("test");
getComputedStyle(target).opacity;
target.style.setProperty("opacity", "1", "important");
target.style.setProperty("opacity", "0", "important");
getComputedStyle(target).opacity;
requestAnimationFrame(() => {

Просмотреть файл

@ -14,8 +14,15 @@ span {
#test {
width: 100px; height: 100px;
background: blue;
transition: transform 100s steps(1, start);
transform: translateX(200px) ! important;
/*
* On the compositor we use a previous vsync time stamp rather than the
* current time stamp, as a result sometimes transition may be still in
* before phase after waiting a frame. To compose the same transform value
* regardless of whether the transition is in before or active phase, we use
* steps(1, end) here.
*/
transition: transform 100s steps(1, end);
transform: none ! important;
}
</style>
<span></span>
@ -25,7 +32,7 @@ window.addEventListener("load", () => {
var target = document.getElementById("test");
getComputedStyle(target).transform;
target.style.setProperty("transform", "none", "important");
target.style.setProperty("transform", "translateX(200px)", "important");
getComputedStyle(target).transform;
requestAnimationFrame(() => {