Commit 82b3d458 authored by Majid Valipour's avatar Majid Valipour Committed by Commit Bot

[animation-worklet] Support undefined as default localTime value

EffectProxy.localTime should accept undefined as its local time and treat
that as meaning that the keyframe effect is not in effect.


Note:
This is a partial fix. We still need to make sure that any applied effect
is cleared once localTime is set to undefined. This patch only ensures that
when the initial value is not set, or set to undefined the keyframe effect
is not applied.

Test: virtual/threaded/fast/animationworklet/worklet-animation-local-time-undefined.html

Bug: 870711
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I2fdc716c331eb11a9b3eed524ac703f50a222a49
Reviewed-on: https://chromium-review.googlesource.com/1181935Reviewed-by: default avatarStephen McGruer <smcgruer@chromium.org>
Reviewed-by: default avatarYi Gu <yigu@chromium.org>
Commit-Queue: Majid Valipour <majidvp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585849}
parent 48d788fb
...@@ -50,8 +50,8 @@ class AnimationHostTest : public AnimationTimelinesTest { ...@@ -50,8 +50,8 @@ class AnimationHostTest : public AnimationTimelinesTest {
} }
void SetOutputState(base::TimeDelta local_time) { void SetOutputState(base::TimeDelta local_time) {
worklet_animation_impl_->SetOutputState( MutatorOutputState::AnimationState state(worklet_animation_id_, local_time);
{worklet_animation_id_, local_time}); worklet_animation_impl_->SetOutputState(state);
} }
scoped_refptr<WorkletAnimation> worklet_animation_; scoped_refptr<WorkletAnimation> worklet_animation_;
......
...@@ -88,4 +88,11 @@ std::unique_ptr<AnimationWorkletInput> MutatorInputState::TakeWorkletState( ...@@ -88,4 +88,11 @@ std::unique_ptr<AnimationWorkletInput> MutatorInputState::TakeWorkletState(
AnimationWorkletOutput::AnimationWorkletOutput() = default; AnimationWorkletOutput::AnimationWorkletOutput() = default;
AnimationWorkletOutput::~AnimationWorkletOutput() = default; AnimationWorkletOutput::~AnimationWorkletOutput() = default;
AnimationWorkletOutput::AnimationState::AnimationState(
WorkletAnimationId id,
base::Optional<base::TimeDelta> time)
: worklet_animation_id(id), local_time(time) {}
AnimationWorkletOutput::AnimationState::AnimationState(const AnimationState&) =
default;
} // namespace cc } // namespace cc
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CC_TREES_LAYER_TREE_MUTATOR_H_ #define CC_TREES_LAYER_TREE_MUTATOR_H_
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/optional.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "cc/cc_export.h" #include "cc/cc_export.h"
#include "cc/trees/animation_options.h" #include "cc/trees/animation_options.h"
...@@ -101,12 +102,16 @@ class CC_EXPORT MutatorInputState { ...@@ -101,12 +102,16 @@ class CC_EXPORT MutatorInputState {
struct CC_EXPORT AnimationWorkletOutput { struct CC_EXPORT AnimationWorkletOutput {
struct CC_EXPORT AnimationState { struct CC_EXPORT AnimationState {
AnimationState(WorkletAnimationId,
base::Optional<base::TimeDelta> local_time);
AnimationState(const AnimationState&);
WorkletAnimationId worklet_animation_id; WorkletAnimationId worklet_animation_id;
// The animator effect's local time. // The animator effect's local time.
// TODO(majidvp): This assumes each animator has a single output effect // TODO(majidvp): This assumes each animator has a single output effect
// which does not hold once we state support group effects. // which does not hold once we state support group effects.
// http://crbug.com/767043 // http://crbug.com/767043
base::TimeDelta local_time; base::Optional<base::TimeDelta> local_time;
}; };
AnimationWorkletOutput(); AnimationWorkletOutput();
......
<!DOCTYPE html>
<style>
.box {
width: 100px;
height: 100px;
background-color: #0f0;
transform: translateY(0px);
}
</style>
<div id="first" class="box"></div>
<div id="second" class="box"></div>
<!DOCTYPE html>
<style>
.box {
width: 100px;
height: 100px;
background-color: #0f0;
}
</style>
<div id="first" class="box"></div>
<div id="second" class="box"></div>
<script type="text/worklet">
registerAnimator("first_animator", class {
animate(currentTime, effect) {
// Unset effect.localTime is equivalent to 'undefined'
}
});
registerAnimator("second_animator", class {
animate(currentTime, effect) {
// explicitly set the localtime to undefined
effect.localTime = undefined;
}
});
</script>
<script src="resources/animation-worklet-tests.js"></script>
<script>
if (window.testRunner)
testRunner.waitUntilDone();
runInAnimationWorklet(
document.querySelector('script[type*=worklet]').textContent
).then(_ => {
for (let testcase of ['first', 'second']) {
const animation = new WorkletAnimation(`${testcase}_animator`,
new KeyframeEffect(document.getElementById(testcase),
[
{ transform: 'translateY(200px)' },
{ transform: 'translateY(0px)' }
], {
duration: 1000,
}
)
);
animation.play();
}
if (window.testRunner) {
waitTwoAnimationFrames(_ => {
testRunner.notifyDone();
});
}
});
</script>
...@@ -22,6 +22,7 @@ blink_modules_sources("animationworklet") { ...@@ -22,6 +22,7 @@ blink_modules_sources("animationworklet") {
"animator_definition.h", "animator_definition.h",
"css_animation_worklet.cc", "css_animation_worklet.cc",
"css_animation_worklet.h", "css_animation_worklet.h",
"effect_proxy.cc",
"effect_proxy.h", "effect_proxy.h",
"worklet_animation.cc", "worklet_animation.cc",
"worklet_animation.h", "worklet_animation.h",
......
...@@ -24,9 +24,9 @@ void UpdateAnimation(Animator* animator, ...@@ -24,9 +24,9 @@ void UpdateAnimation(Animator* animator,
WorkletAnimationId id, WorkletAnimationId id,
double current_time, double current_time,
CompositorMutatorOutputState* result) { CompositorMutatorOutputState* result) {
CompositorMutatorOutputState::AnimationState animation_output; CompositorMutatorOutputState::AnimationState animation_output(id,
base::nullopt);
if (animator->Animate(script_state, current_time, &animation_output)) { if (animator->Animate(script_state, current_time, &animation_output)) {
animation_output.worklet_animation_id = id;
result->animations.push_back(std::move(animation_output)); result->animations.push_back(std::move(animation_output));
} }
} }
......
...@@ -61,7 +61,7 @@ bool Animator::Animate(ScriptState* script_state, ...@@ -61,7 +61,7 @@ bool Animator::Animate(ScriptState* script_state,
if (block.HasCaught()) if (block.HasCaught())
return false; return false;
output->local_time = effect_->GetLocalTime(); output->local_time = effect_->local_time();
return true; return true;
} }
......
// 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/effect_proxy.h"
namespace blink {
EffectProxy::EffectProxy() : local_time_(base::nullopt) {}
void EffectProxy::setLocalTime(double time_ms, bool is_null) {
if (is_null) {
local_time_.reset();
return;
}
// Convert double to TimeDelta because cc/animation expects TimeDelta.
//
// Note on precision loss: TimeDelta has microseconds precision which is
// also the precision recommended by the web animation specification as well
// [1]. If the input time value has a bigger precision then the conversion
// causes precision loss. Doing the conversion here ensures that reading the
// value back provides the actual value we use in further computation which
// is the least surprising path.
// [1] https://drafts.csswg.org/web-animations/#precision-of-time-values
local_time_ = WTF::TimeDelta::FromMillisecondsD(time_ms);
}
double EffectProxy::localTime(bool& is_null) const {
is_null = !local_time_.has_value();
return local_time_.value_or(base::TimeDelta()).InMillisecondsF();
}
base::Optional<WTF::TimeDelta> EffectProxy::local_time() const {
return local_time_;
}
} // namespace blink
...@@ -17,27 +17,14 @@ class MODULES_EXPORT EffectProxy : public ScriptWrappable { ...@@ -17,27 +17,14 @@ class MODULES_EXPORT EffectProxy : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
EffectProxy() = default; EffectProxy();
void setLocalTime(double time_ms) { void setLocalTime(double time_ms, bool is_null);
// Convert double to TimeDelta because cc/animation expects TimeDelta. double localTime(bool& is_null) const;
// base::Optional<WTF::TimeDelta> local_time() const;
// Note on precision loss: TimeDelta has microseconds precision which is
// also the precision recommended by the web animation specification as well
// [1]. If the input time value has a bigger precision then the conversion
// causes precision loss. Doing the conversion here ensures that reading the
// value back provides the actual value we use in further computation which
// is the least surprising path.
// [1] https://drafts.csswg.org/web-animations/#precision-of-time-values
local_time_ = WTF::TimeDelta::FromMillisecondsD(time_ms);
}
double localTime() const { return local_time_.InMillisecondsF(); }
WTF::TimeDelta GetLocalTime() const { return local_time_; }
private: private:
WTF::TimeDelta local_time_; base::Optional<WTF::TimeDelta> local_time_;
}; };
} // namespace blink } // namespace blink
......
...@@ -8,5 +8,5 @@ ...@@ -8,5 +8,5 @@
Exposed=AnimationWorklet, Exposed=AnimationWorklet,
OriginTrialEnabled=AnimationWorklet OriginTrialEnabled=AnimationWorklet
] interface EffectProxy { ] interface EffectProxy {
attribute unrestricted double localTime; attribute unrestricted double? localTime;
}; };
\ No newline at end of file
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