Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / views / controls / native / native_view_host_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/controls/native/native_view_host.h"
6
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "ui/aura/window.h"
10 #include "ui/views/controls/native/native_view_host_test_base.h"
11 #include "ui/views/test/views_test_base.h"
12 #include "ui/views/widget/widget.h"
13
14 namespace views {
15
16 class NativeViewHostTest : public test::NativeViewHostTestBase {
17  public:
18   NativeViewHostTest() {
19   }
20
21   virtual void SetUp() OVERRIDE {
22     ViewsTestBase::SetUp();
23     CreateTopLevel();
24   }
25
26  private:
27   DISALLOW_COPY_AND_ASSIGN(NativeViewHostTest);
28 };
29
30 namespace {
31
32 // View implementation used by NativeViewHierarchyChanged to count number of
33 // times NativeViewHierarchyChanged() is invoked.
34 class NativeViewHierarchyChangedTestView : public View {
35  public:
36   NativeViewHierarchyChangedTestView() : notification_count_(0) {
37   }
38
39   void ResetCount() {
40     notification_count_ = 0;
41   }
42
43   int notification_count() const { return notification_count_; }
44
45   // Overriden from View:
46   virtual void NativeViewHierarchyChanged() OVERRIDE {
47     ++notification_count_;
48     View::NativeViewHierarchyChanged();
49   }
50
51  private:
52   int notification_count_;
53
54   DISALLOW_COPY_AND_ASSIGN(NativeViewHierarchyChangedTestView);
55 };
56
57 aura::Window* GetNativeParent(aura::Window* window) {
58   return window->parent();
59 }
60
61 class ViewHierarchyChangedTestHost : public NativeViewHost {
62  public:
63   ViewHierarchyChangedTestHost()
64       : num_parent_changes_(0) {
65   }
66
67   void ResetParentChanges() {
68     num_parent_changes_ = 0;
69   }
70
71   int num_parent_changes() const {
72     return num_parent_changes_;
73   }
74
75   // Overriden from NativeViewHost:
76   virtual void ViewHierarchyChanged(
77       const ViewHierarchyChangedDetails& details) OVERRIDE {
78     gfx::NativeView parent_before = native_view() ?
79         GetNativeParent(native_view()) : NULL;
80     NativeViewHost::ViewHierarchyChanged(details);
81     gfx::NativeView parent_after = native_view() ?
82         GetNativeParent(native_view()) : NULL;
83     if (parent_before != parent_after)
84       ++num_parent_changes_;
85   }
86
87  private:
88   int num_parent_changes_;
89
90   DISALLOW_COPY_AND_ASSIGN(ViewHierarchyChangedTestHost);
91 };
92
93 }  // namespace
94
95 // Verifies NativeViewHierarchyChanged is sent.
96 TEST_F(NativeViewHostTest, NativeViewHierarchyChanged) {
97   // Create a child widget.
98   NativeViewHierarchyChangedTestView* test_view =
99       new NativeViewHierarchyChangedTestView;
100   NativeViewHost* host = new NativeViewHost;
101   scoped_ptr<Widget> child(CreateChildForHost(toplevel()->GetNativeView(),
102                                               toplevel()->GetRootView(),
103                                               test_view,
104                                               host));
105 #if defined(USE_AURA)
106   // Two notifications are generated from inserting the native view into the
107   // clipping window and then inserting the clipping window into the root
108   // window.
109   EXPECT_EQ(2, test_view->notification_count());
110 #else
111   EXPECT_EQ(0, test_view->notification_count());
112 #endif
113   test_view->ResetCount();
114
115   // Detaching should send a NativeViewHierarchyChanged() notification and
116   // change the parent.
117   host->Detach();
118 #if defined(USE_AURA)
119   // Two notifications are generated from removing the native view from the
120   // clipping window and then reparenting it to the root window.
121   EXPECT_EQ(2, test_view->notification_count());
122 #else
123   EXPECT_EQ(1, test_view->notification_count());
124 #endif
125   EXPECT_NE(toplevel()->GetNativeView(),
126             GetNativeParent(child->GetNativeView()));
127   test_view->ResetCount();
128
129   // Attaching should send a NativeViewHierarchyChanged() notification and
130   // reset the parent.
131   host->Attach(child->GetNativeView());
132 #if defined(USE_AURA)
133   // There is a clipping window inserted above the native view that needs to be
134   // accounted for when looking at the relationship between the native views.
135   EXPECT_EQ(2, test_view->notification_count());
136   EXPECT_EQ(toplevel()->GetNativeView(),
137             GetNativeParent(GetNativeParent(child->GetNativeView())));
138 #else
139   EXPECT_EQ(1, test_view->notification_count());
140   EXPECT_EQ(toplevel()->GetNativeView(),
141             GetNativeParent(child->GetNativeView()));
142 #endif
143 }
144
145 // Verifies ViewHierarchyChanged handles NativeViewHost remove, add and move
146 // (reparent) operations with correct parent changes.
147 // This exercises the non-recursive code paths in
148 // View::PropagateRemoveNotifications() and View::PropagateAddNotifications().
149 TEST_F(NativeViewHostTest, ViewHierarchyChangedForHost) {
150   // Original tree:
151   // toplevel
152   // +-- host0 (NativeViewHost)
153   //     +-- child0 (Widget, attached to host0)
154   //     +-- test_host (ViewHierarchyChangedTestHost)
155   //         +-- test_child (Widget, attached to test_host)
156   // +-- host1 (NativeViewHost)
157   //     +-- child1 (Widget, attached to host1)
158
159   // Add two children widgets attached to a NativeViewHost, and a test
160   // grandchild as child widget of host0.
161   NativeViewHost* host0 = new NativeViewHost;
162   scoped_ptr<Widget> child0(CreateChildForHost(toplevel()->GetNativeView(),
163                                                toplevel()->GetRootView(),
164                                                new View,
165                                                host0));
166   NativeViewHost* host1 = new NativeViewHost;
167   scoped_ptr<Widget> child1(CreateChildForHost(toplevel()->GetNativeView(),
168                                                toplevel()->GetRootView(),
169                                                new View,
170                                                host1));
171   ViewHierarchyChangedTestHost* test_host = new ViewHierarchyChangedTestHost;
172   scoped_ptr<Widget> test_child(CreateChildForHost(host0->native_view(),
173                                                    host0,
174                                                    new View,
175                                                    test_host));
176
177   // Remove test_host from host0, expect 1 parent change.
178   test_host->ResetParentChanges();
179   EXPECT_EQ(0, test_host->num_parent_changes());
180   host0->RemoveChildView(test_host);
181   EXPECT_EQ(1, test_host->num_parent_changes());
182
183   // Add test_host back to host0, expect 1 parent change.
184   test_host->ResetParentChanges();
185   EXPECT_EQ(0, test_host->num_parent_changes());
186   host0->AddChildView(test_host);
187   EXPECT_EQ(1, test_host->num_parent_changes());
188
189   // Reparent test_host to host1, expect no parent change because the old and
190   // new parents, host0 and host1, belong to the same toplevel widget.
191   test_host->ResetParentChanges();
192   EXPECT_EQ(0, test_host->num_parent_changes());
193   host1->AddChildView(test_host);
194   EXPECT_EQ(0, test_host->num_parent_changes());
195
196   // Reparent test_host to contents view of child0, expect 2 parent changes
197   // because the old parent belongs to the toplevel widget whereas the new
198   // parent belongs to the child0.
199   test_host->ResetParentChanges();
200   EXPECT_EQ(0, test_host->num_parent_changes());
201   child0->GetContentsView()->AddChildView(test_host);
202   EXPECT_EQ(2, test_host->num_parent_changes());
203 }
204
205 // Verifies ViewHierarchyChanged handles NativeViewHost's parent remove, add and
206 // move (reparent) operations with correct parent changes.
207 // This exercises the recursive code paths in
208 // View::PropagateRemoveNotifications() and View::PropagateAddNotifications().
209 TEST_F(NativeViewHostTest, ViewHierarchyChangedForHostParent) {
210   // Original tree:
211   // toplevel
212   // +-- view0 (View)
213   //     +-- host0 (NativeViewHierarchyChangedTestHost)
214   //         +-- child0 (Widget, attached to host0)
215   // +-- view1 (View)
216   //     +-- host1 (NativeViewHierarchyChangedTestHost)
217   //         +-- child1 (Widget, attached to host1)
218
219   // Add two children views.
220   View* view0 = new View;
221   toplevel()->GetRootView()->AddChildView(view0);
222   View* view1 = new View;
223   toplevel()->GetRootView()->AddChildView(view1);
224
225   // To each child view, add a child widget.
226   ViewHierarchyChangedTestHost* host0 = new ViewHierarchyChangedTestHost;
227   scoped_ptr<Widget> child0(CreateChildForHost(toplevel()->GetNativeView(),
228                                                view0,
229                                                new View,
230                                                host0));
231   ViewHierarchyChangedTestHost* host1 = new ViewHierarchyChangedTestHost;
232   scoped_ptr<Widget> child1(CreateChildForHost(toplevel()->GetNativeView(),
233                                                view1,
234                                                new View,
235                                                host1));
236
237   // Remove view0 from top level, expect 1 parent change.
238   host0->ResetParentChanges();
239   EXPECT_EQ(0, host0->num_parent_changes());
240   toplevel()->GetRootView()->RemoveChildView(view0);
241   EXPECT_EQ(1, host0->num_parent_changes());
242
243   // Add view0 back to top level, expect 1 parent change.
244   host0->ResetParentChanges();
245   EXPECT_EQ(0, host0->num_parent_changes());
246   toplevel()->GetRootView()->AddChildView(view0);
247   EXPECT_EQ(1, host0->num_parent_changes());
248
249   // Reparent view0 to view1, expect no parent change because the old and new
250   // parents of both view0 and view1 belong to the same toplevel widget.
251   host0->ResetParentChanges();
252   host1->ResetParentChanges();
253   EXPECT_EQ(0, host0->num_parent_changes());
254   EXPECT_EQ(0, host1->num_parent_changes());
255   view1->AddChildView(view0);
256   EXPECT_EQ(0, host0->num_parent_changes());
257   EXPECT_EQ(0, host1->num_parent_changes());
258
259   // Restore original view hierarchy by adding back view0 to top level.
260   // Then, reparent view1 to contents view of child0.
261   // Expect 2 parent changes because the old parent belongs to the toplevel
262   // widget whereas the new parent belongs to the 1st child widget.
263   toplevel()->GetRootView()->AddChildView(view0);
264   host0->ResetParentChanges();
265   host1->ResetParentChanges();
266   EXPECT_EQ(0, host0->num_parent_changes());
267   EXPECT_EQ(0, host1->num_parent_changes());
268   child0->GetContentsView()->AddChildView(view1);
269   EXPECT_EQ(0, host0->num_parent_changes());
270   EXPECT_EQ(2, host1->num_parent_changes());
271 }
272
273 }  // namespace views