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#include "chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h"
6
7#include "ash/ash_constants.h"
8#include "ash/ash_switches.h"
9#include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
10#include "ash/frame/header_painter.h"
11#include "ash/shell.h"
12#include "ash/wm/maximize_mode/maximize_mode_controller.h"
13#include "base/command_line.h"
14#include "chrome/browser/ui/browser.h"
15#include "chrome/browser/ui/browser_commands.h"
16#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
17#include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h"
18#include "chrome/browser/ui/views/frame/browser_view.h"
19#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
20#include "chrome/browser/ui/views/tabs/tab.h"
21#include "chrome/test/base/in_process_browser_test.h"
22#include "ui/base/hit_test.h"
23#include "ui/compositor/scoped_animation_duration_scale_mode.h"
24#include "ui/views/widget/widget.h"
25
26using views::Widget;
27
28typedef InProcessBrowserTest BrowserNonClientFrameViewAshTest;
29
30IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, NonClientHitTest) {
31  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
32  Widget* widget = browser_view->GetWidget();
33  // We know we're using Ash, so static cast.
34  BrowserNonClientFrameViewAsh* frame_view =
35      static_cast<BrowserNonClientFrameViewAsh*>(
36          widget->non_client_view()->frame_view());
37
38  // Click on the top edge of a restored window hits the top edge resize handle.
39  const int kWindowWidth = 300;
40  const int kWindowHeight = 290;
41  widget->SetBounds(gfx::Rect(10, 10, kWindowWidth, kWindowHeight));
42  gfx::Point top_edge(kWindowWidth / 2, 0);
43  EXPECT_EQ(HTTOP, frame_view->NonClientHitTest(top_edge));
44
45  // Click just below the resize handle hits the caption.
46  gfx::Point below_resize(kWindowWidth / 2, ash::kResizeInsideBoundsSize);
47  EXPECT_EQ(HTCAPTION, frame_view->NonClientHitTest(below_resize));
48
49  // Click in the top edge of a maximized window now hits the client area,
50  // because we want it to fall through to the tab strip and select a tab.
51  widget->Maximize();
52  EXPECT_EQ(HTCLIENT, frame_view->NonClientHitTest(top_edge));
53}
54
55// Test that the frame view does not do any painting in non-immersive
56// fullscreen.
57IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest,
58                       NonImmersiveFullscreen) {
59  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
60  content::WebContents* web_contents = browser_view->GetActiveWebContents();
61  Widget* widget = browser_view->GetWidget();
62  // We know we're using Ash, so static cast.
63  BrowserNonClientFrameViewAsh* frame_view =
64      static_cast<BrowserNonClientFrameViewAsh*>(
65          widget->non_client_view()->frame_view());
66
67  // Frame paints by default.
68  EXPECT_TRUE(frame_view->ShouldPaint());
69
70  // No painting should occur in non-immersive fullscreen. (We enter into tab
71  // fullscreen here because tab fullscreen is non-immersive even on ChromeOS).
72  {
73    // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously.
74    scoped_ptr<FullscreenNotificationObserver> waiter(
75        new FullscreenNotificationObserver());
76    browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
77        web_contents, true);
78    waiter->Wait();
79  }
80  EXPECT_FALSE(browser_view->immersive_mode_controller()->IsEnabled());
81  EXPECT_FALSE(frame_view->ShouldPaint());
82
83  // The client view abuts top of the window.
84  EXPECT_EQ(0, frame_view->GetBoundsForClientView().y());
85
86  // The frame should be painted again when fullscreen is exited and the caption
87  // buttons should be visible.
88  {
89    scoped_ptr<FullscreenNotificationObserver> waiter(
90        new FullscreenNotificationObserver());
91    chrome::ToggleFullscreenMode(browser());
92    waiter->Wait();
93  }
94  EXPECT_TRUE(frame_view->ShouldPaint());
95  EXPECT_TRUE(frame_view->caption_button_container_->visible());
96}
97
98// TODO(zturner): Change this to USE_ASH after fixing the test on Windows.
99#if defined(OS_CHROMEOS)
100IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, ImmersiveFullscreen) {
101  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
102  content::WebContents* web_contents = browser_view->GetActiveWebContents();
103  Widget* widget = browser_view->GetWidget();
104  // We know we're using Ash, so static cast.
105  BrowserNonClientFrameViewAsh* frame_view =
106      static_cast<BrowserNonClientFrameViewAsh*>(
107          widget->non_client_view()->frame_view());
108
109  ImmersiveModeController* immersive_mode_controller =
110      browser_view->immersive_mode_controller();
111  immersive_mode_controller->SetupForTest();
112
113  // Immersive fullscreen starts disabled.
114  ASSERT_FALSE(widget->IsFullscreen());
115  EXPECT_FALSE(immersive_mode_controller->IsEnabled());
116
117  // Frame paints by default.
118  EXPECT_TRUE(frame_view->ShouldPaint());
119  EXPECT_LT(Tab::GetImmersiveHeight(),
120            frame_view->header_painter_->GetHeaderHeightForPainting());
121
122  // Enter both browser fullscreen and tab fullscreen. Entering browser
123  // fullscreen should enable immersive fullscreen.
124  {
125    // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously.
126    scoped_ptr<FullscreenNotificationObserver> waiter(
127        new FullscreenNotificationObserver());
128    chrome::ToggleFullscreenMode(browser());
129    waiter->Wait();
130  }
131  {
132    scoped_ptr<FullscreenNotificationObserver> waiter(
133        new FullscreenNotificationObserver());
134    browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
135        web_contents, true);
136    waiter->Wait();
137  }
138  EXPECT_TRUE(immersive_mode_controller->IsEnabled());
139
140  // An immersive reveal shows the buttons and the top of the frame.
141  scoped_ptr<ImmersiveRevealedLock> revealed_lock(
142      immersive_mode_controller->GetRevealedLock(
143          ImmersiveModeController::ANIMATE_REVEAL_NO));
144  EXPECT_TRUE(immersive_mode_controller->IsRevealed());
145  EXPECT_TRUE(frame_view->ShouldPaint());
146  EXPECT_TRUE(frame_view->caption_button_container_->visible());
147  EXPECT_FALSE(frame_view->UseImmersiveLightbarHeaderStyle());
148
149  // End the reveal. When in both immersive browser fullscreen and tab
150  // fullscreen, the tab lightbars should not be painted.
151  revealed_lock.reset();
152  EXPECT_FALSE(immersive_mode_controller->IsRevealed());
153  EXPECT_FALSE(frame_view->ShouldPaint());
154  EXPECT_EQ(0, frame_view->header_painter_->GetHeaderHeightForPainting());
155
156  // Repeat test but without tab fullscreen. The tab lightbars should now show
157  // when the top-of-window views are not revealed.
158  {
159    scoped_ptr<FullscreenNotificationObserver> waiter(
160        new FullscreenNotificationObserver());
161    browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
162        web_contents, false);
163    waiter->Wait();
164  }
165
166  // Immersive reveal should have same behavior as before.
167  revealed_lock.reset(immersive_mode_controller->GetRevealedLock(
168      ImmersiveModeController::ANIMATE_REVEAL_NO));
169  EXPECT_TRUE(immersive_mode_controller->IsRevealed());
170  EXPECT_TRUE(frame_view->ShouldPaint());
171  EXPECT_TRUE(frame_view->caption_button_container_->visible());
172  EXPECT_FALSE(frame_view->UseImmersiveLightbarHeaderStyle());
173  EXPECT_LT(Tab::GetImmersiveHeight(),
174            frame_view->header_painter_->GetHeaderHeightForPainting());
175
176  // Ending the reveal should hide the caption buttons and the header should
177  // be in the lightbar style.
178  revealed_lock.reset();
179  EXPECT_TRUE(frame_view->ShouldPaint());
180  EXPECT_FALSE(frame_view->caption_button_container_->visible());
181  EXPECT_TRUE(frame_view->UseImmersiveLightbarHeaderStyle());
182  EXPECT_EQ(Tab::GetImmersiveHeight(),
183            frame_view->header_painter_->GetHeaderHeightForPainting());
184
185  // Exiting immersive fullscreen should make the caption buttons and the frame
186  // visible again.
187  {
188    scoped_ptr<FullscreenNotificationObserver> waiter(
189        new FullscreenNotificationObserver());
190    browser_view->ExitFullscreen();
191    waiter->Wait();
192  }
193  EXPECT_FALSE(immersive_mode_controller->IsEnabled());
194  EXPECT_TRUE(frame_view->ShouldPaint());
195  EXPECT_TRUE(frame_view->caption_button_container_->visible());
196  EXPECT_FALSE(frame_view->UseImmersiveLightbarHeaderStyle());
197  EXPECT_LT(Tab::GetImmersiveHeight(),
198            frame_view->header_painter_->GetHeaderHeightForPainting());
199}
200#endif  // defined(OS_CHROMEOS)
201
202// Tests that FrameCaptionButtonContainer has been relaid out in response to
203// maximize mode being toggled.
204IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest,
205                       ToggleMaximizeModeRelayout) {
206  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
207  Widget* widget = browser_view->GetWidget();
208  // We know we're using Ash, so static cast.
209  BrowserNonClientFrameViewAsh* frame_view =
210      static_cast<BrowserNonClientFrameViewAsh*>(
211          widget->non_client_view()->frame_view());
212
213  const gfx::Rect initial = frame_view->caption_button_container_->bounds();
214  ash::Shell::GetInstance()->maximize_mode_controller()->
215      EnableMaximizeModeWindowManager(true);
216  ash::FrameCaptionButtonContainerView::TestApi test(frame_view->
217                                                     caption_button_container_);
218  test.EndAnimations();
219  const gfx::Rect during_maximize = frame_view->caption_button_container_->
220      bounds();
221  EXPECT_GT(initial.width(), during_maximize.width());
222  ash::Shell::GetInstance()->maximize_mode_controller()->
223      EnableMaximizeModeWindowManager(false);
224  test.EndAnimations();
225  const gfx::Rect after_restore = frame_view->caption_button_container_->
226      bounds();
227  EXPECT_EQ(initial, after_restore);
228}
229