Commit 859ff152 authored by Yi Gu's avatar Yi Gu Committed by Commit Bot

[animation worklet] Drive group effects by their own local time

Currently all the effects of an animation are driven by the local time
of the first effect. Rather, they should be driven by the individual
local time.

This patch adds WorkletGroupEffectProxy to Animator and only initialize
it when necessary, i.e. animating group effects. Single effect animation
follows the existing logic which is not affected by this patch.

Bug: 894180
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I24a828d5afd07d94854683744e5d765af45c82c8
Reviewed-on: https://chromium-review.googlesource.com/c/1274192Reviewed-by: default avatarStephen McGruer <smcgruer@chromium.org>
Reviewed-by: default avatarJeremy Roman <jbroman@chromium.org>
Reviewed-by: default avatarMajid Valipour <majidvp@chromium.org>
Commit-Queue: Yi Gu <yigu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600073}
parent 8a1ad3a1
...@@ -50,7 +50,8 @@ class AnimationHostTest : public AnimationTimelinesTest { ...@@ -50,7 +50,8 @@ class AnimationHostTest : public AnimationTimelinesTest {
} }
void SetOutputState(base::TimeDelta local_time) { void SetOutputState(base::TimeDelta local_time) {
MutatorOutputState::AnimationState state(worklet_animation_id_, local_time); MutatorOutputState::AnimationState state(worklet_animation_id_);
state.local_times.push_back(local_time);
worklet_animation_impl_->SetOutputState(state); worklet_animation_impl_->SetOutputState(state);
} }
......
...@@ -112,8 +112,12 @@ void WorkletAnimation::UpdateInputState(MutatorInputState* input_state, ...@@ -112,8 +112,12 @@ void WorkletAnimation::UpdateInputState(MutatorInputState* input_state,
switch (state_) { switch (state_) {
case State::PENDING: case State::PENDING:
input_state->Add( // TODO(yigu): cc side WorkletAnimation is only capable of handling single
{worklet_animation_id(), name(), current_time, CloneOptions()}); // keyframe effect at the moment. We should pass in the number of effects
// once Worklet Group Effect is fully implemented in cc.
// https://crbug.com/767043.
input_state->Add({worklet_animation_id(), name(), current_time,
CloneOptions(), 1 /* num_effects */});
state_ = State::RUNNING; state_ = State::RUNNING;
break; break;
case State::RUNNING: case State::RUNNING:
...@@ -127,7 +131,10 @@ void WorkletAnimation::UpdateInputState(MutatorInputState* input_state, ...@@ -127,7 +131,10 @@ void WorkletAnimation::UpdateInputState(MutatorInputState* input_state,
void WorkletAnimation::SetOutputState( void WorkletAnimation::SetOutputState(
const MutatorOutputState::AnimationState& state) { const MutatorOutputState::AnimationState& state) {
local_time_ = state.local_time; // TODO(yigu): cc side WorkletAnimation is only capable of handling single
// keyframe effect at the moment. https://crbug.com/767043.
DCHECK_EQ(state.local_times.size(), 1u);
local_time_ = state.local_times[0];
} }
// TODO(crbug.com/780151): Multiply the result by the play back rate. // TODO(crbug.com/780151): Multiply the result by the play back rate.
......
...@@ -64,8 +64,10 @@ TEST_F(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe) { ...@@ -64,8 +64,10 @@ TEST_F(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe) {
false /* not impl instance*/, std::move(effect))); false /* not impl instance*/, std::move(effect)));
EXPECT_CALL(*mock_effect, Tick(_)).Times(0); EXPECT_CALL(*mock_effect, Tick(_)).Times(0);
worklet_animation->SetOutputState(
{worklet_animation_id_, base::TimeDelta::FromSecondsD(1)}); MutatorOutputState::AnimationState state(worklet_animation_id_);
state.local_times.push_back(base::TimeDelta::FromSecondsD(1));
worklet_animation->SetOutputState(state);
worklet_animation->Tick(base::TimeTicks()); worklet_animation->Tick(base::TimeTicks());
} }
...@@ -87,7 +89,9 @@ TEST_F(WorkletAnimationTest, LocalTimeIsUsedWhenTicking) { ...@@ -87,7 +89,9 @@ TEST_F(WorkletAnimationTest, LocalTimeIsUsedWhenTicking) {
keyframe_model->set_needs_synchronized_start_time(false); keyframe_model->set_needs_synchronized_start_time(false);
base::TimeDelta local_time = base::TimeDelta::FromSecondsD(duration / 2); base::TimeDelta local_time = base::TimeDelta::FromSecondsD(duration / 2);
worklet_animation_->SetOutputState({worklet_animation_id_, local_time}); MutatorOutputState::AnimationState state(worklet_animation_id_);
state.local_times.push_back(local_time);
worklet_animation_->SetOutputState(state);
worklet_animation_->Tick(base::TimeTicks()); worklet_animation_->Tick(base::TimeTicks());
......
...@@ -12,11 +12,13 @@ AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState( ...@@ -12,11 +12,13 @@ AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState(
WorkletAnimationId worklet_animation_id, WorkletAnimationId worklet_animation_id,
std::string name, std::string name,
double current_time, double current_time,
std::unique_ptr<AnimationOptions> options) std::unique_ptr<AnimationOptions> options,
int num_effects)
: worklet_animation_id(worklet_animation_id), : worklet_animation_id(worklet_animation_id),
name(name), name(name),
current_time(current_time), current_time(current_time),
options(std::move(options)) {} options(std::move(options)),
num_effects(num_effects) {}
AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState( AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState(
AddAndUpdateState&&) = default; AddAndUpdateState&&) = default;
AnimationWorkletInput::AddAndUpdateState::~AddAndUpdateState() = default; AnimationWorkletInput::AddAndUpdateState::~AddAndUpdateState() = default;
...@@ -97,11 +99,10 @@ std::unique_ptr<AnimationWorkletInput> MutatorInputState::TakeWorkletState( ...@@ -97,11 +99,10 @@ std::unique_ptr<AnimationWorkletInput> MutatorInputState::TakeWorkletState(
AnimationWorkletOutput::AnimationWorkletOutput() = default; AnimationWorkletOutput::AnimationWorkletOutput() = default;
AnimationWorkletOutput::~AnimationWorkletOutput() = default; AnimationWorkletOutput::~AnimationWorkletOutput() = default;
AnimationWorkletOutput::AnimationState::AnimationState( AnimationWorkletOutput::AnimationState::AnimationState(WorkletAnimationId id)
WorkletAnimationId id, : worklet_animation_id(id) {}
base::Optional<base::TimeDelta> time)
: worklet_animation_id(id), local_time(time) {}
AnimationWorkletOutput::AnimationState::AnimationState(const AnimationState&) = AnimationWorkletOutput::AnimationState::AnimationState(const AnimationState&) =
default; default;
AnimationWorkletOutput::AnimationState::~AnimationState() = default;
} // namespace cc } // namespace cc
...@@ -40,11 +40,13 @@ struct CC_EXPORT AnimationWorkletInput { ...@@ -40,11 +40,13 @@ struct CC_EXPORT AnimationWorkletInput {
// Worklet animation's current time, from its associated timeline. // Worklet animation's current time, from its associated timeline.
double current_time; double current_time;
std::unique_ptr<AnimationOptions> options; std::unique_ptr<AnimationOptions> options;
int num_effects;
AddAndUpdateState(WorkletAnimationId worklet_animation_id, AddAndUpdateState(WorkletAnimationId worklet_animation_id,
std::string name, std::string name,
double current_time, double current_time,
std::unique_ptr<AnimationOptions> options); std::unique_ptr<AnimationOptions> options,
int num_effects);
AddAndUpdateState(AddAndUpdateState&&); AddAndUpdateState(AddAndUpdateState&&);
~AddAndUpdateState(); ~AddAndUpdateState();
...@@ -109,16 +111,12 @@ class CC_EXPORT MutatorInputState { ...@@ -109,16 +111,12 @@ class CC_EXPORT MutatorInputState {
struct CC_EXPORT AnimationWorkletOutput { struct CC_EXPORT AnimationWorkletOutput {
struct CC_EXPORT AnimationState { struct CC_EXPORT AnimationState {
AnimationState(WorkletAnimationId, explicit AnimationState(WorkletAnimationId);
base::Optional<base::TimeDelta> local_time);
AnimationState(const AnimationState&); AnimationState(const AnimationState&);
~AnimationState();
WorkletAnimationId worklet_animation_id; WorkletAnimationId worklet_animation_id;
// The animator effect's local time. std::vector<base::Optional<base::TimeDelta>> local_times;
// TODO(majidvp): This assumes each animator has a single output effect
// which does not hold once we state support group effects.
// http://crbug.com/767043
base::Optional<base::TimeDelta> local_time;
}; };
AnimationWorkletOutput(); AnimationWorkletOutput();
......
CONSOLE MESSAGE: line 63: background-color for the first target is: rgb(0, 128, 128)
CONSOLE MESSAGE: line 65: box-shadow for the second target is: rgb(0, 128, 128) 4px 4px 25px 0px
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
<script id="simple_animate" type="text/worklet"> <script id="simple_animate" type="text/worklet">
registerAnimator("test_animator", class { registerAnimator("test_animator", class {
animate(currentTime, effect) { animate(currentTime, effect) {
effect.localTime = 1000; let effects = effect.getChildren();
effects[0].localTime = 1000;
effects[1].localTime = 1000;
} }
}); });
</script> </script>
...@@ -52,38 +54,16 @@ runInAnimationWorklet( ...@@ -52,38 +54,16 @@ runInAnimationWorklet(
{ duration: 2000 } { duration: 2000 }
); );
const effect3 = new KeyframeEffect(
document.getElementById("target"),
[
{ width: '100px' },
{ width: '200px' }
],
{ duration: 2000 }
);
const effect4 = new KeyframeEffect(
document.getElementById("target2"),
[
{ opacity: 1 },
{ opacity: 0 }
],
{ duration: 2000 }
);
const animation = new WorkletAnimation('test_animator', const animation = new WorkletAnimation('test_animator',
[ effect, effect2, effect3, effect4 ]); [ effect, effect2 ]);
animation.play(); animation.play();
if (window.testRunner) { if (window.testRunner) {
waitTwoAnimationFrames( _ => { waitTwoAnimationFrames( _ => {
console.log('background-color for the first target is: ' + console.log('background-color for the first target is: ' +
getComputedStyle(document.getElementById('target')).backgroundColor); getComputedStyle(document.getElementById('target')).backgroundColor);
console.log('width for the first target is: ' +
getComputedStyle(document.getElementById('target')).width);
console.log('box-shadow for the second target is: ' + console.log('box-shadow for the second target is: ' +
getComputedStyle(document.getElementById('target2')).boxShadow); getComputedStyle(document.getElementById('target2')).boxShadow);
console.log('opacity for the second target is: ' +
getComputedStyle(document.getElementById('target2')).opacity);
testRunner.notifyDone(); testRunner.notifyDone();
}); });
} }
......
CONSOLE MESSAGE: line 62: background-color for the first target is: rgb(0, 255, 0)
CONSOLE MESSAGE: line 64: width for the first target is: 150px
<!DOCTYPE html>
<style>
#target {
width: 100px;
height: 100px;
background-color: #0f0;
}
#target2 {
width: 100px;
height: 100px;
background-color: #00f;
box-shadow: 4px 4px 25px #00f;
}
</style>
<div id="target"></div>
<script id="simple_animate" type="text/worklet">
registerAnimator("test_animator", class {
animate(currentTime, effect) {
let effects = effect.getChildren();
effects[0].localTime = 0;
effects[1].localTime = 1000;
}
});
</script>
<script src="resources/animation-worklet-tests.js"></script>
<script>
if (window.testRunner) {
testRunner.dumpAsText();
testRunner.waitUntilDone();
}
runInAnimationWorklet(
document.getElementById('simple_animate').textContent
).then(_ => {
const effect = new KeyframeEffect(
document.getElementById("target"),
[
{ background: '#0f0' },
{ background: '#00f' },
],
{ duration: 2000 }
);
const effect2 = new KeyframeEffect(
document.getElementById("target"),
[
{ width: '100px' },
{ width: '200px' }
],
{ duration: 2000 }
);
const animation = new WorkletAnimation('test_animator',
[ effect, effect2 ]);
animation.play();
if (window.testRunner) {
waitTwoAnimationFrames( _ => {
console.log('background-color for the first target is: ' +
getComputedStyle(document.getElementById('target')).backgroundColor);
console.log('width for the first target is: ' +
getComputedStyle(document.getElementById('target')).width);
testRunner.notifyDone();
});
}
});
</script>
...@@ -25,6 +25,9 @@ CONSOLE MESSAGE: line 153: getter writable ...@@ -25,6 +25,9 @@ CONSOLE MESSAGE: line 153: getter writable
CONSOLE MESSAGE: line 153: method constructor CONSOLE MESSAGE: line 153: method constructor
CONSOLE MESSAGE: line 153: interface WorkletGlobalScope CONSOLE MESSAGE: line 153: interface WorkletGlobalScope
CONSOLE MESSAGE: line 153: method constructor CONSOLE MESSAGE: line 153: method constructor
CONSOLE MESSAGE: line 153: interface WorkletGroupEffectProxy
CONSOLE MESSAGE: line 153: method constructor
CONSOLE MESSAGE: line 153: method getChildren
CONSOLE MESSAGE: line 153: interface WritableStream CONSOLE MESSAGE: line 153: interface WritableStream
CONSOLE MESSAGE: line 153: getter locked CONSOLE MESSAGE: line 153: getter locked
CONSOLE MESSAGE: line 153: method abort CONSOLE MESSAGE: line 153: method abort
......
...@@ -25,6 +25,9 @@ CONSOLE MESSAGE: line 151: getter writable ...@@ -25,6 +25,9 @@ CONSOLE MESSAGE: line 151: getter writable
CONSOLE MESSAGE: line 151: method constructor CONSOLE MESSAGE: line 151: method constructor
CONSOLE MESSAGE: line 151: interface WorkletGlobalScope CONSOLE MESSAGE: line 151: interface WorkletGlobalScope
CONSOLE MESSAGE: line 151: method constructor CONSOLE MESSAGE: line 151: method constructor
CONSOLE MESSAGE: line 153: interface WorkletGroupEffectProxy
CONSOLE MESSAGE: line 153: method constructor
CONSOLE MESSAGE: line 153: method getChildren
CONSOLE MESSAGE: line 151: interface WritableStream CONSOLE MESSAGE: line 151: interface WritableStream
CONSOLE MESSAGE: line 151: getter locked CONSOLE MESSAGE: line 151: getter locked
CONSOLE MESSAGE: line 151: method abort CONSOLE MESSAGE: line 151: method abort
......
...@@ -28,5 +28,7 @@ blink_modules_sources("animationworklet") { ...@@ -28,5 +28,7 @@ blink_modules_sources("animationworklet") {
"worklet_animation.h", "worklet_animation.h",
"worklet_animation_options.cc", "worklet_animation_options.cc",
"worklet_animation_options.h", "worklet_animation_options.h",
"worklet_group_effect_proxy.cc",
"worklet_group_effect_proxy.h",
] ]
} }
...@@ -25,8 +25,7 @@ void UpdateAnimation(Animator* animator, ...@@ -25,8 +25,7 @@ void UpdateAnimation(Animator* animator,
WorkletAnimationId id, WorkletAnimationId id,
double current_time, double current_time,
AnimationWorkletDispatcherOutput* result) { AnimationWorkletDispatcherOutput* result) {
AnimationWorkletDispatcherOutput::AnimationState animation_output( AnimationWorkletDispatcherOutput::AnimationState animation_output(id);
id, base::nullopt);
if (animator->Animate(script_state, current_time, &animation_output)) { if (animator->Animate(script_state, current_time, &animation_output)) {
result->animations.push_back(std::move(animation_output)); result->animations.push_back(std::move(animation_output));
} }
...@@ -66,9 +65,10 @@ void AnimationWorkletGlobalScope::Dispose() { ...@@ -66,9 +65,10 @@ void AnimationWorkletGlobalScope::Dispose() {
Animator* AnimationWorkletGlobalScope::CreateAnimatorFor( Animator* AnimationWorkletGlobalScope::CreateAnimatorFor(
int animation_id, int animation_id,
const String& name, const String& name,
WorkletAnimationOptions* options) { WorkletAnimationOptions* options,
int num_effects) {
DCHECK(!animators_.at(animation_id)); DCHECK(!animators_.at(animation_id));
Animator* animator = CreateInstance(name, options); Animator* animator = CreateInstance(name, options, num_effects);
if (!animator) if (!animator)
return nullptr; return nullptr;
animators_.Set(animation_id, animator); animators_.Set(animation_id, animator);
...@@ -99,7 +99,8 @@ std::unique_ptr<AnimationWorkletOutput> AnimationWorkletGlobalScope::Mutate( ...@@ -99,7 +99,8 @@ std::unique_ptr<AnimationWorkletOutput> AnimationWorkletGlobalScope::Mutate(
WorkletAnimationOptions* options = WorkletAnimationOptions* options =
static_cast<WorkletAnimationOptions*>(animation.options.get()); static_cast<WorkletAnimationOptions*>(animation.options.get());
Animator* animator = CreateAnimatorFor(id, name, options); Animator* animator =
CreateAnimatorFor(id, name, options, animation.num_effects);
if (!animator) if (!animator)
continue; continue;
...@@ -121,10 +122,13 @@ std::unique_ptr<AnimationWorkletOutput> AnimationWorkletGlobalScope::Mutate( ...@@ -121,10 +122,13 @@ std::unique_ptr<AnimationWorkletOutput> AnimationWorkletGlobalScope::Mutate(
for (const auto& worklet_animation_id : mutator_input.peeked_animations) { for (const auto& worklet_animation_id : mutator_input.peeked_animations) {
int id = worklet_animation_id.animation_id; int id = worklet_animation_id.animation_id;
Animator* animator = animators_.at(id); Animator* animator = animators_.at(id);
if (!animator)
continue;
result->animations.emplace_back( AnimationWorkletDispatcherOutput::AnimationState animation_output(
worklet_animation_id, worklet_animation_id);
animator ? animator->GetLastLocalTime() : base::nullopt); animation_output.local_times = animator->GetLocalTimes();
result->animations.push_back(animation_output);
} }
return result; return result;
...@@ -185,7 +189,8 @@ void AnimationWorkletGlobalScope::registerAnimator( ...@@ -185,7 +189,8 @@ void AnimationWorkletGlobalScope::registerAnimator(
Animator* AnimationWorkletGlobalScope::CreateInstance( Animator* AnimationWorkletGlobalScope::CreateInstance(
const String& name, const String& name,
WorkletAnimationOptions* options) { WorkletAnimationOptions* options,
int num_effects) {
DCHECK(IsContextThread()); DCHECK(IsContextThread());
AnimatorDefinition* definition = animator_definitions_.at(name); AnimatorDefinition* definition = animator_definitions_.at(name);
if (!definition) if (!definition)
...@@ -206,7 +211,7 @@ Animator* AnimationWorkletGlobalScope::CreateInstance( ...@@ -206,7 +211,7 @@ Animator* AnimationWorkletGlobalScope::CreateInstance(
.ToLocal(&instance)) .ToLocal(&instance))
return nullptr; return nullptr;
return new Animator(isolate, definition, instance); return new Animator(isolate, definition, instance, num_effects);
} }
AnimatorDefinition* AnimationWorkletGlobalScope::FindDefinitionForTest( AnimatorDefinition* AnimationWorkletGlobalScope::FindDefinitionForTest(
......
...@@ -56,10 +56,12 @@ class MODULES_EXPORT AnimationWorkletGlobalScope : public WorkletGlobalScope { ...@@ -56,10 +56,12 @@ class MODULES_EXPORT AnimationWorkletGlobalScope : public WorkletGlobalScope {
void RegisterWithProxyClientIfNeeded(); void RegisterWithProxyClientIfNeeded();
Animator* CreateInstance(const String& name, Animator* CreateInstance(const String& name,
WorkletAnimationOptions* options); WorkletAnimationOptions* options,
int num_effects);
Animator* CreateAnimatorFor(int animation_id, Animator* CreateAnimatorFor(int animation_id,
const String& name, const String& name,
WorkletAnimationOptions* options); WorkletAnimationOptions* options,
int num_effects);
typedef HeapHashMap<String, TraceWrapperMember<AnimatorDefinition>> typedef HeapHashMap<String, TraceWrapperMember<AnimatorDefinition>>
DefinitionMap; DefinitionMap;
DefinitionMap animator_definitions_; DefinitionMap animator_definitions_;
......
...@@ -222,7 +222,7 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase { ...@@ -222,7 +222,7 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
cc::WorkletAnimationId animation_id = {1, 1}; cc::WorkletAnimationId animation_id = {1, 1};
AnimationWorkletInput state; AnimationWorkletInput state;
state.added_and_updated_animations.emplace_back(animation_id, "test", 5000, state.added_and_updated_animations.emplace_back(animation_id, "test", 5000,
nullptr); nullptr, 1);
std::unique_ptr<AnimationWorkletOutput> output = std::unique_ptr<AnimationWorkletOutput> output =
global_scope->Mutate(state); global_scope->Mutate(state);
...@@ -273,14 +273,14 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase { ...@@ -273,14 +273,14 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
cc::WorkletAnimationId animation_id = {1, 1}; cc::WorkletAnimationId animation_id = {1, 1};
AnimationWorkletInput state; AnimationWorkletInput state;
state.added_and_updated_animations.emplace_back(animation_id, "test", 5000, state.added_and_updated_animations.emplace_back(animation_id, "test", 5000,
nullptr); nullptr, 1);
std::unique_ptr<AnimationWorkletOutput> output = std::unique_ptr<AnimationWorkletOutput> output =
global_scope->Mutate(state); global_scope->Mutate(state);
EXPECT_TRUE(output); EXPECT_TRUE(output);
EXPECT_EQ(output->animations.size(), 1ul); EXPECT_EQ(output->animations.size(), 1ul);
EXPECT_EQ(output->animations[0].local_time, EXPECT_EQ(output->animations[0].local_times[0],
WTF::TimeDelta::FromMillisecondsD(123)); WTF::TimeDelta::FromMillisecondsD(123));
waitable_event->Signal(); waitable_event->Signal();
...@@ -329,7 +329,7 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase { ...@@ -329,7 +329,7 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
EXPECT_EQ(global_scope->GetAnimatorsSizeForTest(), 0u); EXPECT_EQ(global_scope->GetAnimatorsSizeForTest(), 0u);
state.added_and_updated_animations.push_back( state.added_and_updated_animations.push_back(
{animation_id, "test", 5000, nullptr}); {animation_id, "test", 5000, nullptr, 1});
EXPECT_EQ(state.added_and_updated_animations.size(), 1u); EXPECT_EQ(state.added_and_updated_animations.size(), 1u);
global_scope->Mutate(state); global_scope->Mutate(state);
EXPECT_EQ(global_scope->GetAnimatorsSizeForTest(), 1u); EXPECT_EQ(global_scope->GetAnimatorsSizeForTest(), 1u);
...@@ -366,7 +366,7 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase { ...@@ -366,7 +366,7 @@ class AnimationWorkletGlobalScopeTest : public PageTestBase {
cc::WorkletAnimationId animation_id = {1, 1}; cc::WorkletAnimationId animation_id = {1, 1};
AnimationWorkletInput state; AnimationWorkletInput state;
state.added_and_updated_animations.push_back( state.added_and_updated_animations.push_back(
{animation_id, "test", 5000, nullptr}); {animation_id, "test", 5000, nullptr, 1});
EXPECT_EQ(state.added_and_updated_animations.size(), 1u); EXPECT_EQ(state.added_and_updated_animations.size(), 1u);
global_scope->Mutate(state); global_scope->Mutate(state);
EXPECT_EQ(global_scope->GetAnimatorsSizeForTest(), 1u); EXPECT_EQ(global_scope->GetAnimatorsSizeForTest(), 1u);
......
...@@ -15,16 +15,19 @@ namespace blink { ...@@ -15,16 +15,19 @@ namespace blink {
Animator::Animator(v8::Isolate* isolate, Animator::Animator(v8::Isolate* isolate,
AnimatorDefinition* definition, AnimatorDefinition* definition,
v8::Local<v8::Value> instance) v8::Local<v8::Value> instance,
int num_effects)
: definition_(definition), : definition_(definition),
instance_(isolate, instance), instance_(isolate, instance),
effect_(new EffectProxy()) {} group_effect_(new WorkletGroupEffectProxy(num_effects)) {
DCHECK_GE(num_effects, 1);
}
Animator::~Animator() = default; Animator::~Animator() = default;
void Animator::Trace(blink::Visitor* visitor) { void Animator::Trace(blink::Visitor* visitor) {
visitor->Trace(definition_); visitor->Trace(definition_);
visitor->Trace(effect_); visitor->Trace(group_effect_);
visitor->Trace(instance_); visitor->Trace(instance_);
} }
...@@ -46,8 +49,14 @@ bool Animator::Animate( ...@@ -46,8 +49,14 @@ bool Animator::Animate(
// Prepare arguments (i.e., current time and effect) and pass them to animate // Prepare arguments (i.e., current time and effect) and pass them to animate
// callback. // callback.
v8::Local<v8::Value> v8_effect = v8::Local<v8::Value> v8_effect;
ToV8(effect_, script_state->GetContext()->Global(), isolate); if (group_effect_->getChildren().size() == 1) {
v8_effect = ToV8(group_effect_->getChildren()[0],
script_state->GetContext()->Global(), isolate);
} else {
v8_effect =
ToV8(group_effect_, script_state->GetContext()->Global(), isolate);
}
v8::Local<v8::Value> v8_current_time = v8::Local<v8::Value> v8_current_time =
ToV8(current_time, script_state->GetContext()->Global(), isolate); ToV8(current_time, script_state->GetContext()->Global(), isolate);
...@@ -62,8 +71,17 @@ bool Animator::Animate( ...@@ -62,8 +71,17 @@ bool Animator::Animate(
if (block.HasCaught()) if (block.HasCaught())
return false; return false;
output->local_time = effect_->local_time(); output->local_times = GetLocalTimes();
return true; return true;
} }
std::vector<base::Optional<TimeDelta>> Animator::GetLocalTimes() const {
std::vector<base::Optional<TimeDelta>> local_times;
local_times.reserve(group_effect_->getChildren().size());
for (const auto& effect : group_effect_->getChildren()) {
local_times.push_back(effect->local_time());
}
return local_times;
}
} // namespace blink } // namespace blink
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATOR_H_ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATOR_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATOR_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATOR_H_
#include "third_party/blink/renderer/modules/animationworklet/effect_proxy.h" #include "third_party/blink/renderer/modules/animationworklet/worklet_group_effect_proxy.h"
#include "third_party/blink/renderer/platform/bindings/name_client.h" #include "third_party/blink/renderer/platform/bindings/name_client.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
...@@ -25,7 +25,10 @@ class ScriptState; ...@@ -25,7 +25,10 @@ class ScriptState;
class Animator final : public GarbageCollectedFinalized<Animator>, class Animator final : public GarbageCollectedFinalized<Animator>,
public NameClient { public NameClient {
public: public:
Animator(v8::Isolate*, AnimatorDefinition*, v8::Local<v8::Value> instance); Animator(v8::Isolate*,
AnimatorDefinition*,
v8::Local<v8::Value> instance,
int num_effects);
~Animator(); ~Animator();
void Trace(blink::Visitor*); void Trace(blink::Visitor*);
const char* NameInHeapSnapshot() const override { return "Animator"; } const char* NameInHeapSnapshot() const override { return "Animator"; }
...@@ -36,9 +39,7 @@ class Animator final : public GarbageCollectedFinalized<Animator>, ...@@ -36,9 +39,7 @@ class Animator final : public GarbageCollectedFinalized<Animator>,
bool Animate(ScriptState*, bool Animate(ScriptState*,
double current_time, double current_time,
AnimationWorkletDispatcherOutput::AnimationState*); AnimationWorkletDispatcherOutput::AnimationState*);
base::Optional<TimeDelta> GetLastLocalTime() const { std::vector<base::Optional<TimeDelta>> GetLocalTimes() const;
return effect_->local_time();
}
private: private:
// This object keeps the definition object, and animator instance alive. // This object keeps the definition object, and animator instance alive.
...@@ -46,7 +47,7 @@ class Animator final : public GarbageCollectedFinalized<Animator>, ...@@ -46,7 +47,7 @@ class Animator final : public GarbageCollectedFinalized<Animator>,
TraceWrapperMember<AnimatorDefinition> definition_; TraceWrapperMember<AnimatorDefinition> definition_;
TraceWrapperV8Reference<v8::Value> instance_; TraceWrapperV8Reference<v8::Value> instance_;
Member<EffectProxy> effect_; Member<WorkletGroupEffectProxy> group_effect_;
}; };
} // namespace blink } // namespace blink
......
...@@ -291,6 +291,7 @@ WorkletAnimation::WorkletAnimation( ...@@ -291,6 +291,7 @@ WorkletAnimation::WorkletAnimation(
for (auto& effect : effects_) { for (auto& effect : effects_) {
AnimationEffect* target_effect = effect; AnimationEffect* target_effect = effect;
target_effect->Attach(this); target_effect->Attach(this);
local_times_.push_back(base::nullopt);
} }
if (timeline_->IsScrollTimeline()) if (timeline_->IsScrollTimeline())
...@@ -338,7 +339,7 @@ void WorkletAnimation::cancel() { ...@@ -338,7 +339,7 @@ void WorkletAnimation::cancel() {
DestroyCompositorAnimation(); DestroyCompositorAnimation();
} }
local_time_ = base::nullopt; local_times_.Fill(base::nullopt);
start_time_ = base::nullopt; start_time_ = base::nullopt;
running_on_main_thread_ = false; running_on_main_thread_ = false;
// TODO(yigu): Because this animation has been detached and will not receive // TODO(yigu): Because this animation has been detached and will not receive
...@@ -382,16 +383,18 @@ void WorkletAnimation::Update(TimingUpdateReason reason) { ...@@ -382,16 +383,18 @@ void WorkletAnimation::Update(TimingUpdateReason reason) {
if (!start_time_) if (!start_time_)
return; return;
// TODO(crbug.com/756539): For now we use 0 as inherited time for compositor DCHECK_EQ(effects_.size(), local_times_.size());
// worklet animations. Will need to get the inherited time from worklet for (size_t i = 0; i < effects_.size(); ++i) {
// context. // TODO(crbug.com/756539): For now we use 0 as inherited time for compositor
double inherited_time_seconds = 0; // worklet animations. Will need to get the inherited time from worklet
// context.
double inherited_time_seconds = 0;
if (local_time_) if (local_times_[i])
inherited_time_seconds = local_time_->InSecondsF(); inherited_time_seconds = local_times_[i]->InSecondsF();
for (auto& effect : effects_) effects_[i]->UpdateInheritedTime(inherited_time_seconds, reason);
effect->UpdateInheritedTime(inherited_time_seconds, reason); }
} }
bool WorkletAnimation::CheckCanStart(String* failure_message) { bool WorkletAnimation::CheckCanStart(String* failure_message) {
...@@ -573,7 +576,7 @@ void WorkletAnimation::UpdateInputState( ...@@ -573,7 +576,7 @@ void WorkletAnimation::UpdateInputState(
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()),
current_time, CloneOptions()}); current_time, CloneOptions(), effects_.size()});
} else if (was_active && is_active) { } else if (was_active && is_active) {
// Skip if the input time is not changed. // Skip if the input time is not changed.
if (did_time_change) if (did_time_change)
...@@ -587,7 +590,13 @@ void WorkletAnimation::UpdateInputState( ...@@ -587,7 +590,13 @@ void WorkletAnimation::UpdateInputState(
void WorkletAnimation::SetOutputState( void WorkletAnimation::SetOutputState(
const AnimationWorkletOutput::AnimationState& state) { const AnimationWorkletOutput::AnimationState& state) {
DCHECK(state.worklet_animation_id == id_); DCHECK(state.worklet_animation_id == id_);
local_time_ = state.local_time; // The local times for composited effects, i.e. not running on main, are
// peeked and set via the main thread. If an animator is not ready upon
// peeking state.local_times will be empty.
DCHECK(local_times_.size() == state.local_times.size() ||
!running_on_main_thread_);
for (size_t i = 0; i < state.local_times.size(); ++i)
local_times_[i] = state.local_times[i];
} }
void WorkletAnimation::Dispose() { void WorkletAnimation::Dispose() {
......
...@@ -155,7 +155,7 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase, ...@@ -155,7 +155,7 @@ class MODULES_EXPORT WorkletAnimation : public WorkletAnimationBase,
Animation::AnimationPlayState last_play_state_; Animation::AnimationPlayState last_play_state_;
// Start time in ms. // Start time in ms.
base::Optional<base::TimeDelta> start_time_; base::Optional<base::TimeDelta> start_time_;
base::Optional<base::TimeDelta> local_time_; Vector<base::Optional<base::TimeDelta>> local_times_;
// We use this to skip updating if current time has not changed since last // We use this to skip updating if current time has not changed since last
// update. // update.
base::Optional<base::TimeDelta> last_current_time_; base::Optional<base::TimeDelta> last_current_time_;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/animationworklet/worklet_group_effect_proxy.h"
namespace blink {
WorkletGroupEffectProxy::WorkletGroupEffectProxy(int num_effects)
: effects_(num_effects) {
for (int i = 0; i < num_effects; ++i)
effects_[i] = new EffectProxy();
}
void WorkletGroupEffectProxy::Trace(blink::Visitor* visitor) {
visitor->Trace(effects_);
ScriptWrappable::Trace(visitor);
}
} // namespace blink
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_WORKLET_GROUP_EFFECT_PROXY_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_WORKLET_GROUP_EFFECT_PROXY_H_
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/modules/animationworklet/effect_proxy.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
namespace blink {
class MODULES_EXPORT WorkletGroupEffectProxy : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
explicit WorkletGroupEffectProxy(int num_effects);
HeapVector<Member<EffectProxy>>& getChildren() { return effects_; }
void Trace(blink::Visitor*) override;
private:
HeapVector<Member<EffectProxy>> effects_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_WORKLET_GROUP_EFFECT_PROXY_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[
Exposed=AnimationWorklet,
OriginTrialEnabled=AnimationWorklet
] interface WorkletGroupEffectProxy {
sequence<EffectProxy> getChildren();
};
...@@ -63,6 +63,7 @@ modules_idl_files = ...@@ -63,6 +63,7 @@ modules_idl_files =
"animationworklet/animation_worklet_global_scope.idl", "animationworklet/animation_worklet_global_scope.idl",
"animationworklet/effect_proxy.idl", "animationworklet/effect_proxy.idl",
"animationworklet/worklet_animation.idl", "animationworklet/worklet_animation.idl",
"animationworklet/worklet_group_effect_proxy.idl",
"app_banner/before_install_prompt_event.idl", "app_banner/before_install_prompt_event.idl",
"background_fetch/background_fetch_event.idl", "background_fetch/background_fetch_event.idl",
"background_fetch/background_fetch_fetch.idl", "background_fetch/background_fetch_fetch.idl",
......
...@@ -94,10 +94,10 @@ class AnimationWorkletMutatorDispatcherImplTest : public ::testing::Test { ...@@ -94,10 +94,10 @@ class AnimationWorkletMutatorDispatcherImplTest : public ::testing::Test {
std::unique_ptr<AnimationWorkletDispatcherInput> CreateTestMutatorInput() { std::unique_ptr<AnimationWorkletDispatcherInput> CreateTestMutatorInput() {
AnimationWorkletInput::AddAndUpdateState state1{ AnimationWorkletInput::AddAndUpdateState state1{
{11, 1}, "test1", 5000, nullptr}; {11, 1}, "test1", 5000, nullptr, 1};
AnimationWorkletInput::AddAndUpdateState state2{ AnimationWorkletInput::AddAndUpdateState state2{
{22, 2}, "test2", 5000, nullptr}; {22, 2}, "test2", 5000, nullptr, 1};
auto input = std::make_unique<AnimationWorkletDispatcherInput>(); auto input = std::make_unique<AnimationWorkletDispatcherInput>();
input->Add(std::move(state1)); input->Add(std::move(state1));
...@@ -146,7 +146,7 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest, ...@@ -146,7 +146,7 @@ TEST_F(AnimationWorkletMutatorDispatcherImplTest,
EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0); EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
AnimationWorkletInput::AddAndUpdateState state2{ AnimationWorkletInput::AddAndUpdateState state2{
{22, 2}, "test2", 5000, nullptr}; {22, 2}, "test2", 5000, nullptr, 1};
auto input = std::make_unique<AnimationWorkletDispatcherInput>(); auto input = std::make_unique<AnimationWorkletDispatcherInput>();
input->Add(std::move(state2)); input->Add(std::move(state2));
......
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