OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/views/controls/native/native_view_host_aura.h" | 5 #include "ui/views/controls/native/native_view_host_aura.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
9 #include "ui/aura/window.h" | 9 #include "ui/aura/window.h" |
10 #include "ui/views/controls/native/native_view_host.h" | 10 #include "ui/views/controls/native/native_view_host.h" |
11 #include "ui/views/test/views_test_base.h" | 11 #include "ui/views/test/views_test_base.h" |
12 #include "ui/views/view.h" | 12 #include "ui/views/view.h" |
13 #include "ui/views/view_constants_aura.h" | 13 #include "ui/views/view_constants_aura.h" |
14 #include "ui/views/widget/widget.h" | 14 #include "ui/views/widget/widget.h" |
15 | 15 |
16 namespace views { | 16 namespace views { |
17 | 17 |
| 18 // Testing wrapper of the NativeViewHost |
| 19 class NativeViewHostTesting : public NativeViewHost { |
| 20 public: |
| 21 NativeViewHostTesting() {} |
| 22 virtual ~NativeViewHostTesting() { |
| 23 destroyed_count_++; |
| 24 } |
| 25 |
| 26 static void ResetDestroyedCount() { |
| 27 destroyed_count_ = 0; |
| 28 } |
| 29 |
| 30 static int destroyed_count() { |
| 31 return destroyed_count_; |
| 32 } |
| 33 |
| 34 private: |
| 35 static int destroyed_count_; |
| 36 |
| 37 DISALLOW_COPY_AND_ASSIGN(NativeViewHostTesting); |
| 38 }; |
| 39 int NativeViewHostTesting::destroyed_count_ = 0; |
| 40 |
| 41 // Observer watching for how many times an aura::Window has been destroyed. This |
| 42 // is used to confirm that an object has been cleaned up when expected. |
| 43 class AuraWindowDestroyedObserver : public aura::WindowObserver { |
| 44 public: |
| 45 AuraWindowDestroyedObserver(aura::Window *window) : |
| 46 destroyed_count_(0) { |
| 47 window->AddObserver(this); |
| 48 } |
| 49 |
| 50 virtual ~AuraWindowDestroyedObserver() {} |
| 51 |
| 52 int destroyed_count() { return destroyed_count_; } |
| 53 |
| 54 // aura::WindowObserver overrides |
| 55 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { |
| 56 destroyed_count_++; |
| 57 } |
| 58 |
| 59 private: |
| 60 int destroyed_count_; |
| 61 |
| 62 DISALLOW_COPY_AND_ASSIGN(AuraWindowDestroyedObserver); |
| 63 }; |
| 64 |
18 class NativeViewHostAuraTest : public ViewsTestBase { | 65 class NativeViewHostAuraTest : public ViewsTestBase { |
19 public: | 66 public: |
20 NativeViewHostAuraTest() { | 67 NativeViewHostAuraTest() { |
21 } | 68 } |
22 | 69 |
23 NativeViewHostAura* native_host() { | 70 NativeViewHostAura* native_host() { |
24 return static_cast<NativeViewHostAura*>(host_->native_wrapper_.get()); | 71 return static_cast<NativeViewHostAura*>(host_->native_wrapper_.get()); |
25 } | 72 } |
26 | 73 |
27 NativeViewHost* host() { | 74 NativeViewHost* host() { |
28 return host_.get(); | 75 return host_.get(); |
29 } | 76 } |
30 | 77 |
31 Widget* child() { | 78 Widget* child() { |
32 return child_.get(); | 79 return child_.get(); |
33 } | 80 } |
34 | 81 |
| 82 aura::Window* clipping_window() { |
| 83 return native_host()->clipping_window_; |
| 84 } |
| 85 |
| 86 Widget* toplevel() { |
| 87 return toplevel_.get(); |
| 88 } |
| 89 |
35 void CreateHost() { | 90 void CreateHost() { |
36 // Create the top level widget. | 91 // Create the top level widget. |
37 toplevel_.reset(new Widget); | 92 toplevel_.reset(new Widget); |
38 Widget::InitParams toplevel_params = | 93 Widget::InitParams toplevel_params = |
39 CreateParams(Widget::InitParams::TYPE_WINDOW); | 94 CreateParams(Widget::InitParams::TYPE_WINDOW); |
40 toplevel_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 95 toplevel_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
41 toplevel_->Init(toplevel_params); | 96 toplevel_->Init(toplevel_params); |
42 | 97 |
43 // And the child widget. | 98 // And the child widget. |
44 View* test_view = new View; | 99 View* test_view = new View; |
45 child_.reset(new Widget); | 100 child_.reset(new Widget); |
46 Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL); | 101 Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL); |
47 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 102 child_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
48 child_params.parent = toplevel_->GetNativeView(); | 103 child_params.parent = toplevel_->GetNativeView(); |
49 child_->Init(child_params); | 104 child_->Init(child_params); |
50 child_->SetContentsView(test_view); | 105 child_->SetContentsView(test_view); |
51 | 106 |
52 // Owned by |toplevel|. | 107 // Owned by |toplevel|. |
53 host_.reset(new NativeViewHost); | 108 host_.reset(new NativeViewHostTesting); |
54 toplevel_->GetRootView()->AddChildView(host_.get()); | 109 toplevel_->GetRootView()->AddChildView(host_.get()); |
55 host_->Attach(child_->GetNativeView()); | 110 host_->Attach(child_->GetNativeView()); |
56 } | 111 } |
57 | 112 |
58 void DestroyHost() { | 113 void DestroyHost() { |
59 host_.reset(); | 114 host_.reset(); |
60 } | 115 } |
61 | 116 |
| 117 NativeViewHostTesting* ReleaseHost() { |
| 118 return host_.release(); |
| 119 } |
| 120 |
| 121 void DestroyTopLevel() { |
| 122 toplevel_.reset(); |
| 123 } |
| 124 |
| 125 gfx::Point CalculateNativeViewOrigin(gfx::Rect input_rect, |
| 126 gfx::Rect native_rect) { |
| 127 return native_host()->CalculateNativeViewOrigin(input_rect, native_rect); |
| 128 } |
| 129 |
62 private: | 130 private: |
63 scoped_ptr<Widget> toplevel_; | 131 scoped_ptr<Widget> toplevel_; |
64 scoped_ptr<NativeViewHost> host_; | 132 scoped_ptr<NativeViewHostTesting> host_; |
65 scoped_ptr<Widget> child_; | 133 scoped_ptr<Widget> child_; |
66 | 134 |
67 DISALLOW_COPY_AND_ASSIGN(NativeViewHostAuraTest); | 135 DISALLOW_COPY_AND_ASSIGN(NativeViewHostAuraTest); |
68 }; | 136 }; |
69 | 137 |
70 // Verifies NativeViewHostAura stops observing native view on destruction. | 138 // Verifies NativeViewHostAura stops observing native view on destruction. |
71 TEST_F(NativeViewHostAuraTest, StopObservingNativeViewOnDestruct) { | 139 TEST_F(NativeViewHostAuraTest, StopObservingNativeViewOnDestruct) { |
72 CreateHost(); | 140 CreateHost(); |
73 aura::Window* child_win = child()->GetNativeView(); | 141 aura::Window* child_win = child()->GetNativeView(); |
74 NativeViewHostAura* aura_host = native_host(); | 142 NativeViewHostAura* aura_host = native_host(); |
75 | 143 |
76 EXPECT_TRUE(child_win->HasObserver(aura_host)); | 144 EXPECT_TRUE(child_win->HasObserver(aura_host)); |
77 DestroyHost(); | 145 DestroyHost(); |
78 EXPECT_FALSE(child_win->HasObserver(aura_host)); | 146 EXPECT_FALSE(child_win->HasObserver(aura_host)); |
79 } | 147 } |
80 | 148 |
81 // Tests that the kHostViewKey is correctly set and cleared. | 149 // Tests that the kHostViewKey is correctly set and cleared. |
82 TEST_F(NativeViewHostAuraTest, HostViewPropertyKey) { | 150 TEST_F(NativeViewHostAuraTest, HostViewPropertyKey) { |
83 // Create the NativeViewHost and attach a NativeView. | 151 // Create the NativeViewHost and attach a NativeView. |
84 CreateHost(); | 152 CreateHost(); |
85 aura::Window* child_win = child()->GetNativeView(); | 153 aura::Window* child_win = child()->GetNativeView(); |
86 EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey)); | 154 EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey)); |
| 155 EXPECT_EQ(host(), clipping_window()->GetProperty(views::kHostViewKey)); |
87 | 156 |
88 host()->Detach(); | 157 host()->Detach(); |
89 EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey)); | 158 EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey)); |
90 | 159 |
91 host()->Attach(child_win); | 160 host()->Attach(child_win); |
92 EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey)); | 161 EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey)); |
| 162 EXPECT_EQ(host(), clipping_window()->GetProperty(views::kHostViewKey)); |
93 | 163 |
94 DestroyHost(); | 164 DestroyHost(); |
95 EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey)); | 165 EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey)); |
96 } | 166 } |
97 | 167 |
| 168 // Tests that the values being calculated by CalculateNativeViewOrigin are |
| 169 // correct. |
| 170 TEST_F(NativeViewHostAuraTest, CalculateNewNativeViewOrigin) { |
| 171 CreateHost(); |
| 172 |
| 173 gfx::Rect clip_rect(0, 0, 50, 50); |
| 174 gfx::Rect contents_rect(50, 50, 100, 100); |
| 175 |
| 176 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_NORTHWEST); |
| 177 EXPECT_EQ(gfx::Point(0, 0).ToString(), |
| 178 CalculateNativeViewOrigin(clip_rect, contents_rect).ToString()); |
| 179 |
| 180 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_NORTH); |
| 181 EXPECT_EQ(gfx::Point(-25, 0).ToString(), |
| 182 CalculateNativeViewOrigin(clip_rect, contents_rect).ToString()); |
| 183 |
| 184 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_NORTHEAST); |
| 185 EXPECT_EQ(gfx::Point(-50, 0).ToString(), |
| 186 CalculateNativeViewOrigin(clip_rect, contents_rect).ToString()); |
| 187 |
| 188 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_EAST); |
| 189 EXPECT_EQ(gfx::Point(-50, -25).ToString(), |
| 190 CalculateNativeViewOrigin(clip_rect, contents_rect).ToString()); |
| 191 |
| 192 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_SOUTHEAST); |
| 193 EXPECT_EQ(gfx::Point(-50, -50).ToString(), |
| 194 CalculateNativeViewOrigin(clip_rect, contents_rect).ToString()); |
| 195 |
| 196 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_SOUTH); |
| 197 EXPECT_EQ(gfx::Point(-25, -50).ToString(), |
| 198 CalculateNativeViewOrigin(clip_rect, contents_rect).ToString()); |
| 199 |
| 200 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_SOUTHWEST); |
| 201 EXPECT_EQ(gfx::Point(0, -50).ToString(), |
| 202 CalculateNativeViewOrigin(clip_rect, contents_rect).ToString()); |
| 203 |
| 204 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_WEST); |
| 205 EXPECT_EQ(gfx::Point(0, -25).ToString(), |
| 206 CalculateNativeViewOrigin(clip_rect, contents_rect).ToString()); |
| 207 |
| 208 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_CENTER); |
| 209 EXPECT_EQ(gfx::Point(-25, -25).ToString(), |
| 210 CalculateNativeViewOrigin(clip_rect, contents_rect).ToString()); |
| 211 |
| 212 DestroyHost(); |
| 213 } |
| 214 |
| 215 // Test that the fast resize path places the clipping and content windows were |
| 216 // they are supposed to be. |
| 217 TEST_F(NativeViewHostAuraTest, FastResizePath) { |
| 218 CreateHost(); |
| 219 host()->set_fast_resize(false); |
| 220 toplevel()->SetBounds(gfx::Rect(0, 0, 100, 100)); |
| 221 native_host()->ShowWidget(0, 0, 100, 100); |
| 222 host()->set_fast_resize(true); |
| 223 |
| 224 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_CENTER); |
| 225 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), |
| 226 host()->native_view()->layer()->bounds().ToString()); |
| 227 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), |
| 228 clipping_window()->layer()->bounds().ToString()); |
| 229 |
| 230 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_NORTHWEST); |
| 231 native_host()->ShowWidget(0, 0, 50, 50); |
| 232 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), |
| 233 host()->native_view()->layer()->bounds().ToString()); |
| 234 EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(), |
| 235 clipping_window()->layer()->bounds().ToString()); |
| 236 |
| 237 host()->set_fast_resize_gravity(NativeViewHost::GRAVITY_SOUTHEAST); |
| 238 native_host()->ShowWidget(0, 0, 50, 50); |
| 239 EXPECT_EQ(gfx::Rect(-50, -50, 100, 100).ToString(), |
| 240 host()->native_view()->layer()->bounds().ToString()); |
| 241 EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(), |
| 242 clipping_window()->layer()->bounds().ToString()); |
| 243 |
| 244 DestroyHost(); |
| 245 } |
| 246 |
| 247 // Test that destroying the top level widget before destroying the attached |
| 248 // NativeViewHost works correctly. Specifically the associated NVH should be |
| 249 // destroyed and there shouldn't be any errors. |
| 250 TEST_F(NativeViewHostAuraTest, DestroyWidget) { |
| 251 NativeViewHostTesting::ResetDestroyedCount(); |
| 252 CreateHost(); |
| 253 ReleaseHost(); |
| 254 EXPECT_EQ(0, NativeViewHostTesting::destroyed_count()); |
| 255 DestroyTopLevel(); |
| 256 EXPECT_EQ(1, NativeViewHostTesting::destroyed_count()); |
| 257 } |
| 258 |
| 259 // Test that the clipping window and the native view are destroyed when the |
| 260 // containing widget for the native view is closed. |
| 261 TEST_F(NativeViewHostAuraTest, ClosingWidgetDoesntLeak) { |
| 262 CreateHost(); |
| 263 AuraWindowDestroyedObserver clipping_observer(clipping_window()); |
| 264 AuraWindowDestroyedObserver native_view_observer(child()->GetNativeView()); |
| 265 EXPECT_EQ(0, clipping_observer.destroyed_count()); |
| 266 EXPECT_EQ(0, native_view_observer.destroyed_count()); |
| 267 child()->CloseNow(); |
| 268 EXPECT_EQ(1, clipping_observer.destroyed_count()); |
| 269 EXPECT_EQ(1, native_view_observer.destroyed_count()); |
| 270 DestroyHost(); |
| 271 } |
| 272 |
| 273 // Test that the none fast resize path is clipped and positioned correctly. |
| 274 TEST_F(NativeViewHostAuraTest, NonFastResizePath) { |
| 275 const gfx::Rect base_rect = gfx::Rect(0, 0, 100, 100); |
| 276 CreateHost(); |
| 277 toplevel()->SetBounds(base_rect); |
| 278 native_host()->ShowWidget(base_rect.x(), base_rect.y(), |
| 279 base_rect.width(), base_rect.height()); |
| 280 EXPECT_EQ(base_rect.ToString(), |
| 281 host()->native_view()->bounds().ToString()); |
| 282 EXPECT_EQ(base_rect.ToString(), |
| 283 clipping_window()->bounds().ToString()); |
| 284 |
| 285 const gfx::Rect kTestCases[] = { |
| 286 gfx::Rect(-10, -20, 100, 100), |
| 287 gfx::Rect(0, -20, 100, 100), |
| 288 gfx::Rect(10, -20, 100, 100), |
| 289 gfx::Rect(-10, 0, 100, 100), |
| 290 gfx::Rect(0, 0, 100, 100), |
| 291 gfx::Rect(10, 0, 100, 100), |
| 292 gfx::Rect(-10, 20, 100, 100), |
| 293 gfx::Rect(0, 20, 100, 100), |
| 294 gfx::Rect(10, 20, 100, 100), |
| 295 gfx::Rect(0, 0, 200, 300), |
| 296 gfx::Rect(-50, -100, 200, 300), |
| 297 }; |
| 298 |
| 299 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { |
| 300 const gfx::Rect& bounds = kTestCases[i]; |
| 301 |
| 302 host()->SetBoundsRect(bounds); |
| 303 |
| 304 gfx::Rect clip_rect = gfx::IntersectRects(bounds, base_rect); |
| 305 EXPECT_EQ(clip_rect.ToString(), clipping_window()->bounds().ToString()); |
| 306 |
| 307 gfx::Rect native_view_bounds = bounds; |
| 308 native_view_bounds.Offset(-clip_rect.x(), -clip_rect.y()); |
| 309 EXPECT_EQ(native_view_bounds.ToString(), |
| 310 host()->native_view()->bounds().ToString()); |
| 311 } |
| 312 |
| 313 DestroyHost(); |
| 314 } |
| 315 |
98 } // namespace views | 316 } // namespace views |
OLD | NEW |