Home | History | Annotate | Download | only in display
      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