Chromium Code Reviews| Index: third_party/WebKit/Source/core/svg/graphics/SVGImageTest.cpp |
| diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImageTest.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImageTest.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..aeec490f302ef94b17302813468326e88fe957bd |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/core/svg/graphics/SVGImageTest.cpp |
| @@ -0,0 +1,194 @@ |
| +// Copyright 2016 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 "core/svg/graphics/SVGImage.h" |
| + |
| +#include "core/svg/graphics/SVGImageChromeClient.h" |
| +#include "platform/SharedBuffer.h" |
| +#include "platform/Timer.h" |
| +#include "platform/geometry/FloatRect.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "third_party/skia/include/core/SkCanvas.h" |
| +#include "third_party/skia/include/utils/SkNullCanvas.h" |
| + |
| +namespace blink { |
| +namespace { |
| + |
| +class MockTaskRunner : public WebTaskRunner { |
| +public: |
| + void setTime(double newTime) { m_time = newTime; } |
| + |
| + MockTaskRunner() |
| + : WebTaskRunner(), m_time(0.0), m_currentTask(nullptr) |
| + { } |
| + |
| + virtual ~MockTaskRunner() |
| + { |
| + if (m_currentTask) |
| + delete m_currentTask; |
| + } |
| + |
| +private: |
| + void postTask(const WebTraceLocation&, Task*) override { } |
| + void postDelayedTask(const WebTraceLocation&, Task* task, double) override |
| + { |
| + if (m_currentTask) |
| + delete m_currentTask; |
| + m_currentTask = task; |
| + |
| + } |
| + WebTaskRunner* clone() override { return nullptr; } |
| + double virtualTimeSeconds() const override { return 0.0; } |
| + double monotonicallyIncreasingVirtualTimeSeconds() const override { return m_time; } |
| + |
| + double m_time; |
| + Task* m_currentTask; |
| +}; |
| + |
| +class MockTimer : public Timer<SVGImageChromeClient> { |
| + typedef void (SVGImageChromeClient::*TimerFiredFunction)(Timer*); |
| +public: |
| + MockTimer(SVGImageChromeClient* o, TimerFiredFunction f) |
| + : Timer<SVGImageChromeClient>(o, f, &m_taskRunner) |
| + { |
| + } |
| + |
| + void fire() |
| + { |
| + this->Timer<SVGImageChromeClient>::fired(); |
| + stop(); |
| + } |
| + |
| + void setTime(double newTime) |
| + { |
| + m_taskRunner.setTime(newTime); |
| + } |
| + |
| +private: |
| + MockTaskRunner m_taskRunner; |
| +}; |
| + |
| +} // namespace |
| + |
| +class SVGImageTest : public testing::Test { |
| +public: |
| + SVGImage& image() { return *m_image; } |
| + |
| + void load(const char* data, bool shouldPause) |
| + { |
| + m_observer = new PauseControlImageObserver(shouldPause); |
| + m_image = SVGImage::create(m_observer); |
| + m_image->setData(SharedBuffer::create(data, strlen(data)), true); |
| + } |
| + |
| + void pumpFrame() |
| + { |
| + Image* image = m_image.get(); |
| + RefPtr<SkCanvas> nullCanvas = adoptRef(SkCreateNullCanvas()); |
| + SkPaint paint; |
| + FloatRect dummyRect(0, 0, 100, 100); |
| + image->draw( |
| + nullCanvas.get(), paint, |
| + dummyRect, dummyRect, |
| + DoNotRespectImageOrientation, Image::DoNotClampImageToSourceRect); |
| + } |
| + |
| +private: |
| + class PauseControlImageObserver |
| + : public GarbageCollectedFinalized<PauseControlImageObserver>, public ImageObserver { |
| + USING_GARBAGE_COLLECTED_MIXIN(PauseControlImageObserver); |
| + public: |
| + PauseControlImageObserver(bool shouldPause) : m_shouldPause(shouldPause) { } |
| + |
| + void decodedSizeChangedTo(const Image*, size_t newSize) override { } |
| + void didDraw(const Image*) override { } |
| + |
| + bool shouldPauseAnimation(const Image*) override { return m_shouldPause; } |
| + void animationAdvanced(const Image*) override { } |
| + |
| + void changedInRect(const Image*, const IntRect&) override { } |
| + |
| + DEFINE_INLINE_VIRTUAL_TRACE() { ImageObserver::trace(visitor); } |
| + private: |
| + bool m_shouldPause; |
| + }; |
| + Persistent<PauseControlImageObserver> m_observer; |
| + RefPtr<SVGImage> m_image; |
| +}; |
| + |
| +const char kAnimatedDocument[] = |
| + "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'>" |
| + "<style>" |
| + "@keyframes rot {" |
| + " from { transform: rotate(0deg); } to { transform: rotate(-360deg); }" |
| + "}" |
| + ".spinner {" |
| + " transform-origin: 50%% 50%%;" |
| + " animation-name: rot;" |
| + " animation-duration: 4s;" |
| + " animation-iteration-count: infinite;" |
| + " animation-timing-function: linear;" |
| + "}" |
| + "</style>" |
| + "<path class='spinner' fill='none' d='M 8,1.125 A 6.875,6.875 0 1 1 1.125,8' stroke-width='2' stroke='blue'/>" |
| + "</svg>"; |
| + |
| +TEST_F(SVGImageTest, TimelineSuspendAndResume) |
| +{ |
| + const bool shouldPause = true; |
| + load(kAnimatedDocument, shouldPause); |
| + SVGImageChromeClient& chromeClient = image().chromeClientForTesting(); |
| + MockTimer* timer = new MockTimer(&chromeClient, &SVGImageChromeClient::animationTimerFired); |
| + chromeClient.setTimer(timer); |
| + |
| + // Simulate a draw. Cause a frame (timer) to be scheduled. |
| + pumpFrame(); |
| + EXPECT_TRUE(image().hasAnimations()); |
| + EXPECT_TRUE(timer->isActive()); |
| + |
| + // Fire the timer/trigger a frame update. Since the observer always returns |
| + // true for shouldPauseAnimation, this will result in the timeline being |
| + // suspended. |
| + timer->fire(); |
| + EXPECT_TRUE(chromeClient.isSuspended()); |
| + EXPECT_FALSE(timer->isActive()); |
| + |
| + // Simulate a draw. This should resume the animation again. |
| + pumpFrame(); |
| + EXPECT_TRUE(timer->isActive()); |
| + EXPECT_FALSE(chromeClient.isSuspended()); |
|
chrishtr
2016/05/25 20:23:47
Why doesn't it pause again?
fs
2016/05/25 20:30:16
It will/would when the timer fires (i.e shouldPaus
chrishtr
2016/05/25 22:18:13
oh right, you're calling pumpFrame() not timer->fi
|
| +} |
| + |
| +TEST_F(SVGImageTest, ResetAnimation) |
| +{ |
| + const bool shouldPause = false; |
| + load(kAnimatedDocument, shouldPause); |
| + SVGImageChromeClient& chromeClient = image().chromeClientForTesting(); |
| + MockTimer* timer = new MockTimer(&chromeClient, &SVGImageChromeClient::animationTimerFired); |
| + chromeClient.setTimer(timer); |
| + |
| + // Simulate a draw. Cause a frame (timer) to be scheduled. |
| + pumpFrame(); |
| + EXPECT_TRUE(image().hasAnimations()); |
| + EXPECT_TRUE(timer->isActive()); |
| + |
| + // Reset the animation. This will suspend the timeline but not cancel the |
| + // timer. |
| + image().resetAnimation(); |
| + EXPECT_TRUE(chromeClient.isSuspended()); |
| + EXPECT_TRUE(timer->isActive()); |
| + |
| + // Fire the timer/trigger a frame update. The timeline will remain |
| + // suspended and no frame will be scheduled. |
| + timer->fire(); |
| + EXPECT_TRUE(chromeClient.isSuspended()); |
| + EXPECT_FALSE(timer->isActive()); |
| + |
| + // Simulate a draw. This should resume the animation again. |
| + pumpFrame(); |
| + EXPECT_FALSE(chromeClient.isSuspended()); |
| + EXPECT_TRUE(timer->isActive()); |
| +} |
| + |
| +} // namespace blink |