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 20namespace { 21 22class 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 115class TestTargetDisplayProvider : public WindowSizer::TargetDisplayProvider { 116public: 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 134TestStateProvider::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 141void 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 151void 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 159bool 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 171bool 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 181int kWindowTilePixels = WindowSizer::kWindowTilePixels; 182 183// The window sizer commonly used test functions. 184void 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 217void 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 233ui::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& bounds, 239 const gfx::Rect& display_config) { 240 TestScreen test_screen; 241 test_screen.AddDisplay(display_config, display_config); 242 scoped_ptr<TestStateProvider> sp(new TestStateProvider); 243 if (source == PERSISTED || source == BOTH) 244 sp->SetPersistentState(bounds, display_config, show_state_persisted, true); 245 if (source == LAST_ACTIVE || source == BOTH) 246 sp->SetLastActiveState(bounds, show_state_last, true); 247 scoped_ptr<WindowSizer::TargetDisplayProvider> tdp( 248 new TestTargetDisplayProvider); 249 250 WindowSizer sizer(sp.PassAs<WindowSizer::StateProvider>(), 251 tdp.Pass(), &test_screen, browser); 252 253 ui::WindowShowState out_show_state = ui::SHOW_STATE_DEFAULT; 254 gfx::Rect out_bounds; 255 sizer.DetermineWindowBoundsAndShowState( 256 gfx::Rect(), 257 &out_bounds, 258 &out_show_state); 259 return out_show_state; 260} 261 262#if !defined(OS_MACOSX) 263TEST(WindowSizerTestCommon, 264 PersistedWindowOffscreenWithNonAggressiveRepositioning) { 265 { // off the left but the minimum visibility condition is barely satisfied 266 // without relocaiton. 267 gfx::Rect initial_bounds(-470, 50, 500, 400); 268 269 gfx::Rect window_bounds; 270 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 271 initial_bounds, gfx::Rect(), PERSISTED, 272 NULL, gfx::Rect(), &window_bounds); 273 EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString()); 274 } 275 276 { // off the left and the minimum visibility condition is satisfied by 277 // relocation. 278 gfx::Rect window_bounds; 279 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 280 gfx::Rect(-471, 50, 500, 400), gfx::Rect(), PERSISTED, 281 NULL, gfx::Rect(), &window_bounds); 282 EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 50, 500, 400).ToString(), 283 window_bounds.ToString()); 284 } 285 286 { // off the top 287 gfx::Rect initial_bounds(50, -370, 500, 400); 288 289 gfx::Rect window_bounds; 290 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 291 gfx::Rect(50, -370, 500, 400), gfx::Rect(), PERSISTED, 292 NULL, gfx::Rect(), &window_bounds); 293 EXPECT_EQ("50,0 500x400", window_bounds.ToString()); 294 } 295 296 { // off the right but the minimum visibility condition is barely satisified 297 // without relocation. 298 gfx::Rect initial_bounds(994, 50, 500, 400); 299 300 gfx::Rect window_bounds; 301 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 302 initial_bounds, gfx::Rect(), PERSISTED, 303 NULL, gfx::Rect(), &window_bounds); 304 EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString()); 305 } 306 307 { // off the right and the minimum visibility condition is satisified by 308 // relocation. 309 gfx::Rect window_bounds; 310 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 311 gfx::Rect(995, 50, 500, 400), gfx::Rect(), PERSISTED, 312 NULL, gfx::Rect(), &window_bounds); 313 EXPECT_EQ(gfx::Rect(994 /* not 995 */, 50, 500, 400).ToString(), 314 window_bounds.ToString()); 315 } 316 317 { // off the bottom but the minimum visibility condition is barely satisified 318 // without relocation. 319 gfx::Rect initial_bounds(50, 738, 500, 400); 320 321 gfx::Rect window_bounds; 322 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 323 initial_bounds, gfx::Rect(), PERSISTED, 324 NULL, gfx::Rect(), &window_bounds); 325 EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString()); 326 } 327 328 { // off the bottom and the minimum visibility condition is satisified by 329 // relocation. 330 gfx::Rect window_bounds; 331 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 332 gfx::Rect(50, 739, 500, 400), gfx::Rect(), PERSISTED, 333 NULL, gfx::Rect(), &window_bounds); 334 EXPECT_EQ(gfx::Rect(50, 738 /* not 739 */, 500, 400).ToString(), 335 window_bounds.ToString()); 336 } 337 338 { // off the topleft 339 gfx::Rect window_bounds; 340 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 341 gfx::Rect(-471, -371, 500, 400), gfx::Rect(), PERSISTED, 342 NULL, gfx::Rect(), &window_bounds); 343 EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 0, 500, 400).ToString(), 344 window_bounds.ToString()); 345 } 346 347 { // off the topright and the minimum visibility condition is satisified by 348 // relocation. 349 gfx::Rect window_bounds; 350 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 351 gfx::Rect(995, -371, 500, 400), gfx::Rect(), PERSISTED, 352 NULL, gfx::Rect(), &window_bounds); 353 EXPECT_EQ(gfx::Rect(994 /* not 995 */, 0, 500, 400).ToString(), 354 window_bounds.ToString()); 355 } 356 357 { // off the bottomleft and the minimum visibility condition is satisified by 358 // relocation. 359 gfx::Rect window_bounds; 360 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 361 gfx::Rect(-471, 739, 500, 400), gfx::Rect(), PERSISTED, 362 NULL, gfx::Rect(), &window_bounds); 363 EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 364 738 /* not 739 */, 365 500, 366 400).ToString(), 367 window_bounds.ToString()); 368 } 369 370 { // off the bottomright and the minimum visibility condition is satisified by 371 // relocation. 372 gfx::Rect window_bounds; 373 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 374 gfx::Rect(995, 739, 500, 400), gfx::Rect(), PERSISTED, 375 NULL, gfx::Rect(), &window_bounds); 376 EXPECT_EQ(gfx::Rect(994 /* not 995 */, 377 738 /* not 739 */, 378 500, 379 400).ToString(), 380 window_bounds.ToString()); 381 } 382 383 { // entirely off left 384 gfx::Rect window_bounds; 385 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 386 gfx::Rect(-700, 50, 500, 400), gfx::Rect(), PERSISTED, 387 NULL, gfx::Rect(), &window_bounds); 388 EXPECT_EQ(gfx::Rect(-470 /* not -700 */, 50, 500, 400).ToString(), 389 window_bounds.ToString()); 390 } 391 392 { // entirely off left (monitor was detached since last run) 393 gfx::Rect window_bounds; 394 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 395 gfx::Rect(-700, 50, 500, 400), left_s1024x768, PERSISTED, 396 NULL, gfx::Rect(), &window_bounds); 397 EXPECT_EQ("0,50 500x400", window_bounds.ToString()); 398 } 399 400 { // entirely off top 401 gfx::Rect window_bounds; 402 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 403 gfx::Rect(50, -500, 500, 400), gfx::Rect(), PERSISTED, 404 NULL, gfx::Rect(), &window_bounds); 405 EXPECT_EQ("50,0 500x400", window_bounds.ToString()); 406 } 407 408 { // entirely off top (monitor was detached since last run) 409 gfx::Rect window_bounds; 410 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 411 gfx::Rect(50, -500, 500, 400), top_s1024x768, 412 PERSISTED, NULL, gfx::Rect(), &window_bounds); 413 EXPECT_EQ("50,0 500x400", window_bounds.ToString()); 414 } 415 416 { // entirely off right 417 gfx::Rect window_bounds; 418 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 419 gfx::Rect(1200, 50, 500, 400), gfx::Rect(), PERSISTED, 420 NULL, gfx::Rect(), &window_bounds); 421 EXPECT_EQ(gfx::Rect(994 /* not 1200 */, 50, 500, 400).ToString(), 422 window_bounds.ToString()); 423 } 424 425 { // entirely off right (monitor was detached since last run) 426 gfx::Rect window_bounds; 427 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 428 gfx::Rect(1200, 50, 500, 400), right_s1024x768, 429 PERSISTED, NULL, gfx::Rect(), &window_bounds); 430 EXPECT_EQ("524,50 500x400", window_bounds.ToString()); 431 } 432 433 { // entirely off bottom 434 gfx::Rect window_bounds; 435 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 436 gfx::Rect(50, 800, 500, 400), gfx::Rect(), PERSISTED, 437 NULL, gfx::Rect(), &window_bounds); 438 EXPECT_EQ(gfx::Rect(50, 738 /* not 800 */, 500, 400).ToString(), 439 window_bounds.ToString()); 440 } 441 442 { // entirely off bottom (monitor was detached since last run) 443 gfx::Rect window_bounds; 444 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), 445 gfx::Rect(50, 800, 500, 400), bottom_s1024x768, 446 PERSISTED, NULL, gfx::Rect(), &window_bounds); 447 EXPECT_EQ("50,368 500x400", window_bounds.ToString()); 448 } 449} 450 451// Test that the window is sized appropriately for the first run experience 452// where the default window bounds calculation is invoked. 453TEST(WindowSizerTestCommon, AdjustFitSize) { 454 { // Check that the window gets resized to the screen. 455 gfx::Rect window_bounds; 456 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(), 457 gfx::Rect(), DEFAULT, NULL, 458 gfx::Rect(-10, -10, 1024 + 20, 768 + 20), &window_bounds); 459 EXPECT_EQ("0,0 1024x768", window_bounds.ToString()); 460 } 461 462 { // Check that a window which hangs out of the screen get moved back in. 463 gfx::Rect window_bounds; 464 GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(), 465 gfx::Rect(), DEFAULT, NULL, 466 gfx::Rect(1020, 700, 100, 100), &window_bounds); 467 EXPECT_EQ("924,668 100x100", window_bounds.ToString()); 468 } 469} 470 471#endif // defined(OS_MACOSX) 472