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