// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #import "chrome/browser/ui/cocoa/browser_window_controller.h" #include #import "base/mac/mac_util.h" #include "base/mac/sdk_forward_declarations.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/devtools/devtools_window_testing.h" #include "chrome/browser/fullscreen.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/bookmarks/bookmark_utils.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/cocoa/browser_window_cocoa.h" #import "chrome/browser/ui/cocoa/browser_window_controller_private.h" #import "chrome/browser/ui/cocoa/fast_resize_view.h" #import "chrome/browser/ui/cocoa/history_overlay_controller.h" #import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" #import "chrome/browser/ui/cocoa/infobars/infobar_controller.h" #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" #import "chrome/browser/ui/cocoa/presentation_mode_controller.h" #import "chrome/browser/ui/cocoa/profiles/avatar_base_controller.h" #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/find_bar/find_bar.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/infobar_container_delegate.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/testing_profile.h" #include "components/infobars/core/infobar_delegate.h" #include "components/infobars/core/simple_alert_infobar_delegate.h" #include "content/public/browser/web_contents.h" #include "content/public/test/test_utils.h" #import "testing/gtest_mac.h" #import "third_party/ocmock/OCMock/OCMock.h" #import "ui/base/cocoa/nsview_additions.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/gfx/vector_icons_public.h" namespace { // Creates a mock of an NSWindow that has the given |frame|. id MockWindowWithFrame(NSRect frame) { id window = [OCMockObject mockForClass:[NSWindow class]]; NSValue* window_frame = [NSValue valueWithBytes:&frame objCType:@encode(NSRect)]; [[[window stub] andReturnValue:window_frame] frame]; return window; } void CreateProfileCallback(const base::Closure& quit_closure, Profile* profile, Profile::CreateStatus status) { EXPECT_TRUE(profile); EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status); EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status); // This will be called multiple times. Wait until the profile is initialized // fully to quit the loop. if (status == Profile::CREATE_STATUS_INITIALIZED) quit_closure.Run(); } enum ViewID { VIEW_ID_TOOLBAR, VIEW_ID_BOOKMARK_BAR, VIEW_ID_INFO_BAR, VIEW_ID_FIND_BAR, VIEW_ID_DOWNLOAD_SHELF, VIEW_ID_TAB_CONTENT_AREA, VIEW_ID_FULLSCREEN_FLOATING_BAR, VIEW_ID_COUNT, }; // Checks that no views draw on top of the supposedly exposed view. class ViewExposedChecker { public: ViewExposedChecker() : below_exposed_view_(YES) {} ~ViewExposedChecker() {} void SetExceptions(NSArray* exceptions) { exceptions_.reset([exceptions retain]); } // Checks that no views draw in front of |view|, with the exception of // |exceptions|. void CheckViewExposed(NSView* view) { below_exposed_view_ = YES; exposed_view_.reset([view retain]); CheckViewsDoNotObscure([[[view window] contentView] superview]); } private: // Checks that |view| does not draw on top of |exposed_view_|. void CheckViewDoesNotObscure(NSView* view) { NSRect viewWindowFrame = [view convertRect:[view bounds] toView:nil]; NSRect viewBeingVerifiedWindowFrame = [exposed_view_ convertRect:[exposed_view_ bounds] toView:nil]; // The views do not intersect. if (!NSIntersectsRect(viewBeingVerifiedWindowFrame, viewWindowFrame)) return; // No view can be above the view being checked. EXPECT_TRUE(below_exposed_view_); // If |view| is a parent of |exposed_view_|, then there's nothing else // to check. NSView* parent = exposed_view_; while (parent != nil) { parent = [parent superview]; if (parent == view) return; } if ([exposed_view_ layer]) return; // If the view being verified doesn't have a layer, then no views that // intersect it can have a layer. if ([exceptions_ containsObject:view]) { EXPECT_FALSE([view isOpaque]); return; } EXPECT_TRUE(![view layer]) << [[view description] UTF8String] << " " << [NSStringFromRect(viewWindowFrame) UTF8String]; } // Recursively checks that |view| and its subviews do not draw on top of // |exposed_view_|. The recursion passes through all views in order of // back-most in Z-order to front-most in Z-order. void CheckViewsDoNotObscure(NSView* view) { // If this is the view being checked, don't recurse into its subviews. All // future views encountered in the recursion are in front of the view being // checked. if (view == exposed_view_) { below_exposed_view_ = NO; return; } CheckViewDoesNotObscure(view); // Perform the recursion. for (NSView* subview in [view subviews]) CheckViewsDoNotObscure(subview); } // The method CheckViewExposed() recurses through the views in the view // hierarchy and checks that none of the views obscure |exposed_view_|. base::scoped_nsobject exposed_view_; // While this flag is true, the views being recursed through are below // |exposed_view_| in Z-order. After the recursion passes |exposed_view_|, // this flag is set to false. BOOL below_exposed_view_; // Exceptions are allowed to overlap |exposed_view_|. Exceptions must still // be Z-order behind |exposed_view_|. base::scoped_nsobject exceptions_; DISALLOW_COPY_AND_ASSIGN(ViewExposedChecker); }; } // namespace @interface InfoBarContainerController(TestingAPI) - (BOOL)isTopInfoBarAnimationRunning; @end @implementation InfoBarContainerController(TestingAPI) - (BOOL)isTopInfoBarAnimationRunning { InfoBarController* infoBarController = [infobarControllers_ objectAtIndex:0]; if (infoBarController) { const gfx::SlideAnimation& infobarAnimation = static_cast( infoBarController.infobar)->animation(); return infobarAnimation.is_animating(); } return NO; } @end class BrowserWindowControllerTest : public InProcessBrowserTest { public: BrowserWindowControllerTest() : InProcessBrowserTest() { } void SetUpOnMainThread() override { [[controller() bookmarkBarController] setStateAnimationsEnabled:NO]; [[controller() bookmarkBarController] setInnerContentAnimationsEnabled:NO]; } BrowserWindowController* controller() const { return [BrowserWindowController browserWindowControllerForWindow: browser()->window()->GetNativeWindow()]; } static void ShowInfoBar(Browser* browser) { SimpleAlertInfoBarDelegate::Create( InfoBarService::FromWebContents( browser->tab_strip_model()->GetActiveWebContents()), infobars::InfoBarDelegate::TEST_INFOBAR, 0, gfx::VectorIconId::VECTOR_ICON_NONE, base::string16(), false); } NSView* GetViewWithID(ViewID view_id) const { switch (view_id) { case VIEW_ID_FULLSCREEN_FLOATING_BAR: return [controller() floatingBarBackingView]; case VIEW_ID_TOOLBAR: return [[controller() toolbarController] view]; case VIEW_ID_BOOKMARK_BAR: return [[controller() bookmarkBarController] view]; case VIEW_ID_INFO_BAR: return [[controller() infoBarContainerController] view]; case VIEW_ID_FIND_BAR: return [[controller() findBarCocoaController] view]; case VIEW_ID_DOWNLOAD_SHELF: return [[controller() downloadShelf] view]; case VIEW_ID_TAB_CONTENT_AREA: return [controller() tabContentArea]; default: NOTREACHED(); return nil; } } void VerifyZOrder(const std::vector& view_list) const { std::vector visible_views; for (size_t i = 0; i < view_list.size(); ++i) { NSView* view = GetViewWithID(view_list[i]); if ([view superview]) visible_views.push_back(view); } for (size_t i = 0; i < visible_views.size() - 1; ++i) { NSView* bottom_view = visible_views[i]; NSView* top_view = visible_views[i + 1]; EXPECT_NSEQ([bottom_view superview], [top_view superview]); EXPECT_TRUE([bottom_view cr_isBelowView:top_view]); } // Views not in |view_list| must either be nil or not parented. for (size_t i = 0; i < VIEW_ID_COUNT; ++i) { if (std::find(view_list.begin(), view_list.end(), i) == view_list.end()) { NSView* view = GetViewWithID(static_cast(i)); EXPECT_TRUE(!view || ![view superview]); } } } CGFloat GetViewHeight(ViewID viewID) const { CGFloat height = NSHeight([GetViewWithID(viewID) frame]); if (viewID == VIEW_ID_INFO_BAR) { height -= [[controller() infoBarContainerController] overlappingTipHeight]; } return height; } static void CheckTopInfoBarAnimation( InfoBarContainerController* info_bar_container_controller, const base::Closure& quit_task) { if (![info_bar_container_controller isTopInfoBarAnimationRunning]) quit_task.Run(); } static void CheckBookmarkBarAnimation( BookmarkBarController* bookmark_bar_controller, const base::Closure& quit_task) { if (![bookmark_bar_controller isAnimationRunning]) quit_task.Run(); } void WaitForTopInfoBarAnimationToFinish() { scoped_refptr runner = new content::MessageLoopRunner; base::Timer timer(false, true); timer.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(15), base::Bind(&CheckTopInfoBarAnimation, [controller() infoBarContainerController], runner->QuitClosure())); runner->Run(); } void WaitForBookmarkBarAnimationToFinish() { scoped_refptr runner = new content::MessageLoopRunner; base::Timer timer(false, true); timer.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(15), base::Bind(&CheckBookmarkBarAnimation, [controller() bookmarkBarController], runner->QuitClosure())); runner->Run(); } void VerifyFullscreenToolbarVisibility(fullscreen_mac::SlidingStyle style) { EXPECT_EQ([[controller() presentationModeController] slidingStyle], style); NSRect toolbarFrame = [[[controller() toolbarController] view] frame]; NSRect screenFrame = [[[controller() window] screen] frame]; if (style == fullscreen_mac::OMNIBOX_TABS_PRESENT) EXPECT_LE(NSMaxY(toolbarFrame), NSMaxY(screenFrame)); else EXPECT_GE(NSMinY(toolbarFrame), NSMaxY(screenFrame)); } NSInteger GetExpectedTopInfoBarTipHeight() { InfoBarContainerController* info_bar_container_controller = [controller() infoBarContainerController]; CGFloat overlapping_tip_height = [info_bar_container_controller overlappingTipHeight]; LocationBarViewMac* location_bar_view = [controller() locationBarBridge]; NSPoint icon_bottom = location_bar_view->GetPageInfoBubblePoint(); NSPoint info_bar_top = NSMakePoint(0, NSHeight([info_bar_container_controller view].frame) - overlapping_tip_height); info_bar_top = [[info_bar_container_controller view] convertPoint:info_bar_top toView:nil]; return icon_bottom.y - info_bar_top.y; } // Nothing should draw on top of the window controls. void VerifyWindowControlsZOrder() { NSWindow* window = [controller() window]; ViewExposedChecker checker; // The exceptions are the contentView, chromeContentView and tabStripView, // which are layer backed but transparent. NSArray* exceptions = @[ [window contentView], controller().chromeContentView, controller().tabStripView ]; checker.SetExceptions(exceptions); checker.CheckViewExposed([window standardWindowButton:NSWindowCloseButton]); checker.CheckViewExposed( [window standardWindowButton:NSWindowMiniaturizeButton]); checker.CheckViewExposed([window standardWindowButton:NSWindowZoomButton]); // There is no fullscreen button on OSX 10.6 or OSX 10.10+. NSView* view = [window standardWindowButton:NSWindowFullScreenButton]; if (view) checker.CheckViewExposed(view); } // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously. // This method toggles fullscreen and waits for the notification. void ToggleFullscreenAndWaitForNotification() { scoped_ptr waiter( new FullscreenNotificationObserver()); browser() ->exclusive_access_manager() ->fullscreen_controller() ->ToggleBrowserFullscreenWithToolbar(); waiter->Wait(); } // Verifies that the flags |blockLayoutSubviews_| and |blockFullscreenResize| // are false. void VerifyFullscreenResizeFlagsAfterTransition() { ASSERT_FALSE([controller() isLayoutSubviewsBlocked]); ASSERT_FALSE([controller() isActiveTabContentsControllerResizeBlocked]); } private: DISALLOW_COPY_AND_ASSIGN(BrowserWindowControllerTest); }; // Tests that adding the first profile moves the Lion fullscreen button over // correctly. // DISABLED_ because it regularly times out: http://crbug.com/159002. IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, DISABLED_ProfileAvatarFullscreenButton) { if (base::mac::IsOSSnowLeopard()) return; // Initialize the locals. ProfileManager* profile_manager = g_browser_process->profile_manager(); ASSERT_TRUE(profile_manager); NSWindow* window = browser()->window()->GetNativeWindow(); ASSERT_TRUE(window); // With only one profile, the fullscreen button should be visible, but the // avatar button should not. EXPECT_EQ(1u, profile_manager->GetNumberOfProfiles()); NSButton* fullscreen_button = [window standardWindowButton:NSWindowFullScreenButton]; EXPECT_TRUE(fullscreen_button); EXPECT_FALSE([fullscreen_button isHidden]); AvatarBaseController* avatar_controller = [controller() avatarButtonController]; NSView* avatar = [avatar_controller view]; EXPECT_TRUE(avatar); EXPECT_TRUE([avatar isHidden]); // Create a profile asynchronously and run the loop until its creation // is complete. base::RunLoop run_loop; ProfileManager::CreateCallback create_callback = base::Bind(&CreateProfileCallback, run_loop.QuitClosure()); profile_manager->CreateProfileAsync( profile_manager->user_data_dir().Append("test"), create_callback, base::ASCIIToUTF16("avatar_test"), std::string(), std::string()); run_loop.Run(); // There should now be two profiles, and the avatar button and fullscreen // button are both visible. EXPECT_EQ(2u, profile_manager->GetNumberOfProfiles()); EXPECT_FALSE([avatar isHidden]); EXPECT_FALSE([fullscreen_button isHidden]); EXPECT_EQ([avatar window], [fullscreen_button window]); // Make sure the visual order of the buttons is correct and that they don't // overlap. NSRect avatar_frame = [avatar frame]; NSRect fullscreen_frame = [fullscreen_button frame]; EXPECT_LT(NSMinX(fullscreen_frame), NSMinX(avatar_frame)); EXPECT_LT(NSMaxX(fullscreen_frame), NSMinX(avatar_frame)); } // Verify that in non-Instant normal mode that the find bar and download shelf // are above the content area. Everything else should be below it. IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, ZOrderNormal) { browser()->GetFindBarController(); // add find bar std::vector view_list; view_list.push_back(VIEW_ID_DOWNLOAD_SHELF); view_list.push_back(VIEW_ID_BOOKMARK_BAR); view_list.push_back(VIEW_ID_TOOLBAR); view_list.push_back(VIEW_ID_INFO_BAR); view_list.push_back(VIEW_ID_TAB_CONTENT_AREA); view_list.push_back(VIEW_ID_FIND_BAR); VerifyZOrder(view_list); [controller() showOverlay]; [controller() removeOverlay]; VerifyZOrder(view_list); [controller() enterImmersiveFullscreen]; [controller() exitImmersiveFullscreen]; VerifyZOrder(view_list); } // Verify that in non-Instant presentation mode that the info bar is below the // content are and everything else is above it. // DISABLED due to flaky failures on trybots. http://crbug.com/178778 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, DISABLED_ZOrderPresentationMode) { chrome::ToggleFullscreenMode(browser()); browser()->GetFindBarController(); // add find bar std::vector view_list; view_list.push_back(VIEW_ID_INFO_BAR); view_list.push_back(VIEW_ID_TAB_CONTENT_AREA); view_list.push_back(VIEW_ID_FULLSCREEN_FLOATING_BAR); view_list.push_back(VIEW_ID_BOOKMARK_BAR); view_list.push_back(VIEW_ID_TOOLBAR); view_list.push_back(VIEW_ID_FIND_BAR); view_list.push_back(VIEW_ID_DOWNLOAD_SHELF); VerifyZOrder(view_list); } // Verify that if the fullscreen floating bar view is below the tab content area // then calling |updateSubviewZOrder:| will correctly move back above. IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, DISABLED_FloatingBarBelowContentView) { // TODO(kbr): re-enable: http://crbug.com/222296 if (base::mac::IsOSMountainLionOrLater()) return; chrome::ToggleFullscreenMode(browser()); NSView* fullscreen_floating_bar = GetViewWithID(VIEW_ID_FULLSCREEN_FLOATING_BAR); [fullscreen_floating_bar removeFromSuperview]; [[[controller() window] contentView] addSubview:fullscreen_floating_bar positioned:NSWindowBelow relativeTo:nil]; [controller() updateSubviewZOrder]; std::vector view_list; view_list.push_back(VIEW_ID_INFO_BAR); view_list.push_back(VIEW_ID_TAB_CONTENT_AREA); view_list.push_back(VIEW_ID_FULLSCREEN_FLOATING_BAR); view_list.push_back(VIEW_ID_BOOKMARK_BAR); view_list.push_back(VIEW_ID_TOOLBAR); view_list.push_back(VIEW_ID_DOWNLOAD_SHELF); VerifyZOrder(view_list); } IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, SheetPosition) { ASSERT_TRUE([controller() isKindOfClass:[BrowserWindowController class]]); EXPECT_TRUE([controller() isTabbedWindow]); EXPECT_TRUE([controller() hasTabStrip]); EXPECT_FALSE([controller() hasTitleBar]); EXPECT_TRUE([controller() hasToolbar]); EXPECT_FALSE([controller() isBookmarkBarVisible]); id sheet = MockWindowWithFrame(NSMakeRect(0, 0, 300, 200)); NSWindow* window = browser()->window()->GetNativeWindow(); NSRect contentFrame = [[window contentView] frame]; NSRect defaultLocation = NSMakeRect(0, NSMaxY(contentFrame), NSWidth(contentFrame), 0); NSRect sheetLocation = [controller() window:window willPositionSheet:nil usingRect:defaultLocation]; NSRect toolbarFrame = [[[controller() toolbarController] view] frame]; EXPECT_EQ(NSMinY(toolbarFrame), NSMinY(sheetLocation)); // Open sheet with normal browser window, persistent bookmark bar. chrome::ToggleBookmarkBarWhenVisible(browser()->profile()); EXPECT_TRUE([controller() isBookmarkBarVisible]); sheetLocation = [controller() window:window willPositionSheet:sheet usingRect:defaultLocation]; NSRect bookmarkBarFrame = [[[controller() bookmarkBarController] view] frame]; EXPECT_EQ(NSMinY(bookmarkBarFrame), NSMinY(sheetLocation)); // If the sheet is too large, it should be positioned at the top of the // window. sheet = MockWindowWithFrame(NSMakeRect(0, 0, 300, 2000)); sheetLocation = [controller() window:window willPositionSheet:sheet usingRect:defaultLocation]; EXPECT_EQ(NSHeight([window frame]), NSMinY(sheetLocation)); // Reset the sheet's size. sheet = MockWindowWithFrame(NSMakeRect(0, 0, 300, 200)); // Make sure the profile does not have the bookmark visible so that // we'll create the shortcut window without the bookmark bar. chrome::ToggleBookmarkBarWhenVisible(browser()->profile()); // Open application mode window. OpenAppShortcutWindow(browser()->profile(), GURL("about:blank")); Browser* popup_browser = BrowserList::GetInstance()->GetLastActive(); NSWindow* popupWindow = popup_browser->window()->GetNativeWindow(); BrowserWindowController* popupController = [BrowserWindowController browserWindowControllerForWindow:popupWindow]; ASSERT_TRUE([popupController isKindOfClass:[BrowserWindowController class]]); EXPECT_FALSE([popupController isTabbedWindow]); EXPECT_FALSE([popupController hasTabStrip]); EXPECT_TRUE([popupController hasTitleBar]); EXPECT_FALSE([popupController isBookmarkBarVisible]); EXPECT_FALSE([popupController hasToolbar]); // Open sheet in an application window. [popupController showWindow:nil]; sheetLocation = [popupController window:popupWindow willPositionSheet:sheet usingRect:defaultLocation]; EXPECT_EQ(NSHeight([[popupWindow contentView] frame]), NSMinY(sheetLocation)); // Close the application window. popup_browser->tab_strip_model()->CloseSelectedTabs(); [popupController close]; } // Verify that the info bar tip is hidden when the toolbar is not visible. IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, InfoBarTipHiddenForWindowWithoutToolbar) { ShowInfoBar(browser()); EXPECT_FALSE( [[controller() infoBarContainerController] shouldSuppressTopInfoBarTip]); OpenAppShortcutWindow(browser()->profile(), GURL("about:blank")); Browser* popup_browser = BrowserList::GetInstance()->GetLastActive(); NSWindow* popupWindow = popup_browser->window()->GetNativeWindow(); BrowserWindowController* popupController = [BrowserWindowController browserWindowControllerForWindow:popupWindow]; EXPECT_FALSE([popupController hasToolbar]); // Show infobar for controller. ShowInfoBar(popup_browser); EXPECT_TRUE( [[popupController infoBarContainerController] shouldSuppressTopInfoBarTip]); } // Tests that status bubble's base frame does move when devTools are docked. IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, StatusBubblePositioning) { NSPoint origin = [controller() statusBubbleBaseFrame].origin; DevToolsWindow* devtools_window = DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true); DevToolsWindowTesting::Get(devtools_window)->SetInspectedPageBounds( gfx::Rect(10, 10, 100, 100)); NSPoint originWithDevTools = [controller() statusBubbleBaseFrame].origin; EXPECT_NSNE(origin, originWithDevTools); DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window); } // Tests that top infobar tip is streched when bookmark bar becomes SHOWN/HIDDEN IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, InfoBarTipStretchedWhenBookmarkBarStatusChanged) { EXPECT_FALSE([controller() isBookmarkBarVisible]); ShowInfoBar(browser()); // The infobar tip is animated during the infobar is being added, wait until // it completes. WaitForTopInfoBarAnimationToFinish(); EXPECT_FALSE([[controller() infoBarContainerController] shouldSuppressTopInfoBarTip]); NSInteger max_tip_height = InfoBarContainerDelegate::kMaximumArrowTargetHeight + InfoBarContainerDelegate::kSeparatorLineHeight; chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR); WaitForBookmarkBarAnimationToFinish(); EXPECT_TRUE([controller() isBookmarkBarVisible]); EXPECT_EQ(std::min(GetExpectedTopInfoBarTipHeight(), max_tip_height), [[controller() infoBarContainerController] overlappingTipHeight]); chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR); WaitForBookmarkBarAnimationToFinish(); EXPECT_FALSE([controller() isBookmarkBarVisible]); EXPECT_EQ(std::min(GetExpectedTopInfoBarTipHeight(), max_tip_height), [[controller() infoBarContainerController] overlappingTipHeight]); } IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, TrafficLightZOrder) { // Verify z order immediately after creation. VerifyWindowControlsZOrder(); // Verify z order in and out of overlay. [controller() showOverlay]; VerifyWindowControlsZOrder(); [controller() removeOverlay]; VerifyWindowControlsZOrder(); // Toggle immersive fullscreen, then verify z order. In immersive fullscreen, // there are no window controls. [controller() enterImmersiveFullscreen]; [controller() exitImmersiveFullscreen]; VerifyWindowControlsZOrder(); } // Ensure that the blocking resize flags set during fullscreen transition to // are reset correctly after the transition. IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, FullscreenResizeFlags) { // Enter fullscreen and verify the flags. ToggleFullscreenAndWaitForNotification(); VerifyFullscreenResizeFlagsAfterTransition(); // Exit fullscreen and verify the flags. ToggleFullscreenAndWaitForNotification(); VerifyFullscreenResizeFlagsAfterTransition(); } // Tests that the omnibox and tabs are hidden/visible in fullscreen mode. // Ensure that when the user toggles this setting, the omnibox, tabs and // preferences are updated correctly. IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, FullscreenToolbarIsVisibleAccordingToPrefs) { // This feature is only available on SystemFullscreen. if (!chrome::mac::SupportsSystemFullscreen()) return; // Tests that the preference is set to true by default. PrefService* prefs = browser()->profile()->GetPrefs(); EXPECT_TRUE(prefs->GetBoolean(prefs::kShowFullscreenToolbar)); // Toggle fullscreen and check if the toolbar is shown. ToggleFullscreenAndWaitForNotification(); VerifyFullscreenToolbarVisibility(fullscreen_mac::OMNIBOX_TABS_PRESENT); // Toggle the visibility of the fullscreen toolbar. Verify that the toolbar // is hidden and the preference is correctly updated. [[controller() presentationModeController] setToolbarFraction:0.0]; chrome::ExecuteCommand(browser(), IDC_TOGGLE_FULLSCREEN_TOOLBAR); EXPECT_FALSE(prefs->GetBoolean(prefs::kShowFullscreenToolbar)); VerifyFullscreenToolbarVisibility(fullscreen_mac::OMNIBOX_TABS_HIDDEN); // Toggle out and back into fullscreen and verify that the toolbar is still // hidden. ToggleFullscreenAndWaitForNotification(); ToggleFullscreenAndWaitForNotification(); VerifyFullscreenToolbarVisibility(fullscreen_mac::OMNIBOX_TABS_HIDDEN); chrome::ExecuteCommand(browser(), IDC_TOGGLE_FULLSCREEN_TOOLBAR); EXPECT_TRUE(prefs->GetBoolean(prefs::kShowFullscreenToolbar)); }