Chromium Code Reviews| 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..c59d9acbc17ed619dc2501ceb42724243bf3c4d4 |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/modules/compositorworker/WorkletAnimation.cpp |
| @@ -0,0 +1,201 @@ |
| +// 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/DocumentTimeline.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) { |
|
alancutter (OOO until 2018)
2017/06/26 11:57:02
Blink style is to use references instead of pointe
smcgruer
2017/06/26 21:14:08
Done.
|
| + 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)); |
| + animation->AttachCompositorTimeline(); |
| + |
| + 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? |
|
flackr
2017/06/19 20:35:33
The WorkletAnimationController should I think.
smcgruer
2017/07/24 14:48:58
Ack added TODO on the WorkletAnimationController.
|
| + 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(); |
| + static_cast<KeyframeEffectModelBase*>(effects_.at(0)->Model()) |
|
alancutter (OOO until 2018)
2017/06/26 11:57:02
Use ToKeyframeEffectModelBase().
smcgruer
2017/06/26 21:14:08
Done.
|
| + ->SnapshotAllCompositorKeyframes(target, target.ComputedStyleRef(), |
| + target.ParentComputedStyle()); |
| + bool success = effects_.at(0)->MaybeStartAnimationOnCompositor( |
|
alancutter (OOO until 2018)
2017/06/26 11:57:02
MaybeStartAnimationOnCompositor() is now CanStartA
smcgruer
2017/06/26 21:14:08
Ack; I see that there is now a new cl to make them
smcgruer
2017/06/27 18:02:43
Done.
|
| + group, start_time, current_time, animation_playback_rate, |
| + compositor_player_->Player()); |
|
flackr
2017/06/19 20:35:33
I'm a bit confused about what this is doing. We're
smcgruer
2017/06/26 21:14:08
As far as I understand it, a lot of plumbing is st
smcgruer
2017/06/27 18:02:43
A question was raised today as to why this doesn't
flackr
2017/07/19 19:23:48
I think we should just assume success (or failure?
smcgruer
2017/07/24 14:48:58
Done.
|
| + play_state_ = success ? kRunning : kIdle; |
| + return success; |
| +} |
| + |
| +void WorkletAnimation::AttachCompositorTimeline() { |
| + document_->Timeline().CompositorTimeline()->PlayerAttached(*this); |
| +} |
| + |
| +void WorkletAnimation::DetachCompositorTimeline() { |
| + document_->Timeline().CompositorTimeline()->PlayerDestroyed(*this); |
| +} |
|
alancutter (OOO until 2018)
2017/06/26 11:57:02
I'm not sure we need these two methods given they'
smcgruer
2017/06/26 21:14:08
Done.
|
| + |
| +void WorkletAnimation::Dispose() { |
| + DetachCompositorTimeline(); |
| + compositor_player_->Detach(); |
| + compositor_player_ = nullptr; |
| +} |
| + |
| +void WorkletAnimation::SetEffectInheritedTimeForTesting( |
| + Member<KeyframeEffectReadOnly> effect, |
| + double inherited_time) {} |
| + |
| +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 |