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/display/display_util.h"
10 #include "ash/host/root_window_transformer.h"
11 #include "ash/magnifier/magnification_controller.h"
12 #include "ash/screen_util.h"
13 #include "ash/shelf/shelf.h"
14 #include "ash/shelf/shelf_widget.h"
15 #include "ash/shell.h"
16 #include "ash/test/ash_test_base.h"
17 #include "ash/test/cursor_manager_test_api.h"
18 #include "ash/test/display_manager_test_api.h"
19 #include "ash/test/mirror_window_test_api.h"
20 #include "base/synchronization/waitable_event.h"
21 #include "ui/aura/env.h"
22 #include "ui/aura/window_event_dispatcher.h"
23 #include "ui/aura/window_tracker.h"
24 #include "ui/events/event_handler.h"
25 #include "ui/events/test/event_generator.h"
26 #include "ui/gfx/display.h"
27 #include "ui/gfx/geometry/rect_conversions.h"
28 #include "ui/gfx/screen.h"
29 #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 ~TestEventHandler() override
{}
47 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 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
->pointer_details().radius_x();
63 touch_radius_y_
= event
->pointer_details().radius_y();
64 event
->StopPropagation();
67 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 float GetStoredUIScale(int64 id
) {
112 return Shell::GetInstance()->display_manager()->GetDisplayInfo(id
).
113 GetEffectiveUIScale();
116 scoped_ptr
<RootWindowTransformer
>
117 CreateCurrentRootWindowTransformerForMirroring() {
118 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
119 DCHECK(display_manager
->IsInMirrorMode());
120 const DisplayInfo
& mirror_display_info
=
121 display_manager
->GetDisplayInfo(display_manager
->mirroring_display_id());
122 const DisplayInfo
& source_display_info
= display_manager
->GetDisplayInfo(
123 Shell::GetScreen()->GetPrimaryDisplay().id());
124 return scoped_ptr
<RootWindowTransformer
>(
125 CreateRootWindowTransformerForMirroredDisplay(source_display_info
,
126 mirror_display_info
));
131 typedef test::AshTestBase RootWindowTransformersTest
;
134 // TODO(scottmg): RootWindow doesn't get resized on Windows
135 // Ash. http://crbug.com/247916.
136 #define MAYBE_RotateAndMagnify DISABLED_RotateAndMagniy
137 #define MAYBE_TouchScaleAndMagnify DISABLED_TouchScaleAndMagnify
138 #define MAYBE_ConvertHostToRootCoords DISABLED_ConvertHostToRootCoords
140 #define MAYBE_RotateAndMagnify RotateAndMagniy
141 #define MAYBE_TouchScaleAndMagnify TouchScaleAndMagnify
142 #define MAYBE_ConvertHostToRootCoords ConvertHostToRootCoords
145 TEST_F(RootWindowTransformersTest
, MAYBE_RotateAndMagnify
) {
146 MagnificationController
* magnifier
=
147 Shell::GetInstance()->magnification_controller();
148 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
150 TestEventHandler event_handler
;
151 Shell::GetInstance()->AddPreTargetHandler(&event_handler
);
153 UpdateDisplay("120x200,300x400*2");
154 gfx::Display display1
= Shell::GetScreen()->GetPrimaryDisplay();
155 int64 display2_id
= ScreenUtil::GetSecondaryDisplay().id();
157 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
158 ui::test::EventGenerator
generator1(root_windows
[0]);
159 ui::test::EventGenerator
generator2(root_windows
[1]);
161 magnifier
->SetEnabled(true);
162 EXPECT_EQ(2.0f
, magnifier
->GetScale());
163 EXPECT_EQ("120x200", root_windows
[0]->bounds().size().ToString());
164 EXPECT_EQ("150x200", root_windows
[1]->bounds().size().ToString());
165 EXPECT_EQ("120,0 150x200",
166 ScreenUtil::GetSecondaryDisplay().bounds().ToString());
167 generator1
.MoveMouseToInHost(40, 80);
168 EXPECT_EQ("50,90", event_handler
.GetLocationAndReset());
170 aura::Env::GetInstance()->last_mouse_location().ToString());
171 EXPECT_EQ(gfx::Display::ROTATE_0
, GetActiveDisplayRotation(display1
.id()));
172 EXPECT_EQ(gfx::Display::ROTATE_0
, GetActiveDisplayRotation(display2_id
));
173 magnifier
->SetEnabled(false);
175 display_manager
->SetDisplayRotation(display1
.id(), gfx::Display::ROTATE_90
,
176 gfx::Display::ROTATION_SOURCE_ACTIVE
);
177 // Move the cursor to the center of the first root window.
178 generator1
.MoveMouseToInHost(59, 100);
180 magnifier
->SetEnabled(true);
181 EXPECT_EQ(2.0f
, magnifier
->GetScale());
182 EXPECT_EQ("200x120", root_windows
[0]->bounds().size().ToString());
183 EXPECT_EQ("150x200", root_windows
[1]->bounds().size().ToString());
184 EXPECT_EQ("200,0 150x200",
185 ScreenUtil::GetSecondaryDisplay().bounds().ToString());
186 generator1
.MoveMouseToInHost(39, 120);
187 EXPECT_EQ("110,70", event_handler
.GetLocationAndReset());
189 aura::Env::GetInstance()->last_mouse_location().ToString());
190 EXPECT_EQ(gfx::Display::ROTATE_90
, GetActiveDisplayRotation(display1
.id()));
191 EXPECT_EQ(gfx::Display::ROTATE_0
, GetActiveDisplayRotation(display2_id
));
192 magnifier
->SetEnabled(false);
194 DisplayLayout
display_layout(DisplayLayout::BOTTOM
, 50);
195 display_manager
->SetLayoutForCurrentDisplays(display_layout
);
196 EXPECT_EQ("50,120 150x200",
197 ScreenUtil::GetSecondaryDisplay().bounds().ToString());
199 display_manager
->SetDisplayRotation(display2_id
, gfx::Display::ROTATE_270
,
200 gfx::Display::ROTATION_SOURCE_ACTIVE
);
201 // Move the cursor to the center of the second root window.
202 generator2
.MoveMouseToInHost(151, 199);
204 magnifier
->SetEnabled(true);
205 EXPECT_EQ("200x120", root_windows
[0]->bounds().size().ToString());
206 EXPECT_EQ("200x150", root_windows
[1]->bounds().size().ToString());
207 EXPECT_EQ("50,120 200x150",
208 ScreenUtil::GetSecondaryDisplay().bounds().ToString());
209 generator2
.MoveMouseToInHost(172, 219);
210 EXPECT_EQ("95,80", event_handler
.GetLocationAndReset());
212 aura::Env::GetInstance()->last_mouse_location().ToString());
213 EXPECT_EQ(gfx::Display::ROTATE_90
, GetActiveDisplayRotation(display1
.id()));
214 EXPECT_EQ(gfx::Display::ROTATE_270
, GetActiveDisplayRotation(display2_id
));
215 magnifier
->SetEnabled(false);
217 display_manager
->SetDisplayRotation(display1
.id(), gfx::Display::ROTATE_180
,
218 gfx::Display::ROTATION_SOURCE_ACTIVE
);
219 // Move the cursor to the center of the first root window.
220 generator1
.MoveMouseToInHost(59, 99);
222 magnifier
->SetEnabled(true);
223 EXPECT_EQ("120x200", root_windows
[0]->bounds().size().ToString());
224 EXPECT_EQ("200x150", root_windows
[1]->bounds().size().ToString());
225 // Dislay must share at least 100, so the x's offset becomes 20.
226 EXPECT_EQ("20,200 200x150",
227 ScreenUtil::GetSecondaryDisplay().bounds().ToString());
228 generator1
.MoveMouseToInHost(39, 59);
229 EXPECT_EQ("70,120", event_handler
.GetLocationAndReset());
230 EXPECT_EQ(gfx::Display::ROTATE_180
, GetActiveDisplayRotation(display1
.id()));
231 EXPECT_EQ(gfx::Display::ROTATE_270
, GetActiveDisplayRotation(display2_id
));
232 magnifier
->SetEnabled(false);
234 Shell::GetInstance()->RemovePreTargetHandler(&event_handler
);
237 TEST_F(RootWindowTransformersTest
, ScaleAndMagnify
) {
238 if (!SupportsMultipleDisplays())
241 TestEventHandler event_handler
;
242 Shell::GetInstance()->AddPreTargetHandler(&event_handler
);
244 UpdateDisplay("600x400*2@1.5,500x300");
246 gfx::Display display1
= Shell::GetScreen()->GetPrimaryDisplay();
247 test::ScopedSetInternalDisplayId
set_internal(display1
.id());
248 gfx::Display display2
= ScreenUtil::GetSecondaryDisplay();
249 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
250 MagnificationController
* magnifier
=
251 Shell::GetInstance()->magnification_controller();
253 magnifier
->SetEnabled(true);
254 EXPECT_EQ(2.0f
, magnifier
->GetScale());
255 EXPECT_EQ("0,0 450x300", display1
.bounds().ToString());
256 EXPECT_EQ("0,0 450x300", root_windows
[0]->bounds().ToString());
257 EXPECT_EQ("450,0 500x300", display2
.bounds().ToString());
258 EXPECT_EQ(1.5f
, GetStoredUIScale(display1
.id()));
259 EXPECT_EQ(1.0f
, GetStoredUIScale(display2
.id()));
261 ui::test::EventGenerator
generator(root_windows
[0]);
262 generator
.MoveMouseToInHost(500, 200);
263 EXPECT_EQ("299,150", event_handler
.GetLocationAndReset());
264 magnifier
->SetEnabled(false);
266 SetDisplayUIScale(display1
.id(), 1.25f
);
267 display1
= Shell::GetScreen()->GetPrimaryDisplay();
268 display2
= ScreenUtil::GetSecondaryDisplay();
269 magnifier
->SetEnabled(true);
270 EXPECT_EQ(2.0f
, magnifier
->GetScale());
271 EXPECT_EQ("0,0 375x250", display1
.bounds().ToString());
272 EXPECT_EQ("0,0 375x250", root_windows
[0]->bounds().ToString());
273 EXPECT_EQ("375,0 500x300", display2
.bounds().ToString());
274 EXPECT_EQ(1.25f
, GetStoredUIScale(display1
.id()));
275 EXPECT_EQ(1.0f
, GetStoredUIScale(display2
.id()));
276 magnifier
->SetEnabled(false);
278 Shell::GetInstance()->RemovePreTargetHandler(&event_handler
);
281 TEST_F(RootWindowTransformersTest
, MAYBE_TouchScaleAndMagnify
) {
282 TestEventHandler event_handler
;
283 Shell::GetInstance()->AddPreTargetHandler(&event_handler
);
285 UpdateDisplay("200x200*2");
286 gfx::Display display
= Shell::GetScreen()->GetPrimaryDisplay();
287 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
288 aura::Window
* root_window
= root_windows
[0];
289 ui::test::EventGenerator
generator(root_window
);
290 MagnificationController
* magnifier
=
291 Shell::GetInstance()->magnification_controller();
293 magnifier
->SetEnabled(true);
294 EXPECT_FLOAT_EQ(2.0f
, magnifier
->GetScale());
295 magnifier
->SetScale(2.5f
, false);
296 EXPECT_FLOAT_EQ(2.5f
, magnifier
->GetScale());
297 generator
.PressMoveAndReleaseTouchTo(50, 50);
298 // Default test touches have radius_x/y = 1.0, with device scale
299 // factor = 2, the scaled radius_x/y should be 0.5.
300 EXPECT_FLOAT_EQ(0.2f
, event_handler
.touch_radius_x());
301 EXPECT_FLOAT_EQ(0.2f
, event_handler
.touch_radius_y());
303 generator
.ScrollSequence(gfx::Point(0,0),
304 base::TimeDelta::FromMilliseconds(100),
307 // ordinal_offset is invariant to the device scale factor.
308 EXPECT_FLOAT_EQ(event_handler
.scroll_x_offset(),
309 event_handler
.scroll_x_offset_ordinal());
310 EXPECT_FLOAT_EQ(event_handler
.scroll_y_offset(),
311 event_handler
.scroll_y_offset_ordinal());
312 magnifier
->SetEnabled(false);
314 Shell::GetInstance()->RemovePreTargetHandler(&event_handler
);
317 TEST_F(RootWindowTransformersTest
, MAYBE_ConvertHostToRootCoords
) {
318 TestEventHandler event_handler
;
319 Shell::GetInstance()->AddPreTargetHandler(&event_handler
);
320 MagnificationController
* magnifier
=
321 Shell::GetInstance()->magnification_controller();
324 UpdateDisplay("600x400*2/r@1.5");
326 gfx::Display display1
= Shell::GetScreen()->GetPrimaryDisplay();
327 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
328 EXPECT_EQ("0,0 300x450", display1
.bounds().ToString());
329 EXPECT_EQ("0,0 300x450", root_windows
[0]->bounds().ToString());
330 EXPECT_EQ(1.5f
, GetStoredUIScale(display1
.id()));
332 ui::test::EventGenerator
generator(root_windows
[0]);
333 generator
.MoveMouseToInHost(300, 200);
334 magnifier
->SetEnabled(true);
335 EXPECT_EQ("150,224", event_handler
.GetLocationAndReset());
336 EXPECT_FLOAT_EQ(2.0f
, magnifier
->GetScale());
338 generator
.MoveMouseToInHost(300, 200);
339 EXPECT_EQ("150,224", event_handler
.GetLocationAndReset());
340 generator
.MoveMouseToInHost(200, 300);
341 EXPECT_EQ("187,261", event_handler
.GetLocationAndReset());
342 generator
.MoveMouseToInHost(100, 400);
343 EXPECT_EQ("237,299", event_handler
.GetLocationAndReset());
344 generator
.MoveMouseToInHost(0, 0);
345 EXPECT_EQ("137,348", event_handler
.GetLocationAndReset());
347 magnifier
->SetEnabled(false);
348 EXPECT_FLOAT_EQ(1.0f
, magnifier
->GetScale());
351 UpdateDisplay("600x400*2/u@1.5");
352 display1
= Shell::GetScreen()->GetPrimaryDisplay();
353 root_windows
= Shell::GetAllRootWindows();
354 EXPECT_EQ("0,0 450x300", display1
.bounds().ToString());
355 EXPECT_EQ("0,0 450x300", root_windows
[0]->bounds().ToString());
356 EXPECT_EQ(1.5f
, GetStoredUIScale(display1
.id()));
358 generator
.MoveMouseToInHost(300, 200);
359 magnifier
->SetEnabled(true);
360 EXPECT_EQ("224,149", event_handler
.GetLocationAndReset());
361 EXPECT_FLOAT_EQ(2.0f
, magnifier
->GetScale());
363 generator
.MoveMouseToInHost(300, 200);
364 EXPECT_EQ("224,148", event_handler
.GetLocationAndReset());
365 generator
.MoveMouseToInHost(200, 300);
366 EXPECT_EQ("261,111", event_handler
.GetLocationAndReset());
367 generator
.MoveMouseToInHost(100, 400);
368 EXPECT_EQ("299,60", event_handler
.GetLocationAndReset());
369 generator
.MoveMouseToInHost(0, 0);
370 EXPECT_EQ("348,159", event_handler
.GetLocationAndReset());
372 magnifier
->SetEnabled(false);
373 EXPECT_FLOAT_EQ(1.0f
, magnifier
->GetScale());
376 UpdateDisplay("600x400*2/l@1.5");
377 display1
= Shell::GetScreen()->GetPrimaryDisplay();
378 root_windows
= Shell::GetAllRootWindows();
379 EXPECT_EQ("0,0 300x450", display1
.bounds().ToString());
380 EXPECT_EQ("0,0 300x450", root_windows
[0]->bounds().ToString());
381 EXPECT_EQ(1.5f
, GetStoredUIScale(display1
.id()));
383 generator
.MoveMouseToInHost(300, 200);
384 magnifier
->SetEnabled(true);
385 EXPECT_EQ("149,225", event_handler
.GetLocationAndReset());
386 EXPECT_FLOAT_EQ(2.0f
, magnifier
->GetScale());
388 generator
.MoveMouseToInHost(300, 200);
389 EXPECT_EQ("148,224", event_handler
.GetLocationAndReset());
390 generator
.MoveMouseToInHost(200, 300);
391 EXPECT_EQ("111,187", event_handler
.GetLocationAndReset());
392 generator
.MoveMouseToInHost(100, 400);
393 EXPECT_EQ("60,149", event_handler
.GetLocationAndReset());
394 generator
.MoveMouseToInHost(0, 0);
395 EXPECT_EQ("159,99", event_handler
.GetLocationAndReset());
397 magnifier
->SetEnabled(false);
398 EXPECT_FLOAT_EQ(1.0f
, magnifier
->GetScale());
400 Shell::GetInstance()->RemovePreTargetHandler(&event_handler
);
403 TEST_F(RootWindowTransformersTest
, LetterBoxPillarBox
) {
404 if (!SupportsMultipleDisplays())
406 test::MirrorWindowTestApi test_api
;
407 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
408 display_manager
->SetMultiDisplayMode(DisplayManager::MIRRORING
);
409 UpdateDisplay("400x200,500x500");
410 scoped_ptr
<RootWindowTransformer
> transformer(
411 CreateCurrentRootWindowTransformerForMirroring());
412 // Y margin must be margin is (500 - 500/400 * 200) / 2 = 125.
413 EXPECT_EQ("0,125,0,125", transformer
->GetHostInsets().ToString());
415 UpdateDisplay("200x400,500x500");
416 // The aspect ratio is flipped, so X margin is now 125.
417 transformer
= CreateCurrentRootWindowTransformerForMirroring();
418 EXPECT_EQ("125,0,125,0", transformer
->GetHostInsets().ToString());