Home | History | Annotate | Download | only in fullscreen
      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 "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/fullscreen/fullscreen_controller.h"
     10 #include "chrome/browser/ui/fullscreen/fullscreen_controller_state_test.h"
     11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     12 #include "chrome/test/base/browser_with_test_window_test.h"
     13 #include "content/public/browser/web_contents.h"
     14 #include "content/public/common/url_constants.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 // The FullscreenControllerStateUnitTest unit test suite exhastively tests
     18 // the FullscreenController through all permutations of events. The behavior
     19 // of the BrowserWindow is mocked via FullscreenControllerTestWindow.
     20 
     21 
     22 // FullscreenControllerTestWindow ----------------------------------------------
     23 
     24 // A BrowserWindow used for testing FullscreenController. The behavior of this
     25 // mock is verfied manually by running FullscreenControllerStateInteractiveTest.
     26 class FullscreenControllerTestWindow : public TestBrowserWindow {
     27  public:
     28   // Simulate the window state with an enumeration.
     29   enum WindowState {
     30     NORMAL,
     31     FULLSCREEN,
     32     // No TO_ state for METRO_SNAP, the windows implementation is synchronous.
     33     METRO_SNAP,
     34     TO_NORMAL,
     35     TO_FULLSCREEN,
     36   };
     37 
     38   FullscreenControllerTestWindow();
     39   virtual ~FullscreenControllerTestWindow() {}
     40 
     41   // BrowserWindow Interface:
     42   virtual void EnterFullscreen(const GURL& url,
     43                                FullscreenExitBubbleType type) OVERRIDE;
     44   virtual void ExitFullscreen() OVERRIDE;
     45   virtual bool ShouldHideUIForFullscreen() const OVERRIDE;
     46   virtual bool IsFullscreen() const OVERRIDE;
     47 #if defined(OS_WIN)
     48   virtual void SetMetroSnapMode(bool enable) OVERRIDE;
     49   virtual bool IsInMetroSnapMode() const OVERRIDE;
     50 #endif
     51 #if defined(OS_MACOSX)
     52   virtual void EnterFullscreenWithChrome() OVERRIDE;
     53   virtual void EnterFullscreenWithoutChrome() OVERRIDE;
     54   virtual bool IsFullscreenWithChrome() OVERRIDE;
     55   virtual bool IsFullscreenWithoutChrome() OVERRIDE;
     56 #endif
     57 
     58   static const char* GetWindowStateString(WindowState state);
     59   WindowState state() const { return state_; }
     60   void set_browser(Browser* browser) { browser_ = browser; }
     61 
     62   // Simulates the window changing state.
     63   void ChangeWindowFullscreenState();
     64 
     65  private:
     66   // Enters fullscreen with |new_mac_with_chrome_mode|.
     67   void EnterFullscreen(bool new_mac_with_chrome_mode);
     68 
     69   // Returns true if ChangeWindowFullscreenState() should be called as a result
     70   // of updating the current fullscreen state to the passed in state.
     71   bool IsTransitionReentrant(bool new_fullscreen,
     72                              bool new_mac_with_chrome_mode);
     73 
     74   WindowState state_;
     75   bool mac_with_chrome_mode_;
     76   Browser* browser_;
     77 };
     78 
     79 FullscreenControllerTestWindow::FullscreenControllerTestWindow()
     80     : state_(NORMAL),
     81       mac_with_chrome_mode_(false),
     82       browser_(NULL) {
     83 }
     84 
     85 void FullscreenControllerTestWindow::EnterFullscreen(
     86     const GURL& url, FullscreenExitBubbleType type) {
     87   EnterFullscreen(false);
     88 }
     89 
     90 void FullscreenControllerTestWindow::ExitFullscreen() {
     91   if (IsFullscreen()) {
     92     state_ = TO_NORMAL;
     93     mac_with_chrome_mode_ = false;
     94 
     95     if (IsTransitionReentrant(false, false))
     96       ChangeWindowFullscreenState();
     97   }
     98 }
     99 
    100 bool FullscreenControllerTestWindow::ShouldHideUIForFullscreen() const {
    101   return IsFullscreen();
    102 }
    103 
    104 bool FullscreenControllerTestWindow::IsFullscreen() const {
    105 #if defined(OS_MACOSX)
    106   return state_ == FULLSCREEN || state_ == TO_FULLSCREEN;
    107 #else
    108   return state_ == FULLSCREEN || state_ == TO_NORMAL;
    109 #endif
    110 }
    111 
    112 #if defined(OS_WIN)
    113 void FullscreenControllerTestWindow::SetMetroSnapMode(bool enable) {
    114   if (enable != IsInMetroSnapMode())
    115     state_ = enable ? METRO_SNAP : NORMAL;
    116 
    117   if (FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant())
    118     ChangeWindowFullscreenState();
    119 }
    120 
    121 bool FullscreenControllerTestWindow::IsInMetroSnapMode() const {
    122   return state_ == METRO_SNAP;
    123 }
    124 #endif
    125 
    126 #if defined(OS_MACOSX)
    127 void FullscreenControllerTestWindow::EnterFullscreenWithChrome() {
    128   EnterFullscreen(true);
    129 }
    130 
    131 void FullscreenControllerTestWindow::EnterFullscreenWithoutChrome() {
    132   EnterFullscreen(false);
    133 }
    134 
    135 bool FullscreenControllerTestWindow::IsFullscreenWithChrome() {
    136   return IsFullscreen() && mac_with_chrome_mode_;
    137 }
    138 
    139 bool FullscreenControllerTestWindow::IsFullscreenWithoutChrome() {
    140   return IsFullscreen() && !mac_with_chrome_mode_;
    141 }
    142 #endif
    143 
    144 // static
    145 const char* FullscreenControllerTestWindow::GetWindowStateString(
    146     WindowState state) {
    147   switch (state) {
    148     ENUM_TO_STRING(NORMAL);
    149     ENUM_TO_STRING(FULLSCREEN);
    150     ENUM_TO_STRING(METRO_SNAP);
    151     ENUM_TO_STRING(TO_FULLSCREEN);
    152     ENUM_TO_STRING(TO_NORMAL);
    153     default:
    154       NOTREACHED() << "No string for state " << state;
    155       return "WindowState-Unknown";
    156   }
    157 }
    158 
    159 void FullscreenControllerTestWindow::ChangeWindowFullscreenState() {
    160   // Most states result in "no operation" intentionally. The tests
    161   // assume that all possible states and event pairs can be tested, even
    162   // though window managers will not generate all of these.
    163   if (state_ == TO_FULLSCREEN)
    164       state_ = FULLSCREEN;
    165   else if (state_ == TO_NORMAL)
    166       state_ = NORMAL;
    167 
    168   // Emit a change event from every state to ensure the Fullscreen Controller
    169   // handles it in all circumstances.
    170   browser_->WindowFullscreenStateChanged();
    171 }
    172 
    173 void FullscreenControllerTestWindow::EnterFullscreen(
    174     bool new_mac_with_chrome_mode) {
    175   bool reentrant = IsTransitionReentrant(true, new_mac_with_chrome_mode);
    176 
    177   mac_with_chrome_mode_ = new_mac_with_chrome_mode;
    178   if (!IsFullscreen())
    179     state_ = TO_FULLSCREEN;
    180 
    181   if (reentrant)
    182     ChangeWindowFullscreenState();
    183 }
    184 
    185 bool FullscreenControllerTestWindow::IsTransitionReentrant(
    186     bool new_fullscreen,
    187     bool new_mac_with_chrome_mode) {
    188 #if defined(OS_MACOSX)
    189   bool mac_with_chrome_mode_changed = new_mac_with_chrome_mode ?
    190       IsFullscreenWithoutChrome() : IsFullscreenWithChrome();
    191 #else
    192   bool mac_with_chrome_mode_changed = false;
    193 #endif
    194   bool fullscreen_changed = (new_fullscreen != IsFullscreen());
    195 
    196   if (!fullscreen_changed && !mac_with_chrome_mode_changed)
    197     return false;
    198 
    199   if (FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant())
    200     return true;
    201 
    202   // BrowserWindowCocoa::EnterFullscreen() and
    203   // BrowserWindowCocoa::EnterFullscreenWithChrome() are reentrant when
    204   // switching between fullscreen with chrome and fullscreen without chrome.
    205   return state_ == FULLSCREEN &&
    206       !fullscreen_changed &&
    207       mac_with_chrome_mode_changed;
    208 }
    209 
    210 
    211 // FullscreenControllerStateUnitTest -------------------------------------------
    212 
    213 // Unit test fixture testing Fullscreen Controller through its states. Most of
    214 // the test logic comes from FullscreenControllerStateTest.
    215 class FullscreenControllerStateUnitTest : public BrowserWithTestWindowTest,
    216                                           public FullscreenControllerStateTest {
    217  public:
    218   FullscreenControllerStateUnitTest();
    219 
    220   // FullscreenControllerStateTest:
    221   virtual void SetUp() OVERRIDE;
    222   virtual BrowserWindow* CreateBrowserWindow() OVERRIDE;
    223   virtual void ChangeWindowFullscreenState() OVERRIDE;
    224   virtual const char* GetWindowStateString() OVERRIDE;
    225   virtual void VerifyWindowState() OVERRIDE;
    226 
    227  protected:
    228   // FullscreenControllerStateTest:
    229   virtual bool ShouldSkipStateAndEventPair(State state, Event event) OVERRIDE;
    230   virtual Browser* GetBrowser() OVERRIDE;
    231   FullscreenControllerTestWindow* window_;
    232 };
    233 
    234 FullscreenControllerStateUnitTest::FullscreenControllerStateUnitTest ()
    235     : window_(NULL) {
    236 }
    237 
    238 void FullscreenControllerStateUnitTest::SetUp() {
    239   BrowserWithTestWindowTest::SetUp();
    240   window_->set_browser(browser());
    241 }
    242 
    243 BrowserWindow* FullscreenControllerStateUnitTest::CreateBrowserWindow() {
    244   window_ = new FullscreenControllerTestWindow();
    245   return window_;  // BrowserWithTestWindowTest takes ownership.
    246 }
    247 
    248 void FullscreenControllerStateUnitTest::ChangeWindowFullscreenState() {
    249   window_->ChangeWindowFullscreenState();
    250 }
    251 
    252 const char* FullscreenControllerStateUnitTest::GetWindowStateString() {
    253   return FullscreenControllerTestWindow::GetWindowStateString(window_->state());
    254 }
    255 
    256 void FullscreenControllerStateUnitTest::VerifyWindowState() {
    257   switch (state()) {
    258     case STATE_NORMAL:
    259       EXPECT_EQ(FullscreenControllerTestWindow::NORMAL,
    260                 window_->state()) << GetAndClearDebugLog();
    261       break;
    262 
    263     case STATE_BROWSER_FULLSCREEN_NO_CHROME:
    264     case STATE_BROWSER_FULLSCREEN_WITH_CHROME:
    265     case STATE_TAB_FULLSCREEN:
    266     case STATE_TAB_BROWSER_FULLSCREEN:
    267     case STATE_TAB_BROWSER_FULLSCREEN_CHROME:
    268       EXPECT_EQ(FullscreenControllerTestWindow::FULLSCREEN,
    269                 window_->state()) << GetAndClearDebugLog();
    270       break;
    271 
    272 #if defined(OS_WIN)
    273     case STATE_METRO_SNAP:
    274       EXPECT_EQ(FullscreenControllerTestWindow::METRO_SNAP,
    275                 window_->state()) << GetAndClearDebugLog();
    276       break;
    277 #endif
    278 
    279     case STATE_TO_NORMAL:
    280       EXPECT_EQ(FullscreenControllerTestWindow::TO_NORMAL,
    281                 window_->state()) << GetAndClearDebugLog();
    282       break;
    283 
    284     case STATE_TO_BROWSER_FULLSCREEN_NO_CHROME:
    285     case STATE_TO_BROWSER_FULLSCREEN_WITH_CHROME:
    286     case STATE_TO_TAB_FULLSCREEN:
    287       EXPECT_EQ(FullscreenControllerTestWindow::TO_FULLSCREEN,
    288                 window_->state()) << GetAndClearDebugLog();
    289       break;
    290 
    291     default:
    292       NOTREACHED() << GetAndClearDebugLog();
    293   }
    294 
    295   FullscreenControllerStateTest::VerifyWindowState();
    296 }
    297 
    298 bool FullscreenControllerStateUnitTest::ShouldSkipStateAndEventPair(
    299     State state, Event event) {
    300 #if defined(OS_MACOSX)
    301   // TODO(scheib) Toggle, Window Event, Toggle, Toggle on Mac as exposed by
    302   // test *.STATE_TO_NORMAL__TOGGLE_FULLSCREEN runs interactively and exits to
    303   // Normal. This doesn't appear to be the desired result, and would add
    304   // too much complexity to mimic in our simple FullscreenControllerTestWindow.
    305   // http://crbug.com/156968
    306   if ((state == STATE_TO_NORMAL ||
    307        state == STATE_TO_BROWSER_FULLSCREEN_NO_CHROME ||
    308        state == STATE_TO_TAB_FULLSCREEN) &&
    309       event == TOGGLE_FULLSCREEN)
    310     return true;
    311 #endif
    312 
    313   return FullscreenControllerStateTest::ShouldSkipStateAndEventPair(state,
    314                                                                     event);
    315 }
    316 
    317 Browser* FullscreenControllerStateUnitTest::GetBrowser() {
    318   return BrowserWithTestWindowTest::browser();
    319 }
    320 
    321 
    322 // Soak tests ------------------------------------------------------------------
    323 
    324 // Tests all states with all permutations of multiple events to detect lingering
    325 // state issues that would bleed over to other states.
    326 // I.E. for each state test all combinations of events E1, E2, E3.
    327 //
    328 // This produces coverage for event sequences that may happen normally but
    329 // would not be exposed by traversing to each state via TransitionToState().
    330 // TransitionToState() always takes the same path even when multiple paths
    331 // exist.
    332 TEST_F(FullscreenControllerStateUnitTest, TransitionsForEachState) {
    333   // A tab is needed for tab fullscreen.
    334   AddTab(browser(), GURL(url::kAboutBlankURL));
    335   TestTransitionsForEachState();
    336   // Progress of test can be examined via LOG(INFO) << GetAndClearDebugLog();
    337 }
    338 
    339 
    340 // Individual tests for each pair of state and event ---------------------------
    341 
    342 #define TEST_EVENT(state, event)                                \
    343   TEST_F(FullscreenControllerStateUnitTest, state##__##event) { \
    344     AddTab(browser(), GURL(url::kAboutBlankURL));               \
    345     ASSERT_NO_FATAL_FAILURE(TestStateAndEvent(state, event))    \
    346         << GetAndClearDebugLog();                               \
    347   }
    348     // Progress of tests can be examined by inserting the following line:
    349     // LOG(INFO) << GetAndClearDebugLog(); }
    350 
    351 #include "chrome/browser/ui/fullscreen/fullscreen_controller_state_tests.h"
    352 
    353 
    354 // Specific one-off tests for known issues -------------------------------------
    355 
    356 // TODO(scheib) Toggling Tab fullscreen while pending Tab or
    357 // Browser fullscreen is broken currently http://crbug.com/154196
    358 TEST_F(FullscreenControllerStateUnitTest,
    359        DISABLED_ToggleTabWhenPendingBrowser) {
    360   // Only possible without reentrancy.
    361   if (FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant())
    362     return;
    363   AddTab(browser(), GURL(url::kAboutBlankURL));
    364   ASSERT_NO_FATAL_FAILURE(
    365       TransitionToState(STATE_TO_BROWSER_FULLSCREEN_NO_CHROME))
    366       << GetAndClearDebugLog();
    367 
    368   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE)) << GetAndClearDebugLog();
    369   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE)) << GetAndClearDebugLog();
    370   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE)) << GetAndClearDebugLog();
    371 }
    372 
    373 // TODO(scheib) Toggling Tab fullscreen while pending Tab or
    374 // Browser fullscreen is broken currently http://crbug.com/154196
    375 TEST_F(FullscreenControllerStateUnitTest, DISABLED_ToggleTabWhenPendingTab) {
    376   // Only possible without reentrancy.
    377   if (FullscreenControllerStateTest::IsWindowFullscreenStateChangedReentrant())
    378     return;
    379   AddTab(browser(), GURL(url::kAboutBlankURL));
    380   ASSERT_NO_FATAL_FAILURE(
    381       TransitionToState(STATE_TO_TAB_FULLSCREEN))
    382       << GetAndClearDebugLog();
    383 
    384   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE)) << GetAndClearDebugLog();
    385   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE)) << GetAndClearDebugLog();
    386   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE)) << GetAndClearDebugLog();
    387 }
    388 
    389 // Debugging utility: Display the transition tables. Intentionally disabled
    390 TEST_F(FullscreenControllerStateUnitTest, DISABLED_DebugLogStateTables) {
    391   std::ostringstream output;
    392   output << "\n\nTransition Table:";
    393   output << GetTransitionTableAsString();
    394 
    395   output << "\n\nInitial transitions:";
    396   output << GetStateTransitionsAsString();
    397 
    398   // Calculate all transition pairs.
    399   for (int state1_int = 0; state1_int < NUM_STATES; ++state1_int) {
    400     State state1 = static_cast<State>(state1_int);
    401     for (int state2_int = 0; state2_int < NUM_STATES; ++state2_int) {
    402       State state2 = static_cast<State>(state2_int);
    403       if (ShouldSkipStateAndEventPair(state1, EVENT_INVALID) ||
    404           ShouldSkipStateAndEventPair(state2, EVENT_INVALID))
    405         continue;
    406       // Compute the transition
    407       if (NextTransitionInShortestPath(state1, state2, NUM_STATES).state ==
    408           STATE_INVALID) {
    409         LOG(ERROR) << "Should be skipping state transitions for: "
    410             << GetStateString(state1) << " " << GetStateString(state2);
    411       }
    412     }
    413   }
    414 
    415   output << "\n\nAll transitions:";
    416   output << GetStateTransitionsAsString();
    417   LOG(INFO) << output.str();
    418 }
    419 
    420 // Test that the fullscreen exit bubble is closed by
    421 // WindowFullscreenStateChanged() if fullscreen is exited via BrowserWindow.
    422 // This currently occurs when an extension exits fullscreen via changing the
    423 // browser bounds.
    424 TEST_F(FullscreenControllerStateUnitTest, ExitFullscreenViaBrowserWindow) {
    425   AddTab(browser(), GURL(url::kAboutBlankURL));
    426   ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN));
    427   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    428   ASSERT_TRUE(browser()->window()->IsFullscreen());
    429   // Exit fullscreen without going through fullscreen controller.
    430   browser()->window()->ExitFullscreen();
    431   ChangeWindowFullscreenState();
    432   EXPECT_EQ(FEB_TYPE_NONE,
    433             browser()->fullscreen_controller()->GetFullscreenExitBubbleType());
    434 }
    435 
    436 // Test that switching tabs takes the browser out of tab fullscreen.
    437 TEST_F(FullscreenControllerStateUnitTest, ExitTabFullscreenViaSwitchingTab) {
    438   AddTab(browser(), GURL(url::kAboutBlankURL));
    439   AddTab(browser(), GURL(url::kAboutBlankURL));
    440   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    441   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    442   ASSERT_TRUE(browser()->window()->IsFullscreen());
    443 
    444   browser()->tab_strip_model()->SelectNextTab();
    445   ChangeWindowFullscreenState();
    446   EXPECT_FALSE(browser()->window()->IsFullscreen());
    447 }
    448 
    449 // Test that switching tabs via detaching the active tab (which is in tab
    450 // fullscreen) takes the browser out of tab fullscreen. This case can
    451 // occur if the user is in both tab fullscreen and immersive browser fullscreen.
    452 TEST_F(FullscreenControllerStateUnitTest, ExitTabFullscreenViaDetachingTab) {
    453   AddTab(browser(), GURL(url::kAboutBlankURL));
    454   AddTab(browser(), GURL(url::kAboutBlankURL));
    455   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    456   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    457   ASSERT_TRUE(browser()->window()->IsFullscreen());
    458 
    459   scoped_ptr<content::WebContents> web_contents(
    460       browser()->tab_strip_model()->DetachWebContentsAt(0));
    461   ChangeWindowFullscreenState();
    462   EXPECT_FALSE(browser()->window()->IsFullscreen());
    463 }
    464 
    465 // Test that replacing the web contents for a tab which is in tab fullscreen
    466 // takes the browser out of tab fullscreen. This can occur if the user
    467 // navigates to a prerendered page from a page which is tab fullscreen.
    468 TEST_F(FullscreenControllerStateUnitTest, ExitTabFullscreenViaReplacingTab) {
    469   AddTab(browser(), GURL(url::kAboutBlankURL));
    470   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    471   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    472   ASSERT_TRUE(browser()->window()->IsFullscreen());
    473 
    474   content::WebContents* new_web_contents = content::WebContents::Create(
    475       content::WebContents::CreateParams(profile()));
    476   scoped_ptr<content::WebContents> old_web_contents(
    477       browser()->tab_strip_model()->ReplaceWebContentsAt(
    478           0, new_web_contents));
    479   ChangeWindowFullscreenState();
    480   EXPECT_FALSE(browser()->window()->IsFullscreen());
    481 }
    482 
    483 // Tests that, in a browser configured for Fullscreen-Within-Tab mode,
    484 // fullscreening a screen-captured tab will NOT cause any fullscreen state
    485 // change to the browser window. Furthermore, the test switches between tabs to
    486 // confirm a captured tab will be resized by FullscreenController to the capture
    487 // video resolution once the widget is detached from the UI.
    488 //
    489 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
    490 TEST_F(FullscreenControllerStateUnitTest, OneCapturedFullscreenedTab) {
    491   content::WebContentsDelegate* const wc_delegate =
    492       static_cast<content::WebContentsDelegate*>(browser());
    493   ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
    494 
    495   AddTab(browser(), GURL(url::kAboutBlankURL));
    496   AddTab(browser(), GURL(url::kAboutBlankURL));
    497   content::WebContents* const first_tab =
    498       browser()->tab_strip_model()->GetWebContentsAt(0);
    499   content::WebContents* const second_tab =
    500       browser()->tab_strip_model()->GetWebContentsAt(1);
    501 
    502   // Activate the first tab and tell its WebContents it is being captured.
    503   browser()->tab_strip_model()->ActivateTabAt(0, true);
    504   const gfx::Size kCaptureSize(1280, 720);
    505   first_tab->IncrementCapturerCount(kCaptureSize);
    506   ASSERT_FALSE(browser()->window()->IsFullscreen());
    507   ASSERT_FALSE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    508   ASSERT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    509   ASSERT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    510 
    511   // Enter tab fullscreen.  Since the tab is being captured, the browser window
    512   // should not expand to fill the screen.
    513   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    514   EXPECT_FALSE(browser()->window()->IsFullscreen());
    515   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    516   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    517   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    518 
    519   // Switch to the other tab.  Check that the first tab was resized to the
    520   // WebContents' preferred size.
    521   browser()->tab_strip_model()->ActivateTabAt(1, true);
    522   EXPECT_FALSE(browser()->window()->IsFullscreen());
    523   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    524   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    525   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    526   // TODO(miu): Need to make an adjustment to content::WebContentsViewMac for
    527   // the following to work:
    528 #if !defined(OS_MACOSX)
    529   EXPECT_EQ(kCaptureSize, first_tab->GetViewBounds().size());
    530 #endif
    531 
    532   // Switch back to the first tab and exit fullscreen.
    533   browser()->tab_strip_model()->ActivateTabAt(0, true);
    534   EXPECT_FALSE(browser()->window()->IsFullscreen());
    535   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    536   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    537   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    538   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE));
    539   EXPECT_FALSE(browser()->window()->IsFullscreen());
    540   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    541   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    542   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    543 }
    544 
    545 // Tests that, in a browser configured for Fullscreen-Within-Tab mode, more than
    546 // one tab can be in fullscreen mode at the same time without interfering with
    547 // each other.  One tab is being screen-captured and is toggled into fullscreen
    548 // mode, and then the user switches to another tab not being screen-captured and
    549 // fullscreens it.  The first tab's fullscreen toggle does not affect the
    550 // browser window fullscreen, while the second one's does.  Then, the order of
    551 // operations is reversed.
    552 //
    553 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
    554 TEST_F(FullscreenControllerStateUnitTest, TwoFullscreenedTabsOneCaptured) {
    555   content::WebContentsDelegate* const wc_delegate =
    556       static_cast<content::WebContentsDelegate*>(browser());
    557   ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
    558 
    559   AddTab(browser(), GURL(url::kAboutBlankURL));
    560   AddTab(browser(), GURL(url::kAboutBlankURL));
    561   content::WebContents* const first_tab =
    562       browser()->tab_strip_model()->GetWebContentsAt(0);
    563   content::WebContents* const second_tab =
    564       browser()->tab_strip_model()->GetWebContentsAt(1);
    565 
    566   // Start capturing the first tab, fullscreen it, then switch to the second tab
    567   // and fullscreen that.  The second tab will cause the browser window to
    568   // expand to fill the screen.
    569   browser()->tab_strip_model()->ActivateTabAt(0, true);
    570   const gfx::Size kCaptureSize(1280, 720);
    571   first_tab->IncrementCapturerCount(kCaptureSize);
    572   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    573   EXPECT_FALSE(browser()->window()->IsFullscreen());
    574   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    575   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    576   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    577   browser()->tab_strip_model()->ActivateTabAt(1, true);
    578   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    579   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    580   EXPECT_TRUE(browser()->window()->IsFullscreen());
    581   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    582   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    583   EXPECT_TRUE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    584 
    585   // Now exit fullscreen while still in the second tab.  The browser window
    586   // should no longer be fullscreened.
    587   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE));
    588   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    589   EXPECT_FALSE(browser()->window()->IsFullscreen());
    590   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    591   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    592   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    593 
    594   // Finally, exit fullscreen on the captured tab.
    595   browser()->tab_strip_model()->ActivateTabAt(0, true);
    596   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE));
    597   EXPECT_FALSE(browser()->window()->IsFullscreen());
    598   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    599   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    600   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    601 }
    602 
    603 // Tests that, in a browser configured for Fullscreen-Within-Tab mode, more than
    604 // one tab can be in fullscreen mode at the same time.  This is like the
    605 // TwoFullscreenedTabsOneCaptured test above, except that the screen-captured
    606 // tab exits fullscreen mode while the second tab is still in the foreground.
    607 // When the first tab exits fullscreen, the fullscreen state of the second tab
    608 // and the browser window should remain unchanged.
    609 //
    610 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
    611 TEST_F(FullscreenControllerStateUnitTest,
    612        BackgroundCapturedTabExitsFullscreen) {
    613   content::WebContentsDelegate* const wc_delegate =
    614       static_cast<content::WebContentsDelegate*>(browser());
    615   ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
    616 
    617   AddTab(browser(), GURL(url::kAboutBlankURL));
    618   AddTab(browser(), GURL(url::kAboutBlankURL));
    619   content::WebContents* const first_tab =
    620       browser()->tab_strip_model()->GetWebContentsAt(0);
    621   content::WebContents* const second_tab =
    622       browser()->tab_strip_model()->GetWebContentsAt(1);
    623 
    624   // Start capturing the first tab, fullscreen it, then switch to the second tab
    625   // and fullscreen that.  The second tab will cause the browser window to
    626   // expand to fill the screen.
    627   browser()->tab_strip_model()->ActivateTabAt(0, true);
    628   const gfx::Size kCaptureSize(1280, 720);
    629   first_tab->IncrementCapturerCount(kCaptureSize);
    630   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    631   EXPECT_FALSE(browser()->window()->IsFullscreen());
    632   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    633   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    634   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    635   browser()->tab_strip_model()->ActivateTabAt(1, true);
    636   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    637   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    638   EXPECT_TRUE(browser()->window()->IsFullscreen());
    639   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    640   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    641   EXPECT_TRUE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    642 
    643   // Now, the first tab (backgrounded) exits fullscreen.  This should not affect
    644   // the second tab's fullscreen, nor the state of the browser window.
    645   GetFullscreenController()->ToggleFullscreenModeForTab(first_tab, false);
    646   EXPECT_TRUE(browser()->window()->IsFullscreen());
    647   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    648   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    649   EXPECT_TRUE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    650 
    651   // Finally, exit fullscreen on the second tab.
    652   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE));
    653   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    654   EXPECT_FALSE(browser()->window()->IsFullscreen());
    655   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(first_tab));
    656   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(second_tab));
    657   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    658 }
    659 
    660 // Tests that, in a browser configured for Fullscreen-Within-Tab mode,
    661 // fullscreening a screen-captured tab will NOT cause any fullscreen state
    662 // change to the browser window. Then, toggling Browser Fullscreen mode should
    663 // fullscreen the browser window, but this should behave fully independently of
    664 // the tab's fullscreen state.
    665 //
    666 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
    667 TEST_F(FullscreenControllerStateUnitTest,
    668        OneCapturedTabFullscreenedBeforeBrowserFullscreen) {
    669   content::WebContentsDelegate* const wc_delegate =
    670       static_cast<content::WebContentsDelegate*>(browser());
    671   ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
    672 
    673   AddTab(browser(), GURL(url::kAboutBlankURL));
    674   content::WebContents* const tab =
    675       browser()->tab_strip_model()->GetWebContentsAt(0);
    676 
    677   // Start capturing the tab and fullscreen it.  The state of the browser window
    678   // should remain unchanged.
    679   browser()->tab_strip_model()->ActivateTabAt(0, true);
    680   const gfx::Size kCaptureSize(1280, 720);
    681   tab->IncrementCapturerCount(kCaptureSize);
    682   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    683   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(tab));
    684   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    685   EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser());
    686 
    687   // Now, toggle into Browser Fullscreen mode.  The browser window should now be
    688   // fullscreened.
    689   ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN));
    690   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    691   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(tab));
    692   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    693   EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser());
    694 
    695   // Now, toggle back out of Browser Fullscreen mode.  The browser window exits
    696   // fullscreen mode, but the tab stays in fullscreen mode.
    697   ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN));
    698   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    699   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(tab));
    700   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    701   EXPECT_FALSE(GetFullscreenController()->IsFullscreenForBrowser());
    702 
    703   // Finally, toggle back into Browser Fullscreen mode and then toggle out of
    704   // tab fullscreen mode.  The browser window should stay fullscreened, while
    705   // the tab exits fullscreen mode.
    706   ASSERT_TRUE(InvokeEvent(TOGGLE_FULLSCREEN));
    707   ASSERT_TRUE(InvokeEvent(WINDOW_CHANGE));
    708   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE));
    709   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(tab));
    710   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    711   EXPECT_TRUE(GetFullscreenController()->IsFullscreenForBrowser());
    712 }
    713 
    714 // Tests that the state of a fullscreened, screen-captured tab is preserved if
    715 // the tab is detached from one Browser window and attached to another.
    716 //
    717 // See 'FullscreenWithinTab Note' in fullscreen_controller.h.
    718 TEST_F(FullscreenControllerStateUnitTest,
    719        CapturedFullscreenedTabTransferredBetweenBrowserWindows) {
    720   content::WebContentsDelegate* const wc_delegate =
    721       static_cast<content::WebContentsDelegate*>(browser());
    722   ASSERT_TRUE(wc_delegate->EmbedsFullscreenWidget());
    723 
    724   AddTab(browser(), GURL(url::kAboutBlankURL));
    725   AddTab(browser(), GURL(url::kAboutBlankURL));
    726   content::WebContents* const tab =
    727       browser()->tab_strip_model()->GetWebContentsAt(0);
    728 
    729   // Activate the first tab and tell its WebContents it is being captured.
    730   browser()->tab_strip_model()->ActivateTabAt(0, true);
    731   const gfx::Size kCaptureSize(1280, 720);
    732   tab->IncrementCapturerCount(kCaptureSize);
    733   ASSERT_FALSE(browser()->window()->IsFullscreen());
    734   ASSERT_FALSE(wc_delegate->IsFullscreenForTabOrPending(tab));
    735   ASSERT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    736 
    737   // Enter tab fullscreen.  Since the tab is being captured, the browser window
    738   // should not expand to fill the screen.
    739   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_TRUE));
    740   EXPECT_FALSE(browser()->window()->IsFullscreen());
    741   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(tab));
    742   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    743 
    744   // Create the second browser window.
    745   const scoped_ptr<BrowserWindow> second_browser_window(CreateBrowserWindow());
    746   const scoped_ptr<Browser> second_browser(CreateBrowser(
    747       browser()->profile(),
    748       browser()->type(),
    749       false,
    750       browser()->host_desktop_type(),
    751       second_browser_window.get()));
    752   AddTab(second_browser.get(), GURL(url::kAboutBlankURL));
    753   content::WebContentsDelegate* const second_wc_delegate =
    754       static_cast<content::WebContentsDelegate*>(second_browser.get());
    755 
    756   // Detach the tab from the first browser window and attach it to the second.
    757   // The tab should remain in fullscreen mode and neither browser window should
    758   // have expanded. It is correct for both FullscreenControllers to agree the
    759   // tab is in fullscreen mode.
    760   browser()->tab_strip_model()->DetachWebContentsAt(0);
    761   second_browser->tab_strip_model()->
    762       InsertWebContentsAt(0, tab, TabStripModel::ADD_ACTIVE);
    763   EXPECT_FALSE(browser()->window()->IsFullscreen());
    764   EXPECT_FALSE(second_browser->window()->IsFullscreen());
    765   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(tab));
    766   EXPECT_TRUE(second_wc_delegate->IsFullscreenForTabOrPending(tab));
    767   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    768   EXPECT_FALSE(second_browser->fullscreen_controller()->
    769                    IsWindowFullscreenForTabOrPending());
    770 
    771   // Now, detach and reattach it back to the first browser window.  Again, the
    772   // tab should remain in fullscreen mode and neither browser window should have
    773   // expanded.
    774   second_browser->tab_strip_model()->DetachWebContentsAt(0);
    775   browser()->tab_strip_model()->
    776       InsertWebContentsAt(0, tab, TabStripModel::ADD_ACTIVE);
    777   EXPECT_FALSE(browser()->window()->IsFullscreen());
    778   EXPECT_FALSE(second_browser->window()->IsFullscreen());
    779   EXPECT_TRUE(wc_delegate->IsFullscreenForTabOrPending(tab));
    780   EXPECT_TRUE(second_wc_delegate->IsFullscreenForTabOrPending(tab));
    781   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    782   EXPECT_FALSE(second_browser->fullscreen_controller()->
    783                    IsWindowFullscreenForTabOrPending());
    784 
    785   // Exit fullscreen.
    786   ASSERT_TRUE(InvokeEvent(TAB_FULLSCREEN_FALSE));
    787   EXPECT_FALSE(browser()->window()->IsFullscreen());
    788   EXPECT_FALSE(wc_delegate->IsFullscreenForTabOrPending(tab));
    789   EXPECT_FALSE(second_wc_delegate->IsFullscreenForTabOrPending(tab));
    790   EXPECT_FALSE(GetFullscreenController()->IsWindowFullscreenForTabOrPending());
    791   EXPECT_FALSE(second_browser->fullscreen_controller()->
    792                    IsWindowFullscreenForTabOrPending());
    793 
    794   // Required tear-down specific to this test.
    795   second_browser->tab_strip_model()->CloseAllTabs();
    796 }
    797