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