• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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();
~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);
state() const58   WindowState state() const { return state_; }
set_browser(Browser * browser)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 
FullscreenControllerTestWindow()78 FullscreenControllerTestWindow::FullscreenControllerTestWindow()
79     : state_(NORMAL),
80       mac_with_chrome_mode_(false),
81       browser_(NULL) {
82 }
83 
EnterFullscreen(const GURL & url,FullscreenExitBubbleType type)84 void FullscreenControllerTestWindow::EnterFullscreen(
85     const GURL& url, FullscreenExitBubbleType type) {
86   EnterFullscreen(false);
87 }
88 
ExitFullscreen()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 
ShouldHideUIForFullscreen() const99 bool FullscreenControllerTestWindow::ShouldHideUIForFullscreen() const {
100   return IsFullscreen();
101 }
102 
IsFullscreen() const103 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)
SetMetroSnapMode(bool enable)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 
IsInMetroSnapMode() const120 bool FullscreenControllerTestWindow::IsInMetroSnapMode() const {
121   return state_ == METRO_SNAP;
122 }
123 #endif
124 
125 #if defined(OS_MACOSX)
EnterFullscreenWithChrome()126 void FullscreenControllerTestWindow::EnterFullscreenWithChrome() {
127   EnterFullscreen(true);
128 }
129 
IsFullscreenWithChrome()130 bool FullscreenControllerTestWindow::IsFullscreenWithChrome() {
131   return IsFullscreen() && mac_with_chrome_mode_;
132 }
133 
IsFullscreenWithoutChrome()134 bool FullscreenControllerTestWindow::IsFullscreenWithoutChrome() {
135   return IsFullscreen() && !mac_with_chrome_mode_;
136 }
137 #endif
138 
139 // static
GetWindowStateString(WindowState state)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 
ChangeWindowFullscreenState()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 
EnterFullscreen(bool new_mac_with_chrome_mode)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 
IsTransitionReentrant(bool new_fullscreen,bool new_mac_with_chrome_mode)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 
FullscreenControllerStateUnitTest()229 FullscreenControllerStateUnitTest::FullscreenControllerStateUnitTest ()
230     : window_(NULL) {
231 }
232 
SetUp()233 void FullscreenControllerStateUnitTest::SetUp() {
234   BrowserWithTestWindowTest::SetUp();
235   window_->set_browser(browser());
236 }
237 
CreateBrowserWindow()238 BrowserWindow* FullscreenControllerStateUnitTest::CreateBrowserWindow() {
239   window_ = new FullscreenControllerTestWindow();
240   return window_;  // BrowserWithTestWindowTest takes ownership.
241 }
242 
ChangeWindowFullscreenState()243 void FullscreenControllerStateUnitTest::ChangeWindowFullscreenState() {
244   window_->ChangeWindowFullscreenState();
245 }
246 
GetWindowStateString()247 const char* FullscreenControllerStateUnitTest::GetWindowStateString() {
248   return FullscreenControllerTestWindow::GetWindowStateString(window_->state());
249 }
250 
VerifyWindowState()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 
ShouldSkipStateAndEventPair(State state,Event event)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 
GetBrowser()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.
TEST_F(FullscreenControllerStateUnitTest,TransitionsForEachState)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
TEST_F(FullscreenControllerStateUnitTest,DISABLED_ToggleTabWhenPendingBrowser)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
TEST_F(FullscreenControllerStateUnitTest,DISABLED_ToggleTabWhenPendingTab)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
TEST_F(FullscreenControllerStateUnitTest,DISABLED_DebugLogStateTables)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.
TEST_F(FullscreenControllerStateUnitTest,ExitFullscreenViaBrowserWindow)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.
TEST_F(FullscreenControllerStateUnitTest,ExitTabFullscreenViaSwitchingTab)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.
TEST_F(FullscreenControllerStateUnitTest,ExitTabFullscreenViaDetachingTab)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.
TEST_F(FullscreenControllerStateUnitTest,ExitTabFullscreenViaReplacingTab)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.
TEST_F(FullscreenControllerStateUnitTest,OneCapturedFullscreenedTab)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.
TEST_F(FullscreenControllerStateUnitTest,TwoFullscreenedTabsOneCaptured)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.
TEST_F(FullscreenControllerStateUnitTest,BackgroundCapturedTabExitsFullscreen)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.
TEST_F(FullscreenControllerStateUnitTest,OneCapturedTabFullscreenedBeforeBrowserFullscreen)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.
TEST_F(FullscreenControllerStateUnitTest,CapturedFullscreenedTabTransferredBetweenBrowserWindows)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