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