Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: chrome/browser/ui/exclusive_access/mouse_lock_controller.cc

Issue 836933005: Refactor fullscreen_controller. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" 5 #include "chrome/browser/ui/exclusive_access/mouse_lock_controller.h"
6 6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "chrome/browser/app_mode/app_mode_utils.h"
11 #include "chrome/browser/chrome_notification_types.h" 7 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/download/download_shelf.h"
13 #include "chrome/browser/profiles/profile.h" 8 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h" 9 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_window.h" 10 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
16 #include "chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h"
17 #include "chrome/browser/ui/status_bubble.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/browser/ui/web_contents_sizer.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "components/content_settings/core/browser/host_content_settings_map.h" 11 #include "components/content_settings/core/browser/host_content_settings_map.h"
22 #include "content/public/browser/navigation_details.h"
23 #include "content/public/browser/navigation_entry.h"
24 #include "content/public/browser/notification_service.h" 12 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/render_view_host.h" 13 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/render_widget_host_view.h" 14 #include "content/public/browser/render_widget_host_view.h"
27 #include "content/public/browser/user_metrics.h"
28 #include "content/public/browser/web_contents.h" 15 #include "content/public/browser/web_contents.h"
29 #include "extensions/common/extension.h"
30 16
31 #if !defined(OS_MACOSX)
32 #include "base/prefs/pref_service.h"
33 #include "chrome/common/pref_names.h"
34 #endif
35
36 using base::UserMetricsAction;
37 using content::RenderViewHost; 17 using content::RenderViewHost;
38 using content::WebContents; 18 using content::WebContents;
39 19
40 FullscreenController::FullscreenController(Browser* browser) 20 MouseLockController::MouseLockController(
41 : browser_(browser), 21 ExclusiveAccessControllerManager* manager,
42 window_(browser->window()), 22 Browser* browser)
43 profile_(browser->profile()), 23 : ExclusiveAccessControllerBase(manager, browser),
44 fullscreened_tab_(NULL), 24 mouse_lock_state_(MOUSELOCK_NOT_REQUESTED) {
45 state_prior_to_tab_fullscreen_(STATE_INVALID),
46 tab_fullscreen_accepted_(false),
47 toggled_into_fullscreen_(false),
48 mouse_lock_tab_(NULL),
49 mouse_lock_state_(MOUSELOCK_NOT_REQUESTED),
50 reentrant_window_state_change_call_check_(false),
51 is_privileged_fullscreen_for_testing_(false),
52 ptr_factory_(this) {
53 DCHECK(window_);
54 DCHECK(profile_);
55 } 25 }
56 26
57 FullscreenController::~FullscreenController() { 27 MouseLockController::~MouseLockController() {
58 } 28 }
59 29
60 bool FullscreenController::IsFullscreenForBrowser() const { 30 bool MouseLockController::IsMouseLocked() const {
61 return window_->IsFullscreen() && !IsFullscreenCausedByTab();
62 }
63
64 void FullscreenController::ToggleBrowserFullscreenMode() {
65 extension_caused_fullscreen_ = GURL();
66 ToggleFullscreenModeInternal(BROWSER);
67 }
68
69 void FullscreenController::ToggleBrowserFullscreenWithToolbar() {
70 ToggleFullscreenModeInternal(BROWSER_WITH_TOOLBAR);
71 }
72
73 void FullscreenController::ToggleBrowserFullscreenModeWithExtension(
74 const GURL& extension_url) {
75 // |extension_caused_fullscreen_| will be reset if this causes fullscreen to
76 // exit.
77 extension_caused_fullscreen_ = extension_url;
78 ToggleFullscreenModeInternal(BROWSER);
79 }
80
81 bool FullscreenController::IsWindowFullscreenForTabOrPending() const {
82 return fullscreened_tab_ != NULL;
83 }
84
85 bool FullscreenController::IsFullscreenForTabOrPending(
86 const WebContents* web_contents) const {
87 if (web_contents == fullscreened_tab_) {
88 DCHECK(web_contents == browser_->tab_strip_model()->GetActiveWebContents());
89 DCHECK(web_contents->GetCapturerCount() == 0);
90 return true;
91 }
92 return IsFullscreenForCapturedTab(web_contents);
93 }
94
95 bool FullscreenController::IsFullscreenCausedByTab() const {
96 return state_prior_to_tab_fullscreen_ == STATE_NORMAL;
97 }
98
99 void FullscreenController::ToggleFullscreenModeForTab(WebContents* web_contents,
100 bool enter_fullscreen) {
101 if (MaybeToggleFullscreenForCapturedTab(web_contents, enter_fullscreen)) {
102 // During tab capture of fullscreen-within-tab views, the browser window
103 // fullscreen state is unchanged, so return now.
104 return;
105 }
106 if (fullscreened_tab_) {
107 if (web_contents != fullscreened_tab_)
108 return;
109 } else if (
110 web_contents != browser_->tab_strip_model()->GetActiveWebContents()) {
111 return;
112 }
113 if (IsWindowFullscreenForTabOrPending() == enter_fullscreen)
114 return;
115
116 #if defined(OS_WIN)
117 // For now, avoid breaking when initiating full screen tab mode while in
118 // a metro snap.
119 // TODO(robertshield): Find a way to reconcile tab-initiated fullscreen
120 // modes with metro snap.
121 if (IsInMetroSnapMode())
122 return;
123 #endif
124
125 bool in_browser_or_tab_fullscreen_mode = window_->IsFullscreen();
126
127 if (enter_fullscreen) {
128 SetFullscreenedTab(web_contents);
129 if (!in_browser_or_tab_fullscreen_mode) {
130 // Normal -> Tab Fullscreen.
131 state_prior_to_tab_fullscreen_ = STATE_NORMAL;
132 ToggleFullscreenModeInternal(TAB);
133 } else {
134 if (window_->IsFullscreenWithToolbar()) {
135 // Browser Fullscreen with Toolbar -> Tab Fullscreen (no toolbar).
136 window_->UpdateFullscreenWithToolbar(false);
137 state_prior_to_tab_fullscreen_ = STATE_BROWSER_FULLSCREEN_WITH_TOOLBAR;
138 } else {
139 // Browser Fullscreen without Toolbar -> Tab Fullscreen.
140 state_prior_to_tab_fullscreen_ = STATE_BROWSER_FULLSCREEN_NO_TOOLBAR;
141 }
142
143 // We need to update the fullscreen exit bubble, e.g., going from browser
144 // fullscreen to tab fullscreen will need to show different content.
145 const GURL& url = web_contents->GetURL();
146 if (!tab_fullscreen_accepted_) {
147 tab_fullscreen_accepted_ =
148 GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW;
149 }
150 UpdateFullscreenExitBubbleContent();
151
152 // This is only a change between Browser and Tab fullscreen. We generate
153 // a fullscreen notification now because there is no window change.
154 PostFullscreenChangeNotification(true);
155 }
156 } else {
157 if (in_browser_or_tab_fullscreen_mode) {
158 if (IsFullscreenCausedByTab()) {
159 // Tab Fullscreen -> Normal.
160 ToggleFullscreenModeInternal(TAB);
161 } else {
162 // Tab Fullscreen -> Browser Fullscreen (with or without toolbar).
163 if (state_prior_to_tab_fullscreen_ ==
164 STATE_BROWSER_FULLSCREEN_WITH_TOOLBAR) {
165 // Tab Fullscreen (no toolbar) -> Browser Fullscreen with Toolbar.
166 window_->UpdateFullscreenWithToolbar(true);
167 }
168
169 #if defined(OS_MACOSX)
170 // Clear the bubble URL, which forces the Mac UI to redraw.
171 UpdateFullscreenExitBubbleContent();
172 #endif // defined(OS_MACOSX)
173
174 // If currently there is a tab in "tab fullscreen" mode and fullscreen
175 // was not caused by it (i.e., previously it was in "browser fullscreen"
176 // mode), we need to switch back to "browser fullscreen" mode. In this
177 // case, all we have to do is notifying the tab that it has exited "tab
178 // fullscreen" mode.
179 NotifyTabOfExitIfNecessary();
180
181 // This is only a change between Browser and Tab fullscreen. We generate
182 // a fullscreen notification now because there is no window change.
183 PostFullscreenChangeNotification(true);
184 }
185 }
186 }
187 }
188
189 bool FullscreenController::IsInMetroSnapMode() {
190 #if defined(OS_WIN)
191 return window_->IsInMetroSnapMode();
192 #else
193 return false;
194 #endif
195 }
196
197 #if defined(OS_WIN)
198 void FullscreenController::SetMetroSnapMode(bool enable) {
199 reentrant_window_state_change_call_check_ = false;
200
201 toggled_into_fullscreen_ = false;
202 window_->SetMetroSnapMode(enable);
203
204 // FullscreenController unit tests for metro snap assume that on Windows calls
205 // to WindowFullscreenStateChanged are reentrant. If that assumption is
206 // invalidated, the tests must be updated to maintain coverage.
207 CHECK(reentrant_window_state_change_call_check_);
208 }
209 #endif // defined(OS_WIN)
210
211 bool FullscreenController::IsMouseLockRequested() const {
212 return mouse_lock_state_ == MOUSELOCK_REQUESTED;
213 }
214
215 bool FullscreenController::IsMouseLocked() const {
216 return mouse_lock_state_ == MOUSELOCK_ACCEPTED || 31 return mouse_lock_state_ == MOUSELOCK_ACCEPTED ||
217 mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY; 32 mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY;
218 } 33 }
219 34
220 void FullscreenController::RequestToLockMouse(WebContents* web_contents, 35 bool MouseLockController::IsMouseLockSilentlyAccepted() const {
221 bool user_gesture, 36 return mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY;
222 bool last_unlocked_by_target) { 37 }
38
39 void MouseLockController::RequestToLockMouse(WebContents* web_contents,
40 bool user_gesture,
41 bool last_unlocked_by_target) {
223 DCHECK(!IsMouseLocked()); 42 DCHECK(!IsMouseLocked());
224 NotifyMouseLockChange(); 43 NotifyMouseLockChange();
225 44
226 // Must have a user gesture to prevent misbehaving sites from constantly 45 // Must have a user gesture to prevent misbehaving sites from constantly
227 // re-locking the mouse. Exceptions are when the page has unlocked 46 // re-locking the mouse. Exceptions are when the page has unlocked
228 // (i.e. not the user), or if we're in tab fullscreen (user gesture required 47 // (i.e. not the user), or if we're in tab fullscreen (user gesture required
229 // for that) 48 // for that)
230 if (!last_unlocked_by_target && !user_gesture && 49 if (!last_unlocked_by_target && !user_gesture &&
231 !IsFullscreenForTabOrPending(web_contents)) { 50 !GetManager()->GetFullscreenController()->IsFullscreenForTabOrPending(
51 web_contents)) {
232 web_contents->GotResponseToLockMouseRequest(false); 52 web_contents->GotResponseToLockMouseRequest(false);
233 return; 53 return;
234 } 54 }
235 SetMouseLockTab(web_contents); 55 SetTabWithExclusiveAccess(web_contents);
236 ExclusiveAccessBubbleType bubble_type = GetExclusiveAccessBubbleType(); 56 ExclusiveAccessBubbleType bubble_type = GetExclusiveAccessExitBubbleType();
237 57
238 switch (GetMouseLockSetting(web_contents->GetURL())) { 58 switch (GetMouseLockSetting(web_contents->GetURL())) {
239 case CONTENT_SETTING_ALLOW: 59 case CONTENT_SETTING_ALLOW:
240 // If bubble already displaying buttons we must not lock the mouse yet, 60 // If bubble already displaying buttons we must not lock the mouse yet,
241 // or it would prevent pressing those buttons. Instead, merge the request. 61 // or it would prevent pressing those buttons. Instead, merge the request.
242 if (!IsPrivilegedFullscreenForTab() && 62 if (!GetManager()
63 ->GetFullscreenController()
64 ->IsPrivilegedFullscreenForTab() &&
243 exclusive_access_bubble::ShowButtonsForType(bubble_type)) { 65 exclusive_access_bubble::ShowButtonsForType(bubble_type)) {
244 mouse_lock_state_ = MOUSELOCK_REQUESTED; 66 mouse_lock_state_ = MOUSELOCK_REQUESTED;
245 } else { 67 } else {
246 // Lock mouse. 68 // Lock mouse.
247 if (web_contents->GotResponseToLockMouseRequest(true)) { 69 if (web_contents->GotResponseToLockMouseRequest(true)) {
248 if (last_unlocked_by_target) { 70 if (last_unlocked_by_target) {
249 mouse_lock_state_ = MOUSELOCK_ACCEPTED_SILENTLY; 71 mouse_lock_state_ = MOUSELOCK_ACCEPTED_SILENTLY;
250 } else { 72 } else {
251 mouse_lock_state_ = MOUSELOCK_ACCEPTED; 73 mouse_lock_state_ = MOUSELOCK_ACCEPTED;
252 } 74 }
253 } else { 75 } else {
254 SetMouseLockTab(NULL); 76 SetTabWithExclusiveAccess(nullptr);
255 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED; 77 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
256 } 78 }
257 } 79 }
258 break; 80 break;
259 case CONTENT_SETTING_BLOCK: 81 case CONTENT_SETTING_BLOCK:
260 web_contents->GotResponseToLockMouseRequest(false); 82 web_contents->GotResponseToLockMouseRequest(false);
261 SetMouseLockTab(NULL); 83 SetTabWithExclusiveAccess(nullptr);
262 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED; 84 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
263 break; 85 break;
264 case CONTENT_SETTING_ASK: 86 case CONTENT_SETTING_ASK:
265 mouse_lock_state_ = MOUSELOCK_REQUESTED; 87 mouse_lock_state_ = MOUSELOCK_REQUESTED;
266 break; 88 break;
267 default: 89 default:
268 NOTREACHED(); 90 NOTREACHED();
269 } 91 }
270 UpdateFullscreenExitBubbleContent(); 92 UpdateExclusiveAccessExitBubbleContent();
271 } 93 }
272 94
273 void FullscreenController::OnTabDeactivated(WebContents* web_contents) { 95 void MouseLockController::ExitExclusiveAccessIfNecessary() {
274 if (web_contents == fullscreened_tab_ || web_contents == mouse_lock_tab_) 96 NotifyTabOfExclusiveAccessChange();
275 ExitTabFullscreenOrMouseLockIfNecessary();
276 } 97 }
277 98
278 void FullscreenController::OnTabDetachedFromView(WebContents* old_contents) { 99 void MouseLockController::NotifyTabOfExclusiveAccessChange() {
279 if (!IsFullscreenForCapturedTab(old_contents)) 100 WebContents* tab = GetExclusiveAccessTab();
280 return; 101 if (tab) {
281 102 if (IsMouseLockRequested()) {
282 // A fullscreen-within-tab view undergoing screen capture has been detached 103 tab->GotResponseToLockMouseRequest(false);
283 // and is no longer visible to the user. Set it to exactly the WebContents' 104 NotifyMouseLockChange();
284 // preferred size. See 'FullscreenWithinTab Note'. 105 } else {
285 // 106 UnlockMouse();
286 // When the user later selects the tab to show |old_contents| again, UI code 107 }
287 // elsewhere (e.g., views::WebView) will resize the view to fit within the 108 SetTabWithExclusiveAccess(nullptr);
288 // browser window once again. 109 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
289 110 UpdateExclusiveAccessExitBubbleContent();
290 // If the view has been detached from the browser window (e.g., to drag a tab
291 // off into a new browser window), return immediately to avoid an unnecessary
292 // resize.
293 if (!old_contents->GetDelegate())
294 return;
295
296 // Do nothing if tab capture ended after toggling fullscreen, or a preferred
297 // size was never specified by the capturer.
298 if (old_contents->GetCapturerCount() == 0 ||
299 old_contents->GetPreferredSize().IsEmpty()) {
300 return;
301 }
302
303 content::RenderWidgetHostView* const current_fs_view =
304 old_contents->GetFullscreenRenderWidgetHostView();
305 if (current_fs_view)
306 current_fs_view->SetSize(old_contents->GetPreferredSize());
307 ResizeWebContents(old_contents, old_contents->GetPreferredSize());
308 }
309
310 void FullscreenController::OnTabClosing(WebContents* web_contents) {
311 if (IsFullscreenForCapturedTab(web_contents)) {
312 RenderViewHost* const rvh = web_contents->GetRenderViewHost();
313 if (rvh)
314 rvh->ExitFullscreen();
315 } else if (web_contents == fullscreened_tab_ ||
316 web_contents == mouse_lock_tab_) {
317 ExitTabFullscreenOrMouseLockIfNecessary();
318 // The call to exit fullscreen may result in asynchronous notification of
319 // fullscreen state change (e.g., on Linux). We don't want to rely on it
320 // to call NotifyTabOfExitIfNecessary(), because at that point
321 // |fullscreened_tab_| may not be valid. Instead, we call it here to clean
322 // up tab fullscreen related state.
323 NotifyTabOfExitIfNecessary();
324 } 111 }
325 } 112 }
326 113
327 void FullscreenController::WindowFullscreenStateChanged() { 114 bool MouseLockController::HandleUserPressedEscape() {
328 reentrant_window_state_change_call_check_ = true; 115 if (IsMouseLocked() || IsMouseLockRequested()) {
329 116 ExitExclusiveAccessIfNecessary();
330 bool exiting_fullscreen = !window_->IsFullscreen();
331
332 PostFullscreenChangeNotification(!exiting_fullscreen);
333 if (exiting_fullscreen) {
334 toggled_into_fullscreen_ = false;
335 extension_caused_fullscreen_ = GURL();
336 NotifyTabOfExitIfNecessary();
337 }
338 if (exiting_fullscreen) {
339 window_->GetDownloadShelf()->Unhide();
340 } else {
341 window_->GetDownloadShelf()->Hide();
342 if (window_->GetStatusBubble())
343 window_->GetStatusBubble()->Hide();
344 }
345 }
346
347 bool FullscreenController::HandleUserPressedEscape() {
348 WebContents* const active_web_contents =
349 browser_->tab_strip_model()->GetActiveWebContents();
350 if (IsFullscreenForCapturedTab(active_web_contents)) {
351 RenderViewHost* const rvh = active_web_contents->GetRenderViewHost();
352 if (rvh)
353 rvh->ExitFullscreen();
354 return true;
355 } else if (IsWindowFullscreenForTabOrPending() ||
356 IsMouseLocked() || IsMouseLockRequested()) {
357 ExitTabFullscreenOrMouseLockIfNecessary();
358 return true; 117 return true;
359 } 118 }
360 119
361 return false; 120 return false;
362 } 121 }
363 122
364 void FullscreenController::ExitTabOrBrowserFullscreenToPreviousState() { 123 void MouseLockController::ExitExclusiveAccessToPreviousState() {
365 if (IsWindowFullscreenForTabOrPending()) 124 // Nothing to do for mouse lock.
366 ExitTabFullscreenOrMouseLockIfNecessary();
367 else if (IsFullscreenForBrowser())
368 ExitFullscreenModeInternal();
369 } 125 }
370 126
371 void FullscreenController::OnAcceptFullscreenPermission() { 127 bool MouseLockController::OnAcceptExclusiveAccessPermission() {
372 ExclusiveAccessBubbleType bubble_type = GetExclusiveAccessBubbleType(); 128 ExclusiveAccessBubbleType bubble_type = GetExclusiveAccessExitBubbleType();
373 bool mouse_lock = false; 129 bool mouse_lock = false;
374 bool fullscreen = false; 130 exclusive_access_bubble::PermissionRequestedByType(bubble_type, nullptr,
375 exclusive_access_bubble::PermissionRequestedByType(bubble_type, &fullscreen,
376 &mouse_lock); 131 &mouse_lock);
377 DCHECK(!(fullscreen && tab_fullscreen_accepted_));
378 DCHECK(!(mouse_lock && IsMouseLocked())); 132 DCHECK(!(mouse_lock && IsMouseLocked()));
379 133
380 HostContentSettingsMap* settings_map = profile_->GetHostContentSettingsMap();
381
382 GURL url = GetFullscreenExitBubbleURL();
383 ContentSettingsPattern pattern = ContentSettingsPattern::FromURL(url);
384
385 if (mouse_lock && !IsMouseLocked()) { 134 if (mouse_lock && !IsMouseLocked()) {
386 DCHECK(IsMouseLockRequested()); 135 DCHECK(IsMouseLockRequested());
136
137 HostContentSettingsMap* settings_map =
138 GetProfile()->GetHostContentSettingsMap();
139
140 GURL url = GetExclusiveAccessBubbleURL();
141 ContentSettingsPattern pattern = ContentSettingsPattern::FromURL(url);
142
387 // TODO(markusheintz): We should allow patterns for all possible URLs here. 143 // TODO(markusheintz): We should allow patterns for all possible URLs here.
388 if (pattern.IsValid()) { 144 if (pattern.IsValid()) {
389 settings_map->SetContentSetting( 145 settings_map->SetContentSetting(pattern,
390 pattern, ContentSettingsPattern::Wildcard(), 146 ContentSettingsPattern::Wildcard(),
391 CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string(), 147 CONTENT_SETTINGS_TYPE_MOUSELOCK,
392 CONTENT_SETTING_ALLOW); 148 std::string(), CONTENT_SETTING_ALLOW);
393 } 149 }
394 150
395 if (mouse_lock_tab_ && 151 WebContents* tab = GetExclusiveAccessTab();
396 mouse_lock_tab_->GotResponseToLockMouseRequest(true)) { 152 if (tab && tab->GotResponseToLockMouseRequest(true)) {
397 mouse_lock_state_ = MOUSELOCK_ACCEPTED; 153 mouse_lock_state_ = MOUSELOCK_ACCEPTED;
398 } else { 154 } else {
399 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED; 155 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
400 SetMouseLockTab(NULL); 156 SetTabWithExclusiveAccess(nullptr);
401 } 157 }
402 NotifyMouseLockChange(); 158 NotifyMouseLockChange();
403 } 159 return true;
404
405 if (fullscreen && !tab_fullscreen_accepted_) {
406 DCHECK(fullscreened_tab_);
407 if (pattern.IsValid()) {
408 settings_map->SetContentSetting(
409 pattern, ContentSettingsPattern::Wildcard(),
410 CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string(),
411 CONTENT_SETTING_ALLOW);
412 }
413 tab_fullscreen_accepted_ = true;
414 }
415 UpdateFullscreenExitBubbleContent();
416 }
417
418 void FullscreenController::OnDenyFullscreenPermission() {
419 if (!fullscreened_tab_ && !mouse_lock_tab_)
420 return;
421
422 if (IsMouseLockRequested()) {
423 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
424 if (mouse_lock_tab_)
425 mouse_lock_tab_->GotResponseToLockMouseRequest(false);
426 SetMouseLockTab(NULL);
427 NotifyMouseLockChange();
428
429 // UpdateFullscreenExitBubbleContent() must be called, but to avoid
430 // duplicate calls we do so only if not adjusting the fullscreen state
431 // below, which also calls UpdateFullscreenExitBubbleContent().
432 if (!IsWindowFullscreenForTabOrPending())
433 UpdateFullscreenExitBubbleContent();
434 }
435
436 if (IsWindowFullscreenForTabOrPending())
437 ExitTabFullscreenOrMouseLockIfNecessary();
438 }
439
440 void FullscreenController::LostMouseLock() {
441 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
442 SetMouseLockTab(NULL);
443 NotifyMouseLockChange();
444 UpdateFullscreenExitBubbleContent();
445 }
446
447 void FullscreenController::Observe(int type,
448 const content::NotificationSource& source,
449 const content::NotificationDetails& details) {
450 DCHECK_EQ(content::NOTIFICATION_NAV_ENTRY_COMMITTED, type);
451 if (content::Details<content::LoadCommittedDetails>(details)->
452 is_navigation_to_different_page())
453 ExitTabFullscreenOrMouseLockIfNecessary();
454 }
455
456 GURL FullscreenController::GetFullscreenExitBubbleURL() const {
457 if (fullscreened_tab_)
458 return fullscreened_tab_->GetURL();
459 if (mouse_lock_tab_)
460 return mouse_lock_tab_->GetURL();
461 return extension_caused_fullscreen_;
462 }
463
464 ExclusiveAccessBubbleType FullscreenController::GetExclusiveAccessBubbleType()
465 const {
466 // In kiosk and exclusive app mode we always want to be fullscreen and do not
467 // want to show exit instructions for browser mode fullscreen.
468 bool app_mode = false;
469 #if !defined(OS_MACOSX) // App mode (kiosk) is not available on Mac yet.
470 app_mode = chrome::IsRunningInAppMode();
471 #endif
472
473 if (mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY)
474 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE;
475
476 if (!fullscreened_tab_) {
477 if (IsMouseLocked())
478 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_MOUSELOCK_EXIT_INSTRUCTION;
479 if (IsMouseLockRequested())
480 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_MOUSELOCK_BUTTONS;
481 if (!extension_caused_fullscreen_.is_empty())
482 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION;
483 if (toggled_into_fullscreen_ && !app_mode)
484 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION;
485 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE;
486 }
487
488 if (tab_fullscreen_accepted_) {
489 if (IsPrivilegedFullscreenForTab())
490 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE;
491 if (IsMouseLocked())
492 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_MOUSELOCK_EXIT_INSTRUCTION;
493 if (IsMouseLockRequested())
494 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_MOUSELOCK_BUTTONS;
495 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION;
496 }
497
498 if (IsMouseLockRequested())
499 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_MOUSELOCK_BUTTONS;
500 return EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_BUTTONS;
501 }
502
503 void FullscreenController::UpdateNotificationRegistrations() {
504 if (fullscreened_tab_ && mouse_lock_tab_)
505 DCHECK(fullscreened_tab_ == mouse_lock_tab_);
506
507 WebContents* tab = fullscreened_tab_ ? fullscreened_tab_ : mouse_lock_tab_;
508
509 if (tab && registrar_.IsEmpty()) {
510 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
511 content::Source<content::NavigationController>(&tab->GetController()));
512 } else if (!tab && !registrar_.IsEmpty()) {
513 registrar_.RemoveAll();
514 }
515 }
516
517 void FullscreenController::PostFullscreenChangeNotification(
518 bool is_fullscreen) {
519 base::MessageLoop::current()->PostTask(
520 FROM_HERE,
521 base::Bind(&FullscreenController::NotifyFullscreenChange,
522 ptr_factory_.GetWeakPtr(),
523 is_fullscreen));
524 }
525
526 void FullscreenController::NotifyFullscreenChange(bool is_fullscreen) {
527 content::NotificationService::current()->Notify(
528 chrome::NOTIFICATION_FULLSCREEN_CHANGED,
529 content::Source<FullscreenController>(this),
530 content::Details<bool>(&is_fullscreen));
531 }
532
533 void FullscreenController::NotifyTabOfExitIfNecessary() {
534 if (fullscreened_tab_) {
535 RenderViewHost* rvh = fullscreened_tab_->GetRenderViewHost();
536 SetFullscreenedTab(NULL);
537 state_prior_to_tab_fullscreen_ = STATE_INVALID;
538 tab_fullscreen_accepted_ = false;
539 if (rvh)
540 rvh->ExitFullscreen();
541 }
542
543 if (mouse_lock_tab_) {
544 if (IsMouseLockRequested()) {
545 mouse_lock_tab_->GotResponseToLockMouseRequest(false);
546 NotifyMouseLockChange();
547 } else {
548 UnlockMouse();
549 }
550 SetMouseLockTab(NULL);
551 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
552 }
553
554 UpdateFullscreenExitBubbleContent();
555 }
556
557 void FullscreenController::NotifyMouseLockChange() {
558 content::NotificationService::current()->Notify(
559 chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
560 content::Source<FullscreenController>(this),
561 content::NotificationService::NoDetails());
562 }
563
564 void FullscreenController::ToggleFullscreenModeInternal(
565 FullscreenInternalOption option) {
566 #if defined(OS_WIN)
567 // When in Metro snap mode, toggling in and out of fullscreen is prevented.
568 if (IsInMetroSnapMode())
569 return;
570 #endif
571
572 bool enter_fullscreen = !window_->IsFullscreen();
573
574 // When a Mac user requests a toggle they may be toggling between
575 // FullscreenWithoutChrome and FullscreenWithToolbar.
576 if (window_->IsFullscreen() &&
577 !IsWindowFullscreenForTabOrPending() &&
578 window_->SupportsFullscreenWithToolbar()) {
579 if (option == BROWSER_WITH_TOOLBAR) {
580 enter_fullscreen =
581 enter_fullscreen || !window_->IsFullscreenWithToolbar();
582 } else {
583 enter_fullscreen = enter_fullscreen || window_->IsFullscreenWithToolbar();
584 }
585 }
586
587 // In kiosk mode, we always want to be fullscreen. When the browser first
588 // starts we're not yet fullscreen, so let the initial toggle go through.
589 if (chrome::IsRunningInAppMode() && window_->IsFullscreen())
590 return;
591
592 #if !defined(OS_MACOSX)
593 // Do not enter fullscreen mode if disallowed by pref. This prevents the user
594 // from manually entering fullscreen mode and also disables kiosk mode on
595 // desktop platforms.
596 if (enter_fullscreen &&
597 !profile_->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed)) {
598 return;
599 }
600 #endif
601
602 if (enter_fullscreen)
603 EnterFullscreenModeInternal(option);
604 else
605 ExitFullscreenModeInternal();
606 }
607
608 void FullscreenController::EnterFullscreenModeInternal(
609 FullscreenInternalOption option) {
610 toggled_into_fullscreen_ = true;
611 GURL url;
612 if (option == TAB) {
613 url = browser_->tab_strip_model()->GetActiveWebContents()->GetURL();
614 tab_fullscreen_accepted_ =
615 GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW;
616 } else {
617 if (!extension_caused_fullscreen_.is_empty())
618 url = extension_caused_fullscreen_;
619 }
620
621 if (option == BROWSER)
622 content::RecordAction(UserMetricsAction("ToggleFullscreen"));
623 // TODO(scheib): Record metrics for WITH_TOOLBAR, without counting transitions
624 // from tab fullscreen out to browser with toolbar.
625
626 window_->EnterFullscreen(url, GetExclusiveAccessBubbleType(),
627 option == BROWSER_WITH_TOOLBAR);
628
629 UpdateFullscreenExitBubbleContent();
630
631 // Once the window has become fullscreen it'll call back to
632 // WindowFullscreenStateChanged(). We don't do this immediately as
633 // BrowserWindow::EnterFullscreen() asks for bookmark_bar_state_, so we let
634 // the BrowserWindow invoke WindowFullscreenStateChanged when appropriate.
635 }
636
637 void FullscreenController::ExitFullscreenModeInternal() {
638 toggled_into_fullscreen_ = false;
639 #if defined(OS_MACOSX)
640 // Mac windows report a state change instantly, and so we must also clear
641 // state_prior_to_tab_fullscreen_ to match them else other logic using
642 // state_prior_to_tab_fullscreen_ will be incorrect.
643 NotifyTabOfExitIfNecessary();
644 #endif
645 window_->ExitFullscreen();
646 extension_caused_fullscreen_ = GURL();
647
648 UpdateFullscreenExitBubbleContent();
649 }
650
651 void FullscreenController::SetFullscreenedTab(WebContents* tab) {
652 fullscreened_tab_ = tab;
653 UpdateNotificationRegistrations();
654 }
655
656 void FullscreenController::SetMouseLockTab(WebContents* tab) {
657 mouse_lock_tab_ = tab;
658 UpdateNotificationRegistrations();
659 }
660
661 void FullscreenController::ExitTabFullscreenOrMouseLockIfNecessary() {
662 if (IsWindowFullscreenForTabOrPending())
663 ToggleFullscreenModeForTab(fullscreened_tab_, false);
664 else
665 NotifyTabOfExitIfNecessary();
666 }
667
668 void FullscreenController::UpdateFullscreenExitBubbleContent() {
669 GURL url = GetFullscreenExitBubbleURL();
670 ExclusiveAccessBubbleType bubble_type = GetExclusiveAccessBubbleType();
671
672 // If bubble displays buttons, unlock mouse to allow pressing them.
673 if (exclusive_access_bubble::ShowButtonsForType(bubble_type) &&
674 IsMouseLocked())
675 UnlockMouse();
676
677 window_->UpdateFullscreenExitBubbleContent(url, bubble_type);
678 }
679
680 ContentSetting
681 FullscreenController::GetFullscreenSetting(const GURL& url) const {
682 if (IsPrivilegedFullscreenForTab() || url.SchemeIsFile())
683 return CONTENT_SETTING_ALLOW;
684
685 return profile_->GetHostContentSettingsMap()->GetContentSetting(url, url,
686 CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string());
687 }
688
689 ContentSetting
690 FullscreenController::GetMouseLockSetting(const GURL& url) const {
691 if (IsPrivilegedFullscreenForTab() || url.SchemeIsFile())
692 return CONTENT_SETTING_ALLOW;
693
694 HostContentSettingsMap* settings_map = profile_->GetHostContentSettingsMap();
695 return settings_map->GetContentSetting(url, url,
696 CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string());
697 }
698
699 bool FullscreenController::IsPrivilegedFullscreenForTab() const {
700 const bool embedded_widget_present =
701 fullscreened_tab_ &&
702 fullscreened_tab_->GetFullscreenRenderWidgetHostView();
703 return embedded_widget_present || is_privileged_fullscreen_for_testing_;
704 }
705
706 void FullscreenController::SetPrivilegedFullscreenForTesting(
707 bool is_privileged) {
708 is_privileged_fullscreen_for_testing_ = is_privileged;
709 }
710
711 bool FullscreenController::MaybeToggleFullscreenForCapturedTab(
712 WebContents* web_contents, bool enter_fullscreen) {
713 if (enter_fullscreen) {
714 if (web_contents->GetCapturerCount() > 0) {
715 FullscreenWithinTabHelper::CreateForWebContents(web_contents);
716 FullscreenWithinTabHelper::FromWebContents(web_contents)->
717 SetIsFullscreenForCapturedTab(true);
718 return true;
719 }
720 } else {
721 if (IsFullscreenForCapturedTab(web_contents)) {
722 FullscreenWithinTabHelper::RemoveForWebContents(web_contents);
723 return true;
724 }
725 } 160 }
726 161
727 return false; 162 return false;
728 } 163 }
729 164
730 bool FullscreenController::IsFullscreenForCapturedTab( 165 bool MouseLockController::OnDenyExclusiveAccessPermission() {
731 const WebContents* web_contents) const { 166 WebContents* tab = GetExclusiveAccessTab();
732 // Note: On Mac, some of the OnTabXXX() methods get called with a NULL value 167
733 // for web_contents. Check for that here. 168 if (tab && IsMouseLockRequested()) {
734 const FullscreenWithinTabHelper* const helper = web_contents ? 169 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
735 FullscreenWithinTabHelper::FromWebContents(web_contents) : NULL; 170 tab->GotResponseToLockMouseRequest(false);
736 if (helper && helper->is_fullscreen_for_captured_tab()) { 171 SetTabWithExclusiveAccess(nullptr);
737 DCHECK_NE(fullscreened_tab_, web_contents); 172 NotifyMouseLockChange();
738 return true; 173 return true;
739 } 174 }
175
740 return false; 176 return false;
741 } 177 }
742 178
743 void FullscreenController::UnlockMouse() { 179 void MouseLockController::LostMouseLock() {
744 if (!mouse_lock_tab_) 180 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
181 SetTabWithExclusiveAccess(nullptr);
182 NotifyMouseLockChange();
183 UpdateExclusiveAccessExitBubbleContent();
184 }
185
186 bool MouseLockController::IsMouseLockRequested() const {
187 return mouse_lock_state_ == MOUSELOCK_REQUESTED;
188 }
189
190 void MouseLockController::NotifyMouseLockChange() {
191 content::NotificationService::current()->Notify(
192 chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
193 content::Source<MouseLockController>(this),
194 content::NotificationService::NoDetails());
195 }
196
197 void MouseLockController::UnlockMouse() {
198 WebContents* tab = GetExclusiveAccessTab();
199
200 if (!tab)
745 return; 201 return;
746 content::RenderWidgetHostView* mouse_lock_view = 202
747 (fullscreened_tab_ == mouse_lock_tab_ && IsPrivilegedFullscreenForTab()) ? 203 content::RenderWidgetHostView* mouse_lock_view = nullptr;
748 mouse_lock_tab_->GetFullscreenRenderWidgetHostView() : NULL; 204 FullscreenController* fullscreen_controller =
205 GetManager()->GetFullscreenController();
206 if ((fullscreen_controller->GetExclusiveAccessTab() == tab) &&
207 fullscreen_controller->IsPrivilegedFullscreenForTab()) {
208 mouse_lock_view =
209 GetExclusiveAccessTab()->GetFullscreenRenderWidgetHostView();
210 }
211
749 if (!mouse_lock_view) { 212 if (!mouse_lock_view) {
750 RenderViewHost* const rvh = mouse_lock_tab_->GetRenderViewHost(); 213 RenderViewHost* const rvh = GetExclusiveAccessTab()->GetRenderViewHost();
751 if (rvh) 214 if (rvh)
752 mouse_lock_view = rvh->GetView(); 215 mouse_lock_view = rvh->GetView();
753 } 216 }
217
754 if (mouse_lock_view) 218 if (mouse_lock_view)
755 mouse_lock_view->UnlockMouse(); 219 mouse_lock_view->UnlockMouse();
756 } 220 }
221
222 ContentSetting MouseLockController::GetMouseLockSetting(const GURL& url) const {
223 if (GetManager()->GetFullscreenController()->IsPrivilegedFullscreenForTab() ||
224 url.SchemeIsFile())
225 return CONTENT_SETTING_ALLOW;
226
227 HostContentSettingsMap* settings_map =
228 GetProfile()->GetHostContentSettingsMap();
229 return settings_map->GetContentSetting(
230 url, url, CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string());
231 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698