Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / views / widget / native_widget_aura_unittest.cc
1 // Copyright (c) 2012 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 "ui/views/widget/native_widget_aura.h"
6
7 #include "base/basictypes.h"
8 #include "base/command_line.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/aura/client/aura_constants.h"
13 #include "ui/aura/env.h"
14 #include "ui/aura/layout_manager.h"
15 #include "ui/aura/test/aura_test_base.h"
16 #include "ui/aura/window.h"
17 #include "ui/aura/window_tree_host.h"
18 #include "ui/events/event.h"
19 #include "ui/events/event_utils.h"
20 #include "ui/gfx/screen.h"
21 #include "ui/views/layout/fill_layout.h"
22 #include "ui/views/widget/root_view.h"
23 #include "ui/views/widget/widget_delegate.h"
24 #include "ui/wm/core/default_activation_client.h"
25
26 namespace views {
27 namespace {
28
29 NativeWidgetAura* Init(aura::Window* parent, Widget* widget) {
30   Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
31   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
32   params.parent = parent;
33   widget->Init(params);
34   return static_cast<NativeWidgetAura*>(widget->native_widget());
35 }
36
37 class NativeWidgetAuraTest : public aura::test::AuraTestBase {
38  public:
39   NativeWidgetAuraTest() {}
40   virtual ~NativeWidgetAuraTest() {}
41
42   // testing::Test overrides:
43   virtual void SetUp() OVERRIDE {
44     AuraTestBase::SetUp();
45     new wm::DefaultActivationClient(root_window());
46     host()->SetBounds(gfx::Rect(640, 480));
47   }
48
49  private:
50   DISALLOW_COPY_AND_ASSIGN(NativeWidgetAuraTest);
51 };
52
53 TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) {
54   // Make a parent window larger than the host represented by
55   // WindowEventDispatcher.
56   scoped_ptr<aura::Window> parent(new aura::Window(NULL));
57   parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
58   parent->SetBounds(gfx::Rect(0, 0, 1024, 800));
59   scoped_ptr<Widget> widget(new Widget());
60   NativeWidgetAura* window = Init(parent.get(), widget.get());
61
62   window->CenterWindow(gfx::Size(100, 100));
63   EXPECT_EQ(gfx::Rect( (640 - 100) / 2,
64                        (480 - 100) / 2,
65                        100, 100),
66             window->GetNativeWindow()->bounds());
67   widget->CloseNow();
68 }
69
70 TEST_F(NativeWidgetAuraTest, CenterWindowSmallParent) {
71   // Make a parent window smaller than the host represented by
72   // WindowEventDispatcher.
73   scoped_ptr<aura::Window> parent(new aura::Window(NULL));
74   parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
75   parent->SetBounds(gfx::Rect(0, 0, 480, 320));
76   scoped_ptr<Widget> widget(new Widget());
77   NativeWidgetAura* window = Init(parent.get(), widget.get());
78
79   window->CenterWindow(gfx::Size(100, 100));
80   EXPECT_EQ(gfx::Rect( (480 - 100) / 2,
81                        (320 - 100) / 2,
82                        100, 100),
83             window->GetNativeWindow()->bounds());
84   widget->CloseNow();
85 }
86
87 // Verifies CenterWindow() constrains to parent size.
88 TEST_F(NativeWidgetAuraTest, CenterWindowSmallParentNotAtOrigin) {
89   // Make a parent window smaller than the host represented by
90   // WindowEventDispatcher and offset it slightly from the origin.
91   scoped_ptr<aura::Window> parent(new aura::Window(NULL));
92   parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
93   parent->SetBounds(gfx::Rect(20, 40, 480, 320));
94   scoped_ptr<Widget> widget(new Widget());
95   NativeWidgetAura* window = Init(parent.get(), widget.get());
96   window->CenterWindow(gfx::Size(500, 600));
97
98   // |window| should be no bigger than |parent|.
99   EXPECT_EQ("20,40 480x320", window->GetNativeWindow()->bounds().ToString());
100   widget->CloseNow();
101 }
102
103 class TestLayoutManagerBase : public aura::LayoutManager {
104  public:
105   TestLayoutManagerBase() {}
106   virtual ~TestLayoutManagerBase() {}
107
108   // aura::LayoutManager:
109   virtual void OnWindowResized() OVERRIDE {}
110   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {}
111   virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
112   virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {}
113   virtual void OnChildWindowVisibilityChanged(aura::Window* child,
114                                               bool visible) OVERRIDE {}
115   virtual void SetChildBounds(aura::Window* child,
116                               const gfx::Rect& requested_bounds) OVERRIDE {}
117
118  private:
119   DISALLOW_COPY_AND_ASSIGN(TestLayoutManagerBase);
120 };
121
122 // Used by ShowMaximizedDoesntBounceAround. See it for details.
123 class MaximizeLayoutManager : public TestLayoutManagerBase {
124  public:
125   MaximizeLayoutManager() {}
126   virtual ~MaximizeLayoutManager() {}
127
128  private:
129   // aura::LayoutManager:
130   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
131     // This simulates what happens when adding a maximized window.
132     SetChildBoundsDirect(child, gfx::Rect(0, 0, 300, 300));
133   }
134
135   DISALLOW_COPY_AND_ASSIGN(MaximizeLayoutManager);
136 };
137
138 // This simulates BrowserView, which creates a custom RootView so that
139 // OnNativeWidgetSizeChanged that is invoked during Init matters.
140 class TestWidget : public views::Widget {
141  public:
142   TestWidget() : did_size_change_more_than_once_(false) {
143   }
144
145   // Returns true if the size changes to a non-empty size, and then to another
146   // size.
147   bool did_size_change_more_than_once() const {
148     return did_size_change_more_than_once_;
149   }
150
151   virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) OVERRIDE {
152     if (last_size_.IsEmpty())
153       last_size_ = new_size;
154     else if (!did_size_change_more_than_once_ && new_size != last_size_)
155       did_size_change_more_than_once_ = true;
156     Widget::OnNativeWidgetSizeChanged(new_size);
157   }
158
159  private:
160   bool did_size_change_more_than_once_;
161   gfx::Size last_size_;
162
163   DISALLOW_COPY_AND_ASSIGN(TestWidget);
164 };
165
166 // Verifies the size of the widget doesn't change more than once during Init if
167 // the window ends up maximized. This is important as otherwise
168 // RenderWidgetHostViewAura ends up getting resized during construction, which
169 // leads to noticable flashes.
170 TEST_F(NativeWidgetAuraTest, ShowMaximizedDoesntBounceAround) {
171   root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
172   root_window()->SetLayoutManager(new MaximizeLayoutManager);
173   scoped_ptr<TestWidget> widget(new TestWidget());
174   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
175   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
176   params.parent = NULL;
177   params.context = root_window();
178   params.show_state = ui::SHOW_STATE_MAXIMIZED;
179   params.bounds = gfx::Rect(10, 10, 100, 200);
180   widget->Init(params);
181   EXPECT_FALSE(widget->did_size_change_more_than_once());
182   widget->CloseNow();
183 }
184
185 class PropertyTestLayoutManager : public TestLayoutManagerBase {
186  public:
187   PropertyTestLayoutManager() : added_(false) {}
188   virtual ~PropertyTestLayoutManager() {}
189
190   bool added() const { return added_; }
191
192  private:
193   // aura::LayoutManager:
194   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
195     EXPECT_TRUE(child->GetProperty(aura::client::kCanMaximizeKey));
196     EXPECT_TRUE(child->GetProperty(aura::client::kCanResizeKey));
197     added_ = true;
198   }
199
200   bool added_;
201
202   DISALLOW_COPY_AND_ASSIGN(PropertyTestLayoutManager);
203 };
204
205 class PropertyTestWidgetDelegate : public views::WidgetDelegate {
206  public:
207   explicit PropertyTestWidgetDelegate(Widget* widget) : widget_(widget) {}
208   virtual ~PropertyTestWidgetDelegate() {}
209
210  private:
211   // views::WidgetDelegate:
212   virtual bool CanMaximize() const OVERRIDE {
213     return true;
214   }
215   virtual bool CanMinimize() const OVERRIDE {
216     return true;
217   }
218   virtual bool CanResize() const OVERRIDE {
219     return true;
220   }
221   virtual void DeleteDelegate() OVERRIDE {
222     delete this;
223   }
224   virtual Widget* GetWidget() OVERRIDE {
225     return widget_;
226   }
227   virtual const Widget* GetWidget() const OVERRIDE {
228     return widget_;
229   }
230
231   Widget* widget_;
232   DISALLOW_COPY_AND_ASSIGN(PropertyTestWidgetDelegate);
233 };
234
235 // Verifies that the kCanMaximizeKey/kCanReizeKey have the correct
236 // value when added to the layout manager.
237 TEST_F(NativeWidgetAuraTest, TestPropertiesWhenAddedToLayout) {
238   root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
239   PropertyTestLayoutManager* layout_manager = new PropertyTestLayoutManager();
240   root_window()->SetLayoutManager(layout_manager);
241   scoped_ptr<TestWidget> widget(new TestWidget());
242   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
243   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
244   params.delegate = new PropertyTestWidgetDelegate(widget.get());
245   params.parent = NULL;
246   params.context = root_window();
247   widget->Init(params);
248   EXPECT_TRUE(layout_manager->added());
249   widget->CloseNow();
250 }
251
252 TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) {
253   // Create a widget.
254   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
255   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
256   params.context = root_window();
257   params.bounds.SetRect(10, 20, 300, 400);
258   scoped_ptr<Widget> widget(new Widget());
259   widget->Init(params);
260
261   // For Aura, client area bounds match window bounds.
262   gfx::Rect client_bounds = widget->GetClientAreaBoundsInScreen();
263   EXPECT_EQ(10, client_bounds.x());
264   EXPECT_EQ(20, client_bounds.y());
265   EXPECT_EQ(300, client_bounds.width());
266   EXPECT_EQ(400, client_bounds.height());
267 }
268
269 // View subclass that tracks whether it has gotten a gesture event.
270 class GestureTrackingView : public views::View {
271  public:
272   GestureTrackingView()
273       : got_gesture_event_(false),
274         consume_gesture_event_(true) {}
275
276   void set_consume_gesture_event(bool value) {
277     consume_gesture_event_ = value;
278   }
279
280   void clear_got_gesture_event() {
281     got_gesture_event_ = false;
282   }
283   bool got_gesture_event() const {
284     return got_gesture_event_;
285   }
286
287   // View overrides:
288   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
289     got_gesture_event_ = true;
290     if (consume_gesture_event_)
291       event->StopPropagation();
292   }
293
294  private:
295   // Was OnGestureEvent() invoked?
296   bool got_gesture_event_;
297
298   // Dictates what OnGestureEvent() returns.
299   bool consume_gesture_event_;
300
301   DISALLOW_COPY_AND_ASSIGN(GestureTrackingView);
302 };
303
304 // Verifies a capture isn't set on touch press and that the view that gets
305 // the press gets the release.
306 TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
307   // Create two views (both sized the same). |child| is configured not to
308   // consume the gesture event.
309   GestureTrackingView* view = new GestureTrackingView();
310   GestureTrackingView* child = new GestureTrackingView();
311   child->set_consume_gesture_event(false);
312   view->SetLayoutManager(new FillLayout);
313   view->AddChildView(child);
314   scoped_ptr<TestWidget> widget(new TestWidget());
315   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
316   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
317   params.context = root_window();
318   params.bounds = gfx::Rect(0, 0, 100, 200);
319   widget->Init(params);
320   widget->SetContentsView(view);
321   widget->Show();
322
323   ui::TouchEvent press(
324       ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1, ui::EventTimeForNow());
325   ui::EventDispatchDetails details =
326       event_processor()->OnEventFromSource(&press);
327   ASSERT_FALSE(details.dispatcher_destroyed);
328   // Both views should get the press.
329   EXPECT_TRUE(view->got_gesture_event());
330   EXPECT_TRUE(child->got_gesture_event());
331   view->clear_got_gesture_event();
332   child->clear_got_gesture_event();
333   // Touch events should not automatically grab capture.
334   EXPECT_FALSE(widget->HasCapture());
335
336   // Release touch. Only |view| should get the release since that it consumed
337   // the press.
338   ui::TouchEvent release(
339       ui::ET_TOUCH_RELEASED, gfx::Point(250, 251), 1, ui::EventTimeForNow());
340   details = event_processor()->OnEventFromSource(&release);
341   ASSERT_FALSE(details.dispatcher_destroyed);
342   EXPECT_TRUE(view->got_gesture_event());
343   EXPECT_FALSE(child->got_gesture_event());
344   view->clear_got_gesture_event();
345
346   // Work around for bug in NativeWidgetAura.
347   // TODO: fix bug and remove this.
348   widget->Close();
349 }
350
351 // Verifies views with layers are targeted for events properly.
352 TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
353   // Create two widgets: |parent| and |child|. |child| is a child of |parent|.
354   views::View* parent_root = new views::View;
355   scoped_ptr<Widget> parent(new Widget());
356   Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
357   parent_params.ownership =
358       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
359   parent_params.context = root_window();
360   parent->Init(parent_params);
361   parent->SetContentsView(parent_root);
362   parent->SetBounds(gfx::Rect(0, 0, 400, 400));
363   parent->Show();
364
365   scoped_ptr<Widget> child(new Widget());
366   Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
367   child_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
368   child_params.parent = parent->GetNativeWindow();
369   child->Init(child_params);
370   child->SetBounds(gfx::Rect(0, 0, 200, 200));
371   child->Show();
372
373   // Point is over |child|.
374   EXPECT_EQ(child->GetNativeWindow(),
375             parent->GetNativeWindow()->GetEventHandlerForPoint(
376                 gfx::Point(50, 50)));
377
378   // Create a view with a layer and stack it at the bottom (below |child|).
379   views::View* view_with_layer = new views::View;
380   parent_root->AddChildView(view_with_layer);
381   view_with_layer->SetBounds(0, 0, 50, 50);
382   view_with_layer->SetPaintToLayer(true);
383
384   // Make sure that |child| still gets the event.
385   EXPECT_EQ(child->GetNativeWindow(),
386             parent->GetNativeWindow()->GetEventHandlerForPoint(
387                 gfx::Point(20, 20)));
388
389   // Move |view_with_layer| to the top and make sure it gets the
390   // event when the point is within |view_with_layer|'s bounds.
391   view_with_layer->layer()->parent()->StackAtTop(
392       view_with_layer->layer());
393   EXPECT_EQ(parent->GetNativeWindow(),
394             parent->GetNativeWindow()->GetEventHandlerForPoint(
395                 gfx::Point(20, 20)));
396
397   // Point is over |child|, it should get the event.
398   EXPECT_EQ(child->GetNativeWindow(),
399             parent->GetNativeWindow()->GetEventHandlerForPoint(
400                 gfx::Point(70, 70)));
401
402   delete view_with_layer;
403   view_with_layer = NULL;
404
405   EXPECT_EQ(child->GetNativeWindow(),
406             parent->GetNativeWindow()->GetEventHandlerForPoint(
407                 gfx::Point(20, 20)));
408
409   // Work around for bug in NativeWidgetAura.
410   // TODO: fix bug and remove this.
411   parent->Close();
412 }
413
414 // Verifies that widget->FlashFrame() sets aura::client::kDrawAttentionKey,
415 // and activating the window clears it.
416 TEST_F(NativeWidgetAuraTest, FlashFrame) {
417   scoped_ptr<Widget> widget(new Widget());
418   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
419   params.context = root_window();
420   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
421   widget->Init(params);
422   aura::Window* window = widget->GetNativeWindow();
423   EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
424   widget->FlashFrame(true);
425   EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey));
426   widget->FlashFrame(false);
427   EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
428   widget->FlashFrame(true);
429   EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey));
430   widget->Activate();
431   EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
432 }
433
434 TEST_F(NativeWidgetAuraTest, NoCrashOnThemeAfterClose) {
435   scoped_ptr<aura::Window> parent(new aura::Window(NULL));
436   parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
437   parent->SetBounds(gfx::Rect(0, 0, 480, 320));
438   scoped_ptr<Widget> widget(new Widget());
439   Init(parent.get(), widget.get());
440   widget->Show();
441   widget->Close();
442   base::MessageLoop::current()->RunUntilIdle();
443   widget->GetNativeTheme();  // Shouldn't crash.
444 }
445
446 // Used to track calls to WidgetDelegate::OnWidgetMove().
447 class MoveTestWidgetDelegate : public WidgetDelegateView {
448  public:
449   MoveTestWidgetDelegate() : got_move_(false) {}
450   virtual ~MoveTestWidgetDelegate() {}
451
452   void ClearGotMove() { got_move_ = false; }
453   bool got_move() const { return got_move_; }
454
455   // WidgetDelegate overrides:
456   virtual void OnWidgetMove() OVERRIDE { got_move_ = true; }
457
458  private:
459   bool got_move_;
460
461   DISALLOW_COPY_AND_ASSIGN(MoveTestWidgetDelegate);
462 };
463
464 // This test simulates what happens when a window is normally maximized. That
465 // is, it's layer is acquired for animation then the window is maximized.
466 // Acquiring the layer resets the bounds of the window. This test verifies the
467 // Widget is still notified correctly of a move in this case.
468 TEST_F(NativeWidgetAuraTest, OnWidgetMovedInvokedAfterAcquireLayer) {
469   // |delegate| deletes itself when the widget is destroyed.
470   MoveTestWidgetDelegate* delegate = new MoveTestWidgetDelegate;
471   Widget* widget =
472       Widget::CreateWindowWithContextAndBounds(delegate,
473                                                root_window(),
474                                                gfx::Rect(10, 10, 100, 200));
475   widget->Show();
476   delegate->ClearGotMove();
477   // Simulate a maximize with animation.
478   delete widget->GetNativeView()->RecreateLayer().release();
479   widget->SetBounds(gfx::Rect(0, 0, 500, 500));
480   EXPECT_TRUE(delegate->got_move());
481   widget->CloseNow();
482 }
483
484 }  // namespace
485 }  // namespace views