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/base/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 30 namespace ash { 31 namespace internal { 32 33 namespace { 34 35 const char kDesktopBackgroundView[] = "DesktopBackgroundView"; 36 37 class 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 112 gfx::Display::Rotation GetStoredRotation(int64 id) { 113 return Shell::GetInstance()->display_manager()->GetDisplayInfo(id).rotation(); 114 } 115 116 float GetStoredUIScale(int64 id) { 117 return Shell::GetInstance()->display_manager()->GetDisplayInfo(id).ui_scale(); 118 } 119 120 } // namespace 121 122 typedef 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 136 TEST_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 230 TEST_F(RootWindowTransformersTest, ScaleAndMagnify) { 231 if (!SupportsMultipleDisplays()) 232 return; 233 234 TestEventHandler event_handler; 235 Shell::GetInstance()->AddPreTargetHandler(&event_handler); 236 237 UpdateDisplay("600x400*2 (at) 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 275 TEST_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 311 TEST_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 (at) 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 (at) 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 (at) 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 397 TEST_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