root_window_transformers_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/magnifier/magnification_controller.h"
10#include "ash/screen_util.h"
11#include "ash/shelf/shelf.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::Window* 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).
117      GetEffectiveUIScale();
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  MagnificationController* magnifier =
138      Shell::GetInstance()->magnification_controller();
139  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
140
141  TestEventHandler event_handler;
142  Shell::GetInstance()->AddPreTargetHandler(&event_handler);
143
144  UpdateDisplay("120x200,300x400*2");
145  gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay();
146  int64 display2_id = ScreenUtil::GetSecondaryDisplay().id();
147
148  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
149  aura::test::EventGenerator generator1(root_windows[0]);
150  aura::test::EventGenerator generator2(root_windows[1]);
151
152  magnifier->SetEnabled(true);
153  EXPECT_EQ(2.0f, magnifier->GetScale());
154  EXPECT_EQ("120x200", root_windows[0]->bounds().size().ToString());
155  EXPECT_EQ("150x200", root_windows[1]->bounds().size().ToString());
156  EXPECT_EQ("120,0 150x200",
157            ScreenUtil::GetSecondaryDisplay().bounds().ToString());
158  generator1.MoveMouseToInHost(40, 80);
159  EXPECT_EQ("50,90", event_handler.GetLocationAndReset());
160  EXPECT_EQ("50,90",
161            aura::Env::GetInstance()->last_mouse_location().ToString());
162  EXPECT_EQ(gfx::Display::ROTATE_0, GetStoredRotation(display1.id()));
163  EXPECT_EQ(gfx::Display::ROTATE_0, GetStoredRotation(display2_id));
164  magnifier->SetEnabled(false);
165
166  display_manager->SetDisplayRotation(display1.id(),
167                                      gfx::Display::ROTATE_90);
168  // Move the cursor to the center of the first root window.
169  generator1.MoveMouseToInHost(59, 100);
170
171  magnifier->SetEnabled(true);
172  EXPECT_EQ(2.0f, magnifier->GetScale());
173  EXPECT_EQ("200x120", root_windows[0]->bounds().size().ToString());
174  EXPECT_EQ("150x200", root_windows[1]->bounds().size().ToString());
175  EXPECT_EQ("200,0 150x200",
176            ScreenUtil::GetSecondaryDisplay().bounds().ToString());
177  generator1.MoveMouseToInHost(39, 120);
178  EXPECT_EQ("110,70", event_handler.GetLocationAndReset());
179  EXPECT_EQ("110,70",
180            aura::Env::GetInstance()->last_mouse_location().ToString());
181  EXPECT_EQ(gfx::Display::ROTATE_90, GetStoredRotation(display1.id()));
182  EXPECT_EQ(gfx::Display::ROTATE_0, GetStoredRotation(display2_id));
183  magnifier->SetEnabled(false);
184
185  DisplayLayout display_layout(DisplayLayout::BOTTOM, 50);
186  display_manager->SetLayoutForCurrentDisplays(display_layout);
187  EXPECT_EQ("50,120 150x200",
188            ScreenUtil::GetSecondaryDisplay().bounds().ToString());
189
190  display_manager->SetDisplayRotation(display2_id,
191                                      gfx::Display::ROTATE_270);
192  // Move the cursor to the center of the second root window.
193  generator2.MoveMouseToInHost(151, 199);
194
195  magnifier->SetEnabled(true);
196  EXPECT_EQ("200x120", root_windows[0]->bounds().size().ToString());
197  EXPECT_EQ("200x150", root_windows[1]->bounds().size().ToString());
198  EXPECT_EQ("50,120 200x150",
199            ScreenUtil::GetSecondaryDisplay().bounds().ToString());
200  generator2.MoveMouseToInHost(172, 219);
201  EXPECT_EQ("95,80", event_handler.GetLocationAndReset());
202  EXPECT_EQ("145,200",
203            aura::Env::GetInstance()->last_mouse_location().ToString());
204  EXPECT_EQ(gfx::Display::ROTATE_90, GetStoredRotation(display1.id()));
205  EXPECT_EQ(gfx::Display::ROTATE_270, GetStoredRotation(display2_id));
206  magnifier->SetEnabled(false);
207
208  display_manager->SetDisplayRotation(display1.id(),
209                                      gfx::Display::ROTATE_180);
210  // Move the cursor to the center of the first root window.
211  generator1.MoveMouseToInHost(59, 99);
212
213  magnifier->SetEnabled(true);
214  EXPECT_EQ("120x200", root_windows[0]->bounds().size().ToString());
215  EXPECT_EQ("200x150", root_windows[1]->bounds().size().ToString());
216  // Dislay must share at least 100, so the x's offset becomes 20.
217  EXPECT_EQ("20,200 200x150",
218            ScreenUtil::GetSecondaryDisplay().bounds().ToString());
219  generator1.MoveMouseToInHost(39, 59);
220  EXPECT_EQ("70,120", event_handler.GetLocationAndReset());
221  EXPECT_EQ(gfx::Display::ROTATE_180, GetStoredRotation(display1.id()));
222  EXPECT_EQ(gfx::Display::ROTATE_270, GetStoredRotation(display2_id));
223  magnifier->SetEnabled(false);
224
225  Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
226}
227
228TEST_F(RootWindowTransformersTest, ScaleAndMagnify) {
229  if (!SupportsMultipleDisplays())
230    return;
231
232  TestEventHandler event_handler;
233  Shell::GetInstance()->AddPreTargetHandler(&event_handler);
234
235  UpdateDisplay("600x400*2@1.5,500x300");
236
237  gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay();
238  gfx::Display::SetInternalDisplayId(display1.id());
239  gfx::Display display2 = ScreenUtil::GetSecondaryDisplay();
240  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
241  MagnificationController* magnifier =
242      Shell::GetInstance()->magnification_controller();
243
244  magnifier->SetEnabled(true);
245  EXPECT_EQ(2.0f, magnifier->GetScale());
246  EXPECT_EQ("0,0 450x300", display1.bounds().ToString());
247  EXPECT_EQ("0,0 450x300", root_windows[0]->bounds().ToString());
248  EXPECT_EQ("450,0 500x300", display2.bounds().ToString());
249  EXPECT_EQ(1.5f, GetStoredUIScale(display1.id()));
250  EXPECT_EQ(1.0f, GetStoredUIScale(display2.id()));
251
252  aura::test::EventGenerator generator(root_windows[0]);
253  generator.MoveMouseToInHost(500, 200);
254  EXPECT_EQ("299,150", event_handler.GetLocationAndReset());
255  magnifier->SetEnabled(false);
256
257  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
258  display_manager->SetDisplayUIScale(display1.id(), 1.25);
259  display1 = Shell::GetScreen()->GetPrimaryDisplay();
260  display2 = ScreenUtil::GetSecondaryDisplay();
261  magnifier->SetEnabled(true);
262  EXPECT_EQ(2.0f, magnifier->GetScale());
263  EXPECT_EQ("0,0 375x250", display1.bounds().ToString());
264  EXPECT_EQ("0,0 375x250", root_windows[0]->bounds().ToString());
265  EXPECT_EQ("375,0 500x300", display2.bounds().ToString());
266  EXPECT_EQ(1.25f, GetStoredUIScale(display1.id()));
267  EXPECT_EQ(1.0f, GetStoredUIScale(display2.id()));
268  magnifier->SetEnabled(false);
269
270  Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
271}
272
273TEST_F(RootWindowTransformersTest, MAYBE_TouchScaleAndMagnify) {
274  TestEventHandler event_handler;
275  Shell::GetInstance()->AddPreTargetHandler(&event_handler);
276
277  UpdateDisplay("200x200*2");
278  gfx::Display display = Shell::GetScreen()->GetPrimaryDisplay();
279  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
280  aura::Window* root_window = root_windows[0];
281  aura::test::EventGenerator generator(root_window);
282  MagnificationController* magnifier =
283      Shell::GetInstance()->magnification_controller();
284
285  magnifier->SetEnabled(true);
286  EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale());
287  magnifier->SetScale(2.5f, false);
288  EXPECT_FLOAT_EQ(2.5f, magnifier->GetScale());
289  generator.PressMoveAndReleaseTouchTo(50, 50);
290  // Default test touches have radius_x/y = 1.0, with device scale
291  // factor = 2, the scaled radius_x/y should be 0.5.
292  EXPECT_FLOAT_EQ(0.2f, event_handler.touch_radius_x());
293  EXPECT_FLOAT_EQ(0.2f, event_handler.touch_radius_y());
294
295  generator.ScrollSequence(gfx::Point(0,0),
296                           base::TimeDelta::FromMilliseconds(100),
297                           10.0, 1.0, 5, 1);
298
299  // ordinal_offset is invariant to the device scale factor.
300  EXPECT_FLOAT_EQ(event_handler.scroll_x_offset(),
301                  event_handler.scroll_x_offset_ordinal());
302  EXPECT_FLOAT_EQ(event_handler.scroll_y_offset(),
303                  event_handler.scroll_y_offset_ordinal());
304  magnifier->SetEnabled(false);
305
306  Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
307}
308
309TEST_F(RootWindowTransformersTest, MAYBE_ConvertHostToRootCoords) {
310  TestEventHandler event_handler;
311  Shell::GetInstance()->AddPreTargetHandler(&event_handler);
312  MagnificationController* magnifier =
313      Shell::GetInstance()->magnification_controller();
314
315  // Test 1
316  UpdateDisplay("600x400*2/r@1.5");
317
318  gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay();
319  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
320  EXPECT_EQ("0,0 300x450", display1.bounds().ToString());
321  EXPECT_EQ("0,0 300x450", root_windows[0]->bounds().ToString());
322  EXPECT_EQ(1.5f, GetStoredUIScale(display1.id()));
323
324  aura::test::EventGenerator generator(root_windows[0]);
325  generator.MoveMouseToInHost(300, 200);
326  magnifier->SetEnabled(true);
327  EXPECT_EQ("150,224", event_handler.GetLocationAndReset());
328  EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale());
329
330  generator.MoveMouseToInHost(300, 200);
331  EXPECT_EQ("150,224", event_handler.GetLocationAndReset());
332  generator.MoveMouseToInHost(200, 300);
333  EXPECT_EQ("187,261", event_handler.GetLocationAndReset());
334  generator.MoveMouseToInHost(100, 400);
335  EXPECT_EQ("237,299", event_handler.GetLocationAndReset());
336  generator.MoveMouseToInHost(0, 0);
337  EXPECT_EQ("137,348", event_handler.GetLocationAndReset());
338
339  magnifier->SetEnabled(false);
340  EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale());
341
342  // Test 2
343  UpdateDisplay("600x400*2/u@1.5");
344  display1 = Shell::GetScreen()->GetPrimaryDisplay();
345  root_windows = Shell::GetAllRootWindows();
346  EXPECT_EQ("0,0 450x300", display1.bounds().ToString());
347  EXPECT_EQ("0,0 450x300", root_windows[0]->bounds().ToString());
348  EXPECT_EQ(1.5f, GetStoredUIScale(display1.id()));
349
350  generator.MoveMouseToInHost(300, 200);
351  magnifier->SetEnabled(true);
352  EXPECT_EQ("224,149", event_handler.GetLocationAndReset());
353  EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale());
354
355  generator.MoveMouseToInHost(300, 200);
356  EXPECT_EQ("224,148", event_handler.GetLocationAndReset());
357  generator.MoveMouseToInHost(200, 300);
358  EXPECT_EQ("261,111", event_handler.GetLocationAndReset());
359  generator.MoveMouseToInHost(100, 400);
360  EXPECT_EQ("299,60", event_handler.GetLocationAndReset());
361  generator.MoveMouseToInHost(0, 0);
362  EXPECT_EQ("348,159", event_handler.GetLocationAndReset());
363
364  magnifier->SetEnabled(false);
365  EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale());
366
367  // Test 3
368  UpdateDisplay("600x400*2/l@1.5");
369  display1 = Shell::GetScreen()->GetPrimaryDisplay();
370  root_windows = Shell::GetAllRootWindows();
371  EXPECT_EQ("0,0 300x450", display1.bounds().ToString());
372  EXPECT_EQ("0,0 300x450", root_windows[0]->bounds().ToString());
373  EXPECT_EQ(1.5f, GetStoredUIScale(display1.id()));
374
375  generator.MoveMouseToInHost(300, 200);
376  magnifier->SetEnabled(true);
377  EXPECT_EQ("149,225", event_handler.GetLocationAndReset());
378  EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale());
379
380  generator.MoveMouseToInHost(300, 200);
381  EXPECT_EQ("148,224", event_handler.GetLocationAndReset());
382  generator.MoveMouseToInHost(200, 300);
383  EXPECT_EQ("111,187", event_handler.GetLocationAndReset());
384  generator.MoveMouseToInHost(100, 400);
385  EXPECT_EQ("60,149", event_handler.GetLocationAndReset());
386  generator.MoveMouseToInHost(0, 0);
387  EXPECT_EQ("159,99", event_handler.GetLocationAndReset());
388
389  magnifier->SetEnabled(false);
390  EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale());
391
392  Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
393}
394
395TEST_F(RootWindowTransformersTest, LetterBoxPillarBox) {
396  if (!SupportsMultipleDisplays())
397    return;
398  test::MirrorWindowTestApi test_api;
399  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
400  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
401  UpdateDisplay("400x200,500x500");
402  scoped_ptr<aura::RootWindowTransformer> transformer(
403      test_api.CreateCurrentRootWindowTransformer());
404  // Y margin must be margin is (500 - 500/400 * 200) / 2 = 125.
405  EXPECT_EQ("0,125,0,125", transformer->GetHostInsets().ToString());
406
407  UpdateDisplay("200x400,500x500");
408  // The aspect ratio is flipped, so X margin is now 125.
409  transformer = test_api.CreateCurrentRootWindowTransformer();
410  EXPECT_EQ("125,0,125,0", transformer->GetHostInsets().ToString());
411}
412
413}  // namespace test
414}  // namespace ash
415