| // 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/gfx/skia_vector_animation.h" |
| |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "base/memory/ref_counted_memory.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/test/simple_test_tick_clock.h" |
| #include "cc/paint/skottie_wrapper.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "third_party/skia/include/core/SkStream.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/skia_vector_animation_observer.h" |
| |
| namespace gfx { |
| namespace { |
| |
| // 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 float kAnimationDuration = 5.f; |
| |
| class TestAnimationObserver : public SkiaVectorAnimationObserver { |
| public: |
| TestAnimationObserver() = default; |
| |
| void AnimationWillStartPlaying( |
| const SkiaVectorAnimation* animation) override { |
| animation_will_start_playing_ = true; |
| } |
| |
| void AnimationCycleEnded(const SkiaVectorAnimation* animation) override { |
| animation_cycle_ended_ = true; |
| } |
| |
| void AnimationResuming(const SkiaVectorAnimation* animation) override { |
| animation_resuming_ = true; |
| } |
| |
| 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_; } |
| |
| private: |
| bool animation_cycle_ended_ = false; |
| bool animation_will_start_playing_ = false; |
| bool animation_resuming_ = false; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestAnimationObserver); |
| }; |
| |
| } // namespace |
| |
| class SkiaVectorAnimationTest : public testing::Test { |
| public: |
| SkiaVectorAnimationTest() = default; |
| ~SkiaVectorAnimationTest() override {} |
| |
| void SetUp() override { |
| canvas_.reset(new gfx::Canvas(gfx::Size(kAnimationWidth, kAnimationHeight), |
| 1.f, false)); |
| skottie_ = base::MakeRefCounted<cc::SkottieWrapper>( |
| std::make_unique<SkMemoryStream>(kData, std::strlen(kData))); |
| animation_ = std::make_unique<SkiaVectorAnimation>(skottie_); |
| } |
| |
| void TearDown() override { animation_.reset(nullptr); } |
| |
| Canvas* canvas() { return canvas_.get(); } |
| |
| SkiaVectorAnimation::Style GetStyle() const { return animation_->style_; } |
| |
| SkiaVectorAnimation::PlayState GetState() const { return animation_->state_; } |
| |
| bool IsStopped() const { |
| return GetState() == SkiaVectorAnimation::PlayState::kStopped; |
| } |
| |
| bool IsScheduledToPlay() const { |
| return GetState() == SkiaVectorAnimation::PlayState::kSchedulePlay; |
| } |
| |
| bool IsPlaying() const { |
| return GetState() == SkiaVectorAnimation::PlayState::kPlaying; |
| } |
| |
| bool IsScheduledToResume() const { |
| return GetState() == SkiaVectorAnimation::PlayState::kScheduleResume; |
| } |
| |
| bool HasAnimationEnded() const { |
| return GetState() == SkiaVectorAnimation::PlayState::kEnded; |
| } |
| |
| bool IsPaused() const { |
| return GetState() == SkiaVectorAnimation::PlayState::kPaused; |
| } |
| |
| const SkiaVectorAnimation::TimerControl* GetTimerControl() const { |
| return animation_->timer_control_.get(); |
| } |
| |
| const base::TickClock* test_clock() const { return &test_clock_; } |
| |
| void AdvanceClock(int64_t ms) { |
| test_clock_.Advance(base::TimeDelta::FromMilliseconds(ms)); |
| } |
| |
| base::TimeDelta TimeDeltaSince(const base::TimeTicks& ticks) const { |
| return test_clock_.NowTicks() - ticks; |
| } |
| |
| const 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_; |
| } |
| |
| double GetTimerProgressPerMs() const { |
| return animation_->timer_control_->progress_per_millisecond_; |
| } |
| |
| 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<SkiaVectorAnimation> animation_; |
| scoped_refptr<cc::SkottieWrapper> skottie_; |
| |
| private: |
| std::unique_ptr<gfx::Canvas> canvas_; |
| base::SimpleTestTickClock test_clock_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SkiaVectorAnimationTest); |
| }; |
| |
| TEST_F(SkiaVectorAnimationTest, InitializationAndLoadingData) { |
| auto bytes = base::MakeRefCounted<base::RefCountedBytes>( |
| std::vector<unsigned char>(kData, kData + std::strlen(kData))); |
| skottie_ = base::MakeRefCounted<cc::SkottieWrapper>(bytes.get()); |
| animation_ = std::make_unique<SkiaVectorAnimation>(skottie_); |
| EXPECT_FLOAT_EQ(animation_->GetOriginalSize().width(), kAnimationWidth); |
| EXPECT_FLOAT_EQ(animation_->GetOriginalSize().height(), kAnimationHeight); |
| EXPECT_FLOAT_EQ(animation_->GetAnimationDuration().InSecondsF(), |
| kAnimationDuration); |
| EXPECT_TRUE(IsStopped()); |
| |
| skottie_ = base::MakeRefCounted<cc::SkottieWrapper>( |
| std::make_unique<SkMemoryStream>(kData, std::strlen(kData))); |
| animation_ = std::make_unique<SkiaVectorAnimation>(skottie_); |
| EXPECT_FLOAT_EQ(animation_->GetOriginalSize().width(), kAnimationWidth); |
| EXPECT_FLOAT_EQ(animation_->GetOriginalSize().height(), kAnimationHeight); |
| EXPECT_FLOAT_EQ(animation_->GetAnimationDuration().InSecondsF(), |
| kAnimationDuration); |
| EXPECT_TRUE(IsStopped()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PlayLinearAnimation) { |
| TestAnimationObserver observer; |
| animation_->SetAnimationObserver(&observer); |
| |
| // Advance clock by 300 milliseconds. |
| AdvanceClock(300); |
| |
| EXPECT_TRUE(IsStopped()); |
| animation_->Start(SkiaVectorAnimation::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()); |
| |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 0); |
| EXPECT_FLOAT_EQ(GetTimerStartOffset(), 0); |
| EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.f); |
| |
| EXPECT_FLOAT_EQ(GetTimerProgressPerMs(), 1.f / 5000.f); |
| |
| AdvanceClock(50); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 50); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 50.f / 5000.f); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0); |
| |
| // Advance the clock to the end of the animation. |
| AdvanceClock(4951); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 4951); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 1.f); |
| EXPECT_TRUE(HasAnimationEnded()); |
| EXPECT_TRUE(observer.animation_cycle_ended()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, StopLinearAnimation) { |
| TestAnimationObserver observer; |
| animation_->SetAnimationObserver(&observer); |
| |
| // Advance clock by 300 milliseconds. |
| AdvanceClock(300); |
| |
| animation_->Start(SkiaVectorAnimation::Style::kLinear); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_TRUE(IsPlaying()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 0); |
| |
| AdvanceClock(50); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 50.f / 5000.f); |
| |
| animation_->Stop(); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 0.f); |
| EXPECT_TRUE(IsStopped()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PlaySubsectionOfLinearAnimation) { |
| const int start_time_ms = 400; |
| const int duration_ms = 1000; |
| const float total_duration_ms = kAnimationDuration * 1000.f; |
| |
| TestAnimationObserver observer; |
| |
| animation_->SetAnimationObserver(&observer); |
| |
| // Advance clock by 300 milliseconds. |
| AdvanceClock(300); |
| |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| animation_->StartSubsection(base::TimeDelta::FromMilliseconds(start_time_ms), |
| base::TimeDelta::FromMilliseconds(duration_ms), |
| SkiaVectorAnimation::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()); |
| |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerStartOffset()); |
| EXPECT_FLOAT_EQ(GetTimerEndOffset(), |
| (start_time_ms + duration_ms) / total_duration_ms); |
| |
| EXPECT_FLOAT_EQ(GetTimerProgressPerMs(), 1.f / total_duration_ms); |
| |
| AdvanceClock(100); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 100); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (100.f + start_time_ms) / total_duration_ms); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| |
| // Advance clock another 300 ms. |
| AdvanceClock(300); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 300); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (100.f + 300.f + start_time_ms) / total_duration_ms); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| |
| // Reach the end of animation. |
| AdvanceClock(601); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 601); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerEndOffset()); |
| EXPECT_TRUE(observer.animation_cycle_ended()); |
| EXPECT_TRUE(HasAnimationEnded()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PausingLinearAnimation) { |
| const int start_time_ms = 400; |
| const int duration_ms = 1000; |
| const float total_duration_ms = kAnimationDuration * 1000.f; |
| TestAnimationObserver observer; |
| animation_->SetAnimationObserver(&observer); |
| |
| AdvanceClock(200); |
| |
| animation_->StartSubsection(base::TimeDelta::FromMilliseconds(start_time_ms), |
| base::TimeDelta::FromMilliseconds(duration_ms), |
| SkiaVectorAnimation::Style::kLinear); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 500.f / total_duration_ms); |
| |
| AdvanceClock(100); |
| animation_->Pause(); |
| EXPECT_TRUE(IsPaused()); |
| |
| // Advancing clock and stepping animation should have no effect when animation |
| // is paused. |
| AdvanceClock(5000); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 500.f / total_duration_ms); |
| |
| // 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()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 500.f / total_duration_ms); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 600.f / total_duration_ms); |
| |
| AdvanceClock(801); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PlayLoopAnimation) { |
| TestAnimationObserver observer; |
| animation_->SetAnimationObserver(&observer); |
| |
| // Advance clock by 300 milliseconds. |
| AdvanceClock(300); |
| |
| EXPECT_TRUE(IsStopped()); |
| animation_->Start(SkiaVectorAnimation::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_FLOAT_EQ(animation_->GetCurrentProgress(), 0); |
| EXPECT_FLOAT_EQ(GetTimerStartOffset(), 0); |
| EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.f); |
| |
| EXPECT_FLOAT_EQ(GetTimerProgressPerMs(), 1.f / 5000.f); |
| |
| AdvanceClock(50); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 50); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 50.f / 5000.f); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0); |
| |
| // Advance the clock to the end of the animation. |
| AdvanceClock(4950); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 4950); |
| 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(SkiaVectorAnimationTest, PlaySubsectionOfLoopAnimation) { |
| const int start_time_ms = 400; |
| const int duration_ms = 1000; |
| const float total_duration_ms = kAnimationDuration * 1000.f; |
| |
| |
| TestAnimationObserver observer; |
| animation_->SetAnimationObserver(&observer); |
| |
| // Advance clock by 300 milliseconds. |
| AdvanceClock(300); |
| EXPECT_TRUE(IsStopped()); |
| animation_->StartSubsection(base::TimeDelta::FromMilliseconds(start_time_ms), |
| base::TimeDelta::FromMilliseconds(duration_ms), |
| SkiaVectorAnimation::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(), 400.f / total_duration_ms); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerStartOffset()); |
| EXPECT_FLOAT_EQ(GetTimerEndOffset(), |
| (start_time_ms + duration_ms) / total_duration_ms); |
| |
| EXPECT_FLOAT_EQ(GetTimerProgressPerMs(), 1.f / total_duration_ms); |
| |
| AdvanceClock(100); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 100); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (100.f + start_time_ms) / total_duration_ms); |
| |
| // Advance clock another 300 ms. |
| AdvanceClock(300); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 300); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (100.f + 300.f + start_time_ms) / total_duration_ms); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| |
| // Reach the end of animation. |
| AdvanceClock(600); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 600); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_TRUE(observer.animation_cycle_ended()); |
| EXPECT_TRUE(IsPlaying()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerStartOffset()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PausingLoopAnimation) { |
| const int start_time_ms = 400; |
| const int duration_ms = 1000; |
| const float total_duration_ms = kAnimationDuration * 1000.f; |
| |
| TestAnimationObserver observer; |
| animation_->SetAnimationObserver(&observer); |
| |
| AdvanceClock(200); |
| |
| animation_->StartSubsection(base::TimeDelta::FromMilliseconds(start_time_ms), |
| base::TimeDelta::FromMilliseconds(duration_ms), |
| SkiaVectorAnimation::Style::kLoop); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 400.f / total_duration_ms); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 500.f / total_duration_ms); |
| |
| AdvanceClock(100); |
| animation_->Pause(); |
| EXPECT_TRUE(IsPaused()); |
| |
| // Advancing clock and stepping animation should have no effect when animation |
| // is paused. |
| AdvanceClock(5000); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 500.f / total_duration_ms); |
| |
| // 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()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 500.f / total_duration_ms); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 600.f / total_duration_ms); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| |
| AdvanceClock(800); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerStartOffset()); |
| EXPECT_TRUE(IsPlaying()); |
| EXPECT_TRUE(observer.animation_cycle_ended()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PlayThrobbingAnimation) { |
| |
| TestAnimationObserver observer; |
| animation_->SetAnimationObserver(&observer); |
| // Advance clock by 300 milliseconds. |
| AdvanceClock(300); |
| |
| animation_->Start(SkiaVectorAnimation::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(animation_->GetCurrentProgress(), 0); |
| EXPECT_FLOAT_EQ(GetTimerStartOffset(), 0); |
| EXPECT_FLOAT_EQ(GetTimerEndOffset(), 1.f); |
| |
| EXPECT_FLOAT_EQ(GetTimerProgressPerMs(), 1.f / 5000.f); |
| |
| AdvanceClock(50); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 50); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 50.f / 5000.f); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0); |
| |
| // Advance the clock to the end of the animation. |
| AdvanceClock(4950); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 4950); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 1.f); |
| EXPECT_TRUE(IsPlaying()); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| |
| AdvanceClock(2500); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 0.5f); |
| EXPECT_TRUE(IsPlaying()); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| |
| AdvanceClock(2500); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 0); |
| EXPECT_TRUE(IsPlaying()); |
| EXPECT_TRUE(observer.animation_cycle_ended()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PlaySubsectionOfThrobbingAnimation) { |
| const int start_time_ms = 400; |
| const int duration_ms = 1000; |
| const float total_duration_ms = kAnimationDuration * 1000.f; |
| |
| |
| TestAnimationObserver observer; |
| animation_->SetAnimationObserver(&observer); |
| |
| // Advance clock by 300 milliseconds. |
| AdvanceClock(300); |
| |
| animation_->StartSubsection(base::TimeDelta::FromMilliseconds(start_time_ms), |
| base::TimeDelta::FromMilliseconds(duration_ms), |
| SkiaVectorAnimation::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(), 400.f / total_duration_ms); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerStartOffset()); |
| EXPECT_FLOAT_EQ(GetTimerEndOffset(), |
| (start_time_ms + duration_ms) / total_duration_ms); |
| |
| EXPECT_FLOAT_EQ(GetTimerProgressPerMs(), 1.f / total_duration_ms); |
| |
| AdvanceClock(100); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 100); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (100.f + start_time_ms) / total_duration_ms); |
| |
| // Advance clock another 300 ms. |
| AdvanceClock(300); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 300); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 0); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (100.f + 300.f + start_time_ms) / total_duration_ms); |
| |
| // Reach the end of animation. |
| AdvanceClock(600); |
| EXPECT_EQ(TimeDeltaSince(GetTimerPreviousTick()).InMilliseconds(), 600); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_TRUE(IsPlaying()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerEndOffset()); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| |
| AdvanceClock(500); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 900.f / total_duration_ms); |
| EXPECT_TRUE(IsPlaying()); |
| EXPECT_FALSE(observer.animation_cycle_ended()); |
| |
| AdvanceClock(500); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerStartOffset()); |
| EXPECT_TRUE(IsPlaying()); |
| EXPECT_TRUE(observer.animation_cycle_ended()); |
| |
| observer.Reset(); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (start_time_ms + 100.f) / total_duration_ms); |
| EXPECT_TRUE(IsPlaying()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PausingThrobbingAnimation) { |
| const int start_time_ms = 400; |
| const int duration_ms = 1000; |
| const float total_duration_ms = kAnimationDuration * 1000.f; |
| |
| AdvanceClock(200); |
| |
| animation_->StartSubsection(base::TimeDelta::FromMilliseconds(start_time_ms), |
| base::TimeDelta::FromMilliseconds(duration_ms), |
| SkiaVectorAnimation::Style::kThrobbing); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| |
| EXPECT_TRUE(IsPlaying()); |
| |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| start_time_ms / total_duration_ms); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (start_time_ms + 100.f) / total_duration_ms); |
| |
| AdvanceClock(100); |
| animation_->Pause(); |
| EXPECT_TRUE(IsPaused()); |
| |
| // Advancing clock and stepping animation should have no effect when animation |
| // is paused. |
| AdvanceClock(5000); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (start_time_ms + 100.f) / total_duration_ms); |
| |
| // 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()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (start_time_ms + 100.f) / total_duration_ms); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (start_time_ms + 200.f) / total_duration_ms); |
| |
| AdvanceClock(800); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerEndOffset()); |
| EXPECT_TRUE(IsPlaying()); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (start_time_ms + 900.f) / total_duration_ms); |
| EXPECT_TRUE(IsPlaying()); |
| |
| animation_->Pause(); |
| EXPECT_TRUE(IsPaused()); |
| |
| AdvanceClock(10000); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (start_time_ms + 900.f) / total_duration_ms); |
| |
| // Resume playing the animation. |
| animation_->ResumePlaying(); |
| EXPECT_TRUE(IsScheduledToResume()); |
| |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_TRUE(IsPlaying()); |
| |
| AdvanceClock(500); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (start_time_ms + 400.f) / total_duration_ms); |
| |
| AdvanceClock(400); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), GetTimerStartOffset()); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), |
| (start_time_ms + 100.f) / total_duration_ms); |
| EXPECT_TRUE(IsPlaying()); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PauseBeforePlay) { |
| const float total_duration_ms = kAnimationDuration * 1000.f; |
| |
| // Test to see if the race condition is handled correctly. It may happen that |
| // we pause the video before it even starts playing. |
| |
| TestAnimationObserver observer; |
| animation_->SetAnimationObserver(&observer); |
| |
| AdvanceClock(300); |
| |
| animation_->Start(); |
| EXPECT_TRUE(IsScheduledToPlay()); |
| |
| animation_->Pause(); |
| EXPECT_TRUE(IsPaused()); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| |
| animation_->ResumePlaying(); |
| EXPECT_TRUE(IsScheduledToResume()); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_TRUE(IsPlaying()); |
| |
| AdvanceClock(100); |
| animation_->Paint(canvas(), NowTicks(), animation_->GetOriginalSize()); |
| EXPECT_FLOAT_EQ(animation_->GetCurrentProgress(), 100.f / total_duration_ms); |
| } |
| |
| TEST_F(SkiaVectorAnimationTest, PaintTest) { |
| std::unique_ptr<gfx::Canvas> canvas(new gfx::Canvas( |
| gfx::Size(kAnimationWidth, kAnimationHeight), 1.f, false)); |
| |
| // Advance clock by 300 milliseconds. |
| AdvanceClock(300); |
| |
| animation_->Start(SkiaVectorAnimation::Style::kLinear); |
| animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize()); |
| |
| AdvanceClock(50); |
| animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize()); |
| SkBitmap bitmap = canvas->GetBitmap(); |
| IsAllSameColor(SK_ColorGREEN, bitmap); |
| |
| AdvanceClock(2450); |
| animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize()); |
| bitmap = canvas->GetBitmap(); |
| IsAllSameColor(SK_ColorGREEN, bitmap); |
| |
| AdvanceClock(50); |
| animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize()); |
| bitmap = canvas->GetBitmap(); |
| IsAllSameColor(SK_ColorBLUE, bitmap); |
| |
| AdvanceClock(1000); |
| animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize()); |
| bitmap = canvas->GetBitmap(); |
| IsAllSameColor(SK_ColorBLUE, bitmap); |
| |
| AdvanceClock(1400); |
| animation_->Paint(canvas.get(), NowTicks(), animation_->GetOriginalSize()); |
| bitmap = canvas->GetBitmap(); |
| IsAllSameColor(SK_ColorBLUE, bitmap); |
| } |
| |
| } // namespace gfx |