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 29 namespace ash { 30 namespace internal { 31 32 namespace { 33 34 const char kDesktopBackgroundView[] = "DesktopBackgroundView"; 35 36 class 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 111 gfx::Display::Rotation GetStoredRotation(int64 id) { 112 return Shell::GetInstance()->display_manager()->GetDisplayInfo(id).rotation(); 113 } 114 115 float GetStoredUIScale(int64 id) { 116 return Shell::GetInstance()->display_manager()->GetDisplayInfo(id). 117 GetEffectiveUIScale(); 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 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 = ScreenAsh::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 ScreenAsh::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 ScreenAsh::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 ScreenAsh::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 ScreenAsh::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 ScreenAsh::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 228 TEST_F(RootWindowTransformersTest, ScaleAndMagnify) { 229 if (!SupportsMultipleDisplays()) 230 return; 231 232 TestEventHandler event_handler; 233 Shell::GetInstance()->AddPreTargetHandler(&event_handler); 234 235 UpdateDisplay("600x400*2 (at) 1.5,500x300"); 236 237 gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay(); 238 gfx::Display::SetInternalDisplayId(display1.id()); 239 gfx::Display display2 = ScreenAsh::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 = ScreenAsh::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 273 TEST_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 309 TEST_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 (at) 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 (at) 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 (at) 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 395 TEST_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