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 3// found in the LICENSE file. 4 5#import "chrome/browser/ui/cocoa/browser_window_controller.h" 6 7#import "base/mac/mac_util.h" 8#include "base/mac/sdk_forward_declarations.h" 9#include "base/run_loop.h" 10#include "base/strings/utf_string_conversions.h" 11#include "chrome/app/chrome_command_ids.h" 12#include "chrome/browser/browser_process.h" 13#include "chrome/browser/devtools/devtools_window_testing.h" 14#include "chrome/browser/infobars/infobar_service.h" 15#include "chrome/browser/infobars/simple_alert_infobar_delegate.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/browser/profiles/profile_manager.h" 18#include "chrome/browser/ui/bookmarks/bookmark_utils.h" 19#include "chrome/browser/ui/browser.h" 20#include "chrome/browser/ui/browser_commands.h" 21#include "chrome/browser/ui/browser_list.h" 22#include "chrome/browser/ui/browser_window.h" 23#include "chrome/browser/ui/cocoa/browser_window_cocoa.h" 24#import "chrome/browser/ui/cocoa/browser_window_controller_private.h" 25#import "chrome/browser/ui/cocoa/fast_resize_view.h" 26#import "chrome/browser/ui/cocoa/history_overlay_controller.h" 27#import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" 28#import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" 29#import "chrome/browser/ui/cocoa/infobars/infobar_controller.h" 30#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" 31#import "chrome/browser/ui/cocoa/profiles/avatar_base_controller.h" 32#import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" 33#import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" 34#include "chrome/browser/ui/extensions/application_launch.h" 35#include "chrome/browser/ui/find_bar/find_bar.h" 36#include "chrome/browser/ui/find_bar/find_bar_controller.h" 37#include "chrome/browser/ui/tabs/tab_strip_model.h" 38#include "chrome/test/base/in_process_browser_test.h" 39#include "chrome/test/base/testing_profile.h" 40#include "content/public/browser/web_contents.h" 41#include "content/public/test/test_utils.h" 42#import "testing/gtest_mac.h" 43#import "third_party/ocmock/OCMock/OCMock.h" 44#import "ui/base/cocoa/nsview_additions.h" 45#include "ui/gfx/animation/slide_animation.h" 46 47namespace { 48 49// Creates a mock of an NSWindow that has the given |frame|. 50id MockWindowWithFrame(NSRect frame) { 51 id window = [OCMockObject mockForClass:[NSWindow class]]; 52 NSValue* window_frame = 53 [NSValue valueWithBytes:&frame objCType:@encode(NSRect)]; 54 [[[window stub] andReturnValue:window_frame] frame]; 55 return window; 56} 57 58void CreateProfileCallback(const base::Closure& quit_closure, 59 Profile* profile, 60 Profile::CreateStatus status) { 61 EXPECT_TRUE(profile); 62 EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status); 63 EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status); 64 // This will be called multiple times. Wait until the profile is initialized 65 // fully to quit the loop. 66 if (status == Profile::CREATE_STATUS_INITIALIZED) 67 quit_closure.Run(); 68} 69 70enum ViewID { 71 VIEW_ID_TOOLBAR, 72 VIEW_ID_BOOKMARK_BAR, 73 VIEW_ID_INFO_BAR, 74 VIEW_ID_FIND_BAR, 75 VIEW_ID_DOWNLOAD_SHELF, 76 VIEW_ID_TAB_CONTENT_AREA, 77 VIEW_ID_FULLSCREEN_FLOATING_BAR, 78 VIEW_ID_COUNT, 79}; 80 81} // namespace 82 83@interface InfoBarContainerController(TestingAPI) 84- (BOOL)isTopInfoBarAnimationRunning; 85@end 86 87@implementation InfoBarContainerController(TestingAPI) 88- (BOOL)isTopInfoBarAnimationRunning { 89 InfoBarController* infoBarController = [infobarControllers_ objectAtIndex:0]; 90 if (infoBarController) { 91 const gfx::SlideAnimation& infobarAnimation = 92 static_cast<const InfoBarCocoa*>( 93 infoBarController.infobar)->animation(); 94 return infobarAnimation.is_animating(); 95 } 96 return NO; 97} 98@end 99 100class BrowserWindowControllerTest : public InProcessBrowserTest { 101 public: 102 BrowserWindowControllerTest() : InProcessBrowserTest() { 103 } 104 105 virtual void SetUpOnMainThread() OVERRIDE { 106 [[controller() bookmarkBarController] setStateAnimationsEnabled:NO]; 107 [[controller() bookmarkBarController] setInnerContentAnimationsEnabled:NO]; 108 } 109 110 BrowserWindowController* controller() const { 111 return [BrowserWindowController browserWindowControllerForWindow: 112 browser()->window()->GetNativeWindow()]; 113 } 114 115 static void ShowInfoBar(Browser* browser) { 116 SimpleAlertInfoBarDelegate::Create( 117 InfoBarService::FromWebContents( 118 browser->tab_strip_model()->GetActiveWebContents()), 119 0, base::string16(), false); 120 } 121 122 NSView* GetViewWithID(ViewID view_id) const { 123 switch (view_id) { 124 case VIEW_ID_FULLSCREEN_FLOATING_BAR: 125 return [controller() floatingBarBackingView]; 126 case VIEW_ID_TOOLBAR: 127 return [[controller() toolbarController] view]; 128 case VIEW_ID_BOOKMARK_BAR: 129 return [[controller() bookmarkBarController] view]; 130 case VIEW_ID_INFO_BAR: 131 return [[controller() infoBarContainerController] view]; 132 case VIEW_ID_FIND_BAR: 133 return [[controller() findBarCocoaController] view]; 134 case VIEW_ID_DOWNLOAD_SHELF: 135 return [[controller() downloadShelf] view]; 136 case VIEW_ID_TAB_CONTENT_AREA: 137 return [controller() tabContentArea]; 138 default: 139 NOTREACHED(); 140 return nil; 141 } 142 } 143 144 void VerifyZOrder(const std::vector<ViewID>& view_list) const { 145 std::vector<NSView*> visible_views; 146 for (size_t i = 0; i < view_list.size(); ++i) { 147 NSView* view = GetViewWithID(view_list[i]); 148 if ([view superview]) 149 visible_views.push_back(view); 150 } 151 152 for (size_t i = 0; i < visible_views.size() - 1; ++i) { 153 NSView* bottom_view = visible_views[i]; 154 NSView* top_view = visible_views[i + 1]; 155 156 EXPECT_NSEQ([bottom_view superview], [top_view superview]); 157 EXPECT_TRUE([bottom_view cr_isBelowView:top_view]); 158 } 159 160 // Views not in |view_list| must either be nil or not parented. 161 for (size_t i = 0; i < VIEW_ID_COUNT; ++i) { 162 if (std::find(view_list.begin(), view_list.end(), i) == view_list.end()) { 163 NSView* view = GetViewWithID(static_cast<ViewID>(i)); 164 EXPECT_TRUE(!view || ![view superview]); 165 } 166 } 167 } 168 169 CGFloat GetViewHeight(ViewID viewID) const { 170 CGFloat height = NSHeight([GetViewWithID(viewID) frame]); 171 if (viewID == VIEW_ID_INFO_BAR) { 172 height -= [[controller() infoBarContainerController] 173 overlappingTipHeight]; 174 } 175 return height; 176 } 177 178 static void CheckTopInfoBarAnimation( 179 InfoBarContainerController* info_bar_container_controller, 180 const base::Closure& quit_task) { 181 if (![info_bar_container_controller isTopInfoBarAnimationRunning]) 182 quit_task.Run(); 183 } 184 185 static void CheckBookmarkBarAnimation( 186 BookmarkBarController* bookmark_bar_controller, 187 const base::Closure& quit_task) { 188 if (![bookmark_bar_controller isAnimationRunning]) 189 quit_task.Run(); 190 } 191 192 void WaitForTopInfoBarAnimationToFinish() { 193 scoped_refptr<content::MessageLoopRunner> runner = 194 new content::MessageLoopRunner; 195 196 base::Timer timer(false, true); 197 timer.Start( 198 FROM_HERE, 199 base::TimeDelta::FromMilliseconds(15), 200 base::Bind(&CheckTopInfoBarAnimation, 201 [controller() infoBarContainerController], 202 runner->QuitClosure())); 203 runner->Run(); 204 } 205 206 void WaitForBookmarkBarAnimationToFinish() { 207 scoped_refptr<content::MessageLoopRunner> runner = 208 new content::MessageLoopRunner; 209 210 base::Timer timer(false, true); 211 timer.Start( 212 FROM_HERE, 213 base::TimeDelta::FromMilliseconds(15), 214 base::Bind(&CheckBookmarkBarAnimation, 215 [controller() bookmarkBarController], 216 runner->QuitClosure())); 217 runner->Run(); 218 } 219 220 NSInteger GetExpectedTopInfoBarTipHeight() { 221 InfoBarContainerController* info_bar_container_controller = 222 [controller() infoBarContainerController]; 223 CGFloat overlapping_tip_height = 224 [info_bar_container_controller overlappingTipHeight]; 225 LocationBarViewMac* location_bar_view = [controller() locationBarBridge]; 226 NSPoint icon_bottom = location_bar_view->GetPageInfoBubblePoint(); 227 228 NSPoint info_bar_top = NSMakePoint(0, 229 NSHeight([info_bar_container_controller view].frame) - 230 overlapping_tip_height); 231 info_bar_top = [[info_bar_container_controller view] 232 convertPoint:info_bar_top toView:nil]; 233 return icon_bottom.y - info_bar_top.y; 234 } 235 236 // The traffic lights should always be in front of the content view and the 237 // tab strip view. Since the traffic lights change across OSX versions, this 238 // test verifies that the contentView is in the back, and if the tab strip 239 // view is a sibling, it is directly in front of the content view. 240 void VerifyTrafficLightZOrder() const { 241 NSView* contentView = [[controller() window] contentView]; 242 NSView* rootView = [contentView superview]; 243 EXPECT_EQ(contentView, [[rootView subviews] objectAtIndex:0]); 244 245 NSView* tabStripView = [controller() tabStripView]; 246 if ([[rootView subviews] containsObject:tabStripView]) 247 EXPECT_EQ(tabStripView, [[rootView subviews] objectAtIndex:1]); 248 } 249 250 private: 251 DISALLOW_COPY_AND_ASSIGN(BrowserWindowControllerTest); 252}; 253 254// Tests that adding the first profile moves the Lion fullscreen button over 255// correctly. 256// DISABLED_ because it regularly times out: http://crbug.com/159002. 257IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 258 DISABLED_ProfileAvatarFullscreenButton) { 259 if (base::mac::IsOSSnowLeopard()) 260 return; 261 262 // Initialize the locals. 263 ProfileManager* profile_manager = g_browser_process->profile_manager(); 264 ASSERT_TRUE(profile_manager); 265 266 NSWindow* window = browser()->window()->GetNativeWindow(); 267 ASSERT_TRUE(window); 268 269 // With only one profile, the fullscreen button should be visible, but the 270 // avatar button should not. 271 EXPECT_EQ(1u, profile_manager->GetNumberOfProfiles()); 272 273 NSButton* fullscreen_button = 274 [window standardWindowButton:NSWindowFullScreenButton]; 275 EXPECT_TRUE(fullscreen_button); 276 EXPECT_FALSE([fullscreen_button isHidden]); 277 278 AvatarBaseController* avatar_controller = 279 [controller() avatarButtonController]; 280 NSView* avatar = [avatar_controller view]; 281 EXPECT_TRUE(avatar); 282 EXPECT_TRUE([avatar isHidden]); 283 284 // Create a profile asynchronously and run the loop until its creation 285 // is complete. 286 base::RunLoop run_loop; 287 288 ProfileManager::CreateCallback create_callback = 289 base::Bind(&CreateProfileCallback, run_loop.QuitClosure()); 290 profile_manager->CreateProfileAsync( 291 profile_manager->user_data_dir().Append("test"), 292 create_callback, 293 base::ASCIIToUTF16("avatar_test"), 294 base::string16(), 295 std::string()); 296 297 run_loop.Run(); 298 299 // There should now be two profiles, and the avatar button and fullscreen 300 // button are both visible. 301 EXPECT_EQ(2u, profile_manager->GetNumberOfProfiles()); 302 EXPECT_FALSE([avatar isHidden]); 303 EXPECT_FALSE([fullscreen_button isHidden]); 304 EXPECT_EQ([avatar window], [fullscreen_button window]); 305 306 // Make sure the visual order of the buttons is correct and that they don't 307 // overlap. 308 NSRect avatar_frame = [avatar frame]; 309 NSRect fullscreen_frame = [fullscreen_button frame]; 310 311 EXPECT_LT(NSMinX(fullscreen_frame), NSMinX(avatar_frame)); 312 EXPECT_LT(NSMaxX(fullscreen_frame), NSMinX(avatar_frame)); 313} 314 315// Verify that in non-Instant normal mode that the find bar and download shelf 316// are above the content area. Everything else should be below it. 317IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, ZOrderNormal) { 318 browser()->GetFindBarController(); // add find bar 319 320 std::vector<ViewID> view_list; 321 view_list.push_back(VIEW_ID_DOWNLOAD_SHELF); 322 view_list.push_back(VIEW_ID_BOOKMARK_BAR); 323 view_list.push_back(VIEW_ID_TOOLBAR); 324 view_list.push_back(VIEW_ID_INFO_BAR); 325 view_list.push_back(VIEW_ID_TAB_CONTENT_AREA); 326 view_list.push_back(VIEW_ID_FIND_BAR); 327 VerifyZOrder(view_list); 328 329 [controller() showOverlay]; 330 [controller() removeOverlay]; 331 VerifyZOrder(view_list); 332 333 [controller() enterImmersiveFullscreen]; 334 [controller() exitImmersiveFullscreen]; 335 VerifyZOrder(view_list); 336} 337 338// Verify that in non-Instant presentation mode that the info bar is below the 339// content are and everything else is above it. 340// DISABLED due to flaky failures on trybots. http://crbug.com/178778 341IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 342 DISABLED_ZOrderPresentationMode) { 343 chrome::ToggleFullscreenMode(browser()); 344 browser()->GetFindBarController(); // add find bar 345 346 std::vector<ViewID> view_list; 347 view_list.push_back(VIEW_ID_INFO_BAR); 348 view_list.push_back(VIEW_ID_TAB_CONTENT_AREA); 349 view_list.push_back(VIEW_ID_FULLSCREEN_FLOATING_BAR); 350 view_list.push_back(VIEW_ID_BOOKMARK_BAR); 351 view_list.push_back(VIEW_ID_TOOLBAR); 352 view_list.push_back(VIEW_ID_FIND_BAR); 353 view_list.push_back(VIEW_ID_DOWNLOAD_SHELF); 354 VerifyZOrder(view_list); 355} 356 357// Verify that if the fullscreen floating bar view is below the tab content area 358// then calling |updateSubviewZOrder:| will correctly move back above. 359IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 360 DISABLED_FloatingBarBelowContentView) { 361 // TODO(kbr): re-enable: http://crbug.com/222296 362 if (base::mac::IsOSMountainLionOrLater()) 363 return; 364 365 chrome::ToggleFullscreenMode(browser()); 366 367 NSView* fullscreen_floating_bar = 368 GetViewWithID(VIEW_ID_FULLSCREEN_FLOATING_BAR); 369 [fullscreen_floating_bar removeFromSuperview]; 370 [[[controller() window] contentView] addSubview:fullscreen_floating_bar 371 positioned:NSWindowBelow 372 relativeTo:nil]; 373 [controller() updateSubviewZOrder]; 374 375 std::vector<ViewID> view_list; 376 view_list.push_back(VIEW_ID_INFO_BAR); 377 view_list.push_back(VIEW_ID_TAB_CONTENT_AREA); 378 view_list.push_back(VIEW_ID_FULLSCREEN_FLOATING_BAR); 379 view_list.push_back(VIEW_ID_BOOKMARK_BAR); 380 view_list.push_back(VIEW_ID_TOOLBAR); 381 view_list.push_back(VIEW_ID_DOWNLOAD_SHELF); 382 VerifyZOrder(view_list); 383} 384 385IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, SheetPosition) { 386 ASSERT_TRUE([controller() isKindOfClass:[BrowserWindowController class]]); 387 EXPECT_TRUE([controller() isTabbedWindow]); 388 EXPECT_TRUE([controller() hasTabStrip]); 389 EXPECT_FALSE([controller() hasTitleBar]); 390 EXPECT_TRUE([controller() hasToolbar]); 391 EXPECT_FALSE([controller() isBookmarkBarVisible]); 392 393 NSRect defaultAlertFrame = NSMakeRect(0, 0, 300, 200); 394 id sheet = MockWindowWithFrame(defaultAlertFrame); 395 NSWindow* window = browser()->window()->GetNativeWindow(); 396 NSRect alertFrame = [controller() window:window 397 willPositionSheet:nil 398 usingRect:defaultAlertFrame]; 399 NSRect toolbarFrame = [[[controller() toolbarController] view] frame]; 400 EXPECT_EQ(NSMinY(alertFrame), NSMinY(toolbarFrame)); 401 402 // Open sheet with normal browser window, persistent bookmark bar. 403 chrome::ToggleBookmarkBarWhenVisible(browser()->profile()); 404 EXPECT_TRUE([controller() isBookmarkBarVisible]); 405 alertFrame = [controller() window:window 406 willPositionSheet:sheet 407 usingRect:defaultAlertFrame]; 408 NSRect bookmarkBarFrame = [[[controller() bookmarkBarController] view] frame]; 409 EXPECT_EQ(NSMinY(alertFrame), NSMinY(bookmarkBarFrame)); 410 411 // If the sheet is too large, it should be positioned at the top of the 412 // window. 413 defaultAlertFrame = NSMakeRect(0, 0, 300, 2000); 414 sheet = MockWindowWithFrame(defaultAlertFrame); 415 alertFrame = [controller() window:window 416 willPositionSheet:sheet 417 usingRect:defaultAlertFrame]; 418 EXPECT_EQ(NSMinY(alertFrame), NSHeight([window frame])); 419 420 // Reset the sheet's size. 421 defaultAlertFrame = NSMakeRect(0, 0, 300, 200); 422 sheet = MockWindowWithFrame(defaultAlertFrame); 423 424 // Make sure the profile does not have the bookmark visible so that 425 // we'll create the shortcut window without the bookmark bar. 426 chrome::ToggleBookmarkBarWhenVisible(browser()->profile()); 427 // Open application mode window. 428 OpenAppShortcutWindow(browser()->profile(), GURL("about:blank")); 429 Browser* popup_browser = BrowserList::GetInstance( 430 chrome::GetActiveDesktop())->GetLastActive(); 431 NSWindow* popupWindow = popup_browser->window()->GetNativeWindow(); 432 BrowserWindowController* popupController = 433 [BrowserWindowController browserWindowControllerForWindow:popupWindow]; 434 ASSERT_TRUE([popupController isKindOfClass:[BrowserWindowController class]]); 435 EXPECT_FALSE([popupController isTabbedWindow]); 436 EXPECT_FALSE([popupController hasTabStrip]); 437 EXPECT_TRUE([popupController hasTitleBar]); 438 EXPECT_FALSE([popupController isBookmarkBarVisible]); 439 EXPECT_FALSE([popupController hasToolbar]); 440 441 // Open sheet in an application window. 442 [popupController showWindow:nil]; 443 alertFrame = [popupController window:popupWindow 444 willPositionSheet:sheet 445 usingRect:defaultAlertFrame]; 446 EXPECT_EQ(NSMinY(alertFrame), 447 NSHeight([[popupWindow contentView] frame]) - 448 defaultAlertFrame.size.height); 449 450 // Close the application window. 451 popup_browser->tab_strip_model()->CloseSelectedTabs(); 452 [popupController close]; 453} 454 455// Verify that the info bar tip is hidden when the toolbar is not visible. 456IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 457 InfoBarTipHiddenForWindowWithoutToolbar) { 458 ShowInfoBar(browser()); 459 EXPECT_FALSE( 460 [[controller() infoBarContainerController] shouldSuppressTopInfoBarTip]); 461 462 OpenAppShortcutWindow(browser()->profile(), GURL("about:blank")); 463 Browser* popup_browser = BrowserList::GetInstance( 464 chrome::HOST_DESKTOP_TYPE_NATIVE)->GetLastActive(); 465 NSWindow* popupWindow = popup_browser->window()->GetNativeWindow(); 466 BrowserWindowController* popupController = 467 [BrowserWindowController browserWindowControllerForWindow:popupWindow]; 468 EXPECT_FALSE([popupController hasToolbar]); 469 470 // Show infobar for controller. 471 ShowInfoBar(popup_browser); 472 EXPECT_TRUE( 473 [[popupController infoBarContainerController] 474 shouldSuppressTopInfoBarTip]); 475} 476 477// Tests that status bubble's base frame does move when devTools are docked. 478IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 479 StatusBubblePositioning) { 480 NSPoint origin = [controller() statusBubbleBaseFrame].origin; 481 482 DevToolsWindow* devtools_window = 483 DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true); 484 DevToolsWindowTesting::Get(devtools_window)->SetInspectedPageBounds( 485 gfx::Rect(10, 10, 100, 100)); 486 487 NSPoint originWithDevTools = [controller() statusBubbleBaseFrame].origin; 488 EXPECT_FALSE(NSEqualPoints(origin, originWithDevTools)); 489 490 DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window); 491} 492 493// Tests that top infobar tip is streched when bookmark bar becomes SHOWN/HIDDEN 494IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 495 InfoBarTipStretchedWhenBookmarkBarStatusChanged) { 496 EXPECT_FALSE([controller() isBookmarkBarVisible]); 497 ShowInfoBar(browser()); 498 // The infobar tip is animated during the infobar is being added, wait until 499 // it completes. 500 WaitForTopInfoBarAnimationToFinish(); 501 502 EXPECT_FALSE([[controller() infoBarContainerController] 503 shouldSuppressTopInfoBarTip]); 504 505 NSInteger max_tip_height = infobars::InfoBar::kMaximumArrowTargetHeight + 506 infobars::InfoBar::kSeparatorLineHeight; 507 508 chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR); 509 WaitForBookmarkBarAnimationToFinish(); 510 EXPECT_TRUE([controller() isBookmarkBarVisible]); 511 EXPECT_EQ(std::min(GetExpectedTopInfoBarTipHeight(), max_tip_height), 512 [[controller() infoBarContainerController] overlappingTipHeight]); 513 514 chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_BAR); 515 WaitForBookmarkBarAnimationToFinish(); 516 EXPECT_FALSE([controller() isBookmarkBarVisible]); 517 EXPECT_EQ(std::min(GetExpectedTopInfoBarTipHeight(), max_tip_height), 518 [[controller() infoBarContainerController] overlappingTipHeight]); 519} 520 521IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, TrafficLightZOrder) { 522 // Verify z order immediately after creation. 523 VerifyTrafficLightZOrder(); 524 525 // Toggle overlay, then verify z order. 526 [controller() showOverlay]; 527 [controller() removeOverlay]; 528 VerifyTrafficLightZOrder(); 529 530 // Toggle immersive fullscreen, then verify z order. 531 [controller() enterImmersiveFullscreen]; 532 [controller() exitImmersiveFullscreen]; 533 VerifyTrafficLightZOrder(); 534} 535