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/animation/scrollbar_animation_controller_thinning.h"
6
7#include "cc/layers/solid_color_scrollbar_layer_impl.h"
8#include "cc/test/fake_impl_proxy.h"
9#include "cc/test/fake_layer_tree_host_impl.h"
10#include "cc/test/test_shared_bitmap_manager.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace cc {
14namespace {
15
16class ScrollbarAnimationControllerThinningTest
17    : public testing::Test,
18      public ScrollbarAnimationControllerClient {
19 public:
20  ScrollbarAnimationControllerThinningTest()
21      : host_impl_(&proxy_, &shared_bitmap_manager_) {}
22
23  virtual void PostDelayedScrollbarFade(const base::Closure& start_fade,
24                                        base::TimeDelta delay) OVERRIDE {
25    start_fade_ = start_fade;
26  }
27  virtual void SetNeedsScrollbarAnimationFrame() OVERRIDE {}
28
29 protected:
30  virtual void SetUp() {
31    scoped_ptr<LayerImpl> scroll_layer =
32        LayerImpl::Create(host_impl_.active_tree(), 1);
33    clip_layer_ = LayerImpl::Create(host_impl_.active_tree(), 3);
34    scroll_layer->SetScrollClipLayer(clip_layer_->id());
35    LayerImpl* scroll_layer_ptr = scroll_layer.get();
36    clip_layer_->AddChild(scroll_layer.Pass());
37
38    const int kId = 2;
39    const int kThumbThickness = 10;
40    const int kTrackStart = 0;
41    const bool kIsLeftSideVerticalScrollbar = false;
42    const bool kIsOverlayScrollbar = true;
43    scrollbar_layer_ =
44        SolidColorScrollbarLayerImpl::Create(host_impl_.active_tree(),
45                                             kId,
46                                             HORIZONTAL,
47                                             kThumbThickness,
48                                             kTrackStart,
49                                             kIsLeftSideVerticalScrollbar,
50                                             kIsOverlayScrollbar);
51
52    scrollbar_layer_->SetScrollLayerAndClipLayerByIds(scroll_layer_ptr->id(),
53                                                      clip_layer_->id());
54    clip_layer_->SetBounds(gfx::Size(100, 100));
55    scroll_layer_ptr->SetBounds(gfx::Size(50, 50));
56
57    scrollbar_controller_ = ScrollbarAnimationControllerThinning::Create(
58        scroll_layer_ptr,
59        this,
60        base::TimeDelta::FromSeconds(2),
61        base::TimeDelta::FromSeconds(3));
62  }
63
64  FakeImplProxy proxy_;
65  TestSharedBitmapManager shared_bitmap_manager_;
66  FakeLayerTreeHostImpl host_impl_;
67  scoped_ptr<ScrollbarAnimationControllerThinning> scrollbar_controller_;
68  scoped_ptr<LayerImpl> clip_layer_;
69  scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_;
70
71  base::Closure start_fade_;
72};
73
74// Check initialization of scrollbar.
75TEST_F(ScrollbarAnimationControllerThinningTest, Idle) {
76  scrollbar_controller_->Animate(base::TimeTicks());
77  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
78  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
79}
80
81// Scroll content. Confirm the scrollbar gets dark and then becomes light
82// after stopping.
83TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) {
84  base::TimeTicks time;
85  time += base::TimeDelta::FromSeconds(1);
86  scrollbar_controller_->DidScrollUpdate();
87  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
88  // Scrollbar doesn't change size if triggered by scroll.
89  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
90
91  start_fade_.Run();
92
93  time += base::TimeDelta::FromSeconds(1);
94  scrollbar_controller_->Animate(time);
95  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
96  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
97
98  // Subsequent scroll restarts animation.
99  scrollbar_controller_->DidScrollUpdate();
100
101  start_fade_.Run();
102
103  time += base::TimeDelta::FromSeconds(2);
104  scrollbar_controller_->Animate(time);
105  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
106  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
107
108  time += base::TimeDelta::FromSeconds(1);
109  scrollbar_controller_->Animate(time);
110  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
111  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
112
113  time += base::TimeDelta::FromSeconds(1);
114  scrollbar_controller_->Animate(time);
115  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
116  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
117
118  time += base::TimeDelta::FromSeconds(1);
119  scrollbar_controller_->Animate(time);
120  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
121  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
122}
123
124// Initiate a scroll when the pointer is already near the scrollbar. It should
125// remain thick.
126TEST_F(ScrollbarAnimationControllerThinningTest, ScrollWithMouseNear) {
127  base::TimeTicks time;
128  time += base::TimeDelta::FromSeconds(1);
129
130  scrollbar_controller_->DidMouseMoveNear(1);
131  scrollbar_controller_->Animate(time);
132  time += base::TimeDelta::FromSeconds(3);
133
134  scrollbar_controller_->Animate(time);
135  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
136
137  scrollbar_controller_->DidScrollUpdate();
138  start_fade_.Run();
139  scrollbar_controller_->Animate(time);
140  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
141  // Scrollbar should still be thick.
142  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
143
144  time += base::TimeDelta::FromSeconds(5);
145  scrollbar_controller_->Animate(time);
146  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
147  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
148}
149
150// Move the pointer near the scrollbar. Confirm it gets thick and narrow when
151// moved away.
152TEST_F(ScrollbarAnimationControllerThinningTest, MouseNear) {
153  base::TimeTicks time;
154  time += base::TimeDelta::FromSeconds(1);
155  scrollbar_controller_->DidMouseMoveNear(1);
156  scrollbar_controller_->Animate(time);
157  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
158  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
159
160  // Should animate to thickened but not darken.
161  time += base::TimeDelta::FromSeconds(1);
162  scrollbar_controller_->Animate(time);
163  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
164  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
165
166  time += base::TimeDelta::FromSeconds(1);
167  scrollbar_controller_->Animate(time);
168  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
169  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
170
171  time += base::TimeDelta::FromSeconds(1);
172  scrollbar_controller_->Animate(time);
173  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
174  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
175
176  // Subsequent moves should not change anything.
177  scrollbar_controller_->DidMouseMoveNear(1);
178  scrollbar_controller_->Animate(time);
179  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
180  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
181
182  // Now move away from bar.
183  time += base::TimeDelta::FromSeconds(1);
184  scrollbar_controller_->DidMouseMoveNear(26);
185  scrollbar_controller_->Animate(time);
186  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
187  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
188
189  // Animate to narrow.
190  time += base::TimeDelta::FromSeconds(1);
191  scrollbar_controller_->Animate(time);
192  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
193  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
194
195  time += base::TimeDelta::FromSeconds(1);
196  scrollbar_controller_->Animate(time);
197  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
198  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
199
200  time += base::TimeDelta::FromSeconds(1);
201  scrollbar_controller_->Animate(time);
202  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
203  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
204}
205
206// Move the pointer over the scrollbar. Make sure it gets thick and dark
207// and that it gets thin and light when moved away.
208TEST_F(ScrollbarAnimationControllerThinningTest, MouseOver) {
209  base::TimeTicks time;
210  time += base::TimeDelta::FromSeconds(1);
211  scrollbar_controller_->DidMouseMoveNear(0);
212  scrollbar_controller_->Animate(time);
213  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
214  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
215
216  // Should animate to thickened and darkened.
217  time += base::TimeDelta::FromSeconds(1);
218  scrollbar_controller_->Animate(time);
219  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
220  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
221
222  time += base::TimeDelta::FromSeconds(1);
223  scrollbar_controller_->Animate(time);
224  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
225  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
226
227  time += base::TimeDelta::FromSeconds(1);
228  scrollbar_controller_->Animate(time);
229  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
230  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
231
232  // Subsequent moves should not change anything.
233  scrollbar_controller_->DidMouseMoveNear(0);
234  scrollbar_controller_->Animate(time);
235  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
236  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
237
238  // Now move away from bar.
239  time += base::TimeDelta::FromSeconds(1);
240  scrollbar_controller_->DidMouseMoveNear(26);
241  scrollbar_controller_->Animate(time);
242  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
243  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
244
245  // Animate to narrow.
246  time += base::TimeDelta::FromSeconds(1);
247  scrollbar_controller_->Animate(time);
248  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
249  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
250
251  time += base::TimeDelta::FromSeconds(1);
252  scrollbar_controller_->Animate(time);
253  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
254  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
255
256  time += base::TimeDelta::FromSeconds(1);
257  scrollbar_controller_->Animate(time);
258  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
259  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
260}
261
262// First move the pointer near the scrollbar, then over it, then back near
263// then far away. Confirm that first the bar gets thick, then dark, then light,
264// then narrow.
265TEST_F(ScrollbarAnimationControllerThinningTest, MouseNearThenOver) {
266  base::TimeTicks time;
267  time += base::TimeDelta::FromSeconds(1);
268  scrollbar_controller_->DidMouseMoveNear(1);
269  scrollbar_controller_->Animate(time);
270  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
271  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
272
273  // Should animate to thickened but not darken.
274  time += base::TimeDelta::FromSeconds(3);
275  scrollbar_controller_->Animate(time);
276  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
277  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
278
279  // Now move over.
280  scrollbar_controller_->DidMouseMoveNear(0);
281  scrollbar_controller_->Animate(time);
282
283  // Should animate to darkened.
284  time += base::TimeDelta::FromSeconds(1);
285  scrollbar_controller_->Animate(time);
286  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
287  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
288
289  time += base::TimeDelta::FromSeconds(1);
290  scrollbar_controller_->Animate(time);
291  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
292  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
293
294  time += base::TimeDelta::FromSeconds(1);
295  scrollbar_controller_->Animate(time);
296  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
297  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
298
299  // This is tricky. The DidMouseMoveOffScrollbar() is sent before the
300  // subsequent DidMouseMoveNear(), if the mouse moves in that direction.
301  // This results in the thumb thinning. We want to make sure that when the
302  // thumb starts expanding it doesn't first narrow to the idle thinness.
303  time += base::TimeDelta::FromSeconds(1);
304  scrollbar_controller_->DidMouseMoveOffScrollbar();
305  scrollbar_controller_->Animate(time);
306
307  time += base::TimeDelta::FromSeconds(1);
308  scrollbar_controller_->Animate(time);
309  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
310  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
311
312  scrollbar_controller_->DidMouseMoveNear(1);
313  scrollbar_controller_->Animate(time);
314  // A new animation is kicked off.
315
316  time += base::TimeDelta::FromSeconds(1);
317  scrollbar_controller_->Animate(time);
318  // We will initiate the narrowing again, but it won't get decremented until
319  // the new animation catches up to it.
320  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
321  // Now the thickness should be increasing, but it shouldn't happen until the
322  // animation catches up.
323  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
324
325  time += base::TimeDelta::FromSeconds(1);
326  scrollbar_controller_->Animate(time);
327  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity());
328  // The thickness now gets big again.
329  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
330
331  time += base::TimeDelta::FromSeconds(1);
332  scrollbar_controller_->Animate(time);
333  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
334  // The thickness now gets big again.
335  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
336}
337
338}  // namespace
339}  // namespace cc
340