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