| // Copyright 2017 The Chromium Authors |
| // 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/animator.h" |
| |
| #include "third_party/blink/renderer/bindings/modules/v8/v8_animate_callback.h" |
| #include "third_party/blink/renderer/bindings/modules/v8/v8_state_callback.h" |
| #include "third_party/blink/renderer/bindings/modules/v8/v8_union_workletanimationeffect_workletgroupeffect.h" |
| #include "third_party/blink/renderer/modules/animationworklet/animator_definition.h" |
| #include "third_party/blink/renderer/platform/bindings/exception_state.h" |
| #include "third_party/blink/renderer/platform/bindings/v8_binding.h" |
| #include "v8/include/v8.h" |
| |
| namespace blink { |
| |
| Animator::Animator(v8::Isolate* isolate, |
| AnimatorDefinition* definition, |
| v8::Local<v8::Value> instance, |
| const String& name, |
| WorkletAnimationOptions options, |
| const Vector<absl::optional<base::TimeDelta>>& local_times, |
| const Vector<Timing>& timings, |
| const Vector<Timing::NormalizedTiming>& normalized_timings) |
| : definition_(definition), |
| instance_(isolate, instance), |
| name_(name), |
| options_(options), |
| group_effect_( |
| MakeGarbageCollected<WorkletGroupEffect>(local_times, |
| timings, |
| normalized_timings)) { |
| DCHECK_GE(local_times.size(), 1u); |
| } |
| |
| Animator::~Animator() = default; |
| |
| void Animator::Trace(Visitor* visitor) const { |
| visitor->Trace(definition_); |
| visitor->Trace(instance_); |
| visitor->Trace(group_effect_); |
| } |
| |
| bool Animator::Animate( |
| v8::Isolate* isolate, |
| double current_time, |
| AnimationWorkletDispatcherOutput::AnimationState* output) { |
| DCHECK(!std::isnan(current_time)); |
| |
| v8::Local<v8::Value> instance = instance_.Get(isolate); |
| if (IsUndefinedOrNull(instance)) |
| return false; |
| |
| V8UnionWorkletAnimationEffectOrWorkletGroupEffect* effect = nullptr; |
| if (group_effect_->getChildren().size() == 1) { |
| effect = |
| MakeGarbageCollected<V8UnionWorkletAnimationEffectOrWorkletGroupEffect>( |
| group_effect_->getChildren()[0]); |
| } else { |
| effect = |
| MakeGarbageCollected<V8UnionWorkletAnimationEffectOrWorkletGroupEffect>( |
| group_effect_); |
| } |
| |
| v8::TryCatch try_catch(isolate); |
| try_catch.SetVerbose(true); |
| if (definition_->AnimateFunction() |
| ->Invoke(instance, current_time, effect) |
| .IsNothing()) { |
| return false; |
| } |
| |
| GetLocalTimes(output->local_times); |
| return true; |
| } |
| |
| Vector<Timing> Animator::GetTimings() const { |
| Vector<Timing> timings; |
| timings.ReserveInitialCapacity(group_effect_->getChildren().size()); |
| for (const auto& effect : group_effect_->getChildren()) { |
| timings.push_back(effect->SpecifiedTiming()); |
| } |
| return timings; |
| } |
| |
| Vector<Timing::NormalizedTiming> Animator::GetNormalizedTimings() const { |
| Vector<Timing::NormalizedTiming> normalized_timings; |
| normalized_timings.ReserveInitialCapacity( |
| group_effect_->getChildren().size()); |
| for (const auto& effect : group_effect_->getChildren()) { |
| normalized_timings.push_back(effect->NormalizedTiming()); |
| } |
| return normalized_timings; |
| } |
| |
| bool Animator::IsStateful() const { |
| return definition_->IsStateful(); |
| } |
| |
| v8::Local<v8::Value> Animator::State(v8::Isolate* isolate, |
| ExceptionState& exception_state) { |
| if (!IsStateful()) |
| return v8::Undefined(isolate); |
| |
| v8::Local<v8::Value> instance = instance_.Get(isolate); |
| DCHECK(!IsUndefinedOrNull(instance)); |
| |
| v8::TryCatch try_catch(isolate); |
| v8::Maybe<ScriptValue> state = definition_->StateFunction()->Invoke(instance); |
| if (try_catch.HasCaught()) { |
| exception_state.RethrowV8Exception(try_catch.Exception()); |
| return v8::Undefined(isolate); |
| } |
| return state.ToChecked().V8Value(); |
| } |
| |
| } // namespace blink |