| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/layout/ImageQualityController.h" | 5 #include "core/layout/ImageQualityController.h" |
| 6 | 6 |
| 7 #include "core/layout/LayoutImage.h" | 7 #include "core/layout/LayoutImage.h" |
| 8 #include "core/layout/LayoutTestHelper.h" | 8 #include "core/layout/LayoutTestHelper.h" |
| 9 #include "platform/graphics/GraphicsContext.h" | 9 #include "platform/graphics/GraphicsContext.h" |
| 10 #include "platform/graphics/paint/PaintController.h" | 10 #include "platform/graphics/paint/PaintController.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
| 12 #include "wtf/PtrUtil.h" |
| 12 #include <memory> | 13 #include <memory> |
| 13 | 14 |
| 14 namespace blink { | 15 namespace blink { |
| 15 | 16 |
| 16 class ImageQualityControllerTest : public RenderingTest { | 17 class ImageQualityControllerTest : public RenderingTest { |
| 17 protected: | 18 protected: |
| 18 ImageQualityController* controller() { return m_controller; } | 19 ImageQualityController* controller() { return m_controller; } |
| 19 | 20 |
| 20 private: | 21 private: |
| 21 void SetUp() override | 22 void SetUp() override |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 } | 135 } |
| 135 bool runsTasksOnCurrentThread() override { return true; } | 136 bool runsTasksOnCurrentThread() override { return true; } |
| 136 std::unique_ptr<WebTaskRunner> clone() override { return nullptr; } | 137 std::unique_ptr<WebTaskRunner> clone() override { return nullptr; } |
| 137 double virtualTimeSeconds() const override { return 0.0; } | 138 double virtualTimeSeconds() const override { return 0.0; } |
| 138 double monotonicallyIncreasingVirtualTimeSeconds() const override { return m
_time; } | 139 double monotonicallyIncreasingVirtualTimeSeconds() const override { return m
_time; } |
| 139 | 140 |
| 140 double m_time; | 141 double m_time; |
| 141 Task* m_currentTask; | 142 Task* m_currentTask; |
| 142 }; | 143 }; |
| 143 | 144 |
| 144 class MockTimer : public Timer<ImageQualityController> { | 145 class MockTimer : public TaskRunnerTimer<ImageQualityController> { |
| 145 typedef void (ImageQualityController::*TimerFiredFunction)(Timer*); | |
| 146 public: | 146 public: |
| 147 using TimerFiredFunction = typename TaskRunnerTimer<ImageQualityController>:
:TimerFiredFunction; |
| 148 |
| 147 MockTimer(ImageQualityController* o, TimerFiredFunction f) | 149 MockTimer(ImageQualityController* o, TimerFiredFunction f) |
| 148 : Timer<ImageQualityController>(o, f, &m_taskRunner) | 150 : TaskRunnerTimer(&m_taskRunner, o, f) |
| 149 { | 151 { |
| 150 } | 152 } |
| 151 | 153 |
| 152 void fire() | 154 void fire() |
| 153 { | 155 { |
| 154 this->Timer<ImageQualityController>::fired(); | 156 fired(); |
| 155 stop(); | 157 stop(); |
| 156 } | 158 } |
| 157 | 159 |
| 158 void setTime(double newTime) | 160 void setTime(double newTime) |
| 159 { | 161 { |
| 160 m_taskRunner.setTime(newTime); | 162 m_taskRunner.setTime(newTime); |
| 161 } | 163 } |
| 162 | 164 |
| 163 private: | 165 private: |
| 164 MockTaskRunner m_taskRunner; | 166 MockTaskRunner m_taskRunner; |
| 165 }; | 167 }; |
| 166 | 168 |
| 167 TEST_F(ImageQualityControllerTest, LowQualityFilterForResizingImage) | 169 TEST_F(ImageQualityControllerTest, LowQualityFilterForResizingImage) |
| 168 { | 170 { |
| 169 MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::
highQualityRepaintTimerFired); | 171 MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::
highQualityRepaintTimerFired); |
| 170 controller()->setTimer(mockTimer); | 172 controller()->setTimer(wrapUnique(mockTimer)); |
| 171 setBodyInnerHTML("<img src='myimage'></img>"); | 173 setBodyInnerHTML("<img src='myimage'></img>"); |
| 172 LayoutImage* img = toLayoutImage(document().body()->firstChild()->layoutObje
ct()); | 174 LayoutImage* img = toLayoutImage(document().body()->firstChild()->layoutObje
ct()); |
| 173 | 175 |
| 174 RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); | 176 RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); |
| 175 std::unique_ptr<PaintController> paintController = PaintController::create()
; | 177 std::unique_ptr<PaintController> paintController = PaintController::create()
; |
| 176 GraphicsContext context(*paintController); | 178 GraphicsContext context(*paintController); |
| 177 | 179 |
| 178 // Paint once. This will kick off a timer to see if we resize it during that
timer's execution. | 180 // Paint once. This will kick off a timer to see if we resize it during that
timer's execution. |
| 179 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*img
, testImage.get(), testImage.get(), LayoutSize(2, 2))); | 181 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*img
, testImage.get(), testImage.get(), LayoutSize(2, 2))); |
| 180 | 182 |
| 181 // Go into low-quality mode now that the size changed. | 183 // Go into low-quality mode now that the size changed. |
| 182 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(3, 3))); | 184 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(3, 3))); |
| 183 | 185 |
| 184 // Stay in low-quality mode since the size changed again. | 186 // Stay in low-quality mode since the size changed again. |
| 185 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(4, 4))); | 187 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(4, 4))); |
| 186 | 188 |
| 187 mockTimer->fire(); | 189 mockTimer->fire(); |
| 188 // The timer fired before painting at another size, so this doesn't count as
animation. Therefore not painting at low quality. | 190 // The timer fired before painting at another size, so this doesn't count as
animation. Therefore not painting at low quality. |
| 189 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*img
, testImage.get(), testImage.get(), LayoutSize(4, 4))); | 191 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*img
, testImage.get(), testImage.get(), LayoutSize(4, 4))); |
| 190 } | 192 } |
| 191 | 193 |
| 192 TEST_F(ImageQualityControllerTest, MediumQualityFilterForNotAnimatedWhileAnother
Animates) | 194 TEST_F(ImageQualityControllerTest, MediumQualityFilterForNotAnimatedWhileAnother
Animates) |
| 193 { | 195 { |
| 194 MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::
highQualityRepaintTimerFired); | 196 MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::
highQualityRepaintTimerFired); |
| 195 controller()->setTimer(mockTimer); | 197 controller()->setTimer(wrapUnique(mockTimer)); |
| 196 setBodyInnerHTML("<img id='myAnimatingImage' src='myimage'></img> <img id='m
yNonAnimatingImage' src='myimage2'></img>"); | 198 setBodyInnerHTML("<img id='myAnimatingImage' src='myimage'></img> <img id='m
yNonAnimatingImage' src='myimage2'></img>"); |
| 197 LayoutImage* animatingImage = toLayoutImage(document().getElementById("myAni
matingImage")->layoutObject()); | 199 LayoutImage* animatingImage = toLayoutImage(document().getElementById("myAni
matingImage")->layoutObject()); |
| 198 LayoutImage* nonAnimatingImage = toLayoutImage(document().getElementById("my
NonAnimatingImage")->layoutObject()); | 200 LayoutImage* nonAnimatingImage = toLayoutImage(document().getElementById("my
NonAnimatingImage")->layoutObject()); |
| 199 | 201 |
| 200 RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); | 202 RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); |
| 201 std::unique_ptr<PaintController> paintController = PaintController::create()
; | 203 std::unique_ptr<PaintController> paintController = PaintController::create()
; |
| 202 GraphicsContext context(*paintController); | 204 GraphicsContext context(*paintController); |
| 203 | 205 |
| 204 // Paint once. This will kick off a timer to see if we resize it during that
timer's execution. | 206 // Paint once. This will kick off a timer to see if we resize it during that
timer's execution. |
| 205 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*ani
matingImage, testImage.get(), testImage.get(), LayoutSize(2, 2))); | 207 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*ani
matingImage, testImage.get(), testImage.get(), LayoutSize(2, 2))); |
| 206 | 208 |
| 207 // Go into low-quality mode now that the size changed. | 209 // Go into low-quality mode now that the size changed. |
| 208 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*animat
ingImage, testImage.get(), testImage.get(), LayoutSize(3, 3))); | 210 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*animat
ingImage, testImage.get(), testImage.get(), LayoutSize(3, 3))); |
| 209 | 211 |
| 210 // The non-animating image receives a medium-quality filter, even though the
other one is animating. | 212 // The non-animating image receives a medium-quality filter, even though the
other one is animating. |
| 211 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*non
AnimatingImage, testImage.get(), testImage.get(), LayoutSize(4, 4))); | 213 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*non
AnimatingImage, testImage.get(), testImage.get(), LayoutSize(4, 4))); |
| 212 | 214 |
| 213 // Now the second image has animated, so it also gets painted with a low-qua
lity filter. | 215 // Now the second image has animated, so it also gets painted with a low-qua
lity filter. |
| 214 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*nonAni
matingImage, testImage.get(), testImage.get(), LayoutSize(3, 3))); | 216 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*nonAni
matingImage, testImage.get(), testImage.get(), LayoutSize(3, 3))); |
| 215 | 217 |
| 216 mockTimer->fire(); | 218 mockTimer->fire(); |
| 217 // The timer fired before painting at another size, so this doesn't count as
animation. Therefore not painting at low quality for any image. | 219 // The timer fired before painting at another size, so this doesn't count as
animation. Therefore not painting at low quality for any image. |
| 218 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*ani
matingImage, testImage.get(), testImage.get(), LayoutSize(4, 4))); | 220 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*ani
matingImage, testImage.get(), testImage.get(), LayoutSize(4, 4))); |
| 219 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*non
AnimatingImage, testImage.get(), testImage.get(), LayoutSize(4, 4))); | 221 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*non
AnimatingImage, testImage.get(), testImage.get(), LayoutSize(4, 4))); |
| 220 } | 222 } |
| 221 | 223 |
| 222 TEST_F(ImageQualityControllerTest, DontKickTheAnimationTimerWhenPaintingAtTheSam
eSize) | 224 TEST_F(ImageQualityControllerTest, DontKickTheAnimationTimerWhenPaintingAtTheSam
eSize) |
| 223 { | 225 { |
| 224 MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::
highQualityRepaintTimerFired); | 226 MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::
highQualityRepaintTimerFired); |
| 225 controller()->setTimer(mockTimer); | 227 controller()->setTimer(wrapUnique(mockTimer)); |
| 226 setBodyInnerHTML("<img src='myimage'></img>"); | 228 setBodyInnerHTML("<img src='myimage'></img>"); |
| 227 LayoutImage* img = toLayoutImage(document().body()->firstChild()->layoutObje
ct()); | 229 LayoutImage* img = toLayoutImage(document().body()->firstChild()->layoutObje
ct()); |
| 228 | 230 |
| 229 RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); | 231 RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); |
| 230 | 232 |
| 231 // Paint once. This will kick off a timer to see if we resize it during that
timer's execution. | 233 // Paint once. This will kick off a timer to see if we resize it during that
timer's execution. |
| 232 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*img
, testImage.get(), testImage.get(), LayoutSize(2, 2))); | 234 EXPECT_EQ(InterpolationMedium, controller()->chooseInterpolationQuality(*img
, testImage.get(), testImage.get(), LayoutSize(2, 2))); |
| 233 | 235 |
| 234 // Go into low-quality mode now that the size changed. | 236 // Go into low-quality mode now that the size changed. |
| 235 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(3, 3))); | 237 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(3, 3))); |
| 236 | 238 |
| 237 // Stay in low-quality mode since the size changed again. | 239 // Stay in low-quality mode since the size changed again. |
| 238 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(4, 4))); | 240 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(4, 4))); |
| 239 | 241 |
| 240 mockTimer->stop(); | 242 mockTimer->stop(); |
| 241 EXPECT_FALSE(mockTimer->isActive()); | 243 EXPECT_FALSE(mockTimer->isActive()); |
| 242 // Painted at the same size, so even though timer is still executing, don't
go to low quality. | 244 // Painted at the same size, so even though timer is still executing, don't
go to low quality. |
| 243 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(4, 4))); | 245 EXPECT_EQ(InterpolationLow, controller()->chooseInterpolationQuality(*img, t
estImage.get(), testImage.get(), LayoutSize(4, 4))); |
| 244 // Check that the timer was not kicked. It should not have been, since the i
mage was painted at the same size as last time. | 246 // Check that the timer was not kicked. It should not have been, since the i
mage was painted at the same size as last time. |
| 245 EXPECT_FALSE(mockTimer->isActive()); | 247 EXPECT_FALSE(mockTimer->isActive()); |
| 246 } | 248 } |
| 247 | 249 |
| 248 TEST_F(ImageQualityControllerTest, DontRestartTimerUnlessAdvanced) | 250 TEST_F(ImageQualityControllerTest, DontRestartTimerUnlessAdvanced) |
| 249 { | 251 { |
| 250 MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::
highQualityRepaintTimerFired); | 252 MockTimer* mockTimer = new MockTimer(controller(), &ImageQualityController::
highQualityRepaintTimerFired); |
| 251 controller()->setTimer(mockTimer); | 253 controller()->setTimer(wrapUnique(mockTimer)); |
| 252 setBodyInnerHTML("<img src='myimage'></img>"); | 254 setBodyInnerHTML("<img src='myimage'></img>"); |
| 253 LayoutImage* img = toLayoutImage(document().body()->firstChild()->layoutObje
ct()); | 255 LayoutImage* img = toLayoutImage(document().body()->firstChild()->layoutObje
ct()); |
| 254 | 256 |
| 255 RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); | 257 RefPtr<TestImageLowQuality> testImage = adoptRef(new TestImageLowQuality); |
| 256 | 258 |
| 257 // Paint once. This will kick off a timer to see if we resize it during that
timer's execution. | 259 // Paint once. This will kick off a timer to see if we resize it during that
timer's execution. |
| 258 mockTimer->setTime(0.1); | 260 mockTimer->setTime(0.1); |
| 259 EXPECT_FALSE(controller()->shouldPaintAtLowQuality(*img, testImage.get(), te
stImage.get(), LayoutSize(2, 2), 0.1)); | 261 EXPECT_FALSE(controller()->shouldPaintAtLowQuality(*img, testImage.get(), te
stImage.get(), LayoutSize(2, 2), 0.1)); |
| 260 EXPECT_EQ(ImageQualityController::cLowQualityTimeThreshold, mockTimer->nextF
ireInterval()); | 262 EXPECT_EQ(ImageQualityController::cLowQualityTimeThreshold, mockTimer->nextF
ireInterval()); |
| 261 | 263 |
| 262 // Go into low-quality mode now that the size changed. | 264 // Go into low-quality mode now that the size changed. |
| 263 double nextTime = 0.1 + ImageQualityController::cTimerRestartThreshold / 2.0
; | 265 double nextTime = 0.1 + ImageQualityController::cTimerRestartThreshold / 2.0
; |
| 264 mockTimer->setTime(nextTime); | 266 mockTimer->setTime(nextTime); |
| 265 EXPECT_EQ(true, controller()->shouldPaintAtLowQuality(*img, testImage.get(),
testImage.get(), LayoutSize(3, 3), nextTime)); | 267 EXPECT_EQ(true, controller()->shouldPaintAtLowQuality(*img, testImage.get(),
testImage.get(), LayoutSize(3, 3), nextTime)); |
| 266 // The fire interval has decreased, because we have not restarted the timer. | 268 // The fire interval has decreased, because we have not restarted the timer. |
| 267 EXPECT_EQ(ImageQualityController::cLowQualityTimeThreshold - ImageQualityCon
troller::cTimerRestartThreshold / 2.0, mockTimer->nextFireInterval()); | 269 EXPECT_EQ(ImageQualityController::cLowQualityTimeThreshold - ImageQualityCon
troller::cTimerRestartThreshold / 2.0, mockTimer->nextFireInterval()); |
| 268 | 270 |
| 269 // This animation is far enough in the future to make the timer restart, sin
ce it is half over. | 271 // This animation is far enough in the future to make the timer restart, sin
ce it is half over. |
| 270 nextTime = 0.1 + ImageQualityController::cTimerRestartThreshold + 0.01; | 272 nextTime = 0.1 + ImageQualityController::cTimerRestartThreshold + 0.01; |
| 271 EXPECT_EQ(true, controller()->shouldPaintAtLowQuality(*img, testImage.get(),
testImage.get(), LayoutSize(4, 4), nextTime)); | 273 EXPECT_EQ(true, controller()->shouldPaintAtLowQuality(*img, testImage.get(),
testImage.get(), LayoutSize(4, 4), nextTime)); |
| 272 // Now the timer has restarted, leading to a larger fire interval. | 274 // Now the timer has restarted, leading to a larger fire interval. |
| 273 EXPECT_EQ(ImageQualityController::cLowQualityTimeThreshold, mockTimer->nextF
ireInterval()); | 275 EXPECT_EQ(ImageQualityController::cLowQualityTimeThreshold, mockTimer->nextF
ireInterval()); |
| 274 } | 276 } |
| 275 | 277 |
| 276 #endif | 278 #endif |
| 277 | 279 |
| 278 } // namespace blink | 280 } // namespace blink |
| OLD | NEW |