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#ifndef CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_H_
6#define CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_H_
7
8#include <set>
9
10#include "base/basictypes.h"
11#include "base/memory/weak_ptr.h"
12#include "chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.h"
13#include "components/content_settings/core/common/content_settings.h"
14#include "content/public/browser/notification_observer.h"
15#include "content/public/browser/notification_registrar.h"
16
17class Browser;
18class BrowserWindow;
19class GURL;
20class Profile;
21
22namespace content {
23class WebContents;
24}
25
26// There are two different kinds of fullscreen mode - "tab fullscreen" and
27// "browser fullscreen". "Tab fullscreen" refers to a renderer-initiated
28// fullscreen mode (eg: from a Flash plugin or via the JS fullscreen API),
29// whereas "browser fullscreen" refers to the user putting the browser itself
30// into fullscreen mode from the UI. The difference is that tab fullscreen has
31// implications for how the contents of the tab render (eg: a video element may
32// grow to consume the whole tab), whereas browser fullscreen mode doesn't.
33// Therefore if a user forces an exit from tab fullscreen, we need to notify the
34// tab so it can stop rendering in its fullscreen mode.
35//
36// For Flash, FullscreenController will auto-accept all permission requests for
37// fullscreen and/or mouse lock, since the assumption is that the plugin handles
38// this for us.
39//
40// FullscreenWithinTab Note:
41// All fullscreen widgets are displayed within the tab contents area, and
42// FullscreenController will expand the browser window so that the tab contents
43// area fills the entire screen. However, special behavior applies when a tab is
44// being screen-captured. First, the browser window will not be
45// fullscreened. This allows the user to retain control of their desktop to work
46// in other browser tabs or applications while the fullscreen view is displayed
47// on a remote screen. Second, FullscreenController will auto-resize fullscreen
48// widgets to that of the capture video resolution when they are hidden (e.g.,
49// when a user has switched to another tab). This is both a performance and
50// quality improvement since scaling and letterboxing steps can be skipped in
51// the capture pipeline.
52
53// This class implements fullscreen and mouselock behaviour.
54class FullscreenController : public content::NotificationObserver {
55 public:
56  explicit FullscreenController(Browser* browser);
57  virtual ~FullscreenController();
58
59  // Browser/User Fullscreen ///////////////////////////////////////////////////
60
61  // Returns true if the window is currently fullscreen and was initially
62  // transitioned to fullscreen by a browser (i.e., not tab-initiated) mode
63  // transition.
64  bool IsFullscreenForBrowser() const;
65
66  void ToggleBrowserFullscreenMode();
67
68  // Extension API implementation uses this method to toggle fullscreen mode.
69  // The extension's name is displayed in the full screen bubble UI to attribute
70  // the cause of the full screen state change.
71  void ToggleBrowserFullscreenModeWithExtension(const GURL& extension_url);
72
73  // Tab/HTML/Flash Fullscreen /////////////////////////////////////////////////
74
75  // Returns true if the browser window has/will fullscreen because of
76  // tab-initiated fullscreen. The window may still be transitioning, and
77  // BrowserWindow::IsFullscreen() may still return false.
78  bool IsWindowFullscreenForTabOrPending() const;
79
80  // Returns true if the tab is/will be in fullscreen mode. Note: This does NOT
81  // indicate whether the browser window is/will be fullscreened as well. See
82  // 'FullscreenWithinTab Note'.
83  bool IsFullscreenForTabOrPending(
84      const content::WebContents* web_contents) const;
85
86  // True if fullscreen was entered because of tab fullscreen (was not
87  // previously in user-initiated fullscreen).
88  bool IsFullscreenCausedByTab() const;
89
90  // Enter or leave tab-initiated fullscreen mode. FullscreenController will
91  // decide whether to also fullscreen the browser window. See
92  // 'FullscreenWithinTab Note'.
93  void ToggleFullscreenModeForTab(content::WebContents* web_contents,
94                                  bool enter_fullscreen);
95
96  // Platform Fullscreen ///////////////////////////////////////////////////////
97
98  // Returns whether we are currently in a Metro snap view.
99  bool IsInMetroSnapMode();
100
101#if defined(OS_WIN)
102  // API that puts the window into a mode suitable for rendering when Chrome
103  // is rendered in a 20% screen-width Metro snap view on Windows 8.
104  void SetMetroSnapMode(bool enable);
105#endif
106
107#if defined(OS_MACOSX)
108  void ToggleBrowserFullscreenWithChrome();
109#endif
110
111  // Mouse Lock ////////////////////////////////////////////////////////////////
112
113  bool IsMouseLockRequested() const;
114  bool IsMouseLocked() const;
115
116  void RequestToLockMouse(content::WebContents* web_contents,
117                          bool user_gesture,
118                          bool last_unlocked_by_target);
119
120  // Callbacks /////////////////////////////////////////////////////////////////
121
122  // Called by Browser::TabDeactivated.
123  void OnTabDeactivated(content::WebContents* web_contents);
124
125  // Called by Browser::ActiveTabChanged.
126  void OnTabDetachedFromView(content::WebContents* web_contents);
127
128  // Called by Browser::TabClosingAt.
129  void OnTabClosing(content::WebContents* web_contents);
130
131  // Called by Browser::WindowFullscreenStateChanged.
132  void WindowFullscreenStateChanged();
133
134  // Called by Browser::PreHandleKeyboardEvent.
135  bool HandleUserPressedEscape();
136
137  // Called by platform FullscreenExitBubble.
138  void ExitTabOrBrowserFullscreenToPreviousState();
139  void OnAcceptFullscreenPermission();
140  void OnDenyFullscreenPermission();
141
142  // Called by Browser::LostMouseLock.
143  void LostMouseLock();
144
145  // content::NotificationObserver:
146  virtual void Observe(int type,
147                       const content::NotificationSource& source,
148                       const content::NotificationDetails& details) OVERRIDE;
149
150  // Bubble Content ////////////////////////////////////////////////////////////
151
152  GURL GetFullscreenExitBubbleURL() const;
153  FullscreenExitBubbleType GetFullscreenExitBubbleType() const;
154
155 private:
156  friend class FullscreenControllerTest;
157
158  enum MouseLockState {
159    MOUSELOCK_NOT_REQUESTED,
160    // The page requests to lock the mouse and the user hasn't responded to the
161    // request.
162    MOUSELOCK_REQUESTED,
163    // Mouse lock has been allowed by the user.
164    MOUSELOCK_ACCEPTED,
165    // Mouse lock has been silently accepted, no notification to user.
166    MOUSELOCK_ACCEPTED_SILENTLY
167  };
168
169  enum FullscreenInternalOption {
170    BROWSER,
171#if defined(OS_MACOSX)
172    BROWSER_WITH_CHROME,
173#endif
174    TAB
175  };
176
177  void UpdateNotificationRegistrations();
178
179  // Posts a task to call NotifyFullscreenChange.
180  void PostFullscreenChangeNotification(bool is_fullscreen);
181  // Sends a NOTIFICATION_FULLSCREEN_CHANGED notification.
182  void NotifyFullscreenChange(bool is_fullscreen);
183  // Notifies the tab that it has been forced out of fullscreen and mouse lock
184  // mode if necessary.
185  void NotifyTabOfExitIfNecessary();
186  void NotifyMouseLockChange();
187
188  void ToggleFullscreenModeInternal(FullscreenInternalOption option);
189  void EnterFullscreenModeInternal(FullscreenInternalOption option);
190  void ExitFullscreenModeInternal();
191  void SetFullscreenedTab(content::WebContents* tab);
192  void SetMouseLockTab(content::WebContents* tab);
193
194  // Make the current tab exit fullscreen mode or mouse lock if it is in it.
195  void ExitTabFullscreenOrMouseLockIfNecessary();
196  void UpdateFullscreenExitBubbleContent();
197
198  ContentSetting GetFullscreenSetting(const GURL& url) const;
199  ContentSetting GetMouseLockSetting(const GURL& url) const;
200
201  bool IsPrivilegedFullscreenForTab() const;
202  void SetPrivilegedFullscreenForTesting(bool is_privileged);
203  // Returns true if |web_contents| was toggled into/out of fullscreen mode as a
204  // screen-captured tab. See 'FullscreenWithinTab Note'.
205  bool MaybeToggleFullscreenForCapturedTab(content::WebContents* web_contents,
206                                           bool enter_fullscreen);
207  // Returns true if |web_contents| is in fullscreen mode as a screen-captured
208  // tab. See 'FullscreenWithinTab Note'.
209  bool IsFullscreenForCapturedTab(const content::WebContents* web_contents)
210      const;
211  void UnlockMouse();
212
213  Browser* const browser_;
214  BrowserWindow* const window_;
215  Profile* const profile_;
216
217  // If there is currently a tab in fullscreen mode (entered via
218  // webkitRequestFullScreen), this is its WebContents.
219  // Assign using SetFullscreenedTab().
220  content::WebContents* fullscreened_tab_;
221
222  // The URL of the extension which trigerred "browser fullscreen" mode.
223  GURL extension_caused_fullscreen_;
224
225  enum PriorFullscreenState {
226    STATE_INVALID,
227    STATE_NORMAL,
228    STATE_BROWSER_FULLSCREEN_NO_CHROME,
229#if defined(OS_MACOSX)
230    STATE_BROWSER_FULLSCREEN_WITH_CHROME,
231#endif
232  };
233  // The state before entering tab fullscreen mode via webkitRequestFullScreen.
234  // When not in tab fullscreen, it is STATE_INVALID.
235  PriorFullscreenState state_prior_to_tab_fullscreen_;
236  // True if tab fullscreen has been allowed, either by settings or by user
237  // clicking the allow button on the fullscreen infobar.
238  bool tab_fullscreen_accepted_;
239
240  // True if this controller has toggled into tab OR browser fullscreen.
241  bool toggled_into_fullscreen_;
242
243  // WebContents for current tab requesting or currently in mouse lock.
244  // Assign using SetMouseLockTab().
245  content::WebContents* mouse_lock_tab_;
246
247  MouseLockState mouse_lock_state_;
248
249  content::NotificationRegistrar registrar_;
250
251  // Used to verify that calls we expect to reenter by calling
252  // WindowFullscreenStateChanged do so.
253  bool reentrant_window_state_change_call_check_;
254
255  // Used in testing to confirm proper behavior for specific, privileged
256  // fullscreen cases.
257  bool is_privileged_fullscreen_for_testing_;
258
259  base::WeakPtrFactory<FullscreenController> ptr_factory_;
260
261  DISALLOW_COPY_AND_ASSIGN(FullscreenController);
262};
263
264#endif  // CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_H_
265