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 3 // found in the LICENSE file. 4 5 #include "ui/views/controls/native/native_view_host_mac.h" 6 7 #import <Cocoa/Cocoa.h> 8 9 #import "base/mac/scoped_nsobject.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "ui/views/controls/native/native_view_host.h" 12 #include "ui/views/controls/native/native_view_host_test_base.h" 13 #include "ui/views/view.h" 14 #include "ui/views/widget/widget.h" 15 16 namespace views { 17 18 class NativeViewHostMacTest : public test::NativeViewHostTestBase { 19 public: 20 NativeViewHostMacTest() {} 21 22 NativeViewHostMac* native_host() { 23 return static_cast<NativeViewHostMac*>(GetNativeWrapper()); 24 } 25 26 void CreateHost() { 27 CreateTopLevel(); 28 CreateTestingHost(); 29 native_view_.reset([[NSView alloc] initWithFrame:NSZeroRect]); 30 31 // Verify the expectation that the NativeViewHostWrapper is only created 32 // after the NativeViewHost is added to a widget. 33 EXPECT_FALSE(native_host()); 34 toplevel()->GetRootView()->AddChildView(host()); 35 EXPECT_TRUE(native_host()); 36 37 host()->Attach(native_view_); 38 } 39 40 protected: 41 base::scoped_nsobject<NSView> native_view_; 42 43 private: 44 DISALLOW_COPY_AND_ASSIGN(NativeViewHostMacTest); 45 }; 46 47 // Test destroying the top level widget before destroying the NativeViewHost. 48 // On Mac, also ensure that the native view is removed from its superview when 49 // the Widget containing its host is destroyed. 50 TEST_F(NativeViewHostMacTest, DestroyWidget) { 51 ResetHostDestroyedCount(); 52 CreateHost(); 53 ReleaseHost(); 54 EXPECT_EQ(0, host_destroyed_count()); 55 EXPECT_TRUE([native_view_ superview]); 56 DestroyTopLevel(); 57 EXPECT_FALSE([native_view_ superview]); 58 EXPECT_EQ(1, host_destroyed_count()); 59 } 60 61 // Ensure the native view receives the correct bounds when it is attached. On 62 // Mac, the bounds of the native view is relative to the NSWindow it is in, not 63 // the screen, and the coordinates have to be flipped. 64 TEST_F(NativeViewHostMacTest, Attach) { 65 CreateHost(); 66 EXPECT_TRUE([native_view_ superview]); 67 EXPECT_TRUE([native_view_ window]); 68 69 host()->Detach(); 70 71 [native_view_ setFrame:NSZeroRect]; 72 toplevel()->SetBounds(gfx::Rect(64, 48, 100, 200)); 73 host()->SetBounds(10, 10, 80, 60); 74 75 EXPECT_FALSE([native_view_ superview]); 76 EXPECT_FALSE([native_view_ window]); 77 EXPECT_TRUE(NSEqualRects(NSZeroRect, [native_view_ frame])); 78 79 host()->Attach(native_view_); 80 EXPECT_TRUE([native_view_ superview]); 81 EXPECT_TRUE([native_view_ window]); 82 83 // Expect the top-left to be 10 pixels below the titlebar. 84 int bottom = toplevel()->GetClientAreaBoundsInScreen().height() - 10 - 60; 85 EXPECT_TRUE(NSEqualRects(NSMakeRect(10, bottom, 80, 60), 86 [native_view_ frame])); 87 } 88 89 // Ensure the native view is hidden along with its host, and when detaching, or 90 // when attaching to a host that is already hidden. 91 TEST_F(NativeViewHostMacTest, NativeViewHidden) { 92 CreateHost(); 93 toplevel()->SetBounds(gfx::Rect(0, 0, 100, 100)); 94 host()->SetBounds(10, 10, 80, 60); 95 96 EXPECT_FALSE([native_view_ isHidden]); 97 host()->SetVisible(false); 98 EXPECT_TRUE([native_view_ isHidden]); 99 host()->SetVisible(true); 100 EXPECT_FALSE([native_view_ isHidden]); 101 102 host()->Detach(); 103 EXPECT_TRUE([native_view_ isHidden]); // Hidden when detached. 104 [native_view_ setHidden:NO]; 105 106 host()->SetVisible(false); 107 EXPECT_FALSE([native_view_ isHidden]); // Stays visible. 108 host()->Attach(native_view_); 109 EXPECT_TRUE([native_view_ isHidden]); // Hidden when attached. 110 111 host()->Detach(); 112 [native_view_ setHidden:YES]; 113 host()->SetVisible(true); 114 EXPECT_TRUE([native_view_ isHidden]); // Stays hidden. 115 host()->Attach(native_view_); 116 EXPECT_FALSE([native_view_ isHidden]); // Made visible when attached. 117 118 EXPECT_TRUE([native_view_ superview]); 119 toplevel()->GetRootView()->RemoveChildView(host()); 120 EXPECT_TRUE([native_view_ isHidden]); // Hidden when removed from Widget. 121 EXPECT_FALSE([native_view_ superview]); 122 123 toplevel()->GetRootView()->AddChildView(host()); 124 EXPECT_FALSE([native_view_ isHidden]); // And visible when added. 125 EXPECT_TRUE([native_view_ superview]); 126 } 127 128 } // namespace views 129