Commit 4405727f authored by Yi Gu's avatar Yi Gu Committed by Commit Bot

[ScrollTimeline] Add previously finished animation to pending on restart

Previously when scroll-linked animation goes from finished to running we
did not add it to pending animations. As a result it never got restarted
on the compositor. See crbug.com/1070635 for more details.

Bug: 1070635
Change-Id: I1454bfbc75f8ce07dc952645c51fabd3804ef0d1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2218749Reviewed-by: default avatarKevin Ellis <kevers@chromium.org>
Reviewed-by: default avatarMajid Valipour <majidvp@chromium.org>
Commit-Queue: Yi Gu <yigu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#773183}
parent 40372e23
......@@ -1361,6 +1361,11 @@ void Animation::UpdateFinishedState(UpdateType update_type,
ScheduleAsyncFinish();
}
} else {
// Previously finished animation may restart so they should be added to
// pending animations to make sure that a compositor animation is re-created
// during future PreCommit.
if (finished_)
SetCompositorPending();
// 6. If not finished but the current finished promise is already resolved,
// create a new promise.
finished_ = pending_finish_notification_ = committed_finish_notification_ =
......
......@@ -1602,6 +1602,90 @@ TEST_F(AnimationAnimationTestNoCompositing, ScrollLinkedAnimationCreation) {
EXPECT_EQ(40, scroll_animation->currentTime());
}
// Verifies that finished composited scroll-linked animations restart on
// compositor upon reverse scrolling.
TEST_F(AnimationAnimationTestCompositing,
FinishedScrollLinkedAnimationRestartsOnReverseScrolling) {
ResetWithCompositedAnimation();
SetBodyInnerHTML(R"HTML(
<style>
#scroller { will-change: transform; overflow: scroll; width: 100px; height: 100px; }
#target { width: 100px; height: 200px; will-change: opacity;}
#spacer { width: 200px; height: 700px; }
</style>
<div id ='scroller'>
<div id ='target'></div>
<div id ='spacer'></div>
</div>
)HTML");
LayoutBoxModelObject* scroller =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
ASSERT_TRUE(scroller->UsesCompositedScrolling());
// Create ScrollTimeline
ScrollTimelineOptions* options = ScrollTimelineOptions::Create();
DoubleOrScrollTimelineAutoKeyword time_range =
DoubleOrScrollTimelineAutoKeyword::FromDouble(100);
options->setTimeRange(time_range);
options->setScrollSource(GetElementById("scroller"));
ScrollTimeline* scroll_timeline =
ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
// Create KeyframeEffect
Timing timing;
timing.iteration_duration = AnimationTimeDelta::FromSecondsD(30);
Persistent<StringKeyframe> start_keyframe =
MakeGarbageCollected<StringKeyframe>();
start_keyframe->SetCSSPropertyValue(CSSPropertyID::kOpacity, "1.0",
SecureContextMode::kInsecureContext,
nullptr);
Persistent<StringKeyframe> end_keyframe =
MakeGarbageCollected<StringKeyframe>();
end_keyframe->SetCSSPropertyValue(CSSPropertyID::kOpacity, "0.0",
SecureContextMode::kInsecureContext,
nullptr);
StringKeyframeVector keyframes;
keyframes.push_back(start_keyframe);
keyframes.push_back(end_keyframe);
Element* element = GetElementById("target");
auto* model = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes);
KeyframeEffect* keyframe_effect =
MakeGarbageCollected<KeyframeEffect>(element, model, timing);
// Create scroll-linked animation
NonThrowableExceptionState exception_state;
Animation* scroll_animation =
Animation::Create(keyframe_effect, scroll_timeline, exception_state);
model->SnapshotAllCompositorKeyframesIfNecessary(
*element, *ComputedStyle::Create(), nullptr);
UpdateAllLifecyclePhasesForTest();
scroll_animation->play();
EXPECT_EQ(scroll_animation->playState(), "running");
GetDocument().GetPendingAnimations().Update(nullptr, true);
EXPECT_TRUE(scroll_animation->HasActiveAnimationsOnCompositor());
// Advances the animation to "finished" state. The composited animation will
// be destroyed accordingly.
scroll_animation->setCurrentTime(50000);
EXPECT_EQ(scroll_animation->playState(), "finished");
scroll_animation->Update(kTimingUpdateForAnimationFrame);
GetDocument().GetPendingAnimations().Update(nullptr, true);
EXPECT_FALSE(scroll_animation->HasActiveAnimationsOnCompositor());
// Restarting the animation should create a new compositor animation.
scroll_animation->setCurrentTime(100);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(scroll_animation->playState(), "running");
scroll_animation->Update(kTimingUpdateForAnimationFrame);
GetDocument().GetPendingAnimations().Update(nullptr, true);
EXPECT_TRUE(scroll_animation->HasActiveAnimationsOnCompositor());
}
TEST_F(AnimationAnimationTestNoCompositing,
RemoveCanceledAnimationFromActiveSet) {
EXPECT_EQ("running", animation->playState());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment