1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326

cc / animation / animation_host.h [blame]

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_ANIMATION_ANIMATION_HOST_H_
#define CC_ANIMATION_ANIMATION_HOST_H_

#include <memory>
#include <unordered_map>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/keyframe_model.h"
#include "cc/base/protected_sequence_synchronizer.h"
#include "cc/trees/mutator_host.h"
#include "cc/trees/mutator_host_client.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/vector2d_f.h"

namespace cc {

class Animation;
class AnimationTimeline;
class ElementAnimations;
class LayerTreeHost;
class ScrollOffsetAnimations;
class ScrollOffsetAnimationsImpl;
class WorkletAnimation;

enum class ThreadInstance { kMain, kImpl };

// An AnimationHost contains all the state required to play animations.
// Specifically, it owns all the AnimationTimelines objects.
// There is just one AnimationHost for LayerTreeHost on main renderer thread
// and just one AnimationHost for LayerTreeHostImpl on impl thread.
// We synchronize them during the commit process in a one-way data flow process
// (PushPropertiesTo).
// An AnimationHost talks to its correspondent LayerTreeHost via
// MutatorHostClient interface.
class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost,
                                          public LayerTreeMutatorClient,
                                          public ProtectedSequenceSynchronizer {
 public:
  using ElementToAnimationsMap =
      std::unordered_map<ElementId,
                         scoped_refptr<ElementAnimations>,
                         ElementIdHash>;
  using AnimationsList = std::vector<scoped_refptr<Animation>>;

  static std::unique_ptr<AnimationHost> CreateMainInstance();
  static std::unique_ptr<AnimationHost> CreateForTesting(
      ThreadInstance thread_instance);

  AnimationHost(const AnimationHost&) = delete;
  ~AnimationHost() override;

  AnimationHost& operator=(const AnimationHost&) = delete;

  using IdToTimelineMap =
      std::unordered_map<int, scoped_refptr<AnimationTimeline>>;
  const IdToTimelineMap& timelines() const {
    return id_to_timeline_map_.Read(*this);
  }

  void AddAnimationTimeline(scoped_refptr<AnimationTimeline> timeline);
  void RemoveAnimationTimeline(scoped_refptr<AnimationTimeline> timeline);

  // Lazy removal of an unused timeline.
  void DetachAnimationTimeline(scoped_refptr<AnimationTimeline> timeline);

  const AnimationTimeline* GetTimelineById(int timeline_id) const;
  AnimationTimeline* GetTimelineById(int timeline_id);

  void RegisterAnimationForElement(ElementId element_id, Animation* animation);
  void UnregisterAnimationForElement(ElementId element_id,
                                     Animation* animation);
  void UpdateClientAnimationStateForElementAnimations(ElementId element_id);
  gfx::PointF GetScrollOffsetForAnimation(ElementId element_id) const;

  scoped_refptr<const ElementAnimations>
  GetElementAnimationsForElementIdForTesting(ElementId element_id) const;

  // Parent LayerTreeHost or LayerTreeHostImpl.
  MutatorHostClient* mutator_host_client() {
    DCHECK(IsOwnerThread() || InProtectedSequence());
    return mutator_host_client_;
  }
  const MutatorHostClient* mutator_host_client() const {
    DCHECK(IsOwnerThread() || InProtectedSequence());
    return mutator_host_client_;
  }

  // ProtectedSequenceSynchronizer implementation
  bool IsOwnerThread() const override;
  bool InProtectedSequence() const override;
  void WaitForProtectedSequenceCompletion() const override;

  void SetNeedsCommit();
  void SetNeedsPushProperties();
  void ResetNeedsPushProperties();
  bool needs_push_properties() const {
    return needs_push_properties_.Read(*this);
  }

  // MutatorHost implementation.
  std::unique_ptr<MutatorHost> CreateImplInstance() const override;
  void ClearMutators() override;
  base::TimeDelta MinimumTickInterval() const override;

  void InitClientAnimationState() override;

  void RemoveElementId(ElementId element_id) override;

  void SetMutatorHostClient(MutatorHostClient* client) override;

  void SetLayerTreeMutator(std::unique_ptr<LayerTreeMutator> mutator) override;

  void PushPropertiesTo(MutatorHost* host_impl,
                        const PropertyTrees& property_trees) override;

  void RemoveStaleTimelines() override;

  void SetScrollAnimationDurationForTesting(base::TimeDelta duration) override;
  bool NeedsTickAnimations() const override;

  bool ActivateAnimations(MutatorEvents* events) override;
  bool TickAnimations(base::TimeTicks monotonic_time,
                      const ScrollTree& scroll_tree,
                      bool is_active_tree) override;
  void TickScrollAnimations(base::TimeTicks monotonic_time,
                            const ScrollTree& scroll_tree) override;
  void TickWorkletAnimations() override;
  bool UpdateAnimationState(bool start_ready_animations,
                            MutatorEvents* events) override;
  void TakeTimeUpdatedEvents(MutatorEvents* events) override;
  // Should be called when the pending tree is promoted to active, as this may
  // require updating the ElementId for the ScrollTimeline scroll source.
  void PromoteScrollTimelinesPendingToActive() override;

  std::unique_ptr<MutatorEvents> CreateEvents() override;
  void SetAnimationEvents(std::unique_ptr<MutatorEvents> events) override;

  bool ScrollOffsetAnimationWasInterrupted(ElementId element_id) const override;

  bool IsAnimatingProperty(ElementId element_id,
                           ElementListType list_type,
                           TargetProperty::Type property) const override;

  bool HasPotentiallyRunningAnimationForProperty(
      ElementId element_id,
      ElementListType list_type,
      TargetProperty::Type property) const override;

  bool HasAnyAnimationTargetingProperty(
      ElementId element_id,
      TargetProperty::Type property) const override;

  bool AnimationsPreserveAxisAlignment(ElementId element_id) const override;

  float MaximumScale(ElementId element_id,
                     ElementListType list_type) const override;

  bool IsElementAnimating(ElementId element_id) const override;
  bool HasTickingKeyframeModelForTesting(ElementId element_id) const override;

  void ImplOnlyAutoScrollAnimationCreate(
      ElementId element_id,
      const gfx::PointF& target_offset,
      const gfx::PointF& current_offset,
      float autoscroll_velocity,
      base::TimeDelta animation_start_offset) override;

  void ImplOnlyScrollAnimationCreate(
      ElementId element_id,
      const gfx::PointF& target_offset,
      const gfx::PointF& current_offset,
      base::TimeDelta delayed_by,
      base::TimeDelta animation_start_offset) override;
  std::optional<gfx::PointF> ImplOnlyScrollAnimationUpdateTarget(
      const gfx::Vector2dF& scroll_delta,
      const gfx::PointF& max_scroll_offset,
      base::TimeTicks frame_monotonic_time,
      base::TimeDelta delayed_by,
      ElementId element_id) override;

  void ScrollAnimationAbort(ElementId element_id) override;

  bool HasImplOnlyScrollAnimatingElement() const override;
  bool HasImplOnlyAutoScrollAnimatingElement() const override;
  bool ElementHasImplOnlyScrollAnimation(ElementId) const override;
  bool IsElementInPropertyTrees(ElementId element_id,
                                bool commits_to_active) const;
  void HandleRemovedScrollAnimatingElements(bool commits_to_active) override;

  // This should only be called from the main thread.
  ScrollOffsetAnimations& scroll_offset_animations();

  // Registers the given animation as ticking. A ticking animation is one that
  // has a running keyframe model.
  void AddToTicking(scoped_refptr<Animation> animation);

  // Unregisters the given animation. When this happens, the animation will no
  // longer be ticked.
  void RemoveFromTicking(scoped_refptr<Animation> animation);

  const AnimationsList& ticking_animations_for_testing() const;
  const ElementToAnimationsMap& element_animations_for_testing() const;

  // LayerTreeMutatorClient.
  void SetMutationUpdate(
      std::unique_ptr<MutatorOutputState> output_state) override;

  size_t MainThreadAnimationsCount() const override;
  // Returns true if there is any animation that affects pending tree, such as
  // custom property animations via paint worklet.
  bool HasInvalidationAnimation() const override;
  // Returns true if there is any animation that affects active tree, such as
  // transform animation.
  bool HasNativePropertyAnimation() const override;
  bool CurrentFrameHadRAF() const override;
  bool NextFrameHasPendingRAF() const override;
  PendingCompositorMetricsTrackerInfos
  TakePendingCompositorMetricsTrackerInfos() override;
  bool HasCanvasInvalidation() const override;
  bool HasJSAnimation() const override;
  bool HasSmilAnimation() const override;
  bool HasViewTransition() const override;
  bool HasScrollLinkedAnimation(ElementId for_scroller) const override;

  // Starts/stops metrics tracking represented by `sequence_id`.
  void StartCompositorMetricsTracking(TrackedAnimationSequenceId sequence_id);
  void StopCompositorMetricsTracking(TrackedAnimationSequenceId sequence_id);

  void SetAnimationCounts(size_t total_animations_count);
  void SetHasCanvasInvalidation(bool has_canvas_invalidation);
  void SetHasInlineStyleMutation(bool has_inline_style_mutation);
  void SetHasSmilAnimation(bool has_svg_smil_animation);
  void SetHasViewTransition(bool has_view_transition);
  void SetCurrentFrameHadRaf(bool current_frame_had_raf);
  void SetNextFrameHasPendingRaf(bool next_frame_has_pending_raf);

 private:
  explicit AnimationHost(ThreadInstance thread_instance);

  const ElementAnimations* GetElementAnimationsForElementId(
      ElementId element_id) const;
  scoped_refptr<ElementAnimations> GetElementAnimationsForElementId(
      ElementId element_id);

  void PushTimelinesToImplThread(AnimationHost* host_impl) const;
  void RemoveTimelinesFromImplThread(AnimationHost* host_impl) const;
  void PushPropertiesToImplThread(AnimationHost* host_impl);

  void EraseTimeline(scoped_refptr<AnimationTimeline> timeline);

  // Return true if there are any animations that get mutated.
  void TickMutator(base::TimeTicks monotonic_time,
                   const ScrollTree& scroll_tree,
                   bool is_active_tree);

  // Return the state representing all ticking worklet animations.
  std::unique_ptr<MutatorInputState> CollectWorkletAnimationsState(
      base::TimeTicks timeline_time,
      const ScrollTree& scroll_tree,
      bool is_active_tree);

  // Returns a pointer to a worklet animation by worklet animation id or null
  // if there is no match.
  WorkletAnimation* FindWorkletAnimation(WorkletAnimationId id);

  ProtectedSequenceReadable<ElementToAnimationsMap> element_to_animations_map_;
  ProtectedSequenceReadable<AnimationsList> ticking_animations_;

  // A list of all timelines which this host owns.
  ProtectedSequenceReadable<IdToTimelineMap> id_to_timeline_map_;

  // A list of IDs for detached timelines. A timeline may be detached on the
  // owner thread even during a protected sequence. These timelines are no
  // longer used and should be cleaned up at the next opportune moment.
  ProtectedSequenceForbidden<IdToTimelineMap> detached_timeline_map_;

  // AnimationHosts's ProtectedSequenceSynchronizer implementation is
  // implemented using this member. As such the various helpers can not be used
  // to protect access (otherwise we would get infinite recursion).
  raw_ptr<MutatorHostClient> mutator_host_client_ = nullptr;

  // This is only non-null within the call scope of PushPropertiesTo().
  raw_ptr<const PropertyTrees> property_trees_ = nullptr;

  // Exactly one of scroll_offset_animations_ and scroll_offset_animations_impl_
  // will be non-null for a given AnimationHost instance (the former if
  // thread_instance_ == ThreadInstance::MAIN, the latter if thread_instance_ ==
  // ThreadInstance::IMPL).
  ProtectedSequenceWritable<std::unique_ptr<ScrollOffsetAnimations>>
      scroll_offset_animations_;
  ProtectedSequenceReadable<std::unique_ptr<ScrollOffsetAnimationsImpl>>
      scroll_offset_animations_impl_;

  const ThreadInstance thread_instance_;

  ProtectedSequenceWritable<bool> needs_push_properties_{false};

  ProtectedSequenceReadable<std::unique_ptr<LayerTreeMutator>> mutator_;

  ProtectedSequenceReadable<size_t> main_thread_animations_count_{0};
  ProtectedSequenceReadable<bool> current_frame_had_raf_{false};
  ProtectedSequenceReadable<bool> next_frame_has_pending_raf_{false};
  ProtectedSequenceReadable<bool> has_canvas_invalidation_{false};
  ProtectedSequenceReadable<bool> has_inline_style_mutation_{false};
  ProtectedSequenceReadable<bool> has_smil_animation_{false};
  ProtectedSequenceReadable<bool> has_view_transition_{false};

  ProtectedSequenceWritable<PendingCompositorMetricsTrackerInfos>
      pending_compositor_metrics_tracker_infos_;

  base::WeakPtrFactory<AnimationHost> weak_factory_{this};
};

}  // namespace cc

#endif  // CC_ANIMATION_ANIMATION_HOST_H_