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