blob: 4b73d0a4fd9c8e559d0bb8ec3afbbaba8438166f [file] [log] [blame]
// Copyright 2017 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/core/animation/worklet_animation_controller.h"
#include "third_party/blink/renderer/core/animation/document_timeline.h"
#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
#include "third_party/blink/renderer/core/animation/worklet_animation_base.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
#include "third_party/blink/renderer/platform/graphics/main_thread_mutator_client.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
namespace {
int GetId(const WorkletAnimationBase& animation) {
return animation.GetWorkletAnimationId().animation_id;
}
} // namespace
WorkletAnimationController::WorkletAnimationController(Document* document)
: document_(document) {}
WorkletAnimationController::~WorkletAnimationController() = default;
void WorkletAnimationController::AttachAnimation(
WorkletAnimationBase& animation) {
DCHECK(IsMainThread());
DCHECK(!pending_animations_.Contains(&animation));
DCHECK(!animations_.Contains(GetId(animation)));
pending_animations_.insert(&animation);
DCHECK_EQ(document_, animation.GetDocument());
if (LocalFrameView* view = animation.GetDocument()->View())
view->ScheduleAnimation();
}
void WorkletAnimationController::DetachAnimation(
WorkletAnimationBase& animation) {
DCHECK(IsMainThread());
pending_animations_.erase(&animation);
animations_.erase(GetId(animation));
}
void WorkletAnimationController::InvalidateAnimation(
WorkletAnimationBase& animation) {
DCHECK(IsMainThread());
pending_animations_.insert(&animation);
if (LocalFrameView* view = animation.GetDocument()->View())
view->ScheduleAnimation();
}
void WorkletAnimationController::UpdateAnimationStates() {
DCHECK(IsMainThread());
HeapHashSet<Member<WorkletAnimationBase>> animations;
animations.swap(pending_animations_);
for (const auto& animation : animations) {
animation->UpdateCompositingState();
if (animation->IsActiveAnimation())
animations_.insert(GetId(*animation), animation);
}
if (!animations_.IsEmpty() && document_->View())
document_->View()->ScheduleAnimation();
}
void WorkletAnimationController::UpdateAnimationTimings(
TimingUpdateReason reason) {
DCHECK(IsMainThread());
// Worklet animations inherited time values are only ever updated once per
// animation frame. This means the inherited time does not change outside of
// the frame so return early in the on-demand case.
if (reason == kTimingUpdateOnDemand)
return;
MutateAnimations();
ApplyAnimationTimings(reason);
}
void WorkletAnimationController::ScrollSourceCompositingStateChanged(
Node* node) {
DCHECK(ScrollTimeline::HasActiveScrollTimeline(node));
for (const auto& animation : animations_.Values()) {
if (animation->GetTimeline()->IsScrollTimeline() &&
ToScrollTimeline(animation->GetTimeline())->scrollSource() == node) {
InvalidateAnimation(*animation);
}
}
}
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
WorkletAnimationController::EnsureMainThreadMutatorDispatcher(
scoped_refptr<base::SingleThreadTaskRunner>* mutator_task_runner) {
base::WeakPtr<AnimationWorkletMutatorDispatcherImpl> mutator_dispatcher;
if (!mutator_task_runner_) {
main_thread_mutator_client_ =
AnimationWorkletMutatorDispatcherImpl::CreateMainThreadClient(
&mutator_dispatcher, &mutator_task_runner_);
main_thread_mutator_client_->SetDelegate(this);
}
DCHECK(main_thread_mutator_client_);
DCHECK(mutator_task_runner_);
DCHECK(mutator_dispatcher);
*mutator_task_runner = mutator_task_runner_;
return mutator_dispatcher;
}
// TODO(yigu): Currently one animator name is synced back per registration.
// Eventually all registered names should be synced in batch once a module
// completes its loading in the worklet scope. https://crbug.com/920722.
void WorkletAnimationController::SynchronizeAnimatorName(
const String& animator_name) {
animator_names_.insert(animator_name);
}
bool WorkletAnimationController::IsAnimatorRegistered(
const String& animator_name) const {
return animator_names_.Contains(animator_name);
}
void WorkletAnimationController::SetMutationUpdate(
std::unique_ptr<AnimationWorkletOutput> output_state) {
if (!output_state)
return;
for (auto& to_update : output_state->animations) {
int id = to_update.worklet_animation_id.animation_id;
if (auto* animation = animations_.at(id))
animation->SetOutputState(to_update);
}
}
void WorkletAnimationController::MutateAnimations() {
if (!main_thread_mutator_client_)
return;
main_thread_mutator_client_->Mutator()->MutateSynchronously(
CollectAnimationStates());
}
std::unique_ptr<AnimationWorkletDispatcherInput>
WorkletAnimationController::CollectAnimationStates() {
std::unique_ptr<AnimationWorkletDispatcherInput> result =
std::make_unique<AnimationWorkletDispatcherInput>();
for (auto& animation : animations_.Values())
animation->UpdateInputState(result.get());
return result;
}
void WorkletAnimationController::ApplyAnimationTimings(
TimingUpdateReason reason) {
for (const auto& animation : animations_.Values())
animation->Update(reason);
}
void WorkletAnimationController::Trace(blink::Visitor* visitor) {
visitor->Trace(pending_animations_);
visitor->Trace(animations_);
visitor->Trace(document_);
}
} // namespace blink