Chromium Code Reviews| Index: chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm |
| diff --git a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm |
| index c8c0e22e09bb0136af95bf6d17a17d190c4060db..f743a6052cf38099187fd5444e3cac680da92813 100644 |
| --- a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm |
| +++ b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm |
| @@ -68,6 +68,95 @@ enum ViewID { |
| VIEW_ID_COUNT, |
| }; |
| +// Checks that no views draw on top of the supposedly exposed view. |
| +class ViewExposedChecker { |
| + public: |
| + ViewExposedChecker() {} |
| + ~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: |
|
Andre
2014/10/10 18:08:49
DISALLOW_COPY_AND_ASSIGN
erikchen
2014/10/10 18:19:11
Done. (Moved to end of class, since that's the com
|
| + // 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_) { |
|
Andre
2014/10/10 18:08:49
I think you may be able to move the code from abov
erikchen
2014/10/10 18:19:11
That doesn't sound accurate. The first view passed
Andre
2014/10/10 18:22:20
Got it.
|
| + 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<NSView> 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_; |
|
Andre
2014/10/10 18:08:49
This should be initialized in constructor to avoid
erikchen
2014/10/10 18:19:11
Done.
|
| + |
| + // Exceptions are allowed to overlap |exposed_view_|. Exceptions must still |
| + // be Z-order behind |exposed_view_|. |
| + base::scoped_nsobject<NSArray> exceptions_; |
| +}; |
| + |
| } // namespace |
| @interface InfoBarContainerController(TestingAPI) |
| @@ -223,22 +312,29 @@ class BrowserWindowControllerTest : public InProcessBrowserTest { |
| return icon_bottom.y - info_bar_top.y; |
| } |
| - // The traffic lights should always be in front of the content view and the |
| - // tab strip view. Since the traffic lights change across OSX versions, this |
| - // test verifies that the contentView is in the back, and if the tab strip |
| - // view is a sibling, it is directly in front of the content view. |
| - void VerifyTrafficLightZOrder() const { |
| - NSView* contentView = [[controller() window] contentView]; |
| - NSView* rootView = [contentView superview]; |
| - NSArray* subviews = [rootView subviews]; |
| - |
| - EXPECT_EQ([controller() tabStripBackgroundView], |
| - [subviews objectAtIndex:0]); |
| - EXPECT_EQ(contentView, [subviews objectAtIndex:1]); |
| - |
| - NSView* tabStripView = [controller() tabStripView]; |
| - if ([subviews containsObject:tabStripView]) |
| - EXPECT_EQ(tabStripView, [subviews objectAtIndex:2]); |
| + // 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); |
| } |
| private: |
| @@ -500,15 +596,17 @@ IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, |
| IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, TrafficLightZOrder) { |
| // Verify z order immediately after creation. |
| - VerifyTrafficLightZOrder(); |
| + VerifyWindowControlsZOrder(); |
| - // Toggle overlay, then verify z order. |
| + // Verify z order in and out of overlay. |
| [controller() showOverlay]; |
| + VerifyWindowControlsZOrder(); |
| [controller() removeOverlay]; |
| - VerifyTrafficLightZOrder(); |
| + VerifyWindowControlsZOrder(); |
| - // Toggle immersive fullscreen, then verify z order. |
| + // Toggle immersive fullscreen, then verify z order. In immersive fullscreen, |
| + // there are no window controls. |
| [controller() enterImmersiveFullscreen]; |
| [controller() exitImmersiveFullscreen]; |
| - VerifyTrafficLightZOrder(); |
| + VerifyWindowControlsZOrder(); |
| } |