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