Commit 9af971cc authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

RemoteMacViews: Allow for BridgedNativeWidget to create its own NSWindow

Because BridgedNativeWidget will be living in its own process, it will
be necessary for BridgedNativeWidget to create its own NSWindow, instead
of having one be provided during initialization.

This requires substantial refactoring, and two of the NSWindow classes
that BridgedNativeWidget are provided live in chrome/browser/ui, and
will need moving to a new location.

For the moment, allow either creating a new NSWindow or specifying an
NSWindow via the methods BridgedNativeWidget::CreateWindow and
BridgedNativeWidget::SetWindow. This unblocks cross-process development.

Also, be explicit that BridgedNativeWidget's NSWindow is always a
NativeWidgetMacNSWindow or a sub-class thereof. The only exceptions to
this are in tests, so merge testing functionality into
NativeWidgetMacNSWindow.

Bug: 859152
Change-Id: I61edb34d773fc11dff921da5edb34da1e306105b
Reviewed-on: https://chromium-review.googlesource.com/1175051
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583350}
parent 7e4d7965
......@@ -18,6 +18,7 @@
#include "ui/base/ime/text_input_client.h"
#import "ui/views/cocoa/bridged_native_widget_owner.h"
#import "ui/views/cocoa/cocoa_mouse_capture_delegate.h"
#import "ui/views/cocoa/native_widget_mac_nswindow.h"
#import "ui/views/focus/focus_manager.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/widget.h"
......@@ -68,9 +69,17 @@ class VIEWS_EXPORT BridgedNativeWidget
BridgedNativeWidget(BridgedNativeWidgetHost* host, NativeWidgetMac* parent);
~BridgedNativeWidget() override;
// Initialize the bridge, "retains" ownership of |window|.
void Init(base::scoped_nsobject<NSWindow> window,
const Widget::InitParams& params);
// Create the NSWindow using the specified style mask.
void CreateWindow(uint64_t window_style_mask);
// Initialize the NSWindow by taking ownership of the specified object.
// Either CreateWindow or SetWindow maybe used to initialize the NSWindow,
// and the initialization may happen only once.
// TODO(ccameron): When a BridgedNativeWidget is allocated across a process
// boundary, it will not be possible to call SetWindow. Move the relevant
// sub-classes so that they can be allocated via CreateWindow.
void SetWindow(base::scoped_nsobject<NativeWidgetMacNSWindow> window);
// Initialize the bridge (after the NSWindow has been created).
void Init(const Widget::InitParams& params);
// Invoked at the end of Widget::Init().
void OnWidgetInitDone();
......@@ -167,7 +176,7 @@ class VIEWS_EXPORT BridgedNativeWidget
NativeWidgetMac* native_widget_mac() { return native_widget_mac_; }
BridgedContentView* ns_view() { return bridged_view_; }
NSWindow* ns_window() { return window_; }
NativeWidgetMacNSWindow* ns_window() { return window_; }
TooltipManager* tooltip_manager() { return tooltip_manager_.get(); }
......@@ -274,7 +283,7 @@ class VIEWS_EXPORT BridgedNativeWidget
BridgedNativeWidgetHost* const host_; // Weak. Owns this.
NativeWidgetMac* const native_widget_mac_; // Weak. Owns |host_|.
base::scoped_nsobject<NSWindow> window_;
base::scoped_nsobject<NativeWidgetMacNSWindow> window_;
base::scoped_nsobject<ViewsNSWindowDelegate> window_delegate_;
base::scoped_nsobject<BridgedContentView> bridged_view_;
base::scoped_nsobject<ModalShowAnimationWithLayer> show_animation_;
......
......@@ -18,6 +18,7 @@
#include "components/viz/common/surfaces/local_surface_id.h"
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
#import "ui/base/cocoa/window_size_constants.h"
#include "ui/base/hit_test.h"
#include "ui/base/layout.h"
#include "ui/base/ui_base_switches.h"
......@@ -30,6 +31,7 @@
#import "ui/views/cocoa/cocoa_mouse_capture.h"
#import "ui/views/cocoa/cocoa_window_move_loop.h"
#import "ui/views/cocoa/drag_drop_client_mac.h"
#import "ui/views/cocoa/native_widget_mac_nswindow.h"
#include "ui/views/cocoa/tooltip_manager_mac.h"
#import "ui/views/cocoa/views_nswindow_delegate.h"
#import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
......@@ -247,15 +249,29 @@ BridgedNativeWidget::~BridgedNativeWidget() {
SetRootView(nullptr);
}
void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
const Widget::InitParams& params) {
widget_type_ = params.type;
is_translucent_window_ =
params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
void BridgedNativeWidget::CreateWindow(uint64_t window_style_mask) {
DCHECK(!window_);
window_.reset([[NativeWidgetMacNSWindow alloc]
initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:window_style_mask
backing:NSBackingStoreBuffered
defer:NO]);
[window_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
[window_ setDelegate:window_delegate_];
}
void BridgedNativeWidget::SetWindow(
base::scoped_nsobject<NativeWidgetMacNSWindow> window) {
DCHECK(!window_);
window_.swap(window);
window_ = std::move(window);
[window_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
[window_ setDelegate:window_delegate_];
}
void BridgedNativeWidget::Init(const Widget::InitParams& params) {
widget_type_ = params.type;
is_translucent_window_ =
params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
// Register for application hide notifications so that visibility can be
// properly tracked. This is not done in the delegate so that the lifetime is
......
......@@ -248,39 +248,6 @@ NSTextInputContext* g_fake_current_input_context = nullptr;
@end
// Class to override -[NSWindow toggleFullScreen:] to a no-op. This simulates
// NSWindow's behavior when attempting to toggle fullscreen state again, when
// the last attempt failed but Cocoa has not yet sent
// windowDidFailToEnterFullScreen:.
@interface BridgedNativeWidgetTestFullScreenWindow : NativeWidgetMacNSWindow {
@private
int ignoredToggleFullScreenCount_;
}
@property(readonly, nonatomic) int ignoredToggleFullScreenCount;
@end
@implementation BridgedNativeWidgetTestFullScreenWindow
@synthesize ignoredToggleFullScreenCount = ignoredToggleFullScreenCount_;
- (void)performSelector:(SEL)aSelector
withObject:(id)anArgument
afterDelay:(NSTimeInterval)delay {
// This is used in simulations without a message loop. Don't start a message
// loop since that would expose the tests to system notifications and
// potential flakes. Instead, just pretend the message loop is flushed here.
if (aSelector == @selector(toggleFullScreen:))
[self toggleFullScreen:anArgument];
else
[super performSelector:aSelector withObject:anArgument afterDelay:delay];
}
- (void)toggleFullScreen:(id)sender {
++ignoredToggleFullScreenCount_;
}
@end
namespace views {
namespace test {
......@@ -296,6 +263,9 @@ class MockNativeWidgetMac : public NativeWidgetMac {
void InitNativeWidget(const Widget::InitParams& params) override {
ownership_ = params.ownership;
bridge()->CreateWindow(NSBorderlessWindowMask);
bridge()->Init(params);
// Usually the bridge gets initialized here. It is skipped to run extra
// checks in tests, and so that a second window isn't created.
delegate()->OnNativeWidgetCreated(true);
......@@ -358,10 +328,18 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
}
void TearDown() override {
// ui::CocoaTest::TearDown will wait until all NSWindows are destroyed, so
// be sure to destroy the widget (which will destroy its NSWindow)
// beforehand.
widget_.reset();
ui::test::MaterialDesignControllerTestAPI::Uninitialize();
ui::CocoaTest::TearDown();
}
NSWindow* bridge_window() const {
return native_widget_mac_->bridge()->ns_window();
}
protected:
std::unique_ptr<Widget> widget_;
MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|.
......@@ -566,13 +544,7 @@ void BridgedNativeWidgetTest::SetUp() {
BridgedNativeWidgetTestBase::SetUp();
view_.reset(new views::internal::RootView(widget_.get()));
base::scoped_nsobject<NSWindow> window([test_window() retain]);
// BridgedNativeWidget expects to be initialized with a hidden (deferred)
// window.
[window orderOut:nil];
EXPECT_FALSE([window delegate]);
bridge()->Init(window, init_params_);
base::scoped_nsobject<NSWindow> window([bridge_window() retain]);
// The delegate should exist before setting the root view.
EXPECT_TRUE([window delegate]);
......@@ -581,7 +553,7 @@ void BridgedNativeWidgetTest::SetUp() {
// Pretend it has been shown via NativeWidgetMac::Show().
[window orderFront:nil];
[test_window() makePretendKeyWindowAndSetFirstResponder:bridge()->ns_view()];
[window makeFirstResponder:bridge()->ns_view()];
}
void BridgedNativeWidgetTest::TearDown() {
......@@ -741,8 +713,9 @@ void BridgedNativeWidgetTest::TestEditingCommands(NSArray* selectors) {
// what TEST_VIEW usually does.
TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewAddRemove) {
base::scoped_nsobject<BridgedContentView> view([bridge()->ns_view() retain]);
EXPECT_NSEQ([test_window() contentView], view);
EXPECT_NSEQ(test_window(), [view window]);
base::scoped_nsobject<NSWindow> window([bridge_window() retain]);
EXPECT_NSEQ([window contentView], view);
EXPECT_NSEQ(window, [view window]);
// The superview of a contentView is an NSNextStepFrame.
EXPECT_TRUE([view superview]);
......@@ -754,13 +727,13 @@ TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewAddRemove) {
// Closing the window should tear down the C++ bridge, remove references to
// any C++ objects in the ObjectiveC object, and remove it from the hierarchy.
[test_window() close];
[window close];
EXPECT_FALSE([view hostedView]);
EXPECT_FALSE([view superview]);
EXPECT_FALSE([view window]);
EXPECT_EQ(0u, [[view trackingAreas] count]);
EXPECT_FALSE([test_window() contentView]);
EXPECT_FALSE([test_window() delegate]);
EXPECT_FALSE([window contentView]);
EXPECT_FALSE([window delegate]);
}
TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewDisplay) {
......@@ -772,8 +745,8 @@ TEST_F(BridgedNativeWidgetTest, ViewSizeTracksWindow) {
const int kTestNewWidth = 400;
const int kTestNewHeight = 300;
// |test_window()| is borderless, so these should align.
NSSize window_size = [test_window() frame].size;
// |bridge_window()| is borderless, so these should align.
NSSize window_size = [bridge_window() frame].size;
EXPECT_EQ(view_->width(), static_cast<int>(window_size.width));
EXPECT_EQ(view_->height(), static_cast<int>(window_size.height));
......@@ -781,8 +754,8 @@ TEST_F(BridgedNativeWidgetTest, ViewSizeTracksWindow) {
EXPECT_NE(kTestNewWidth, view_->width());
EXPECT_NE(kTestNewHeight, view_->height());
[test_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight)
display:NO];
[bridge_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight)
display:NO];
EXPECT_EQ(kTestNewWidth, view_->width());
EXPECT_EQ(kTestNewHeight, view_->height());
}
......@@ -798,13 +771,7 @@ class BridgedNativeWidgetInitTest : public BridgedNativeWidgetTestBase {
: BridgedNativeWidgetTestBase(SkipInitialization()) {}
// Prepares a new |window_| and |widget_| for a call to PerformInit().
void CreateNewWidgetToInit(NSUInteger style_mask) {
window_.reset(
[[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:style_mask
backing:NSBackingStoreBuffered
defer:NO]);
[window_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
void CreateNewWidgetToInit() {
widget_.reset(new Widget);
native_widget_mac_ = new MockNativeWidgetMac(widget_.get());
init_params_.native_widget = native_widget_mac_;
......@@ -812,12 +779,8 @@ class BridgedNativeWidgetInitTest : public BridgedNativeWidgetTestBase {
void PerformInit() {
widget_->Init(init_params_);
bridge()->Init(window_, init_params_);
}
protected:
base::scoped_nsobject<NSWindow> window_;
private:
DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetInitTest);
};
......@@ -842,34 +805,32 @@ TEST_F(BridgedNativeWidgetInitTest, ShadowType) {
EXPECT_EQ(Widget::InitParams::OPAQUE_WINDOW, init_params_.opacity);
EXPECT_EQ(Widget::InitParams::SHADOW_TYPE_DEFAULT, init_params_.shadow_type);
CreateNewWidgetToInit(NSBorderlessWindowMask);
EXPECT_FALSE([window_ hasShadow]); // Default for NSBorderlessWindowMask.
CreateNewWidgetToInit();
EXPECT_FALSE(
[bridge_window() hasShadow]); // Default for NSBorderlessWindowMask.
PerformInit();
// Borderless is 0, so isn't really a mask. Check that nothing is set.
EXPECT_EQ(NSBorderlessWindowMask, [window_ styleMask]);
EXPECT_TRUE([window_ hasShadow]); // SHADOW_TYPE_DEFAULT means a shadow.
EXPECT_EQ(NSBorderlessWindowMask, [bridge_window() styleMask]);
EXPECT_TRUE(
[bridge_window() hasShadow]); // SHADOW_TYPE_DEFAULT means a shadow.
CreateNewWidgetToInit(NSBorderlessWindowMask);
CreateNewWidgetToInit();
init_params_.shadow_type = Widget::InitParams::SHADOW_TYPE_NONE;
PerformInit();
EXPECT_FALSE([window_ hasShadow]); // Preserves lack of shadow.
EXPECT_FALSE([bridge_window() hasShadow]); // Preserves lack of shadow.
// Default for Widget::InitParams::TYPE_WINDOW.
NSUInteger kBorderedMask =
NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask |
NSResizableWindowMask | NSTexturedBackgroundWindowMask;
CreateNewWidgetToInit(kBorderedMask);
EXPECT_TRUE([window_ hasShadow]); // Default for non-borderless.
CreateNewWidgetToInit();
PerformInit();
EXPECT_FALSE([window_ hasShadow]); // SHADOW_TYPE_NONE removes shadow.
EXPECT_FALSE(
[bridge_window() hasShadow]); // SHADOW_TYPE_NONE removes shadow.
init_params_.shadow_type = Widget::InitParams::SHADOW_TYPE_DEFAULT;
CreateNewWidgetToInit(kBorderedMask);
CreateNewWidgetToInit();
PerformInit();
EXPECT_TRUE([window_ hasShadow]); // Preserves shadow.
EXPECT_TRUE([bridge_window() hasShadow]); // Preserves shadow.
window_.reset();
widget_.reset();
}
......@@ -1581,18 +1542,10 @@ typedef BridgedNativeWidgetTestBase BridgedNativeWidgetSimulateFullscreenTest;
// mashing Ctrl+Left/Right to keep OSX in a transition between Spaces to cause
// the fullscreen transition to fail.
TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) {
base::scoped_nsobject<NSWindow> owned_window(
[[BridgedNativeWidgetTestFullScreenWindow alloc]
initWithContentRect:NSMakeRect(50, 50, 400, 300)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO]);
[owned_window setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
bridge()->Init(owned_window, init_params_); // Transfers ownership.
BridgedNativeWidgetTestFullScreenWindow* window =
base::mac::ObjCCastStrict<BridgedNativeWidgetTestFullScreenWindow>(
NativeWidgetMacNSWindow* window =
base::mac::ObjCCastStrict<NativeWidgetMacNSWindow>(
widget_->GetNativeWindow());
[window disableToggleFullScreenForTesting];
widget_->Show();
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
......@@ -1606,11 +1559,11 @@ TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) {
// On a failure, Cocoa starts by sending an unexpected *exit* fullscreen, and
// BridgedNativeWidget will think it's just a delayed transition and try to go
// back into fullscreen but get ignored by Cocoa.
EXPECT_EQ(0, [window ignoredToggleFullScreenCount]);
EXPECT_EQ(0, [window toggleFullScreenCountForTesting]);
EXPECT_TRUE(bridge()->target_fullscreen_state());
[center postNotificationName:NSWindowDidExitFullScreenNotification
object:window];
EXPECT_EQ(1, [window ignoredToggleFullScreenCount]);
EXPECT_EQ(1, [window toggleFullScreenCountForTesting]);
EXPECT_FALSE(bridge()->target_fullscreen_state());
// Cocoa follows up with a failure message sent to the NSWindowDelegate (there
......@@ -1639,7 +1592,7 @@ TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) {
EXPECT_FALSE(bridge()->target_fullscreen_state());
[center postNotificationName:NSWindowDidExitFullScreenNotification
object:window];
EXPECT_EQ(1, [window ignoredToggleFullScreenCount]); // No change.
EXPECT_EQ(1, [window toggleFullScreenCountForTesting]); // No change.
EXPECT_FALSE(bridge()->target_fullscreen_state());
widget_->CloseNow();
......
......@@ -47,6 +47,16 @@ VIEWS_EXPORT
// create one.
- (void)setWindowTouchBarDelegate:(id<WindowTouchBarDelegate>)delegate;
// Override -[NSWindow toggleFullScreen:] to be a no-op for testing.
- (void)disableToggleFullScreenForTesting;
// Methods to query properties for tests.
// TODO(ccameron): It may be more appropriate to put testing methods into a
// separate subclass.
@property(readonly, nonatomic) int invalidateShadowCountForTesting;
@property(readonly, nonatomic) int orderWindowCountForTesting;
@property(readonly, nonatomic) int toggleFullScreenCountForTesting;
@property(assign, nonatomic) bool* deallocFlagForTesting;
@end
#endif // UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_
......@@ -82,7 +82,18 @@
base::scoped_nsobject<CommandDispatcher> commandDispatcher_;
base::scoped_nsprotocol<id<UserInterfaceItemCommandHandler>> commandHandler_;
id<WindowTouchBarDelegate> touchBarDelegate_; // Weak.
BOOL toggleFullscreenDisabledForTesting_;
int invalidateShadowCountForTesting_;
int orderWindowCountForTesting_;
int toggleFullScreenCountForTesting_;
bool* deallocFlagForTesting_;
}
@synthesize invalidateShadowCountForTesting = invalidateShadowCountForTesting_;
@synthesize orderWindowCountForTesting = orderWindowCountForTesting_;
@synthesize toggleFullScreenCountForTesting = toggleFullScreenCountForTesting_;
@synthesize deallocFlagForTesting = deallocFlagForTesting_;
- (instancetype)initWithContentRect:(NSRect)contentRect
styleMask:(NSUInteger)windowStyle
......@@ -98,8 +109,13 @@
}
// This override doesn't do anything, but keeping it helps diagnose lifetime
// issues in crash stacktraces by inserting a symbol on NativeWidgetMacNSWindow.
// issues in crash stacktraces by inserting a symbol on NativeWidgetMacNSWindow,
// and adds hooks for tests.
- (void)dealloc {
if (deallocFlagForTesting_) {
DCHECK(!*deallocFlagForTesting_);
*deallocFlagForTesting_ = true;
}
[super dealloc];
}
......@@ -124,6 +140,10 @@
touchBarDelegate_ = delegate;
}
- (void)disableToggleFullScreenForTesting {
toggleFullscreenDisabledForTesting_ = YES;
}
// Private methods.
- (ViewsNSWindowDelegate*)viewsNSWindowDelegate {
......@@ -225,10 +245,36 @@
// when ordering in a window for the first time.
- (void)orderWindow:(NSWindowOrderingMode)orderingMode
relativeTo:(NSInteger)otherWindowNumber {
++orderWindowCountForTesting_;
[super orderWindow:orderingMode relativeTo:otherWindowNumber];
[[self viewsNSWindowDelegate] onWindowOrderChanged:nil];
}
- (void)invalidateShadow {
++invalidateShadowCountForTesting_;
[super invalidateShadow];
}
- (void)performSelector:(SEL)aSelector
withObject:(id)anArgument
afterDelay:(NSTimeInterval)delay {
if (toggleFullscreenDisabledForTesting_ && aSelector == @selector
(toggleFullScreen:)) {
// This is used in simulations without a message loop. Don't start a message
// loop since that would expose the tests to system notifications and
// potential flakes. Instead, just pretend the message loop is flushed here.
[self toggleFullScreen:anArgument];
} else {
[super performSelector:aSelector withObject:anArgument afterDelay:delay];
}
}
- (void)toggleFullScreen:(id)sender {
++toggleFullScreenCountForTesting_;
if (!toggleFullscreenDisabledForTesting_)
[super toggleFullScreen:sender];
}
// NSResponder implementation.
- (BOOL)performKeyEquivalent:(NSEvent*)event {
......
......@@ -28,7 +28,6 @@
#import "ui/views/cocoa/bridged_native_widget_host_impl.h"
#include "ui/views/cocoa/cocoa_mouse_capture.h"
#import "ui/views/cocoa/drag_drop_client_mac.h"
#import "ui/views/cocoa/native_widget_mac_nswindow.h"
#import "ui/views/cocoa/views_nswindow_delegate.h"
#include "ui/views/widget/drop_helper.h"
#include "ui/views/widget/widget_delegate.h"
......@@ -129,9 +128,10 @@ int NativeWidgetMac::SheetPositionY() {
void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
ownership_ = params.ownership;
name_ = params.name;
base::scoped_nsobject<NSWindow> window([CreateNSWindow(params) retain]);
[window setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
bridge()->Init(window, params);
base::scoped_nsobject<NativeWidgetMacNSWindow> window(
[CreateNSWindow(params) retain]);
bridge()->SetWindow(window);
bridge()->Init(params);
// Only set always-on-top here if it is true since setting it may affect how
// the window is treated by Expose.
......
......@@ -56,18 +56,6 @@
- (BOOL)_isTitleHidden;
@end
// Test NSWindow that provides hooks via method overrides to verify behavior.
@interface NativeWidgetMacTestWindow : NativeWidgetMacNSWindow {
@private
int invalidateShadowCount_;
int orderWindowCount_;
bool* deallocFlag_;
}
@property(readonly, nonatomic) int invalidateShadowCount;
@property(readonly, nonatomic) int orderWindowCount;
@property(assign, nonatomic) bool* deallocFlag;
@end
// Used to mock BridgedContentView so that calls to drawRect: can be
// intercepted.
@interface MockBridgedView : NSView {
......@@ -121,33 +109,6 @@ class BridgedNativeWidgetTestApi {
DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTestApi);
};
// Custom native_widget to create a NativeWidgetMacTestWindow.
class TestWindowNativeWidgetMac : public NativeWidgetMac {
public:
explicit TestWindowNativeWidgetMac(Widget* delegate)
: NativeWidgetMac(delegate) {}
protected:
// NativeWidgetMac:
NativeWidgetMacNSWindow* CreateNSWindow(
const Widget::InitParams& params) override {
NSUInteger style_mask = NSBorderlessWindowMask;
if (params.type == Widget::InitParams::TYPE_WINDOW) {
style_mask = NSTexturedBackgroundWindowMask | NSTitledWindowMask |
NSClosableWindowMask | NSMiniaturizableWindowMask |
NSResizableWindowMask;
}
return [[[NativeWidgetMacTestWindow alloc]
initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:style_mask
backing:NSBackingStoreBuffered
defer:NO] autorelease];
}
private:
DISALLOW_COPY_AND_ASSIGN(TestWindowNativeWidgetMac);
};
// Tests for parts of NativeWidgetMac not covered by BridgedNativeWidget, which
// need access to Cocoa APIs.
class NativeWidgetMacTest : public WidgetTest {
......@@ -174,14 +135,14 @@ class NativeWidgetMacTest : public WidgetTest {
return MakeNativeParentWithStyle(NSBorderlessWindowMask);
}
// Create a Widget backed by the NativeWidgetMacTestWindow NSWindow subclass.
// Create a Widget backed by the NativeWidgetMacNSWindow NSWindow subclass.
Widget* CreateWidgetWithTestWindow(Widget::InitParams params,
NativeWidgetMacTestWindow** window) {
NativeWidgetMacNSWindow** window) {
Widget* widget = new Widget;
params.native_widget = new TestWindowNativeWidgetMac(widget);
params.native_widget = new NativeWidgetMac(widget);
widget->Init(params);
widget->Show();
*window = base::mac::ObjCCastStrict<NativeWidgetMacTestWindow>(
*window = base::mac::ObjCCastStrict<NativeWidgetMacNSWindow>(
widget->GetNativeWindow());
EXPECT_TRUE(*window);
return widget;
......@@ -469,8 +430,8 @@ TEST_F(NativeWidgetMacTest, DISABLED_OrderFrontAfterMiniaturize) {
// Test that ShowInactive() on already-visible child widgets is ignored, since
// it may cause a space transition. See https://crbug.com/866760.
TEST_F(NativeWidgetMacTest, ShowInactiveOnChildWidget) {
NativeWidgetMacTestWindow* parent_window;
NativeWidgetMacTestWindow* child_window;
NativeWidgetMacNSWindow* parent_window;
NativeWidgetMacNSWindow* child_window;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW);
......@@ -478,28 +439,29 @@ TEST_F(NativeWidgetMacTest, ShowInactiveOnChildWidget) {
Widget* parent = CreateWidgetWithTestWindow(init_params, &parent_window);
// CreateWidgetWithTestWindow calls Show()
EXPECT_EQ(1, [parent_window orderWindowCount]);
EXPECT_EQ(1, [parent_window orderWindowCountForTesting]);
init_params.parent = parent->GetNativeView();
Widget* child = CreateWidgetWithTestWindow(init_params, &child_window);
// The child is ordered twice, once by Show() and again (by AppKit) when it is
// registered as a child window.
EXPECT_EQ(2, [child_window orderWindowCount]);
EXPECT_EQ(2, [child_window orderWindowCountForTesting]);
// Parent is unchanged.
EXPECT_EQ(1, [parent_window orderWindowCount]);
EXPECT_EQ(1, [parent_window orderWindowCountForTesting]);
// ShowInactive() on a visible regular window may serve to raise its stacking
// order without taking focus, so it should invoke -[NSWindow orderWindow:..].
parent->ShowInactive();
EXPECT_EQ(2, [parent_window orderWindowCount]); // Increases.
EXPECT_EQ(2, [parent_window orderWindowCountForTesting]); // Increases.
// However, ShowInactive() on the child should have no effect. It should
// already be in a correct stacking order and we must avoid a Space switch.
child->ShowInactive();
EXPECT_EQ(2, [child_window orderWindowCount]); // No change.
EXPECT_EQ(2, [parent_window orderWindowCount]); // Parent also unchanged.
EXPECT_EQ(2, [child_window orderWindowCountForTesting]); // No change.
EXPECT_EQ(
2, [parent_window orderWindowCountForTesting]); // Parent also unchanged.
parent->CloseNow();
}
......@@ -876,13 +838,13 @@ TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) {
TestNativeParentWindow* native_parent = MakeNativeParent();
[native_parent setDeallocFlag:&native_parent_dealloced];
NativeWidgetMacTestWindow* window;
NativeWidgetMacNSWindow* window;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_POPUP);
init_params.parent = [native_parent_ contentView];
init_params.bounds = gfx::Rect(0, 0, 100, 200);
CreateWidgetWithTestWindow(init_params, &window);
[window setDeallocFlag:&child_dealloced];
[window setDeallocFlagForTesting:&child_dealloced];
}
{
// On 10.11, closing a weak reference on the parent window works, but older
......@@ -1795,7 +1757,7 @@ TEST_F(NativeWidgetMacTest, DoesHideTitle) {
// Test calls to invalidate the shadow when composited frames arrive.
TEST_F(NativeWidgetMacTest, InvalidateShadow) {
NativeWidgetMacTestWindow* window;
NativeWidgetMacNSWindow* window;
const gfx::Rect rect(0, 0, 100, 200);
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
......@@ -1806,7 +1768,7 @@ TEST_F(NativeWidgetMacTest, InvalidateShadow) {
BridgedNativeWidgetTestApi(window).SimulateFrameSwap(rect.size());
// Default is an opaque window, so shadow doesn't need to be invalidated.
EXPECT_EQ(0, [window invalidateShadowCount]);
EXPECT_EQ(0, [window invalidateShadowCountForTesting]);
widget->CloseNow();
init_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
......@@ -1814,40 +1776,40 @@ TEST_F(NativeWidgetMacTest, InvalidateShadow) {
BridgedNativeWidgetTestApi test_api(window);
// First paint on a translucent window needs to invalidate the shadow. Once.
EXPECT_EQ(0, [window invalidateShadowCount]);
EXPECT_EQ(0, [window invalidateShadowCountForTesting]);
test_api.SimulateFrameSwap(rect.size());
EXPECT_EQ(1, [window invalidateShadowCount]);
EXPECT_EQ(1, [window invalidateShadowCountForTesting]);
test_api.SimulateFrameSwap(rect.size());
EXPECT_EQ(1, [window invalidateShadowCount]);
EXPECT_EQ(1, [window invalidateShadowCountForTesting]);
// Resizing the window also needs to trigger a shadow invalidation.
[window setContentSize:NSMakeSize(123, 456)];
// A "late" frame swap at the old size should do nothing.
test_api.SimulateFrameSwap(rect.size());
EXPECT_EQ(1, [window invalidateShadowCount]);
EXPECT_EQ(1, [window invalidateShadowCountForTesting]);
test_api.SimulateFrameSwap(gfx::Size(123, 456));
EXPECT_EQ(2, [window invalidateShadowCount]);
EXPECT_EQ(2, [window invalidateShadowCountForTesting]);
test_api.SimulateFrameSwap(gfx::Size(123, 456));
EXPECT_EQ(2, [window invalidateShadowCount]);
EXPECT_EQ(2, [window invalidateShadowCountForTesting]);
// Hiding the window does not require shadow invalidation.
widget->Hide();
test_api.SimulateFrameSwap(gfx::Size(123, 456));
EXPECT_EQ(2, [window invalidateShadowCount]);
EXPECT_EQ(2, [window invalidateShadowCountForTesting]);
// Showing a translucent window after hiding it, should trigger shadow
// invalidation.
widget->Show();
test_api.SimulateFrameSwap(gfx::Size(123, 456));
EXPECT_EQ(3, [window invalidateShadowCount]);
EXPECT_EQ(3, [window invalidateShadowCountForTesting]);
widget->CloseNow();
}
// Test that the contentView opacity corresponds to the window type.
TEST_F(NativeWidgetMacTest, ContentOpacity) {
NativeWidgetMacTestWindow* window;
NativeWidgetMacNSWindow* window;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
......@@ -2376,33 +2338,6 @@ TEST_F(NativeWidgetMacTest, TouchBar) {
}
@end
@implementation NativeWidgetMacTestWindow
@synthesize invalidateShadowCount = invalidateShadowCount_;
@synthesize orderWindowCount = orderWindowCount_;
@synthesize deallocFlag = deallocFlag_;
- (void)dealloc {
if (deallocFlag_) {
DCHECK(!*deallocFlag_);
*deallocFlag_ = true;
}
[super dealloc];
}
- (void)invalidateShadow {
++invalidateShadowCount_;
[super invalidateShadow];
}
- (void)orderWindow:(NSWindowOrderingMode)orderingMode
relativeTo:(NSInteger)otherWindowNumber {
++orderWindowCount_;
[super orderWindow:orderingMode relativeTo:otherWindowNumber];
}
@end
@implementation MockBridgedView
@synthesize drawRectCount = drawRectCount_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment