Home | History | Annotate | Download | only in aura
      1 // Copyright (c) 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 "content/browser/web_contents/aura/window_slider.h"
      6 
      7 #include "base/bind.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 #include "ui/aura/root_window.h"
     10 #include "ui/aura/test/aura_test_base.h"
     11 #include "ui/aura/test/event_generator.h"
     12 #include "ui/aura/test/test_window_delegate.h"
     13 #include "ui/aura/window.h"
     14 #include "ui/base/hit_test.h"
     15 
     16 namespace content {
     17 
     18 void DispatchEventDuringScrollCallback(aura::RootWindow* root_window,
     19                                        ui::Event* event,
     20                                        ui::EventType type,
     21                                        const gfx::Vector2dF& delta) {
     22   if (type != ui::ET_GESTURE_SCROLL_UPDATE)
     23     return;
     24   aura::RootWindowHostDelegate* delegate =
     25       root_window->AsRootWindowHostDelegate();
     26   if (event->IsMouseEvent())
     27     delegate->OnHostMouseEvent(static_cast<ui::MouseEvent*>(event));
     28   else if (event->IsKeyEvent())
     29     delegate->OnHostKeyEvent(static_cast<ui::KeyEvent*>(event));
     30 }
     31 
     32 void ChangeSliderOwnerDuringScrollCallback(scoped_ptr<aura::Window>* window,
     33                                            WindowSlider* slider,
     34                                            ui::EventType type,
     35                                            const gfx::Vector2dF& delta) {
     36   if (type != ui::ET_GESTURE_SCROLL_UPDATE)
     37     return;
     38   aura::Window* new_window = new aura::Window(NULL);
     39   new_window->Init(ui::LAYER_TEXTURED);
     40   new_window->Show();
     41   slider->ChangeOwner(new_window);
     42   (*window)->parent()->AddChild(new_window);
     43   window->reset(new_window);
     44 }
     45 
     46 // The window delegate does not receive any events.
     47 class NoEventWindowDelegate : public aura::test::TestWindowDelegate {
     48  public:
     49   NoEventWindowDelegate() {
     50   }
     51   virtual ~NoEventWindowDelegate() {}
     52 
     53  private:
     54   // Overridden from aura::WindowDelegate:
     55   virtual bool HasHitTestMask() const OVERRIDE { return true; }
     56 
     57   DISALLOW_COPY_AND_ASSIGN(NoEventWindowDelegate);
     58 };
     59 
     60 class WindowSliderDelegateTest : public WindowSlider::Delegate {
     61  public:
     62   WindowSliderDelegateTest()
     63       : can_create_layer_(true),
     64         created_back_layer_(false),
     65         created_front_layer_(false),
     66         slide_completed_(false),
     67         slide_aborted_(false),
     68         slider_destroyed_(false) {
     69   }
     70   virtual ~WindowSliderDelegateTest() {}
     71 
     72   void Reset() {
     73     can_create_layer_ = true;
     74     created_back_layer_ = false;
     75     created_front_layer_ = false;
     76     slide_completed_ = false;
     77     slide_aborted_ = false;
     78     slider_destroyed_ = false;
     79   }
     80 
     81   void SetCanCreateLayer(bool can_create_layer) {
     82     can_create_layer_ = can_create_layer;
     83   }
     84 
     85   bool created_back_layer() const { return created_back_layer_; }
     86   bool created_front_layer() const { return created_front_layer_; }
     87   bool slide_completed() const { return slide_completed_; }
     88   bool slide_aborted() const { return slide_aborted_; }
     89   bool slider_destroyed() const { return slider_destroyed_; }
     90 
     91  protected:
     92   ui::Layer* CreateLayerForTest() {
     93     CHECK(can_create_layer_);
     94     ui::Layer* layer = new ui::Layer(ui::LAYER_SOLID_COLOR);
     95     layer->SetColor(SK_ColorRED);
     96     return layer;
     97   }
     98 
     99   // Overridden from WindowSlider::Delegate:
    100   virtual ui::Layer* CreateBackLayer() OVERRIDE {
    101     if (!can_create_layer_)
    102       return NULL;
    103     created_back_layer_ = true;
    104     return CreateLayerForTest();
    105   }
    106 
    107   virtual ui::Layer* CreateFrontLayer() OVERRIDE {
    108     if (!can_create_layer_)
    109       return NULL;
    110     created_front_layer_ = true;
    111     return CreateLayerForTest();
    112   }
    113 
    114   virtual void OnWindowSlideComplete() OVERRIDE {
    115     slide_completed_ = true;
    116   }
    117 
    118   virtual void OnWindowSlideAborted() OVERRIDE {
    119     slide_aborted_ = true;
    120   }
    121 
    122   virtual void OnWindowSliderDestroyed() OVERRIDE {
    123     slider_destroyed_ = true;
    124   }
    125 
    126  private:
    127   bool can_create_layer_;
    128   bool created_back_layer_;
    129   bool created_front_layer_;
    130   bool slide_completed_;
    131   bool slide_aborted_;
    132   bool slider_destroyed_;
    133 
    134   DISALLOW_COPY_AND_ASSIGN(WindowSliderDelegateTest);
    135 };
    136 
    137 // This delegate destroys the owner window when the slider is destroyed.
    138 class WindowSliderDeleteOwnerOnDestroy : public WindowSliderDelegateTest {
    139  public:
    140   explicit WindowSliderDeleteOwnerOnDestroy(aura::Window* owner)
    141       : owner_(owner) {
    142   }
    143   virtual ~WindowSliderDeleteOwnerOnDestroy() {}
    144 
    145  private:
    146   // Overridden from WindowSlider::Delegate:
    147   virtual void OnWindowSliderDestroyed() OVERRIDE {
    148     WindowSliderDelegateTest::OnWindowSliderDestroyed();
    149     delete owner_;
    150   }
    151 
    152   aura::Window* owner_;
    153   DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnDestroy);
    154 };
    155 
    156 // This delegate destroyes the owner window when a slide is completed.
    157 class WindowSliderDeleteOwnerOnComplete : public WindowSliderDelegateTest {
    158  public:
    159   explicit WindowSliderDeleteOwnerOnComplete(aura::Window* owner)
    160       : owner_(owner) {
    161   }
    162   virtual ~WindowSliderDeleteOwnerOnComplete() {}
    163 
    164  private:
    165   // Overridden from WindowSlider::Delegate:
    166   virtual void OnWindowSlideComplete() OVERRIDE {
    167     WindowSliderDelegateTest::OnWindowSlideComplete();
    168     delete owner_;
    169   }
    170 
    171   aura::Window* owner_;
    172   DISALLOW_COPY_AND_ASSIGN(WindowSliderDeleteOwnerOnComplete);
    173 };
    174 
    175 typedef aura::test::AuraTestBase WindowSliderTest;
    176 
    177 TEST_F(WindowSliderTest, WindowSlideUsingGesture) {
    178   scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
    179   window->SetBounds(gfx::Rect(0, 0, 400, 400));
    180   WindowSliderDelegateTest slider_delegate;
    181 
    182   aura::test::EventGenerator generator(root_window());
    183 
    184   // Generate a horizontal overscroll.
    185   WindowSlider* slider =
    186       new WindowSlider(&slider_delegate, root_window(), window.get());
    187   generator.GestureScrollSequence(gfx::Point(10, 10),
    188                                   gfx::Point(160, 10),
    189                                   base::TimeDelta::FromMilliseconds(10),
    190                                   10);
    191   EXPECT_TRUE(slider_delegate.created_back_layer());
    192   EXPECT_TRUE(slider_delegate.slide_completed());
    193   EXPECT_FALSE(slider_delegate.created_front_layer());
    194   EXPECT_FALSE(slider_delegate.slide_aborted());
    195   EXPECT_FALSE(slider_delegate.slider_destroyed());
    196   EXPECT_FALSE(slider->IsSlideInProgress());
    197   slider_delegate.Reset();
    198   window->SetTransform(gfx::Transform());
    199 
    200   // Generat a horizontal overscroll in the reverse direction.
    201   generator.GestureScrollSequence(gfx::Point(160, 10),
    202                                   gfx::Point(10, 10),
    203                                   base::TimeDelta::FromMilliseconds(10),
    204                                   10);
    205   EXPECT_TRUE(slider_delegate.created_front_layer());
    206   EXPECT_TRUE(slider_delegate.slide_completed());
    207   EXPECT_FALSE(slider_delegate.created_back_layer());
    208   EXPECT_FALSE(slider_delegate.slide_aborted());
    209   EXPECT_FALSE(slider_delegate.slider_destroyed());
    210   EXPECT_FALSE(slider->IsSlideInProgress());
    211   slider_delegate.Reset();
    212 
    213   // Generate a vertical overscroll.
    214   generator.GestureScrollSequence(gfx::Point(10, 10),
    215                                   gfx::Point(10, 80),
    216                                   base::TimeDelta::FromMilliseconds(10),
    217                                   10);
    218   EXPECT_FALSE(slider_delegate.created_back_layer());
    219   EXPECT_FALSE(slider_delegate.slide_completed());
    220   EXPECT_FALSE(slider_delegate.created_front_layer());
    221   EXPECT_FALSE(slider_delegate.slide_aborted());
    222   EXPECT_FALSE(slider->IsSlideInProgress());
    223   slider_delegate.Reset();
    224 
    225   // Generate a horizontal scroll that starts overscroll, but doesn't scroll
    226   // enough to complete it.
    227   generator.GestureScrollSequence(gfx::Point(10, 10),
    228                                   gfx::Point(60, 10),
    229                                   base::TimeDelta::FromMilliseconds(10),
    230                                   10);
    231   EXPECT_TRUE(slider_delegate.created_back_layer());
    232   EXPECT_TRUE(slider_delegate.slide_aborted());
    233   EXPECT_FALSE(slider_delegate.created_front_layer());
    234   EXPECT_FALSE(slider_delegate.slide_completed());
    235   EXPECT_FALSE(slider_delegate.slider_destroyed());
    236   EXPECT_FALSE(slider->IsSlideInProgress());
    237   slider_delegate.Reset();
    238 
    239   // Destroy the window. This should destroy the slider.
    240   window.reset();
    241   EXPECT_TRUE(slider_delegate.slider_destroyed());
    242 }
    243 
    244 // Tests that the window slide is cancelled when a different type of event
    245 // happens.
    246 TEST_F(WindowSliderTest, WindowSlideIsCancelledOnEvent) {
    247   scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
    248   WindowSliderDelegateTest slider_delegate;
    249 
    250   ui::Event* events[] = {
    251     new ui::MouseEvent(ui::ET_MOUSE_MOVED,
    252                        gfx::Point(55, 10),
    253                        gfx::Point(55, 10),
    254                        0),
    255     new ui::KeyEvent(ui::ET_KEY_PRESSED,
    256                      ui::VKEY_A,
    257                      0,
    258                      true),
    259     NULL
    260   };
    261 
    262   new WindowSlider(&slider_delegate, root_window(), window.get());
    263   for (int i = 0; events[i]; ++i) {
    264     // Generate a horizontal overscroll.
    265     aura::test::EventGenerator generator(root_window());
    266     generator.GestureScrollSequenceWithCallback(
    267         gfx::Point(10, 10),
    268         gfx::Point(80, 10),
    269         base::TimeDelta::FromMilliseconds(10),
    270         1,
    271         base::Bind(&DispatchEventDuringScrollCallback,
    272                    root_window(),
    273                    base::Owned(events[i])));
    274     EXPECT_TRUE(slider_delegate.created_back_layer());
    275     EXPECT_TRUE(slider_delegate.slide_aborted());
    276     EXPECT_FALSE(slider_delegate.created_front_layer());
    277     EXPECT_FALSE(slider_delegate.slide_completed());
    278     EXPECT_FALSE(slider_delegate.slider_destroyed());
    279     slider_delegate.Reset();
    280   }
    281   window.reset();
    282   EXPECT_TRUE(slider_delegate.slider_destroyed());
    283 }
    284 
    285 // Tests that the slide works correctly when the owner of the window changes
    286 // during the duration of the slide.
    287 TEST_F(WindowSliderTest, OwnerWindowChangesDuringWindowSlide) {
    288   scoped_ptr<aura::Window> parent(CreateNormalWindow(0, root_window(), NULL));
    289 
    290   NoEventWindowDelegate window_delegate;
    291   window_delegate.set_window_component(HTNOWHERE);
    292   scoped_ptr<aura::Window> window(CreateNormalWindow(1, parent.get(),
    293                                                      &window_delegate));
    294 
    295   WindowSliderDelegateTest slider_delegate;
    296   scoped_ptr<WindowSlider> slider(
    297       new WindowSlider(&slider_delegate, parent.get(), window.get()));
    298 
    299   // Generate a horizontal scroll, and change the owner in the middle of the
    300   // scroll.
    301   aura::test::EventGenerator generator(root_window());
    302   aura::Window* old_window = window.get();
    303   generator.GestureScrollSequenceWithCallback(
    304       gfx::Point(10, 10),
    305       gfx::Point(80, 10),
    306       base::TimeDelta::FromMilliseconds(10),
    307       1,
    308       base::Bind(&ChangeSliderOwnerDuringScrollCallback,
    309                  base::Unretained(&window),
    310                  slider.get()));
    311   aura::Window* new_window = window.get();
    312   EXPECT_NE(old_window, new_window);
    313 
    314   EXPECT_TRUE(slider_delegate.created_back_layer());
    315   EXPECT_TRUE(slider_delegate.slide_completed());
    316   EXPECT_FALSE(slider_delegate.created_front_layer());
    317   EXPECT_FALSE(slider_delegate.slide_aborted());
    318   EXPECT_FALSE(slider_delegate.slider_destroyed());
    319 }
    320 
    321 TEST_F(WindowSliderTest, NoSlideWhenLayerCantBeCreated) {
    322   scoped_ptr<aura::Window> window(CreateNormalWindow(0, root_window(), NULL));
    323   window->SetBounds(gfx::Rect(0, 0, 400, 400));
    324   WindowSliderDelegateTest slider_delegate;
    325   slider_delegate.SetCanCreateLayer(false);
    326 
    327   aura::test::EventGenerator generator(root_window());
    328 
    329   // Generate a horizontal overscroll.
    330   scoped_ptr<WindowSlider> slider(
    331       new WindowSlider(&slider_delegate, root_window(), window.get()));
    332   generator.GestureScrollSequence(gfx::Point(10, 10),
    333                                   gfx::Point(160, 10),
    334                                   base::TimeDelta::FromMilliseconds(10),
    335                                   10);
    336   EXPECT_FALSE(slider_delegate.created_back_layer());
    337   EXPECT_FALSE(slider_delegate.slide_completed());
    338   EXPECT_FALSE(slider_delegate.created_front_layer());
    339   EXPECT_FALSE(slider_delegate.slide_aborted());
    340   EXPECT_FALSE(slider_delegate.slider_destroyed());
    341   window->SetTransform(gfx::Transform());
    342 
    343   slider_delegate.SetCanCreateLayer(true);
    344   generator.GestureScrollSequence(gfx::Point(10, 10),
    345                                   gfx::Point(160, 10),
    346                                   base::TimeDelta::FromMilliseconds(10),
    347                                   10);
    348   EXPECT_TRUE(slider_delegate.created_back_layer());
    349   EXPECT_TRUE(slider_delegate.slide_completed());
    350   EXPECT_FALSE(slider_delegate.created_front_layer());
    351   EXPECT_FALSE(slider_delegate.slide_aborted());
    352   EXPECT_FALSE(slider_delegate.slider_destroyed());
    353 }
    354 
    355 // Tests that the owner window can be destroyed from |OnWindowSliderDestroyed()|
    356 // delegate callback without causing a crash.
    357 TEST_F(WindowSliderTest, OwnerIsDestroyedOnSliderDestroy) {
    358   size_t child_windows = root_window()->children().size();
    359   aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
    360   window->SetBounds(gfx::Rect(0, 0, 400, 400));
    361   EXPECT_EQ(child_windows + 1, root_window()->children().size());
    362 
    363   WindowSliderDeleteOwnerOnDestroy slider_delegate(window);
    364   aura::test::EventGenerator generator(root_window());
    365 
    366   // Generate a horizontal overscroll.
    367   scoped_ptr<WindowSlider> slider(
    368       new WindowSlider(&slider_delegate, root_window(), window));
    369   generator.GestureScrollSequence(gfx::Point(10, 10),
    370                                   gfx::Point(160, 10),
    371                                   base::TimeDelta::FromMilliseconds(10),
    372                                   10);
    373   EXPECT_TRUE(slider_delegate.created_back_layer());
    374   EXPECT_TRUE(slider_delegate.slide_completed());
    375   EXPECT_FALSE(slider_delegate.created_front_layer());
    376   EXPECT_FALSE(slider_delegate.slide_aborted());
    377   EXPECT_FALSE(slider_delegate.slider_destroyed());
    378 
    379   slider.reset();
    380   // Destroying the slider would have destroyed |window| too. So |window| should
    381   // not need to be destroyed here.
    382   EXPECT_EQ(child_windows, root_window()->children().size());
    383 }
    384 
    385 // Tests that the owner window can be destroyed from |OnWindowSlideComplete()|
    386 // delegate callback without causing a crash.
    387 TEST_F(WindowSliderTest, OwnerIsDestroyedOnSlideComplete) {
    388   size_t child_windows = root_window()->children().size();
    389   aura::Window* window = CreateNormalWindow(0, root_window(), NULL);
    390   window->SetBounds(gfx::Rect(0, 0, 400, 400));
    391   EXPECT_EQ(child_windows + 1, root_window()->children().size());
    392 
    393   WindowSliderDeleteOwnerOnComplete slider_delegate(window);
    394   aura::test::EventGenerator generator(root_window());
    395 
    396   // Generate a horizontal overscroll.
    397   new WindowSlider(&slider_delegate, root_window(), window);
    398   generator.GestureScrollSequence(gfx::Point(10, 10),
    399                                   gfx::Point(160, 10),
    400                                   base::TimeDelta::FromMilliseconds(10),
    401                                   10);
    402   EXPECT_TRUE(slider_delegate.created_back_layer());
    403   EXPECT_TRUE(slider_delegate.slide_completed());
    404   EXPECT_FALSE(slider_delegate.created_front_layer());
    405   EXPECT_FALSE(slider_delegate.slide_aborted());
    406   EXPECT_TRUE(slider_delegate.slider_destroyed());
    407 
    408   // Destroying the slider would have destroyed |window| too. So |window| should
    409   // not need to be destroyed here.
    410   EXPECT_EQ(child_windows, root_window()->children().size());
    411 }
    412 
    413 }  // namespace content
    414