Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / views / widget / root_view_unittest.cc
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 "ui/views/widget/root_view.h"
6
7 #include "ui/views/context_menu_controller.h"
8 #include "ui/views/test/views_test_base.h"
9 #include "ui/views/view_targeter.h"
10 #include "ui/views/widget/root_view.h"
11
12 namespace views {
13 namespace test {
14
15 typedef ViewsTestBase RootViewTest;
16
17 class DeleteOnKeyEventView : public View {
18  public:
19   explicit DeleteOnKeyEventView(bool* set_on_key) : set_on_key_(set_on_key) {}
20   ~DeleteOnKeyEventView() override {}
21
22   bool OnKeyPressed(const ui::KeyEvent& event) override {
23     *set_on_key_ = true;
24     delete this;
25     return true;
26   }
27
28  private:
29   // Set to true in OnKeyPressed().
30   bool* set_on_key_;
31
32   DISALLOW_COPY_AND_ASSIGN(DeleteOnKeyEventView);
33 };
34
35 // Verifies deleting a View in OnKeyPressed() doesn't crash and that the
36 // target is marked as destroyed in the returned EventDispatchDetails.
37 TEST_F(RootViewTest, DeleteViewDuringKeyEventDispatch) {
38   Widget widget;
39   Widget::InitParams init_params =
40       CreateParams(Widget::InitParams::TYPE_POPUP);
41   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
42   widget.Init(init_params);
43
44   bool got_key_event = false;
45
46   View* content = new View;
47   widget.SetContentsView(content);
48
49   View* child = new DeleteOnKeyEventView(&got_key_event);
50   content->AddChildView(child);
51
52   // Give focus to |child| so that it will be the target of the key event.
53   child->SetFocusable(true);
54   child->RequestFocus();
55
56   internal::RootView* root_view =
57       static_cast<internal::RootView*>(widget.GetRootView());
58   ViewTargeter* view_targeter = new ViewTargeter(root_view);
59   root_view->SetEventTargeter(make_scoped_ptr(view_targeter));
60
61   ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, ui::EF_NONE);
62   ui::EventDispatchDetails details = root_view->OnEventFromSource(&key_event);
63   EXPECT_TRUE(details.target_destroyed);
64   EXPECT_FALSE(details.dispatcher_destroyed);
65   EXPECT_TRUE(got_key_event);
66 }
67
68 // Tracks whether a context menu is shown.
69 class TestContextMenuController : public ContextMenuController {
70  public:
71   TestContextMenuController()
72       : show_context_menu_calls_(0),
73         menu_source_view_(NULL),
74         menu_source_type_(ui::MENU_SOURCE_NONE) {
75   }
76   ~TestContextMenuController() override {}
77
78   int show_context_menu_calls() const { return show_context_menu_calls_; }
79   View* menu_source_view() const { return menu_source_view_; }
80   ui::MenuSourceType menu_source_type() const { return menu_source_type_; }
81
82   void Reset() {
83     show_context_menu_calls_ = 0;
84     menu_source_view_ = NULL;
85     menu_source_type_ = ui::MENU_SOURCE_NONE;
86   }
87
88   // ContextMenuController:
89   void ShowContextMenuForView(View* source,
90                               const gfx::Point& point,
91                               ui::MenuSourceType source_type) override {
92     show_context_menu_calls_++;
93     menu_source_view_ = source;
94     menu_source_type_ = source_type;
95   }
96
97  private:
98   int show_context_menu_calls_;
99   View* menu_source_view_;
100   ui::MenuSourceType menu_source_type_;
101
102   DISALLOW_COPY_AND_ASSIGN(TestContextMenuController);
103 };
104
105 // Tests that context menus are shown for certain key events (Shift+F10
106 // and VKEY_APPS) by the pre-target handler installed on RootView.
107 TEST_F(RootViewTest, ContextMenuFromKeyEvent) {
108   Widget widget;
109   Widget::InitParams init_params =
110       CreateParams(Widget::InitParams::TYPE_POPUP);
111   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
112   widget.Init(init_params);
113   internal::RootView* root_view =
114       static_cast<internal::RootView*>(widget.GetRootView());
115
116   TestContextMenuController controller;
117   View* focused_view = new View;
118   focused_view->set_context_menu_controller(&controller);
119   widget.SetContentsView(focused_view);
120   focused_view->SetFocusable(true);
121   focused_view->RequestFocus();
122
123   // No context menu should be shown for a keypress of 'A'.
124   ui::KeyEvent nomenu_key_event('a', ui::VKEY_A, ui::EF_NONE);
125   ui::EventDispatchDetails details =
126       root_view->OnEventFromSource(&nomenu_key_event);
127   EXPECT_FALSE(details.target_destroyed);
128   EXPECT_FALSE(details.dispatcher_destroyed);
129   EXPECT_EQ(0, controller.show_context_menu_calls());
130   EXPECT_EQ(NULL, controller.menu_source_view());
131   EXPECT_EQ(ui::MENU_SOURCE_NONE, controller.menu_source_type());
132   controller.Reset();
133
134   // A context menu should be shown for a keypress of Shift+F10.
135   ui::KeyEvent menu_key_event(
136       ui::ET_KEY_PRESSED, ui::VKEY_F10, ui::EF_SHIFT_DOWN);
137   details = root_view->OnEventFromSource(&menu_key_event);
138   EXPECT_FALSE(details.target_destroyed);
139   EXPECT_FALSE(details.dispatcher_destroyed);
140   EXPECT_EQ(1, controller.show_context_menu_calls());
141   EXPECT_EQ(focused_view, controller.menu_source_view());
142   EXPECT_EQ(ui::MENU_SOURCE_KEYBOARD, controller.menu_source_type());
143   controller.Reset();
144
145   // A context menu should be shown for a keypress of VKEY_APPS.
146   ui::KeyEvent menu_key_event2(ui::ET_KEY_PRESSED, ui::VKEY_APPS, ui::EF_NONE);
147   details = root_view->OnEventFromSource(&menu_key_event2);
148   EXPECT_FALSE(details.target_destroyed);
149   EXPECT_FALSE(details.dispatcher_destroyed);
150   EXPECT_EQ(1, controller.show_context_menu_calls());
151   EXPECT_EQ(focused_view, controller.menu_source_view());
152   EXPECT_EQ(ui::MENU_SOURCE_KEYBOARD, controller.menu_source_type());
153   controller.Reset();
154 }
155
156 // View which handles all gesture events.
157 class GestureHandlingView : public View {
158  public:
159   GestureHandlingView() {
160   }
161
162   ~GestureHandlingView() override {}
163
164   void OnGestureEvent(ui::GestureEvent* event) override { event->SetHandled(); }
165
166  private:
167   DISALLOW_COPY_AND_ASSIGN(GestureHandlingView);
168 };
169
170 // Tests that context menus are shown for long press by the post-target handler
171 // installed on the RootView only if the event is targetted at a view which can
172 // show a context menu.
173 TEST_F(RootViewTest, ContextMenuFromLongPress) {
174   Widget widget;
175   Widget::InitParams init_params =
176       CreateParams(Widget::InitParams::TYPE_POPUP);
177   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
178   init_params.bounds = gfx::Rect(100, 100);
179   widget.Init(init_params);
180   internal::RootView* root_view =
181       static_cast<internal::RootView*>(widget.GetRootView());
182
183   // Create a view capable of showing the context menu with two children one of
184   // which handles all gesture events (e.g. a button).
185   TestContextMenuController controller;
186   View* parent_view = new View;
187   parent_view->set_context_menu_controller(&controller);
188   widget.SetContentsView(parent_view);
189
190   View* gesture_handling_child_view = new GestureHandlingView;
191   gesture_handling_child_view->SetBoundsRect(gfx::Rect(10, 10));
192   parent_view->AddChildView(gesture_handling_child_view);
193
194   View* other_child_view = new View;
195   other_child_view->SetBoundsRect(gfx::Rect(20, 0, 10, 10));
196   parent_view->AddChildView(other_child_view);
197
198   // |parent_view| should not show a context menu as a result of a long press on
199   // |gesture_handling_child_view|.
200   ui::GestureEvent long_press1(
201       5,
202       5,
203       0,
204       base::TimeDelta(),
205       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
206   ui::EventDispatchDetails details = root_view->OnEventFromSource(&long_press1);
207
208   ui::GestureEvent end1(
209       5, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
210   details = root_view->OnEventFromSource(&end1);
211
212   EXPECT_FALSE(details.target_destroyed);
213   EXPECT_FALSE(details.dispatcher_destroyed);
214   EXPECT_EQ(0, controller.show_context_menu_calls());
215   controller.Reset();
216
217   // |parent_view| should show a context menu as a result of a long press on
218   // |other_child_view|.
219   ui::GestureEvent long_press2(
220       25,
221       5,
222       0,
223       base::TimeDelta(),
224       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
225   details = root_view->OnEventFromSource(&long_press2);
226
227   ui::GestureEvent end2(
228       25, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
229   details = root_view->OnEventFromSource(&end2);
230
231   EXPECT_FALSE(details.target_destroyed);
232   EXPECT_FALSE(details.dispatcher_destroyed);
233   EXPECT_EQ(1, controller.show_context_menu_calls());
234   controller.Reset();
235
236   // |parent_view| should show a context menu as a result of a long press on
237   // itself.
238   ui::GestureEvent long_press3(
239       50,
240       50,
241       0,
242       base::TimeDelta(),
243       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
244   details = root_view->OnEventFromSource(&long_press3);
245
246   ui::GestureEvent end3(
247       25, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
248   details = root_view->OnEventFromSource(&end3);
249
250   EXPECT_FALSE(details.target_destroyed);
251   EXPECT_FALSE(details.dispatcher_destroyed);
252   EXPECT_EQ(1, controller.show_context_menu_calls());
253 }
254
255 // Tests that context menus are not shown for disabled views on a long press.
256 TEST_F(RootViewTest, ContextMenuFromLongPressOnDisabledView) {
257   Widget widget;
258   Widget::InitParams init_params =
259       CreateParams(Widget::InitParams::TYPE_POPUP);
260   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
261   init_params.bounds = gfx::Rect(100, 100);
262   widget.Init(init_params);
263   internal::RootView* root_view =
264       static_cast<internal::RootView*>(widget.GetRootView());
265
266   // Create a view capable of showing the context menu with two children one of
267   // which handles all gesture events (e.g. a button). Also mark this view
268   // as disabled.
269   TestContextMenuController controller;
270   View* parent_view = new View;
271   parent_view->set_context_menu_controller(&controller);
272   parent_view->SetEnabled(false);
273   widget.SetContentsView(parent_view);
274
275   View* gesture_handling_child_view = new GestureHandlingView;
276   gesture_handling_child_view->SetBoundsRect(gfx::Rect(10, 10));
277   parent_view->AddChildView(gesture_handling_child_view);
278
279   View* other_child_view = new View;
280   other_child_view->SetBoundsRect(gfx::Rect(20, 0, 10, 10));
281   parent_view->AddChildView(other_child_view);
282
283   // |parent_view| should not show a context menu as a result of a long press on
284   // |gesture_handling_child_view|.
285   ui::GestureEvent long_press1(
286       5,
287       5,
288       0,
289       base::TimeDelta(),
290       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
291   ui::EventDispatchDetails details = root_view->OnEventFromSource(&long_press1);
292
293   ui::GestureEvent end1(
294       5, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
295   details = root_view->OnEventFromSource(&end1);
296
297   EXPECT_FALSE(details.target_destroyed);
298   EXPECT_FALSE(details.dispatcher_destroyed);
299   EXPECT_EQ(0, controller.show_context_menu_calls());
300   controller.Reset();
301
302   // |parent_view| should not show a context menu as a result of a long press on
303   // |other_child_view|.
304   ui::GestureEvent long_press2(
305       25,
306       5,
307       0,
308       base::TimeDelta(),
309       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
310   details = root_view->OnEventFromSource(&long_press2);
311
312   ui::GestureEvent end2(
313       25, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
314   details = root_view->OnEventFromSource(&end2);
315
316   EXPECT_FALSE(details.target_destroyed);
317   EXPECT_FALSE(details.dispatcher_destroyed);
318   EXPECT_EQ(0, controller.show_context_menu_calls());
319   controller.Reset();
320
321   // |parent_view| should not show a context menu as a result of a long press on
322   // itself.
323   ui::GestureEvent long_press3(
324       50,
325       50,
326       0,
327       base::TimeDelta(),
328       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
329   details = root_view->OnEventFromSource(&long_press3);
330
331   ui::GestureEvent end3(
332       25, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
333   details = root_view->OnEventFromSource(&end3);
334
335   EXPECT_FALSE(details.target_destroyed);
336   EXPECT_FALSE(details.dispatcher_destroyed);
337   EXPECT_EQ(0, controller.show_context_menu_calls());
338 }
339
340 }  // namespace test
341 }  // namespace views