| Index: third_party/WebKit/Source/modules/compositorworker/WorkletAnimation.cpp
|
| diff --git a/third_party/WebKit/Source/modules/compositorworker/WorkletAnimation.cpp b/third_party/WebKit/Source/modules/compositorworker/WorkletAnimation.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..134d221eeeaa294700257de5d83f1956cfb4686d
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/modules/compositorworker/WorkletAnimation.cpp
|
| @@ -0,0 +1,194 @@
|
| +// 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 "modules/compositorworker/WorkletAnimation.h"
|
| +
|
| +#include "core/animation/ElementAnimations.h"
|
| +#include "core/animation/KeyframeEffectModel.h"
|
| +#include "core/animation/ScrollTimeline.h"
|
| +#include "core/animation/Timing.h"
|
| +#include "core/dom/Node.h"
|
| +#include "core/dom/NodeComputedStyle.h"
|
| +#include "platform/animation/CompositorAnimationPlayer.h"
|
| +#include "platform/wtf/text/WTFString.h"
|
| +#include "public/platform/Platform.h"
|
| +#include "public/platform/WebCompositorSupport.h"
|
| +
|
| +namespace blink {
|
| +
|
| +namespace {
|
| +bool ValidateEffects(const HeapVector<Member<KeyframeEffectReadOnly>>& effects,
|
| + String& error_string) {
|
| + if (effects.IsEmpty()) {
|
| + error_string = "Effects array must be non-empty";
|
| + return false;
|
| + }
|
| +
|
| + Document& target_document = effects.at(0)->Target()->GetDocument();
|
| + for (const auto& effect : effects) {
|
| + if (effect->Target()->GetDocument() != target_document) {
|
| + error_string = "All effects must target elements in the same document";
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool ValidateTimelines(HeapVector<DocumentTimelineOrScrollTimeline>& timelines,
|
| + String& error_string) {
|
| + if (timelines.IsEmpty()) {
|
| + error_string = "Timelines array must be non-empty";
|
| + return false;
|
| + }
|
| +
|
| + for (const auto& timeline : timelines) {
|
| + if (timeline.isScrollTimeline()) {
|
| + DoubleOrScrollTimelineAutoKeyword time_range;
|
| + timeline.getAsScrollTimeline()->timeRange(time_range);
|
| + if (time_range.isScrollTimelineAutoKeyword()) {
|
| + error_string = "ScrollTimeline timeRange must have non-auto value";
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +String AnimationPlayStateToString(
|
| + WorkletAnimation::AnimationPlayState play_state) {
|
| + switch (play_state) {
|
| + case WorkletAnimation::kIdle:
|
| + return "idle";
|
| + case WorkletAnimation::kPending:
|
| + return "pending";
|
| + case WorkletAnimation::kRunning:
|
| + return "running";
|
| + default:
|
| + NOTREACHED();
|
| + return "";
|
| + }
|
| +}
|
| +} // namespace
|
| +
|
| +WorkletAnimation* WorkletAnimation::Create(
|
| + String animator_name,
|
| + const HeapVector<Member<KeyframeEffectReadOnly>>& effects,
|
| + HeapVector<DocumentTimelineOrScrollTimeline>& timelines,
|
| + RefPtr<SerializedScriptValue> options,
|
| + ExceptionState& exception_state) {
|
| + String error_string;
|
| + if (!ValidateEffects(effects, error_string)) {
|
| + exception_state.ThrowDOMException(kNotSupportedError, error_string);
|
| + return nullptr;
|
| + }
|
| +
|
| + if (!ValidateTimelines(timelines, error_string)) {
|
| + exception_state.ThrowDOMException(kNotSupportedError, error_string);
|
| + return nullptr;
|
| + }
|
| +
|
| + Document& document = effects.at(0)->Target()->GetDocument();
|
| + WorkletAnimation* animation = new WorkletAnimation(
|
| + animator_name, document, effects, timelines, std::move(options));
|
| + document.Timeline().CompositorTimeline()->PlayerAttached(*animation);
|
| +
|
| + return animation;
|
| +}
|
| +
|
| +WorkletAnimation::WorkletAnimation(
|
| + String animator_name,
|
| + Document& document,
|
| + const HeapVector<Member<KeyframeEffectReadOnly>>& effects,
|
| + HeapVector<DocumentTimelineOrScrollTimeline>& timelines,
|
| + RefPtr<SerializedScriptValue> options)
|
| + : animator_name_(animator_name),
|
| + document_(document),
|
| + effects_(effects),
|
| + timelines_(timelines),
|
| + options_(std::move(options)) {
|
| + DCHECK(Platform::Current()->IsThreadedAnimationEnabled());
|
| + DCHECK(Platform::Current()->CompositorSupport());
|
| + compositor_player_ = CompositorAnimationPlayerHolder::Create(this);
|
| + DCHECK(compositor_player_);
|
| +}
|
| +
|
| +String WorkletAnimation::playState() {
|
| + return AnimationPlayStateToString(play_state_);
|
| +}
|
| +
|
| +void WorkletAnimation::play() {
|
| + // TODO(smcgruer): Should this set NeedsCompositingUpdate?
|
| + document_->GetWorkletAnimationController().AttachAnimation(*this);
|
| + play_state_ = kPending;
|
| +}
|
| +
|
| +void WorkletAnimation::cancel() {
|
| + document_->GetWorkletAnimationController().DetachAnimation(*this);
|
| + play_state_ = kIdle;
|
| +}
|
| +
|
| +bool WorkletAnimation::StartOnCompositor() {
|
| + int group = 0;
|
| + double start_time = 0;
|
| + double current_time = 0;
|
| + double animation_playback_rate = 1;
|
| + Element& target = *effects_.at(0)->Target();
|
| + ToKeyframeEffectModelBase(effects_.at(0)->Model())
|
| + ->SnapshotAllCompositorKeyframes(target, target.ComputedStyleRef(),
|
| + target.ParentComputedStyle());
|
| + bool success =
|
| + effects_.at(0)
|
| + ->CheckCanStartAnimationOnCompositor(animation_playback_rate)
|
| + .Ok();
|
| + if (success) {
|
| + effects_.at(0)->StartAnimationOnCompositor(group, start_time, current_time,
|
| + animation_playback_rate,
|
| + compositor_player_->Player());
|
| + }
|
| + play_state_ = success ? kRunning : kIdle;
|
| + return success;
|
| +}
|
| +
|
| +void WorkletAnimation::Dispose() {
|
| + document_->Timeline().CompositorTimeline()->PlayerDestroyed(*this);
|
| + compositor_player_->Detach();
|
| + compositor_player_ = nullptr;
|
| +}
|
| +
|
| +DEFINE_TRACE(WorkletAnimation) {
|
| + visitor->Trace(document_);
|
| + visitor->Trace(effects_);
|
| + visitor->Trace(timelines_);
|
| + visitor->Trace(compositor_player_);
|
| + WorkletAnimationBase::Trace(visitor);
|
| +}
|
| +
|
| +WorkletAnimation::CompositorAnimationPlayerHolder*
|
| +WorkletAnimation::CompositorAnimationPlayerHolder::Create(
|
| + WorkletAnimation* animation) {
|
| + return new CompositorAnimationPlayerHolder(animation);
|
| +}
|
| +
|
| +WorkletAnimation::CompositorAnimationPlayerHolder::
|
| + CompositorAnimationPlayerHolder(WorkletAnimation* animation)
|
| + : animation_(animation) {
|
| + compositor_player_ = CompositorAnimationPlayer::Create();
|
| + compositor_player_->SetAnimationDelegate(animation_);
|
| +}
|
| +
|
| +void WorkletAnimation::CompositorAnimationPlayerHolder::Dispose() {
|
| + if (!animation_)
|
| + return;
|
| + animation_->Dispose();
|
| + DCHECK(!animation_);
|
| + DCHECK(!compositor_player_);
|
| +}
|
| +
|
| +void WorkletAnimation::CompositorAnimationPlayerHolder::Detach() {
|
| + compositor_player_->SetAnimationDelegate(nullptr);
|
| + animation_ = nullptr;
|
| + compositor_player_.reset();
|
| +}
|
| +
|
| +} // namespace blink
|
|
|