OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 #import "ui/views/cocoa/bridged_native_widget.h" | 5 #import "ui/views/cocoa/bridged_native_widget.h" |
6 | 6 |
7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 | 10 |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 } | 199 } |
200 | 200 |
201 @end | 201 @end |
202 | 202 |
203 namespace views { | 203 namespace views { |
204 namespace test { | 204 namespace test { |
205 | 205 |
206 // Provides the |parent| argument to construct a BridgedNativeWidget. | 206 // Provides the |parent| argument to construct a BridgedNativeWidget. |
207 class MockNativeWidgetMac : public NativeWidgetMac { | 207 class MockNativeWidgetMac : public NativeWidgetMac { |
208 public: | 208 public: |
209 MockNativeWidgetMac(Widget* delegate) : NativeWidgetMac(delegate) {} | 209 explicit MockNativeWidgetMac(internal::NativeWidgetDelegate* delegate) |
| 210 : NativeWidgetMac(delegate) {} |
210 | 211 |
211 // Expose a reference, so that it can be reset() independently. | 212 // Expose a reference, so that it can be reset() independently. |
212 std::unique_ptr<BridgedNativeWidget>& bridge() { return bridge_; } | 213 std::unique_ptr<BridgedNativeWidget>& bridge() { return bridge_; } |
213 | 214 |
214 // internal::NativeWidgetPrivate: | 215 // internal::NativeWidgetPrivate: |
215 void InitNativeWidget(const Widget::InitParams& params) override { | 216 void InitNativeWidget(const Widget::InitParams& params) override { |
216 ownership_ = params.ownership; | 217 ownership_ = params.ownership; |
217 | 218 |
218 // Usually the bridge gets initialized here. It is skipped to run extra | 219 // Usually the bridge gets initialized here. It is skipped to run extra |
219 // checks in tests, and so that a second window isn't created. | 220 // checks in tests, and so that a second window isn't created. |
220 delegate()->OnNativeWidgetCreated(true); | 221 delegate()->OnNativeWidgetCreated(true); |
221 | 222 |
222 // To allow events to dispatch to a view, it needs a way to get focus. | 223 // To allow events to dispatch to a view, it needs a way to get focus. |
223 bridge_->SetFocusManager(GetWidget()->GetFocusManager()); | 224 bridge_->SetFocusManager(GetWidget()->GetFocusManager()); |
224 } | 225 } |
225 | 226 |
226 void ReorderNativeViews() override { | 227 void ReorderNativeViews() override { |
227 // Called via Widget::Init to set the content view. No-op in these tests. | 228 // Called via Widget::Init to set the content view. No-op in these tests. |
228 } | 229 } |
229 | 230 |
230 private: | 231 private: |
231 DISALLOW_COPY_AND_ASSIGN(MockNativeWidgetMac); | 232 DISALLOW_COPY_AND_ASSIGN(MockNativeWidgetMac); |
232 }; | 233 }; |
233 | 234 |
234 // Helper test base to construct a BridgedNativeWidget with a valid parent. | 235 // Helper test base to construct a BridgedNativeWidget with a valid parent. |
235 class BridgedNativeWidgetTestBase : public ui::CocoaTest { | 236 class BridgedNativeWidgetTestBase : public ui::CocoaTest { |
236 public: | 237 public: |
| 238 struct SkipInitialization {}; |
| 239 |
237 BridgedNativeWidgetTestBase() | 240 BridgedNativeWidgetTestBase() |
238 : widget_(new Widget), | 241 : widget_(new Widget), |
239 native_widget_mac_(new MockNativeWidgetMac(widget_.get())) { | 242 native_widget_mac_(new MockNativeWidgetMac(widget_.get())) {} |
240 } | 243 |
| 244 explicit BridgedNativeWidgetTestBase(SkipInitialization tag) |
| 245 : native_widget_mac_(nullptr) {} |
241 | 246 |
242 std::unique_ptr<BridgedNativeWidget>& bridge() { | 247 std::unique_ptr<BridgedNativeWidget>& bridge() { |
243 return native_widget_mac_->bridge(); | 248 return native_widget_mac_->bridge(); |
244 } | 249 } |
245 | 250 |
246 // Overridden from testing::Test: | 251 // Overridden from testing::Test: |
247 void SetUp() override { | 252 void SetUp() override { |
248 ui::CocoaTest::SetUp(); | 253 ui::CocoaTest::SetUp(); |
| 254 |
| 255 // MaterialDesignController leaks state across tests. See |
| 256 // http://crbug.com/656871. |
| 257 ui::test::MaterialDesignControllerTestAPI::Uninitialize(); |
249 ui::MaterialDesignController::Initialize(); | 258 ui::MaterialDesignController::Initialize(); |
250 | 259 |
251 init_params_.native_widget = native_widget_mac_; | 260 init_params_.native_widget = native_widget_mac_; |
252 | 261 |
253 // Use a frameless window, otherwise Widget will try to center the window | 262 // Use a frameless window, otherwise Widget will try to center the window |
254 // before the tests covering the Init() flow are ready to do that. | 263 // before the tests covering the Init() flow are ready to do that. |
255 init_params_.type = Widget::InitParams::TYPE_WINDOW_FRAMELESS; | 264 init_params_.type = Widget::InitParams::TYPE_WINDOW_FRAMELESS; |
256 | 265 |
257 // To control the lifetime without an actual window that must be closed, | 266 // To control the lifetime without an actual window that must be closed, |
258 // tests in this file need to use WIDGET_OWNS_NATIVE_WIDGET. | 267 // tests in this file need to use WIDGET_OWNS_NATIVE_WIDGET. |
259 init_params_.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 268 init_params_.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
260 | 269 |
261 // Opacity defaults to "infer" which is usually updated by ViewsDelegate. | 270 // Opacity defaults to "infer" which is usually updated by ViewsDelegate. |
262 init_params_.opacity = Widget::InitParams::OPAQUE_WINDOW; | 271 init_params_.opacity = Widget::InitParams::OPAQUE_WINDOW; |
263 | 272 |
264 init_params_.bounds = gfx::Rect(100, 100, 100, 100); | 273 init_params_.bounds = gfx::Rect(100, 100, 100, 100); |
265 | 274 |
266 native_widget_mac_->GetWidget()->Init(init_params_); | 275 if (native_widget_mac_) |
| 276 native_widget_mac_->GetWidget()->Init(init_params_); |
267 } | 277 } |
268 | 278 |
269 void TearDown() override { | 279 void TearDown() override { |
270 ui::test::MaterialDesignControllerTestAPI::Uninitialize(); | 280 ui::test::MaterialDesignControllerTestAPI::Uninitialize(); |
271 ui::CocoaTest::TearDown(); | 281 ui::CocoaTest::TearDown(); |
272 } | 282 } |
273 | 283 |
274 protected: | 284 protected: |
275 std::unique_ptr<Widget> widget_; | 285 std::unique_ptr<Widget> widget_; |
276 MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|. | 286 MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|. |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 EXPECT_NSEQ(test_window(), [view window]); | 606 EXPECT_NSEQ(test_window(), [view window]); |
597 | 607 |
598 // The superview of a contentView is an NSNextStepFrame. | 608 // The superview of a contentView is an NSNextStepFrame. |
599 EXPECT_TRUE([view superview]); | 609 EXPECT_TRUE([view superview]); |
600 EXPECT_TRUE([view hostedView]); | 610 EXPECT_TRUE([view hostedView]); |
601 | 611 |
602 // Ensure the tracking area to propagate mouseMoved: events to the RootView is | 612 // Ensure the tracking area to propagate mouseMoved: events to the RootView is |
603 // installed. | 613 // installed. |
604 EXPECT_EQ(1u, [[view trackingAreas] count]); | 614 EXPECT_EQ(1u, [[view trackingAreas] count]); |
605 | 615 |
606 // Destroying the C++ bridge should remove references to any C++ objects in | 616 // Closing the window should tear down the C++ bridge, remove references to |
607 // the ObjectiveC object, and remove it from the hierarchy. | 617 // any C++ objects in the ObjectiveC object, and remove it from the hierarchy. |
608 bridge().reset(); | 618 [test_window() close]; |
609 EXPECT_FALSE([view hostedView]); | 619 EXPECT_FALSE([view hostedView]); |
610 EXPECT_FALSE([view superview]); | 620 EXPECT_FALSE([view superview]); |
611 EXPECT_FALSE([view window]); | 621 EXPECT_FALSE([view window]); |
612 EXPECT_EQ(0u, [[view trackingAreas] count]); | 622 EXPECT_EQ(0u, [[view trackingAreas] count]); |
613 EXPECT_FALSE([test_window() contentView]); | 623 EXPECT_FALSE([test_window() contentView]); |
614 EXPECT_FALSE([test_window() delegate]); | 624 EXPECT_FALSE([test_window() delegate]); |
615 } | 625 } |
616 | 626 |
617 TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewDisplay) { | 627 TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewDisplay) { |
618 [bridge()->ns_view() display]; | 628 [bridge()->ns_view() display]; |
(...skipping 19 matching lines...) Expand all Loading... |
638 EXPECT_EQ(kTestNewHeight, view_->height()); | 648 EXPECT_EQ(kTestNewHeight, view_->height()); |
639 } | 649 } |
640 | 650 |
641 TEST_F(BridgedNativeWidgetTest, GetInputMethodShouldNotReturnNull) { | 651 TEST_F(BridgedNativeWidgetTest, GetInputMethodShouldNotReturnNull) { |
642 EXPECT_TRUE(bridge()->GetInputMethod()); | 652 EXPECT_TRUE(bridge()->GetInputMethod()); |
643 } | 653 } |
644 | 654 |
645 // A simpler test harness for testing initialization flows. | 655 // A simpler test harness for testing initialization flows. |
646 class BridgedNativeWidgetInitTest : public BridgedNativeWidgetTestBase { | 656 class BridgedNativeWidgetInitTest : public BridgedNativeWidgetTestBase { |
647 public: | 657 public: |
648 BridgedNativeWidgetInitTest() {} | 658 BridgedNativeWidgetInitTest() |
| 659 : BridgedNativeWidgetTestBase(SkipInitialization()) {} |
649 | 660 |
650 // Prepares a new |window_| and |widget_| for a call to PerformInit(). | 661 // Prepares a new |window_| and |widget_| for a call to PerformInit(). |
651 void CreateNewWidgetToInit(NSUInteger style_mask) { | 662 void CreateNewWidgetToInit(NSUInteger style_mask) { |
652 window_.reset( | 663 window_.reset( |
653 [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater | 664 [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater |
654 styleMask:style_mask | 665 styleMask:style_mask |
655 backing:NSBackingStoreBuffered | 666 backing:NSBackingStoreBuffered |
656 defer:NO]); | 667 defer:NO]); |
657 [window_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject. | 668 [window_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject. |
658 widget_.reset(new Widget); | 669 widget_.reset(new Widget); |
659 native_widget_mac_ = new MockNativeWidgetMac(widget_.get()); | 670 native_widget_mac_ = new MockNativeWidgetMac(widget_.get()); |
660 init_params_.native_widget = native_widget_mac_; | 671 init_params_.native_widget = native_widget_mac_; |
661 } | 672 } |
662 | 673 |
663 void PerformInit() { | 674 void PerformInit() { |
664 widget_->Init(init_params_); | 675 widget_->Init(init_params_); |
665 bridge()->Init(window_, init_params_); | 676 bridge()->Init(window_, init_params_); |
666 } | 677 } |
667 | 678 |
668 protected: | 679 protected: |
669 base::scoped_nsobject<NSWindow> window_; | 680 base::scoped_nsobject<NSWindow> window_; |
670 | 681 |
671 private: | 682 private: |
672 DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetInitTest); | 683 DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetInitTest); |
673 }; | 684 }; |
674 | 685 |
675 // Test that BridgedNativeWidget remains sane if Init() is never called. | 686 // Test that BridgedNativeWidget remains sane if Init() is never called. |
676 TEST_F(BridgedNativeWidgetInitTest, InitNotCalled) { | 687 TEST_F(BridgedNativeWidgetInitTest, InitNotCalled) { |
| 688 // Don't use a Widget* as the delegate. ~Widget() checks for Widget:: |
| 689 // |native_widget_destroyed_| being set to true. That can only happen with a |
| 690 // non-null WidgetDelegate, which is only set in Widget::Init(). Then, since |
| 691 // neither Widget nor NativeWidget take ownership, use a unique_ptr. |
| 692 std::unique_ptr<MockNativeWidgetMac> native_widget( |
| 693 new MockNativeWidgetMac(nullptr)); |
| 694 native_widget_mac_ = native_widget.get(); |
677 EXPECT_FALSE(bridge()->ns_view()); | 695 EXPECT_FALSE(bridge()->ns_view()); |
678 EXPECT_FALSE(bridge()->ns_window()); | 696 EXPECT_FALSE(bridge()->ns_window()); |
679 bridge().reset(); | |
680 } | 697 } |
681 | 698 |
682 // Tests the shadow type given in InitParams. | 699 // Tests the shadow type given in InitParams. |
683 TEST_F(BridgedNativeWidgetInitTest, ShadowType) { | 700 TEST_F(BridgedNativeWidgetInitTest, ShadowType) { |
684 // Verify Widget::InitParam defaults and arguments added from SetUp(). | 701 // Verify Widget::InitParam defaults and arguments added from SetUp(). |
685 EXPECT_EQ(Widget::InitParams::TYPE_WINDOW_FRAMELESS, init_params_.type); | 702 EXPECT_EQ(Widget::InitParams::TYPE_WINDOW_FRAMELESS, init_params_.type); |
686 EXPECT_EQ(Widget::InitParams::OPAQUE_WINDOW, init_params_.opacity); | 703 EXPECT_EQ(Widget::InitParams::OPAQUE_WINDOW, init_params_.opacity); |
687 EXPECT_EQ(Widget::InitParams::SHADOW_TYPE_DEFAULT, init_params_.shadow_type); | 704 EXPECT_EQ(Widget::InitParams::SHADOW_TYPE_DEFAULT, init_params_.shadow_type); |
688 | 705 |
689 CreateNewWidgetToInit(NSBorderlessWindowMask); | 706 CreateNewWidgetToInit(NSBorderlessWindowMask); |
(...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1306 [center postNotificationName:NSWindowDidExitFullScreenNotification | 1323 [center postNotificationName:NSWindowDidExitFullScreenNotification |
1307 object:window]; | 1324 object:window]; |
1308 EXPECT_EQ(1, [window ignoredToggleFullScreenCount]); // No change. | 1325 EXPECT_EQ(1, [window ignoredToggleFullScreenCount]); // No change. |
1309 EXPECT_FALSE(bridge()->target_fullscreen_state()); | 1326 EXPECT_FALSE(bridge()->target_fullscreen_state()); |
1310 | 1327 |
1311 widget_->CloseNow(); | 1328 widget_->CloseNow(); |
1312 } | 1329 } |
1313 | 1330 |
1314 } // namespace test | 1331 } // namespace test |
1315 } // namespace views | 1332 } // namespace views |
OLD | NEW |