Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / views / controls / native / native_view_host_aura_unittest.cc
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 "ui/views/controls/native/native_view_host_aura.h"
6
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "ui/aura/client/aura_constants.h"
10 #include "ui/aura/window.h"
11 #include "ui/base/cursor/cursor.h"
12 #include "ui/views/controls/native/native_view_host.h"
13 #include "ui/views/controls/native/native_view_host_test_base.h"
14 #include "ui/views/view.h"
15 #include "ui/views/view_constants_aura.h"
16 #include "ui/views/widget/widget.h"
17
18 namespace views {
19
20 // Observer watching for window visibility and bounds change events. This is
21 // used to verify that the child and clipping window operations are done in the
22 // right order.
23 class NativeViewHostWindowObserver : public aura::WindowObserver {
24  public:
25   enum EventType {
26     EVENT_NONE,
27     EVENT_SHOWN,
28     EVENT_HIDDEN,
29     EVENT_BOUNDS_CHANGED,
30   };
31
32   struct EventDetails {
33     EventType type;
34     aura::Window* window;
35     gfx::Rect bounds;
36     bool operator!=(const EventDetails& rhs) {
37       return type != rhs.type || window != rhs.window || bounds != rhs.bounds;
38     }
39   };
40
41   NativeViewHostWindowObserver() {}
42   virtual ~NativeViewHostWindowObserver() {}
43
44   const std::vector<EventDetails>& events() const { return events_; }
45
46   // aura::WindowObserver overrides
47   virtual void OnWindowVisibilityChanged(aura::Window* window,
48                                          bool visible) OVERRIDE {
49     EventDetails event;
50     event.type = visible ? EVENT_SHOWN : EVENT_HIDDEN;
51     event.window = window;
52     event.bounds = window->GetBoundsInRootWindow();
53
54     // Dedupe events as a single Hide() call can result in several
55     // notifications.
56     if (events_.size() == 0u || events_.back() != event)
57       events_.push_back(event);
58   }
59
60   virtual void OnWindowBoundsChanged(aura::Window* window,
61                                      const gfx::Rect& old_bounds,
62                                      const gfx::Rect& new_bounds) OVERRIDE {
63     EventDetails event;
64     event.type = EVENT_BOUNDS_CHANGED;
65     event.window = window;
66     event.bounds = window->GetBoundsInRootWindow();
67     events_.push_back(event);
68   }
69
70  private:
71   std::vector<EventDetails> events_;
72   gfx::Rect bounds_at_visibility_changed_;
73
74   DISALLOW_COPY_AND_ASSIGN(NativeViewHostWindowObserver);
75 };
76
77 class NativeViewHostAuraTest : public test::NativeViewHostTestBase {
78  public:
79   NativeViewHostAuraTest() {
80   }
81
82   NativeViewHostAura* native_host() {
83     return static_cast<NativeViewHostAura*>(GetNativeWrapper());
84   }
85
86   Widget* child() {
87     return child_.get();
88   }
89
90   aura::Window* clipping_window() { return &(native_host()->clipping_window_); }
91
92   void CreateHost() {
93     CreateTopLevel();
94     CreateTestingHost();
95     child_.reset(CreateChildForHost(toplevel()->GetNativeView(),
96                                     toplevel()->GetRootView(),
97                                     new View,
98                                     host()));
99   }
100
101  private:
102   scoped_ptr<Widget> child_;
103
104   DISALLOW_COPY_AND_ASSIGN(NativeViewHostAuraTest);
105 };
106
107 // Verifies NativeViewHostAura stops observing native view on destruction.
108 TEST_F(NativeViewHostAuraTest, StopObservingNativeViewOnDestruct) {
109   CreateHost();
110   aura::Window* child_win = child()->GetNativeView();
111   NativeViewHostAura* aura_host = native_host();
112
113   EXPECT_TRUE(child_win->HasObserver(aura_host));
114   DestroyHost();
115   EXPECT_FALSE(child_win->HasObserver(aura_host));
116 }
117
118 // Tests that the kHostViewKey is correctly set and cleared.
119 TEST_F(NativeViewHostAuraTest, HostViewPropertyKey) {
120   // Create the NativeViewHost and attach a NativeView.
121   CreateHost();
122   aura::Window* child_win = child()->GetNativeView();
123   EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey));
124   EXPECT_EQ(host()->GetWidget()->GetNativeView(),
125             child_win->GetProperty(aura::client::kHostWindowKey));
126   EXPECT_EQ(host(), clipping_window()->GetProperty(views::kHostViewKey));
127
128   host()->Detach();
129   EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
130   EXPECT_FALSE(child_win->GetProperty(aura::client::kHostWindowKey));
131   EXPECT_TRUE(clipping_window()->GetProperty(views::kHostViewKey));
132
133   host()->Attach(child_win);
134   EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey));
135   EXPECT_EQ(host()->GetWidget()->GetNativeView(),
136             child_win->GetProperty(aura::client::kHostWindowKey));
137   EXPECT_EQ(host(), clipping_window()->GetProperty(views::kHostViewKey));
138
139   DestroyHost();
140   EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
141   EXPECT_FALSE(child_win->GetProperty(aura::client::kHostWindowKey));
142 }
143
144 // Tests that the NativeViewHost reports the cursor set on its native view.
145 TEST_F(NativeViewHostAuraTest, CursorForNativeView) {
146   CreateHost();
147
148   toplevel()->SetCursor(ui::kCursorHand);
149   child()->SetCursor(ui::kCursorWait);
150   ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
151                             gfx::Point(0, 0), 0, 0);
152
153   EXPECT_EQ(ui::kCursorWait, host()->GetCursor(move_event).native_type());
154
155   DestroyHost();
156 }
157
158 // Test that destroying the top level widget before destroying the attached
159 // NativeViewHost works correctly. Specifically the associated NVH should be
160 // destroyed and there shouldn't be any errors.
161 TEST_F(NativeViewHostAuraTest, DestroyWidget) {
162   ResetHostDestroyedCount();
163   CreateHost();
164   ReleaseHost();
165   EXPECT_EQ(0, host_destroyed_count());
166   DestroyTopLevel();
167   EXPECT_EQ(1, host_destroyed_count());
168 }
169
170 // Test that the fast resize path places the clipping and content windows were
171 // they are supposed to be.
172 TEST_F(NativeViewHostAuraTest, FastResizePath) {
173   CreateHost();
174   toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
175
176   // Without fast resize, the clipping window should size to the native view
177   // with the native view positioned at the origin of the clipping window and
178   // the clipping window positioned where the native view was requested.
179   host()->set_fast_resize(false);
180   native_host()->ShowWidget(5, 10, 100, 100);
181   EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
182             host()->native_view()->bounds().ToString());
183   EXPECT_EQ(gfx::Rect(5, 10, 100, 100).ToString(),
184             clipping_window()->bounds().ToString());
185
186   // With fast resize, the native view should remain the same size but be
187   // clipped the requested size.
188   host()->set_fast_resize(true);
189   native_host()->ShowWidget(10, 25, 50, 50);
190   EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
191             host()->native_view()->bounds().ToString());
192   EXPECT_EQ(gfx::Rect(10, 25, 50, 50).ToString(),
193             clipping_window()->bounds().ToString());
194
195   // Turning off fast resize should make the native view start resizing again.
196   host()->set_fast_resize(false);
197   native_host()->ShowWidget(10, 25, 50, 50);
198   EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
199             host()->native_view()->bounds().ToString());
200   EXPECT_EQ(gfx::Rect(10, 25, 50, 50).ToString(),
201             clipping_window()->bounds().ToString());
202
203   DestroyHost();
204 }
205
206 // Test installing and uninstalling a clip.
207 TEST_F(NativeViewHostAuraTest, InstallClip) {
208   CreateHost();
209   toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
210
211   // Without a clip, the clipping window should always be positioned at the
212   // requested coordinates with the native view positioned at the origin of the
213   // clipping window.
214   native_host()->ShowWidget(10, 20, 100, 100);
215   EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
216             host()->native_view()->bounds().ToString());
217   EXPECT_EQ(gfx::Rect(10, 20, 100, 100).ToString(),
218             clipping_window()->bounds().ToString());
219
220   // Clip to the bottom right quarter of the native view.
221   native_host()->InstallClip(60, 70, 50, 50);
222   native_host()->ShowWidget(10, 20, 100, 100);
223   EXPECT_EQ(gfx::Rect(-50, -50, 100, 100).ToString(),
224             host()->native_view()->bounds().ToString());
225   EXPECT_EQ(gfx::Rect(60, 70, 50, 50).ToString(),
226             clipping_window()->bounds().ToString());
227
228   // Clip to the center of the native view.
229   native_host()->InstallClip(35, 45, 50, 50);
230   native_host()->ShowWidget(10, 20, 100, 100);
231   EXPECT_EQ(gfx::Rect(-25, -25, 100, 100).ToString(),
232             host()->native_view()->bounds().ToString());
233   EXPECT_EQ(gfx::Rect(35, 45, 50, 50).ToString(),
234             clipping_window()->bounds().ToString());
235
236   // Uninstalling the clip should make the clipping window match the native view
237   // again.
238   native_host()->UninstallClip();
239   native_host()->ShowWidget(10, 20, 100, 100);
240   EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
241             host()->native_view()->bounds().ToString());
242   EXPECT_EQ(gfx::Rect(10, 20, 100, 100).ToString(),
243             clipping_window()->bounds().ToString());
244
245   DestroyHost();
246 }
247
248 // Ensure native view is parented to the root window after detaching. This is
249 // a regression test for http://crbug.com/389261.
250 TEST_F(NativeViewHostAuraTest, ParentAfterDetach) {
251   CreateHost();
252   aura::Window* child_win = child()->GetNativeView();
253   aura::Window* root_window = child_win->GetRootWindow();
254   aura::WindowTreeHost* child_win_tree_host = child_win->GetHost();
255
256   host()->Detach();
257   EXPECT_EQ(root_window, child_win->GetRootWindow());
258   EXPECT_EQ(child_win_tree_host, child_win->GetHost());
259
260   DestroyHost();
261 }
262
263 // Ensure the clipping window is hidden before setting the native view's bounds.
264 // This is a regression test for http://crbug.com/388699.
265 TEST_F(NativeViewHostAuraTest, RemoveClippingWindowOrder) {
266   CreateHost();
267   toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
268   native_host()->ShowWidget(10, 20, 100, 100);
269
270   NativeViewHostWindowObserver test_observer;
271   clipping_window()->AddObserver(&test_observer);
272   child()->GetNativeView()->AddObserver(&test_observer);
273
274   host()->Detach();
275
276   ASSERT_EQ(3u, test_observer.events().size());
277   EXPECT_EQ(NativeViewHostWindowObserver::EVENT_HIDDEN,
278             test_observer.events()[0].type);
279   EXPECT_EQ(clipping_window(), test_observer.events()[0].window);
280   EXPECT_EQ(NativeViewHostWindowObserver::EVENT_BOUNDS_CHANGED,
281             test_observer.events()[1].type);
282   EXPECT_EQ(child()->GetNativeView(), test_observer.events()[1].window);
283   EXPECT_EQ(NativeViewHostWindowObserver::EVENT_HIDDEN,
284             test_observer.events()[2].type);
285   EXPECT_EQ(child()->GetNativeView(), test_observer.events()[2].window);
286
287   clipping_window()->RemoveObserver(&test_observer);
288   child()->GetNativeView()->RemoveObserver(&test_observer);
289
290   DestroyHost();
291 }
292
293 // Ensure the native view receives the correct bounds notification when it is
294 // attached. This is a regression test for https://crbug.com/399420.
295 TEST_F(NativeViewHostAuraTest, Attach) {
296   CreateHost();
297   host()->Detach();
298
299   child()->GetNativeView()->SetBounds(gfx::Rect(0, 0, 0, 0));
300   toplevel()->SetBounds(gfx::Rect(0, 0, 100, 100));
301   host()->SetBounds(10, 10, 80, 80);
302
303   NativeViewHostWindowObserver test_observer;
304   child()->GetNativeView()->AddObserver(&test_observer);
305
306   host()->Attach(child()->GetNativeView());
307
308   ASSERT_EQ(3u, test_observer.events().size());
309   EXPECT_EQ(NativeViewHostWindowObserver::EVENT_BOUNDS_CHANGED,
310             test_observer.events()[0].type);
311   EXPECT_EQ(child()->GetNativeView(), test_observer.events()[0].window);
312   EXPECT_EQ(gfx::Rect(10, 10, 80, 80).ToString(),
313             test_observer.events()[0].bounds.ToString());
314   EXPECT_EQ(NativeViewHostWindowObserver::EVENT_SHOWN,
315             test_observer.events()[1].type);
316   EXPECT_EQ(child()->GetNativeView(), test_observer.events()[1].window);
317   EXPECT_EQ(gfx::Rect(10, 10, 80, 80).ToString(),
318             test_observer.events()[1].bounds.ToString());
319   EXPECT_EQ(NativeViewHostWindowObserver::EVENT_SHOWN,
320             test_observer.events()[2].type);
321   EXPECT_EQ(clipping_window(), test_observer.events()[2].window);
322   EXPECT_EQ(gfx::Rect(10, 10, 80, 80).ToString(),
323             test_observer.events()[2].bounds.ToString());
324
325   child()->GetNativeView()->RemoveObserver(&test_observer);
326   DestroyHost();
327 }
328
329 // Ensure the clipping window is hidden with the native view. This is a
330 // regression test for https://crbug.com/408877.
331 TEST_F(NativeViewHostAuraTest, SimpleShowAndHide) {
332   CreateHost();
333
334   toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
335   toplevel()->Show();
336
337   host()->SetBounds(10, 10, 80, 80);
338   EXPECT_TRUE(clipping_window()->IsVisible());
339   EXPECT_TRUE(child()->IsVisible());
340
341   host()->SetVisible(false);
342   EXPECT_FALSE(clipping_window()->IsVisible());
343   EXPECT_FALSE(child()->IsVisible());
344
345   DestroyHost();
346   DestroyTopLevel();
347 }
348
349 }  // namespace views