Commit 5bab54a2 authored by Yi Gu's avatar Yi Gu Committed by Commit Bot

[animation worklet] CurrentTime from DocumentTimeline should be offset by StartTime

Currently upon collecting the inputs for the mutation on main thread, we
don't offset the current time by the start time which is incorrect.

Note:
The layout test animations/animationworklet/worklet-animation-currentTime.html
fails the release build because AnimationClock::currentTime is often
incorrectly ahead of rAF time so that when asking for the current time
in a rAF via getComputedStyle it returns obsolete result. This bug is
tracked by https://crbug.com/785940.

Bug: 905405
Change-Id: I0b7e293ae942e47b96eb8a7a2a8fefd94be66773
Reviewed-on: https://chromium-review.googlesource.com/c/1343558
Commit-Queue: Yi Gu <yigu@chromium.org>
Reviewed-by: default avatarMajid Valipour <majidvp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612238}
parent 8e7542db
...@@ -619,6 +619,17 @@ bool WorkletAnimation::IsActiveAnimation() const { ...@@ -619,6 +619,17 @@ bool WorkletAnimation::IsActiveAnimation() const {
return IsActive(play_state_); return IsActive(play_state_);
} }
base::Optional<double> WorkletAnimation::CurrentTime() const {
bool is_null;
double timeline_time = timeline_->currentTime(is_null);
if (is_null)
return base::nullopt;
if (timeline_->IsScrollTimeline())
return timeline_time;
DCHECK(start_time_);
return timeline_time - start_time_->InSecondsF();
}
void WorkletAnimation::UpdateInputState( void WorkletAnimation::UpdateInputState(
AnimationWorkletDispatcherInput* input_state) { AnimationWorkletDispatcherInput* input_state) {
if (!running_on_main_thread_) { if (!running_on_main_thread_) {
...@@ -632,8 +643,8 @@ void WorkletAnimation::UpdateInputState( ...@@ -632,8 +643,8 @@ void WorkletAnimation::UpdateInputState(
// ScrollTimeline animation doesn't require start_time_ to be set. // ScrollTimeline animation doesn't require start_time_ to be set.
DCHECK(start_time_ || timeline_->IsScrollTimeline()); DCHECK(start_time_ || timeline_->IsScrollTimeline());
DCHECK(last_current_time_ || !was_active); DCHECK(last_current_time_ || !was_active);
bool is_null; double current_time =
double current_time = timeline_->currentTime(is_null); CurrentTime().value_or(std::numeric_limits<double>::quiet_NaN());
bool did_time_change = bool did_time_change =
!last_current_time_ || current_time != last_current_time_->InSecondsF(); !last_current_time_ || current_time != last_current_time_->InSecondsF();
...@@ -641,10 +652,7 @@ void WorkletAnimation::UpdateInputState( ...@@ -641,10 +652,7 @@ void WorkletAnimation::UpdateInputState(
// is resolved, we apply the last current time to the animation if the scroll // is resolved, we apply the last current time to the animation if the scroll
// timeline becomes newly inactive. See https://crbug.com/906050. // timeline becomes newly inactive. See https://crbug.com/906050.
last_current_time_ = base::TimeDelta::FromSecondsD(current_time); last_current_time_ = base::TimeDelta::FromSecondsD(current_time);
if (!was_active && is_active) { if (!was_active && is_active) {
// TODO(yigu): current_time should be offset by start_time_ for animations
// with document timeline. https://crbug.com/905405.
input_state->Add( input_state->Add(
{id_, {id_,
std::string(animator_name_.Ascii().data(), animator_name_.length()), std::string(animator_name_.Ascii().data(), animator_name_.length()),
......
...@@ -145,6 +145,7 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase, ...@@ -145,6 +145,7 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase,
void SetPlayState(const Animation::AnimationPlayState& state) { void SetPlayState(const Animation::AnimationPlayState& state) {
play_state_ = state; play_state_ = state;
} }
base::Optional<double> CurrentTime() const;
unsigned sequence_number_; unsigned sequence_number_;
......
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
#include "third_party/blink/renderer/core/animation/element_animations.h" #include "third_party/blink/renderer/core/animation/element_animations.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect.h" #include "third_party/blink/renderer/core/animation/keyframe_effect.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h" #include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h" #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
...@@ -39,12 +41,16 @@ KeyframeEffect* CreateKeyframeEffect(Element* element) { ...@@ -39,12 +41,16 @@ KeyframeEffect* CreateKeyframeEffect(Element* element) {
return KeyframeEffect::Create(element, CreateEffectModel(), timing); return KeyframeEffect::Create(element, CreateEffectModel(), timing);
} }
WorkletAnimation* CreateWorkletAnimation(ScriptState* script_state, WorkletAnimation* CreateWorkletAnimation(
Element* element) { ScriptState* script_state,
Element* element,
ScrollTimeline* scroll_timeline = nullptr) {
AnimationEffectOrAnimationEffectSequence effects; AnimationEffectOrAnimationEffectSequence effects;
AnimationEffect* effect = CreateKeyframeEffect(element); AnimationEffect* effect = CreateKeyframeEffect(element);
effects.SetAnimationEffect(effect); effects.SetAnimationEffect(effect);
DocumentTimelineOrScrollTimeline timeline; DocumentTimelineOrScrollTimeline timeline;
if (scroll_timeline)
timeline.SetScrollTimeline(scroll_timeline);
scoped_refptr<SerializedScriptValue> options; scoped_refptr<SerializedScriptValue> options;
ScriptState::Scope scope(script_state); ScriptState::Scope scope(script_state);
...@@ -95,4 +101,84 @@ TEST_F(WorkletAnimationTest, StyleHasCurrentAnimation) { ...@@ -95,4 +101,84 @@ TEST_F(WorkletAnimationTest, StyleHasCurrentAnimation) {
EXPECT_EQ(true, style->HasCurrentOpacityAnimation()); EXPECT_EQ(true, style->HasCurrentOpacityAnimation());
} }
TEST_F(WorkletAnimationTest,
CurrentTimeFromDocumentTimelineIsOffsetByStartTime) {
GetDocument().GetAnimationClock().ResetTimeForTesting();
double error = base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF();
WorkletAnimationId id = worklet_animation_->GetWorkletAnimationId();
base::TimeTicks first_ticks =
base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111);
base::TimeTicks second_ticks =
base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111 + 123.4);
GetDocument().GetAnimationClock().UpdateTime(first_ticks);
DummyExceptionStateForTesting exception_state;
worklet_animation_->play(exception_state);
worklet_animation_->UpdateCompositingState();
std::unique_ptr<AnimationWorkletDispatcherInput> state =
std::make_unique<AnimationWorkletDispatcherInput>();
worklet_animation_->UpdateInputState(state.get());
// First state request sets the start time and thus current time should be 0.
std::unique_ptr<AnimationWorkletInput> input =
state->TakeWorkletState(id.scope_id);
EXPECT_NEAR(0, input->added_and_updated_animations[0].current_time, error);
state.reset(new AnimationWorkletDispatcherInput);
GetDocument().GetAnimationClock().UpdateTime(second_ticks);
worklet_animation_->UpdateInputState(state.get());
input = state->TakeWorkletState(id.scope_id);
EXPECT_NEAR(123.4, input->updated_animations[0].current_time, error);
}
TEST_F(WorkletAnimationTest,
CurrentTimeFromScrollTimelineNotOffsetByStartTime) {
SetBodyInnerHTML(R"HTML(
<style>
#scroller { overflow: scroll; width: 100px; height: 100px; }
#spacer { width: 200px; height: 200px; }
</style>
<div id='scroller'>
<div id ='spacer'></div>
</div>
)HTML");
LayoutBoxModelObject* scroller =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
ASSERT_TRUE(scroller);
ASSERT_TRUE(scroller->HasOverflowClip());
PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
ASSERT_TRUE(scrollable_area);
scrollable_area->SetScrollOffset(ScrollOffset(0, 20), kProgrammaticScroll);
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);
WorkletAnimation* worklet_animation =
CreateWorkletAnimation(GetScriptState(), element_, scroll_timeline);
WorkletAnimationId id = worklet_animation->GetWorkletAnimationId();
DummyExceptionStateForTesting exception_state;
worklet_animation->play(exception_state);
worklet_animation->UpdateCompositingState();
double error = base::TimeDelta::FromMicrosecondsD(1).InMillisecondsF();
scrollable_area->SetScrollOffset(ScrollOffset(0, 40), kProgrammaticScroll);
std::unique_ptr<AnimationWorkletDispatcherInput> state =
std::make_unique<AnimationWorkletDispatcherInput>();
worklet_animation->UpdateInputState(state.get());
std::unique_ptr<AnimationWorkletInput> input =
state->TakeWorkletState(id.scope_id);
EXPECT_NEAR(40, input->added_and_updated_animations[0].current_time, error);
state.reset(new AnimationWorkletDispatcherInput);
scrollable_area->SetScrollOffset(ScrollOffset(0, 70), kProgrammaticScroll);
worklet_animation->UpdateInputState(state.get());
input = state->TakeWorkletState(id.scope_id);
EXPECT_NEAR(70, input->updated_animations[0].current_time, error);
}
} // namespace blink } // namespace blink
...@@ -5606,6 +5606,7 @@ crbug.com/886566 http/tests/csspaint/invalidation-border-image.html [ Pass Timeo ...@@ -5606,6 +5606,7 @@ crbug.com/886566 http/tests/csspaint/invalidation-border-image.html [ Pass Timeo
crbug.com/886566 http/tests/csspaint/invalidation-content-image.html [ Pass Timeout ] crbug.com/886566 http/tests/csspaint/invalidation-content-image.html [ Pass Timeout ]
# Enable AnimationWorklet tests for mainthread # Enable AnimationWorklet tests for mainthread
crbug.com/785940 [ Release ] animations/animationworklet/worklet-animation-local-time-after-duration.html [ Pass Failure ]
crbug.com/887659 virtual/threaded/animations/animationworklet/worklet-animation-local-time-after-duration.html [ Failure ] crbug.com/887659 virtual/threaded/animations/animationworklet/worklet-animation-local-time-after-duration.html [ Failure ]
# Sheriff 2018-09-25 # Sheriff 2018-09-25
......
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