Home | History | Annotate | Download | only in ash
      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/ash/window_positioner.h"
      6 
      7 #include "ash/shell.h"
      8 #include "ash/test/ash_test_base.h"
      9 #include "ash/test/test_shell_delegate.h"
     10 #include "ash/wm/window_resizer.h"
     11 #include "base/compiler_specific.h"
     12 #include "base/logging.h"
     13 #include "chrome/browser/ui/browser.h"
     14 #include "chrome/browser/ui/host_desktop.h"
     15 #include "chrome/test/base/test_browser_window.h"
     16 #include "chrome/test/base/testing_profile.h"
     17 #include "content/public/browser/browser_thread.h"
     18 #include "content/public/test/render_view_test.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 #include "ui/aura/env.h"
     21 #include "ui/aura/root_window.h"
     22 #include "ui/aura/test/test_windows.h"
     23 #include "ui/gfx/screen.h"
     24 
     25 namespace ash {
     26 namespace test {
     27 
     28 namespace {
     29 
     30 // A browser window proxy which is able to associate an aura native window with
     31 // it.
     32 class TestBrowserWindowAura : public TestBrowserWindow {
     33  public:
     34   explicit TestBrowserWindowAura(aura::Window *native_window);
     35   virtual ~TestBrowserWindowAura();
     36 
     37   virtual gfx::NativeWindow GetNativeWindow() OVERRIDE {
     38     return native_window_;
     39   }
     40 
     41  private:
     42   gfx::NativeWindow native_window_;
     43 
     44   DISALLOW_COPY_AND_ASSIGN(TestBrowserWindowAura);
     45 };
     46 
     47 TestBrowserWindowAura::TestBrowserWindowAura(aura::Window *native_window)
     48     : native_window_(native_window) {
     49 }
     50 
     51 TestBrowserWindowAura::~TestBrowserWindowAura() {}
     52 
     53 } // namespace
     54 
     55 // A test class for preparing window positioner tests - it creates a testing
     56 // base by adding a window and a popup which can be independently
     57 // positioned to see where the positioner will place the window.
     58 class WindowPositionerTest : public AshTestBase {
     59  public:
     60   WindowPositionerTest();
     61 
     62   virtual void SetUp() OVERRIDE;
     63   virtual void TearDown() OVERRIDE;
     64 
     65  protected:
     66   aura::Window* window() { return window_.get(); }
     67   aura::Window* popup() { return popup_.get(); }
     68 
     69   Browser* window_browser() { return window_owning_browser_.get(); }
     70   Browser* popup_browser() { return popup_owning_browser_.get(); }
     71 
     72   WindowPositioner* window_positioner() { return window_positioner_; }
     73 
     74   // The positioner & desktop's used grid alignment size.
     75   const int grid_size_;
     76 
     77  private:
     78   WindowPositioner* window_positioner_;
     79 
     80   // These two need to be deleted after everything else is gone.
     81   TestingProfile profile_;
     82 
     83   // These get created for each session.
     84   scoped_ptr<aura::Window> window_;
     85   scoped_ptr<aura::Window> popup_;
     86 
     87   scoped_ptr<BrowserWindow> browser_window_;
     88   scoped_ptr<BrowserWindow> browser_popup_;
     89 
     90   scoped_ptr<Browser> window_owning_browser_;
     91   scoped_ptr<Browser> popup_owning_browser_;
     92 
     93   DISALLOW_COPY_AND_ASSIGN(WindowPositionerTest);
     94 };
     95 
     96 WindowPositionerTest::WindowPositionerTest()
     97     : grid_size_(WindowPositioner::kMinimumWindowOffset),
     98       window_positioner_(NULL) {
     99 }
    100 
    101 void WindowPositionerTest::SetUp() {
    102   AshTestBase::SetUp();
    103   // Create some default dummy windows.
    104   window_.reset(CreateTestWindowInShellWithId(0));
    105   window_->SetBounds(gfx::Rect(16, 32, 640, 320));
    106   popup_.reset(CreateTestWindowInShellWithId(1));
    107   popup_->SetBounds(gfx::Rect(16, 32, 128, 256));
    108 
    109   // Create a browser for the window.
    110   browser_window_.reset(new TestBrowserWindowAura(window_.get()));
    111   Browser::CreateParams window_params(&profile_,
    112                                       chrome::HOST_DESKTOP_TYPE_ASH);
    113   window_params.window = browser_window_.get();
    114   window_owning_browser_.reset(new Browser(window_params));
    115 
    116   // Creating a browser for the popup.
    117   browser_popup_.reset(new TestBrowserWindowAura(popup_.get()));
    118   Browser::CreateParams popup_params(Browser::TYPE_POPUP, &profile_,
    119                                      chrome::HOST_DESKTOP_TYPE_ASH);
    120   popup_params.window = browser_popup_.get();
    121   popup_owning_browser_.reset(new Browser(popup_params));
    122 
    123   // We hide all windows upon start - each user is required to set it up
    124   // as he needs it.
    125   window()->Hide();
    126   popup()->Hide();
    127   window_positioner_ = new WindowPositioner();
    128 }
    129 
    130 void WindowPositionerTest::TearDown() {
    131   // Since the AuraTestBase is needed to create our assets, we have to
    132   // also delete them before we tear it down.
    133   window_owning_browser_.reset(NULL);
    134   popup_owning_browser_.reset(NULL);
    135 
    136   browser_window_.reset(NULL);
    137   browser_popup_.reset(NULL);
    138 
    139   window_.reset(NULL);
    140   popup_.reset(NULL);
    141 
    142   AshTestBase::TearDown();
    143   delete window_positioner_;
    144   window_positioner_ = NULL;
    145 }
    146 
    147 int AlignToGridRoundDown(int location, int grid_size) {
    148   if (grid_size <= 1 || location % grid_size == 0)
    149     return location;
    150   return location / grid_size * grid_size;
    151 }
    152 
    153 TEST_F(WindowPositionerTest, cascading) {
    154   const gfx::Rect work_area =
    155       Shell::GetScreen()->GetPrimaryDisplay().work_area();
    156 
    157   // First see that the window will cascade down when there is no space.
    158   window()->SetBounds(work_area);
    159   window()->Show();
    160 
    161   gfx::Rect popup_position(0, 0, 200, 200);
    162   // Check that it gets cascaded.
    163   gfx::Rect cascade_1 = window_positioner()->GetPopupPosition(popup_position);
    164   EXPECT_EQ(gfx::Rect(work_area.x() + grid_size_, work_area.y() + grid_size_,
    165                       popup_position.width(), popup_position.height()),
    166                       cascade_1);
    167 
    168   gfx::Rect cascade_2 = window_positioner()->GetPopupPosition(popup_position);
    169   EXPECT_EQ(gfx::Rect(work_area.x() + 2 * grid_size_,
    170                       work_area.y() + 2 * grid_size_,
    171                       popup_position.width(), popup_position.height()),
    172                       cascade_2);
    173 
    174   // Check that if there is even only a pixel missing it will cascade.
    175   window()->SetBounds(gfx::Rect(work_area.x() + popup_position.width() - 1,
    176                                 work_area.y() + popup_position.height() - 1,
    177                                 work_area.width() -
    178                                     2 * (popup_position.width() - 1),
    179                                 work_area.height() -
    180                                     2 * (popup_position.height() - 1)));
    181 
    182   gfx::Rect cascade_3 = window_positioner()->GetPopupPosition(popup_position);
    183   EXPECT_EQ(gfx::Rect(work_area.x() + 3 * grid_size_,
    184                       work_area.y() + 3 * grid_size_,
    185                       popup_position.width(), popup_position.height()),
    186                       cascade_3);
    187 
    188   // Check that we overflow into the next line when we do not fit anymore in Y.
    189   gfx::Rect popup_position_4(0, 0, 200,
    190                              work_area.height() -
    191                                  (cascade_3.y() - work_area.y()));
    192   gfx::Rect cascade_4 =
    193       window_positioner()->GetPopupPosition(popup_position_4);
    194   EXPECT_EQ(gfx::Rect(work_area.x() + 2 * grid_size_,
    195                       work_area.y() + grid_size_,
    196                       popup_position_4.width(), popup_position_4.height()),
    197                       cascade_4);
    198 
    199   // Check that we overflow back to the first possible location if we overflow
    200   // to the end.
    201   gfx::Rect popup_position_5(0, 0,
    202                             work_area.width() + 1 -
    203                                 (cascade_4.x() - work_area.x()),
    204                             work_area.height() -
    205                                 (2 * grid_size_ - work_area.y()));
    206   gfx::Rect cascade_5 =
    207       window_positioner()->GetPopupPosition(popup_position_5);
    208   EXPECT_EQ(gfx::Rect(work_area.x() + grid_size_,
    209                       work_area.y() + grid_size_,
    210                       popup_position_5.width(), popup_position_5.height()),
    211                       cascade_5);
    212 }
    213 
    214 TEST_F(WindowPositionerTest, filling) {
    215   const gfx::Rect work_area =
    216       Shell::GetScreen()->GetPrimaryDisplay().work_area();
    217   gfx::Rect popup_position(0, 0, 256, 128);
    218   // Leave space on the left and the right and see if we fill top to bottom.
    219   window()->SetBounds(gfx::Rect(work_area.x() + popup_position.width(),
    220                                 work_area.y(),
    221                                 work_area.width() - 2 * popup_position.width(),
    222                                 work_area.height()));
    223   window()->Show();
    224   // Check that we are positioned in the top left corner.
    225   gfx::Rect top_left = window_positioner()->GetPopupPosition(popup_position);
    226   EXPECT_EQ(gfx::Rect(work_area.x(), work_area.y(),
    227                       popup_position.width(), popup_position.height()),
    228                       top_left);
    229 
    230   // Now block the found location.
    231   popup()->SetBounds(top_left);
    232   popup()->Show();
    233   gfx::Rect mid_left = window_positioner()->GetPopupPosition(popup_position);
    234   EXPECT_EQ(gfx::Rect(work_area.x(),
    235                       AlignToGridRoundDown(
    236                           work_area.y() + top_left.height(), grid_size_),
    237                           popup_position.width(), popup_position.height()),
    238                       mid_left);
    239 
    240   // Block now everything so that we can only put the popup on the bottom
    241   // of the left side.
    242   // Note: We need to keep one "grid spacing free" if the window does not
    243   // fit into the grid (which is true for 200 height).`
    244   popup()->SetBounds(gfx::Rect(work_area.x(), work_area.y(),
    245                                popup_position.width(),
    246                                work_area.height() - popup_position.height() -
    247                                    grid_size_ + 1));
    248   gfx::Rect bottom_left = window_positioner()->GetPopupPosition(
    249                               popup_position);
    250   EXPECT_EQ(gfx::Rect(work_area.x(),
    251                       work_area.bottom() - popup_position.height(),
    252                       popup_position.width(), popup_position.height()),
    253                       bottom_left);
    254 
    255   // Block now enough to force the right side.
    256   popup()->SetBounds(gfx::Rect(work_area.x(), work_area.y(),
    257                                popup_position.width(),
    258                                work_area.height() - popup_position.height() +
    259                                1));
    260   gfx::Rect top_right = window_positioner()->GetPopupPosition(
    261                             popup_position);
    262   EXPECT_EQ(gfx::Rect(AlignToGridRoundDown(work_area.right() -
    263                                            popup_position.width(), grid_size_),
    264                       work_area.y(),
    265                       popup_position.width(), popup_position.height()),
    266                       top_right);
    267 }
    268 
    269 TEST_F(WindowPositionerTest, biggerThenBorder) {
    270   const gfx::Rect work_area =
    271       Shell::GetScreen()->GetPrimaryDisplay().work_area();
    272 
    273   gfx::Rect pop_position(0, 0, work_area.width(), work_area.height());
    274 
    275   // Check that the popup is placed full screen.
    276   gfx::Rect full = window_positioner()->GetPopupPosition(pop_position);
    277   EXPECT_EQ(gfx::Rect(work_area.x(), work_area.y(),
    278                       pop_position.width(), pop_position.height()),
    279                       full);
    280 }
    281 
    282 }  // namespace test
    283 }  // namespace ash
    284