1 // Copyright (c) 2012 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 "chrome/browser/ui/window_sizer/window_sizer_common_unittest.h" 6 7 #include "ash/wm/window_resizer.h" 8 #include "base/compiler_specific.h" 9 #include "chrome/browser/ui/browser.h" 10 #include "chrome/common/chrome_switches.h" 11 #include "chrome/test/base/testing_profile.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "ui/gfx/display.h" 14 #include "ui/gfx/screen.h" 15 16 #if defined(USE_AURA) 17 #include "ui/aura/window.h" 18 #endif 19 20 namespace { 21 22 class TestScreen : public gfx::Screen { 23 public: 24 TestScreen() {} 25 virtual ~TestScreen() {} 26 27 // Overridden from gfx::Screen: 28 virtual bool IsDIPEnabled() OVERRIDE { 29 NOTREACHED(); 30 return false; 31 } 32 33 virtual gfx::Point GetCursorScreenPoint() OVERRIDE { 34 NOTREACHED(); 35 return gfx::Point(); 36 } 37 38 virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { 39 NOTREACHED(); 40 return NULL; 41 } 42 43 virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) 44 OVERRIDE { 45 NOTREACHED(); 46 return NULL; 47 } 48 49 virtual int GetNumDisplays() const OVERRIDE { 50 return displays_.size(); 51 } 52 53 virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { 54 return displays_; 55 } 56 57 virtual gfx::Display GetDisplayNearestWindow( 58 gfx::NativeView view) const OVERRIDE { 59 #if defined(USE_AURA) 60 return GetDisplayMatching(view->GetBoundsInScreen()); 61 #else 62 NOTREACHED(); 63 return gfx::Display(); 64 #endif 65 } 66 67 virtual gfx::Display GetDisplayNearestPoint( 68 const gfx::Point& point) const OVERRIDE { 69 NOTREACHED(); 70 return gfx::Display(); 71 } 72 73 virtual gfx::Display GetDisplayMatching( 74 const gfx::Rect& match_rect) const OVERRIDE { 75 int max_area = 0; 76 size_t max_area_index = 0; 77 78 for (size_t i = 0; i < displays_.size(); ++i) { 79 gfx::Rect overlap = displays_[i].bounds(); 80 overlap.Intersect(match_rect); 81 int area = overlap.width() * overlap.height(); 82 if (area > max_area) { 83 max_area = area; 84 max_area_index = i; 85 } 86 } 87 return displays_[max_area_index]; 88 } 89 90 virtual gfx::Display GetPrimaryDisplay() const OVERRIDE { 91 return displays_[0]; 92 } 93 94 virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE { 95 NOTREACHED(); 96 } 97 98 virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE { 99 NOTREACHED(); 100 } 101 102 void AddDisplay(const gfx::Rect& bounds, 103 const gfx::Rect& work_area) { 104 gfx::Display display(displays_.size(), bounds); 105 display.set_work_area(work_area); 106 displays_.push_back(display); 107 } 108 109 private: 110 std::vector<gfx::Display> displays_; 111 112 DISALLOW_COPY_AND_ASSIGN(TestScreen); 113 }; 114 115 class TestTargetDisplayProvider : public WindowSizer::TargetDisplayProvider { 116 public: 117 TestTargetDisplayProvider() {} 118 virtual ~TestTargetDisplayProvider() {} 119 120 virtual gfx::Display GetTargetDisplay( 121 const gfx::Screen* screen, 122 const gfx::Rect& bounds) const OVERRIDE { 123 // On ash, the bounds is used as a indicator to specify 124 // the target display. 125 return screen->GetDisplayMatching(bounds); 126 } 127 128 private: 129 DISALLOW_COPY_AND_ASSIGN(TestTargetDisplayProvider); 130 }; 131 132 } // namespace 133 134 TestStateProvider::TestStateProvider(): 135 has_persistent_data_(false), 136 persistent_show_state_(ui::SHOW_STATE_DEFAULT), 137 has_last_active_data_(false), 138 last_active_show_state_(ui::SHOW_STATE_DEFAULT) { 139 } 140 141 void TestStateProvider::SetPersistentState(const gfx::Rect& bounds, 142 const gfx::Rect& work_area, 143 ui::WindowShowState show_state, 144 bool has_persistent_data) { 145 persistent_bounds_ = bounds; 146 persistent_work_area_ = work_area; 147 persistent_show_state_ = show_state; 148 has_persistent_data_ = has_persistent_data; 149 } 150 151 void TestStateProvider::SetLastActiveState(const gfx::Rect& bounds, 152 ui::WindowShowState show_state, 153 bool has_last_active_data) { 154 last_active_bounds_ = bounds; 155 last_active_show_state_ = show_state; 156 has_last_active_data_ = has_last_active_data; 157 } 158 159 bool TestStateProvider::GetPersistentState( 160 gfx::Rect* bounds, 161 gfx::Rect* saved_work_area, 162 ui::WindowShowState* show_state) const { 163 DCHECK(show_state); 164 *bounds = persistent_bounds_; 165 *saved_work_area = persistent_work_area_; 166 if (*show_state == ui::SHOW_STATE_DEFAULT) 167 *show_state = persistent_show_state_; 168 return has_persistent_data_; 169 } 170 171 bool TestStateProvider::GetLastActiveWindowState( 172 gfx::Rect* bounds, 173 ui::WindowShowState* show_state) const { 174 DCHECK(show_state); 175 *bounds = last_active_bounds_; 176 if (*show_state == ui::SHOW_STATE_DEFAULT) 177 *show_state = last_active_show_state_; 178 return has_last_active_data_; 179 } 180 181 int kWindowTilePixels = WindowSizer::kWindowTilePixels; 182 183 // The window sizer commonly used test functions. 184 void GetWindowBoundsAndShowState( 185 const gfx::Rect& monitor1_bounds, 186 const gfx::Rect& monitor1_work_area, 187 const gfx::Rect& monitor2_bounds, 188 const gfx::Rect& bounds, 189 const gfx::Rect& work_area, 190 ui::WindowShowState show_state_persisted, 191 ui::WindowShowState show_state_last, 192 Source source, 193 const Browser* browser, 194 const gfx::Rect& passed_in, 195 gfx::Rect* out_bounds, 196 ui::WindowShowState* out_show_state) { 197 DCHECK(out_show_state); 198 TestScreen test_screen; 199 test_screen.AddDisplay(monitor1_bounds, monitor1_work_area); 200 if (!monitor2_bounds.IsEmpty()) 201 test_screen.AddDisplay(monitor2_bounds, monitor2_bounds); 202 scoped_ptr<TestStateProvider> sp(new TestStateProvider); 203 if (source == PERSISTED || source == BOTH) 204 sp->SetPersistentState(bounds, work_area, show_state_persisted, true); 205 if (source == LAST_ACTIVE || source == BOTH) 206 sp->SetLastActiveState(bounds, show_state_last, true); 207 scoped_ptr<WindowSizer::TargetDisplayProvider> tdp( 208 new TestTargetDisplayProvider); 209 210 WindowSizer sizer(sp.PassAs<WindowSizer::StateProvider>(), 211 tdp.Pass(), &test_screen, browser); 212 sizer.DetermineWindowBoundsAndShowState(passed_in, 213 out_bounds, 214 out_show_state); 215 } 216 217 void GetWindowBounds(const gfx::Rect& monitor1_bounds, 218 const gfx::Rect& monitor1_work_area, 219 const gfx::Rect& monitor2_bounds, 220 const gfx::Rect& bounds, 221 const gfx::Rect& work_area, 222 Source source, 223 const Browser* browser, 224 const gfx::Rect& passed_in, 225 gfx::Rect* out_bounds) { 226 ui::WindowShowState out_show_state = ui::SHOW_STATE_DEFAULT; 227 GetWindowBoundsAndShowState( 228 monitor1_bounds, monitor1_work_area, monitor2_bounds, bounds, work_area, 229 ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_DEFAULT, source, browser, 230 passed_in, out_bounds, &out_show_state); 231 } 232 233 ui::WindowShowState GetWindowShowState( 234 ui::WindowShowState show_state_persisted, 235 ui::WindowShowState show_state_last, 236 Source source, 237 const Browser* browser, 238 const gfx::Rect& display_config) { 239 gfx::Rect bounds = display_config; 240 gfx::Rect work_area = display_config; 241 TestScreen test_screen; 242 test_screen.AddDisplay(display_config, display_config); 243 scoped_ptr<TestStateProvider> sp(new TestStateProvider); 244 if (source == PERSISTED || source == BOTH) 245 sp->SetPersistentState(bounds, work_area, show_state_persisted, true); 246 if (source == LAST_ACTIVE || source == BOTH) 247 sp->SetLastActiveState(bounds, show_state_last, true); 248 scoped_ptr<WindowSizer::TargetDisplayProvider> tdp( 249 new TestTargetDisplayProvider); 250 251 WindowSizer sizer(sp.PassAs<WindowSizer::StateProvider>(), 252 tdp.Pass(), &test_screen, browser); 253 254 ui::WindowShowState out_show_state = ui::SHOW_STATE_DEFAULT; 255 gfx::Rect out_bounds; 256 sizer.DetermineWindowBoundsAndShowState( 257 gfx::Rect(), 258 &out_bounds, 259 &out_show_state); 260 return out_show_state; 261 } 262 263 #if !defined(OS_MACOSX) 264 TEST(WindowSizerTestCommon, 265 PersistedWindowOffscreenWithNonAggressiveRepositioning) { 266 { // off the left but the minimum visibility condition is barely satisfied 267 // without relocaiton. 268 gfx::Rect initial_bounds(-470, 50, 500, 400); 269 270 gfx::Rect window_bounds; 271 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 272 initial_bounds, gfx::Rect(), PERSISTED, 273 NULL, gfx::Rect(), &window_bounds); 274 EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString()); 275 } 276 277 { // off the left and the minimum visibility condition is satisfied by 278 // relocation. 279 gfx::Rect window_bounds; 280 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 281 gfx::Rect(-471, 50, 500, 400), gfx::Rect(), PERSISTED, 282 NULL, gfx::Rect(), &window_bounds); 283 EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 50, 500, 400).ToString(), 284 window_bounds.ToString()); 285 } 286 287 { // off the top 288 gfx::Rect initial_bounds(50, -370, 500, 400); 289 290 gfx::Rect window_bounds; 291 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 292 gfx::Rect(50, -370, 500, 400), gfx::Rect(), PERSISTED, 293 NULL, gfx::Rect(), &window_bounds); 294 EXPECT_EQ("50,0 500x400", window_bounds.ToString()); 295 } 296 297 { // off the right but the minimum visibility condition is barely satisified 298 // without relocation. 299 gfx::Rect initial_bounds(994, 50, 500, 400); 300 301 gfx::Rect window_bounds; 302 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 303 initial_bounds, gfx::Rect(), PERSISTED, 304 NULL, gfx::Rect(), &window_bounds); 305 EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString()); 306 } 307 308 { // off the right and the minimum visibility condition is satisified by 309 // relocation. 310 gfx::Rect window_bounds; 311 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 312 gfx::Rect(995, 50, 500, 400), gfx::Rect(), PERSISTED, 313 NULL, gfx::Rect(), &window_bounds); 314 EXPECT_EQ(gfx::Rect(994 /* not 995 */, 50, 500, 400).ToString(), 315 window_bounds.ToString()); 316 } 317 318 { // off the bottom but the minimum visibility condition is barely satisified 319 // without relocation. 320 gfx::Rect initial_bounds(50, 738, 500, 400); 321 322 gfx::Rect window_bounds; 323 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 324 initial_bounds, gfx::Rect(), PERSISTED, 325 NULL, gfx::Rect(), &window_bounds); 326 EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString()); 327 } 328 329 { // off the bottom and the minimum visibility condition is satisified by 330 // relocation. 331 gfx::Rect window_bounds; 332 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 333 gfx::Rect(50, 739, 500, 400), gfx::Rect(), PERSISTED, 334 NULL, gfx::Rect(), &window_bounds); 335 EXPECT_EQ(gfx::Rect(50, 738 /* not 739 */, 500, 400).ToString(), 336 window_bounds.ToString()); 337 } 338 339 { // off the topleft 340 gfx::Rect window_bounds; 341 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 342 gfx::Rect(-471, -371, 500, 400), gfx::Rect(), PERSISTED, 343 NULL, gfx::Rect(), &window_bounds); 344 EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 0, 500, 400).ToString(), 345 window_bounds.ToString()); 346 } 347 348 { // off the topright and the minimum visibility condition is satisified by 349 // relocation. 350 gfx::Rect window_bounds; 351 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 352 gfx::Rect(995, -371, 500, 400), gfx::Rect(), PERSISTED, 353 NULL, gfx::Rect(), &window_bounds); 354 EXPECT_EQ(gfx::Rect(994 /* not 995 */, 0, 500, 400).ToString(), 355 window_bounds.ToString()); 356 } 357 358 { // off the bottomleft and the minimum visibility condition is satisified by 359 // relocation. 360 gfx::Rect window_bounds; 361 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 362 gfx::Rect(-471, 739, 500, 400), gfx::Rect(), PERSISTED, 363 NULL, gfx::Rect(), &window_bounds); 364 EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 365 738 /* not 739 */, 366 500, 367 400).ToString(), 368 window_bounds.ToString()); 369 } 370 371 { // off the bottomright and the minimum visibility condition is satisified by 372 // relocation. 373 gfx::Rect window_bounds; 374 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 375 gfx::Rect(995, 739, 500, 400), gfx::Rect(), PERSISTED, 376 NULL, gfx::Rect(), &window_bounds); 377 EXPECT_EQ(gfx::Rect(994 /* not 995 */, 378 738 /* not 739 */, 379 500, 380 400).ToString(), 381 window_bounds.ToString()); 382 } 383 384 { // entirely off left 385 gfx::Rect window_bounds; 386 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 387 gfx::Rect(-700, 50, 500, 400), gfx::Rect(), PERSISTED, 388 NULL, gfx::Rect(), &window_bounds); 389 EXPECT_EQ(gfx::Rect(-470 /* not -700 */, 50, 500, 400).ToString(), 390 window_bounds.ToString()); 391 } 392 393 { // entirely off left (monitor was detached since last run) 394 gfx::Rect window_bounds; 395 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 396 gfx::Rect(-700, 50, 500, 400), left_s1024x768, PERSISTED, 397 NULL, gfx::Rect(), &window_bounds); 398 EXPECT_EQ("0,50 500x400", window_bounds.ToString()); 399 } 400 401 { // entirely off top 402 gfx::Rect window_bounds; 403 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 404 gfx::Rect(50, -500, 500, 400), gfx::Rect(), PERSISTED, 405 NULL, gfx::Rect(), &window_bounds); 406 EXPECT_EQ("50,0 500x400", window_bounds.ToString()); 407 } 408 409 { // entirely off top (monitor was detached since last run) 410 gfx::Rect window_bounds; 411 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 412 gfx::Rect(50, -500, 500, 400), top_s1024x768, 413 PERSISTED, NULL, gfx::Rect(), &window_bounds); 414 EXPECT_EQ("50,0 500x400", window_bounds.ToString()); 415 } 416 417 { // entirely off right 418 gfx::Rect window_bounds; 419 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 420 gfx::Rect(1200, 50, 500, 400), gfx::Rect(), PERSISTED, 421 NULL, gfx::Rect(), &window_bounds); 422 EXPECT_EQ(gfx::Rect(994 /* not 1200 */, 50, 500, 400).ToString(), 423 window_bounds.ToString()); 424 } 425 426 { // entirely off right (monitor was detached since last run) 427 gfx::Rect window_bounds; 428 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 429 gfx::Rect(1200, 50, 500, 400), right_s1024x768, 430 PERSISTED, NULL, gfx::Rect(), &window_bounds); 431 EXPECT_EQ("524,50 500x400", window_bounds.ToString()); 432 } 433 434 { // entirely off bottom 435 gfx::Rect window_bounds; 436 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 437 gfx::Rect(50, 800, 500, 400), gfx::Rect(), PERSISTED, 438 NULL, gfx::Rect(), &window_bounds); 439 EXPECT_EQ(gfx::Rect(50, 738 /* not 800 */, 500, 400).ToString(), 440 window_bounds.ToString()); 441 } 442 443 { // entirely off bottom (monitor was detached since last run) 444 gfx::Rect window_bounds; 445 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 446 gfx::Rect(50, 800, 500, 400), bottom_s1024x768, 447 PERSISTED, NULL, gfx::Rect(), &window_bounds); 448 EXPECT_EQ("50,368 500x400", window_bounds.ToString()); 449 } 450 } 451 452 // Test that the window is sized appropriately for the first run experience 453 // where the default window bounds calculation is invoked. 454 TEST(WindowSizerTestCommon, AdjustFitSize) { 455 { // Check that the window gets resized to the screen. 456 gfx::Rect window_bounds; 457 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(), 458 gfx::Rect(), DEFAULT, NULL, 459 gfx::Rect(-10, -10, 1024 + 20, 768 + 20), &window_bounds); 460 EXPECT_EQ("0,0 1024x768", window_bounds.ToString()); 461 } 462 463 { // Check that a window which hangs out of the screen get moved back in. 464 gfx::Rect window_bounds; 465 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(), 466 gfx::Rect(), DEFAULT, NULL, 467 gfx::Rect(1020, 700, 100, 100), &window_bounds); 468 EXPECT_EQ("924,668 100x100", window_bounds.ToString()); 469 } 470 } 471 472 #endif // defined(OS_MACOSX) 473