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.
5 #include "base/command_line.h"
6 #include "build/build_config.h"
7 #include "chrome/browser/ui/browser.h"
8 #include "chrome/browser/ui/browser_tabstrip.h"
9 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
10 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
11 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_state_test.h"
12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
13 #include "chrome/test/base/browser_with_test_window_test.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/common/url_constants.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 // The FullscreenControllerStateUnitTest unit test suite exhastively tests
19 // the FullscreenController through all permutations of events. The behavior
20 // of the BrowserWindow is mocked via FullscreenControllerTestWindow.
23 // FullscreenControllerTestWindow ----------------------------------------------
25 // A BrowserWindow used for testing FullscreenController. The behavior of this
26 // mock is verfied manually by running FullscreenControllerStateInteractiveTest.
27 class FullscreenControllerTestWindow
: public TestBrowserWindow
,
28 ExclusiveAccessContext
{
30 // Simulate the window state with an enumeration.
34 // No TO_ state for METRO_SNAP, the windows implementation is synchronous.
40 FullscreenControllerTestWindow();
41 ~FullscreenControllerTestWindow() override
{}
43 // BrowserWindow Interface:
44 void EnterFullscreen(const GURL
& url
,
45 ExclusiveAccessBubbleType type
,
46 bool with_toolbar
) override
;
47 void ExitFullscreen() override
;
48 bool ShouldHideUIForFullscreen() const override
;
49 bool IsFullscreen() const override
;
50 bool SupportsFullscreenWithToolbar() const override
;
51 void UpdateFullscreenWithToolbar(bool with_toolbar
) override
;
52 bool IsFullscreenWithToolbar() const override
;
54 void SetMetroSnapMode(bool enable
) override
;
55 bool IsInMetroSnapMode() const override
;
57 static const char* GetWindowStateString(WindowState state
);
58 WindowState
state() const { return state_
; }
59 void set_browser(Browser
* browser
) { browser_
= browser
; }
60 ExclusiveAccessContext
* GetExclusiveAccessContext() override
;
62 // ExclusiveAccessContext Interface:
63 Profile
* GetProfile() override
;
64 content::WebContents
* GetActiveWebContents() override
;
65 void HideDownloadShelf() override
;
66 void UnhideDownloadShelf() override
;
67 void UpdateExclusiveAccessExitBubbleContent(
69 ExclusiveAccessBubbleType bubble_type
) override
;
71 // Simulates the window changing state.
72 void ChangeWindowFullscreenState();
75 // Enters fullscreen with |new_mac_with_toolbar_mode|.
76 void EnterFullscreen(bool new_mac_with_toolbar_mode
);
78 // Returns true if ChangeWindowFullscreenState() should be called as a result
79 // of updating the current fullscreen state to the passed in state.
80 bool IsTransitionReentrant(bool new_fullscreen
,
81 bool new_mac_with_toolbar_mode
);
84 bool mac_with_toolbar_mode_
;
88 FullscreenControllerTestWindow::FullscreenControllerTestWindow()
90 mac_with_toolbar_mode_(false),
94 void FullscreenControllerTestWindow::EnterFullscreen(
96 ExclusiveAccessBubbleType type
,
98 EnterFullscreen(with_toolbar
);
101 void FullscreenControllerTestWindow::ExitFullscreen() {
102 if (IsFullscreen()) {
104 mac_with_toolbar_mode_
= false;
106 if (IsTransitionReentrant(false, false))
107 ChangeWindowFullscreenState();
111 bool FullscreenControllerTestWindow::ShouldHideUIForFullscreen() const {
112 return IsFullscreen();
115 bool FullscreenControllerTestWindow::IsFullscreen() const {
116 #if defined(OS_MACOSX)
117 return state_
== FULLSCREEN
|| state_
== TO_FULLSCREEN
;
119 return state_
== FULLSCREEN
|| state_
== TO_NORMAL
;
123 bool FullscreenControllerTestWindow::SupportsFullscreenWithToolbar() const {
124 #if defined(OS_MACOSX)
131 void FullscreenControllerTestWindow::UpdateFullscreenWithToolbar(
133 EnterFullscreen(with_toolbar
);
136 bool FullscreenControllerTestWindow::IsFullscreenWithToolbar() const {
137 return IsFullscreen() && mac_with_toolbar_mode_
;
141 void FullscreenControllerTestWindow::SetMetroSnapMode(bool enable
) {
142 if (enable
!= IsInMetroSnapMode())
143 state_
= enable
? METRO_SNAP
: NORMAL
;
145 if (FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant())
146 ChangeWindowFullscreenState();
149 bool FullscreenControllerTestWindow::IsInMetroSnapMode() const {
150 return state_
== METRO_SNAP
;
155 const char* FullscreenControllerTestWindow::GetWindowStateString(
158 ENUM_TO_STRING(NORMAL
);
159 ENUM_TO_STRING(FULLSCREEN
);
160 ENUM_TO_STRING(METRO_SNAP
);
161 ENUM_TO_STRING(TO_FULLSCREEN
);
162 ENUM_TO_STRING(TO_NORMAL
);
164 NOTREACHED() << "No string for state " << state
;
165 return "WindowState-Unknown";
169 void FullscreenControllerTestWindow::ChangeWindowFullscreenState() {
170 // Most states result in "no operation" intentionally. The tests
171 // assume that all possible states and event pairs can be tested, even
172 // though window managers will not generate all of these.
173 if (state_
== TO_FULLSCREEN
)
175 else if (state_
== TO_NORMAL
)
178 // Emit a change event from every state to ensure the Fullscreen Controller
179 // handles it in all circumstances.
180 browser_
->WindowFullscreenStateChanged();
183 void FullscreenControllerTestWindow::EnterFullscreen(
184 bool new_mac_with_toolbar_mode
) {
185 bool reentrant
= IsTransitionReentrant(true, new_mac_with_toolbar_mode
);
187 mac_with_toolbar_mode_
= new_mac_with_toolbar_mode
;
189 state_
= TO_FULLSCREEN
;
192 ChangeWindowFullscreenState();
195 bool FullscreenControllerTestWindow::IsTransitionReentrant(
197 bool new_mac_with_toolbar_mode
) {
198 #if defined(OS_MACOSX)
199 bool mac_with_toolbar_mode_changed
=
200 new_mac_with_toolbar_mode
!= IsFullscreenWithToolbar();
202 bool mac_with_toolbar_mode_changed
= false;
204 bool fullscreen_changed
= (new_fullscreen
!= IsFullscreen());
206 if (!fullscreen_changed
&& !mac_with_toolbar_mode_changed
)
209 if (FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant())
212 // BrowserWindowCocoa::EnterFullscreen() and
213 // BrowserWindowCocoa::EnterFullscreenWithToolbar() are reentrant when
214 // switching between fullscreen with chrome and fullscreen without chrome.
215 return state_
== FULLSCREEN
&&
216 !fullscreen_changed
&&
217 mac_with_toolbar_mode_changed
;
220 ExclusiveAccessContext
*
221 FullscreenControllerTestWindow::GetExclusiveAccessContext() {
225 Profile
* FullscreenControllerTestWindow::GetProfile() {
226 return browser_
->profile();
229 content::WebContents
* FullscreenControllerTestWindow::GetActiveWebContents() {
230 return browser_
->tab_strip_model()->GetActiveWebContents();
233 void FullscreenControllerTestWindow::UnhideDownloadShelf() {
234 GetDownloadShelf()->Unhide();
237 void FullscreenControllerTestWindow::HideDownloadShelf() {
238 GetDownloadShelf()->Hide();
241 void FullscreenControllerTestWindow::UpdateExclusiveAccessExitBubbleContent(
243 ExclusiveAccessBubbleType bubble_type
) {
244 TestBrowserWindow::UpdateExclusiveAccessExitBubbleContent(url
, bubble_type
);
247 // FullscreenControllerStateUnitTest -------------------------------------------
249 // Unit test fixture testing Fullscreen Controller through its states. Most of
250 // the test logic comes from FullscreenControllerStateTest.
251 class FullscreenControllerStateUnitTest
: public BrowserWithTestWindowTest
,
252 public FullscreenControllerStateTest
{
254 FullscreenControllerStateUnitTest();
256 // FullscreenControllerStateTest:
257 void SetUp() override
;
258 BrowserWindow
* CreateBrowserWindow() override
;
259 void ChangeWindowFullscreenState() override
;
260 const char* GetWindowStateString() override
;
261 void VerifyWindowState() override
;
264 // FullscreenControllerStateTest:
265 bool ShouldSkipStateAndEventPair(State state
, Event event
) override
;
266 Browser
* GetBrowser() override
;
267 FullscreenControllerTestWindow
* window_
;
270 FullscreenControllerStateUnitTest::FullscreenControllerStateUnitTest()
274 void FullscreenControllerStateUnitTest::SetUp() {
275 BrowserWithTestWindowTest::SetUp();
276 window_
->set_browser(browser());
279 BrowserWindow
* FullscreenControllerStateUnitTest::CreateBrowserWindow() {
280 window_
= new FullscreenControllerTestWindow();
281 return window_
; // BrowserWithTestWindowTest takes ownership.
284 void FullscreenControllerStateUnitTest::ChangeWindowFullscreenState() {
285 window_
->ChangeWindowFullscreenState();
288 const char* FullscreenControllerStateUnitTest::GetWindowStateString() {
289 return FullscreenControllerTestWindow::GetWindowStateString(window_
->state());
292 void FullscreenControllerStateUnitTest::VerifyWindowState() {
295 EXPECT_EQ(FullscreenControllerTestWindow::NORMAL
,
296 window_
->state()) << GetAndClearDebugLog();
299 case STATE_BROWSER_FULLSCREEN_NO_CHROME
:
300 case STATE_BROWSER_FULLSCREEN_WITH_CHROME
:
301 case STATE_TAB_FULLSCREEN
:
302 case STATE_TAB_BROWSER_FULLSCREEN
:
303 case STATE_TAB_BROWSER_FULLSCREEN_CHROME
:
304 EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN
,
305 window_
->state()) << GetAndClearDebugLog();
309 case STATE_METRO_SNAP
:
310 EXPECT_EQ(FullscreenControllerTestWindow::METRO_SNAP
,
311 window_
->state()) << GetAndClearDebugLog();
315 case STATE_TO_NORMAL
:
316 EXPECT_EQ(FullscreenControllerTestWindow::TO_NORMAL
,
317 window_
->state()) << GetAndClearDebugLog();
320 case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
:
321 case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME
:
322 case STATE_TO_TAB_FULLSCREEN
:
323 EXPECT_EQ(FullscreenControllerTestWindow::TO_FULLSCREEN
,
324 window_
->state()) << GetAndClearDebugLog();
328 NOTREACHED() << GetAndClearDebugLog();
331 FullscreenControllerStateTest::VerifyWindowState();
334 bool FullscreenControllerStateUnitTest::ShouldSkipStateAndEventPair(
335 State state
, Event event
) {
336 #if defined(OS_MACOSX)
337 // TODO(scheib) Toggle, Window Event, Toggle, Toggle on Mac as exposed by
338 // test *.STATE_TO_NORMAL__TOGGLE_FULLSCREEN runs interactively and exits to
339 // Normal. This doesn't appear to be the desired result, and would add
340 // too much complexity to mimic in our simple FullscreenControllerTestWindow.
341 // http://crbug.com/156968
342 if ((state
== STATE_TO_NORMAL
||
343 state
== STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
||
344 state
== STATE_TO_TAB_FULLSCREEN
) &&
345 event
== TOGGLE_FULLSCREEN
)
349 return FullscreenControllerStateTest::ShouldSkipStateAndEventPair(state
,
353 Browser
* FullscreenControllerStateUnitTest::GetBrowser() {
354 return BrowserWithTestWindowTest::browser();
357 // Soak tests ------------------------------------------------------------------
359 // Tests all states with all permutations of multiple events to detect lingering
360 // state issues that would bleed over to other states.
361 // I.E. for each state test all combinations of events E1, E2, E3.
363 // This produces coverage for event sequences that may happen normally but
364 // would not be exposed by traversing to each state via TransitionToState().
365 // TransitionToState() always takes the same path even when multiple paths
367 TEST_F(FullscreenControllerStateUnitTest
, TransitionsForEachState
) {
368 // A tab is needed for tab fullscreen.
369 AddTab(browser(), GURL(url::kAboutBlankURL
));
370 TestTransitionsForEachState();
371 // Progress of test can be examined via LOG(INFO) << GetAndClearDebugLog();
375 // Individual tests for each pair of state and event ---------------------------
377 #define TEST_EVENT(state, event) \
378 TEST_F(FullscreenControllerStateUnitTest, state##__##event) { \
379 AddTab(browser(), GURL(url::kAboutBlankURL)); \
380 ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event)) \
381 << GetAndClearDebugLog(); \
383 // Progress of tests can be examined by inserting the following line:
384 // LOG(INFO) << GetAndClearDebugLog(); }
386 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_state_tests.h"
389 // Specific one-off tests for known issues -------------------------------------
391 // TODO(scheib) Toggling Tab fullscreen while pending Tab or
392 // Browser fullscreen is broken currently http://crbug.com/154196
393 TEST_F(FullscreenControllerStateUnitTest
,
394 DISABLED_ToggleTabWhenPendingBrowser
) {
395 // Only possible without reentrancy.
396 if (FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant())
398 AddTab(browser(), GURL(url::kAboutBlankURL
));
399 ASSERT_NO_FATAL_FAILURE(
400 TransitionToState(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME
))
401 << GetAndClearDebugLog();
403 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
)) << GetAndClearDebugLog();
404 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
)) << GetAndClearDebugLog();
405 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
)) << GetAndClearDebugLog();
408 // TODO(scheib) Toggling Tab fullscreen while pending Tab or
409 // Browser fullscreen is broken currently http://crbug.com/154196
410 TEST_F(FullscreenControllerStateUnitTest
, DISABLED_ToggleTabWhenPendingTab
) {
411 // Only possible without reentrancy.
412 if (FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant())
414 AddTab(browser(), GURL(url::kAboutBlankURL
));
415 ASSERT_NO_FATAL_FAILURE(
416 TransitionToState(STATE_TO_TAB_FULLSCREEN
))
417 << GetAndClearDebugLog();
419 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
)) << GetAndClearDebugLog();
420 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
)) << GetAndClearDebugLog();
421 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
)) << GetAndClearDebugLog();
424 // Debugging utility: Display the transition tables. Intentionally disabled
425 TEST_F(FullscreenControllerStateUnitTest
, DISABLED_DebugLogStateTables
) {
426 std::ostringstream output
;
427 output
<< "\n\nTransition Table:";
428 output
<< GetTransitionTableAsString();
430 output
<< "\n\nInitial transitions:";
431 output
<< GetStateTransitionsAsString();
433 // Calculate all transition pairs.
434 for (int state1_int
= 0; state1_int
< NUM_STATES
; ++state1_int
) {
435 State state1
= static_cast<State
>(state1_int
);
436 for (int state2_int
= 0; state2_int
< NUM_STATES
; ++state2_int
) {
437 State state2
= static_cast<State
>(state2_int
);
438 if (ShouldSkipStateAndEventPair(state1
, EVENT_INVALID
) ||
439 ShouldSkipStateAndEventPair(state2
, EVENT_INVALID
))
441 // Compute the transition
442 if (NextTransitionInShortestPath(state1
, state2
, NUM_STATES
).state
==
444 LOG(ERROR
) << "Should be skipping state transitions for: "
445 << GetStateString(state1
) << " " << GetStateString(state2
);
450 output
<< "\n\nAll transitions:";
451 output
<< GetStateTransitionsAsString();
452 LOG(INFO
) << output
.str();
455 // Test that the fullscreen exit bubble is closed by
456 // WindowFullscreenStateChanged() if fullscreen is exited via BrowserWindow.
457 // This currently occurs when an extension exits fullscreen via changing the
459 TEST_F(FullscreenControllerStateUnitTest
, ExitFullscreenViaBrowserWindow
) {
460 AddTab(browser(), GURL(url::kAboutBlankURL
));
461 ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN
));
462 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
463 ASSERT_TRUE(browser()->window()->IsFullscreen());
464 // Exit fullscreen without going through fullscreen controller.
465 browser()->window()->ExitFullscreen();
466 ChangeWindowFullscreenState();
467 EXPECT_EQ(EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE
,
469 ->exclusive_access_manager()
470 ->GetExclusiveAccessExitBubbleType());
473 // Test that switching tabs takes the browser out of tab fullscreen.
474 TEST_F(FullscreenControllerStateUnitTest
, ExitTabFullscreenViaSwitchingTab
) {
475 AddTab(browser(), GURL(url::kAboutBlankURL
));
476 AddTab(browser(), GURL(url::kAboutBlankURL
));
477 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
478 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
479 ASSERT_TRUE(browser()->window()->IsFullscreen());
481 browser()->tab_strip_model()->SelectNextTab();
482 ChangeWindowFullscreenState();
483 EXPECT_FALSE(browser()->window()->IsFullscreen());
486 // Test that switching tabs via detaching the active tab (which is in tab
487 // fullscreen) takes the browser out of tab fullscreen. This case can
488 // occur if the user is in both tab fullscreen and immersive browser fullscreen.
489 TEST_F(FullscreenControllerStateUnitTest
, ExitTabFullscreenViaDetachingTab
) {
490 AddTab(browser(), GURL(url::kAboutBlankURL
));
491 AddTab(browser(), GURL(url::kAboutBlankURL
));
492 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
493 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
494 ASSERT_TRUE(browser()->window()->IsFullscreen());
496 scoped_ptr
<content::WebContents
> web_contents(
497 browser()->tab_strip_model()->DetachWebContentsAt(0));
498 ChangeWindowFullscreenState();
499 EXPECT_FALSE(browser()->window()->IsFullscreen());
502 // Test that replacing the web contents for a tab which is in tab fullscreen
503 // takes the browser out of tab fullscreen. This can occur if the user
504 // navigates to a prerendered page from a page which is tab fullscreen.
505 TEST_F(FullscreenControllerStateUnitTest
, ExitTabFullscreenViaReplacingTab
) {
506 AddTab(browser(), GURL(url::kAboutBlankURL
));
507 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
508 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
509 ASSERT_TRUE(browser()->window()->IsFullscreen());
511 content::WebContents
* new_web_contents
= content::WebContents::Create(
512 content::WebContents::CreateParams(profile()));
513 scoped_ptr
<content::WebContents
> old_web_contents(
514 browser()->tab_strip_model()->ReplaceWebContentsAt(
515 0, new_web_contents
));
516 ChangeWindowFullscreenState();
517 EXPECT_FALSE(browser()->window()->IsFullscreen());
520 // Tests that, in a browser configured for Fullscreen-Within-Tab mode,
521 // fullscreening a screen-captured tab will NOT cause any fullscreen state
522 // change to the browser window. Furthermore, the test switches between tabs to
523 // confirm a captured tab will be resized by FullscreenController to the capture
524 // video resolution once the widget is detached from the UI.
526 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
527 TEST_F(FullscreenControllerStateUnitTest
, OneCapturedFullscreenedTab
) {
528 content::WebContentsDelegate
* const wc_delegate
=
529 static_cast<content::WebContentsDelegate
*>(browser());
530 ASSERT_TRUE(wc_delegate
->EmbedsFullscreenWidget());
532 AddTab(browser(), GURL(url::kAboutBlankURL
));
533 AddTab(browser(), GURL(url::kAboutBlankURL
));
534 content::WebContents
* const first_tab
=
535 browser()->tab_strip_model()->GetWebContentsAt(0);
536 content::WebContents
* const second_tab
=
537 browser()->tab_strip_model()->GetWebContentsAt(1);
539 // Activate the first tab and tell its WebContents it is being captured.
540 browser()->tab_strip_model()->ActivateTabAt(0, true);
541 const gfx::Size
kCaptureSize(1280, 720);
542 first_tab
->IncrementCapturerCount(kCaptureSize
);
543 ASSERT_FALSE(browser()->window()->IsFullscreen());
544 ASSERT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
545 ASSERT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
546 ASSERT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
548 // Enter tab fullscreen. Since the tab is being captured, the browser window
549 // should not expand to fill the screen.
550 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
551 EXPECT_FALSE(browser()->window()->IsFullscreen());
552 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
553 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
554 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
556 // Switch to the other tab. Check that the first tab was resized to the
557 // WebContents' preferred size.
558 browser()->tab_strip_model()->ActivateTabAt(1, true);
559 EXPECT_FALSE(browser()->window()->IsFullscreen());
560 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
561 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
562 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
563 // TODO(miu): Need to make an adjustment to content::WebContentsViewMac for
564 // the following to work:
565 #if !defined(OS_MACOSX)
566 EXPECT_EQ(kCaptureSize
, first_tab
->GetViewBounds().size());
569 // Switch back to the first tab and exit fullscreen.
570 browser()->tab_strip_model()->ActivateTabAt(0, true);
571 EXPECT_FALSE(browser()->window()->IsFullscreen());
572 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
573 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
574 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
575 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
));
576 EXPECT_FALSE(browser()->window()->IsFullscreen());
577 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
578 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
579 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
582 // Tests that, in a browser configured for Fullscreen-Within-Tab mode, more than
583 // one tab can be in fullscreen mode at the same time without interfering with
584 // each other. One tab is being screen-captured and is toggled into fullscreen
585 // mode, and then the user switches to another tab not being screen-captured and
586 // fullscreens it. The first tab's fullscreen toggle does not affect the
587 // browser window fullscreen, while the second one's does. Then, the order of
588 // operations is reversed.
590 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
591 TEST_F(FullscreenControllerStateUnitTest
, TwoFullscreenedTabsOneCaptured
) {
592 content::WebContentsDelegate
* const wc_delegate
=
593 static_cast<content::WebContentsDelegate
*>(browser());
594 ASSERT_TRUE(wc_delegate
->EmbedsFullscreenWidget());
596 AddTab(browser(), GURL(url::kAboutBlankURL
));
597 AddTab(browser(), GURL(url::kAboutBlankURL
));
598 content::WebContents
* const first_tab
=
599 browser()->tab_strip_model()->GetWebContentsAt(0);
600 content::WebContents
* const second_tab
=
601 browser()->tab_strip_model()->GetWebContentsAt(1);
603 // Start capturing the first tab, fullscreen it, then switch to the second tab
604 // and fullscreen that. The second tab will cause the browser window to
605 // expand to fill the screen.
606 browser()->tab_strip_model()->ActivateTabAt(0, true);
607 const gfx::Size
kCaptureSize(1280, 720);
608 first_tab
->IncrementCapturerCount(kCaptureSize
);
609 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
610 EXPECT_FALSE(browser()->window()->IsFullscreen());
611 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
612 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
613 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
614 browser()->tab_strip_model()->ActivateTabAt(1, true);
615 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
616 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
617 EXPECT_TRUE(browser()->window()->IsFullscreen());
618 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
619 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
620 EXPECT_TRUE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
622 // Now exit fullscreen while still in the second tab. The browser window
623 // should no longer be fullscreened.
624 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
));
625 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
626 EXPECT_FALSE(browser()->window()->IsFullscreen());
627 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
628 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
629 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
631 // Finally, exit fullscreen on the captured tab.
632 browser()->tab_strip_model()->ActivateTabAt(0, true);
633 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
));
634 EXPECT_FALSE(browser()->window()->IsFullscreen());
635 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
636 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
637 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
640 // Tests that, in a browser configured for Fullscreen-Within-Tab mode, more than
641 // one tab can be in fullscreen mode at the same time. This is like the
642 // TwoFullscreenedTabsOneCaptured test above, except that the screen-captured
643 // tab exits fullscreen mode while the second tab is still in the foreground.
644 // When the first tab exits fullscreen, the fullscreen state of the second tab
645 // and the browser window should remain unchanged.
647 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
648 TEST_F(FullscreenControllerStateUnitTest
,
649 BackgroundCapturedTabExitsFullscreen
) {
650 content::WebContentsDelegate
* const wc_delegate
=
651 static_cast<content::WebContentsDelegate
*>(browser());
652 ASSERT_TRUE(wc_delegate
->EmbedsFullscreenWidget());
654 AddTab(browser(), GURL(url::kAboutBlankURL
));
655 AddTab(browser(), GURL(url::kAboutBlankURL
));
656 content::WebContents
* const first_tab
=
657 browser()->tab_strip_model()->GetWebContentsAt(0);
658 content::WebContents
* const second_tab
=
659 browser()->tab_strip_model()->GetWebContentsAt(1);
661 // Start capturing the first tab, fullscreen it, then switch to the second tab
662 // and fullscreen that. The second tab will cause the browser window to
663 // expand to fill the screen.
664 browser()->tab_strip_model()->ActivateTabAt(0, true);
665 const gfx::Size
kCaptureSize(1280, 720);
666 first_tab
->IncrementCapturerCount(kCaptureSize
);
667 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
668 EXPECT_FALSE(browser()->window()->IsFullscreen());
669 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
670 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
671 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
672 browser()->tab_strip_model()->ActivateTabAt(1, true);
673 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
674 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
675 EXPECT_TRUE(browser()->window()->IsFullscreen());
676 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
677 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
678 EXPECT_TRUE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
680 // Now, the first tab (backgrounded) exits fullscreen. This should not affect
681 // the second tab's fullscreen, nor the state of the browser window.
682 GetFullscreenController()->ExitFullscreenModeForTab(first_tab
);
683 EXPECT_TRUE(browser()->window()->IsFullscreen());
684 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
685 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
686 EXPECT_TRUE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
688 // Finally, exit fullscreen on the second tab.
689 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
));
690 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
691 EXPECT_FALSE(browser()->window()->IsFullscreen());
692 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(first_tab
));
693 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(second_tab
));
694 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
697 // Tests that, in a browser configured for Fullscreen-Within-Tab mode,
698 // fullscreening a screen-captured tab will NOT cause any fullscreen state
699 // change to the browser window. Then, toggling Browser Fullscreen mode should
700 // fullscreen the browser window, but this should behave fully independently of
701 // the tab's fullscreen state.
703 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
704 TEST_F(FullscreenControllerStateUnitTest
,
705 OneCapturedTabFullscreenedBeforeBrowserFullscreen
) {
706 content::WebContentsDelegate
* const wc_delegate
=
707 static_cast<content::WebContentsDelegate
*>(browser());
708 ASSERT_TRUE(wc_delegate
->EmbedsFullscreenWidget());
710 AddTab(browser(), GURL(url::kAboutBlankURL
));
711 content::WebContents
* const tab
=
712 browser()->tab_strip_model()->GetWebContentsAt(0);
714 // Start capturing the tab and fullscreen it. The state of the browser window
715 // should remain unchanged.
716 browser()->tab_strip_model()->ActivateTabAt(0, true);
717 const gfx::Size
kCaptureSize(1280, 720);
718 tab
->IncrementCapturerCount(kCaptureSize
);
719 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
720 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(tab
));
721 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
722 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser());
724 // Now, toggle into Browser Fullscreen mode. The browser window should now be
726 ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN
));
727 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
728 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(tab
));
729 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
730 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser());
732 // Now, toggle back out of Browser Fullscreen mode. The browser window exits
733 // fullscreen mode, but the tab stays in fullscreen mode.
734 ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN
));
735 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
736 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(tab
));
737 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
738 EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser());
740 // Finally, toggle back into Browser Fullscreen mode and then toggle out of
741 // tab fullscreen mode. The browser window should stay fullscreened, while
742 // the tab exits fullscreen mode.
743 ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN
));
744 ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE
));
745 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
));
746 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(tab
));
747 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
748 EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser());
751 // Tests that the state of a fullscreened, screen-captured tab is preserved if
752 // the tab is detached from one Browser window and attached to another.
754 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
755 TEST_F(FullscreenControllerStateUnitTest
,
756 CapturedFullscreenedTabTransferredBetweenBrowserWindows
) {
757 content::WebContentsDelegate
* const wc_delegate
=
758 static_cast<content::WebContentsDelegate
*>(browser());
759 ASSERT_TRUE(wc_delegate
->EmbedsFullscreenWidget());
761 AddTab(browser(), GURL(url::kAboutBlankURL
));
762 AddTab(browser(), GURL(url::kAboutBlankURL
));
763 content::WebContents
* const tab
=
764 browser()->tab_strip_model()->GetWebContentsAt(0);
766 // Activate the first tab and tell its WebContents it is being captured.
767 browser()->tab_strip_model()->ActivateTabAt(0, true);
768 const gfx::Size
kCaptureSize(1280, 720);
769 tab
->IncrementCapturerCount(kCaptureSize
);
770 ASSERT_FALSE(browser()->window()->IsFullscreen());
771 ASSERT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(tab
));
772 ASSERT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
774 // Enter tab fullscreen. Since the tab is being captured, the browser window
775 // should not expand to fill the screen.
776 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE
));
777 EXPECT_FALSE(browser()->window()->IsFullscreen());
778 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(tab
));
779 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
781 // Create the second browser window.
782 const scoped_ptr
<BrowserWindow
> second_browser_window(CreateBrowserWindow());
783 const scoped_ptr
<Browser
> second_browser(CreateBrowser(
784 browser()->profile(),
787 browser()->host_desktop_type(),
788 second_browser_window
.get()));
789 AddTab(second_browser
.get(), GURL(url::kAboutBlankURL
));
790 content::WebContentsDelegate
* const second_wc_delegate
=
791 static_cast<content::WebContentsDelegate
*>(second_browser
.get());
793 // Detach the tab from the first browser window and attach it to the second.
794 // The tab should remain in fullscreen mode and neither browser window should
795 // have expanded. It is correct for both FullscreenControllers to agree the
796 // tab is in fullscreen mode.
797 browser()->tab_strip_model()->DetachWebContentsAt(0);
798 second_browser
->tab_strip_model()->
799 InsertWebContentsAt(0, tab
, TabStripModel::ADD_ACTIVE
);
800 EXPECT_FALSE(browser()->window()->IsFullscreen());
801 EXPECT_FALSE(second_browser
->window()->IsFullscreen());
802 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(tab
));
803 EXPECT_TRUE(second_wc_delegate
->IsFullscreenForTabOrPending(tab
));
804 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
805 EXPECT_FALSE(second_browser
->exclusive_access_manager()
806 ->fullscreen_controller()
807 ->IsWindowFullscreenForTabOrPending());
809 // Now, detach and reattach it back to the first browser window. Again, the
810 // tab should remain in fullscreen mode and neither browser window should have
812 second_browser
->tab_strip_model()->DetachWebContentsAt(0);
813 browser()->tab_strip_model()->
814 InsertWebContentsAt(0, tab
, TabStripModel::ADD_ACTIVE
);
815 EXPECT_FALSE(browser()->window()->IsFullscreen());
816 EXPECT_FALSE(second_browser
->window()->IsFullscreen());
817 EXPECT_TRUE(wc_delegate
->IsFullscreenForTabOrPending(tab
));
818 EXPECT_TRUE(second_wc_delegate
->IsFullscreenForTabOrPending(tab
));
819 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
820 EXPECT_FALSE(second_browser
->exclusive_access_manager()
821 ->fullscreen_controller()
822 ->IsWindowFullscreenForTabOrPending());
825 ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE
));
826 EXPECT_FALSE(browser()->window()->IsFullscreen());
827 EXPECT_FALSE(wc_delegate
->IsFullscreenForTabOrPending(tab
));
828 EXPECT_FALSE(second_wc_delegate
->IsFullscreenForTabOrPending(tab
));
829 EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
830 EXPECT_FALSE(second_browser
->exclusive_access_manager()
831 ->fullscreen_controller()
832 ->IsWindowFullscreenForTabOrPending());
834 // Required tear-down specific to this test.
835 second_browser
->tab_strip_model()->CloseAllTabs();