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. 4 5 #include "content/browser/web_contents/aura/window_slider.h" 6 7 #include "base/bind.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" 15 16 namespace content { 17 18 void DispatchEventDuringScrollCallback(aura::RootWindow* root_window, 19 ui::Event* event, 20 ui::EventType type, 21 const gfx::Vector2dF& delta) { 22 if (type != ui::ET_GESTURE_SCROLL_UPDATE) 23 return; 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)); 30 } 31 32 void ChangeSliderOwnerDuringScrollCallback(scoped_ptr<aura::Window>* window, 33 WindowSlider* slider, 34 ui::EventType type, 35 const gfx::Vector2dF& delta) { 36 if (type != ui::ET_GESTURE_SCROLL_UPDATE) 37 return; 38 aura::Window* new_window = new aura::Window(NULL); 39 new_window->Init(ui::LAYER_TEXTURED); 40 new_window->Show(); 41 slider->ChangeOwner(new_window); 42 (*window)->parent()->AddChild(new_window); 43 window->reset(new_window); 44 } 45 46 // The window delegate does not receive any events. 47 class NoEventWindowDelegate : public aura::test::TestWindowDelegate { 48 public: 49 NoEventWindowDelegate() { 50 } 51 virtual ~NoEventWindowDelegate() {} 52 53 private: 54 // Overridden from aura::WindowDelegate: 55 virtual bool HasHitTestMask() const OVERRIDE { return true; } 56 57 DISALLOW_COPY_AND_ASSIGN(NoEventWindowDelegate); 58 }; 59 60 class WindowSliderDelegateTest : public WindowSlider::Delegate { 61 public: 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) { 69 } 70 virtual ~WindowSliderDelegateTest() {} 71 72 void Reset() { 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; 79 } 80 81 void SetCanCreateLayer(bool can_create_layer) { 82 can_create_layer_ = can_create_layer; 83 } 84 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_; } 90 91 protected: 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); 96 return layer; 97 } 98 99 // Overridden from WindowSlider::Delegate: 100 virtual ui::Layer* CreateBackLayer() OVERRIDE { 101 if (!can_create_layer_) 102 return NULL; 103 created_back_layer_ = true; 104 return CreateLayerForTest(); 105 } 106 107 virtual ui::Layer* CreateFrontLayer() OVERRIDE { 108 if (!can_create_layer_) 109 return NULL; 110 created_front_layer_ = true; 111 return CreateLayerForTest(); 112 } 113 114 virtual void OnWindowSlideComplete() OVERRIDE { 115 slide_completed_ = true; 116 } 117 118 virtual void OnWindowSlideAborted() OVERRIDE { 119 slide_aborted_ = true; 120 } 121 122 virtual void OnWindowSliderDestroyed() OVERRIDE { 123 slider_destroyed_ = true; 124 } 125 126 private: 127 bool can_create_layer_; 128 bool created_back_layer_; 129 bool created_front_layer_; 130 bool slide_completed_; 131 bool slide_aborted_; 132 bool slider_destroyed_; 133 134 DISALLOW_COPY_AND_ASSIGN(WindowSliderDelegateTest); 135 }; 136 137 // This delegate destroys the owner window when the slider is destroyed. 138 class WindowSliderDeleteOwnerOnDestroy : public WindowSliderDelegateTest { 139 public: 140 explicit WindowSliderDeleteOwnerOnDestroy(aura::Window* owner) 141 : owner_(owner) { 142 } 143 virtual ~WindowSliderDeleteOwnerOnDestroy() {} 144 145 private: 146 // Overridden from WindowSlider::Delegate: 147 virtual void OnWindowSliderDestroyed() OVERRIDE { 148 WindowSliderDelegateTest::OnWindowSliderDestroyed(); 149 delete owner_; 150 } 151 152 aura::Window* owner_; 153 DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnDestroy); 154 }; 155 156 // This delegate destroyes the owner window when a slide is completed. 157 class WindowSliderDeleteOwnerOnComplete : public WindowSliderDelegateTest { 158 public: 159 explicit WindowSliderDeleteOwnerOnComplete(aura::Window* owner) 160 : owner_(owner) { 161 } 162 virtual ~WindowSliderDeleteOwnerOnComplete() {} 163 164 private: 165 // Overridden from WindowSlider::Delegate: 166 virtual void OnWindowSlideComplete() OVERRIDE { 167 WindowSliderDelegateTest::OnWindowSlideComplete(); 168 delete owner_; 169 } 170 171 aura::Window* owner_; 172 DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnComplete); 173 }; 174 175 typedef aura::test::AuraTestBase WindowSliderTest; 176 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; 181 182 aura::test::EventGenerator generator(root_window()); 183 184 // Generate a horizontal overscroll. 185 WindowSlider* slider = 186 new WindowSlider(&slider_delegate, root_window(), window.get()); 187 generator.GestureScrollSequence(gfx::Point(10, 10), 188 gfx::Point(160, 10), 189 base::TimeDelta::FromMilliseconds(10), 190 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()); 199 200 // Generat a horizontal overscroll in the reverse direction. 201 generator.GestureScrollSequence(gfx::Point(160, 10), 202 gfx::Point(10, 10), 203 base::TimeDelta::FromMilliseconds(10), 204 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(); 212 213 // Generate a vertical overscroll. 214 generator.GestureScrollSequence(gfx::Point(10, 10), 215 gfx::Point(10, 80), 216 base::TimeDelta::FromMilliseconds(10), 217 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(); 224 225 // Generate a horizontal scroll that starts overscroll, but doesn't scroll 226 // enough to complete it. 227 generator.GestureScrollSequence(gfx::Point(10, 10), 228 gfx::Point(60, 10), 229 base::TimeDelta::FromMilliseconds(10), 230 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(); 238 239 // Destroy the window. This should destroy the slider. 240 window.reset(); 241 EXPECT_TRUE(slider_delegate.slider_destroyed()); 242 } 243 244 // Tests that the window slide is cancelled when a different type of event 245 // happens. 246 TEST_F(WindowSliderTest, WindowSlideIsCancelledOnEvent) { 247 scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL)); 248 WindowSliderDelegateTest slider_delegate; 249 250 ui::Event* events[] = { 251 new ui::MouseEvent(ui::ET_MOUSE_MOVED, 252 gfx::Point(55, 10), 253 gfx::Point(55, 10), 254 0), 255 new ui::KeyEvent(ui::ET_KEY_PRESSED, 256 ui::VKEY_A, 257 0, 258 true), 259 NULL 260 }; 261 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( 267 gfx::Point(10, 10), 268 gfx::Point(80, 10), 269 base::TimeDelta::FromMilliseconds(10), 270 1, 271 base::Bind(&DispatchEventDuringScrollCallback, 272 root_window(), 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(); 280 } 281 window.reset(); 282 EXPECT_TRUE(slider_delegate.slider_destroyed()); 283 } 284 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)); 289 290 NoEventWindowDelegate window_delegate; 291 window_delegate.set_window_component(HTNOWHERE); 292 scoped_ptr<aura::Window> window(CreateNormalWindow(1, parent.get(), 293 &window_delegate)); 294 295 WindowSliderDelegateTest slider_delegate; 296 scoped_ptr<WindowSlider> slider( 297 new WindowSlider(&slider_delegate, parent.get(), window.get())); 298 299 // Generate a horizontal scroll, and change the owner in the middle of the 300 // scroll. 301 aura::test::EventGenerator generator(root_window()); 302 aura::Window* old_window = window.get(); 303 generator.GestureScrollSequenceWithCallback( 304 gfx::Point(10, 10), 305 gfx::Point(80, 10), 306 base::TimeDelta::FromMilliseconds(10), 307 1, 308 base::Bind(&ChangeSliderOwnerDuringScrollCallback, 309 base::Unretained(&window), 310 slider.get())); 311 aura::Window* new_window = window.get(); 312 EXPECT_NE(old_window, new_window); 313 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()); 319 } 320 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); 326 327 aura::test::EventGenerator generator(root_window()); 328 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), 333 gfx::Point(160, 10), 334 base::TimeDelta::FromMilliseconds(10), 335 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()); 342 343 slider_delegate.SetCanCreateLayer(true); 344 generator.GestureScrollSequence(gfx::Point(10, 10), 345 gfx::Point(160, 10), 346 base::TimeDelta::FromMilliseconds(10), 347 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()); 353 } 354 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()); 362 363 WindowSliderDeleteOwnerOnDestroy slider_delegate(window); 364 aura::test::EventGenerator generator(root_window()); 365 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), 370 gfx::Point(160, 10), 371 base::TimeDelta::FromMilliseconds(10), 372 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()); 378 379 slider.reset(); 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()); 383 } 384 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()); 392 393 WindowSliderDeleteOwnerOnComplete slider_delegate(window); 394 aura::test::EventGenerator generator(root_window()); 395 396 // Generate a horizontal overscroll. 397 new WindowSlider(&slider_delegate, root_window(), window); 398 generator.GestureScrollSequence(gfx::Point(10, 10), 399 gfx::Point(160, 10), 400 base::TimeDelta::FromMilliseconds(10), 401 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()); 407 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()); 411 } 412 413 } // namespace content 414