Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "cc/input/single_scrollbar_animation_controller_thinning.h" | |
| 6 | |
| 7 #include "cc/layers/solid_color_scrollbar_layer_impl.h" | |
| 8 #include "cc/test/fake_impl_task_runner_provider.h" | |
| 9 #include "cc/test/fake_layer_tree_host_impl.h" | |
| 10 #include "cc/test/geometry_test_utils.h" | |
| 11 #include "cc/test/test_task_graph_runner.h" | |
| 12 #include "cc/trees/layer_tree_impl.h" | |
| 13 #include "testing/gmock/include/gmock/gmock.h" | |
| 14 #include "testing/gtest/include/gtest/gtest.h" | |
| 15 | |
| 16 using testing::AtLeast; | |
| 17 using testing::Mock; | |
| 18 using testing::NiceMock; | |
| 19 using testing::_; | |
| 20 | |
| 21 namespace cc { | |
| 22 namespace { | |
| 23 | |
| 24 // These constants are hard-coded and should match the values in | |
| 25 // single_scrollbar_animation_controller_thinning.cc. | |
| 26 const float kIdleThicknessScale = 0.4f; | |
| 27 const float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f; | |
| 28 | |
| 29 class MockSingleScrollbarAnimationControllerClient | |
| 30 : public ScrollbarAnimationControllerClient { | |
| 31 public: | |
| 32 explicit MockSingleScrollbarAnimationControllerClient( | |
| 33 LayerTreeHostImpl* host_impl) | |
| 34 : host_impl_(host_impl) {} | |
| 35 virtual ~MockSingleScrollbarAnimationControllerClient() {} | |
| 36 | |
| 37 void PostDelayedScrollbarAnimationTask(const base::Closure& start_fade, | |
|
bokan
2017/01/06 20:17:56
This should never be called, you can mock this. In
| |
| 38 base::TimeDelta delay) override { | |
| 39 start_fade_ = start_fade; | |
| 40 delay_ = delay; | |
| 41 } | |
| 42 void SetNeedsRedrawForScrollbarAnimation() override {} | |
| 43 void SetNeedsAnimateForScrollbarAnimation() override {} | |
| 44 ScrollbarSet ScrollbarsFor(int scroll_layer_id) const override { | |
| 45 return host_impl_->ScrollbarsFor(scroll_layer_id); | |
| 46 } | |
| 47 MOCK_METHOD0(DidChangeScrollbarVisibility, void()); | |
| 48 | |
| 49 base::Closure& start_fade() { return start_fade_; } | |
| 50 base::TimeDelta& delay() { return delay_; } | |
| 51 | |
| 52 private: | |
| 53 base::Closure start_fade_; | |
| 54 base::TimeDelta delay_; | |
| 55 LayerTreeHostImpl* host_impl_; | |
| 56 }; | |
| 57 | |
| 58 class SingleScrollbarAnimationControllerThinningTest : public testing::Test { | |
| 59 public: | |
| 60 SingleScrollbarAnimationControllerThinningTest() | |
| 61 : host_impl_(&task_runner_provider_, &task_graph_runner_), | |
| 62 client_(&host_impl_) {} | |
| 63 | |
| 64 protected: | |
| 65 const base::TimeDelta kThinningDuration = base::TimeDelta::FromSeconds(2); | |
| 66 | |
| 67 void SetUp() override { | |
| 68 std::unique_ptr<LayerImpl> scroll_layer = | |
| 69 LayerImpl::Create(host_impl_.active_tree(), 1); | |
| 70 std::unique_ptr<LayerImpl> clip = | |
| 71 LayerImpl::Create(host_impl_.active_tree(), 3); | |
| 72 clip_layer_ = clip.get(); | |
| 73 scroll_layer->SetScrollClipLayer(clip_layer_->id()); | |
| 74 LayerImpl* scroll_layer_ptr = scroll_layer.get(); | |
| 75 | |
| 76 const int kId = 2; | |
| 77 const int kThumbThickness = 10; | |
| 78 const int kTrackStart = 0; | |
| 79 const bool kIsLeftSideVerticalScrollbar = false; | |
| 80 const bool kIsOverlayScrollbar = true; | |
| 81 | |
| 82 std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar = | |
| 83 SolidColorScrollbarLayerImpl::Create( | |
| 84 host_impl_.active_tree(), kId, HORIZONTAL, kThumbThickness, | |
| 85 kTrackStart, kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar); | |
| 86 scrollbar_layer_ = scrollbar.get(); | |
| 87 | |
| 88 scroll_layer->test_properties()->AddChild(std::move(scrollbar)); | |
| 89 clip_layer_->test_properties()->AddChild(std::move(scroll_layer)); | |
| 90 host_impl_.active_tree()->SetRootLayerForTesting(std::move(clip)); | |
| 91 | |
| 92 scrollbar_layer_->SetScrollLayerId(scroll_layer_ptr->id()); | |
| 93 scrollbar_layer_->test_properties()->opacity_can_animate = true; | |
| 94 clip_layer_->SetBounds(gfx::Size(100, 100)); | |
| 95 scroll_layer_ptr->SetBounds(gfx::Size(200, 200)); | |
| 96 host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting(); | |
| 97 | |
| 98 scrollbar_controller_ = SingleScrollbarAnimationControllerThinning::Create( | |
| 99 scroll_layer_ptr->id(), HORIZONTAL, &client_, kThinningDuration); | |
| 100 } | |
| 101 | |
| 102 FakeImplTaskRunnerProvider task_runner_provider_; | |
| 103 TestTaskGraphRunner task_graph_runner_; | |
| 104 FakeLayerTreeHostImpl host_impl_; | |
| 105 std::unique_ptr<SingleScrollbarAnimationControllerThinning> | |
| 106 scrollbar_controller_; | |
| 107 LayerImpl* clip_layer_; | |
| 108 SolidColorScrollbarLayerImpl* scrollbar_layer_; | |
| 109 NiceMock<MockSingleScrollbarAnimationControllerClient> client_; | |
| 110 }; | |
| 111 | |
| 112 // Check initialization of scrollbar. Should start thin. | |
| 113 TEST_F(SingleScrollbarAnimationControllerThinningTest, Idle) { | |
| 114 EXPECT_FLOAT_EQ(kIdleThicknessScale, | |
| 115 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 116 } | |
| 117 | |
| 118 // Move the pointer near the scrollbar. Confirm it gets thick and narrow when | |
| 119 // moved away. | |
| 120 TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseNear) { | |
| 121 base::TimeTicks time; | |
| 122 time += base::TimeDelta::FromSeconds(1); | |
| 123 | |
| 124 scrollbar_controller_->DidMouseMoveNear(1); | |
| 125 scrollbar_controller_->Animate(time); | |
| 126 EXPECT_FLOAT_EQ(kIdleThicknessScale, | |
| 127 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 128 | |
| 129 // Should animate to thickened. | |
| 130 time += kThinningDuration; | |
| 131 scrollbar_controller_->Animate(time); | |
| 132 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 133 | |
| 134 // Subsequent moves within the nearness threshold should not change anything. | |
| 135 scrollbar_controller_->DidMouseMoveNear(2); | |
| 136 scrollbar_controller_->Animate(time); | |
| 137 time += base::TimeDelta::FromSeconds(10); | |
| 138 scrollbar_controller_->Animate(time); | |
| 139 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 140 | |
| 141 // Now move away from bar. | |
| 142 scrollbar_controller_->DidMouseMoveNear( | |
| 143 kDefaultMouseMoveDistanceToTriggerAnimation); | |
| 144 scrollbar_controller_->Animate(time); | |
| 145 time += kThinningDuration; | |
| 146 scrollbar_controller_->Animate(time); | |
| 147 EXPECT_FLOAT_EQ(kIdleThicknessScale, | |
| 148 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 149 } | |
| 150 | |
| 151 // Move the pointer over the scrollbar. Make sure it gets thick that it gets | |
| 152 // thin when moved away. | |
| 153 TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseOver) { | |
| 154 base::TimeTicks time; | |
| 155 time += base::TimeDelta::FromSeconds(1); | |
| 156 | |
| 157 scrollbar_controller_->DidMouseMoveNear(0); | |
| 158 scrollbar_controller_->Animate(time); | |
| 159 EXPECT_FLOAT_EQ(kIdleThicknessScale, | |
| 160 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 161 | |
| 162 // Should animate to thickened. | |
| 163 time += kThinningDuration; | |
| 164 scrollbar_controller_->Animate(time); | |
| 165 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 166 | |
| 167 // Subsequent moves should not change anything. | |
| 168 scrollbar_controller_->DidMouseMoveNear(0); | |
| 169 scrollbar_controller_->Animate(time); | |
| 170 time += base::TimeDelta::FromSeconds(10); | |
| 171 scrollbar_controller_->Animate(time); | |
| 172 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 173 | |
| 174 // Moving off the scrollbar but still withing the "near" threshold should do | |
| 175 // nothing. | |
| 176 scrollbar_controller_->DidMouseMoveNear( | |
| 177 kDefaultMouseMoveDistanceToTriggerAnimation - 1.f); | |
| 178 scrollbar_controller_->Animate(time); | |
| 179 time += base::TimeDelta::FromSeconds(10); | |
| 180 scrollbar_controller_->Animate(time); | |
| 181 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 182 | |
| 183 // Now move away from bar. | |
| 184 scrollbar_controller_->DidMouseMoveNear( | |
| 185 kDefaultMouseMoveDistanceToTriggerAnimation); | |
| 186 scrollbar_controller_->Animate(time); | |
| 187 time += kThinningDuration; | |
| 188 scrollbar_controller_->Animate(time); | |
| 189 EXPECT_FLOAT_EQ(kIdleThicknessScale, | |
| 190 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 191 } | |
| 192 | |
| 193 // First move the pointer over the scrollbar off of it. Make sure the thinning | |
| 194 // animation kicked off in DidMouseMoveOffScrollbar gets overridden by the | |
| 195 // thickening animation in the DidMouseMoveNear call. | |
| 196 TEST_F(SingleScrollbarAnimationControllerThinningTest, | |
| 197 MouseNearThenAwayWhileAnimating) { | |
| 198 base::TimeTicks time; | |
| 199 time += base::TimeDelta::FromSeconds(1); | |
| 200 | |
| 201 scrollbar_controller_->DidMouseMoveNear(0); | |
| 202 scrollbar_controller_->Animate(time); | |
| 203 EXPECT_FLOAT_EQ(kIdleThicknessScale, | |
| 204 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 205 | |
| 206 // Should animate to thickened. | |
| 207 time += kThinningDuration; | |
| 208 scrollbar_controller_->Animate(time); | |
| 209 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 210 | |
| 211 // This is tricky. The DidMouseLeave() is sent before the | |
| 212 // subsequent DidMouseMoveNear(), if the mouse moves in that direction. | |
| 213 // This results in the thumb thinning. We want to make sure that when the | |
| 214 // thumb starts expanding it doesn't first narrow to the idle thinness. | |
| 215 time += base::TimeDelta::FromSeconds(1); | |
| 216 scrollbar_controller_->DidMouseLeave(); | |
| 217 scrollbar_controller_->Animate(time); | |
| 218 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 219 | |
| 220 // Let the animation run half of the way through the thinning animation. | |
| 221 time += kThinningDuration / 2; | |
| 222 scrollbar_controller_->Animate(time); | |
| 223 EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f, | |
| 224 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 225 | |
| 226 // Now we get a notification for the mouse moving over the scroller. The | |
| 227 // animation is reset to the thickening direction but we won't start | |
| 228 // thickening until the new animation catches up to the current thickness. | |
|
bokan
2017/01/06 20:17:56
Hmm, I don't like this. Could we make it that the
chaopeng
2017/01/10 20:49:50
Yes, today we just change the animation direction
| |
| 229 scrollbar_controller_->DidMouseMoveNear(1); | |
| 230 scrollbar_controller_->Animate(time); | |
| 231 EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f, | |
| 232 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 233 | |
| 234 // Until we reach the half way point, the animation will have no effect. | |
| 235 time += kThinningDuration / 4; | |
| 236 scrollbar_controller_->Animate(time); | |
| 237 EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f, | |
| 238 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 239 | |
| 240 time += kThinningDuration / 4; | |
| 241 scrollbar_controller_->Animate(time); | |
| 242 EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f, | |
| 243 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 244 | |
| 245 // We're now at three quarters of the way through so it should now started | |
| 246 // thickening again. | |
| 247 time += kThinningDuration / 4; | |
| 248 scrollbar_controller_->Animate(time); | |
| 249 EXPECT_FLOAT_EQ(kIdleThicknessScale + 3 * (1.0f - kIdleThicknessScale) / 4.0f, | |
| 250 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 251 | |
| 252 // And all the way to the end. | |
| 253 time += kThinningDuration / 4; | |
| 254 scrollbar_controller_->Animate(time); | |
| 255 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 256 } | |
| 257 | |
| 258 // First move the pointer on the scrollbar, then press it, then away. | |
| 259 // Confirm that the bar gets thick. Then mouse up. Confirm that | |
| 260 // the bar gets thin. | |
| 261 TEST_F(SingleScrollbarAnimationControllerThinningTest, | |
| 262 MouseCaptureAndReleaseOutOfBar) { | |
| 263 base::TimeTicks time; | |
| 264 time += base::TimeDelta::FromSeconds(1); | |
| 265 | |
| 266 // Move over the scrollbar. | |
| 267 scrollbar_controller_->DidMouseMoveNear(0); | |
| 268 scrollbar_controller_->Animate(time); | |
| 269 time += kThinningDuration; | |
| 270 scrollbar_controller_->Animate(time); | |
| 271 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 272 | |
| 273 // Capture | |
| 274 scrollbar_controller_->DidMouseDown(); | |
| 275 time += base::TimeDelta::FromSeconds(1); | |
| 276 scrollbar_controller_->Animate(time); | |
| 277 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 278 | |
| 279 // Should stay thick for a while. | |
| 280 time += base::TimeDelta::FromSeconds(10); | |
| 281 scrollbar_controller_->Animate(time); | |
| 282 | |
| 283 // Move outside the "near" threshold. Because the scrollbar is captured it | |
| 284 // should remain thick. | |
| 285 scrollbar_controller_->DidMouseMoveNear( | |
| 286 kDefaultMouseMoveDistanceToTriggerAnimation); | |
| 287 time += kThinningDuration; | |
| 288 scrollbar_controller_->Animate(time); | |
| 289 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 290 | |
| 291 // Release. | |
| 292 scrollbar_controller_->DidMouseUp(); | |
| 293 | |
| 294 // Should become thin. | |
| 295 time += base::TimeDelta::FromSeconds(1); | |
| 296 scrollbar_controller_->Animate(time); | |
| 297 time += kThinningDuration; | |
| 298 scrollbar_controller_->Animate(time); | |
| 299 EXPECT_FLOAT_EQ(kIdleThicknessScale, | |
| 300 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 301 } | |
| 302 | |
| 303 // First move the pointer on the scrollbar, then press it, then away. Confirm | |
| 304 // that the bar gets thick. Then move point on the scrollbar and mouse up. | |
| 305 // Confirm that the bar stays thick. | |
| 306 TEST_F(SingleScrollbarAnimationControllerThinningTest, | |
| 307 MouseCaptureAndReleaseOnBar) { | |
| 308 base::TimeTicks time; | |
| 309 time += base::TimeDelta::FromSeconds(1); | |
| 310 | |
| 311 // Move over scrollbar. | |
| 312 scrollbar_controller_->DidMouseMoveNear(0); | |
| 313 scrollbar_controller_->Animate(time); | |
| 314 time += kThinningDuration; | |
| 315 scrollbar_controller_->Animate(time); | |
| 316 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 317 | |
| 318 // Capture. Nothing should change. | |
| 319 scrollbar_controller_->DidMouseDown(); | |
| 320 time += base::TimeDelta::FromSeconds(1); | |
| 321 scrollbar_controller_->Animate(time); | |
| 322 time += base::TimeDelta::FromSeconds(10); | |
| 323 scrollbar_controller_->Animate(time); | |
| 324 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 325 | |
| 326 // Move away from scrollbar. Nothing should change. | |
| 327 scrollbar_controller_->DidMouseMoveNear( | |
| 328 kDefaultMouseMoveDistanceToTriggerAnimation); | |
| 329 time += base::TimeDelta::FromSeconds(1); | |
| 330 scrollbar_controller_->Animate(time); | |
| 331 time += base::TimeDelta::FromSeconds(10); | |
| 332 scrollbar_controller_->Animate(time); | |
| 333 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 334 | |
| 335 // Move over scrollbar and release. Since we're near the scrollbar, it should | |
| 336 // remain thick. | |
| 337 scrollbar_controller_->DidMouseMoveNear(0); | |
| 338 scrollbar_controller_->DidMouseUp(); | |
| 339 time += base::TimeDelta::FromSeconds(1); | |
| 340 scrollbar_controller_->Animate(time); | |
| 341 time += base::TimeDelta::FromSeconds(10); | |
| 342 scrollbar_controller_->Animate(time); | |
| 343 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 344 } | |
| 345 | |
| 346 // Tests that the thickening/thinning effects are animated. | |
| 347 TEST_F(SingleScrollbarAnimationControllerThinningTest, ThicknessAnimated) { | |
| 348 base::TimeTicks time; | |
| 349 time += base::TimeDelta::FromSeconds(1); | |
| 350 | |
| 351 // Move mouse near scrollbar. Test that at half the duration time, the | |
| 352 // thickness is half way through its animation. | |
| 353 scrollbar_controller_->DidMouseMoveNear(1); | |
| 354 scrollbar_controller_->Animate(time); | |
| 355 EXPECT_FLOAT_EQ(kIdleThicknessScale, | |
| 356 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 357 | |
| 358 time += kThinningDuration / 2; | |
| 359 scrollbar_controller_->Animate(time); | |
| 360 EXPECT_FLOAT_EQ(kIdleThicknessScale + (1.0f - kIdleThicknessScale) / 2.0f, | |
| 361 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 362 | |
| 363 time += kThinningDuration / 2; | |
| 364 scrollbar_controller_->Animate(time); | |
| 365 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 366 | |
| 367 // Move mouse away from scrollbar. Same check. | |
| 368 time += base::TimeDelta::FromSeconds(1); | |
| 369 scrollbar_controller_->DidMouseMoveNear( | |
| 370 kDefaultMouseMoveDistanceToTriggerAnimation); | |
| 371 scrollbar_controller_->Animate(time); | |
| 372 EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 373 | |
| 374 time += kThinningDuration / 2; | |
| 375 scrollbar_controller_->Animate(time); | |
| 376 EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f, | |
| 377 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 378 | |
| 379 time += kThinningDuration / 2; | |
| 380 scrollbar_controller_->Animate(time); | |
| 381 EXPECT_FLOAT_EQ(kIdleThicknessScale, | |
| 382 scrollbar_layer_->thumb_thickness_scale_factor()); | |
| 383 } | |
| 384 | |
| 385 } // namespace | |
| 386 } // namespace cc | |
| OLD | NEW |