animation.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. // Copyright 2018 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. #ifndef UI_LOTTIE_ANIMATION_H_
  5. #define UI_LOTTIE_ANIMATION_H_
  6. #include <functional>
  7. #include <memory>
  8. #include <vector>
  9. #include "base/component_export.h"
  10. #include "base/containers/flat_map.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/memory/ref_counted_memory.h"
  13. #include "base/memory/scoped_refptr.h"
  14. #include "base/observer_list.h"
  15. #include "base/time/time.h"
  16. #include "cc/paint/skottie_color_map.h"
  17. #include "cc/paint/skottie_frame_data.h"
  18. #include "cc/paint/skottie_frame_data_provider.h"
  19. #include "cc/paint/skottie_resource_metadata.h"
  20. #include "cc/paint/skottie_text_property_value.h"
  21. #include "cc/paint/skottie_wrapper.h"
  22. #include "third_party/abseil-cpp/absl/types/optional.h"
  23. #include "third_party/skia/include/core/SkRefCnt.h"
  24. #include "third_party/skia/include/core/SkStream.h"
  25. #include "third_party/skia/modules/skottie/include/Skottie.h"
  26. #include "ui/gfx/geometry/size.h"
  27. class SkImage;
  28. struct SkSamplingOptions;
  29. namespace gfx {
  30. class Canvas;
  31. } // namespace gfx
  32. namespace lottie {
  33. class AnimationTest;
  34. class AnimationObserver;
  35. // This class is a wrapper over the Skia object for lottie vector graphic
  36. // animations. It has its own timeline manager for the animation controls. The
  37. // framerate of the animation and the animation ticks are controlled externally
  38. // and hence the consumer must manage the timer and call paint at the desired
  39. // frame per second.
  40. // This helps keep multiple animations be synchronized by having a common
  41. // external tick clock.
  42. //
  43. // Usage example:
  44. // 1. Rendering a single frame on the canvas:
  45. // Animation animation_ = Animation(data);
  46. // animation_.Paint(canvas, t);
  47. //
  48. // 2. Playing the animation and rendering each frame:
  49. // void SampleClient::Init() {
  50. // Animation animation_ = Animation(data);
  51. // animation_.Start(Animation::PlaybackConfig::CreateWithStyle(
  52. // Animation::Style::kLinear, *animation_));
  53. // }
  54. //
  55. // // overrides cc::CompositorAnimationObserver
  56. // void SampleClient::OnAnimationStep(TimeTicks* timestamp) {
  57. // timestamp_ = timestamp;
  58. // SchedulePaint();
  59. // }
  60. //
  61. // void SampleClient::OnPaint(Canvas* canvas) {
  62. // animation_.Paint(canvas, timestamp_);
  63. // }
  64. //
  65. // 2. If you only want to play a subsection of the animation:
  66. // void SampleClient::Init() {
  67. // // This will seek to the 1st second of the animation and from there
  68. // // play it for 5 seconds.
  69. // Animation animation_ = Animation(data);
  70. // animation_.Start(Animation::PlaybackConfig({
  71. // Seconds(1), Seconds(5), Animation::Style::kLinear}));
  72. // }
  73. //
  74. // // overrides cc::CompositorAnimationObserver
  75. // void SampleClient::OnAnimationStep(TimeTicks*) {
  76. // timestamp_ = timestamp;
  77. // SchedulePaint();
  78. // }
  79. //
  80. // void SampleClient::OnPaint(Canvas* canvas) {
  81. // animation_.Paint(canvas, timestamp_, gfx::Size(10, 10));
  82. // }
  83. //
  84. class COMPONENT_EXPORT(UI_LOTTIE) Animation final {
  85. public:
  86. enum class Style {
  87. kLinear = 0, // The animation plays from one time instant to another.
  88. kThrobbing, // The animation plays from one time instant to another and
  89. // then back. The animation plays in loop until stopped.
  90. kLoop // Same as LINEAR, except the animation repeats after it ends.
  91. };
  92. // An animation goes through a single "cycle" when it's played from one
  93. // timestamp to another. After reaching the final timestamp, it may either
  94. // loop back to the initial timestamp again, or even play in reverse depending
  95. // on the style described above.
  96. struct COMPONENT_EXPORT(UI_LOTTIE) CycleBoundaries {
  97. // Returns the range [0, animation.GetAnimationDuration()).
  98. static CycleBoundaries FullCycle(const Animation& animation);
  99. // The cycle's range is [start_offset, end_offset). |start_offset| must be
  100. // < |end_offset|, and both must be in the range
  101. // [0, GetAnimationDuration()]. They represent non-normalized timestamps in
  102. // the animation.
  103. base::TimeDelta start_offset;
  104. base::TimeDelta end_offset;
  105. };
  106. struct COMPONENT_EXPORT(UI_LOTTIE) PlaybackConfig {
  107. // By default, loop from the beginning of the animation to the end.
  108. static PlaybackConfig CreateDefault(const Animation& animation);
  109. // Play from the beginning of the animation to the end with the provided
  110. // |style|.
  111. static PlaybackConfig CreateWithStyle(Style style,
  112. const Animation& animation);
  113. PlaybackConfig();
  114. PlaybackConfig(std::vector<CycleBoundaries> scheduled_cycles,
  115. base::TimeDelta initial_offset,
  116. int initial_completed_cycles,
  117. Style style);
  118. PlaybackConfig(const PlaybackConfig& other);
  119. PlaybackConfig& operator=(const PlaybackConfig& other);
  120. ~PlaybackConfig();
  121. // Set of cycles that the animation will iterate through in the order they
  122. // appear. Must not be empty. After reaching the last entry in
  123. // |scheduled_cycles|, the animation will continue re-using the last entry's
  124. // boundaries in all future cycles.
  125. //
  126. // Example: {[0, T), [T/2, 3T/4)}. In the first cycle, the animation will
  127. // play starting at time 0 until it reaches timestamp T. After that, it will
  128. // loop back to timestamp T/2 and play until 3T/4. The [T/2, 3T/4) cycle
  129. // repeats indefinitely until the animation is stopped.
  130. //
  131. // If |style| is kLinear, |scheduled_cycles| must have exactly one entry.
  132. std::vector<CycleBoundaries> scheduled_cycles;
  133. // |initial_offset| and |initial_completed_cycles| combined dictate
  134. // where to start playing the animation from within the |scheduled_cycles|
  135. // above. The most common thing is to start playing from the very beginning
  136. // (|initial_offset| is the |start_offset| of the first scheduled cycle
  137. // and |initial_completed_cycles| is 0). But this allows the caller to
  138. // specify an arbitrary starting point.
  139. base::TimeDelta initial_offset;
  140. // The animation will start playing as if it has already completed the
  141. // number of cycles specified below. Note this not only dictates which
  142. // scheduled cycle the animation starts within, but also the initial
  143. // direction of the animation for throbbing animations.
  144. int initial_completed_cycles = 0;
  145. Style style = Style::kLoop;
  146. };
  147. // |frame_data_provider| may be null if it's known that the incoming skottie
  148. // animation does not contain any image assets.
  149. explicit Animation(
  150. scoped_refptr<cc::SkottieWrapper> skottie,
  151. cc::SkottieColorMap color_map = cc::SkottieColorMap(),
  152. cc::SkottieFrameDataProvider* frame_data_provider = nullptr);
  153. Animation(const Animation&) = delete;
  154. Animation& operator=(const Animation&) = delete;
  155. ~Animation();
  156. void AddObserver(AnimationObserver* observer);
  157. void RemoveObserver(AnimationObserver* observer);
  158. // Animation properties ------------------------------------------------------
  159. // Returns the total duration of the animation as reported by |animation_|.
  160. base::TimeDelta GetAnimationDuration() const;
  161. // Returns the size of the vector graphic as reported by |animation_|. This is
  162. // constant for a given |animation_|.
  163. gfx::Size GetOriginalSize() const;
  164. // Animation controls --------------------------------------------------------
  165. // This is an asynchronous call that would start playing the animation on the
  166. // next animation step. On a successful start the |observer_| would be
  167. // notified.
  168. //
  169. // If a null |playback_config| is provided, the default one is used.
  170. void Start(absl::optional<PlaybackConfig> playback_config = absl::nullopt);
  171. // Pauses the animation.
  172. void Pause();
  173. // This is an asynchronous call that would resume playing a paused animation
  174. // on the next animation step.
  175. void ResumePlaying();
  176. // Resets the animation to the first frame and stops.
  177. void Stop();
  178. // Returns the current normalized [0..1] value at which the animation frame
  179. // is.
  180. // 0 -> first frame and 1 -> last frame.
  181. //
  182. // Returns nullopt if a timestamp is currently is unavailable. This is the
  183. // case if:
  184. // * The animation is currently Stop()ed.
  185. // * The animation has been Start()ed but a single frame has not been painted
  186. // yet.
  187. absl::optional<float> GetCurrentProgress() const;
  188. // Returns the currently playing cycle within the PlaybackConfig's
  189. // |scheduled_cycles|. Returns nullopt under the same circumstances as
  190. // GetCurrentProgress().
  191. absl::optional<CycleBoundaries> GetCurrentCycleBoundaries() const;
  192. // Returns the number of animation cycles that have been completed since
  193. // Play() was called, or nullopt if the animation is currently Stop()ed.
  194. absl::optional<int> GetNumCompletedCycles() const;
  195. // Returns the currently active PlaybackConfig, or nullopt if the animation
  196. // is currently Stop()ed.
  197. absl::optional<PlaybackConfig> GetPlaybackConfig() const;
  198. // Paint operations ----------------------------------------------------------
  199. // Paints the frame of the animation for the given |timestamp| at the given
  200. // |size|.
  201. void Paint(gfx::Canvas* canvas,
  202. const base::TimeTicks& timestamp,
  203. const gfx::Size& size);
  204. // Paints the frame of the animation for the normalized time instance |t|. Use
  205. // this for special cases when you want to manually manage which frame to
  206. // paint.
  207. void PaintFrame(gfx::Canvas* canvas, float t, const gfx::Size& size);
  208. // Returns the skottie object that contins the animation data.
  209. scoped_refptr<cc::SkottieWrapper> skottie() const { return skottie_; }
  210. // Returns the text nodes in the animation and their corresponding current
  211. // property values. The text nodes' initial property values reflect those
  212. // embedded in the Lottie animation file. A mutable reference is returned
  213. // so that the caller may modify the text map with its own custom values
  214. // before calling Paint(). The caller may do so as many times as desired.
  215. cc::SkottieTextPropertyValueMap& text_map() { return text_map_; }
  216. // Sets the rate at which the animation will be played. A |playback_speed| of
  217. // 1 renders exactly in real time, 0.5 is half as fast, 2 is twice as fast,
  218. // etc. This may be called at any time, and the |timestamp| passed to Paint()
  219. // is automatically adjusted internally to account for the playback speed.
  220. //
  221. // Defaults to 1 if not called.
  222. void SetPlaybackSpeed(float playback_speed);
  223. private:
  224. friend class AnimationTest;
  225. enum class PlayState {
  226. kStopped = 0, // Animation is stopped.
  227. kSchedulePlay, // Animation will start playing on the next animatin step.
  228. kPlaying, // Animation is playing.
  229. kPaused, // Animation is paused.
  230. kScheduleResume, // Animation will resume playing on the next animation
  231. // step
  232. kEnded // Animation has ended.
  233. };
  234. // Class to manage the timeline when playing the animation. Manages the
  235. // normalized progress [0..1] between the given start and end offset. If the
  236. // reverse flag is set, the progress runs in reverse.
  237. class COMPONENT_EXPORT(UI_LOTTIE) TimerControl final {
  238. public:
  239. TimerControl(std::vector<CycleBoundaries> scheduled_cycles,
  240. base::TimeDelta initial_offset,
  241. int initial_completed_cycles,
  242. const base::TimeDelta& total_duration,
  243. const base::TimeTicks& start_timestamp,
  244. bool should_reverse,
  245. float playback_speed);
  246. ~TimerControl();
  247. TimerControl(const TimerControl&) = delete;
  248. TimerControl& operator=(const TimerControl&) = delete;
  249. // Update timeline progress based on the new timetick |timestamp|.
  250. void Step(const base::TimeTicks& timestamp);
  251. // Resumes the timer.
  252. void Resume(const base::TimeTicks& timestamp);
  253. void SetPlaybackSpeed(float playback_speed);
  254. double GetNormalizedCurrentCycleProgress() const;
  255. double GetNormalizedStartOffset() const;
  256. double GetNormalizedEndOffset() const;
  257. int completed_cycles() const { return completed_cycles_; }
  258. CycleBoundaries current_cycle() const { return current_cycle_; }
  259. private:
  260. friend class AnimationTest;
  261. // Only applies to throbbing animations, for which every even numbered
  262. // cycle plays forwards, and every odd numbered cycle plays reversed.
  263. bool IsPlayingInReverse() const;
  264. // See comments in |PlaybackConfig::scheduled_cycles|.
  265. const std::vector<CycleBoundaries> scheduled_cycles_;
  266. // Total duration of all cycles.
  267. const base::TimeDelta total_duration_;
  268. // The timetick at which |progress_| was updated last.
  269. base::TimeTicks previous_tick_;
  270. // This is the progress of the timer in the current cycle.
  271. base::TimeDelta current_cycle_progress_;
  272. // If true, the progress will go into reverse after each cycle. This is used
  273. // for throbbing animations.
  274. const bool should_reverse_ = false;
  275. // The number of times each |cycle_duration_| is covered by the timer.
  276. int completed_cycles_ = 0;
  277. // See comments above SetPlaybackSpeed().
  278. float playback_speed_ = 1.f;
  279. // The boundaries of the current cycle. This is a copy of one of the entries
  280. // in |scheduled_cycles_|.
  281. CycleBoundaries current_cycle_;
  282. };
  283. void InitTimer(const base::TimeTicks& timestamp);
  284. void TryNotifyAnimationCycleEnded() const;
  285. cc::SkottieWrapper::FrameDataFetchResult LoadImageForAsset(
  286. gfx::Canvas* canvas,
  287. cc::SkottieFrameDataMap& all_frame_data,
  288. cc::SkottieResourceIdHash asset_id,
  289. float t,
  290. sk_sp<SkImage>&,
  291. SkSamplingOptions&);
  292. void VerifyPlaybackConfigIsValid(const PlaybackConfig& playback_config) const;
  293. // Manages the timeline for the current playing animation.
  294. std::unique_ptr<TimerControl> timer_control_;
  295. // The current state of animation.
  296. PlayState state_ = PlayState::kStopped;
  297. // The config from the most recent call to Start().
  298. PlaybackConfig playback_config_;
  299. base::ObserverList<AnimationObserver> observers_;
  300. scoped_refptr<cc::SkottieWrapper> skottie_;
  301. cc::SkottieColorMap color_map_;
  302. cc::SkottieTextPropertyValueMap text_map_;
  303. base::flat_map<cc::SkottieResourceIdHash,
  304. scoped_refptr<cc::SkottieFrameDataProvider::ImageAsset>>
  305. image_assets_;
  306. float playback_speed_ = 1.f;
  307. };
  308. } // namespace lottie
  309. #endif // UI_LOTTIE_ANIMATION_H_