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

cc / animation / worklet_animation.h [blame]

// Copyright 2017 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_WORKLET_ANIMATION_H_
#define CC_ANIMATION_WORKLET_ANIMATION_H_

#include <memory>
#include <optional>
#include <string>

#include "base/gtest_prod_util.h"
#include "base/time/time.h"
#include "cc/animation/animation.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/animation_host.h"
#include "cc/trees/property_tree.h"

namespace cc {

class AnimationOptions;
class AnimationEffectTimings;

// A WorkletAnimation is an animation that allows its animation
// timing to be controlled by an animator instance that is running in a
// AnimationWorkletGlobalScope.

// Two instances of this class are created for Blink WorkletAnimation:
// 1. UI thread instance that keeps all the meta data.
// 2. Impl thread instance that ticks the animations on the Impl thread.
// When Blink WorkletAnimation is updated, it calls the UI thread instance to
// modify its properties. The updated properties are pushed by the UI thread
// instance to the Impl thread instance during commit.
class CC_ANIMATION_EXPORT WorkletAnimation final : public Animation {
 public:
  enum class State { kPending, kRunning, kRemoved };
  WorkletAnimation(int cc_animation_id,
                   WorkletAnimationId worklet_animation_id,
                   const std::string& name,
                   double playback_rate_value,
                   std::unique_ptr<AnimationOptions> options,
                   std::unique_ptr<AnimationEffectTimings> effect_timings,
                   bool is_controlling_instance);
  static scoped_refptr<WorkletAnimation> Create(
      WorkletAnimationId worklet_animation_id,
      const std::string& name,
      double playback_rate_value,
      std::unique_ptr<AnimationOptions> options,
      std::unique_ptr<AnimationEffectTimings> effect_timings);
  scoped_refptr<Animation> CreateImplInstance() const override;

  WorkletAnimationId worklet_animation_id() { return worklet_animation_id_; }
  const std::string& name() const { return name_; }

  bool IsWorkletAnimation() const override;

  bool Tick(base::TimeTicks monotonic_time) override;

  void UpdateState(bool start_ready_animations,
                   AnimationEvents* events) override;

  void TakeTimeUpdatedEvent(AnimationEvents* events) override;
  void UpdateInputState(MutatorInputState* input_state,
                        base::TimeTicks monotonic_time,
                        const ScrollTree& scroll_tree,
                        bool is_active_tree);
  void SetOutputState(const MutatorOutputState::AnimationState& state);

  void PushPropertiesTo(Animation* animation_impl) override;

  // Called by Blink WorkletAnimation when its playback rate is updated.
  void UpdatePlaybackRate(double rate);
  void SetPlaybackRateForTesting(double playback_rate) {
    SetPlaybackRate(playback_rate);
  }

  void RemoveKeyframeModel(int keyframe_model_id) override;
  void ReleasePendingTreeLock();

 private:
  ~WorkletAnimation() override;

  double playback_rate() const { return playback_rate_.Read(*this); }

  // Returns the current time to be passed into the underlying AnimationWorklet.
  // The current time is based on the timeline associated with the animation and
  // in case of scroll timeline it may be nullopt when the associated scrolling
  // node is not available in the particular ScrollTree.
  std::optional<base::TimeDelta> CurrentTime(base::TimeTicks monotonic_time,
                                             const ScrollTree& scroll_tree,
                                             bool is_active_tree);

  // Returns true if the worklet animation needs to be updated which happens iff
  // its current time is going to be different from last time given these input.
  bool NeedsUpdate(base::TimeTicks monotonic_time,
                   const ScrollTree& scroll_tree,
                   bool is_active_tree);

  std::unique_ptr<AnimationOptions> CloneOptions() const {
    return options_ ? options_->Clone() : nullptr;
  }

  std::unique_ptr<AnimationEffectTimings> CloneEffectTimings() const {
    return effect_timings_ ? effect_timings_->Clone() : nullptr;
  }

  // Updates the playback rate of the Impl thread instance.
  // Called by the UI thread WorkletAnimation instance during commit.
  void SetPlaybackRate(double rate);

  bool IsTimelineActive(const ScrollTree& scroll_tree,
                        bool is_active_tree) const;

  const WorkletAnimationId worklet_animation_id_;
  const std::string name_;

  // Controls speed of the animation.
  // https://drafts.csswg.org/web-animations-2/#animation-effect-playback-rate

  // For UI thread instance contains the meta value to be pushed to the Impl
  // thread instance.
  // For the Impl thread instance contains the actual playback rate of the
  // animation.
  ProtectedSequenceReadable<double> playback_rate_;

  // These are set once, and never change.
  std::unique_ptr<AnimationOptions> options_;
  std::unique_ptr<AnimationEffectTimings> effect_timings_;

  // Local time is used as an input to the keyframe effect of this animation.
  // The value comes from the user script that runs inside the animation worklet
  // global scope.
  ProtectedSequenceReadable<std::optional<base::TimeDelta>> local_time_;
  // Local time passed to the main thread worklet animation to update its
  // keyframe effect. We only set the most recent local time, meaning that if
  // there are multiple compositor frames without a single main frame only
  // the local time associated with the latest frame is sent to the main thread.
  ProtectedSequenceReadable<std::optional<base::TimeDelta>>
      last_synced_local_time_;

  ProtectedSequenceReadable<std::optional<base::TimeTicks>> start_time_;

  // Last current time used for updating. We use this to skip updating if
  // current time has not changed since last update.
  ProtectedSequenceReadable<std::optional<base::TimeDelta>> last_current_time_;

  // To ensure that 'time' progresses forward for scroll animations, we guard
  // against allowing active tree mutations while the pending tree has a
  // lock in the worklet. The lock is established when updating the input state
  // for the pending tree and release on pending tree activation.
  ProtectedSequenceReadable<bool> has_pending_tree_lock_{false};
  ProtectedSequenceReadable<State> state_{State::kPending};

  const bool is_impl_instance_;
};

inline WorkletAnimation* ToWorkletAnimation(Animation* animation) {
  DCHECK(animation->IsWorkletAnimation());
  return static_cast<WorkletAnimation*>(animation);
}

}  // namespace cc

#endif  // CC_ANIMATION_WORKLET_ANIMATION_H_