| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "modules/compositorworker/WorkletAnimation.h" |
| 6 |
| 7 #include "core/animation/ElementAnimations.h" |
| 8 #include "core/animation/KeyframeEffectModel.h" |
| 9 #include "core/animation/ScrollTimeline.h" |
| 10 #include "core/animation/Timing.h" |
| 11 #include "core/dom/Node.h" |
| 12 #include "core/dom/NodeComputedStyle.h" |
| 13 #include "platform/animation/CompositorAnimationPlayer.h" |
| 14 #include "platform/wtf/text/WTFString.h" |
| 15 #include "public/platform/Platform.h" |
| 16 #include "public/platform/WebCompositorSupport.h" |
| 17 |
| 18 namespace blink { |
| 19 |
| 20 namespace { |
| 21 bool ValidateEffects(const HeapVector<Member<KeyframeEffectReadOnly>>& effects, |
| 22 String& error_string) { |
| 23 if (effects.IsEmpty()) { |
| 24 error_string = "Effects array must be non-empty"; |
| 25 return false; |
| 26 } |
| 27 |
| 28 Document& target_document = effects.at(0)->Target()->GetDocument(); |
| 29 for (const auto& effect : effects) { |
| 30 if (effect->Target()->GetDocument() != target_document) { |
| 31 error_string = "All effects must target elements in the same document"; |
| 32 return false; |
| 33 } |
| 34 } |
| 35 return true; |
| 36 } |
| 37 |
| 38 bool ValidateTimelines(HeapVector<DocumentTimelineOrScrollTimeline>& timelines, |
| 39 String& error_string) { |
| 40 if (timelines.IsEmpty()) { |
| 41 error_string = "Timelines array must be non-empty"; |
| 42 return false; |
| 43 } |
| 44 |
| 45 for (const auto& timeline : timelines) { |
| 46 if (timeline.isScrollTimeline()) { |
| 47 DoubleOrScrollTimelineAutoKeyword time_range; |
| 48 timeline.getAsScrollTimeline()->timeRange(time_range); |
| 49 if (time_range.isScrollTimelineAutoKeyword()) { |
| 50 error_string = "ScrollTimeline timeRange must have non-auto value"; |
| 51 return false; |
| 52 } |
| 53 } |
| 54 } |
| 55 return true; |
| 56 } |
| 57 |
| 58 String AnimationPlayStateToString( |
| 59 WorkletAnimation::AnimationPlayState play_state) { |
| 60 switch (play_state) { |
| 61 case WorkletAnimation::kIdle: |
| 62 return "idle"; |
| 63 case WorkletAnimation::kPending: |
| 64 return "pending"; |
| 65 case WorkletAnimation::kRunning: |
| 66 return "running"; |
| 67 default: |
| 68 NOTREACHED(); |
| 69 return ""; |
| 70 } |
| 71 } |
| 72 } // namespace |
| 73 |
| 74 WorkletAnimation* WorkletAnimation::Create( |
| 75 String animator_name, |
| 76 const HeapVector<Member<KeyframeEffectReadOnly>>& effects, |
| 77 HeapVector<DocumentTimelineOrScrollTimeline>& timelines, |
| 78 RefPtr<SerializedScriptValue> options, |
| 79 ExceptionState& exception_state) { |
| 80 String error_string; |
| 81 if (!ValidateEffects(effects, error_string)) { |
| 82 exception_state.ThrowDOMException(kNotSupportedError, error_string); |
| 83 return nullptr; |
| 84 } |
| 85 |
| 86 if (!ValidateTimelines(timelines, error_string)) { |
| 87 exception_state.ThrowDOMException(kNotSupportedError, error_string); |
| 88 return nullptr; |
| 89 } |
| 90 |
| 91 Document& document = effects.at(0)->Target()->GetDocument(); |
| 92 WorkletAnimation* animation = new WorkletAnimation( |
| 93 animator_name, document, effects, timelines, std::move(options)); |
| 94 document.Timeline().CompositorTimeline()->PlayerAttached(*animation); |
| 95 |
| 96 return animation; |
| 97 } |
| 98 |
| 99 WorkletAnimation::WorkletAnimation( |
| 100 String animator_name, |
| 101 Document& document, |
| 102 const HeapVector<Member<KeyframeEffectReadOnly>>& effects, |
| 103 HeapVector<DocumentTimelineOrScrollTimeline>& timelines, |
| 104 RefPtr<SerializedScriptValue> options) |
| 105 : animator_name_(animator_name), |
| 106 document_(document), |
| 107 effects_(effects), |
| 108 timelines_(timelines), |
| 109 options_(std::move(options)) { |
| 110 DCHECK(Platform::Current()->IsThreadedAnimationEnabled()); |
| 111 DCHECK(Platform::Current()->CompositorSupport()); |
| 112 compositor_player_ = CompositorAnimationPlayerHolder::Create(this); |
| 113 DCHECK(compositor_player_); |
| 114 } |
| 115 |
| 116 String WorkletAnimation::playState() { |
| 117 return AnimationPlayStateToString(play_state_); |
| 118 } |
| 119 |
| 120 void WorkletAnimation::play() { |
| 121 // TODO(smcgruer): Should this set NeedsCompositingUpdate? |
| 122 document_->GetWorkletAnimationController().AttachAnimation(*this); |
| 123 play_state_ = kPending; |
| 124 } |
| 125 |
| 126 void WorkletAnimation::cancel() { |
| 127 document_->GetWorkletAnimationController().DetachAnimation(*this); |
| 128 play_state_ = kIdle; |
| 129 } |
| 130 |
| 131 bool WorkletAnimation::StartOnCompositor() { |
| 132 int group = 0; |
| 133 double start_time = 0; |
| 134 double current_time = 0; |
| 135 double animation_playback_rate = 1; |
| 136 Element& target = *effects_.at(0)->Target(); |
| 137 ToKeyframeEffectModelBase(effects_.at(0)->Model()) |
| 138 ->SnapshotAllCompositorKeyframes(target, target.ComputedStyleRef(), |
| 139 target.ParentComputedStyle()); |
| 140 bool success = |
| 141 effects_.at(0) |
| 142 ->CheckCanStartAnimationOnCompositor(animation_playback_rate) |
| 143 .Ok(); |
| 144 if (success) { |
| 145 effects_.at(0)->StartAnimationOnCompositor(group, start_time, current_time, |
| 146 animation_playback_rate, |
| 147 compositor_player_->Player()); |
| 148 } |
| 149 play_state_ = success ? kRunning : kIdle; |
| 150 return success; |
| 151 } |
| 152 |
| 153 void WorkletAnimation::Dispose() { |
| 154 document_->Timeline().CompositorTimeline()->PlayerDestroyed(*this); |
| 155 compositor_player_->Detach(); |
| 156 compositor_player_ = nullptr; |
| 157 } |
| 158 |
| 159 DEFINE_TRACE(WorkletAnimation) { |
| 160 visitor->Trace(document_); |
| 161 visitor->Trace(effects_); |
| 162 visitor->Trace(timelines_); |
| 163 visitor->Trace(compositor_player_); |
| 164 WorkletAnimationBase::Trace(visitor); |
| 165 } |
| 166 |
| 167 WorkletAnimation::CompositorAnimationPlayerHolder* |
| 168 WorkletAnimation::CompositorAnimationPlayerHolder::Create( |
| 169 WorkletAnimation* animation) { |
| 170 return new CompositorAnimationPlayerHolder(animation); |
| 171 } |
| 172 |
| 173 WorkletAnimation::CompositorAnimationPlayerHolder:: |
| 174 CompositorAnimationPlayerHolder(WorkletAnimation* animation) |
| 175 : animation_(animation) { |
| 176 compositor_player_ = CompositorAnimationPlayer::Create(); |
| 177 compositor_player_->SetAnimationDelegate(animation_); |
| 178 } |
| 179 |
| 180 void WorkletAnimation::CompositorAnimationPlayerHolder::Dispose() { |
| 181 if (!animation_) |
| 182 return; |
| 183 animation_->Dispose(); |
| 184 DCHECK(!animation_); |
| 185 DCHECK(!compositor_player_); |
| 186 } |
| 187 |
| 188 void WorkletAnimation::CompositorAnimationPlayerHolder::Detach() { |
| 189 compositor_player_->SetAnimationDelegate(nullptr); |
| 190 animation_ = nullptr; |
| 191 compositor_player_.reset(); |
| 192 } |
| 193 |
| 194 } // namespace blink |
| OLD | NEW |