1 // Copyright 2014 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 "third_party/blink/renderer/core/scroll/scroll_animator_compositor_coordinator.h"
6 
7 #include <memory>
8 
9 #include "cc/animation/animation_host.h"
10 #include "cc/animation/scroll_offset_animation_curve.h"
11 #include "cc/layers/picture_layer.h"
12 #include "third_party/blink/public/platform/platform.h"
13 #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
14 #include "third_party/blink/renderer/platform/animation/compositor_animation.h"
15 #include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h"
16 #include "third_party/blink/renderer/platform/animation/compositor_keyframe_model.h"
17 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
18 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
19 
20 namespace blink {
21 
ScrollAnimatorCompositorCoordinator()22 ScrollAnimatorCompositorCoordinator::ScrollAnimatorCompositorCoordinator()
23     : element_id_(),
24       run_state_(RunState::kIdle),
25       impl_only_animation_takeover_(false),
26       compositor_animation_id_(0),
27       compositor_animation_group_id_(0) {
28   compositor_animation_ = CompositorAnimation::Create();
29   DCHECK(compositor_animation_);
30   compositor_animation_->SetAnimationDelegate(this);
31 }
32 
33 ScrollAnimatorCompositorCoordinator::~ScrollAnimatorCompositorCoordinator() =
34     default;
35 
Dispose()36 void ScrollAnimatorCompositorCoordinator::Dispose() {
37   compositor_animation_->SetAnimationDelegate(nullptr);
38   compositor_animation_.reset();
39 }
40 
ResetAnimationState()41 void ScrollAnimatorCompositorCoordinator::ResetAnimationState() {
42   run_state_ = RunState::kIdle;
43   RemoveAnimation();
44 }
45 
HasAnimationThatRequiresService() const46 bool ScrollAnimatorCompositorCoordinator::HasAnimationThatRequiresService()
47     const {
48   if (HasImplOnlyAnimationUpdate())
49     return true;
50 
51   switch (run_state_) {
52     case RunState::kIdle:
53     case RunState::kRunningOnCompositor:
54       return false;
55     case RunState::kWaitingToCancelOnCompositorButNewScroll:
56     case RunState::kPostAnimationCleanup:
57     case RunState::kWaitingToSendToCompositor:
58     case RunState::kRunningOnMainThread:
59     case RunState::kRunningOnCompositorButNeedsUpdate:
60     case RunState::kRunningOnCompositorButNeedsTakeover:
61     case RunState::kRunningOnCompositorButNeedsAdjustment:
62     case RunState::kWaitingToCancelOnCompositor:
63       return true;
64   }
65   NOTREACHED();
66   return false;
67 }
68 
AddAnimation(std::unique_ptr<CompositorKeyframeModel> keyframe_model)69 bool ScrollAnimatorCompositorCoordinator::AddAnimation(
70     std::unique_ptr<CompositorKeyframeModel> keyframe_model) {
71   RemoveAnimation();
72   if (compositor_animation_->IsElementAttached()) {
73     compositor_animation_id_ = keyframe_model->Id();
74     compositor_animation_group_id_ = keyframe_model->Group();
75     compositor_animation_->AddKeyframeModel(std::move(keyframe_model));
76     return true;
77   }
78   return false;
79 }
80 
RemoveAnimation()81 void ScrollAnimatorCompositorCoordinator::RemoveAnimation() {
82   if (compositor_animation_id_) {
83     compositor_animation_->RemoveKeyframeModel(compositor_animation_id_);
84     compositor_animation_id_ = 0;
85     compositor_animation_group_id_ = 0;
86   }
87 }
88 
AbortAnimation()89 void ScrollAnimatorCompositorCoordinator::AbortAnimation() {
90   if (compositor_animation_id_) {
91     compositor_animation_->AbortKeyframeModel(compositor_animation_id_);
92     compositor_animation_id_ = 0;
93     compositor_animation_group_id_ = 0;
94   }
95 }
96 
CancelAnimation()97 void ScrollAnimatorCompositorCoordinator::CancelAnimation() {
98   switch (run_state_) {
99     case RunState::kIdle:
100     case RunState::kWaitingToCancelOnCompositor:
101     case RunState::kPostAnimationCleanup:
102       break;
103     case RunState::kWaitingToSendToCompositor:
104       if (compositor_animation_id_) {
105         // We still have a previous animation running on the compositor.
106         run_state_ = RunState::kWaitingToCancelOnCompositor;
107       } else {
108         ResetAnimationState();
109       }
110       break;
111     case RunState::kRunningOnMainThread:
112       run_state_ = RunState::kPostAnimationCleanup;
113       break;
114     case RunState::kWaitingToCancelOnCompositorButNewScroll:
115     case RunState::kRunningOnCompositorButNeedsAdjustment:
116     case RunState::kRunningOnCompositorButNeedsTakeover:
117     case RunState::kRunningOnCompositorButNeedsUpdate:
118     case RunState::kRunningOnCompositor:
119       run_state_ = RunState::kWaitingToCancelOnCompositor;
120 
121       // Get serviced the next time compositor updates are allowed.
122       GetScrollableArea()->RegisterForAnimation();
123   }
124 }
125 
TakeOverCompositorAnimation()126 void ScrollAnimatorCompositorCoordinator::TakeOverCompositorAnimation() {
127   switch (run_state_) {
128     case RunState::kIdle:
129       TakeOverImplOnlyScrollOffsetAnimation();
130       break;
131     case RunState::kWaitingToCancelOnCompositor:
132     case RunState::kWaitingToCancelOnCompositorButNewScroll:
133     case RunState::kPostAnimationCleanup:
134     case RunState::kRunningOnCompositorButNeedsTakeover:
135     case RunState::kWaitingToSendToCompositor:
136     case RunState::kRunningOnMainThread:
137       break;
138     case RunState::kRunningOnCompositorButNeedsAdjustment:
139     case RunState::kRunningOnCompositorButNeedsUpdate:
140     case RunState::kRunningOnCompositor:
141       // We call abortAnimation that makes changes to the animation running on
142       // the compositor. Thus, this function should only be called when in
143       // CompositingClean state.
144       AbortAnimation();
145 
146       run_state_ = RunState::kRunningOnCompositorButNeedsTakeover;
147 
148       // Get serviced the next time compositor updates are allowed.
149       GetScrollableArea()->RegisterForAnimation();
150   }
151 }
152 
CompositorAnimationFinished(int group_id)153 void ScrollAnimatorCompositorCoordinator::CompositorAnimationFinished(
154     int group_id) {
155   if (compositor_animation_group_id_ != group_id)
156     return;
157 
158   // TODO(crbug.com/992437) We should not need to remove completed animations
159   // however they are sometimes accidentally restarted if we don't explicitly
160   // remove them.
161   RemoveAnimation();
162 
163   switch (run_state_) {
164     case RunState::kIdle:
165     case RunState::kPostAnimationCleanup:
166     case RunState::kRunningOnMainThread:
167       NOTREACHED();
168       break;
169     case RunState::kWaitingToSendToCompositor:
170     case RunState::kWaitingToCancelOnCompositorButNewScroll:
171       break;
172     case RunState::kRunningOnCompositor:
173     case RunState::kRunningOnCompositorButNeedsAdjustment:
174     case RunState::kRunningOnCompositorButNeedsUpdate:
175     case RunState::kRunningOnCompositorButNeedsTakeover:
176     case RunState::kWaitingToCancelOnCompositor:
177       run_state_ = RunState::kPostAnimationCleanup;
178       // Get serviced the next time compositor updates are allowed.
179       if (GetScrollableArea())
180         GetScrollableArea()->RegisterForAnimation();
181       else
182         ResetAnimationState();
183   }
184 }
185 
ReattachCompositorAnimationIfNeeded(CompositorAnimationTimeline * timeline)186 bool ScrollAnimatorCompositorCoordinator::ReattachCompositorAnimationIfNeeded(
187     CompositorAnimationTimeline* timeline) {
188   bool reattached = false;
189   CompositorElementId element_id = GetScrollElementId();
190   DCHECK(element_id || (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
191                         !GetScrollableArea()->LayerForScrolling()));
192 
193   if (element_id != element_id_) {
194     if (compositor_animation_ && timeline) {
195       // Detach from old layer (if any).
196       if (element_id_) {
197         if (compositor_animation_->IsElementAttached())
198           compositor_animation_->DetachElement();
199         timeline->AnimationDestroyed(*this);
200       }
201       // Attach to new layer (if any).
202       if (element_id) {
203         DCHECK(!compositor_animation_->IsElementAttached());
204         timeline->AnimationAttached(*this);
205         compositor_animation_->AttachElement(element_id);
206         reattached = true;
207       }
208       element_id_ = element_id;
209     }
210   }
211 
212   return reattached;
213 }
214 
NotifyAnimationStarted(double monotonic_time,int group)215 void ScrollAnimatorCompositorCoordinator::NotifyAnimationStarted(
216     double monotonic_time,
217     int group) {}
218 
NotifyAnimationFinished(double monotonic_time,int group)219 void ScrollAnimatorCompositorCoordinator::NotifyAnimationFinished(
220     double monotonic_time,
221     int group) {
222   NotifyCompositorAnimationFinished(group);
223 }
224 
NotifyAnimationAborted(double monotonic_time,int group)225 void ScrollAnimatorCompositorCoordinator::NotifyAnimationAborted(
226     double monotonic_time,
227     int group) {
228   // An animation aborted by the compositor is treated as a finished
229   // animation.
230   NotifyCompositorAnimationFinished(group);
231 }
232 
233 CompositorAnimation*
GetCompositorAnimation() const234 ScrollAnimatorCompositorCoordinator::GetCompositorAnimation() const {
235   return compositor_animation_.get();
236 }
237 
CompositorOffsetFromBlinkOffset(ScrollOffset offset)238 FloatPoint ScrollAnimatorCompositorCoordinator::CompositorOffsetFromBlinkOffset(
239     ScrollOffset offset) {
240   return GetScrollableArea()->ScrollOffsetToPosition(offset);
241 }
242 
243 ScrollOffset
BlinkOffsetFromCompositorOffset(FloatPoint position)244 ScrollAnimatorCompositorCoordinator::BlinkOffsetFromCompositorOffset(
245     FloatPoint position) {
246   return GetScrollableArea()->ScrollPositionToOffset(position);
247 }
248 
HasImplOnlyAnimationUpdate() const249 bool ScrollAnimatorCompositorCoordinator::HasImplOnlyAnimationUpdate() const {
250   return !impl_only_animation_adjustment_.IsZero() ||
251          impl_only_animation_takeover_;
252 }
253 
GetScrollElementId() const254 CompositorElementId ScrollAnimatorCompositorCoordinator::GetScrollElementId()
255     const {
256   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
257     return GetScrollableArea()->GetScrollElementId();
258 
259   cc::Layer* layer = GetScrollableArea()->LayerForScrolling();
260   return layer ? layer->element_id() : CompositorElementId();
261 }
262 
UpdateImplOnlyCompositorAnimations()263 void ScrollAnimatorCompositorCoordinator::UpdateImplOnlyCompositorAnimations() {
264   if (!HasImplOnlyAnimationUpdate())
265     return;
266 
267   cc::AnimationHost* host = GetScrollableArea()->GetCompositorAnimationHost();
268   CompositorElementId element_id = GetScrollElementId();
269   if (host && element_id) {
270     if (!impl_only_animation_adjustment_.IsZero()) {
271       host->scroll_offset_animations().AddAdjustmentUpdate(
272           element_id, gfx::Vector2dF(impl_only_animation_adjustment_.Width(),
273                                      impl_only_animation_adjustment_.Height()));
274     }
275     if (impl_only_animation_takeover_)
276       host->scroll_offset_animations().AddTakeoverUpdate(element_id);
277   }
278   impl_only_animation_adjustment_ = IntSize();
279   impl_only_animation_takeover_ = false;
280 }
281 
UpdateCompositorAnimations()282 void ScrollAnimatorCompositorCoordinator::UpdateCompositorAnimations() {
283   if (!GetScrollableArea()->ScrollAnimatorEnabled())
284     return;
285 
286   UpdateImplOnlyCompositorAnimations();
287 }
288 
ScrollOffsetChanged(const ScrollOffset & offset,mojom::blink::ScrollType scroll_type)289 void ScrollAnimatorCompositorCoordinator::ScrollOffsetChanged(
290     const ScrollOffset& offset,
291     mojom::blink::ScrollType scroll_type) {
292   ScrollOffset clamped_offset = GetScrollableArea()->ClampScrollOffset(offset);
293   GetScrollableArea()->ScrollOffsetChanged(clamped_offset, scroll_type);
294 }
295 
AdjustAnimationAndSetScrollOffset(const ScrollOffset & offset,mojom::blink::ScrollType scroll_type)296 void ScrollAnimatorCompositorCoordinator::AdjustAnimationAndSetScrollOffset(
297     const ScrollOffset& offset,
298     mojom::blink::ScrollType scroll_type) {
299   // Subclasses should override this and adjust the animation as necessary.
300   ScrollOffsetChanged(offset, scroll_type);
301 }
302 
AdjustImplOnlyScrollOffsetAnimation(const IntSize & adjustment)303 void ScrollAnimatorCompositorCoordinator::AdjustImplOnlyScrollOffsetAnimation(
304     const IntSize& adjustment) {
305   if (!GetScrollableArea()->ScrollAnimatorEnabled())
306     return;
307 
308   impl_only_animation_adjustment_.Expand(adjustment.Width(),
309                                          adjustment.Height());
310 
311   GetScrollableArea()->RegisterForAnimation();
312 }
313 
314 void ScrollAnimatorCompositorCoordinator::
TakeOverImplOnlyScrollOffsetAnimation()315     TakeOverImplOnlyScrollOffsetAnimation() {
316   if (!GetScrollableArea()->ScrollAnimatorEnabled())
317     return;
318 
319   impl_only_animation_takeover_ = true;
320 
321   // Update compositor animations right away to avoid skipping a frame.
322   // This imposes the constraint that this function should only be called
323   // from or after DocumentLifecycle::LifecycleState::CompositingClean state.
324   UpdateImplOnlyCompositorAnimations();
325 
326   GetScrollableArea()->RegisterForAnimation();
327 }
328 
RunStateAsText() const329 String ScrollAnimatorCompositorCoordinator::RunStateAsText() const {
330   switch (run_state_) {
331     case RunState::kIdle:
332       return String("Idle");
333     case RunState::kWaitingToSendToCompositor:
334       return String("WaitingToSendToCompositor");
335     case RunState::kRunningOnCompositor:
336       return String("RunningOnCompositor");
337     case RunState::kRunningOnMainThread:
338       return String("RunningOnMainThread");
339     case RunState::kRunningOnCompositorButNeedsUpdate:
340       return String("RunningOnCompositorButNeedsUpdate");
341     case RunState::kWaitingToCancelOnCompositor:
342       return String("WaitingToCancelOnCompositor");
343     case RunState::kPostAnimationCleanup:
344       return String("PostAnimationCleanup");
345     case RunState::kRunningOnCompositorButNeedsTakeover:
346       return String("RunningOnCompositorButNeedsTakeover");
347     case RunState::kWaitingToCancelOnCompositorButNewScroll:
348       return String("WaitingToCancelOnCompositorButNewScroll");
349     case RunState::kRunningOnCompositorButNeedsAdjustment:
350       return String("RunningOnCompositorButNeedsAdjustment");
351   }
352   NOTREACHED();
353   return String();
354 }
355 
356 }  // namespace blink
357