Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / views / controls / native / native_view_host_aura_unittest.cc
blob54212cdc99d5d783dfec4a4e3dd5a2339fba600b
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.
5 #include "ui/views/controls/native/native_view_host_aura.h"
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/test/views_test_base.h"
14 #include "ui/views/view.h"
15 #include "ui/views/view_constants_aura.h"
16 #include "ui/views/widget/widget.h"
18 namespace views {
20 // Testing wrapper of the NativeViewHost
21 class NativeViewHostTesting : public NativeViewHost {
22 public:
23 NativeViewHostTesting() {}
24 virtual ~NativeViewHostTesting() { destroyed_count_++; }
26 static void ResetDestroyedCount() { destroyed_count_ = 0; }
28 static int destroyed_count() { return destroyed_count_; }
30 private:
31 static int destroyed_count_;
33 DISALLOW_COPY_AND_ASSIGN(NativeViewHostTesting);
35 int NativeViewHostTesting::destroyed_count_ = 0;
37 // Observer watching for window visibility and bounds change events. This is
38 // used to verify that the child and clipping window operations are done in the
39 // right order.
40 class NativeViewHostWindowObserver : public aura::WindowObserver {
41 public:
42 enum EventType {
43 EVENT_NONE,
44 EVENT_SHOWN,
45 EVENT_HIDDEN,
46 EVENT_BOUNDS_CHANGED,
49 struct EventDetails {
50 EventType type;
51 aura::Window* window;
52 gfx::Rect bounds;
53 bool operator!=(const EventDetails& rhs) {
54 return type != rhs.type || window != rhs.window || bounds != rhs.bounds;
58 NativeViewHostWindowObserver() {}
59 virtual ~NativeViewHostWindowObserver() {}
61 const std::vector<EventDetails>& events() const { return events_; }
63 // aura::WindowObserver overrides
64 virtual void OnWindowVisibilityChanged(aura::Window* window,
65 bool visible) OVERRIDE {
66 EventDetails event;
67 event.type = visible ? EVENT_SHOWN : EVENT_HIDDEN;
68 event.window = window;
69 event.bounds = window->GetBoundsInRootWindow();
71 // Dedupe events as a single Hide() call can result in several
72 // notifications.
73 if (events_.size() == 0u || events_.back() != event)
74 events_.push_back(event);
77 virtual void OnWindowBoundsChanged(aura::Window* window,
78 const gfx::Rect& old_bounds,
79 const gfx::Rect& new_bounds) OVERRIDE {
80 EventDetails event;
81 event.type = EVENT_BOUNDS_CHANGED;
82 event.window = window;
83 event.bounds = window->GetBoundsInRootWindow();
84 events_.push_back(event);
87 private:
88 std::vector<EventDetails> events_;
89 gfx::Rect bounds_at_visibility_changed_;
91 DISALLOW_COPY_AND_ASSIGN(NativeViewHostWindowObserver);
94 class NativeViewHostAuraTest : public ViewsTestBase {
95 public:
96 NativeViewHostAuraTest() {
99 NativeViewHostAura* native_host() {
100 return static_cast<NativeViewHostAura*>(host_->native_wrapper_.get());
103 Widget* toplevel() {
104 return toplevel_.get();
107 NativeViewHost* host() {
108 return host_.get();
111 Widget* child() {
112 return child_.get();
115 aura::Window* clipping_window() { return &(native_host()->clipping_window_); }
117 void CreateHost() {
118 // Create the top level widget.
119 toplevel_.reset(new Widget);
120 Widget::InitParams toplevel_params =
121 CreateParams(Widget::InitParams::TYPE_WINDOW);
122 toplevel_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
123 toplevel_->Init(toplevel_params);
125 // And the child widget.
126 child_.reset(new Widget);
127 Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
128 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
129 child_params.parent = toplevel_->GetNativeView();
130 child_->Init(child_params);
131 child_->SetContentsView(new View);
133 // Owned by |toplevel|.
134 host_.reset(new NativeViewHostTesting);
135 toplevel_->GetRootView()->AddChildView(host_.get());
136 host_->Attach(child_->GetNativeView());
139 void DestroyHost() {
140 host_.reset();
143 NativeViewHostTesting* ReleaseHost() { return host_.release(); }
145 void DestroyTopLevel() { toplevel_.reset(); }
147 private:
148 scoped_ptr<Widget> toplevel_;
149 scoped_ptr<NativeViewHostTesting> host_;
150 scoped_ptr<Widget> child_;
152 DISALLOW_COPY_AND_ASSIGN(NativeViewHostAuraTest);
155 // Verifies NativeViewHostAura stops observing native view on destruction.
156 TEST_F(NativeViewHostAuraTest, StopObservingNativeViewOnDestruct) {
157 CreateHost();
158 aura::Window* child_win = child()->GetNativeView();
159 NativeViewHostAura* aura_host = native_host();
161 EXPECT_TRUE(child_win->HasObserver(aura_host));
162 DestroyHost();
163 EXPECT_FALSE(child_win->HasObserver(aura_host));
166 // Tests that the kHostViewKey is correctly set and cleared.
167 TEST_F(NativeViewHostAuraTest, HostViewPropertyKey) {
168 // Create the NativeViewHost and attach a NativeView.
169 CreateHost();
170 aura::Window* child_win = child()->GetNativeView();
171 EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey));
172 EXPECT_EQ(host()->GetWidget()->GetNativeView(),
173 child_win->GetProperty(aura::client::kHostWindowKey));
174 EXPECT_EQ(host(), clipping_window()->GetProperty(views::kHostViewKey));
176 host()->Detach();
177 EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
178 EXPECT_FALSE(child_win->GetProperty(aura::client::kHostWindowKey));
179 EXPECT_TRUE(clipping_window()->GetProperty(views::kHostViewKey));
181 host()->Attach(child_win);
182 EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey));
183 EXPECT_EQ(host()->GetWidget()->GetNativeView(),
184 child_win->GetProperty(aura::client::kHostWindowKey));
185 EXPECT_EQ(host(), clipping_window()->GetProperty(views::kHostViewKey));
187 DestroyHost();
188 EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
189 EXPECT_FALSE(child_win->GetProperty(aura::client::kHostWindowKey));
192 // Tests that the NativeViewHost reports the cursor set on its native view.
193 TEST_F(NativeViewHostAuraTest, CursorForNativeView) {
194 CreateHost();
196 toplevel()->SetCursor(ui::kCursorHand);
197 child()->SetCursor(ui::kCursorWait);
198 ui::MouseEvent move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
199 gfx::Point(0, 0), 0, 0);
201 EXPECT_EQ(ui::kCursorWait, host()->GetCursor(move_event).native_type());
203 DestroyHost();
206 // Test that destroying the top level widget before destroying the attached
207 // NativeViewHost works correctly. Specifically the associated NVH should be
208 // destroyed and there shouldn't be any errors.
209 TEST_F(NativeViewHostAuraTest, DestroyWidget) {
210 NativeViewHostTesting::ResetDestroyedCount();
211 CreateHost();
212 ReleaseHost();
213 EXPECT_EQ(0, NativeViewHostTesting::destroyed_count());
214 DestroyTopLevel();
215 EXPECT_EQ(1, NativeViewHostTesting::destroyed_count());
218 // Test that the fast resize path places the clipping and content windows were
219 // they are supposed to be.
220 TEST_F(NativeViewHostAuraTest, FastResizePath) {
221 CreateHost();
222 toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
224 // Without fast resize, the clipping window should size to the native view
225 // with the native view positioned at the origin of the clipping window and
226 // the clipping window positioned where the native view was requested.
227 host()->set_fast_resize(false);
228 native_host()->ShowWidget(5, 10, 100, 100);
229 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
230 host()->native_view()->bounds().ToString());
231 EXPECT_EQ(gfx::Rect(5, 10, 100, 100).ToString(),
232 clipping_window()->bounds().ToString());
234 // With fast resize, the native view should remain the same size but be
235 // clipped the requested size.
236 host()->set_fast_resize(true);
237 native_host()->ShowWidget(10, 25, 50, 50);
238 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
239 host()->native_view()->bounds().ToString());
240 EXPECT_EQ(gfx::Rect(10, 25, 50, 50).ToString(),
241 clipping_window()->bounds().ToString());
243 // Turning off fast resize should make the native view start resizing again.
244 host()->set_fast_resize(false);
245 native_host()->ShowWidget(10, 25, 50, 50);
246 EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
247 host()->native_view()->bounds().ToString());
248 EXPECT_EQ(gfx::Rect(10, 25, 50, 50).ToString(),
249 clipping_window()->bounds().ToString());
251 DestroyHost();
254 // Test installing and uninstalling a clip.
255 TEST_F(NativeViewHostAuraTest, InstallClip) {
256 CreateHost();
257 toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
259 // Without a clip, the clipping window should always be positioned at the
260 // requested coordinates with the native view positioned at the origin of the
261 // clipping window.
262 native_host()->ShowWidget(10, 20, 100, 100);
263 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
264 host()->native_view()->bounds().ToString());
265 EXPECT_EQ(gfx::Rect(10, 20, 100, 100).ToString(),
266 clipping_window()->bounds().ToString());
268 // Clip to the bottom right quarter of the native view.
269 native_host()->InstallClip(60, 70, 50, 50);
270 native_host()->ShowWidget(10, 20, 100, 100);
271 EXPECT_EQ(gfx::Rect(-50, -50, 100, 100).ToString(),
272 host()->native_view()->bounds().ToString());
273 EXPECT_EQ(gfx::Rect(60, 70, 50, 50).ToString(),
274 clipping_window()->bounds().ToString());
276 // Clip to the center of the native view.
277 native_host()->InstallClip(35, 45, 50, 50);
278 native_host()->ShowWidget(10, 20, 100, 100);
279 EXPECT_EQ(gfx::Rect(-25, -25, 100, 100).ToString(),
280 host()->native_view()->bounds().ToString());
281 EXPECT_EQ(gfx::Rect(35, 45, 50, 50).ToString(),
282 clipping_window()->bounds().ToString());
284 // Uninstalling the clip should make the clipping window match the native view
285 // again.
286 native_host()->UninstallClip();
287 native_host()->ShowWidget(10, 20, 100, 100);
288 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
289 host()->native_view()->bounds().ToString());
290 EXPECT_EQ(gfx::Rect(10, 20, 100, 100).ToString(),
291 clipping_window()->bounds().ToString());
293 DestroyHost();
296 // Ensure native view is parented to the root window after detaching. This is
297 // a regression test for http://crbug.com/389261.
298 TEST_F(NativeViewHostAuraTest, ParentAfterDetach) {
299 CreateHost();
300 aura::Window* child_win = child()->GetNativeView();
301 aura::Window* root_window = child_win->GetRootWindow();
302 aura::WindowTreeHost* child_win_tree_host = child_win->GetHost();
304 host()->Detach();
305 EXPECT_EQ(root_window, child_win->GetRootWindow());
306 EXPECT_EQ(child_win_tree_host, child_win->GetHost());
308 DestroyHost();
311 // Ensure the clipping window is hidden before setting the native view's bounds.
312 // This is a regression test for http://crbug.com/388699.
313 TEST_F(NativeViewHostAuraTest, RemoveClippingWindowOrder) {
314 CreateHost();
315 toplevel()->SetBounds(gfx::Rect(20, 20, 100, 100));
316 native_host()->ShowWidget(10, 20, 100, 100);
318 NativeViewHostWindowObserver test_observer;
319 clipping_window()->AddObserver(&test_observer);
320 child()->GetNativeView()->AddObserver(&test_observer);
322 host()->Detach();
324 ASSERT_EQ(3u, test_observer.events().size());
325 EXPECT_EQ(NativeViewHostWindowObserver::EVENT_HIDDEN,
326 test_observer.events()[0].type);
327 EXPECT_EQ(clipping_window(), test_observer.events()[0].window);
328 EXPECT_EQ(NativeViewHostWindowObserver::EVENT_BOUNDS_CHANGED,
329 test_observer.events()[1].type);
330 EXPECT_EQ(child()->GetNativeView(), test_observer.events()[1].window);
331 EXPECT_EQ(NativeViewHostWindowObserver::EVENT_HIDDEN,
332 test_observer.events()[2].type);
333 EXPECT_EQ(child()->GetNativeView(), test_observer.events()[2].window);
335 clipping_window()->RemoveObserver(&test_observer);
336 child()->GetNativeView()->RemoveObserver(&test_observer);
338 DestroyHost();
341 // Ensure the native view receives the correct bounds notification when it is
342 // attached. This is a regression test for https://crbug.com/399420.
343 TEST_F(NativeViewHostAuraTest, Attach) {
344 CreateHost();
345 host()->Detach();
347 child()->GetNativeView()->SetBounds(gfx::Rect(0, 0, 0, 0));
348 toplevel()->SetBounds(gfx::Rect(0, 0, 100, 100));
349 host()->SetBounds(10, 10, 80, 80);
351 NativeViewHostWindowObserver test_observer;
352 child()->GetNativeView()->AddObserver(&test_observer);
354 host()->Attach(child()->GetNativeView());
356 ASSERT_EQ(3u, test_observer.events().size());
357 EXPECT_EQ(NativeViewHostWindowObserver::EVENT_BOUNDS_CHANGED,
358 test_observer.events()[0].type);
359 EXPECT_EQ(child()->GetNativeView(), test_observer.events()[0].window);
360 EXPECT_EQ(gfx::Rect(10, 10, 80, 80).ToString(),
361 test_observer.events()[0].bounds.ToString());
362 EXPECT_EQ(NativeViewHostWindowObserver::EVENT_SHOWN,
363 test_observer.events()[1].type);
364 EXPECT_EQ(child()->GetNativeView(), test_observer.events()[1].window);
365 EXPECT_EQ(gfx::Rect(10, 10, 80, 80).ToString(),
366 test_observer.events()[1].bounds.ToString());
367 EXPECT_EQ(NativeViewHostWindowObserver::EVENT_SHOWN,
368 test_observer.events()[2].type);
369 EXPECT_EQ(clipping_window(), test_observer.events()[2].window);
370 EXPECT_EQ(gfx::Rect(10, 10, 80, 80).ToString(),
371 test_observer.events()[2].bounds.ToString());
373 child()->GetNativeView()->RemoveObserver(&test_observer);
374 DestroyHost();
377 } // namespace views