| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/ui/cocoa/browser_window_controller.h" | 5 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
| 6 | 6 |
| 7 #import "base/mac/mac_util.h" | 7 #import "base/mac/mac_util.h" |
| 8 #include "base/mac/sdk_forward_declarations.h" | 8 #include "base/mac/sdk_forward_declarations.h" |
| 9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 VIEW_ID_TOOLBAR, | 61 VIEW_ID_TOOLBAR, |
| 62 VIEW_ID_BOOKMARK_BAR, | 62 VIEW_ID_BOOKMARK_BAR, |
| 63 VIEW_ID_INFO_BAR, | 63 VIEW_ID_INFO_BAR, |
| 64 VIEW_ID_FIND_BAR, | 64 VIEW_ID_FIND_BAR, |
| 65 VIEW_ID_DOWNLOAD_SHELF, | 65 VIEW_ID_DOWNLOAD_SHELF, |
| 66 VIEW_ID_TAB_CONTENT_AREA, | 66 VIEW_ID_TAB_CONTENT_AREA, |
| 67 VIEW_ID_FULLSCREEN_FLOATING_BAR, | 67 VIEW_ID_FULLSCREEN_FLOATING_BAR, |
| 68 VIEW_ID_COUNT, | 68 VIEW_ID_COUNT, |
| 69 }; | 69 }; |
| 70 | 70 |
| 71 // Checks that no views draw on top of the supposedly exposed view. |
| 72 class ViewExposedChecker { |
| 73 public: |
| 74 ViewExposedChecker() : below_exposed_view_(YES) {} |
| 75 ~ViewExposedChecker() {} |
| 76 |
| 77 void SetExceptions(NSArray* exceptions) { |
| 78 exceptions_.reset([exceptions retain]); |
| 79 } |
| 80 |
| 81 // Checks that no views draw in front of |view|, with the exception of |
| 82 // |exceptions|. |
| 83 void CheckViewExposed(NSView* view) { |
| 84 below_exposed_view_ = YES; |
| 85 exposed_view_.reset([view retain]); |
| 86 CheckViewsDoNotObscure([[[view window] contentView] superview]); |
| 87 } |
| 88 |
| 89 private: |
| 90 // Checks that |view| does not draw on top of |exposed_view_|. |
| 91 void CheckViewDoesNotObscure(NSView* view) { |
| 92 NSRect viewWindowFrame = [view convertRect:[view bounds] toView:nil]; |
| 93 NSRect viewBeingVerifiedWindowFrame = |
| 94 [exposed_view_ convertRect:[exposed_view_ bounds] toView:nil]; |
| 95 |
| 96 // The views do not intersect. |
| 97 if (!NSIntersectsRect(viewBeingVerifiedWindowFrame, viewWindowFrame)) |
| 98 return; |
| 99 |
| 100 // No view can be above the view being checked. |
| 101 EXPECT_TRUE(below_exposed_view_); |
| 102 |
| 103 // If |view| is a parent of |exposed_view_|, then there's nothing else |
| 104 // to check. |
| 105 NSView* parent = exposed_view_; |
| 106 while (parent != nil) { |
| 107 parent = [parent superview]; |
| 108 if (parent == view) |
| 109 return; |
| 110 } |
| 111 |
| 112 if ([exposed_view_ layer]) |
| 113 return; |
| 114 |
| 115 // If the view being verified doesn't have a layer, then no views that |
| 116 // intersect it can have a layer. |
| 117 if ([exceptions_ containsObject:view]) { |
| 118 EXPECT_FALSE([view isOpaque]); |
| 119 return; |
| 120 } |
| 121 |
| 122 EXPECT_TRUE(![view layer]) << [[view description] UTF8String] << " " << |
| 123 [NSStringFromRect(viewWindowFrame) UTF8String]; |
| 124 } |
| 125 |
| 126 // Recursively checks that |view| and its subviews do not draw on top of |
| 127 // |exposed_view_|. The recursion passes through all views in order of |
| 128 // back-most in Z-order to front-most in Z-order. |
| 129 void CheckViewsDoNotObscure(NSView* view) { |
| 130 // If this is the view being checked, don't recurse into its subviews. All |
| 131 // future views encountered in the recursion are in front of the view being |
| 132 // checked. |
| 133 if (view == exposed_view_) { |
| 134 below_exposed_view_ = NO; |
| 135 return; |
| 136 } |
| 137 |
| 138 CheckViewDoesNotObscure(view); |
| 139 |
| 140 // Perform the recursion. |
| 141 for (NSView* subview in [view subviews]) |
| 142 CheckViewsDoNotObscure(subview); |
| 143 } |
| 144 |
| 145 // The method CheckViewExposed() recurses through the views in the view |
| 146 // hierarchy and checks that none of the views obscure |exposed_view_|. |
| 147 base::scoped_nsobject<NSView> exposed_view_; |
| 148 |
| 149 // While this flag is true, the views being recursed through are below |
| 150 // |exposed_view_| in Z-order. After the recursion passes |exposed_view_|, |
| 151 // this flag is set to false. |
| 152 BOOL below_exposed_view_; |
| 153 |
| 154 // Exceptions are allowed to overlap |exposed_view_|. Exceptions must still |
| 155 // be Z-order behind |exposed_view_|. |
| 156 base::scoped_nsobject<NSArray> exceptions_; |
| 157 |
| 158 DISALLOW_COPY_AND_ASSIGN(ViewExposedChecker); |
| 159 }; |
| 160 |
| 71 } // namespace | 161 } // namespace |
| 72 | 162 |
| 73 @interface InfoBarContainerController(TestingAPI) | 163 @interface InfoBarContainerController(TestingAPI) |
| 74 - (BOOL)isTopInfoBarAnimationRunning; | 164 - (BOOL)isTopInfoBarAnimationRunning; |
| 75 @end | 165 @end |
| 76 | 166 |
| 77 @implementation InfoBarContainerController(TestingAPI) | 167 @implementation InfoBarContainerController(TestingAPI) |
| 78 - (BOOL)isTopInfoBarAnimationRunning { | 168 - (BOOL)isTopInfoBarAnimationRunning { |
| 79 InfoBarController* infoBarController = [infobarControllers_ objectAtIndex:0]; | 169 InfoBarController* infoBarController = [infobarControllers_ objectAtIndex:0]; |
| 80 if (infoBarController) { | 170 if (infoBarController) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 NSPoint icon_bottom = location_bar_view->GetPageInfoBubblePoint(); | 306 NSPoint icon_bottom = location_bar_view->GetPageInfoBubblePoint(); |
| 217 | 307 |
| 218 NSPoint info_bar_top = NSMakePoint(0, | 308 NSPoint info_bar_top = NSMakePoint(0, |
| 219 NSHeight([info_bar_container_controller view].frame) - | 309 NSHeight([info_bar_container_controller view].frame) - |
| 220 overlapping_tip_height); | 310 overlapping_tip_height); |
| 221 info_bar_top = [[info_bar_container_controller view] | 311 info_bar_top = [[info_bar_container_controller view] |
| 222 convertPoint:info_bar_top toView:nil]; | 312 convertPoint:info_bar_top toView:nil]; |
| 223 return icon_bottom.y - info_bar_top.y; | 313 return icon_bottom.y - info_bar_top.y; |
| 224 } | 314 } |
| 225 | 315 |
| 226 // The traffic lights should always be in front of the content view and the | 316 // Nothing should draw on top of the window controls. |
| 227 // tab strip view. Since the traffic lights change across OSX versions, this | 317 void VerifyWindowControlsZOrder() { |
| 228 // test verifies that the contentView is in the back, and if the tab strip | 318 NSWindow* window = [controller() window]; |
| 229 // view is a sibling, it is directly in front of the content view. | 319 ViewExposedChecker checker; |
| 230 void VerifyTrafficLightZOrder() const { | |
| 231 NSView* contentView = [[controller() window] contentView]; | |
| 232 NSView* rootView = [contentView superview]; | |
| 233 NSArray* subviews = [rootView subviews]; | |
| 234 | 320 |
| 235 EXPECT_EQ([controller() tabStripBackgroundView], | 321 // The exceptions are the contentView, chromeContentView and tabStripView, |
| 236 [subviews objectAtIndex:0]); | 322 // which are layer backed but transparent. |
| 237 EXPECT_EQ(contentView, [subviews objectAtIndex:1]); | 323 NSArray* exceptions = @[ |
| 324 [window contentView], |
| 325 controller().chromeContentView, |
| 326 controller().tabStripView |
| 327 ]; |
| 328 checker.SetExceptions(exceptions); |
| 238 | 329 |
| 239 NSView* tabStripView = [controller() tabStripView]; | 330 checker.CheckViewExposed([window standardWindowButton:NSWindowCloseButton]); |
| 240 if ([subviews containsObject:tabStripView]) | 331 checker.CheckViewExposed( |
| 241 EXPECT_EQ(tabStripView, [subviews objectAtIndex:2]); | 332 [window standardWindowButton:NSWindowMiniaturizeButton]); |
| 333 checker.CheckViewExposed([window standardWindowButton:NSWindowZoomButton]); |
| 334 |
| 335 // There is no fullscreen button on OSX 10.6 or OSX 10.10+. |
| 336 NSView* view = [window standardWindowButton:NSWindowFullScreenButton]; |
| 337 if (view) |
| 338 checker.CheckViewExposed(view); |
| 242 } | 339 } |
| 243 | 340 |
| 244 private: | 341 private: |
| 245 DISALLOW_COPY_AND_ASSIGN(BrowserWindowControllerTest); | 342 DISALLOW_COPY_AND_ASSIGN(BrowserWindowControllerTest); |
| 246 }; | 343 }; |
| 247 | 344 |
| 248 // Tests that adding the first profile moves the Lion fullscreen button over | 345 // Tests that adding the first profile moves the Lion fullscreen button over |
| 249 // correctly. | 346 // correctly. |
| 250 // DISABLED_ because it regularly times out: http://crbug.com/159002. | 347 // DISABLED_ because it regularly times out: http://crbug.com/159002. |
| 251 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, | 348 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 | 590 |
| 494 chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR); | 591 chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR); |
| 495 WaitForBookmarkBarAnimationToFinish(); | 592 WaitForBookmarkBarAnimationToFinish(); |
| 496 EXPECT_FALSE([controller() isBookmarkBarVisible]); | 593 EXPECT_FALSE([controller() isBookmarkBarVisible]); |
| 497 EXPECT_EQ(std::min(GetExpectedTopInfoBarTipHeight(), max_tip_height), | 594 EXPECT_EQ(std::min(GetExpectedTopInfoBarTipHeight(), max_tip_height), |
| 498 [[controller() infoBarContainerController] overlappingTipHeight]); | 595 [[controller() infoBarContainerController] overlappingTipHeight]); |
| 499 } | 596 } |
| 500 | 597 |
| 501 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, TrafficLightZOrder) { | 598 IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, TrafficLightZOrder) { |
| 502 // Verify z order immediately after creation. | 599 // Verify z order immediately after creation. |
| 503 VerifyTrafficLightZOrder(); | 600 VerifyWindowControlsZOrder(); |
| 504 | 601 |
| 505 // Toggle overlay, then verify z order. | 602 // Verify z order in and out of overlay. |
| 506 [controller() showOverlay]; | 603 [controller() showOverlay]; |
| 604 VerifyWindowControlsZOrder(); |
| 507 [controller() removeOverlay]; | 605 [controller() removeOverlay]; |
| 508 VerifyTrafficLightZOrder(); | 606 VerifyWindowControlsZOrder(); |
| 509 | 607 |
| 510 // Toggle immersive fullscreen, then verify z order. | 608 // Toggle immersive fullscreen, then verify z order. In immersive fullscreen, |
| 609 // there are no window controls. |
| 511 [controller() enterImmersiveFullscreen]; | 610 [controller() enterImmersiveFullscreen]; |
| 512 [controller() exitImmersiveFullscreen]; | 611 [controller() exitImmersiveFullscreen]; |
| 513 VerifyTrafficLightZOrder(); | 612 VerifyWindowControlsZOrder(); |
| 514 } | 613 } |
| OLD | NEW |