1 // Copyright 2013 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/display/root_window_transformers.h"
7 #include "ash/display/display_info.h"
8 #include "ash/display/display_manager.h"
9 #include "ash/launcher/launcher.h"
10 #include "ash/magnifier/magnification_controller.h"
11 #include "ash/screen_ash.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.h"
14 #include "ash/test/ash_test_base.h"
15 #include "ash/test/cursor_manager_test_api.h"
16 #include "ash/test/mirror_window_test_api.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "ui/aura/env.h"
19 #include "ui/aura/root_window.h"
20 #include "ui/aura/root_window_transformer.h"
21 #include "ui/aura/test/event_generator.h"
22 #include "ui/aura/window_tracker.h"
23 #include "ui/events/event_handler.h"
24 #include "ui/gfx/display.h"
25 #include "ui/gfx/rect_conversions.h"
26 #include "ui/gfx/screen.h"
27 #include "ui/views/widget/widget.h"
34 const char kDesktopBackgroundView[] = "DesktopBackgroundView";
36 class TestEventHandler : public ui::EventHandler {
38 TestEventHandler() : target_root_(NULL),
41 scroll_x_offset_(0.0),
42 scroll_y_offset_(0.0),
43 scroll_x_offset_ordinal_(0.0),
44 scroll_y_offset_ordinal_(0.0) {}
45 virtual ~TestEventHandler() {}
47 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
48 if (event->flags() & ui::EF_IS_SYNTHESIZED)
50 aura::Window* target = static_cast<aura::Window*>(event->target());
51 mouse_location_ = event->root_location();
52 target_root_ = target->GetRootWindow();
53 event->StopPropagation();
56 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
57 aura::Window* target = static_cast<aura::Window*>(event->target());
58 // Only record when the target is the background which covers
59 // entire root window.
60 if (target->name() != kDesktopBackgroundView)
62 touch_radius_x_ = event->radius_x();
63 touch_radius_y_ = event->radius_y();
64 event->StopPropagation();
67 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
68 aura::Window* target = static_cast<aura::Window*>(event->target());
69 // Only record when the target is the background which covers
70 // entire root window.
71 if (target->name() != kDesktopBackgroundView)
74 if (event->type() == ui::ET_SCROLL) {
75 scroll_x_offset_ = event->x_offset();
76 scroll_y_offset_ = event->y_offset();
77 scroll_x_offset_ordinal_ = event->x_offset_ordinal();
78 scroll_y_offset_ordinal_ = event->y_offset_ordinal();
80 event->StopPropagation();
83 std::string GetLocationAndReset() {
84 std::string result = mouse_location_.ToString();
85 mouse_location_.SetPoint(0, 0);
90 float touch_radius_x() const { return touch_radius_x_; }
91 float touch_radius_y() const { return touch_radius_y_; }
92 float scroll_x_offset() const { return scroll_x_offset_; }
93 float scroll_y_offset() const { return scroll_y_offset_; }
94 float scroll_x_offset_ordinal() const { return scroll_x_offset_ordinal_; }
95 float scroll_y_offset_ordinal() const { return scroll_y_offset_ordinal_; }
98 gfx::Point mouse_location_;
99 aura::Window* target_root_;
101 float touch_radius_x_;
102 float touch_radius_y_;
103 float scroll_x_offset_;
104 float scroll_y_offset_;
105 float scroll_x_offset_ordinal_;
106 float scroll_y_offset_ordinal_;
108 DISALLOW_COPY_AND_ASSIGN(TestEventHandler);
111 gfx::Display::Rotation GetStoredRotation(int64 id) {
112 return Shell::GetInstance()->display_manager()->GetDisplayInfo(id).rotation();
115 float GetStoredUIScale(int64 id) {
116 return Shell::GetInstance()->display_manager()->GetDisplayInfo(id).ui_scale();
121 typedef test::AshTestBase RootWindowTransformersTest;
124 // TODO(scottmg): RootWindow doesn't get resized on Windows
125 // Ash. http://crbug.com/247916.
126 #define MAYBE_RotateAndMagnify DISABLED_RotateAndMagniy
127 #define MAYBE_TouchScaleAndMagnify DISABLED_TouchScaleAndMagnify
128 #define MAYBE_ConvertHostToRootCoords DISABLED_ConvertHostToRootCoords
130 #define MAYBE_RotateAndMagnify RotateAndMagniy
131 #define MAYBE_TouchScaleAndMagnify TouchScaleAndMagnify
132 #define MAYBE_ConvertHostToRootCoords ConvertHostToRootCoords
135 TEST_F(RootWindowTransformersTest, MAYBE_RotateAndMagnify) {
136 MagnificationController* magnifier =
137 Shell::GetInstance()->magnification_controller();
138 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
140 TestEventHandler event_handler;
141 Shell::GetInstance()->AddPreTargetHandler(&event_handler);
143 UpdateDisplay("120x200,300x400*2");
144 gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay();
145 int64 display2_id = ScreenAsh::GetSecondaryDisplay().id();
147 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
148 aura::test::EventGenerator generator1(root_windows[0]);
149 aura::test::EventGenerator generator2(root_windows[1]);
151 magnifier->SetEnabled(true);
152 EXPECT_EQ(2.0f, magnifier->GetScale());
153 EXPECT_EQ("120x200", root_windows[0]->bounds().size().ToString());
154 EXPECT_EQ("150x200", root_windows[1]->bounds().size().ToString());
155 EXPECT_EQ("120,0 150x200",
156 ScreenAsh::GetSecondaryDisplay().bounds().ToString());
157 generator1.MoveMouseToInHost(40, 80);
158 EXPECT_EQ("50,90", event_handler.GetLocationAndReset());
160 aura::Env::GetInstance()->last_mouse_location().ToString());
161 EXPECT_EQ(gfx::Display::ROTATE_0, GetStoredRotation(display1.id()));
162 EXPECT_EQ(gfx::Display::ROTATE_0, GetStoredRotation(display2_id));
163 magnifier->SetEnabled(false);
165 display_manager->SetDisplayRotation(display1.id(),
166 gfx::Display::ROTATE_90);
167 // Move the cursor to the center of the first root window.
168 generator1.MoveMouseToInHost(59, 100);
170 magnifier->SetEnabled(true);
171 EXPECT_EQ(2.0f, magnifier->GetScale());
172 EXPECT_EQ("200x120", root_windows[0]->bounds().size().ToString());
173 EXPECT_EQ("150x200", root_windows[1]->bounds().size().ToString());
174 EXPECT_EQ("200,0 150x200",
175 ScreenAsh::GetSecondaryDisplay().bounds().ToString());
176 generator1.MoveMouseToInHost(39, 120);
177 EXPECT_EQ("110,70", event_handler.GetLocationAndReset());
179 aura::Env::GetInstance()->last_mouse_location().ToString());
180 EXPECT_EQ(gfx::Display::ROTATE_90, GetStoredRotation(display1.id()));
181 EXPECT_EQ(gfx::Display::ROTATE_0, GetStoredRotation(display2_id));
182 magnifier->SetEnabled(false);
184 DisplayLayout display_layout(DisplayLayout::BOTTOM, 50);
185 display_manager->SetLayoutForCurrentDisplays(display_layout);
186 EXPECT_EQ("50,120 150x200",
187 ScreenAsh::GetSecondaryDisplay().bounds().ToString());
189 display_manager->SetDisplayRotation(display2_id,
190 gfx::Display::ROTATE_270);
191 // Move the cursor to the center of the second root window.
192 generator2.MoveMouseToInHost(151, 199);
194 magnifier->SetEnabled(true);
195 EXPECT_EQ("200x120", root_windows[0]->bounds().size().ToString());
196 EXPECT_EQ("200x150", root_windows[1]->bounds().size().ToString());
197 EXPECT_EQ("50,120 200x150",
198 ScreenAsh::GetSecondaryDisplay().bounds().ToString());
199 generator2.MoveMouseToInHost(172, 219);
200 EXPECT_EQ("95,80", event_handler.GetLocationAndReset());
202 aura::Env::GetInstance()->last_mouse_location().ToString());
203 EXPECT_EQ(gfx::Display::ROTATE_90, GetStoredRotation(display1.id()));
204 EXPECT_EQ(gfx::Display::ROTATE_270, GetStoredRotation(display2_id));
205 magnifier->SetEnabled(false);
207 display_manager->SetDisplayRotation(display1.id(),
208 gfx::Display::ROTATE_180);
209 // Move the cursor to the center of the first root window.
210 generator1.MoveMouseToInHost(59, 99);
212 magnifier->SetEnabled(true);
213 EXPECT_EQ("120x200", root_windows[0]->bounds().size().ToString());
214 EXPECT_EQ("200x150", root_windows[1]->bounds().size().ToString());
215 // Dislay must share at least 100, so the x's offset becomes 20.
216 EXPECT_EQ("20,200 200x150",
217 ScreenAsh::GetSecondaryDisplay().bounds().ToString());
218 generator1.MoveMouseToInHost(39, 59);
219 EXPECT_EQ("70,120", event_handler.GetLocationAndReset());
220 EXPECT_EQ(gfx::Display::ROTATE_180, GetStoredRotation(display1.id()));
221 EXPECT_EQ(gfx::Display::ROTATE_270, GetStoredRotation(display2_id));
222 magnifier->SetEnabled(false);
224 Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
227 TEST_F(RootWindowTransformersTest, ScaleAndMagnify) {
228 if (!SupportsMultipleDisplays())
231 TestEventHandler event_handler;
232 Shell::GetInstance()->AddPreTargetHandler(&event_handler);
234 UpdateDisplay("600x400*2@1.5,500x300");
236 gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay();
237 gfx::Display::SetInternalDisplayId(display1.id());
238 gfx::Display display2 = ScreenAsh::GetSecondaryDisplay();
239 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
240 MagnificationController* magnifier =
241 Shell::GetInstance()->magnification_controller();
243 magnifier->SetEnabled(true);
244 EXPECT_EQ(2.0f, magnifier->GetScale());
245 EXPECT_EQ("0,0 450x300", display1.bounds().ToString());
246 EXPECT_EQ("0,0 450x300", root_windows[0]->bounds().ToString());
247 EXPECT_EQ("450,0 500x300", display2.bounds().ToString());
248 EXPECT_EQ(1.5f, GetStoredUIScale(display1.id()));
249 EXPECT_EQ(1.0f, GetStoredUIScale(display2.id()));
251 aura::test::EventGenerator generator(root_windows[0]);
252 generator.MoveMouseToInHost(500, 200);
253 EXPECT_EQ("299,150", event_handler.GetLocationAndReset());
254 magnifier->SetEnabled(false);
256 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
257 display_manager->SetDisplayUIScale(display1.id(), 1.25);
258 display1 = Shell::GetScreen()->GetPrimaryDisplay();
259 display2 = ScreenAsh::GetSecondaryDisplay();
260 magnifier->SetEnabled(true);
261 EXPECT_EQ(2.0f, magnifier->GetScale());
262 EXPECT_EQ("0,0 375x250", display1.bounds().ToString());
263 EXPECT_EQ("0,0 375x250", root_windows[0]->bounds().ToString());
264 EXPECT_EQ("375,0 500x300", display2.bounds().ToString());
265 EXPECT_EQ(1.25f, GetStoredUIScale(display1.id()));
266 EXPECT_EQ(1.0f, GetStoredUIScale(display2.id()));
267 magnifier->SetEnabled(false);
269 Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
272 TEST_F(RootWindowTransformersTest, MAYBE_TouchScaleAndMagnify) {
273 TestEventHandler event_handler;
274 Shell::GetInstance()->AddPreTargetHandler(&event_handler);
276 UpdateDisplay("200x200*2");
277 gfx::Display display = Shell::GetScreen()->GetPrimaryDisplay();
278 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
279 aura::RootWindow* root_window = root_windows[0];
280 aura::test::EventGenerator generator(root_window);
281 MagnificationController* magnifier =
282 Shell::GetInstance()->magnification_controller();
284 magnifier->SetEnabled(true);
285 EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale());
286 magnifier->SetScale(2.5f, false);
287 EXPECT_FLOAT_EQ(2.5f, magnifier->GetScale());
288 generator.PressMoveAndReleaseTouchTo(50, 50);
289 // Default test touches have radius_x/y = 1.0, with device scale
290 // factor = 2, the scaled radius_x/y should be 0.5.
291 EXPECT_FLOAT_EQ(0.2f, event_handler.touch_radius_x());
292 EXPECT_FLOAT_EQ(0.2f, event_handler.touch_radius_y());
294 generator.ScrollSequence(gfx::Point(0,0),
295 base::TimeDelta::FromMilliseconds(100),
298 // ordinal_offset is invariant to the device scale factor.
299 EXPECT_FLOAT_EQ(event_handler.scroll_x_offset(),
300 event_handler.scroll_x_offset_ordinal());
301 EXPECT_FLOAT_EQ(event_handler.scroll_y_offset(),
302 event_handler.scroll_y_offset_ordinal());
303 magnifier->SetEnabled(false);
305 Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
308 TEST_F(RootWindowTransformersTest, MAYBE_ConvertHostToRootCoords) {
309 TestEventHandler event_handler;
310 Shell::GetInstance()->AddPreTargetHandler(&event_handler);
311 MagnificationController* magnifier =
312 Shell::GetInstance()->magnification_controller();
315 UpdateDisplay("600x400*2/r@1.5");
317 gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay();
318 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
319 EXPECT_EQ("0,0 300x450", display1.bounds().ToString());
320 EXPECT_EQ("0,0 300x450", root_windows[0]->bounds().ToString());
321 EXPECT_EQ(1.5f, GetStoredUIScale(display1.id()));
323 aura::test::EventGenerator generator(root_windows[0]);
324 generator.MoveMouseToInHost(300, 200);
325 magnifier->SetEnabled(true);
326 EXPECT_EQ("150,224", event_handler.GetLocationAndReset());
327 EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale());
329 generator.MoveMouseToInHost(300, 200);
330 EXPECT_EQ("150,224", event_handler.GetLocationAndReset());
331 generator.MoveMouseToInHost(200, 300);
332 EXPECT_EQ("187,261", event_handler.GetLocationAndReset());
333 generator.MoveMouseToInHost(100, 400);
334 EXPECT_EQ("237,299", event_handler.GetLocationAndReset());
335 generator.MoveMouseToInHost(0, 0);
336 EXPECT_EQ("137,348", event_handler.GetLocationAndReset());
338 magnifier->SetEnabled(false);
339 EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale());
342 UpdateDisplay("600x400*2/u@1.5");
343 display1 = Shell::GetScreen()->GetPrimaryDisplay();
344 root_windows = Shell::GetAllRootWindows();
345 EXPECT_EQ("0,0 450x300", display1.bounds().ToString());
346 EXPECT_EQ("0,0 450x300", root_windows[0]->bounds().ToString());
347 EXPECT_EQ(1.5f, GetStoredUIScale(display1.id()));
349 generator.MoveMouseToInHost(300, 200);
350 magnifier->SetEnabled(true);
351 EXPECT_EQ("224,149", event_handler.GetLocationAndReset());
352 EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale());
354 generator.MoveMouseToInHost(300, 200);
355 EXPECT_EQ("224,148", event_handler.GetLocationAndReset());
356 generator.MoveMouseToInHost(200, 300);
357 EXPECT_EQ("261,111", event_handler.GetLocationAndReset());
358 generator.MoveMouseToInHost(100, 400);
359 EXPECT_EQ("299,60", event_handler.GetLocationAndReset());
360 generator.MoveMouseToInHost(0, 0);
361 EXPECT_EQ("348,159", event_handler.GetLocationAndReset());
363 magnifier->SetEnabled(false);
364 EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale());
367 UpdateDisplay("600x400*2/l@1.5");
368 display1 = Shell::GetScreen()->GetPrimaryDisplay();
369 root_windows = Shell::GetAllRootWindows();
370 EXPECT_EQ("0,0 300x450", display1.bounds().ToString());
371 EXPECT_EQ("0,0 300x450", root_windows[0]->bounds().ToString());
372 EXPECT_EQ(1.5f, GetStoredUIScale(display1.id()));
374 generator.MoveMouseToInHost(300, 200);
375 magnifier->SetEnabled(true);
376 EXPECT_EQ("149,225", event_handler.GetLocationAndReset());
377 EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale());
379 generator.MoveMouseToInHost(300, 200);
380 EXPECT_EQ("148,224", event_handler.GetLocationAndReset());
381 generator.MoveMouseToInHost(200, 300);
382 EXPECT_EQ("111,187", event_handler.GetLocationAndReset());
383 generator.MoveMouseToInHost(100, 400);
384 EXPECT_EQ("60,149", event_handler.GetLocationAndReset());
385 generator.MoveMouseToInHost(0, 0);
386 EXPECT_EQ("159,99", event_handler.GetLocationAndReset());
388 magnifier->SetEnabled(false);
389 EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale());
391 Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
394 TEST_F(RootWindowTransformersTest, LetterBoxPillarBox) {
395 if (!SupportsMultipleDisplays())
397 test::MirrorWindowTestApi test_api;
398 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
399 display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
400 UpdateDisplay("400x200,500x500");
401 scoped_ptr<aura::RootWindowTransformer> transformer(
402 test_api.CreateCurrentRootWindowTransformer());
403 // Y margin must be margin is (500 - 500/400 * 200) / 2 = 125.
404 EXPECT_EQ("0,125,0,125", transformer->GetHostInsets().ToString());
406 UpdateDisplay("200x400,500x500");
407 // The aspect ratio is flipped, so X margin is now 125.
408 transformer = test_api.CreateCurrentRootWindowTransformer();
409 EXPECT_EQ("125,0,125,0", transformer->GetHostInsets().ToString());