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 |