single_scrollbar_animation_controller_thinning_unittest.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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. #include "cc/input/single_scrollbar_animation_controller_thinning.h"
  5. #include "base/memory/raw_ptr.h"
  6. #include "base/time/time.h"
  7. #include "cc/layers/solid_color_scrollbar_layer_impl.h"
  8. #include "cc/test/layer_tree_impl_test_base.h"
  9. #include "cc/trees/layer_tree_impl.h"
  10. #include "testing/gmock/include/gmock/gmock.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. using ::testing::_;
  13. using ::testing::Bool;
  14. using ::testing::Mock;
  15. using ::testing::NiceMock;
  16. namespace cc {
  17. namespace {
  18. const float kIdleThicknessScale =
  19. SingleScrollbarAnimationControllerThinning::kIdleThicknessScale;
  20. class MockSingleScrollbarAnimationControllerClient
  21. : public ScrollbarAnimationControllerClient {
  22. public:
  23. MockSingleScrollbarAnimationControllerClient(LayerTreeHostImpl* host_impl,
  24. bool is_fluent)
  25. : host_impl_(host_impl), is_fluent_(is_fluent) {}
  26. ~MockSingleScrollbarAnimationControllerClient() override = default;
  27. ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const override {
  28. return host_impl_->ScrollbarsFor(scroll_element_id);
  29. }
  30. bool IsFluentScrollbar() const override { return is_fluent_; }
  31. MOCK_METHOD2(PostDelayedScrollbarAnimationTask,
  32. void(base::OnceClosure start_fade, base::TimeDelta delay));
  33. MOCK_METHOD0(SetNeedsRedrawForScrollbarAnimation, void());
  34. MOCK_METHOD0(SetNeedsAnimateForScrollbarAnimation, void());
  35. MOCK_METHOD0(DidChangeScrollbarVisibility, void());
  36. private:
  37. raw_ptr<LayerTreeHostImpl> host_impl_;
  38. bool is_fluent_;
  39. };
  40. class SingleScrollbarAnimationControllerThinningTest
  41. : public LayerTreeImplTestBase,
  42. public testing::Test,
  43. public testing::WithParamInterface<bool> {
  44. public:
  45. explicit SingleScrollbarAnimationControllerThinningTest(
  46. bool is_fluent = GetParam())
  47. : client_(host_impl(), is_fluent) {}
  48. protected:
  49. const base::TimeDelta kThinningDuration = base::Seconds(2);
  50. const int kThumbThickness = 10;
  51. void SetUp() override {
  52. root_layer()->SetBounds(gfx::Size(100, 100));
  53. auto* scroll_layer = AddLayer<LayerImpl>();
  54. scroll_layer->SetBounds(gfx::Size(200, 200));
  55. scroll_layer->SetElementId(
  56. LayerIdToElementIdForTesting(scroll_layer->id()));
  57. const int kTrackStart = 0;
  58. const int kTrackLength = 100;
  59. const bool kIsLeftSideVerticalScrollbar = false;
  60. scrollbar_layer_ = AddLayer<SolidColorScrollbarLayerImpl>(
  61. ScrollbarOrientation::HORIZONTAL, kThumbThickness, kTrackStart,
  62. kIsLeftSideVerticalScrollbar);
  63. scrollbar_layer_->SetBounds(gfx::Size(kThumbThickness, kTrackLength));
  64. scrollbar_layer_->SetScrollElementId(scroll_layer->element_id());
  65. CopyProperties(root_layer(), scroll_layer);
  66. CreateTransformNode(scroll_layer);
  67. CreateScrollNode(scroll_layer, gfx::Size(100, 100));
  68. CopyProperties(scroll_layer, scrollbar_layer_);
  69. scrollbar_layer_->SetOffsetToTransformParent(gfx::Vector2dF(90, 0));
  70. CreateEffectNode(scrollbar_layer_).has_potential_opacity_animation = true;
  71. UpdateActiveTreeDrawProperties();
  72. scrollbar_controller_ = SingleScrollbarAnimationControllerThinning::Create(
  73. scroll_layer->element_id(), ScrollbarOrientation::HORIZONTAL, &client_,
  74. kThinningDuration);
  75. mouse_move_distance_to_trigger_fade_in_ =
  76. scrollbar_controller_->MouseMoveDistanceToTriggerFadeIn();
  77. mouse_move_distance_to_trigger_expand_ =
  78. scrollbar_controller_->MouseMoveDistanceToTriggerExpand();
  79. }
  80. float mouse_move_distance_to_trigger_fade_in_;
  81. float mouse_move_distance_to_trigger_expand_;
  82. std::unique_ptr<SingleScrollbarAnimationControllerThinning>
  83. scrollbar_controller_;
  84. raw_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_;
  85. NiceMock<MockSingleScrollbarAnimationControllerClient> client_;
  86. };
  87. // Return a point with given offset from the top-left of scrollbar.
  88. gfx::PointF NearScrollbar(float offset_x, float offset_y) {
  89. gfx::PointF p(90, 0);
  90. p.Offset(offset_x, offset_y);
  91. return p;
  92. }
  93. class SingleScrollbarAnimationControllerThinningFluentTest
  94. : public SingleScrollbarAnimationControllerThinningTest {
  95. public:
  96. SingleScrollbarAnimationControllerThinningFluentTest()
  97. : SingleScrollbarAnimationControllerThinningTest(/* is_fluent */ true) {}
  98. };
  99. // Check initialization of scrollbar. Should start thin.
  100. TEST_P(SingleScrollbarAnimationControllerThinningTest, Idle) {
  101. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  102. scrollbar_layer_->thumb_thickness_scale_factor());
  103. }
  104. // Move the pointer near the scrollbar. Confirm it gets thick and narrow when
  105. // moved away.
  106. TEST_P(SingleScrollbarAnimationControllerThinningTest, MouseNear) {
  107. base::TimeTicks time;
  108. time += base::Seconds(1);
  109. scrollbar_controller_->DidMouseMove(
  110. NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
  111. scrollbar_controller_->Animate(time);
  112. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  113. scrollbar_layer_->thumb_thickness_scale_factor());
  114. // Should animate to thickened.
  115. time += kThinningDuration;
  116. scrollbar_controller_->Animate(time);
  117. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  118. // Subsequent moves within the nearness threshold should not change anything.
  119. scrollbar_controller_->DidMouseMove(
  120. NearScrollbar(-mouse_move_distance_to_trigger_expand_ + 1, 0));
  121. scrollbar_controller_->Animate(time);
  122. time += base::Seconds(10);
  123. scrollbar_controller_->Animate(time);
  124. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  125. // Now move away from thumb.
  126. scrollbar_controller_->DidMouseMove(
  127. NearScrollbar(-mouse_move_distance_to_trigger_expand_ - 1, 0));
  128. scrollbar_controller_->Animate(time);
  129. time += kThinningDuration;
  130. scrollbar_controller_->Animate(time);
  131. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  132. scrollbar_layer_->thumb_thickness_scale_factor());
  133. // Move away from track.
  134. scrollbar_controller_->DidMouseMove(
  135. NearScrollbar(-mouse_move_distance_to_trigger_fade_in_ - 1, 0));
  136. scrollbar_controller_->Animate(time);
  137. time += kThinningDuration;
  138. scrollbar_controller_->Animate(time);
  139. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  140. scrollbar_layer_->thumb_thickness_scale_factor());
  141. }
  142. // Move the pointer over the scrollbar. Make sure it gets thick that it gets
  143. // thin when moved away.
  144. TEST_P(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
  145. base::TimeTicks time;
  146. time += base::Seconds(1);
  147. scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
  148. scrollbar_controller_->Animate(time);
  149. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  150. scrollbar_layer_->thumb_thickness_scale_factor());
  151. // Should animate to thickened.
  152. time += kThinningDuration;
  153. scrollbar_controller_->Animate(time);
  154. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  155. // Subsequent moves should not change anything.
  156. scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
  157. scrollbar_controller_->Animate(time);
  158. time += base::Seconds(10);
  159. scrollbar_controller_->Animate(time);
  160. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  161. // Moving off the scrollbar but still withing the "near" threshold should do
  162. // nothing.
  163. scrollbar_controller_->DidMouseMove(
  164. NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
  165. scrollbar_controller_->Animate(time);
  166. time += base::Seconds(10);
  167. scrollbar_controller_->Animate(time);
  168. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  169. // Now move away from thumb.
  170. scrollbar_controller_->DidMouseMove(
  171. NearScrollbar(-mouse_move_distance_to_trigger_expand_ - 1, 0));
  172. scrollbar_controller_->Animate(time);
  173. time += kThinningDuration;
  174. scrollbar_controller_->Animate(time);
  175. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  176. scrollbar_layer_->thumb_thickness_scale_factor());
  177. }
  178. // First move the pointer over the scrollbar off of it. Make sure the thinning
  179. // animation kicked off in DidMouseMoveOffScrollbar gets overridden by the
  180. // thickening animation in the DidMouseMove call.
  181. TEST_P(SingleScrollbarAnimationControllerThinningTest,
  182. MouseNearThenAwayWhileAnimating) {
  183. base::TimeTicks time;
  184. time += base::Seconds(1);
  185. scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
  186. scrollbar_controller_->Animate(time);
  187. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  188. scrollbar_layer_->thumb_thickness_scale_factor());
  189. // Should animate to thickened.
  190. time += kThinningDuration;
  191. scrollbar_controller_->Animate(time);
  192. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  193. // This is tricky. The DidMouseLeave() is sent before the
  194. // subsequent DidMouseMove(), if the mouse moves in that direction.
  195. // This results in the thumb thinning. We want to make sure that when the
  196. // thumb starts expanding it doesn't first narrow to the idle thinness.
  197. time += base::Seconds(1);
  198. scrollbar_controller_->DidMouseLeave();
  199. scrollbar_controller_->Animate(time);
  200. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  201. // Let the animation run half of the way through the thinning animation.
  202. time += kThinningDuration / 2;
  203. scrollbar_controller_->Animate(time);
  204. EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
  205. scrollbar_layer_->thumb_thickness_scale_factor());
  206. // Now we get a notification for the mouse moving over the scroller. The
  207. // animation is reset to the thickening direction but we won't start
  208. // thickening until the new animation catches up to the current thickness.
  209. scrollbar_controller_->DidMouseMove(
  210. NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
  211. scrollbar_controller_->Animate(time);
  212. EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
  213. scrollbar_layer_->thumb_thickness_scale_factor());
  214. // Until we reach the half way point, the animation will have no effect.
  215. time += kThinningDuration / 4;
  216. scrollbar_controller_->Animate(time);
  217. EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
  218. scrollbar_layer_->thumb_thickness_scale_factor());
  219. time += kThinningDuration / 4;
  220. scrollbar_controller_->Animate(time);
  221. EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
  222. scrollbar_layer_->thumb_thickness_scale_factor());
  223. // We're now at three quarters of the way through so it should now started
  224. // thickening again.
  225. time += kThinningDuration / 4;
  226. scrollbar_controller_->Animate(time);
  227. EXPECT_FLOAT_EQ(kIdleThicknessScale + 3 * (1.0f - kIdleThicknessScale) / 4.0f,
  228. scrollbar_layer_->thumb_thickness_scale_factor());
  229. // And all the way to the end.
  230. time += kThinningDuration / 4;
  231. scrollbar_controller_->Animate(time);
  232. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  233. }
  234. // First move the pointer on the scrollbar, then press it, then away.
  235. // Confirm that the bar gets thick. Then mouse up. Confirm that
  236. // the bar gets thin.
  237. TEST_P(SingleScrollbarAnimationControllerThinningTest,
  238. MouseCaptureAndReleaseOutOfBar) {
  239. base::TimeTicks time;
  240. time += base::Seconds(1);
  241. // Move over the scrollbar.
  242. scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
  243. scrollbar_controller_->Animate(time);
  244. time += kThinningDuration;
  245. scrollbar_controller_->Animate(time);
  246. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  247. // Capture
  248. scrollbar_controller_->DidMouseDown();
  249. time += base::Seconds(1);
  250. scrollbar_controller_->Animate(time);
  251. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  252. // Should stay thick for a while.
  253. time += base::Seconds(10);
  254. scrollbar_controller_->Animate(time);
  255. // Move outside the "near" threshold. Because the scrollbar is captured it
  256. // should remain thick.
  257. scrollbar_controller_->DidMouseMove(
  258. NearScrollbar(-mouse_move_distance_to_trigger_expand_ - 1, 0));
  259. time += kThinningDuration;
  260. scrollbar_controller_->Animate(time);
  261. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  262. // Release.
  263. scrollbar_controller_->DidMouseUp();
  264. // Should become thin.
  265. time += base::Seconds(1);
  266. scrollbar_controller_->Animate(time);
  267. time += kThinningDuration;
  268. scrollbar_controller_->Animate(time);
  269. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  270. scrollbar_layer_->thumb_thickness_scale_factor());
  271. }
  272. // First move the pointer on the scrollbar, then press it, then away. Confirm
  273. // that the bar gets thick. Then move point on the scrollbar and mouse up.
  274. // Confirm that the bar stays thick.
  275. TEST_P(SingleScrollbarAnimationControllerThinningTest,
  276. MouseCaptureAndReleaseOnBar) {
  277. base::TimeTicks time;
  278. time += base::Seconds(1);
  279. // Move over scrollbar.
  280. scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
  281. scrollbar_controller_->Animate(time);
  282. time += kThinningDuration;
  283. scrollbar_controller_->Animate(time);
  284. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  285. // Capture. Nothing should change.
  286. scrollbar_controller_->DidMouseDown();
  287. time += base::Seconds(1);
  288. scrollbar_controller_->Animate(time);
  289. time += base::Seconds(10);
  290. scrollbar_controller_->Animate(time);
  291. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  292. // Move away from scrollbar. Nothing should change.
  293. scrollbar_controller_->DidMouseMove(
  294. NearScrollbar(mouse_move_distance_to_trigger_expand_ + 1, 0));
  295. time += base::Seconds(1);
  296. scrollbar_controller_->Animate(time);
  297. time += base::Seconds(10);
  298. scrollbar_controller_->Animate(time);
  299. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  300. // Move over scrollbar and release. Since we're near the scrollbar, it should
  301. // remain thick.
  302. scrollbar_controller_->DidMouseMove(
  303. NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
  304. scrollbar_controller_->DidMouseUp();
  305. time += base::Seconds(1);
  306. scrollbar_controller_->Animate(time);
  307. time += base::Seconds(10);
  308. scrollbar_controller_->Animate(time);
  309. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  310. }
  311. // Tests that the thickening/thinning effects are animated.
  312. TEST_P(SingleScrollbarAnimationControllerThinningTest, ThicknessAnimated) {
  313. base::TimeTicks time;
  314. time += base::Seconds(1);
  315. // Move mouse near scrollbar. Test that at half the duration time, the
  316. // thickness is half way through its animation.
  317. scrollbar_controller_->DidMouseMove(
  318. NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
  319. scrollbar_controller_->Animate(time);
  320. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  321. scrollbar_layer_->thumb_thickness_scale_factor());
  322. time += kThinningDuration / 2;
  323. scrollbar_controller_->Animate(time);
  324. EXPECT_FLOAT_EQ(kIdleThicknessScale + (1.0f - kIdleThicknessScale) / 2.0f,
  325. scrollbar_layer_->thumb_thickness_scale_factor());
  326. time += kThinningDuration / 2;
  327. scrollbar_controller_->Animate(time);
  328. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  329. // Move mouse away from scrollbar. Same check.
  330. time += base::Seconds(1);
  331. scrollbar_controller_->DidMouseMove(
  332. NearScrollbar(-mouse_move_distance_to_trigger_expand_ - 1, 0));
  333. scrollbar_controller_->Animate(time);
  334. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  335. time += kThinningDuration / 2;
  336. scrollbar_controller_->Animate(time);
  337. EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
  338. scrollbar_layer_->thumb_thickness_scale_factor());
  339. time += kThinningDuration / 2;
  340. scrollbar_controller_->Animate(time);
  341. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  342. scrollbar_layer_->thumb_thickness_scale_factor());
  343. }
  344. // Make sure the Fluent scrollbar transitions to the full mode (thick) after
  345. // moving the mouse over scrollbar track and get back to the minimal mode (thin)
  346. // when moved away both inside and outside the layer.
  347. TEST_F(SingleScrollbarAnimationControllerThinningFluentTest,
  348. FluentMouseOverTrack) {
  349. base::TimeTicks time;
  350. time += base::Seconds(1);
  351. // Move the mouse over the scrollbar track.
  352. scrollbar_controller_->DidMouseMove(NearScrollbar(0, 75));
  353. scrollbar_controller_->Animate(time);
  354. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  355. scrollbar_layer_->thumb_thickness_scale_factor());
  356. // Should animate to the full mode.
  357. time += kThinningDuration;
  358. scrollbar_controller_->Animate(time);
  359. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  360. // Subsequent moves should not change anything.
  361. scrollbar_controller_->DidMouseMove(NearScrollbar(0, 75));
  362. scrollbar_controller_->Animate(time);
  363. time += base::Seconds(10);
  364. scrollbar_controller_->Animate(time);
  365. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  366. // Moving away from the scrollbar track should trigger the transition to the
  367. // minimal mode.
  368. scrollbar_controller_->DidMouseMove(NearScrollbar(-1, 75));
  369. scrollbar_controller_->Animate(time);
  370. time += kThinningDuration;
  371. scrollbar_controller_->Animate(time);
  372. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  373. scrollbar_layer_->thumb_thickness_scale_factor());
  374. // Move the mouse over the scrollbar track again. Scrollbar should be in the
  375. // full mode.
  376. scrollbar_controller_->DidMouseMove(NearScrollbar(0, 75));
  377. scrollbar_controller_->Animate(time);
  378. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  379. scrollbar_layer_->thumb_thickness_scale_factor());
  380. time += kThinningDuration;
  381. scrollbar_controller_->Animate(time);
  382. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
  383. // Moving away from the scrollbar track out of the layer should also
  384. // trigger the transition to the minimal mode.
  385. scrollbar_controller_->DidMouseMove(NearScrollbar(kThumbThickness + 1, 75));
  386. scrollbar_controller_->Animate(time);
  387. time += kThinningDuration;
  388. scrollbar_controller_->Animate(time);
  389. EXPECT_FLOAT_EQ(kIdleThicknessScale,
  390. scrollbar_layer_->thumb_thickness_scale_factor());
  391. }
  392. INSTANTIATE_TEST_SUITE_P(All,
  393. SingleScrollbarAnimationControllerThinningTest,
  394. Bool());
  395. } // namespace
  396. } // namespace cc