1 // Copyright (c) 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.
5 #include "content/browser/web_contents/aura/window_slider.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "ui/aura/root_window.h"
10 #include "ui/aura/test/aura_test_base.h"
11 #include "ui/aura/test/event_generator.h"
12 #include "ui/aura/test/test_window_delegate.h"
13 #include "ui/aura/window.h"
14 #include "ui/base/hit_test.h"
18 void DispatchEventDuringScrollCallback(aura::RootWindow* root_window,
21 const gfx::Vector2dF& delta) {
22 if (type != ui::ET_GESTURE_SCROLL_UPDATE)
24 aura::RootWindowHostDelegate* delegate =
25 root_window->AsRootWindowHostDelegate();
26 if (event->IsMouseEvent())
27 delegate->OnHostMouseEvent(static_cast<ui::MouseEvent*>(event));
28 else if (event->IsKeyEvent())
29 delegate->OnHostKeyEvent(static_cast<ui::KeyEvent*>(event));
32 void ChangeSliderOwnerDuringScrollCallback(scoped_ptr<aura::Window>* window,
35 const gfx::Vector2dF& delta) {
36 if (type != ui::ET_GESTURE_SCROLL_UPDATE)
38 aura::Window* new_window = new aura::Window(NULL);
39 new_window->Init(ui::LAYER_TEXTURED);
41 slider->ChangeOwner(new_window);
42 (*window)->parent()->AddChild(new_window);
43 window->reset(new_window);
46 // The window delegate does not receive any events.
47 class NoEventWindowDelegate : public aura::test::TestWindowDelegate {
49 NoEventWindowDelegate() {
51 virtual ~NoEventWindowDelegate() {}
54 // Overridden from aura::WindowDelegate:
55 virtual bool HasHitTestMask() const OVERRIDE { return true; }
57 DISALLOW_COPY_AND_ASSIGN(NoEventWindowDelegate);
60 class WindowSliderDelegateTest : public WindowSlider::Delegate {
62 WindowSliderDelegateTest()
63 : can_create_layer_(true),
64 created_back_layer_(false),
65 created_front_layer_(false),
66 slide_completed_(false),
67 slide_aborted_(false),
68 slider_destroyed_(false) {
70 virtual ~WindowSliderDelegateTest() {}
73 can_create_layer_ = true;
74 created_back_layer_ = false;
75 created_front_layer_ = false;
76 slide_completed_ = false;
77 slide_aborted_ = false;
78 slider_destroyed_ = false;
81 void SetCanCreateLayer(bool can_create_layer) {
82 can_create_layer_ = can_create_layer;
85 bool created_back_layer() const { return created_back_layer_; }
86 bool created_front_layer() const { return created_front_layer_; }
87 bool slide_completed() const { return slide_completed_; }
88 bool slide_aborted() const { return slide_aborted_; }
89 bool slider_destroyed() const { return slider_destroyed_; }
92 ui::Layer* CreateLayerForTest() {
93 CHECK(can_create_layer_);
94 ui::Layer* layer = new ui::Layer(ui::LAYER_SOLID_COLOR);
95 layer->SetColor(SK_ColorRED);
99 // Overridden from WindowSlider::Delegate:
100 virtual ui::Layer* CreateBackLayer() OVERRIDE {
101 if (!can_create_layer_)
103 created_back_layer_ = true;
104 return CreateLayerForTest();
107 virtual ui::Layer* CreateFrontLayer() OVERRIDE {
108 if (!can_create_layer_)
110 created_front_layer_ = true;
111 return CreateLayerForTest();
114 virtual void OnWindowSlideComplete() OVERRIDE {
115 slide_completed_ = true;
118 virtual void OnWindowSlideAborted() OVERRIDE {
119 slide_aborted_ = true;
122 virtual void OnWindowSliderDestroyed() OVERRIDE {
123 slider_destroyed_ = true;
127 bool can_create_layer_;
128 bool created_back_layer_;
129 bool created_front_layer_;
130 bool slide_completed_;
132 bool slider_destroyed_;
134 DISALLOW_COPY_AND_ASSIGN(WindowSliderDelegateTest);
137 // This delegate destroys the owner window when the slider is destroyed.
138 class WindowSliderDeleteOwnerOnDestroy : public WindowSliderDelegateTest {
140 explicit WindowSliderDeleteOwnerOnDestroy(aura::Window* owner)
143 virtual ~WindowSliderDeleteOwnerOnDestroy() {}
146 // Overridden from WindowSlider::Delegate:
147 virtual void OnWindowSliderDestroyed() OVERRIDE {
148 WindowSliderDelegateTest::OnWindowSliderDestroyed();
152 aura::Window* owner_;
153 DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnDestroy);
156 // This delegate destroyes the owner window when a slide is completed.
157 class WindowSliderDeleteOwnerOnComplete : public WindowSliderDelegateTest {
159 explicit WindowSliderDeleteOwnerOnComplete(aura::Window* owner)
162 virtual ~WindowSliderDeleteOwnerOnComplete() {}
165 // Overridden from WindowSlider::Delegate:
166 virtual void OnWindowSlideComplete() OVERRIDE {
167 WindowSliderDelegateTest::OnWindowSlideComplete();
171 aura::Window* owner_;
172 DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnComplete);
175 typedef aura::test::AuraTestBase WindowSliderTest;
177 TEST_F(WindowSliderTest, WindowSlideUsingGesture) {
178 scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
179 window->SetBounds(gfx::Rect(0, 0, 400, 400));
180 WindowSliderDelegateTest slider_delegate;
182 aura::test::EventGenerator generator(root_window());
184 // Generate a horizontal overscroll.
185 WindowSlider* slider =
186 new WindowSlider(&slider_delegate, root_window(), window.get());
187 generator.GestureScrollSequence(gfx::Point(10, 10),
189 base::TimeDelta::FromMilliseconds(10),
191 EXPECT_TRUE(slider_delegate.created_back_layer());
192 EXPECT_TRUE(slider_delegate.slide_completed());
193 EXPECT_FALSE(slider_delegate.created_front_layer());
194 EXPECT_FALSE(slider_delegate.slide_aborted());
195 EXPECT_FALSE(slider_delegate.slider_destroyed());
196 EXPECT_FALSE(slider->IsSlideInProgress());
197 slider_delegate.Reset();
198 window->SetTransform(gfx::Transform());
200 // Generat a horizontal overscroll in the reverse direction.
201 generator.GestureScrollSequence(gfx::Point(160, 10),
203 base::TimeDelta::FromMilliseconds(10),
205 EXPECT_TRUE(slider_delegate.created_front_layer());
206 EXPECT_TRUE(slider_delegate.slide_completed());
207 EXPECT_FALSE(slider_delegate.created_back_layer());
208 EXPECT_FALSE(slider_delegate.slide_aborted());
209 EXPECT_FALSE(slider_delegate.slider_destroyed());
210 EXPECT_FALSE(slider->IsSlideInProgress());
211 slider_delegate.Reset();
213 // Generate a vertical overscroll.
214 generator.GestureScrollSequence(gfx::Point(10, 10),
216 base::TimeDelta::FromMilliseconds(10),
218 EXPECT_FALSE(slider_delegate.created_back_layer());
219 EXPECT_FALSE(slider_delegate.slide_completed());
220 EXPECT_FALSE(slider_delegate.created_front_layer());
221 EXPECT_FALSE(slider_delegate.slide_aborted());
222 EXPECT_FALSE(slider->IsSlideInProgress());
223 slider_delegate.Reset();
225 // Generate a horizontal scroll that starts overscroll, but doesn't scroll
226 // enough to complete it.
227 generator.GestureScrollSequence(gfx::Point(10, 10),
229 base::TimeDelta::FromMilliseconds(10),
231 EXPECT_TRUE(slider_delegate.created_back_layer());
232 EXPECT_TRUE(slider_delegate.slide_aborted());
233 EXPECT_FALSE(slider_delegate.created_front_layer());
234 EXPECT_FALSE(slider_delegate.slide_completed());
235 EXPECT_FALSE(slider_delegate.slider_destroyed());
236 EXPECT_FALSE(slider->IsSlideInProgress());
237 slider_delegate.Reset();
239 // Destroy the window. This should destroy the slider.
241 EXPECT_TRUE(slider_delegate.slider_destroyed());
244 // Tests that the window slide is cancelled when a different type of event
246 TEST_F(WindowSliderTest, WindowSlideIsCancelledOnEvent) {
247 scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
248 WindowSliderDelegateTest slider_delegate;
250 ui::Event* events[] = {
251 new ui::MouseEvent(ui::ET_MOUSE_MOVED,
255 new ui::KeyEvent(ui::ET_KEY_PRESSED,
262 new WindowSlider(&slider_delegate, root_window(), window.get());
263 for (int i = 0; events[i]; ++i) {
264 // Generate a horizontal overscroll.
265 aura::test::EventGenerator generator(root_window());
266 generator.GestureScrollSequenceWithCallback(
269 base::TimeDelta::FromMilliseconds(10),
271 base::Bind(&DispatchEventDuringScrollCallback,
273 base::Owned(events[i])));
274 EXPECT_TRUE(slider_delegate.created_back_layer());
275 EXPECT_TRUE(slider_delegate.slide_aborted());
276 EXPECT_FALSE(slider_delegate.created_front_layer());
277 EXPECT_FALSE(slider_delegate.slide_completed());
278 EXPECT_FALSE(slider_delegate.slider_destroyed());
279 slider_delegate.Reset();
282 EXPECT_TRUE(slider_delegate.slider_destroyed());
285 // Tests that the slide works correctly when the owner of the window changes
286 // during the duration of the slide.
287 TEST_F(WindowSliderTest, OwnerWindowChangesDuringWindowSlide) {
288 scoped_ptr<aura::Window> parent(CreateNormalWindow(0, root_window(), NULL));
290 NoEventWindowDelegate window_delegate;
291 window_delegate.set_window_component(HTNOWHERE);
292 scoped_ptr<aura::Window> window(CreateNormalWindow(1, parent.get(),
295 WindowSliderDelegateTest slider_delegate;
296 scoped_ptr<WindowSlider> slider(
297 new WindowSlider(&slider_delegate, parent.get(), window.get()));
299 // Generate a horizontal scroll, and change the owner in the middle of the
301 aura::test::EventGenerator generator(root_window());
302 aura::Window* old_window = window.get();
303 generator.GestureScrollSequenceWithCallback(
306 base::TimeDelta::FromMilliseconds(10),
308 base::Bind(&ChangeSliderOwnerDuringScrollCallback,
309 base::Unretained(&window),
311 aura::Window* new_window = window.get();
312 EXPECT_NE(old_window, new_window);
314 EXPECT_TRUE(slider_delegate.created_back_layer());
315 EXPECT_TRUE(slider_delegate.slide_completed());
316 EXPECT_FALSE(slider_delegate.created_front_layer());
317 EXPECT_FALSE(slider_delegate.slide_aborted());
318 EXPECT_FALSE(slider_delegate.slider_destroyed());
321 TEST_F(WindowSliderTest, NoSlideWhenLayerCantBeCreated) {
322 scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
323 window->SetBounds(gfx::Rect(0, 0, 400, 400));
324 WindowSliderDelegateTest slider_delegate;
325 slider_delegate.SetCanCreateLayer(false);
327 aura::test::EventGenerator generator(root_window());
329 // Generate a horizontal overscroll.
330 scoped_ptr<WindowSlider> slider(
331 new WindowSlider(&slider_delegate, root_window(), window.get()));
332 generator.GestureScrollSequence(gfx::Point(10, 10),
334 base::TimeDelta::FromMilliseconds(10),
336 EXPECT_FALSE(slider_delegate.created_back_layer());
337 EXPECT_FALSE(slider_delegate.slide_completed());
338 EXPECT_FALSE(slider_delegate.created_front_layer());
339 EXPECT_FALSE(slider_delegate.slide_aborted());
340 EXPECT_FALSE(slider_delegate.slider_destroyed());
341 window->SetTransform(gfx::Transform());
343 slider_delegate.SetCanCreateLayer(true);
344 generator.GestureScrollSequence(gfx::Point(10, 10),
346 base::TimeDelta::FromMilliseconds(10),
348 EXPECT_TRUE(slider_delegate.created_back_layer());
349 EXPECT_TRUE(slider_delegate.slide_completed());
350 EXPECT_FALSE(slider_delegate.created_front_layer());
351 EXPECT_FALSE(slider_delegate.slide_aborted());
352 EXPECT_FALSE(slider_delegate.slider_destroyed());
355 // Tests that the owner window can be destroyed from |OnWindowSliderDestroyed()|
356 // delegate callback without causing a crash.
357 TEST_F(WindowSliderTest, OwnerIsDestroyedOnSliderDestroy) {
358 size_t child_windows = root_window()->children().size();
359 aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
360 window->SetBounds(gfx::Rect(0, 0, 400, 400));
361 EXPECT_EQ(child_windows + 1, root_window()->children().size());
363 WindowSliderDeleteOwnerOnDestroy slider_delegate(window);
364 aura::test::EventGenerator generator(root_window());
366 // Generate a horizontal overscroll.
367 scoped_ptr<WindowSlider> slider(
368 new WindowSlider(&slider_delegate, root_window(), window));
369 generator.GestureScrollSequence(gfx::Point(10, 10),
371 base::TimeDelta::FromMilliseconds(10),
373 EXPECT_TRUE(slider_delegate.created_back_layer());
374 EXPECT_TRUE(slider_delegate.slide_completed());
375 EXPECT_FALSE(slider_delegate.created_front_layer());
376 EXPECT_FALSE(slider_delegate.slide_aborted());
377 EXPECT_FALSE(slider_delegate.slider_destroyed());
380 // Destroying the slider would have destroyed |window| too. So |window| should
381 // not need to be destroyed here.
382 EXPECT_EQ(child_windows, root_window()->children().size());
385 // Tests that the owner window can be destroyed from |OnWindowSlideComplete()|
386 // delegate callback without causing a crash.
387 TEST_F(WindowSliderTest, OwnerIsDestroyedOnSlideComplete) {
388 size_t child_windows = root_window()->children().size();
389 aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
390 window->SetBounds(gfx::Rect(0, 0, 400, 400));
391 EXPECT_EQ(child_windows + 1, root_window()->children().size());
393 WindowSliderDeleteOwnerOnComplete slider_delegate(window);
394 aura::test::EventGenerator generator(root_window());
396 // Generate a horizontal overscroll.
397 new WindowSlider(&slider_delegate, root_window(), window);
398 generator.GestureScrollSequence(gfx::Point(10, 10),
400 base::TimeDelta::FromMilliseconds(10),
402 EXPECT_TRUE(slider_delegate.created_back_layer());
403 EXPECT_TRUE(slider_delegate.slide_completed());
404 EXPECT_FALSE(slider_delegate.created_front_layer());
405 EXPECT_FALSE(slider_delegate.slide_aborted());
406 EXPECT_TRUE(slider_delegate.slider_destroyed());
408 // Destroying the slider would have destroyed |window| too. So |window| should
409 // not need to be destroyed here.
410 EXPECT_EQ(child_windows, root_window()->children().size());
413 } // namespace content