// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ash/wm/window_positioner.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/test_shell_delegate.h" #include "ash/wm/window_resizer.h" #include "base/compiler_specific.h" #include "base/logging.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/test/base/test_browser_window.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/render_view_test.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/env.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/gfx/screen.h" namespace ash { namespace test { namespace { // A browser window proxy which is able to associate an aura native window with // it. class TestBrowserWindowAura : public TestBrowserWindow { public: explicit TestBrowserWindowAura(aura::Window* native_window); virtual ~TestBrowserWindowAura(); virtual gfx::NativeWindow GetNativeWindow() OVERRIDE { return native_window_; } private: gfx::NativeWindow native_window_; DISALLOW_COPY_AND_ASSIGN(TestBrowserWindowAura); }; TestBrowserWindowAura::TestBrowserWindowAura(aura::Window *native_window) : native_window_(native_window) { } TestBrowserWindowAura::~TestBrowserWindowAura() {} } // namespace // A test class for preparing window positioner tests - it creates a testing // base by adding a window and a popup which can be independently // positioned to see where the positioner will place the window. class WindowPositionerTest : public AshTestBase { public: WindowPositionerTest(); virtual void SetUp() OVERRIDE; virtual void TearDown() OVERRIDE; protected: aura::Window* window() { return window_.get(); } aura::Window* popup() { return popup_.get(); } Browser* window_browser() { return window_owning_browser_.get(); } Browser* popup_browser() { return popup_owning_browser_.get(); } WindowPositioner* window_positioner() { return window_positioner_; } // The positioner & desktop's used grid alignment size. const int grid_size_; private: WindowPositioner* window_positioner_; // These two need to be deleted after everything else is gone. TestingProfile profile_; // These get created for each session. scoped_ptr window_; scoped_ptr popup_; scoped_ptr browser_window_; scoped_ptr browser_popup_; scoped_ptr window_owning_browser_; scoped_ptr popup_owning_browser_; DISALLOW_COPY_AND_ASSIGN(WindowPositionerTest); }; WindowPositionerTest::WindowPositionerTest() : grid_size_(WindowPositioner::kMinimumWindowOffset), window_positioner_(NULL) { } void WindowPositionerTest::SetUp() { AshTestBase::SetUp(); // Create some default dummy windows. window_.reset(CreateTestWindowInShellWithId(0)); window_->SetBounds(gfx::Rect(16, 32, 640, 320)); popup_.reset(CreateTestWindowInShellWithId(1)); popup_->SetBounds(gfx::Rect(16, 32, 128, 256)); // Create a browser for the window. browser_window_.reset(new TestBrowserWindowAura(window_.get())); Browser::CreateParams window_params(&profile_, chrome::HOST_DESKTOP_TYPE_ASH); window_params.window = browser_window_.get(); window_owning_browser_.reset(new Browser(window_params)); // Creating a browser for the popup. browser_popup_.reset(new TestBrowserWindowAura(popup_.get())); Browser::CreateParams popup_params(Browser::TYPE_POPUP, &profile_, chrome::HOST_DESKTOP_TYPE_ASH); popup_params.window = browser_popup_.get(); popup_owning_browser_.reset(new Browser(popup_params)); // We hide all windows upon start - each user is required to set it up // as he needs it. window()->Hide(); popup()->Hide(); window_positioner_ = new WindowPositioner(); } void WindowPositionerTest::TearDown() { // Since the AuraTestBase is needed to create our assets, we have to // also delete them before we tear it down. window_owning_browser_.reset(NULL); popup_owning_browser_.reset(NULL); browser_window_.reset(NULL); browser_popup_.reset(NULL); window_.reset(NULL); popup_.reset(NULL); AshTestBase::TearDown(); delete window_positioner_; window_positioner_ = NULL; } int AlignToGridRoundDown(int location, int grid_size) { if (grid_size <= 1 || location % grid_size == 0) return location; return location / grid_size * grid_size; } TEST_F(WindowPositionerTest, cascading) { const gfx::Rect work_area = Shell::GetScreen()->GetPrimaryDisplay().work_area(); // First see that the window will cascade down when there is no space. window()->SetBounds(work_area); window()->Show(); gfx::Rect popup_position(0, 0, 200, 200); // Check that it gets cascaded. gfx::Rect cascade_1 = window_positioner()->GetPopupPosition(popup_position); EXPECT_EQ(gfx::Rect(work_area.x() + grid_size_, work_area.y() + grid_size_, popup_position.width(), popup_position.height()), cascade_1); gfx::Rect cascade_2 = window_positioner()->GetPopupPosition(popup_position); EXPECT_EQ(gfx::Rect(work_area.x() + 2 * grid_size_, work_area.y() + 2 * grid_size_, popup_position.width(), popup_position.height()), cascade_2); // Check that if there is even only a pixel missing it will cascade. window()->SetBounds(gfx::Rect(work_area.x() + popup_position.width() - 1, work_area.y() + popup_position.height() - 1, work_area.width() - 2 * (popup_position.width() - 1), work_area.height() - 2 * (popup_position.height() - 1))); gfx::Rect cascade_3 = window_positioner()->GetPopupPosition(popup_position); EXPECT_EQ(gfx::Rect(work_area.x() + 3 * grid_size_, work_area.y() + 3 * grid_size_, popup_position.width(), popup_position.height()), cascade_3); // Check that we overflow into the next line when we do not fit anymore in Y. gfx::Rect popup_position_4(0, 0, 200, work_area.height() - (cascade_3.y() - work_area.y())); gfx::Rect cascade_4 = window_positioner()->GetPopupPosition(popup_position_4); EXPECT_EQ(gfx::Rect(work_area.x() + 2 * grid_size_, work_area.y() + grid_size_, popup_position_4.width(), popup_position_4.height()), cascade_4); // Check that we overflow back to the first possible location if we overflow // to the end. gfx::Rect popup_position_5(0, 0, work_area.width() + 1 - (cascade_4.x() - work_area.x()), work_area.height() - (2 * grid_size_ - work_area.y())); gfx::Rect cascade_5 = window_positioner()->GetPopupPosition(popup_position_5); EXPECT_EQ(gfx::Rect(work_area.x() + grid_size_, work_area.y() + grid_size_, popup_position_5.width(), popup_position_5.height()), cascade_5); } TEST_F(WindowPositionerTest, filling) { const gfx::Rect work_area = Shell::GetScreen()->GetPrimaryDisplay().work_area(); gfx::Rect popup_position(0, 0, 256, 128); // Leave space on the left and the right and see if we fill top to bottom. window()->SetBounds(gfx::Rect(work_area.x() + popup_position.width(), work_area.y(), work_area.width() - 2 * popup_position.width(), work_area.height())); window()->Show(); // Check that we are positioned in the top left corner. gfx::Rect top_left = window_positioner()->GetPopupPosition(popup_position); EXPECT_EQ(gfx::Rect(work_area.x(), work_area.y(), popup_position.width(), popup_position.height()), top_left); // Now block the found location. popup()->SetBounds(top_left); popup()->Show(); gfx::Rect mid_left = window_positioner()->GetPopupPosition(popup_position); EXPECT_EQ(gfx::Rect(work_area.x(), AlignToGridRoundDown( work_area.y() + top_left.height(), grid_size_), popup_position.width(), popup_position.height()), mid_left); // Block now everything so that we can only put the popup on the bottom // of the left side. // Note: We need to keep one "grid spacing free" if the window does not // fit into the grid (which is true for 200 height).` popup()->SetBounds(gfx::Rect(work_area.x(), work_area.y(), popup_position.width(), work_area.height() - popup_position.height() - grid_size_ + 1)); gfx::Rect bottom_left = window_positioner()->GetPopupPosition( popup_position); EXPECT_EQ(gfx::Rect(work_area.x(), work_area.bottom() - popup_position.height(), popup_position.width(), popup_position.height()), bottom_left); // Block now enough to force the right side. popup()->SetBounds(gfx::Rect(work_area.x(), work_area.y(), popup_position.width(), work_area.height() - popup_position.height() + 1)); gfx::Rect top_right = window_positioner()->GetPopupPosition( popup_position); EXPECT_EQ(gfx::Rect(AlignToGridRoundDown(work_area.right() - popup_position.width(), grid_size_), work_area.y(), popup_position.width(), popup_position.height()), top_right); } TEST_F(WindowPositionerTest, biggerThenBorder) { const gfx::Rect work_area = Shell::GetScreen()->GetPrimaryDisplay().work_area(); gfx::Rect pop_position(0, 0, work_area.width(), work_area.height()); // Check that the popup is placed full screen. gfx::Rect full = window_positioner()->GetPopupPosition(pop_position); EXPECT_EQ(gfx::Rect(work_area.x(), work_area.y(), pop_position.width(), pop_position.height()), full); } } // namespace test } // namespace ash