root_window_transformers_unittest.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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/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"
28
29namespace ash {
30namespace internal {
31
32namespace {
33
34const char kDesktopBackgroundView[] = "DesktopBackgroundView";
35
36class TestEventHandler : public ui::EventHandler {
37 public:
38  TestEventHandler() : target_root_(NULL),
39                       touch_radius_x_(0.0),
40                       touch_radius_y_(0.0),
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() {}
46
47  virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
48    if (event->flags() & ui::EF_IS_SYNTHESIZED)
49      return;
50    aura::Window* target = static_cast<aura::Window*>(event->target());
51    mouse_location_ = event->root_location();
52    target_root_ = target->GetRootWindow();
53    event->StopPropagation();
54  }
55
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)
61      return;
62    touch_radius_x_ = event->radius_x();
63    touch_radius_y_ = event->radius_y();
64    event->StopPropagation();
65  }
66
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)
72      return;
73
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();
79    }
80    event->StopPropagation();
81  }
82
83  std::string GetLocationAndReset() {
84    std::string result = mouse_location_.ToString();
85    mouse_location_.SetPoint(0, 0);
86    target_root_ = NULL;
87    return result;
88  }
89
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_; }
96
97 private:
98  gfx::Point mouse_location_;
99  aura::RootWindow* target_root_;
100
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_;
107
108  DISALLOW_COPY_AND_ASSIGN(TestEventHandler);
109};
110
111gfx::Display::Rotation GetStoredRotation(int64 id) {
112  return Shell::GetInstance()->display_manager()->GetDisplayInfo(id).rotation();
113}
114
115float GetStoredUIScale(int64 id) {
116  return Shell::GetInstance()->display_manager()->GetDisplayInfo(id).ui_scale();
117}
118
119}  // namespace
120
121typedef test::AshTestBase RootWindowTransformersTest;
122
123#if defined(OS_WIN)
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
129#else
130#define MAYBE_RotateAndMagnify RotateAndMagniy
131#define MAYBE_TouchScaleAndMagnify TouchScaleAndMagnify
132#define MAYBE_ConvertHostToRootCoords ConvertHostToRootCoords
133#endif
134
135TEST_F(RootWindowTransformersTest, MAYBE_RotateAndMagnify) {
136  MagnificationController* magnifier =
137      Shell::GetInstance()->magnification_controller();
138  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
139
140  TestEventHandler event_handler;
141  Shell::GetInstance()->AddPreTargetHandler(&event_handler);
142
143  UpdateDisplay("120x200,300x400*2");
144  gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay();
145  int64 display2_id = ScreenAsh::GetSecondaryDisplay().id();
146
147  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
148  aura::test::EventGenerator generator1(root_windows[0]);
149  aura::test::EventGenerator generator2(root_windows[1]);
150
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());
159  EXPECT_EQ("50,90",
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);
164
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);
169
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());
178  EXPECT_EQ("110,70",
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);
183
184  DisplayLayout display_layout(DisplayLayout::BOTTOM, 50);
185  display_manager->SetLayoutForCurrentDisplays(display_layout);
186  EXPECT_EQ("50,120 150x200",
187            ScreenAsh::GetSecondaryDisplay().bounds().ToString());
188
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);
193
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());
201  EXPECT_EQ("145,200",
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);
206
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);
211
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);
223
224  Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
225}
226
227TEST_F(RootWindowTransformersTest, ScaleAndMagnify) {
228  if (!SupportsMultipleDisplays())
229    return;
230
231  TestEventHandler event_handler;
232  Shell::GetInstance()->AddPreTargetHandler(&event_handler);
233
234  UpdateDisplay("600x400*2@1.5,500x300");
235
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();
242
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()));
250
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);
255
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);
268
269  Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
270}
271
272TEST_F(RootWindowTransformersTest, MAYBE_TouchScaleAndMagnify) {
273  TestEventHandler event_handler;
274  Shell::GetInstance()->AddPreTargetHandler(&event_handler);
275
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();
283
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());
293
294  generator.ScrollSequence(gfx::Point(0,0),
295                           base::TimeDelta::FromMilliseconds(100),
296                           10.0, 1.0, 5, 1);
297
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);
304
305  Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
306}
307
308TEST_F(RootWindowTransformersTest, MAYBE_ConvertHostToRootCoords) {
309  TestEventHandler event_handler;
310  Shell::GetInstance()->AddPreTargetHandler(&event_handler);
311  MagnificationController* magnifier =
312      Shell::GetInstance()->magnification_controller();
313
314  // Test 1
315  UpdateDisplay("600x400*2/r@1.5");
316
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()));
322
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());
328
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());
337
338  magnifier->SetEnabled(false);
339  EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale());
340
341  // Test 2
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()));
348
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());
353
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());
362
363  magnifier->SetEnabled(false);
364  EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale());
365
366  // Test 3
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()));
373
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());
378
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());
387
388  magnifier->SetEnabled(false);
389  EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale());
390
391  Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
392}
393
394TEST_F(RootWindowTransformersTest, LetterBoxPillarBox) {
395  if (!SupportsMultipleDisplays())
396    return;
397  test::MirrorWindowTestApi test_api;
398  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
399  display_manager->SetSoftwareMirroring(true);
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());
405
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());
410}
411
412}  // namespace test
413}  // namespace ash
414