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::WindowEventDispatcher* dispatcher,
21 const gfx::Vector2dF& delta) {
22 if (type != ui::ET_GESTURE_SCROLL_UPDATE)
24 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(event);
25 CHECK(!details.dispatcher_destroyed);
28 void ChangeSliderOwnerDuringScrollCallback(scoped_ptr<aura::Window>* window,
31 const gfx::Vector2dF& delta) {
32 if (type != ui::ET_GESTURE_SCROLL_UPDATE)
34 aura::Window* new_window = new aura::Window(NULL);
35 new_window->Init(aura::WINDOW_LAYER_TEXTURED);
37 slider->ChangeOwner(new_window);
38 (*window)->parent()->AddChild(new_window);
39 window->reset(new_window);
42 // The window delegate does not receive any events.
43 class NoEventWindowDelegate : public aura::test::TestWindowDelegate {
45 NoEventWindowDelegate() {
47 virtual ~NoEventWindowDelegate() {}
50 // Overridden from aura::WindowDelegate:
51 virtual bool HasHitTestMask() const OVERRIDE { return true; }
53 DISALLOW_COPY_AND_ASSIGN(NoEventWindowDelegate);
56 class WindowSliderDelegateTest : public WindowSlider::Delegate {
58 WindowSliderDelegateTest()
59 : can_create_layer_(true),
60 created_back_layer_(false),
61 created_front_layer_(false),
62 slide_completed_(false),
63 slide_aborted_(false),
64 slider_destroyed_(false) {
66 virtual ~WindowSliderDelegateTest() {}
69 can_create_layer_ = true;
70 created_back_layer_ = false;
71 created_front_layer_ = false;
72 slide_completed_ = false;
73 slide_aborted_ = false;
74 slider_destroyed_ = false;
77 void SetCanCreateLayer(bool can_create_layer) {
78 can_create_layer_ = can_create_layer;
81 bool created_back_layer() const { return created_back_layer_; }
82 bool created_front_layer() const { return created_front_layer_; }
83 bool slide_completed() const { return slide_completed_; }
84 bool slide_aborted() const { return slide_aborted_; }
85 bool slider_destroyed() const { return slider_destroyed_; }
88 ui::Layer* CreateLayerForTest() {
89 CHECK(can_create_layer_);
90 ui::Layer* layer = new ui::Layer(ui::LAYER_SOLID_COLOR);
91 layer->SetColor(SK_ColorRED);
95 // Overridden from WindowSlider::Delegate:
96 virtual ui::Layer* CreateBackLayer() OVERRIDE {
97 if (!can_create_layer_)
99 created_back_layer_ = true;
100 return CreateLayerForTest();
103 virtual ui::Layer* CreateFrontLayer() OVERRIDE {
104 if (!can_create_layer_)
106 created_front_layer_ = true;
107 return CreateLayerForTest();
110 virtual void OnWindowSlideComplete() OVERRIDE {
111 slide_completed_ = true;
114 virtual void OnWindowSlideAborted() OVERRIDE {
115 slide_aborted_ = true;
118 virtual void OnWindowSliderDestroyed() OVERRIDE {
119 slider_destroyed_ = true;
123 bool can_create_layer_;
124 bool created_back_layer_;
125 bool created_front_layer_;
126 bool slide_completed_;
128 bool slider_destroyed_;
130 DISALLOW_COPY_AND_ASSIGN(WindowSliderDelegateTest);
133 // This delegate destroys the owner window when the slider is destroyed.
134 class WindowSliderDeleteOwnerOnDestroy : public WindowSliderDelegateTest {
136 explicit WindowSliderDeleteOwnerOnDestroy(aura::Window* owner)
139 virtual ~WindowSliderDeleteOwnerOnDestroy() {}
142 // Overridden from WindowSlider::Delegate:
143 virtual void OnWindowSliderDestroyed() OVERRIDE {
144 WindowSliderDelegateTest::OnWindowSliderDestroyed();
148 aura::Window* owner_;
149 DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnDestroy);
152 // This delegate destroyes the owner window when a slide is completed.
153 class WindowSliderDeleteOwnerOnComplete : public WindowSliderDelegateTest {
155 explicit WindowSliderDeleteOwnerOnComplete(aura::Window* owner)
158 virtual ~WindowSliderDeleteOwnerOnComplete() {}
161 // Overridden from WindowSlider::Delegate:
162 virtual void OnWindowSlideComplete() OVERRIDE {
163 WindowSliderDelegateTest::OnWindowSlideComplete();
167 aura::Window* owner_;
168 DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnComplete);
171 typedef aura::test::AuraTestBase WindowSliderTest;
173 TEST_F(WindowSliderTest, WindowSlideUsingGesture) {
174 scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
175 window->SetBounds(gfx::Rect(0, 0, 400, 400));
176 WindowSliderDelegateTest slider_delegate;
178 aura::test::EventGenerator generator(root_window());
180 // Generate a horizontal overscroll.
181 WindowSlider* slider =
182 new WindowSlider(&slider_delegate, root_window(), window.get());
183 generator.GestureScrollSequence(gfx::Point(10, 10),
185 base::TimeDelta::FromMilliseconds(10),
187 EXPECT_TRUE(slider_delegate.created_back_layer());
188 EXPECT_TRUE(slider_delegate.slide_completed());
189 EXPECT_FALSE(slider_delegate.created_front_layer());
190 EXPECT_FALSE(slider_delegate.slide_aborted());
191 EXPECT_FALSE(slider_delegate.slider_destroyed());
192 EXPECT_FALSE(slider->IsSlideInProgress());
193 slider_delegate.Reset();
194 window->SetTransform(gfx::Transform());
196 // Generat a horizontal overscroll in the reverse direction.
197 generator.GestureScrollSequence(gfx::Point(180, 10),
199 base::TimeDelta::FromMilliseconds(10),
201 EXPECT_TRUE(slider_delegate.created_front_layer());
202 EXPECT_TRUE(slider_delegate.slide_completed());
203 EXPECT_FALSE(slider_delegate.created_back_layer());
204 EXPECT_FALSE(slider_delegate.slide_aborted());
205 EXPECT_FALSE(slider_delegate.slider_destroyed());
206 EXPECT_FALSE(slider->IsSlideInProgress());
207 slider_delegate.Reset();
209 // Generate a vertical overscroll.
210 generator.GestureScrollSequence(gfx::Point(10, 10),
212 base::TimeDelta::FromMilliseconds(10),
214 EXPECT_FALSE(slider_delegate.created_back_layer());
215 EXPECT_FALSE(slider_delegate.slide_completed());
216 EXPECT_FALSE(slider_delegate.created_front_layer());
217 EXPECT_FALSE(slider_delegate.slide_aborted());
218 EXPECT_FALSE(slider->IsSlideInProgress());
219 slider_delegate.Reset();
221 // Generate a horizontal scroll that starts overscroll, but doesn't scroll
222 // enough to complete it.
223 generator.GestureScrollSequence(gfx::Point(10, 10),
225 base::TimeDelta::FromMilliseconds(10),
227 EXPECT_TRUE(slider_delegate.created_back_layer());
228 EXPECT_TRUE(slider_delegate.slide_aborted());
229 EXPECT_FALSE(slider_delegate.created_front_layer());
230 EXPECT_FALSE(slider_delegate.slide_completed());
231 EXPECT_FALSE(slider_delegate.slider_destroyed());
232 EXPECT_FALSE(slider->IsSlideInProgress());
233 slider_delegate.Reset();
235 // Destroy the window. This should destroy the slider.
237 EXPECT_TRUE(slider_delegate.slider_destroyed());
240 // Tests that the window slide is cancelled when a different type of event
242 TEST_F(WindowSliderTest, WindowSlideIsCancelledOnEvent) {
243 scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
244 WindowSliderDelegateTest slider_delegate;
246 ui::Event* events[] = {
247 new ui::MouseEvent(ui::ET_MOUSE_MOVED,
251 new ui::KeyEvent(ui::ET_KEY_PRESSED,
258 new WindowSlider(&slider_delegate, root_window(), window.get());
259 for (int i = 0; events[i]; ++i) {
260 // Generate a horizontal overscroll.
261 aura::test::EventGenerator generator(root_window());
262 generator.GestureScrollSequenceWithCallback(
265 base::TimeDelta::FromMilliseconds(10),
267 base::Bind(&DispatchEventDuringScrollCallback,
268 root_window()->GetDispatcher(),
269 base::Owned(events[i])));
270 EXPECT_TRUE(slider_delegate.created_back_layer());
271 EXPECT_TRUE(slider_delegate.slide_aborted());
272 EXPECT_FALSE(slider_delegate.created_front_layer());
273 EXPECT_FALSE(slider_delegate.slide_completed());
274 EXPECT_FALSE(slider_delegate.slider_destroyed());
275 slider_delegate.Reset();
278 EXPECT_TRUE(slider_delegate.slider_destroyed());
281 // Tests that the slide works correctly when the owner of the window changes
282 // during the duration of the slide.
283 TEST_F(WindowSliderTest, OwnerWindowChangesDuringWindowSlide) {
284 scoped_ptr<aura::Window> parent(CreateNormalWindow(0, root_window(), NULL));
286 NoEventWindowDelegate window_delegate;
287 window_delegate.set_window_component(HTNOWHERE);
288 scoped_ptr<aura::Window> window(CreateNormalWindow(1, parent.get(),
291 WindowSliderDelegateTest slider_delegate;
292 scoped_ptr<WindowSlider> slider(
293 new WindowSlider(&slider_delegate, parent.get(), window.get()));
295 // Generate a horizontal scroll, and change the owner in the middle of the
297 aura::test::EventGenerator generator(root_window());
298 aura::Window* old_window = window.get();
299 generator.GestureScrollSequenceWithCallback(
302 base::TimeDelta::FromMilliseconds(10),
304 base::Bind(&ChangeSliderOwnerDuringScrollCallback,
305 base::Unretained(&window),
307 aura::Window* new_window = window.get();
308 EXPECT_NE(old_window, new_window);
310 EXPECT_TRUE(slider_delegate.created_back_layer());
311 EXPECT_TRUE(slider_delegate.slide_completed());
312 EXPECT_FALSE(slider_delegate.created_front_layer());
313 EXPECT_FALSE(slider_delegate.slide_aborted());
314 EXPECT_FALSE(slider_delegate.slider_destroyed());
317 TEST_F(WindowSliderTest, NoSlideWhenLayerCantBeCreated) {
318 scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
319 window->SetBounds(gfx::Rect(0, 0, 400, 400));
320 WindowSliderDelegateTest slider_delegate;
321 slider_delegate.SetCanCreateLayer(false);
323 aura::test::EventGenerator generator(root_window());
325 // Generate a horizontal overscroll.
326 scoped_ptr<WindowSlider> slider(
327 new WindowSlider(&slider_delegate, root_window(), window.get()));
328 generator.GestureScrollSequence(gfx::Point(10, 10),
330 base::TimeDelta::FromMilliseconds(10),
332 EXPECT_FALSE(slider_delegate.created_back_layer());
333 EXPECT_FALSE(slider_delegate.slide_completed());
334 EXPECT_FALSE(slider_delegate.created_front_layer());
335 EXPECT_FALSE(slider_delegate.slide_aborted());
336 EXPECT_FALSE(slider_delegate.slider_destroyed());
337 window->SetTransform(gfx::Transform());
339 slider_delegate.SetCanCreateLayer(true);
340 generator.GestureScrollSequence(gfx::Point(10, 10),
342 base::TimeDelta::FromMilliseconds(10),
344 EXPECT_TRUE(slider_delegate.created_back_layer());
345 EXPECT_TRUE(slider_delegate.slide_completed());
346 EXPECT_FALSE(slider_delegate.created_front_layer());
347 EXPECT_FALSE(slider_delegate.slide_aborted());
348 EXPECT_FALSE(slider_delegate.slider_destroyed());
351 // Tests that the owner window can be destroyed from |OnWindowSliderDestroyed()|
352 // delegate callback without causing a crash.
353 TEST_F(WindowSliderTest, OwnerIsDestroyedOnSliderDestroy) {
354 size_t child_windows = root_window()->children().size();
355 aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
356 window->SetBounds(gfx::Rect(0, 0, 400, 400));
357 EXPECT_EQ(child_windows + 1, root_window()->children().size());
359 WindowSliderDeleteOwnerOnDestroy slider_delegate(window);
360 aura::test::EventGenerator generator(root_window());
362 // Generate a horizontal overscroll.
363 scoped_ptr<WindowSlider> slider(
364 new WindowSlider(&slider_delegate, root_window(), window));
365 generator.GestureScrollSequence(gfx::Point(10, 10),
367 base::TimeDelta::FromMilliseconds(10),
369 EXPECT_TRUE(slider_delegate.created_back_layer());
370 EXPECT_TRUE(slider_delegate.slide_completed());
371 EXPECT_FALSE(slider_delegate.created_front_layer());
372 EXPECT_FALSE(slider_delegate.slide_aborted());
373 EXPECT_FALSE(slider_delegate.slider_destroyed());
376 // Destroying the slider would have destroyed |window| too. So |window| should
377 // not need to be destroyed here.
378 EXPECT_EQ(child_windows, root_window()->children().size());
381 // Tests that the owner window can be destroyed from |OnWindowSlideComplete()|
382 // delegate callback without causing a crash.
383 TEST_F(WindowSliderTest, OwnerIsDestroyedOnSlideComplete) {
384 size_t child_windows = root_window()->children().size();
385 aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
386 window->SetBounds(gfx::Rect(0, 0, 400, 400));
387 EXPECT_EQ(child_windows + 1, root_window()->children().size());
389 WindowSliderDeleteOwnerOnComplete slider_delegate(window);
390 aura::test::EventGenerator generator(root_window());
392 // Generate a horizontal overscroll.
393 new WindowSlider(&slider_delegate, root_window(), window);
394 generator.GestureScrollSequence(gfx::Point(10, 10),
396 base::TimeDelta::FromMilliseconds(10),
398 EXPECT_TRUE(slider_delegate.created_back_layer());
399 EXPECT_TRUE(slider_delegate.slide_completed());
400 EXPECT_FALSE(slider_delegate.created_front_layer());
401 EXPECT_FALSE(slider_delegate.slide_aborted());
402 EXPECT_TRUE(slider_delegate.slider_destroyed());
404 // Destroying the slider would have destroyed |window| too. So |window| should
405 // not need to be destroyed here.
406 EXPECT_EQ(child_windows, root_window()->children().size());
409 } // namespace content