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.
5 #include "ash/wm/window_positioner.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/root_window.h"
21 #include "ui/aura/test/test_windows.h"
22 #include "ui/gfx/screen.h"
29 // A browser window proxy which is able to associate an aura native window with
31 class TestBrowserWindowAura
: public TestBrowserWindow
{
33 explicit TestBrowserWindowAura(aura::Window
* native_window
);
34 virtual ~TestBrowserWindowAura();
36 virtual gfx::NativeWindow
GetNativeWindow() OVERRIDE
{
37 return native_window_
;
41 gfx::NativeWindow native_window_
;
43 DISALLOW_COPY_AND_ASSIGN(TestBrowserWindowAura
);
46 TestBrowserWindowAura::TestBrowserWindowAura(aura::Window
*native_window
)
47 : native_window_(native_window
) {
50 TestBrowserWindowAura::~TestBrowserWindowAura() {}
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
{
59 WindowPositionerTest();
61 virtual void SetUp() OVERRIDE
;
62 virtual void TearDown() OVERRIDE
;
65 aura::Window
* window() { return window_
.get(); }
66 aura::Window
* popup() { return popup_
.get(); }
68 Browser
* window_browser() { return window_owning_browser_
.get(); }
69 Browser
* popup_browser() { return popup_owning_browser_
.get(); }
71 WindowPositioner
* window_positioner() { return window_positioner_
; }
73 // The positioner & desktop's used grid alignment size.
77 WindowPositioner
* window_positioner_
;
79 // These two need to be deleted after everything else is gone.
80 TestingProfile profile_
;
82 // These get created for each session.
83 scoped_ptr
<aura::Window
> window_
;
84 scoped_ptr
<aura::Window
> popup_
;
86 scoped_ptr
<BrowserWindow
> browser_window_
;
87 scoped_ptr
<BrowserWindow
> browser_popup_
;
89 scoped_ptr
<Browser
> window_owning_browser_
;
90 scoped_ptr
<Browser
> popup_owning_browser_
;
92 DISALLOW_COPY_AND_ASSIGN(WindowPositionerTest
);
95 WindowPositionerTest::WindowPositionerTest()
96 : grid_size_(WindowPositioner::kMinimumWindowOffset
),
97 window_positioner_(NULL
) {
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));
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
));
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
));
122 // We hide all windows upon start - each user is required to set it up
126 window_positioner_
= new WindowPositioner();
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
);
135 browser_window_
.reset(NULL
);
136 browser_popup_
.reset(NULL
);
141 AshTestBase::TearDown();
142 delete window_positioner_
;
143 window_positioner_
= NULL
;
146 int AlignToGridRoundDown(int location
, int grid_size
) {
147 if (grid_size
<= 1 || location
% grid_size
== 0)
149 return location
/ grid_size
* grid_size
;
152 TEST_F(WindowPositionerTest
, cascading
) {
153 const gfx::Rect work_area
=
154 Shell::GetScreen()->GetPrimaryDisplay().work_area();
156 // First see that the window will cascade down when there is no space.
157 window()->SetBounds(work_area
);
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()),
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()),
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,
177 2 * (popup_position
.width() - 1),
179 2 * (popup_position
.height() - 1)));
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()),
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,
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()),
198 // Check that we overflow back to the first possible location if we overflow
200 gfx::Rect
popup_position_5(0, 0,
201 work_area
.width() + 1 -
202 (cascade_4
.x() - work_area
.x()),
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()),
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(),
220 work_area
.width() - 2 * popup_position
.width(),
221 work_area
.height()));
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()),
229 // Now block the found location.
230 popup()->SetBounds(top_left
);
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()),
239 // Block now everything so that we can only put the popup on the bottom
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() -
247 gfx::Rect bottom_left
= window_positioner()->GetPopupPosition(
249 EXPECT_EQ(gfx::Rect(work_area
.x(),
250 work_area
.bottom() - popup_position
.height(),
251 popup_position
.width(), popup_position
.height()),
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() +
259 gfx::Rect top_right
= window_positioner()->GetPopupPosition(
261 EXPECT_EQ(gfx::Rect(AlignToGridRoundDown(work_area
.right() -
262 popup_position
.width(), grid_size_
),
264 popup_position
.width(), popup_position
.height()),
268 TEST_F(WindowPositionerTest
, biggerThenBorder
) {
269 const gfx::Rect work_area
=
270 Shell::GetScreen()->GetPrimaryDisplay().work_area();
272 gfx::Rect
pop_position(0, 0, work_area
.width(), work_area
.height());
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()),