12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727 |
- // 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.
- #include "ui/lottie/animation.h"
- #include <map>
- #include <string>
- #include "base/check.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/ref_counted_memory.h"
- #include "base/memory/scoped_refptr.h"
- #include "base/scoped_observation.h"
- #include "base/test/simple_test_tick_clock.h"
- #include "cc/paint/display_item_list.h"
- #include "cc/paint/paint_op_buffer.h"
- #include "cc/paint/paint_record.h"
- #include "cc/paint/record_paint_canvas.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_wrapper.h"
- #include "cc/test/lottie_test_data.h"
- #include "cc/test/skia_common.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "third_party/skia/include/core/SkBitmap.h"
- #include "third_party/skia/include/core/SkRect.h"
- #include "third_party/skia/include/core/SkStream.h"
- #include "ui/gfx/canvas.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/lottie/animation_observer.h"
- namespace lottie {
- namespace {
- using ::testing::ElementsAre;
- using ::testing::Eq;
- using ::testing::FieldsAre;
- using ::testing::FloatEq;
- using ::testing::FloatNear;
- using ::testing::IsEmpty;
- using ::testing::NotNull;
- using ::testing::Pair;
- using ::testing::SizeIs;
- using ::testing::UnorderedElementsAre;
- // A skottie animation with solid green color for the first 2.5 seconds and then
- // a solid blue color for the next 2.5 seconds.
- constexpr char kData[] =
- "{"
- " \"v\" : \"4.12.0\","
- " \"fr\": 30,"
- " \"w\" : 400,"
- " \"h\" : 200,"
- " \"ip\": 0,"
- " \"op\": 150,"
- " \"assets\": [],"
- " \"layers\": ["
- " {"
- " \"ty\": 1,"
- " \"sw\": 400,"
- " \"sh\": 200,"
- " \"sc\": \"#00ff00\","
- " \"ip\": 0,"
- " \"op\": 75"
- " },"
- " {"
- " \"ty\": 1,"
- " \"sw\": 400,"
- " \"sh\": 200,"
- " \"sc\": \"#0000ff\","
- " \"ip\": 76,"
- " \"op\": 150"
- " }"
- " ]"
- "}";
- constexpr float kAnimationWidth = 400.f;
- constexpr float kAnimationHeight = 200.f;
- constexpr auto kAnimationDuration = base::Seconds(5);
- constexpr float kCanvasImageScale = 2.f;
- constexpr float kFrameTimestampToleranceSec = 0.1f;
- class TestAnimationObserver : public AnimationObserver {
- public:
- explicit TestAnimationObserver(Animation* animation) {
- observation_.Observe(animation);
- }
- ~TestAnimationObserver() override = default;
- TestAnimationObserver(const TestAnimationObserver&) = delete;
- TestAnimationObserver& operator=(const TestAnimationObserver&) = delete;
- void AnimationWillStartPlaying(const Animation* animation) override {
- animation_will_start_playing_ = true;
- }
- void AnimationCycleEnded(const Animation* animation) override {
- animation_cycle_ended_ = true;
- }
- void AnimationResuming(const Animation* animation) override {
- animation_resuming_ = true;
- }
- void AnimationFramePainted(const Animation* animation, float t) override {
- last_frame_painted_ = t;
- }
- void AnimationIsDeleting(const Animation* animation) override {
- animation_is_deleted_ = true;
- observation_.Reset();
- }
- void Reset() {
- animation_cycle_ended_ = false;
- animation_will_start_playing_ = false;
- animation_resuming_ = false;
- }
- bool animation_cycle_ended() const { return animation_cycle_ended_; }
- bool animation_will_start_playing() const {
- return animation_will_start_playing_;
- }
- bool animation_resuming() const { return animation_resuming_; }
- bool animation_is_deleted() const { return animation_is_deleted_; }
- const absl::optional<float>& last_frame_painted() const {
- return last_frame_painted_;
- }
- private:
- base::ScopedObservation<Animation, AnimationObserver> observation_{this};
- bool animation_cycle_ended_ = false;
- bool animation_will_start_playing_ = false;
- bool animation_resuming_ = false;
- bool animation_is_deleted_ = false;
- absl::optional<float> last_frame_painted_;
- };
- class TestSkottieFrameDataProvider : public cc::SkottieFrameDataProvider {
- public:
- class ImageAssetImpl : public cc::SkottieFrameDataProvider::ImageAsset {
- public:
- ImageAssetImpl() = default;
- ImageAssetImpl(const ImageAssetImpl& other) = delete;
- ImageAssetImpl& operator=(const ImageAssetImpl& other) = delete;
- cc::SkottieFrameData GetFrameData(float t, float scale_factor) override {
- last_frame_t_ = t;
- last_frame_scale_factor_ = scale_factor;
- return current_frame_data_;
- }
- void set_current_frame_data(cc::SkottieFrameData current_frame_data) {
- current_frame_data_ = std::move(current_frame_data);
- }
- const absl::optional<float>& last_frame_t() const { return last_frame_t_; }
- const absl::optional<float>& last_frame_scale_factor() const {
- return last_frame_scale_factor_;
- }
- private:
- friend class TestSkottieFrameDataProvider;
- ~ImageAssetImpl() override = default;
- cc::SkottieFrameData current_frame_data_;
- absl::optional<float> last_frame_t_;
- absl::optional<float> last_frame_scale_factor_;
- };
- TestSkottieFrameDataProvider() = default;
- TestSkottieFrameDataProvider(const TestSkottieFrameDataProvider&) = delete;
- TestSkottieFrameDataProvider& operator=(const TestSkottieFrameDataProvider&) =
- delete;
- ~TestSkottieFrameDataProvider() override = default;
- scoped_refptr<ImageAsset> LoadImageAsset(
- base::StringPiece resource_id,
- const base::FilePath& resource_path,
- const absl::optional<gfx::Size>& size) override {
- auto new_asset = base::MakeRefCounted<ImageAssetImpl>();
- CHECK(current_assets_.emplace(std::string(resource_id), new_asset).second);
- return new_asset;
- }
- ImageAssetImpl* GetLoadedImageAsset(const std::string& resource_id) {
- auto iter = current_assets_.find(resource_id);
- return iter == current_assets_.end() ? nullptr : iter->second.get();
- }
- private:
- std::map<std::string, scoped_refptr<ImageAssetImpl>> current_assets_;
- };
- } // namespace
- class AnimationTest : public testing::Test {
- public:
- AnimationTest() = default;
- ~AnimationTest() override = default;
- AnimationTest(const AnimationTest&) = delete;
- AnimationTest& operator=(const AnimationTest&) = delete;
- void SetUp() override {
- canvas_ = std::make_unique<gfx::Canvas>(
- gfx::Size(kAnimationWidth, kAnimationHeight), 1.f, false);
- skottie_ = cc::SkottieWrapper::CreateNonSerializable(
- base::as_bytes(base::make_span(kData, std::strlen(kData))));
- animation_ = std::make_unique<Animation>(skottie_);
- }
- void TearDown() override { animation_.reset(nullptr); }
- gfx::Canvas* canvas() { return canvas_.get(); }
- Animation::Style GetStyle() const {
- return animation_->playback_config_.style;
- }
- Animation::PlayState GetState() const { return animation_->state_; }
- bool IsStopped() const {
- return GetState() == Animation::PlayState::kStopped;
- }
- bool IsScheduledToPlay() const {
- return GetState() == Animation::PlayState::kSchedulePlay;
- }
- bool IsPlaying() const {
- return GetState() == Animation::PlayState::kPlaying;
- }
- bool IsScheduledToResume() const {
- return GetState() == Animation::PlayState::kScheduleResume;
- }
- bool HasAnimationEnded() const {
- return GetState() == Animation::PlayState::kEnded;
- }
- bool IsPaused() const { return GetState() == Animation::PlayState::kPaused; }
- const Animation::TimerControl* GetTimerControl() const {
- return animation_->timer_control_.get();
- }
- const base::TickClock* test_clock() const { return &test_clock_; }
- void AdvanceClock(base::TimeDelta advance) { test_clock_.Advance(advance); }
- base::TimeDelta TimeDeltaSince(const base::TimeTicks& ticks) const {
- return test_clock_.NowTicks() - ticks;
- }
- base::TimeTicks NowTicks() const { return test_clock_.NowTicks(); }
- double GetTimerStartOffset() const {
- return animation_->timer_control_->GetNormalizedStartOffset();
- }
- double GetTimerEndOffset() const {
- return animation_->timer_control_->GetNormalizedEndOffset();
- }
- const base::TimeTicks& GetTimerPreviousTick() const {
- return animation_->timer_control_->previous_tick_;
- }
- base::TimeDelta GetTimerTotalDuration() const {
- return animation_->timer_control_->total_duration_;
- }
- int GetTimerCycles() const {
- return animation_->timer_control_->completed_cycles();
- }
- void IsAllSameColor(SkColor color, const SkBitmap& bitmap) const {
- if (bitmap.colorType() == kBGRA_8888_SkColorType) {
- const SkColor* pixels = reinterpret_cast<SkColor*>(bitmap.getPixels());
- const int num_pixels = bitmap.width() * bitmap.height();
- for (int i = 0; i < num_pixels; i++)
- EXPECT_EQ(pixels[i], color);
- } else {
- for (int x = 0; x < bitmap.width(); x++)
- for (int y = 0; y < bitmap.height(); y++)
- EXPECT_EQ(bitmap.getColor(x, y), color);
- }
- }
- protected:
- std::unique_ptr<gfx::Canvas> canvas_;
- std::unique_ptr<Animation> animation_;
- scoped_refptr<cc::SkottieWrapper> skottie_;
- private:
- base::SimpleTestTickClock test_clock_;
- };
- class AnimationWithImageAssetsTest : public AnimationTest {
- protected:
- AnimationWithImageAssetsTest()
- : display_list_(base::MakeRefCounted<cc::DisplayItemList>(
- cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer)),
- record_canvas_(display_list_.get(),
- SkRect::MakeIWH(cc::kLottieDataWith2AssetsWidth,
- cc::kLottieDataWith2AssetsHeight)) {}
- void SetUp() override {
- canvas_ = std::make_unique<gfx::Canvas>(&record_canvas_, kCanvasImageScale);
- skottie_ = cc::CreateSkottieFromString(cc::kLottieDataWith2Assets);
- animation_ = std::make_unique<Animation>(skottie_, cc::SkottieColorMap(),
- &frame_data_provider_);
- asset_0_ = frame_data_provider_.GetLoadedImageAsset("image_0");
- asset_1_ = frame_data_provider_.GetLoadedImageAsset("image_1");
- ASSERT_THAT(asset_0_, NotNull());
- ASSERT_THAT(asset_1_, NotNull());
- }
- cc::SkottieFrameData CreateHighQualityTestFrameData() {
- return {
- .image = cc::CreateDiscardablePaintImage(animation_->GetOriginalSize()),
- .quality = cc::PaintFlags::FilterQuality::kHigh};
- }
- const scoped_refptr<cc::DisplayItemList> display_list_;
- cc::RecordPaintCanvas record_canvas_;
- TestSkottieFrameDataProvider frame_data_provider_;
- raw_ptr<TestSkottieFrameDataProvider::ImageAssetImpl> asset_0_;
- raw_ptr<TestSkottieFrameDataProvider::ImageAssetImpl> asset_1_;
- };
- TEST_F(AnimationTest, InitializationAndLoadingData) {
- skottie_ = cc::SkottieWrapper::CreateNonSerializable(
- base::as_bytes(base::make_span(kData, std::strlen(kData))));
- animation_ = std::make_unique<Animation>(skottie_);
- EXPECT_FLOAT_EQ(animation_->GetOriginalSize().width(), kAnimationWidth);
- EXPECT_FLOAT_EQ(animation_->GetOriginalSize().height(), kAnimationHeight);
- EXPECT_EQ(animation_->GetAnimationDuration(), kAnimationDuration);
- EXPECT_TRUE(IsStopped());
- skottie_ = cc::SkottieWrapper::CreateNonSerializable(
- base::as_bytes(base::make_span(kData, std::strlen(kData))));
- animation_ = std::make_unique<Animation>(skottie_);
- EXPECT_FLOAT_EQ(animation_->GetOriginalSize().width(), kAnimationWidth);
- EXPECT_FLOAT_EQ(animation_->GetOriginalSize().height(), kAnimationHeight);
- EXPECT_EQ(animation_->GetAnimationDuration(), kAnimationDuration);
- EXPECT_TRUE(IsStopped());
- }
- TEST_F(AnimationTest, PlayLinearAnimation) {
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- EXPECT_TRUE(IsStopped());
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLinear, *animation_));
- EXPECT_TRUE(IsScheduledToPlay());
- EXPECT_FALSE(observer.animation_will_start_playing());
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_FALSE(IsScheduledToPlay());
- EXPECT_TRUE(IsPlaying());
- EXPECT_TRUE(observer.animation_will_start_playing());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0);
- EXPECT_FLOAT_EQ(GetTimerStartOffset(), 0);
- EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.f);
- IsAllSameColor(SK_ColorGREEN, canvas()->GetBitmap());
- EXPECT_EQ(GetTimerTotalDuration(), kAnimationDuration);
- constexpr auto kAdvance = base::Milliseconds(50);
- AdvanceClock(kAdvance);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kAdvance / kAnimationDuration);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), base::TimeDelta());
- IsAllSameColor(SK_ColorGREEN, canvas()->GetBitmap());
- // Advance the clock to the end of the animation.
- constexpr auto kAdvanceToEnd =
- kAnimationDuration - kAdvance + base::Milliseconds(1);
- AdvanceClock(kAdvanceToEnd);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvanceToEnd);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 1.f);
- EXPECT_TRUE(HasAnimationEnded());
- EXPECT_TRUE(observer.animation_cycle_ended());
- IsAllSameColor(SK_ColorBLUE, canvas()->GetBitmap());
- }
- TEST_F(AnimationTest, StopLinearAnimation) {
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLinear, *animation_));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_TRUE(IsPlaying());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0);
- constexpr auto kAdvance = base::Milliseconds(50);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kAdvance / kAnimationDuration);
- animation_->Stop();
- EXPECT_FALSE(animation_->GetCurrentProgress());
- EXPECT_TRUE(IsStopped());
- }
- TEST_F(AnimationTest, PlaySubsectionOfLinearAnimation) {
- constexpr auto kStartTime = base::Milliseconds(400);
- constexpr auto kDuration = base::Milliseconds(1000);
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- EXPECT_FALSE(observer.animation_cycle_ended());
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime, kStartTime + kDuration}}, /*initial_offset=*/kStartTime,
- /*initial_completed_cycles=*/0, Animation::Style::kLinear));
- EXPECT_TRUE(IsScheduledToPlay());
- EXPECT_FALSE(observer.animation_will_start_playing());
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_FALSE(IsScheduledToPlay());
- EXPECT_TRUE(IsPlaying());
- EXPECT_TRUE(observer.animation_will_start_playing());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerStartOffset());
- EXPECT_FLOAT_EQ(GetTimerEndOffset(),
- (kStartTime + kDuration) / kAnimationDuration);
- EXPECT_EQ(GetTimerTotalDuration(), kAnimationDuration);
- constexpr auto kAdvance = base::Milliseconds(100);
- AdvanceClock(kAdvance);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), base::TimeDelta());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- EXPECT_FALSE(observer.animation_cycle_ended());
- // Advance clock another 300 ms.
- constexpr auto kAdvance2 = base::Milliseconds(300);
- AdvanceClock(kAdvance2);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvance2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0);
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance + kAdvance2) / kAnimationDuration);
- EXPECT_FALSE(observer.animation_cycle_ended());
- // Reach the end of animation.
- constexpr auto kAdvanceToEnd =
- kDuration - kAdvance - kAdvance2 + base::Milliseconds(1);
- AdvanceClock(kAdvanceToEnd);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvanceToEnd);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerEndOffset());
- EXPECT_TRUE(observer.animation_cycle_ended());
- EXPECT_TRUE(HasAnimationEnded());
- }
- TEST_F(AnimationTest, PausingLinearAnimation) {
- constexpr auto kStartTime = base::Milliseconds(400);
- constexpr auto kDuration = base::Milliseconds(1000);
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(200));
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime, kStartTime + kDuration}}, /*initial_offset=*/kStartTime,
- /*initial_completed_cycles=*/0, Animation::Style::kLinear));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- constexpr auto kAdvance = base::Milliseconds(100);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- AdvanceClock(kAdvance);
- animation_->Pause();
- EXPECT_TRUE(IsPaused());
- // Advancing clock and stepping animation should have no effect when animation
- // is paused.
- AdvanceClock(kAnimationDuration);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- // Resume playing the animation.
- animation_->ResumePlaying();
- EXPECT_TRUE(IsScheduledToResume());
- // There should be no progress, since we haven't advanced the clock yet.
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_TRUE(IsPlaying());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance * 2) / kAnimationDuration);
- AdvanceClock(kDuration - kAdvance * 2 + base::Milliseconds(1));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- }
- TEST_F(AnimationTest, PlayLoopAnimation) {
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- EXPECT_TRUE(IsStopped());
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLoop, *animation_));
- EXPECT_TRUE(IsScheduledToPlay());
- EXPECT_FALSE(observer.animation_will_start_playing());
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_FALSE(IsScheduledToPlay());
- EXPECT_TRUE(IsPlaying());
- EXPECT_TRUE(observer.animation_will_start_playing());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0);
- EXPECT_FLOAT_EQ(GetTimerStartOffset(), 0);
- EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.0f);
- EXPECT_EQ(GetTimerTotalDuration(), kAnimationDuration);
- constexpr auto kAdvance = base::Milliseconds(50);
- AdvanceClock(kAdvance);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kAdvance / kAnimationDuration);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), base::TimeDelta());
- // Advance the clock to the end of the animation.
- AdvanceClock(kAnimationDuration - kAdvance);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()),
- kAnimationDuration - kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_EQ(GetTimerCycles(), 1);
- EXPECT_TRUE(std::abs(*animation_->GetCurrentProgress() - 0.f) < 0.0001f);
- EXPECT_TRUE(observer.animation_cycle_ended());
- EXPECT_TRUE(IsPlaying());
- }
- TEST_F(AnimationTest, PlaySubsectionOfLoopAnimation) {
- constexpr auto kStartTime = base::Milliseconds(400);
- constexpr auto kDuration = base::Milliseconds(1000);
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- EXPECT_TRUE(IsStopped());
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime, kStartTime + kDuration}}, /*initial_offset=*/kStartTime,
- /*initial_completed_cycles=*/0, Animation::Style::kLoop));
- EXPECT_TRUE(IsScheduledToPlay());
- EXPECT_FALSE(observer.animation_will_start_playing());
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_FALSE(IsScheduledToPlay());
- EXPECT_TRUE(IsPlaying());
- EXPECT_TRUE(observer.animation_will_start_playing());
- EXPECT_FALSE(observer.animation_cycle_ended());
- EXPECT_FLOAT_EQ(GetTimerStartOffset(), kStartTime / kAnimationDuration);
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerStartOffset());
- EXPECT_FLOAT_EQ(GetTimerEndOffset(),
- (kStartTime + kDuration) / kAnimationDuration);
- EXPECT_EQ(GetTimerTotalDuration(), kAnimationDuration);
- constexpr auto kAdvance = base::Milliseconds(100);
- AdvanceClock(kAdvance);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvance);
- EXPECT_FALSE(observer.animation_cycle_ended());
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0);
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- constexpr auto kAdvance2 = base::Milliseconds(300);
- AdvanceClock(kAdvance2);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvance2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0);
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance + kAdvance2) / kAnimationDuration);
- EXPECT_FALSE(observer.animation_cycle_ended());
- // Reach the end of animation.
- AdvanceClock(kDuration - kAdvance - kAdvance2);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()),
- kDuration - kAdvance - kAdvance2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_TRUE(observer.animation_cycle_ended());
- EXPECT_TRUE(IsPlaying());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerStartOffset());
- }
- TEST_F(AnimationTest, PlayDifferentSubsectionsOfLoopingAnimation) {
- constexpr auto kStartTime1 = base::Milliseconds(400);
- constexpr auto kDuration1 = base::Milliseconds(1000);
- constexpr auto kStartTime2 = base::Milliseconds(100);
- constexpr auto kDuration2 = base::Milliseconds(500);
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime1, kStartTime1 + kDuration1},
- {kStartTime2, kStartTime2 + kDuration2}},
- /*initial_offset=*/kStartTime1,
- /*initial_completed_cycles=*/0, Animation::Style::kLoop));
- // T: 400 ms
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kStartTime1 / kAnimationDuration);
- // T: 600 ms
- AdvanceClock(base::Milliseconds(200));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime1 + base::Milliseconds(200)) / kAnimationDuration);
- // T: 1399 ms (just before first cycle end)
- AdvanceClock(base::Milliseconds(799));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(
- *animation_->GetCurrentProgress(),
- (kStartTime1 + kDuration1 - base::Milliseconds(1)) / kAnimationDuration);
- // T: 100 ms (start of second cycle)
- AdvanceClock(base::Milliseconds(1));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kStartTime2 / kAnimationDuration);
- // T: 300 ms
- AdvanceClock(base::Milliseconds(200));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime2 + base::Milliseconds(200)) / kAnimationDuration);
- // T: 599 ms (just before second cycle end)
- AdvanceClock(base::Milliseconds(299));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(
- *animation_->GetCurrentProgress(),
- (kStartTime2 + kDuration2 - base::Milliseconds(1)) / kAnimationDuration);
- // T: 100 ms (start of second cycle)
- AdvanceClock(base::Milliseconds(1));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kStartTime2 / kAnimationDuration);
- }
- TEST_F(AnimationTest, HandlesLargeStepsInLoopingAnimation) {
- constexpr auto kStartTime1 = base::Milliseconds(400);
- constexpr auto kDuration1 = base::Milliseconds(1000);
- constexpr auto kStartTime2 = base::Milliseconds(100);
- constexpr auto kDuration2 = base::Milliseconds(500);
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime1, kStartTime1 + kDuration1},
- {kStartTime2, kStartTime2 + kDuration2}},
- /*initial_offset=*/kStartTime1,
- /*initial_completed_cycles=*/0, Animation::Style::kLoop));
- // T: 400 ms
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kStartTime1 / kAnimationDuration);
- // T: 200 ms (end of first cycle + 100 ms into second cycle)
- AdvanceClock(kDuration1 + base::Milliseconds(100));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime2 + base::Milliseconds(100)) / kAnimationDuration);
- // T: 300 ms (end of second cycle + 200 ms into third cycle)
- AdvanceClock(base::Milliseconds(600));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime2 + base::Milliseconds(200)) / kAnimationDuration);
- }
- TEST_F(AnimationTest, PausingLoopAnimation) {
- constexpr auto kStartTime = base::Milliseconds(400);
- constexpr auto kDuration = base::Milliseconds(1000);
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(200));
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime, kStartTime + kDuration}}, /*initial_offset=*/kStartTime,
- /*initial_completed_cycles=*/0, Animation::Style::kLoop));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kStartTime / kAnimationDuration);
- constexpr auto kAdvance = base::Milliseconds(100);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- AdvanceClock(kAdvance);
- animation_->Pause();
- EXPECT_TRUE(IsPaused());
- // Advancing clock and stepping animation should have no effect when animation
- // is paused.
- AdvanceClock(kAnimationDuration);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- // Resume playing the animation.
- animation_->ResumePlaying();
- EXPECT_TRUE(IsScheduledToResume());
- // There should be no progress, since we haven't advanced the clock yet.
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_TRUE(IsPlaying());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance * 2) / kAnimationDuration);
- EXPECT_FALSE(observer.animation_cycle_ended());
- AdvanceClock(kDuration - kAdvance * 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerStartOffset());
- EXPECT_TRUE(IsPlaying());
- EXPECT_TRUE(observer.animation_cycle_ended());
- }
- TEST_F(AnimationTest, PlayThrobbingAnimation) {
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kThrobbing, *animation_));
- EXPECT_TRUE(IsScheduledToPlay());
- EXPECT_FALSE(observer.animation_will_start_playing());
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_FALSE(IsScheduledToPlay());
- EXPECT_TRUE(IsPlaying());
- EXPECT_TRUE(observer.animation_will_start_playing());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0);
- EXPECT_FLOAT_EQ(GetTimerStartOffset(), 0);
- EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.0f);
- EXPECT_EQ(GetTimerTotalDuration(), kAnimationDuration);
- constexpr auto kAdvance = base::Milliseconds(50);
- AdvanceClock(kAdvance);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kAdvance / kAnimationDuration);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), base::TimeDelta());
- // Advance the clock to the end of the animation.
- AdvanceClock(kAnimationDuration - kAdvance);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()),
- kAnimationDuration - kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 1.0f);
- EXPECT_TRUE(IsPlaying());
- EXPECT_FALSE(observer.animation_cycle_ended());
- AdvanceClock(kAnimationDuration / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0.5f);
- EXPECT_TRUE(IsPlaying());
- EXPECT_FALSE(observer.animation_cycle_ended());
- AdvanceClock(kAnimationDuration / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0);
- EXPECT_TRUE(IsPlaying());
- EXPECT_TRUE(observer.animation_cycle_ended());
- }
- TEST_F(AnimationTest, PlaySubsectionOfThrobbingAnimation) {
- constexpr auto kStartTime = base::Milliseconds(400);
- constexpr auto kDuration = base::Milliseconds(1000);
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime, kStartTime + kDuration}}, /*initial_offset=*/kStartTime,
- /*initial_completed_cycles=*/0, Animation::Style::kThrobbing));
- EXPECT_TRUE(IsScheduledToPlay());
- EXPECT_FALSE(observer.animation_will_start_playing());
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_FALSE(IsScheduledToPlay());
- EXPECT_TRUE(IsPlaying());
- EXPECT_TRUE(observer.animation_will_start_playing());
- EXPECT_FLOAT_EQ(GetTimerStartOffset(), kStartTime / kAnimationDuration);
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerStartOffset());
- EXPECT_FLOAT_EQ(GetTimerEndOffset(),
- (kStartTime + kDuration) / kAnimationDuration);
- EXPECT_EQ(GetTimerTotalDuration(), kAnimationDuration);
- constexpr auto kAdvance = base::Milliseconds(100);
- AdvanceClock(kAdvance);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_FALSE(observer.animation_cycle_ended());
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0);
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- constexpr auto kAdvance2 = base::Milliseconds(300);
- AdvanceClock(kAdvance2);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), kAdvance2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_FALSE(observer.animation_cycle_ended());
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()), base::TimeDelta());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance + kAdvance2) / kAnimationDuration);
- // Reach the end of animation.
- AdvanceClock(kDuration - kAdvance - kAdvance2);
- EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()),
- kDuration - kAdvance - kAdvance2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_TRUE(IsPlaying());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerEndOffset());
- EXPECT_FALSE(observer.animation_cycle_ended());
- constexpr auto kAdvance3 = base::Milliseconds(500);
- AdvanceClock(kAdvance3);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kDuration - kAdvance3) / kAnimationDuration);
- EXPECT_TRUE(IsPlaying());
- EXPECT_FALSE(observer.animation_cycle_ended());
- AdvanceClock(kDuration - kAdvance3);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerStartOffset());
- EXPECT_TRUE(IsPlaying());
- EXPECT_TRUE(observer.animation_cycle_ended());
- observer.Reset();
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- EXPECT_TRUE(IsPlaying());
- }
- TEST_F(AnimationTest, PlayDifferentSubsectionsOfThrobbingAnimation) {
- constexpr auto kStartTime1 = base::Milliseconds(400);
- constexpr auto kDuration1 = base::Milliseconds(1000);
- constexpr auto kStartTime2 = base::Milliseconds(100);
- constexpr auto kDuration2 = base::Milliseconds(500);
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime1, kStartTime1 + kDuration1},
- {kStartTime2, kStartTime2 + kDuration2}},
- /*initial_offset=*/kStartTime1,
- /*initial_completed_cycles=*/0, Animation::Style::kThrobbing));
- // T: 400 ms
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kStartTime1 / kAnimationDuration);
- // T: 600 ms
- AdvanceClock(base::Milliseconds(200));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime1 + base::Milliseconds(200)) / kAnimationDuration);
- // T: 1399 ms (just before first cycle end)
- AdvanceClock(base::Milliseconds(799));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(
- *animation_->GetCurrentProgress(),
- (kStartTime1 + kDuration1 - base::Milliseconds(1)) / kAnimationDuration);
- // T: 600 ms (end of second cycle, reversed)
- AdvanceClock(base::Milliseconds(1));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime2 + kDuration2) / kAnimationDuration);
- // T: 400 ms
- AdvanceClock(base::Milliseconds(200));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime2 + kDuration2 - base::Milliseconds(200)) /
- kAnimationDuration);
- // T: 101 ms (just after start of second cycle start)
- AdvanceClock(base::Milliseconds(299));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime2 + base::Milliseconds(1)) / kAnimationDuration);
- // T: 100 ms (start of second cycle)
- AdvanceClock(base::Milliseconds(1));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kStartTime2 / kAnimationDuration);
- // T: 300 ms (going forward)
- AdvanceClock(base::Milliseconds(200));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime2 + base::Milliseconds(200)) / kAnimationDuration);
- }
- TEST_F(AnimationTest, HandlesLargeStepsInThrobbingAnimation) {
- constexpr auto kStartTime1 = base::Milliseconds(400);
- constexpr auto kDuration1 = base::Milliseconds(1000);
- constexpr auto kStartTime2 = base::Milliseconds(100);
- constexpr auto kDuration2 = base::Milliseconds(500);
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime1, kStartTime1 + kDuration1},
- {kStartTime2, kStartTime2 + kDuration2}},
- /*initial_offset=*/kStartTime1,
- /*initial_completed_cycles=*/0, Animation::Style::kThrobbing));
- // T: 400 ms
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kStartTime1 / kAnimationDuration);
- // T: 500 ms (end of first cycle + 100 ms into second cycle)
- AdvanceClock(kDuration1 + base::Milliseconds(100));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime2 + kDuration2 - base::Milliseconds(100)) /
- kAnimationDuration);
- // T: 300 ms (end of second cycle + 200 ms into third cycle)
- AdvanceClock(base::Milliseconds(600));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime2 + base::Milliseconds(200)) / kAnimationDuration);
- }
- TEST_F(AnimationTest, PausingThrobbingAnimation) {
- constexpr auto kStartTime = base::Milliseconds(400);
- constexpr auto kDuration = base::Milliseconds(1000);
- AdvanceClock(base::Milliseconds(200));
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime, kStartTime + kDuration}}, /*initial_offset=*/kStartTime,
- /*initial_completed_cycles=*/0, Animation::Style::kThrobbing));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_TRUE(IsPlaying());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kStartTime / kAnimationDuration);
- constexpr auto kAdvance = base::Milliseconds(100);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- AdvanceClock(kAdvance);
- animation_->Pause();
- EXPECT_TRUE(IsPaused());
- // Advancing clock and stepping animation should have no effect when animation
- // is paused.
- AdvanceClock(kAnimationDuration);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- // Resume playing the animation.
- animation_->ResumePlaying();
- EXPECT_TRUE(IsScheduledToResume());
- // There should be no progress, since we haven't advanced the clock yet.
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_TRUE(IsPlaying());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance * 2) / kAnimationDuration);
- AdvanceClock(kDuration - kAdvance * 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerEndOffset());
- EXPECT_TRUE(IsPlaying());
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kDuration - kAdvance) / kAnimationDuration);
- EXPECT_TRUE(IsPlaying());
- animation_->Pause();
- EXPECT_TRUE(IsPaused());
- AdvanceClock(kAnimationDuration * 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kDuration - kAdvance) / kAnimationDuration);
- // Resume playing the animation.
- animation_->ResumePlaying();
- EXPECT_TRUE(IsScheduledToResume());
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_TRUE(IsPlaying());
- constexpr auto kAdvance2 = base::Milliseconds(500);
- AdvanceClock(kAdvance2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_FLOAT_EQ(
- *animation_->GetCurrentProgress(),
- (kStartTime + kDuration - kAdvance - kAdvance2) / kAnimationDuration);
- AdvanceClock(kDuration - kAdvance - kAdvance2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerStartOffset());
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + kAdvance) / kAnimationDuration);
- EXPECT_TRUE(IsPlaying());
- }
- // Test to see if the race condition is handled correctly. It may happen that we
- // pause the video before it even starts playing.
- TEST_F(AnimationTest, PauseBeforePlay) {
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start();
- EXPECT_TRUE(IsScheduledToPlay());
- EXPECT_FALSE(animation_->GetCurrentProgress());
- animation_->Pause();
- EXPECT_TRUE(IsPaused());
- EXPECT_FALSE(animation_->GetCurrentProgress());
- AdvanceClock(base::Milliseconds(100));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerStartOffset());
- animation_->ResumePlaying();
- EXPECT_TRUE(IsScheduledToResume());
- AdvanceClock(base::Milliseconds(100));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- EXPECT_TRUE(IsPlaying());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), GetTimerStartOffset());
- constexpr auto kAdvance = base::Milliseconds(100);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kAdvance / kAnimationDuration);
- }
- TEST_F(AnimationTest, PaintTest) {
- gfx::Canvas canvas(gfx::Size(kAnimationWidth, kAnimationHeight), 1.f, false);
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLinear, *animation_));
- animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
- AdvanceClock(base::Milliseconds(50));
- animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
- IsAllSameColor(SK_ColorGREEN, canvas.GetBitmap());
- AdvanceClock(base::Milliseconds(2450));
- animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
- IsAllSameColor(SK_ColorGREEN, canvas.GetBitmap());
- AdvanceClock(base::Milliseconds(50));
- animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
- IsAllSameColor(SK_ColorBLUE, canvas.GetBitmap());
- AdvanceClock(base::Milliseconds(1000));
- animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
- IsAllSameColor(SK_ColorBLUE, canvas.GetBitmap());
- AdvanceClock(base::Milliseconds(1400));
- animation_->Paint(&canvas, NowTicks(), animation_->GetOriginalSize());
- IsAllSameColor(SK_ColorBLUE, canvas.GetBitmap());
- }
- TEST_F(AnimationTest, NotifiesObserverFramePainted) {
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLoop, *animation_));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(observer.last_frame_painted());
- EXPECT_EQ(*observer.last_frame_painted(), 0.f);
- AdvanceClock(kAnimationDuration / 4);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(observer.last_frame_painted());
- EXPECT_FLOAT_EQ(*observer.last_frame_painted(), 0.25f);
- AdvanceClock(kAnimationDuration / 4);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(observer.last_frame_painted());
- EXPECT_FLOAT_EQ(*observer.last_frame_painted(), 0.5f);
- AdvanceClock(kAnimationDuration / 2 - base::Milliseconds(1));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(observer.last_frame_painted());
- EXPECT_NEAR(*observer.last_frame_painted(), 1.f, 1E-3);
- AdvanceClock(base::Milliseconds(2));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(observer.last_frame_painted());
- EXPECT_FLOAT_EQ(*observer.last_frame_painted(),
- base::Milliseconds(1) / kAnimationDuration);
- }
- TEST_F(AnimationTest, SetsPlaybackSpeed) {
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->SetPlaybackSpeed(2);
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLinear, *animation_));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0);
- AdvanceClock(kAnimationDuration / 8);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 1.f / 4);
- AdvanceClock(kAnimationDuration / 8);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 1.f / 2);
- animation_->SetPlaybackSpeed(0.5f);
- AdvanceClock(kAnimationDuration / 4);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), (1.f / 2) + (1.f / 8));
- AdvanceClock(kAnimationDuration / 4);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 3.f / 4);
- }
- TEST_F(AnimationWithImageAssetsTest, PaintsAnimationImagesToCanvas) {
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLoop, *animation_));
- TestSkottieFrameDataProvider::ImageAssetImpl* asset_0 =
- frame_data_provider_.GetLoadedImageAsset("image_0");
- TestSkottieFrameDataProvider::ImageAssetImpl* asset_1 =
- frame_data_provider_.GetLoadedImageAsset("image_1");
- ASSERT_THAT(asset_0, NotNull());
- ASSERT_THAT(asset_1, NotNull());
- cc::SkottieFrameData frame_0 = CreateHighQualityTestFrameData();
- cc::SkottieFrameData frame_1 = CreateHighQualityTestFrameData();
- asset_0->set_current_frame_data(frame_0);
- asset_1->set_current_frame_data(frame_1);
- display_list_->StartPaint();
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- display_list_->EndPaintOfUnpaired(gfx::Rect(animation_->GetOriginalSize()));
- sk_sp<cc::PaintRecord> paint_record = display_list_->ReleaseAsRecord();
- ASSERT_THAT(paint_record, NotNull());
- ASSERT_THAT(paint_record->size(), Eq(1u));
- const cc::DrawSkottieOp* op =
- paint_record->GetOpAtForTesting<cc::DrawSkottieOp>(0);
- ASSERT_THAT(op, NotNull());
- EXPECT_THAT(op->images, UnorderedElementsAre(Pair(
- cc::HashSkottieResourceId("image_0"), frame_0)));
- AdvanceClock(animation_->GetAnimationDuration() * .75);
- display_list_->StartPaint();
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- display_list_->EndPaintOfUnpaired(gfx::Rect(animation_->GetOriginalSize()));
- paint_record = display_list_->ReleaseAsRecord();
- ASSERT_THAT(paint_record, NotNull());
- ASSERT_THAT(paint_record->size(), Eq(1u));
- op = paint_record->GetOpAtForTesting<cc::DrawSkottieOp>(0);
- ASSERT_THAT(op, NotNull());
- EXPECT_THAT(op->images, UnorderedElementsAre(Pair(
- cc::HashSkottieResourceId("image_1"), frame_1)));
- }
- TEST_F(AnimationWithImageAssetsTest, GracefullyHandlesNullImages) {
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLoop, *animation_));
- display_list_->StartPaint();
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- display_list_->EndPaintOfUnpaired(gfx::Rect(animation_->GetOriginalSize()));
- sk_sp<cc::PaintRecord> paint_record = display_list_->ReleaseAsRecord();
- ASSERT_THAT(paint_record, NotNull());
- ASSERT_THAT(paint_record->size(), Eq(1u));
- const cc::DrawSkottieOp* op =
- paint_record->GetOpAtForTesting<cc::DrawSkottieOp>(0);
- ASSERT_THAT(op, NotNull());
- EXPECT_THAT(op->images,
- UnorderedElementsAre(Pair(cc::HashSkottieResourceId("image_0"),
- cc::SkottieFrameData())));
- }
- TEST_F(AnimationWithImageAssetsTest, LoadsCorrectFrameTimestamp) {
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLoop, *animation_));
- asset_0_->set_current_frame_data(CreateHighQualityTestFrameData());
- asset_1_->set_current_frame_data(CreateHighQualityTestFrameData());
- display_list_->StartPaint();
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- display_list_->EndPaintOfUnpaired(gfx::Rect(animation_->GetOriginalSize()));
- ASSERT_TRUE(asset_0_->last_frame_t().has_value());
- EXPECT_THAT(asset_0_->last_frame_t().value(), FloatEq(0));
- base::TimeDelta three_quarter_duration =
- animation_->GetAnimationDuration() * .75;
- AdvanceClock(three_quarter_duration);
- display_list_->StartPaint();
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- display_list_->EndPaintOfUnpaired(gfx::Rect(animation_->GetOriginalSize()));
- // The timestamp is "relative to the image layer timeline origin" (see
- // SkResources.h). The test animation used in this case has 2 layers for the
- // first and second halves of the animation. So the 3/4 point of the animation
- // is half way into the second layer, or 1/4 the duration of the whole
- // animation.
- base::TimeDelta half_duration = animation_->GetAnimationDuration() * .5;
- ASSERT_TRUE(asset_1_->last_frame_t().has_value());
- EXPECT_THAT(asset_1_->last_frame_t().value(),
- FloatNear((three_quarter_duration - half_duration).InSecondsF(),
- kFrameTimestampToleranceSec));
- AdvanceClock(half_duration);
- display_list_->StartPaint();
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- display_list_->EndPaintOfUnpaired(gfx::Rect(animation_->GetOriginalSize()));
- base::TimeDelta quarter_duration = animation_->GetAnimationDuration() / 4;
- ASSERT_TRUE(asset_0_->last_frame_t().has_value());
- EXPECT_THAT(
- asset_0_->last_frame_t().value(),
- FloatNear(quarter_duration.InSecondsF(), kFrameTimestampToleranceSec));
- }
- TEST_F(AnimationWithImageAssetsTest, LoadsCorrectImageScale) {
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLoop, *animation_));
- asset_0_->set_current_frame_data(CreateHighQualityTestFrameData());
- display_list_->StartPaint();
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- display_list_->EndPaintOfUnpaired(gfx::Rect(animation_->GetOriginalSize()));
- ASSERT_TRUE(asset_0_->last_frame_scale_factor().has_value());
- EXPECT_THAT(asset_0_->last_frame_scale_factor().value(),
- FloatEq(kCanvasImageScale));
- }
- TEST_F(AnimationTest, HandlesTimeStepGreaterThanAnimationDuration) {
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLoop, *animation_));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0);
- AdvanceClock(kAnimationDuration / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0.5f);
- AdvanceClock(kAnimationDuration * 5);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0.5f);
- }
- class AnimationRestarter : public AnimationObserver {
- public:
- explicit AnimationRestarter(Animation* animation) : animation_(animation) {
- observation_.Observe(animation);
- }
- AnimationRestarter(const AnimationRestarter&) = delete;
- AnimationRestarter& operator=(const AnimationRestarter&) = delete;
- ~AnimationRestarter() override = default;
- void AnimationCycleEnded(const Animation* animation) override {
- animation_->Stop();
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLinear, *animation_));
- }
- private:
- const base::raw_ptr<Animation> animation_;
- base::ScopedObservation<Animation, AnimationObserver> observation_{this};
- };
- TEST_F(AnimationTest, HandlesChangingAnimationStateWithinObserverCall) {
- AnimationRestarter observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLinear, *animation_));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- // Advance the clock to the end of the animation.
- constexpr auto kAdvanceToEnd = kAnimationDuration + base::Milliseconds(1);
- AdvanceClock(kAdvanceToEnd);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- // The AnimationRestarter should have restarted the animation again from the
- // beginning.
- constexpr auto kAdvance = base::Milliseconds(50);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(), 0.f);
- AdvanceClock(kAdvance);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- kAdvance / kAnimationDuration);
- }
- TEST_F(AnimationTest, NotifiesAnimationIsDeleting) {
- TestAnimationObserver observer_1(animation_.get());
- TestAnimationObserver observer_2(animation_.get());
- ASSERT_FALSE(observer_1.animation_is_deleted());
- ASSERT_FALSE(observer_2.animation_is_deleted());
- animation_.reset();
- EXPECT_TRUE(observer_1.animation_is_deleted());
- EXPECT_TRUE(observer_2.animation_is_deleted());
- }
- TEST_F(AnimationTest, GetPlaybackConfig) {
- EXPECT_FALSE(animation_->GetPlaybackConfig());
- Animation::PlaybackConfig test_config(
- {{/*start_offset=*/kAnimationDuration / 4,
- /*end_offset=*/kAnimationDuration * 3 / 4}},
- /*initial_offset=*/kAnimationDuration / 2,
- /*initial_completed_cycles=*/2, Animation::Style::kThrobbing);
- animation_->Start(test_config);
- ASSERT_TRUE(animation_->GetPlaybackConfig());
- EXPECT_THAT(
- *animation_->GetPlaybackConfig(),
- FieldsAre(ElementsAre(
- FieldsAre(test_config.scheduled_cycles.front().start_offset,
- test_config.scheduled_cycles.front().end_offset)),
- test_config.initial_offset,
- test_config.initial_completed_cycles, test_config.style));
- animation_->Stop();
- EXPECT_FALSE(animation_->GetPlaybackConfig());
- test_config.scheduled_cycles.front().start_offset = kAnimationDuration / 2;
- test_config.style = Animation::Style::kLoop;
- animation_->Start(test_config);
- ASSERT_TRUE(animation_->GetPlaybackConfig());
- EXPECT_THAT(
- *animation_->GetPlaybackConfig(),
- FieldsAre(ElementsAre(
- FieldsAre(test_config.scheduled_cycles.front().start_offset,
- test_config.scheduled_cycles.front().end_offset)),
- test_config.initial_offset,
- test_config.initial_completed_cycles, test_config.style));
- }
- TEST_F(AnimationTest, GetNumCompletedCycles) {
- EXPECT_FALSE(animation_->GetNumCompletedCycles());
- animation_->Start(Animation::PlaybackConfig::CreateDefault(*animation_));
- ASSERT_TRUE(animation_->GetNumCompletedCycles());
- EXPECT_THAT(*animation_->GetNumCompletedCycles(), Eq(0));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetNumCompletedCycles());
- EXPECT_THAT(*animation_->GetNumCompletedCycles(), Eq(0));
- AdvanceClock(kAnimationDuration / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetNumCompletedCycles());
- EXPECT_THAT(*animation_->GetNumCompletedCycles(), Eq(0));
- AdvanceClock(kAnimationDuration / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetNumCompletedCycles());
- EXPECT_THAT(*animation_->GetNumCompletedCycles(), Eq(1));
- AdvanceClock(kAnimationDuration);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetNumCompletedCycles());
- EXPECT_THAT(*animation_->GetNumCompletedCycles(), Eq(2));
- animation_->Stop();
- EXPECT_FALSE(animation_->GetNumCompletedCycles());
- }
- TEST_F(AnimationTest, GetNumCompletedCyclesLinear) {
- animation_->Start(Animation::PlaybackConfig::CreateWithStyle(
- Animation::Style::kLinear, *animation_));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetNumCompletedCycles());
- EXPECT_THAT(*animation_->GetNumCompletedCycles(), Eq(0));
- AdvanceClock(kAnimationDuration / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetNumCompletedCycles());
- EXPECT_THAT(*animation_->GetNumCompletedCycles(), Eq(0));
- AdvanceClock(kAnimationDuration / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetNumCompletedCycles());
- EXPECT_THAT(*animation_->GetNumCompletedCycles(), Eq(1));
- AdvanceClock(kAnimationDuration);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetNumCompletedCycles());
- EXPECT_THAT(*animation_->GetNumCompletedCycles(), Eq(1));
- }
- TEST_F(AnimationTest, StartsAtArbitraryInitialTimestamp) {
- constexpr auto kStartTime = base::Milliseconds(400);
- constexpr auto kDuration = base::Milliseconds(1000);
- AdvanceClock(base::Milliseconds(300));
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime, kStartTime + kDuration}},
- /*initial_offset=*/kStartTime + base::Milliseconds(100),
- /*initial_completed_cycles=*/0, Animation::Style::kThrobbing));
- // T: 500 ms
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + base::Milliseconds(100)) / kAnimationDuration);
- // T: 600 ms
- AdvanceClock(base::Milliseconds(100));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + base::Milliseconds(200)) / kAnimationDuration);
- animation_->Stop();
- // The animation has 1 completed cycle, so for a throbbing animation, it
- // should immediately start playing in reverse.
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime, kStartTime + kDuration}},
- /*initial_offset=*/kStartTime + base::Milliseconds(500),
- /*initial_completed_cycles=*/1, Animation::Style::kThrobbing));
- // T: 900 ms
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + base::Milliseconds(500)) / kAnimationDuration);
- // T: 800 ms
- AdvanceClock(base::Milliseconds(100));
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_FLOAT_EQ(*animation_->GetCurrentProgress(),
- (kStartTime + base::Milliseconds(400)) / kAnimationDuration);
- }
- TEST_F(AnimationTest, GetCurrentCycleBoundaries) {
- constexpr auto kStartTime1 = base::Milliseconds(400);
- constexpr auto kEndTime1 = base::Milliseconds(800);
- constexpr auto kDuration1 = kEndTime1 - kStartTime1;
- constexpr auto kStartTime2 = base::Milliseconds(100);
- constexpr auto kEndTime2 = base::Milliseconds(500);
- constexpr auto kDuration2 = kEndTime2 - kStartTime2;
- TestAnimationObserver observer(animation_.get());
- AdvanceClock(base::Milliseconds(300));
- EXPECT_FALSE(animation_->GetCurrentCycleBoundaries());
- animation_->Start(Animation::PlaybackConfig(
- {{kStartTime1, kEndTime1}, {kStartTime2, kEndTime2}},
- /*initial_offset=*/kStartTime1,
- /*initial_completed_cycles=*/0, Animation::Style::kLoop));
- // No frames have been painted yet.
- EXPECT_FALSE(animation_->GetCurrentCycleBoundaries());
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentCycleBoundaries());
- EXPECT_THAT(*animation_->GetCurrentCycleBoundaries(),
- FieldsAre(kStartTime1, kEndTime1));
- // T: 1/2 of first cycle
- AdvanceClock(kDuration1 / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_THAT(*animation_->GetCurrentCycleBoundaries(),
- FieldsAre(kStartTime1, kEndTime1));
- // T: Start of first cycle
- AdvanceClock(kDuration1 / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_THAT(*animation_->GetCurrentCycleBoundaries(),
- FieldsAre(kStartTime2, kEndTime2));
- // T: Middle of second cycle
- AdvanceClock(kDuration2 / 2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_THAT(*animation_->GetCurrentCycleBoundaries(),
- FieldsAre(kStartTime2, kEndTime2));
- // T: Middle of second cycle (again)
- AdvanceClock(kDuration2);
- animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize());
- ASSERT_TRUE(animation_->GetCurrentProgress());
- EXPECT_THAT(*animation_->GetCurrentCycleBoundaries(),
- FieldsAre(kStartTime2, kEndTime2));
- animation_->Stop();
- EXPECT_FALSE(animation_->GetCurrentCycleBoundaries());
- }
- } // namespace lottie
|