Upstream version 5.34.92.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/root_window.h"
16 #include "ui/aura/window.h"
17 #include "ui/events/event.h"
18 #include "ui/gfx/screen.h"
19 #include "ui/views/layout/fill_layout.h"
20 #include "ui/views/test/views_test_base.h"
21 #include "ui/views/widget/root_view.h"
22 #include "ui/views/widget/widget_delegate.h"
23
24 namespace views {
25 namespace {
26
27 NativeWidgetAura* Init(aura::Window* parent, Widget* widget) {
28   Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
29   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
30   params.parent = parent;
31   widget->Init(params);
32   return static_cast<NativeWidgetAura*>(widget->native_widget());
33 }
34
35 class NativeWidgetAuraTest : public ViewsTestBase {
36  public:
37   NativeWidgetAuraTest() {}
38   virtual ~NativeWidgetAuraTest() {}
39
40   // testing::Test overrides:
41   virtual void SetUp() OVERRIDE {
42     ViewsTestBase::SetUp();
43     dispatcher()->host()->SetBounds(gfx::Rect(640, 480));
44   }
45
46  protected:
47   aura::Window* root_window() { return GetContext(); }
48   aura::RootWindow* dispatcher() { return root_window()->GetDispatcher(); }
49
50  private:
51   DISALLOW_COPY_AND_ASSIGN(NativeWidgetAuraTest);
52 };
53
54 TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) {
55   // Make a parent window larger than the host represented by rootwindow.
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 rootwindow.
72   scoped_ptr<aura::Window> parent(new aura::Window(NULL));
73   parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
74   parent->SetBounds(gfx::Rect(0, 0, 480, 320));
75   scoped_ptr<Widget> widget(new Widget());
76   NativeWidgetAura* window = Init(parent.get(), widget.get());
77
78   window->CenterWindow(gfx::Size(100, 100));
79   EXPECT_EQ(gfx::Rect( (480 - 100) / 2,
80                        (320 - 100) / 2,
81                        100, 100),
82             window->GetNativeWindow()->bounds());
83   widget->CloseNow();
84 }
85
86 // Verifies CenterWindow() constrains to parent size.
87 TEST_F(NativeWidgetAuraTest, CenterWindowSmallParentNotAtOrigin) {
88   // Make a parent window smaller than the host represented by rootwindow and
89   // offset it slightly from the origin.
90   scoped_ptr<aura::Window> parent(new aura::Window(NULL));
91   parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
92   parent->SetBounds(gfx::Rect(20, 40, 480, 320));
93   scoped_ptr<Widget> widget(new Widget());
94   NativeWidgetAura* window = Init(parent.get(), widget.get());
95   window->CenterWindow(gfx::Size(500, 600));
96
97   // |window| should be no bigger than |parent|.
98   EXPECT_EQ("20,40 480x320", window->GetNativeWindow()->bounds().ToString());
99   widget->CloseNow();
100 }
101
102 // Used by ShowMaximizedDoesntBounceAround. See it for details.
103 class TestLayoutManager : public aura::LayoutManager {
104  public:
105   TestLayoutManager() {}
106
107   virtual void OnWindowResized() OVERRIDE {
108   }
109   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
110     // This simulates what happens when adding a maximized window.
111     SetChildBoundsDirect(child, gfx::Rect(0, 0, 300, 300));
112   }
113   virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {
114   }
115   virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {
116   }
117   virtual void OnChildWindowVisibilityChanged(aura::Window* child,
118                                               bool visible) OVERRIDE {
119   }
120   virtual void SetChildBounds(aura::Window* child,
121                               const gfx::Rect& requested_bounds) OVERRIDE {
122   }
123
124  private:
125   DISALLOW_COPY_AND_ASSIGN(TestLayoutManager);
126 };
127
128 // This simulates BrowserView, which creates a custom RootView so that
129 // OnNativeWidgetSizeChanged that is invoked during Init matters.
130 class TestWidget : public views::Widget {
131  public:
132   TestWidget() : did_size_change_more_than_once_(false) {
133   }
134
135   // Returns true if the size changes to a non-empty size, and then to another
136   // size.
137   bool did_size_change_more_than_once() const {
138     return did_size_change_more_than_once_;
139   }
140
141   virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) OVERRIDE {
142     if (last_size_.IsEmpty())
143       last_size_ = new_size;
144     else if (!did_size_change_more_than_once_ && new_size != last_size_)
145       did_size_change_more_than_once_ = true;
146     Widget::OnNativeWidgetSizeChanged(new_size);
147   }
148
149  private:
150   bool did_size_change_more_than_once_;
151   gfx::Size last_size_;
152
153   DISALLOW_COPY_AND_ASSIGN(TestWidget);
154 };
155
156 // Verifies the size of the widget doesn't change more than once during Init if
157 // the window ends up maximized. This is important as otherwise
158 // RenderWidgetHostViewAura ends up getting resized during construction, which
159 // leads to noticable flashes.
160 TEST_F(NativeWidgetAuraTest, ShowMaximizedDoesntBounceAround) {
161   root_window()->SetBounds(gfx::Rect(0, 0, 640, 480));
162   root_window()->SetLayoutManager(new TestLayoutManager);
163   scoped_ptr<TestWidget> widget(new TestWidget());
164   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
165   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
166   params.parent = NULL;
167   params.context = root_window();
168   params.show_state = ui::SHOW_STATE_MAXIMIZED;
169   params.bounds = gfx::Rect(10, 10, 100, 200);
170   widget->Init(params);
171   EXPECT_FALSE(widget->did_size_change_more_than_once());
172   widget->CloseNow();
173 }
174
175 TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) {
176   // Create a widget.
177   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
178   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
179   params.context = root_window();
180   params.bounds.SetRect(10, 20, 300, 400);
181   scoped_ptr<Widget> widget(new Widget());
182   widget->Init(params);
183
184   // For Aura, client area bounds match window bounds.
185   gfx::Rect client_bounds = widget->GetClientAreaBoundsInScreen();
186   EXPECT_EQ(10, client_bounds.x());
187   EXPECT_EQ(20, client_bounds.y());
188   EXPECT_EQ(300, client_bounds.width());
189   EXPECT_EQ(400, client_bounds.height());
190 }
191
192 namespace {
193
194 // View subclass that tracks whether it has gotten a gesture event.
195 class GestureTrackingView : public views::View {
196  public:
197   GestureTrackingView()
198       : got_gesture_event_(false),
199         consume_gesture_event_(true) {}
200
201   void set_consume_gesture_event(bool value) {
202     consume_gesture_event_ = value;
203   }
204
205   void clear_got_gesture_event() {
206     got_gesture_event_ = false;
207   }
208   bool got_gesture_event() const {
209     return got_gesture_event_;
210   }
211
212   // View overrides:
213   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
214     got_gesture_event_ = true;
215     if (consume_gesture_event_)
216       event->StopPropagation();
217   }
218
219  private:
220   // Was OnGestureEvent() invoked?
221   bool got_gesture_event_;
222
223   // Dictates what OnGestureEvent() returns.
224   bool consume_gesture_event_;
225
226   DISALLOW_COPY_AND_ASSIGN(GestureTrackingView);
227 };
228
229 }  // namespace
230
231 // Verifies a capture isn't set on touch press and that the view that gets
232 // the press gets the release.
233 TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) {
234   // Create two views (both sized the same). |child| is configured not to
235   // consume the gesture event.
236   GestureTrackingView* view = new GestureTrackingView();
237   GestureTrackingView* child = new GestureTrackingView();
238   child->set_consume_gesture_event(false);
239   view->SetLayoutManager(new FillLayout);
240   view->AddChildView(child);
241   scoped_ptr<TestWidget> widget(new TestWidget());
242   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
243   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
244   params.context = root_window();
245   params.bounds = gfx::Rect(0, 0, 100, 200);
246   widget->Init(params);
247   widget->SetContentsView(view);
248   widget->Show();
249
250   ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1,
251                            base::TimeDelta());
252   dispatcher()->AsWindowTreeHostDelegate()->OnHostTouchEvent(&press);
253   // Both views should get the press.
254   EXPECT_TRUE(view->got_gesture_event());
255   EXPECT_TRUE(child->got_gesture_event());
256   view->clear_got_gesture_event();
257   child->clear_got_gesture_event();
258   // Touch events should not automatically grab capture.
259   EXPECT_FALSE(widget->HasCapture());
260
261   // Release touch. Only |view| should get the release since that it consumed
262   // the press.
263   ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(250, 251), 1,
264                              base::TimeDelta());
265   dispatcher()->AsWindowTreeHostDelegate()->OnHostTouchEvent(&release);
266   EXPECT_TRUE(view->got_gesture_event());
267   EXPECT_FALSE(child->got_gesture_event());
268   view->clear_got_gesture_event();
269
270   // Work around for bug in NativeWidgetAura.
271   // TODO: fix bug and remove this.
272   widget->Close();
273 }
274
275 TEST_F(NativeWidgetAuraTest, ReleaseCaptureOnTouchRelease) {
276   GestureTrackingView* view = new GestureTrackingView();
277   scoped_ptr<TestWidget> widget(new TestWidget());
278   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
279   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
280   params.context = root_window();
281   params.bounds = gfx::Rect(0, 0, 100, 200);
282   widget->Init(params);
283   widget->SetContentsView(view);
284   widget->Show();
285
286   ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1,
287                            base::TimeDelta());
288   dispatcher()->AsWindowTreeHostDelegate()->OnHostTouchEvent(&press);
289   EXPECT_TRUE(view->got_gesture_event());
290   view->clear_got_gesture_event();
291   // Set the capture.
292   widget->SetCapture(view);
293   EXPECT_TRUE(widget->HasCapture());
294
295   // Generate a release, this should trigger releasing capture.
296   ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(41, 51), 1,
297                              base::TimeDelta());
298   dispatcher()->AsWindowTreeHostDelegate()->OnHostTouchEvent(&release);
299   EXPECT_TRUE(view->got_gesture_event());
300   view->clear_got_gesture_event();
301   EXPECT_FALSE(widget->HasCapture());
302
303   // Work around for bug in NativeWidgetAura.
304   // TODO: fix bug and remove this.
305   widget->Close();
306 }
307
308 // Verifies views with layers are targeted for events properly.
309 TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
310   // Create two widgets: |parent| and |child|. |child| is a child of |parent|.
311   views::View* parent_root = new views::View;
312   scoped_ptr<Widget> parent(new Widget());
313   Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
314   parent_params.ownership =
315       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
316   parent_params.context = root_window();
317   parent->Init(parent_params);
318   parent->SetContentsView(parent_root);
319   parent->SetBounds(gfx::Rect(0, 0, 400, 400));
320   parent->Show();
321
322   scoped_ptr<Widget> child(new Widget());
323   Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
324   child_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
325   child_params.parent = parent->GetNativeWindow();
326   child->Init(child_params);
327   child->SetBounds(gfx::Rect(0, 0, 200, 200));
328   child->Show();
329
330   // Point is over |child|.
331   EXPECT_EQ(child->GetNativeWindow(),
332             parent->GetNativeWindow()->GetEventHandlerForPoint(
333                 gfx::Point(50, 50)));
334
335   // Create a view with a layer and stack it at the bottom (below |child|).
336   views::View* view_with_layer = new views::View;
337   parent_root->AddChildView(view_with_layer);
338   view_with_layer->SetBounds(0, 0, 50, 50);
339   view_with_layer->SetPaintToLayer(true);
340
341   // Make sure that |child| still gets the event.
342   EXPECT_EQ(child->GetNativeWindow(),
343             parent->GetNativeWindow()->GetEventHandlerForPoint(
344                 gfx::Point(20, 20)));
345
346   // Move |view_with_layer| to the top and make sure it gets the
347   // event when the point is within |view_with_layer|'s bounds.
348   view_with_layer->layer()->parent()->StackAtTop(
349       view_with_layer->layer());
350   EXPECT_EQ(parent->GetNativeWindow(),
351             parent->GetNativeWindow()->GetEventHandlerForPoint(
352                 gfx::Point(20, 20)));
353
354   // Point is over |child|, it should get the event.
355   EXPECT_EQ(child->GetNativeWindow(),
356             parent->GetNativeWindow()->GetEventHandlerForPoint(
357                 gfx::Point(70, 70)));
358
359   delete view_with_layer;
360   view_with_layer = NULL;
361
362   EXPECT_EQ(child->GetNativeWindow(),
363             parent->GetNativeWindow()->GetEventHandlerForPoint(
364                 gfx::Point(20, 20)));
365
366   // Work around for bug in NativeWidgetAura.
367   // TODO: fix bug and remove this.
368   parent->Close();
369 }
370
371 // Verifies that widget->FlashFrame() sets aura::client::kDrawAttentionKey,
372 // and activating the window clears it.
373 TEST_F(NativeWidgetAuraTest, FlashFrame) {
374   scoped_ptr<Widget> widget(new Widget());
375   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
376   params.context = root_window();
377   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
378   widget->Init(params);
379   aura::Window* window = widget->GetNativeWindow();
380   EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
381   widget->FlashFrame(true);
382   EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey));
383   widget->FlashFrame(false);
384   EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
385   widget->FlashFrame(true);
386   EXPECT_TRUE(window->GetProperty(aura::client::kDrawAttentionKey));
387   widget->Activate();
388   EXPECT_FALSE(window->GetProperty(aura::client::kDrawAttentionKey));
389 }
390
391 TEST_F(NativeWidgetAuraTest, NoCrashOnThemeAfterClose) {
392   scoped_ptr<aura::Window> parent(new aura::Window(NULL));
393   parent->Init(aura::WINDOW_LAYER_NOT_DRAWN);
394   parent->SetBounds(gfx::Rect(0, 0, 480, 320));
395   scoped_ptr<Widget> widget(new Widget());
396   NativeWidgetAura* window = Init(parent.get(), widget.get());
397   window->Show();
398   window->Close();
399   base::MessageLoop::current()->RunUntilIdle();
400   widget->GetNativeTheme();  // Shouldn't crash.
401 }
402
403 }  // namespace
404 }  // namespace views