123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef UI_LOTTIE_ANIMATION_H_
- #define UI_LOTTIE_ANIMATION_H_
- #include <functional>
- #include <memory>
- #include <vector>
- #include "base/component_export.h"
- #include "base/containers/flat_map.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/ref_counted_memory.h"
- #include "base/memory/scoped_refptr.h"
- #include "base/observer_list.h"
- #include "base/time/time.h"
- #include "cc/paint/skottie_color_map.h"
- #include "cc/paint/skottie_frame_data.h"
- #include "cc/paint/skottie_frame_data_provider.h"
- #include "cc/paint/skottie_resource_metadata.h"
- #include "cc/paint/skottie_text_property_value.h"
- #include "cc/paint/skottie_wrapper.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "third_party/skia/include/core/SkRefCnt.h"
- #include "third_party/skia/include/core/SkStream.h"
- #include "third_party/skia/modules/skottie/include/Skottie.h"
- #include "ui/gfx/geometry/size.h"
- class SkImage;
- struct SkSamplingOptions;
- namespace gfx {
- class Canvas;
- } // namespace gfx
- namespace lottie {
- class AnimationTest;
- class AnimationObserver;
- // This class is a wrapper over the Skia object for lottie vector graphic
- // animations. It has its own timeline manager for the animation controls. The
- // framerate of the animation and the animation ticks are controlled externally
- // and hence the consumer must manage the timer and call paint at the desired
- // frame per second.
- // This helps keep multiple animations be synchronized by having a common
- // external tick clock.
- //
- // Usage example:
- // 1. Rendering a single frame on the canvas:
- // Animation animation_ = Animation(data);
- // animation_.Paint(canvas, t);
- //
- // 2. Playing the animation and rendering each frame:
- // void SampleClient::Init() {
- // Animation animation_ = Animation(data);
- // animation_.Start(Animation::PlaybackConfig::CreateWithStyle(
- // Animation::Style::kLinear, *animation_));
- // }
- //
- // // overrides cc::CompositorAnimationObserver
- // void SampleClient::OnAnimationStep(TimeTicks* timestamp) {
- // timestamp_ = timestamp;
- // SchedulePaint();
- // }
- //
- // void SampleClient::OnPaint(Canvas* canvas) {
- // animation_.Paint(canvas, timestamp_);
- // }
- //
- // 2. If you only want to play a subsection of the animation:
- // void SampleClient::Init() {
- // // This will seek to the 1st second of the animation and from there
- // // play it for 5 seconds.
- // Animation animation_ = Animation(data);
- // animation_.Start(Animation::PlaybackConfig({
- // Seconds(1), Seconds(5), Animation::Style::kLinear}));
- // }
- //
- // // overrides cc::CompositorAnimationObserver
- // void SampleClient::OnAnimationStep(TimeTicks*) {
- // timestamp_ = timestamp;
- // SchedulePaint();
- // }
- //
- // void SampleClient::OnPaint(Canvas* canvas) {
- // animation_.Paint(canvas, timestamp_, gfx::Size(10, 10));
- // }
- //
- class COMPONENT_EXPORT(UI_LOTTIE) Animation final {
- public:
- enum class Style {
- kLinear = 0, // The animation plays from one time instant to another.
- kThrobbing, // The animation plays from one time instant to another and
- // then back. The animation plays in loop until stopped.
- kLoop // Same as LINEAR, except the animation repeats after it ends.
- };
- // An animation goes through a single "cycle" when it's played from one
- // timestamp to another. After reaching the final timestamp, it may either
- // loop back to the initial timestamp again, or even play in reverse depending
- // on the style described above.
- struct COMPONENT_EXPORT(UI_LOTTIE) CycleBoundaries {
- // Returns the range [0, animation.GetAnimationDuration()).
- static CycleBoundaries FullCycle(const Animation& animation);
- // The cycle's range is [start_offset, end_offset). |start_offset| must be
- // < |end_offset|, and both must be in the range
- // [0, GetAnimationDuration()]. They represent non-normalized timestamps in
- // the animation.
- base::TimeDelta start_offset;
- base::TimeDelta end_offset;
- };
- struct COMPONENT_EXPORT(UI_LOTTIE) PlaybackConfig {
- // By default, loop from the beginning of the animation to the end.
- static PlaybackConfig CreateDefault(const Animation& animation);
- // Play from the beginning of the animation to the end with the provided
- // |style|.
- static PlaybackConfig CreateWithStyle(Style style,
- const Animation& animation);
- PlaybackConfig();
- PlaybackConfig(std::vector<CycleBoundaries> scheduled_cycles,
- base::TimeDelta initial_offset,
- int initial_completed_cycles,
- Style style);
- PlaybackConfig(const PlaybackConfig& other);
- PlaybackConfig& operator=(const PlaybackConfig& other);
- ~PlaybackConfig();
- // Set of cycles that the animation will iterate through in the order they
- // appear. Must not be empty. After reaching the last entry in
- // |scheduled_cycles|, the animation will continue re-using the last entry's
- // boundaries in all future cycles.
- //
- // Example: {[0, T), [T/2, 3T/4)}. In the first cycle, the animation will
- // play starting at time 0 until it reaches timestamp T. After that, it will
- // loop back to timestamp T/2 and play until 3T/4. The [T/2, 3T/4) cycle
- // repeats indefinitely until the animation is stopped.
- //
- // If |style| is kLinear, |scheduled_cycles| must have exactly one entry.
- std::vector<CycleBoundaries> scheduled_cycles;
- // |initial_offset| and |initial_completed_cycles| combined dictate
- // where to start playing the animation from within the |scheduled_cycles|
- // above. The most common thing is to start playing from the very beginning
- // (|initial_offset| is the |start_offset| of the first scheduled cycle
- // and |initial_completed_cycles| is 0). But this allows the caller to
- // specify an arbitrary starting point.
- base::TimeDelta initial_offset;
- // The animation will start playing as if it has already completed the
- // number of cycles specified below. Note this not only dictates which
- // scheduled cycle the animation starts within, but also the initial
- // direction of the animation for throbbing animations.
- int initial_completed_cycles = 0;
- Style style = Style::kLoop;
- };
- // |frame_data_provider| may be null if it's known that the incoming skottie
- // animation does not contain any image assets.
- explicit Animation(
- scoped_refptr<cc::SkottieWrapper> skottie,
- cc::SkottieColorMap color_map = cc::SkottieColorMap(),
- cc::SkottieFrameDataProvider* frame_data_provider = nullptr);
- Animation(const Animation&) = delete;
- Animation& operator=(const Animation&) = delete;
- ~Animation();
- void AddObserver(AnimationObserver* observer);
- void RemoveObserver(AnimationObserver* observer);
- // Animation properties ------------------------------------------------------
- // Returns the total duration of the animation as reported by |animation_|.
- base::TimeDelta GetAnimationDuration() const;
- // Returns the size of the vector graphic as reported by |animation_|. This is
- // constant for a given |animation_|.
- gfx::Size GetOriginalSize() const;
- // Animation controls --------------------------------------------------------
- // This is an asynchronous call that would start playing the animation on the
- // next animation step. On a successful start the |observer_| would be
- // notified.
- //
- // If a null |playback_config| is provided, the default one is used.
- void Start(absl::optional<PlaybackConfig> playback_config = absl::nullopt);
- // Pauses the animation.
- void Pause();
- // This is an asynchronous call that would resume playing a paused animation
- // on the next animation step.
- void ResumePlaying();
- // Resets the animation to the first frame and stops.
- void Stop();
- // Returns the current normalized [0..1] value at which the animation frame
- // is.
- // 0 -> first frame and 1 -> last frame.
- //
- // Returns nullopt if a timestamp is currently is unavailable. This is the
- // case if:
- // * The animation is currently Stop()ed.
- // * The animation has been Start()ed but a single frame has not been painted
- // yet.
- absl::optional<float> GetCurrentProgress() const;
- // Returns the currently playing cycle within the PlaybackConfig's
- // |scheduled_cycles|. Returns nullopt under the same circumstances as
- // GetCurrentProgress().
- absl::optional<CycleBoundaries> GetCurrentCycleBoundaries() const;
- // Returns the number of animation cycles that have been completed since
- // Play() was called, or nullopt if the animation is currently Stop()ed.
- absl::optional<int> GetNumCompletedCycles() const;
- // Returns the currently active PlaybackConfig, or nullopt if the animation
- // is currently Stop()ed.
- absl::optional<PlaybackConfig> GetPlaybackConfig() const;
- // Paint operations ----------------------------------------------------------
- // Paints the frame of the animation for the given |timestamp| at the given
- // |size|.
- void Paint(gfx::Canvas* canvas,
- const base::TimeTicks& timestamp,
- const gfx::Size& size);
- // Paints the frame of the animation for the normalized time instance |t|. Use
- // this for special cases when you want to manually manage which frame to
- // paint.
- void PaintFrame(gfx::Canvas* canvas, float t, const gfx::Size& size);
- // Returns the skottie object that contins the animation data.
- scoped_refptr<cc::SkottieWrapper> skottie() const { return skottie_; }
- // Returns the text nodes in the animation and their corresponding current
- // property values. The text nodes' initial property values reflect those
- // embedded in the Lottie animation file. A mutable reference is returned
- // so that the caller may modify the text map with its own custom values
- // before calling Paint(). The caller may do so as many times as desired.
- cc::SkottieTextPropertyValueMap& text_map() { return text_map_; }
- // Sets the rate at which the animation will be played. A |playback_speed| of
- // 1 renders exactly in real time, 0.5 is half as fast, 2 is twice as fast,
- // etc. This may be called at any time, and the |timestamp| passed to Paint()
- // is automatically adjusted internally to account for the playback speed.
- //
- // Defaults to 1 if not called.
- void SetPlaybackSpeed(float playback_speed);
- private:
- friend class AnimationTest;
- enum class PlayState {
- kStopped = 0, // Animation is stopped.
- kSchedulePlay, // Animation will start playing on the next animatin step.
- kPlaying, // Animation is playing.
- kPaused, // Animation is paused.
- kScheduleResume, // Animation will resume playing on the next animation
- // step
- kEnded // Animation has ended.
- };
- // Class to manage the timeline when playing the animation. Manages the
- // normalized progress [0..1] between the given start and end offset. If the
- // reverse flag is set, the progress runs in reverse.
- class COMPONENT_EXPORT(UI_LOTTIE) TimerControl final {
- public:
- TimerControl(std::vector<CycleBoundaries> scheduled_cycles,
- base::TimeDelta initial_offset,
- int initial_completed_cycles,
- const base::TimeDelta& total_duration,
- const base::TimeTicks& start_timestamp,
- bool should_reverse,
- float playback_speed);
- ~TimerControl();
- TimerControl(const TimerControl&) = delete;
- TimerControl& operator=(const TimerControl&) = delete;
- // Update timeline progress based on the new timetick |timestamp|.
- void Step(const base::TimeTicks& timestamp);
- // Resumes the timer.
- void Resume(const base::TimeTicks& timestamp);
- void SetPlaybackSpeed(float playback_speed);
- double GetNormalizedCurrentCycleProgress() const;
- double GetNormalizedStartOffset() const;
- double GetNormalizedEndOffset() const;
- int completed_cycles() const { return completed_cycles_; }
- CycleBoundaries current_cycle() const { return current_cycle_; }
- private:
- friend class AnimationTest;
- // Only applies to throbbing animations, for which every even numbered
- // cycle plays forwards, and every odd numbered cycle plays reversed.
- bool IsPlayingInReverse() const;
- // See comments in |PlaybackConfig::scheduled_cycles|.
- const std::vector<CycleBoundaries> scheduled_cycles_;
- // Total duration of all cycles.
- const base::TimeDelta total_duration_;
- // The timetick at which |progress_| was updated last.
- base::TimeTicks previous_tick_;
- // This is the progress of the timer in the current cycle.
- base::TimeDelta current_cycle_progress_;
- // If true, the progress will go into reverse after each cycle. This is used
- // for throbbing animations.
- const bool should_reverse_ = false;
- // The number of times each |cycle_duration_| is covered by the timer.
- int completed_cycles_ = 0;
- // See comments above SetPlaybackSpeed().
- float playback_speed_ = 1.f;
- // The boundaries of the current cycle. This is a copy of one of the entries
- // in |scheduled_cycles_|.
- CycleBoundaries current_cycle_;
- };
- void InitTimer(const base::TimeTicks& timestamp);
- void TryNotifyAnimationCycleEnded() const;
- cc::SkottieWrapper::FrameDataFetchResult LoadImageForAsset(
- gfx::Canvas* canvas,
- cc::SkottieFrameDataMap& all_frame_data,
- cc::SkottieResourceIdHash asset_id,
- float t,
- sk_sp<SkImage>&,
- SkSamplingOptions&);
- void VerifyPlaybackConfigIsValid(const PlaybackConfig& playback_config) const;
- // Manages the timeline for the current playing animation.
- std::unique_ptr<TimerControl> timer_control_;
- // The current state of animation.
- PlayState state_ = PlayState::kStopped;
- // The config from the most recent call to Start().
- PlaybackConfig playback_config_;
- base::ObserverList<AnimationObserver> observers_;
- scoped_refptr<cc::SkottieWrapper> skottie_;
- cc::SkottieColorMap color_map_;
- cc::SkottieTextPropertyValueMap text_map_;
- base::flat_map<cc::SkottieResourceIdHash,
- scoped_refptr<cc::SkottieFrameDataProvider::ImageAsset>>
- image_assets_;
- float playback_speed_ = 1.f;
- };
- } // namespace lottie
- #endif // UI_LOTTIE_ANIMATION_H_
|