Home | History | Annotate | Download | only in native
      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