1 // Copyright 2015 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 "cc/animation/animation_host.h"
6 
7 #include <algorithm>
8 #include <memory>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/stl_util.h"
15 #include "base/trace_event/trace_event.h"
16 #include "base/trace_event/traced_value.h"
17 #include "cc/animation/animation.h"
18 #include "cc/animation/animation_delegate.h"
19 #include "cc/animation/animation_events.h"
20 #include "cc/animation/animation_id_provider.h"
21 #include "cc/animation/animation_timeline.h"
22 #include "cc/animation/element_animations.h"
23 #include "cc/animation/scroll_offset_animation_curve.h"
24 #include "cc/animation/scroll_offset_animations.h"
25 #include "cc/animation/scroll_offset_animations_impl.h"
26 #include "cc/animation/scroll_timeline.h"
27 #include "cc/animation/timing_function.h"
28 #include "cc/animation/worklet_animation.h"
29 #include "ui/gfx/geometry/box_f.h"
30 #include "ui/gfx/geometry/scroll_offset.h"
31 
32 namespace cc {
33 
34 namespace {
35 
ToAnimationWorkletMutationState(MutateStatus status)36 AnimationWorkletMutationState ToAnimationWorkletMutationState(
37     MutateStatus status) {
38   switch (status) {
39     case MutateStatus::kCompletedWithUpdate:
40       return AnimationWorkletMutationState::COMPLETED_WITH_UPDATE;
41 
42     case MutateStatus::kCompletedNoUpdate:
43       return AnimationWorkletMutationState::COMPLETED_NO_UPDATE;
44 
45     case MutateStatus::kCanceled:
46       return AnimationWorkletMutationState::CANCELED;
47   }
48 }
49 
50 }  // namespace
51 
CreateMainInstance()52 std::unique_ptr<AnimationHost> AnimationHost::CreateMainInstance() {
53   return base::WrapUnique(new AnimationHost(ThreadInstance::MAIN));
54 }
55 
CreateForTesting(ThreadInstance thread_instance)56 std::unique_ptr<AnimationHost> AnimationHost::CreateForTesting(
57     ThreadInstance thread_instance) {
58   auto animation_host = base::WrapUnique(new AnimationHost(thread_instance));
59 
60   if (thread_instance == ThreadInstance::IMPL)
61     animation_host->SetSupportsScrollAnimations(true);
62 
63   return animation_host;
64 }
65 
AnimationHost(ThreadInstance thread_instance)66 AnimationHost::AnimationHost(ThreadInstance thread_instance)
67     : mutator_host_client_(nullptr),
68       thread_instance_(thread_instance),
69       supports_scroll_animations_(false),
70       needs_push_properties_(false),
71       mutator_(nullptr) {
72   if (thread_instance_ == ThreadInstance::IMPL) {
73     scroll_offset_animations_impl_ =
74         std::make_unique<ScrollOffsetAnimationsImpl>(this);
75   } else {
76     scroll_offset_animations_ = std::make_unique<ScrollOffsetAnimations>(this);
77   }
78 }
79 
~AnimationHost()80 AnimationHost::~AnimationHost() {
81   scroll_offset_animations_impl_ = nullptr;
82 
83   ClearMutators();
84   DCHECK(!mutator_host_client());
85   DCHECK(element_to_animations_map_.empty());
86 }
87 
CreateImplInstance(bool supports_impl_scrolling) const88 std::unique_ptr<MutatorHost> AnimationHost::CreateImplInstance(
89     bool supports_impl_scrolling) const {
90   DCHECK_EQ(thread_instance_, ThreadInstance::MAIN);
91 
92   auto mutator_host_impl =
93       base::WrapUnique<MutatorHost>(new AnimationHost(ThreadInstance::IMPL));
94   mutator_host_impl->SetSupportsScrollAnimations(supports_impl_scrolling);
95   return mutator_host_impl;
96 }
97 
GetTimelineById(int timeline_id) const98 AnimationTimeline* AnimationHost::GetTimelineById(int timeline_id) const {
99   auto f = id_to_timeline_map_.find(timeline_id);
100   return f == id_to_timeline_map_.end() ? nullptr : f->second.get();
101 }
102 
ClearMutators()103 void AnimationHost::ClearMutators() {
104   for (auto& kv : id_to_timeline_map_)
105     EraseTimeline(kv.second);
106   id_to_timeline_map_.clear();
107 }
108 
EraseTimeline(scoped_refptr<AnimationTimeline> timeline)109 void AnimationHost::EraseTimeline(scoped_refptr<AnimationTimeline> timeline) {
110   timeline->ClearAnimations();
111   timeline->SetAnimationHost(nullptr);
112 }
113 
AddAnimationTimeline(scoped_refptr<AnimationTimeline> timeline)114 void AnimationHost::AddAnimationTimeline(
115     scoped_refptr<AnimationTimeline> timeline) {
116   DCHECK(timeline->id());
117   timeline->SetAnimationHost(this);
118   id_to_timeline_map_.insert(
119       std::make_pair(timeline->id(), std::move(timeline)));
120   SetNeedsPushProperties();
121 }
122 
RemoveAnimationTimeline(scoped_refptr<AnimationTimeline> timeline)123 void AnimationHost::RemoveAnimationTimeline(
124     scoped_refptr<AnimationTimeline> timeline) {
125   DCHECK(timeline->id());
126   EraseTimeline(timeline);
127   id_to_timeline_map_.erase(timeline->id());
128   SetNeedsPushProperties();
129 }
130 
SetHasCanvasInvalidation(bool has_canvas_invalidation)131 void AnimationHost::SetHasCanvasInvalidation(bool has_canvas_invalidation) {
132   has_canvas_invalidation_ = has_canvas_invalidation;
133 }
134 
HasCanvasInvalidation() const135 bool AnimationHost::HasCanvasInvalidation() const {
136   return has_canvas_invalidation_;
137 }
138 
HasJSAnimation() const139 bool AnimationHost::HasJSAnimation() const {
140   return has_inline_style_mutation_;
141 }
142 
SetHasInlineStyleMutation(bool has_inline_style_mutation)143 void AnimationHost::SetHasInlineStyleMutation(bool has_inline_style_mutation) {
144   has_inline_style_mutation_ = has_inline_style_mutation;
145 }
146 
UpdateRegisteredElementIds(ElementListType changed_list)147 void AnimationHost::UpdateRegisteredElementIds(ElementListType changed_list) {
148   for (auto map_entry : element_to_animations_map_) {
149     // kReservedElementId is reserved for an paint worklet element that animates
150     // a custom property. This element is assumed to always be present as no
151     // element is needed to tick this animation.
152     if (mutator_host_client()->IsElementInPropertyTrees(map_entry.first,
153                                                         changed_list) ||
154         map_entry.first.GetStableId() == ElementId::kReservedElementId) {
155       map_entry.second->ElementIdRegistered(map_entry.first, changed_list);
156     } else {
157       map_entry.second->ElementIdUnregistered(map_entry.first, changed_list);
158     }
159   }
160 }
161 
InitClientAnimationState()162 void AnimationHost::InitClientAnimationState() {
163   for (auto map_entry : element_to_animations_map_)
164     map_entry.second->InitClientAnimationState();
165 }
166 
RegisterElementId(ElementId element_id,ElementListType list_type)167 void AnimationHost::RegisterElementId(ElementId element_id,
168                                       ElementListType list_type) {
169   scoped_refptr<ElementAnimations> element_animations =
170       GetElementAnimationsForElementId(element_id);
171   if (element_animations)
172     element_animations->ElementIdRegistered(element_id, list_type);
173 }
174 
UnregisterElementId(ElementId element_id,ElementListType list_type)175 void AnimationHost::UnregisterElementId(ElementId element_id,
176                                         ElementListType list_type) {
177   scoped_refptr<ElementAnimations> element_animations =
178       GetElementAnimationsForElementId(element_id);
179   if (element_animations)
180     element_animations->ElementIdUnregistered(element_id, list_type);
181 }
182 
RegisterAnimationForElement(ElementId element_id,Animation * animation)183 void AnimationHost::RegisterAnimationForElement(ElementId element_id,
184                                                 Animation* animation) {
185   DCHECK(element_id);
186   DCHECK(animation);
187 
188   scoped_refptr<ElementAnimations> element_animations =
189       GetElementAnimationsForElementId(element_id);
190   if (!element_animations) {
191     element_animations = ElementAnimations::Create(this, element_id);
192     element_to_animations_map_[element_animations->element_id()] =
193         element_animations;
194   }
195 
196   DCHECK(element_animations->AnimationHostIs(this));
197 
198   element_animations->AddKeyframeEffect(animation->keyframe_effect());
199 }
200 
UnregisterAnimationForElement(ElementId element_id,Animation * animation)201 void AnimationHost::UnregisterAnimationForElement(ElementId element_id,
202                                                   Animation* animation) {
203   DCHECK(element_id);
204   DCHECK(animation);
205 
206   scoped_refptr<ElementAnimations> element_animations =
207       GetElementAnimationsForElementId(element_id);
208   DCHECK(element_animations);
209 
210   // |ClearAffectedElementTypes| requires an ElementId map in order to update
211   // the property trees. Generating that map requires walking the keyframe
212   // effects, so we have to do it before removing this one.
213   PropertyToElementIdMap element_id_map =
214       element_animations->GetPropertyToElementIdMap();
215 
216   element_animations->RemoveKeyframeEffect(animation->keyframe_effect());
217 
218   if (element_animations->IsEmpty()) {
219     element_animations->ClearAffectedElementTypes(element_id_map);
220     element_to_animations_map_.erase(element_animations->element_id());
221     element_animations->ClearAnimationHost();
222   }
223 
224   RemoveFromTicking(animation);
225 }
226 
SetMutatorHostClient(MutatorHostClient * client)227 void AnimationHost::SetMutatorHostClient(MutatorHostClient* client) {
228   if (mutator_host_client_ == client)
229     return;
230 
231   mutator_host_client_ = client;
232   if (mutator_host_client_ && needs_push_properties_)
233     mutator_host_client_->SetMutatorsNeedCommit();
234 }
235 
SetNeedsCommit()236 void AnimationHost::SetNeedsCommit() {
237   DCHECK(mutator_host_client_);
238   mutator_host_client_->SetMutatorsNeedCommit();
239   // TODO(loyso): Invalidate property trees only if really needed.
240   mutator_host_client_->SetMutatorsNeedRebuildPropertyTrees();
241 }
242 
SetNeedsPushProperties()243 void AnimationHost::SetNeedsPushProperties() {
244   if (needs_push_properties_)
245     return;
246   needs_push_properties_ = true;
247   if (mutator_host_client_)
248     mutator_host_client_->SetMutatorsNeedCommit();
249 }
250 
PushPropertiesTo(MutatorHost * mutator_host_impl)251 void AnimationHost::PushPropertiesTo(MutatorHost* mutator_host_impl) {
252   auto* host_impl = static_cast<AnimationHost*>(mutator_host_impl);
253 
254   // Update animation counts and whether raf was requested. These explicitly
255   // do not request push properties and are pushed as part of the next commit
256   // when it happens as requesting a commit leads to performance issues:
257   // https://crbug.com/1083244
258   host_impl->main_thread_animations_count_ = main_thread_animations_count_;
259   host_impl->current_frame_had_raf_ = current_frame_had_raf_;
260   host_impl->next_frame_has_pending_raf_ = next_frame_has_pending_raf_;
261   host_impl->has_canvas_invalidation_ = has_canvas_invalidation_;
262   host_impl->has_inline_style_mutation_ = has_inline_style_mutation_;
263 
264   if (needs_push_properties_) {
265     needs_push_properties_ = false;
266     PushTimelinesToImplThread(host_impl);
267     RemoveTimelinesFromImplThread(host_impl);
268     PushPropertiesToImplThread(host_impl);
269     // This is redundant but used in tests.
270     host_impl->needs_push_properties_ = false;
271   }
272 }
273 
PushTimelinesToImplThread(AnimationHost * host_impl) const274 void AnimationHost::PushTimelinesToImplThread(AnimationHost* host_impl) const {
275   for (auto& kv : id_to_timeline_map_) {
276     auto& timeline = kv.second;
277     AnimationTimeline* timeline_impl =
278         host_impl->GetTimelineById(timeline->id());
279     if (timeline_impl)
280       continue;
281 
282     scoped_refptr<AnimationTimeline> to_add = timeline->CreateImplInstance();
283     host_impl->AddAnimationTimeline(to_add.get());
284   }
285 }
286 
RemoveTimelinesFromImplThread(AnimationHost * host_impl) const287 void AnimationHost::RemoveTimelinesFromImplThread(
288     AnimationHost* host_impl) const {
289   IdToTimelineMap& timelines_impl = host_impl->id_to_timeline_map_;
290 
291   // Erase all the impl timelines which |this| doesn't have.
292   for (auto it = timelines_impl.begin(); it != timelines_impl.end();) {
293     auto& timeline_impl = it->second;
294     if (timeline_impl->is_impl_only() || GetTimelineById(timeline_impl->id())) {
295       ++it;
296     } else {
297       host_impl->EraseTimeline(it->second);
298       it = timelines_impl.erase(it);
299     }
300   }
301 }
302 
PushPropertiesToImplThread(AnimationHost * host_impl)303 void AnimationHost::PushPropertiesToImplThread(AnimationHost* host_impl) {
304   // Sync all animations with impl thread to create ElementAnimations. This
305   // needs to happen before the element animations are synced below.
306   for (auto& kv : id_to_timeline_map_) {
307     AnimationTimeline* timeline = kv.second.get();
308     if (AnimationTimeline* timeline_impl =
309             host_impl->GetTimelineById(timeline->id())) {
310       timeline->PushPropertiesTo(timeline_impl);
311     }
312   }
313 
314   // Sync properties for created ElementAnimations.
315   for (auto& kv : element_to_animations_map_) {
316     const auto& element_animations = kv.second;
317     if (auto element_animations_impl =
318             host_impl->GetElementAnimationsForElementId(kv.first)) {
319       element_animations->PushPropertiesTo(std::move(element_animations_impl));
320     }
321   }
322 
323   // Update the impl-only scroll offset animations.
324   scroll_offset_animations_->PushPropertiesTo(
325       host_impl->scroll_offset_animations_impl_.get());
326 
327   // The pending info list is cleared in LayerTreeHostImpl::CommitComplete
328   // and should be empty when pushing properties.
329   DCHECK(host_impl->pending_throughput_tracker_infos_.empty());
330   host_impl->pending_throughput_tracker_infos_ =
331       TakePendingThroughputTrackerInfos();
332 }
333 
334 scoped_refptr<ElementAnimations>
GetElementAnimationsForElementId(ElementId element_id) const335 AnimationHost::GetElementAnimationsForElementId(ElementId element_id) const {
336   if (!element_id)
337     return nullptr;
338   auto iter = element_to_animations_map_.find(element_id);
339   return iter == element_to_animations_map_.end() ? nullptr : iter->second;
340 }
341 
SetSupportsScrollAnimations(bool supports_scroll_animations)342 void AnimationHost::SetSupportsScrollAnimations(
343     bool supports_scroll_animations) {
344   supports_scroll_animations_ = supports_scroll_animations;
345 }
346 
SetScrollAnimationDurationForTesting(base::TimeDelta duration)347 void AnimationHost::SetScrollAnimationDurationForTesting(
348     base::TimeDelta duration) {
349   ScrollOffsetAnimationCurve::SetAnimationDurationForTesting(duration);
350 }
351 
SupportsScrollAnimations() const352 bool AnimationHost::SupportsScrollAnimations() const {
353   return supports_scroll_animations_;
354 }
355 
NeedsTickAnimations() const356 bool AnimationHost::NeedsTickAnimations() const {
357   return !ticking_animations_.empty();
358 }
359 
TickMutator(base::TimeTicks monotonic_time,const ScrollTree & scroll_tree,bool is_active_tree)360 void AnimationHost::TickMutator(base::TimeTicks monotonic_time,
361                                 const ScrollTree& scroll_tree,
362                                 bool is_active_tree) {
363   if (!mutator_ || !mutator_->HasMutators())
364     return;
365 
366   std::unique_ptr<MutatorInputState> state = CollectWorkletAnimationsState(
367       monotonic_time, scroll_tree, is_active_tree);
368   if (state->IsEmpty())
369     return;
370 
371   ElementListType tree_type =
372       is_active_tree ? ElementListType::ACTIVE : ElementListType::PENDING;
373 
374   auto on_done = base::BindOnce(
375       [](base::WeakPtr<AnimationHost> animation_host, ElementListType tree_type,
376          MutateStatus status) {
377         if (animation_host->mutator_host_client_) {
378           animation_host->mutator_host_client_
379               ->NotifyAnimationWorkletStateChange(
380                   ToAnimationWorkletMutationState(status), tree_type);
381         }
382       },
383       weak_factory_.GetWeakPtr(), tree_type);
384 
385   MutateQueuingStrategy queuing_strategy =
386       is_active_tree ? MutateQueuingStrategy::kQueueAndReplaceNormalPriority
387                      : MutateQueuingStrategy::kQueueHighPriority;
388   if (mutator_->Mutate(std::move(state), queuing_strategy,
389                        std::move(on_done))) {
390     mutator_host_client_->NotifyAnimationWorkletStateChange(
391         AnimationWorkletMutationState::STARTED, tree_type);
392   }
393   return;
394 }
395 
ActivateAnimations(MutatorEvents * mutator_events)396 bool AnimationHost::ActivateAnimations(MutatorEvents* mutator_events) {
397   if (!NeedsTickAnimations())
398     return false;
399 
400   auto* animation_events = static_cast<AnimationEvents*>(mutator_events);
401 
402   TRACE_EVENT0("cc", "AnimationHost::ActivateAnimations");
403   AnimationsList ticking_animations_copy = ticking_animations_;
404   for (auto& it : ticking_animations_copy) {
405     it->ActivateKeyframeModels();
406     // Finish animations which no longer affect active or pending elements.
407     it->UpdateState(false, animation_events);
408   }
409 
410   return true;
411 }
412 
TickAnimations(base::TimeTicks monotonic_time,const ScrollTree & scroll_tree,bool is_active_tree)413 bool AnimationHost::TickAnimations(base::TimeTicks monotonic_time,
414                                    const ScrollTree& scroll_tree,
415                                    bool is_active_tree) {
416   TRACE_EVENT0("cc", "AnimationHost::TickAnimations");
417   // We tick animations in the following order:
418   // 1. regular animations 2. mutator 3. worklet animations
419   //
420   // Mutator may depend on scroll offset as its time input e.g., when there is
421   // a worklet animation attached to a scroll timeline.
422   // This ordering ensures we use the latest scroll offset as the input to the
423   // mutator even if there are active scroll animations.
424   // The ticking of worklet animations is deferred until draw to ensure that
425   // mutator output takes effect in the same impl frame that it was mutated.
426   if (!NeedsTickAnimations())
427     return false;
428 
429   TRACE_EVENT_INSTANT0("cc", "NeedsTickAnimations", TRACE_EVENT_SCOPE_THREAD);
430 
431   bool animated = false;
432   for (auto& kv : id_to_timeline_map_) {
433     AnimationTimeline* timeline = kv.second.get();
434     if (timeline->IsScrollTimeline()) {
435       animated |= timeline->TickScrollLinkedAnimations(
436           ticking_animations_, scroll_tree, is_active_tree);
437     } else {
438       animated |= timeline->TickTimeLinkedAnimations(ticking_animations_,
439                                                      monotonic_time);
440     }
441   }
442 
443   // TODO(majidvp): At the moment we call this for both active and pending
444   // trees similar to other animations. However our final goal is to only call
445   // it once, ideally after activation, and only when the input
446   // to an active timeline has changed. http://crbug.com/767210
447   // Note that the TickMutator does not set the animated flag since these
448   // mutations are processed asynchronously. Additional actions required to
449   // handle these mutations are performed on receiving the asynchronous results.
450   TickMutator(monotonic_time, scroll_tree, is_active_tree);
451 
452   return animated;
453 }
454 
TickScrollAnimations(base::TimeTicks monotonic_time,const ScrollTree & scroll_tree)455 void AnimationHost::TickScrollAnimations(base::TimeTicks monotonic_time,
456                                          const ScrollTree& scroll_tree) {
457   // TODO(majidvp): We need to return a boolean here so that LTHI knows
458   // whether it needs to schedule another frame.
459   TickMutator(monotonic_time, scroll_tree, true /* is_active_tree */);
460 }
461 
TickWorkletAnimations()462 void AnimationHost::TickWorkletAnimations() {
463   for (auto& animation : ticking_animations_) {
464     if (!animation->IsWorkletAnimation())
465       continue;
466     animation->Tick(base::TimeTicks());
467   }
468 }
469 
CollectWorkletAnimationsState(base::TimeTicks monotonic_time,const ScrollTree & scroll_tree,bool is_active_tree)470 std::unique_ptr<MutatorInputState> AnimationHost::CollectWorkletAnimationsState(
471     base::TimeTicks monotonic_time,
472     const ScrollTree& scroll_tree,
473     bool is_active_tree) {
474   TRACE_EVENT0("cc", "AnimationHost::CollectWorkletAnimationsState");
475   std::unique_ptr<MutatorInputState> result =
476       std::make_unique<MutatorInputState>();
477 
478   for (auto& animation : ticking_animations_) {
479     if (!animation->IsWorkletAnimation())
480       continue;
481 
482     ToWorkletAnimation(animation.get())
483         ->UpdateInputState(result.get(), monotonic_time, scroll_tree,
484                            is_active_tree);
485   }
486 
487   return result;
488 }
489 
UpdateAnimationState(bool start_ready_animations,MutatorEvents * mutator_events)490 bool AnimationHost::UpdateAnimationState(bool start_ready_animations,
491                                          MutatorEvents* mutator_events) {
492   if (!NeedsTickAnimations())
493     return false;
494 
495   auto* animation_events = static_cast<AnimationEvents*>(mutator_events);
496 
497   TRACE_EVENT0("cc", "AnimationHost::UpdateAnimationState");
498   AnimationsList ticking_animations_copy = ticking_animations_;
499   for (auto& it : ticking_animations_copy)
500     it->UpdateState(start_ready_animations, animation_events);
501 
502   return true;
503 }
504 
TakeTimeUpdatedEvents(MutatorEvents * events)505 void AnimationHost::TakeTimeUpdatedEvents(MutatorEvents* events) {
506   auto* animation_events = static_cast<AnimationEvents*>(events);
507   if (!animation_events->needs_time_updated_events())
508     return;
509 
510   for (auto& it : ticking_animations_)
511     it->TakeTimeUpdatedEvent(animation_events);
512 
513   animation_events->set_needs_time_updated_events(false);
514 }
515 
PromoteScrollTimelinesPendingToActive()516 void AnimationHost::PromoteScrollTimelinesPendingToActive() {
517   for (auto& kv : id_to_timeline_map_) {
518     auto& timeline = kv.second;
519     timeline->ActivateTimeline();
520   }
521 }
522 
CreateEvents()523 std::unique_ptr<MutatorEvents> AnimationHost::CreateEvents() {
524   return std::make_unique<AnimationEvents>();
525 }
526 
SetAnimationEvents(std::unique_ptr<MutatorEvents> mutator_events)527 void AnimationHost::SetAnimationEvents(
528     std::unique_ptr<MutatorEvents> mutator_events) {
529   DCHECK_EQ(thread_instance_, ThreadInstance::MAIN);
530   auto events =
531       base::WrapUnique(static_cast<AnimationEvents*>(mutator_events.release()));
532 
533   for (size_t event_index = 0; event_index < events->events_.size();
534        ++event_index) {
535     AnimationEvent& event = events->events_[event_index];
536     AnimationTimeline* timeline = GetTimelineById(event.uid.timeline_id);
537     if (timeline) {
538       Animation* animation = timeline->GetAnimationById(event.uid.animation_id);
539       if (animation)
540         animation->DispatchAndDelegateAnimationEvent(event);
541     }
542   }
543 }
544 
ScrollOffsetAnimationWasInterrupted(ElementId element_id) const545 bool AnimationHost::ScrollOffsetAnimationWasInterrupted(
546     ElementId element_id) const {
547   auto element_animations = GetElementAnimationsForElementId(element_id);
548   return element_animations
549              ? element_animations->ScrollOffsetAnimationWasInterrupted()
550              : false;
551 }
552 
IsAnimatingFilterProperty(ElementId element_id,ElementListType list_type) const553 bool AnimationHost::IsAnimatingFilterProperty(ElementId element_id,
554                                               ElementListType list_type) const {
555   auto element_animations = GetElementAnimationsForElementId(element_id);
556   return element_animations
557              ? element_animations->IsCurrentlyAnimatingProperty(
558                    TargetProperty::FILTER, list_type)
559              : false;
560 }
561 
IsAnimatingBackdropFilterProperty(ElementId element_id,ElementListType list_type) const562 bool AnimationHost::IsAnimatingBackdropFilterProperty(
563     ElementId element_id,
564     ElementListType list_type) const {
565   auto element_animations = GetElementAnimationsForElementId(element_id);
566   return element_animations ? element_animations->IsCurrentlyAnimatingProperty(
567                                   TargetProperty::BACKDROP_FILTER, list_type)
568                             : false;
569 }
570 
IsAnimatingOpacityProperty(ElementId element_id,ElementListType list_type) const571 bool AnimationHost::IsAnimatingOpacityProperty(
572     ElementId element_id,
573     ElementListType list_type) const {
574   auto element_animations = GetElementAnimationsForElementId(element_id);
575   return element_animations
576              ? element_animations->IsCurrentlyAnimatingProperty(
577                    TargetProperty::OPACITY, list_type)
578              : false;
579 }
580 
IsAnimatingTransformProperty(ElementId element_id,ElementListType list_type) const581 bool AnimationHost::IsAnimatingTransformProperty(
582     ElementId element_id,
583     ElementListType list_type) const {
584   auto element_animations = GetElementAnimationsForElementId(element_id);
585   return element_animations
586              ? element_animations->IsCurrentlyAnimatingProperty(
587                    TargetProperty::TRANSFORM, list_type)
588              : false;
589 }
590 
HasPotentiallyRunningFilterAnimation(ElementId element_id,ElementListType list_type) const591 bool AnimationHost::HasPotentiallyRunningFilterAnimation(
592     ElementId element_id,
593     ElementListType list_type) const {
594   auto element_animations = GetElementAnimationsForElementId(element_id);
595   return element_animations
596              ? element_animations->IsPotentiallyAnimatingProperty(
597                    TargetProperty::FILTER, list_type)
598              : false;
599 }
600 
HasPotentiallyRunningBackdropFilterAnimation(ElementId element_id,ElementListType list_type) const601 bool AnimationHost::HasPotentiallyRunningBackdropFilterAnimation(
602     ElementId element_id,
603     ElementListType list_type) const {
604   auto element_animations = GetElementAnimationsForElementId(element_id);
605   return element_animations
606              ? element_animations->IsPotentiallyAnimatingProperty(
607                    TargetProperty::BACKDROP_FILTER, list_type)
608              : false;
609 }
610 
HasPotentiallyRunningOpacityAnimation(ElementId element_id,ElementListType list_type) const611 bool AnimationHost::HasPotentiallyRunningOpacityAnimation(
612     ElementId element_id,
613     ElementListType list_type) const {
614   auto element_animations = GetElementAnimationsForElementId(element_id);
615   return element_animations
616              ? element_animations->IsPotentiallyAnimatingProperty(
617                    TargetProperty::OPACITY, list_type)
618              : false;
619 }
620 
HasPotentiallyRunningTransformAnimation(ElementId element_id,ElementListType list_type) const621 bool AnimationHost::HasPotentiallyRunningTransformAnimation(
622     ElementId element_id,
623     ElementListType list_type) const {
624   auto element_animations = GetElementAnimationsForElementId(element_id);
625   return element_animations
626              ? element_animations->IsPotentiallyAnimatingProperty(
627                    TargetProperty::TRANSFORM, list_type)
628              : false;
629 }
630 
HasAnyAnimationTargetingProperty(ElementId element_id,TargetProperty::Type property) const631 bool AnimationHost::HasAnyAnimationTargetingProperty(
632     ElementId element_id,
633     TargetProperty::Type property) const {
634   auto element_animations = GetElementAnimationsForElementId(element_id);
635   if (!element_animations)
636     return false;
637 
638   return element_animations->HasAnyAnimationTargetingProperty(property);
639 }
640 
AnimationsPreserveAxisAlignment(ElementId element_id) const641 bool AnimationHost::AnimationsPreserveAxisAlignment(
642     ElementId element_id) const {
643   auto element_animations = GetElementAnimationsForElementId(element_id);
644   return element_animations
645              ? element_animations->AnimationsPreserveAxisAlignment()
646              : true;
647 }
648 
GetAnimationScales(ElementId element_id,ElementListType list_type,float * maximum_scale,float * starting_scale) const649 void AnimationHost::GetAnimationScales(ElementId element_id,
650                                        ElementListType list_type,
651                                        float* maximum_scale,
652                                        float* starting_scale) const {
653   if (auto element_animations = GetElementAnimationsForElementId(element_id)) {
654     element_animations->GetAnimationScales(list_type, maximum_scale,
655                                            starting_scale);
656     return;
657   }
658   *maximum_scale = kNotScaled;
659   *starting_scale = kNotScaled;
660 }
661 
IsElementAnimating(ElementId element_id) const662 bool AnimationHost::IsElementAnimating(ElementId element_id) const {
663   auto element_animations = GetElementAnimationsForElementId(element_id);
664   return element_animations ? element_animations->HasAnyKeyframeModel() : false;
665 }
666 
HasTickingKeyframeModelForTesting(ElementId element_id) const667 bool AnimationHost::HasTickingKeyframeModelForTesting(
668     ElementId element_id) const {
669   auto element_animations = GetElementAnimationsForElementId(element_id);
670   return element_animations ? element_animations->HasTickingKeyframeEffect()
671                             : false;
672 }
673 
ImplOnlyAutoScrollAnimationCreate(ElementId element_id,const gfx::ScrollOffset & target_offset,const gfx::ScrollOffset & current_offset,float autoscroll_velocity,base::TimeDelta animation_start_offset)674 void AnimationHost::ImplOnlyAutoScrollAnimationCreate(
675     ElementId element_id,
676     const gfx::ScrollOffset& target_offset,
677     const gfx::ScrollOffset& current_offset,
678     float autoscroll_velocity,
679     base::TimeDelta animation_start_offset) {
680   DCHECK(scroll_offset_animations_impl_);
681   scroll_offset_animations_impl_->AutoScrollAnimationCreate(
682       element_id, target_offset, current_offset, autoscroll_velocity,
683       animation_start_offset);
684 }
685 
ImplOnlyScrollAnimationCreate(ElementId element_id,const gfx::ScrollOffset & target_offset,const gfx::ScrollOffset & current_offset,base::TimeDelta delayed_by,base::TimeDelta animation_start_offset)686 void AnimationHost::ImplOnlyScrollAnimationCreate(
687     ElementId element_id,
688     const gfx::ScrollOffset& target_offset,
689     const gfx::ScrollOffset& current_offset,
690     base::TimeDelta delayed_by,
691     base::TimeDelta animation_start_offset) {
692   DCHECK(scroll_offset_animations_impl_);
693   scroll_offset_animations_impl_->MouseWheelScrollAnimationCreate(
694       element_id, target_offset, current_offset, delayed_by,
695       animation_start_offset);
696 }
697 
ImplOnlyScrollAnimationUpdateTarget(const gfx::Vector2dF & scroll_delta,const gfx::ScrollOffset & max_scroll_offset,base::TimeTicks frame_monotonic_time,base::TimeDelta delayed_by)698 bool AnimationHost::ImplOnlyScrollAnimationUpdateTarget(
699     const gfx::Vector2dF& scroll_delta,
700     const gfx::ScrollOffset& max_scroll_offset,
701     base::TimeTicks frame_monotonic_time,
702     base::TimeDelta delayed_by) {
703   DCHECK(scroll_offset_animations_impl_);
704   return scroll_offset_animations_impl_->ScrollAnimationUpdateTarget(
705       scroll_delta, max_scroll_offset, frame_monotonic_time, delayed_by);
706 }
707 
scroll_offset_animations() const708 ScrollOffsetAnimations& AnimationHost::scroll_offset_animations() const {
709   DCHECK(scroll_offset_animations_);
710   return *scroll_offset_animations_.get();
711 }
712 
ScrollAnimationAbort()713 void AnimationHost::ScrollAnimationAbort() {
714   DCHECK(scroll_offset_animations_impl_);
715   scroll_offset_animations_impl_->ScrollAnimationAbort(
716       false /* needs_completion */);
717 }
718 
ImplOnlyScrollAnimatingElement() const719 ElementId AnimationHost::ImplOnlyScrollAnimatingElement() const {
720   DCHECK(scroll_offset_animations_impl_);
721   if (!scroll_offset_animations_impl_->IsAnimating())
722     return ElementId();
723 
724   return scroll_offset_animations_impl_->GetElementId();
725 }
726 
AddToTicking(scoped_refptr<Animation> animation)727 void AnimationHost::AddToTicking(scoped_refptr<Animation> animation) {
728   DCHECK(!base::Contains(ticking_animations_, animation));
729   ticking_animations_.push_back(animation);
730 }
731 
RemoveFromTicking(scoped_refptr<Animation> animation)732 void AnimationHost::RemoveFromTicking(scoped_refptr<Animation> animation) {
733   auto to_erase = std::find(ticking_animations_.begin(),
734                             ticking_animations_.end(), animation);
735   if (to_erase != ticking_animations_.end())
736     ticking_animations_.erase(to_erase);
737 }
738 
739 const AnimationHost::AnimationsList&
ticking_animations_for_testing() const740 AnimationHost::ticking_animations_for_testing() const {
741   return ticking_animations_;
742 }
743 
744 const AnimationHost::ElementToAnimationsMap&
element_animations_for_testing() const745 AnimationHost::element_animations_for_testing() const {
746   return element_to_animations_map_;
747 }
748 
SetLayerTreeMutator(std::unique_ptr<LayerTreeMutator> mutator)749 void AnimationHost::SetLayerTreeMutator(
750     std::unique_ptr<LayerTreeMutator> mutator) {
751   if (mutator == mutator_)
752     return;
753   mutator_ = std::move(mutator);
754   mutator_->SetClient(this);
755 }
756 
FindWorkletAnimation(WorkletAnimationId id)757 WorkletAnimation* AnimationHost::FindWorkletAnimation(WorkletAnimationId id) {
758   // TODO(majidvp): Use a map to make lookup O(1)
759   auto animation = std::find_if(
760       ticking_animations_.begin(), ticking_animations_.end(), [id](auto& it) {
761         return it->IsWorkletAnimation() &&
762                ToWorkletAnimation(it.get())->worklet_animation_id() == id;
763       });
764 
765   if (animation == ticking_animations_.end())
766     return nullptr;
767 
768   return ToWorkletAnimation(animation->get());
769 }
770 
SetMutationUpdate(std::unique_ptr<MutatorOutputState> output_state)771 void AnimationHost::SetMutationUpdate(
772     std::unique_ptr<MutatorOutputState> output_state) {
773   if (!output_state)
774     return;
775 
776   TRACE_EVENT0("cc", "AnimationHost::SetMutationUpdate");
777   for (auto& animation_state : output_state->animations) {
778     WorkletAnimationId id = animation_state.worklet_animation_id;
779 
780     WorkletAnimation* to_update = FindWorkletAnimation(id);
781     if (to_update)
782       to_update->SetOutputState(animation_state);
783   }
784 }
785 
SetAnimationCounts(size_t total_animations_count,bool current_frame_had_raf,bool next_frame_has_pending_raf)786 void AnimationHost::SetAnimationCounts(
787     size_t total_animations_count,
788     bool current_frame_had_raf,
789     bool next_frame_has_pending_raf) {
790   // Though these changes are pushed as part of AnimationHost::PushPropertiesTo
791   // we don't SetNeedsPushProperties as pushing the values requires a commit.
792   // Instead we allow them to be pushed whenever the next required commit
793   // happens to avoid unnecessary work. See https://crbug.com/1083244.
794 
795   // If an animation is being run on the compositor, it will have a ticking
796   // Animation (which will have a corresponding impl-thread version). Therefore
797   // to find the count of main-only animations, we can simply subtract the
798   // number of ticking animations from the total count.
799   size_t ticking_animations_count = ticking_animations_.size();
800   main_thread_animations_count_ =
801       total_animations_count - ticking_animations_count;
802   DCHECK_GE(main_thread_animations_count_, 0u);
803   current_frame_had_raf_ = current_frame_had_raf;
804   next_frame_has_pending_raf_ = next_frame_has_pending_raf;
805 }
806 
MainThreadAnimationsCount() const807 size_t AnimationHost::MainThreadAnimationsCount() const {
808   return main_thread_animations_count_;
809 }
810 
HasCustomPropertyAnimations() const811 bool AnimationHost::HasCustomPropertyAnimations() const {
812   for (const auto& it : ticking_animations_)
813     if (it->AffectsCustomProperty())
814       return true;
815   return false;
816 }
817 
CurrentFrameHadRAF() const818 bool AnimationHost::CurrentFrameHadRAF() const {
819   return current_frame_had_raf_;
820 }
821 
NextFrameHasPendingRAF() const822 bool AnimationHost::NextFrameHasPendingRAF() const {
823   return next_frame_has_pending_raf_;
824 }
825 
826 AnimationHost::PendingThroughputTrackerInfos
TakePendingThroughputTrackerInfos()827 AnimationHost::TakePendingThroughputTrackerInfos() {
828   PendingThroughputTrackerInfos infos =
829       std::move(pending_throughput_tracker_infos_);
830   pending_throughput_tracker_infos_ = {};
831   return infos;
832 }
833 
StartThroughputTracking(TrackedAnimationSequenceId sequence_id)834 void AnimationHost::StartThroughputTracking(
835     TrackedAnimationSequenceId sequence_id) {
836   pending_throughput_tracker_infos_.push_back({sequence_id, true});
837   SetNeedsPushProperties();
838 }
839 
StopThroughputTracking(TrackedAnimationSequenceId sequnece_id)840 void AnimationHost::StopThroughputTracking(
841     TrackedAnimationSequenceId sequnece_id) {
842   pending_throughput_tracker_infos_.push_back({sequnece_id, false});
843   SetNeedsPushProperties();
844 }
845 
846 }  // namespace cc
847