NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / ui / fullscreen / fullscreen_controller.cc
blobc259830c94837df84d252068ac40ec0285b13acb
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.
5 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
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"
12 #include "chrome/browser/content_settings/host_content_settings_map.h"
13 #include "chrome/browser/download/download_shelf.h"
14 #include "chrome/browser/fullscreen.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_window.h"
18 #include "chrome/browser/ui/status_bubble.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "content/public/browser/navigation_details.h"
22 #include "content/public/browser/navigation_entry.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/render_widget_host_view.h"
26 #include "content/public/browser/user_metrics.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_view.h"
29 #include "extensions/common/extension.h"
31 #if defined(OS_MACOSX)
32 #include "base/mac/mac_util.h"
33 #else
34 #include "base/prefs/pref_service.h"
35 #include "chrome/common/pref_names.h"
36 #endif
38 using base::UserMetricsAction;
39 using content::RenderViewHost;
40 using content::WebContents;
42 FullscreenController::FullscreenController(Browser* browser)
43 : browser_(browser),
44 window_(browser->window()),
45 profile_(browser->profile()),
46 fullscreened_tab_(NULL),
47 state_prior_to_tab_fullscreen_(STATE_INVALID),
48 tab_fullscreen_accepted_(false),
49 toggled_into_fullscreen_(false),
50 mouse_lock_tab_(NULL),
51 mouse_lock_state_(MOUSELOCK_NOT_REQUESTED),
52 reentrant_window_state_change_call_check_(false),
53 is_privileged_fullscreen_for_testing_(false),
54 ptr_factory_(this) {
55 DCHECK(window_);
56 DCHECK(profile_);
59 FullscreenController::~FullscreenController() {
62 bool FullscreenController::IsFullscreenForBrowser() const {
63 return window_->IsFullscreen() && !IsFullscreenCausedByTab();
66 void FullscreenController::ToggleFullscreenMode() {
67 extension_caused_fullscreen_ = GURL();
68 ToggleFullscreenModeInternal(BROWSER);
71 bool FullscreenController::IsFullscreenForTabOrPending() const {
72 return fullscreened_tab_ != NULL;
75 bool FullscreenController::IsFullscreenForTabOrPending(
76 const WebContents* web_contents) const {
77 if (web_contents == fullscreened_tab_) {
78 DCHECK(web_contents == browser_->tab_strip_model()->GetActiveWebContents());
79 DCHECK(!IsFullscreenWithinTabPossible() ||
80 web_contents->GetCapturerCount() == 0);
81 return true;
83 return IsFullscreenForCapturedTab(web_contents);
86 bool FullscreenController::IsFullscreenCausedByTab() const {
87 return state_prior_to_tab_fullscreen_ == STATE_NORMAL;
90 void FullscreenController::ToggleFullscreenModeForTab(WebContents* web_contents,
91 bool enter_fullscreen) {
92 if (MaybeToggleFullscreenForCapturedTab(web_contents, enter_fullscreen)) {
93 // During tab capture of fullscreen-within-tab views, the browser window
94 // fullscreen state is unchanged, so return now.
95 return;
97 if (fullscreened_tab_) {
98 if (web_contents != fullscreened_tab_)
99 return;
100 } else if (
101 web_contents != browser_->tab_strip_model()->GetActiveWebContents()) {
102 return;
104 if (IsFullscreenForTabOrPending() == enter_fullscreen)
105 return;
107 #if defined(OS_WIN)
108 // For now, avoid breaking when initiating full screen tab mode while in
109 // a metro snap.
110 // TODO(robertshield): Find a way to reconcile tab-initiated fullscreen
111 // modes with metro snap.
112 if (IsInMetroSnapMode())
113 return;
114 #endif
116 bool in_browser_or_tab_fullscreen_mode = window_->IsFullscreen();
117 bool window_is_fullscreen_with_chrome = false;
118 #if defined(OS_MACOSX)
119 window_is_fullscreen_with_chrome = window_->IsFullscreenWithChrome();
120 #endif
122 if (enter_fullscreen) {
123 SetFullscreenedTab(web_contents);
124 if (!in_browser_or_tab_fullscreen_mode) {
125 state_prior_to_tab_fullscreen_ = STATE_NORMAL;
126 ToggleFullscreenModeInternal(TAB);
127 } else if (window_is_fullscreen_with_chrome) {
128 #if defined(OS_MACOSX)
129 state_prior_to_tab_fullscreen_ = STATE_BROWSER_FULLSCREEN_WITH_CHROME;
130 EnterFullscreenModeInternal(TAB);
131 #else
132 NOTREACHED();
133 #endif
134 } else {
135 state_prior_to_tab_fullscreen_ = STATE_BROWSER_FULLSCREEN_NO_CHROME;
137 // We need to update the fullscreen exit bubble, e.g., going from browser
138 // fullscreen to tab fullscreen will need to show different content.
139 const GURL& url = web_contents->GetURL();
140 if (!tab_fullscreen_accepted_) {
141 tab_fullscreen_accepted_ =
142 GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW;
144 UpdateFullscreenExitBubbleContent();
146 // This is only a change between Browser and Tab fullscreen. We generate
147 // a fullscreen notification now because there is no window change.
148 PostFullscreenChangeNotification(true);
150 } else {
151 if (in_browser_or_tab_fullscreen_mode) {
152 if (IsFullscreenCausedByTab()) {
153 ToggleFullscreenModeInternal(TAB);
154 } else {
155 #if defined(OS_MACOSX)
156 if (state_prior_to_tab_fullscreen_ ==
157 STATE_BROWSER_FULLSCREEN_WITH_CHROME) {
158 EnterFullscreenModeInternal(BROWSER_WITH_CHROME);
159 } else {
160 // Clear the bubble URL, which forces the Mac UI to redraw.
161 UpdateFullscreenExitBubbleContent();
163 #endif
164 // If currently there is a tab in "tab fullscreen" mode and fullscreen
165 // was not caused by it (i.e., previously it was in "browser fullscreen"
166 // mode), we need to switch back to "browser fullscreen" mode. In this
167 // case, all we have to do is notifying the tab that it has exited "tab
168 // fullscreen" mode.
169 NotifyTabOfExitIfNecessary();
171 // This is only a change between Browser and Tab fullscreen. We generate
172 // a fullscreen notification now because there is no window change.
173 PostFullscreenChangeNotification(true);
179 void FullscreenController::ToggleFullscreenModeWithExtension(
180 const GURL& extension_url) {
181 // |extension_caused_fullscreen_| will be reset if this causes fullscreen to
182 // exit.
183 extension_caused_fullscreen_ = extension_url;
184 ToggleFullscreenModeInternal(BROWSER);
187 bool FullscreenController::IsInMetroSnapMode() {
188 #if defined(OS_WIN)
189 return window_->IsInMetroSnapMode();
190 #else
191 return false;
192 #endif
195 #if defined(OS_WIN)
196 void FullscreenController::SetMetroSnapMode(bool enable) {
197 reentrant_window_state_change_call_check_ = false;
199 toggled_into_fullscreen_ = false;
200 window_->SetMetroSnapMode(enable);
202 // FullscreenController unit tests for metro snap assume that on Windows calls
203 // to WindowFullscreenStateChanged are reentrant. If that assumption is
204 // invalidated, the tests must be updated to maintain coverage.
205 CHECK(reentrant_window_state_change_call_check_);
207 #endif // defined(OS_WIN)
209 #if defined(OS_MACOSX)
210 void FullscreenController::ToggleFullscreenWithChrome() {
211 // This method cannot be called if simplified fullscreen is enabled.
212 const CommandLine* command_line = CommandLine::ForCurrentProcess();
213 DCHECK(!command_line->HasSwitch(switches::kEnableSimplifiedFullscreen));
214 ToggleFullscreenModeInternal(BROWSER_WITH_CHROME);
216 #endif
218 bool FullscreenController::IsMouseLockRequested() const {
219 return mouse_lock_state_ == MOUSELOCK_REQUESTED;
222 bool FullscreenController::IsMouseLocked() const {
223 return mouse_lock_state_ == MOUSELOCK_ACCEPTED ||
224 mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY;
227 void FullscreenController::RequestToLockMouse(WebContents* web_contents,
228 bool user_gesture,
229 bool last_unlocked_by_target) {
230 DCHECK(!IsMouseLocked());
231 NotifyMouseLockChange();
233 // Must have a user gesture to prevent misbehaving sites from constantly
234 // re-locking the mouse. Exceptions are when the page has unlocked
235 // (i.e. not the user), or if we're in tab fullscreen (user gesture required
236 // for that)
237 if (!last_unlocked_by_target && !user_gesture &&
238 !IsFullscreenForTabOrPending(web_contents)) {
239 web_contents->GotResponseToLockMouseRequest(false);
240 return;
242 SetMouseLockTab(web_contents);
243 FullscreenExitBubbleType bubble_type = GetFullscreenExitBubbleType();
245 switch (GetMouseLockSetting(web_contents->GetURL())) {
246 case CONTENT_SETTING_ALLOW:
247 // If bubble already displaying buttons we must not lock the mouse yet,
248 // or it would prevent pressing those buttons. Instead, merge the request.
249 if (!IsPrivilegedFullscreenForTab() &&
250 fullscreen_bubble::ShowButtonsForType(bubble_type)) {
251 mouse_lock_state_ = MOUSELOCK_REQUESTED;
252 } else {
253 // Lock mouse.
254 if (web_contents->GotResponseToLockMouseRequest(true)) {
255 if (last_unlocked_by_target) {
256 mouse_lock_state_ = MOUSELOCK_ACCEPTED_SILENTLY;
257 } else {
258 mouse_lock_state_ = MOUSELOCK_ACCEPTED;
260 } else {
261 SetMouseLockTab(NULL);
262 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
265 break;
266 case CONTENT_SETTING_BLOCK:
267 web_contents->GotResponseToLockMouseRequest(false);
268 SetMouseLockTab(NULL);
269 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
270 break;
271 case CONTENT_SETTING_ASK:
272 mouse_lock_state_ = MOUSELOCK_REQUESTED;
273 break;
274 default:
275 NOTREACHED();
277 UpdateFullscreenExitBubbleContent();
280 void FullscreenController::OnTabDeactivated(WebContents* web_contents) {
281 if (web_contents == fullscreened_tab_ || web_contents == mouse_lock_tab_)
282 ExitTabFullscreenOrMouseLockIfNecessary();
285 void FullscreenController::OnTabDetachedFromView(WebContents* old_contents) {
286 if (!IsFullscreenForCapturedTab(old_contents))
287 return;
289 // A fullscreen-within-tab view undergoing screen capture has been detached
290 // and is no longer visible to the user. Set it to exactly the WebContents'
291 // preferred size. See 'FullscreenWithinTab Note'.
293 // When the user later selects the tab to show |old_contents| again, UI code
294 // elsewhere (e.g., views::WebView) will resize the view to fit within the
295 // browser window once again.
296 if (old_contents->GetCapturerCount() == 0 ||
297 old_contents->GetPreferredSize().IsEmpty()) {
298 // Do nothing if tab capture ended after toggling fullscreen, or a preferred
299 // size was never specified by the capturer.
300 return;
302 content::RenderWidgetHostView* const current_fs_view =
303 old_contents->GetFullscreenRenderWidgetHostView();
304 if (current_fs_view)
305 current_fs_view->SetSize(old_contents->GetPreferredSize());
306 old_contents->GetView()->SizeContents(old_contents->GetPreferredSize());
309 void FullscreenController::OnTabClosing(WebContents* web_contents) {
310 if (IsFullscreenForCapturedTab(web_contents)) {
311 RenderViewHost* const rvh = web_contents->GetRenderViewHost();
312 if (rvh)
313 rvh->ExitFullscreen();
314 } else if (web_contents == fullscreened_tab_ ||
315 web_contents == mouse_lock_tab_) {
316 ExitTabFullscreenOrMouseLockIfNecessary();
317 // The call to exit fullscreen may result in asynchronous notification of
318 // fullscreen state change (e.g., on Linux). We don't want to rely on it
319 // to call NotifyTabOfExitIfNecessary(), because at that point
320 // |fullscreened_tab_| may not be valid. Instead, we call it here to clean
321 // up tab fullscreen related state.
322 NotifyTabOfExitIfNecessary();
326 void FullscreenController::WindowFullscreenStateChanged() {
327 reentrant_window_state_change_call_check_ = true;
329 bool exiting_fullscreen = !window_->IsFullscreen();
331 PostFullscreenChangeNotification(!exiting_fullscreen);
332 if (exiting_fullscreen) {
333 toggled_into_fullscreen_ = false;
334 extension_caused_fullscreen_ = GURL();
335 NotifyTabOfExitIfNecessary();
337 if (exiting_fullscreen) {
338 window_->GetDownloadShelf()->Unhide();
339 } else {
340 window_->GetDownloadShelf()->Hide();
341 if (window_->GetStatusBubble())
342 window_->GetStatusBubble()->Hide();
346 bool FullscreenController::HandleUserPressedEscape() {
347 WebContents* const active_web_contents =
348 browser_->tab_strip_model()->GetActiveWebContents();
349 if (IsFullscreenForCapturedTab(active_web_contents)) {
350 RenderViewHost* const rvh = active_web_contents->GetRenderViewHost();
351 if (rvh)
352 rvh->ExitFullscreen();
353 return true;
354 } else if (IsFullscreenForTabOrPending() ||
355 IsMouseLocked() || IsMouseLockRequested()) {
356 ExitTabFullscreenOrMouseLockIfNecessary();
357 return true;
360 return false;
363 void FullscreenController::ExitTabOrBrowserFullscreenToPreviousState() {
364 if (IsFullscreenForTabOrPending())
365 ExitTabFullscreenOrMouseLockIfNecessary();
366 else if (IsFullscreenForBrowser())
367 ExitFullscreenModeInternal();
370 void FullscreenController::OnAcceptFullscreenPermission() {
371 FullscreenExitBubbleType bubble_type = GetFullscreenExitBubbleType();
372 bool mouse_lock = false;
373 bool fullscreen = false;
374 fullscreen_bubble::PermissionRequestedByType(bubble_type, &fullscreen,
375 &mouse_lock);
376 DCHECK(!(fullscreen && tab_fullscreen_accepted_));
377 DCHECK(!(mouse_lock && IsMouseLocked()));
379 HostContentSettingsMap* settings_map = profile_->GetHostContentSettingsMap();
381 GURL url = GetFullscreenExitBubbleURL();
382 ContentSettingsPattern pattern = ContentSettingsPattern::FromURL(url);
384 if (mouse_lock && !IsMouseLocked()) {
385 DCHECK(IsMouseLockRequested());
386 // TODO(markusheintz): We should allow patterns for all possible URLs here.
387 if (pattern.IsValid()) {
388 settings_map->SetContentSetting(
389 pattern, ContentSettingsPattern::Wildcard(),
390 CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string(),
391 CONTENT_SETTING_ALLOW);
394 if (mouse_lock_tab_ &&
395 mouse_lock_tab_->GotResponseToLockMouseRequest(true)) {
396 mouse_lock_state_ = MOUSELOCK_ACCEPTED;
397 } else {
398 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
399 SetMouseLockTab(NULL);
401 NotifyMouseLockChange();
404 if (fullscreen && !tab_fullscreen_accepted_) {
405 DCHECK(fullscreened_tab_);
406 if (pattern.IsValid()) {
407 settings_map->SetContentSetting(
408 pattern, ContentSettingsPattern::Wildcard(),
409 CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string(),
410 CONTENT_SETTING_ALLOW);
412 tab_fullscreen_accepted_ = true;
414 UpdateFullscreenExitBubbleContent();
417 void FullscreenController::OnDenyFullscreenPermission() {
418 if (!fullscreened_tab_ && !mouse_lock_tab_)
419 return;
421 if (IsMouseLockRequested()) {
422 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
423 if (mouse_lock_tab_)
424 mouse_lock_tab_->GotResponseToLockMouseRequest(false);
425 SetMouseLockTab(NULL);
426 NotifyMouseLockChange();
428 // UpdateFullscreenExitBubbleContent() must be called, but to avoid
429 // duplicate calls we do so only if not adjusting the fullscreen state
430 // below, which also calls UpdateFullscreenExitBubbleContent().
431 if (!IsFullscreenForTabOrPending())
432 UpdateFullscreenExitBubbleContent();
435 if (IsFullscreenForTabOrPending())
436 ExitTabFullscreenOrMouseLockIfNecessary();
439 void FullscreenController::LostMouseLock() {
440 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
441 SetMouseLockTab(NULL);
442 NotifyMouseLockChange();
443 UpdateFullscreenExitBubbleContent();
446 void FullscreenController::Observe(int type,
447 const content::NotificationSource& source,
448 const content::NotificationDetails& details) {
449 switch (type) {
450 case content::NOTIFICATION_NAV_ENTRY_COMMITTED:
451 if (content::Details<content::LoadCommittedDetails>(details)->
452 is_navigation_to_different_page()) {
453 ExitTabFullscreenOrMouseLockIfNecessary();
455 break;
457 default:
458 NOTREACHED() << "Got a notification we didn't register for.";
462 GURL FullscreenController::GetFullscreenExitBubbleURL() const {
463 if (fullscreened_tab_)
464 return fullscreened_tab_->GetURL();
465 else if (mouse_lock_tab_)
466 return mouse_lock_tab_->GetURL();
467 else if (!extension_caused_fullscreen_.is_empty())
468 return extension_caused_fullscreen_;
469 else
470 return GURL();
473 FullscreenExitBubbleType FullscreenController::GetFullscreenExitBubbleType()
474 const {
475 // In kiosk and exclusive app mode we always want to be fullscreen and do not
476 // want to show exit instructions for browser mode fullscreen.
477 bool app_mode = false;
478 #if !defined(OS_MACOSX) // App mode (kiosk) is not available on Mac yet.
479 app_mode = chrome::IsRunningInAppMode();
480 #endif
482 if (mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY) {
483 return FEB_TYPE_NONE;
486 if (fullscreened_tab_) {
487 if (tab_fullscreen_accepted_) {
488 if (IsPrivilegedFullscreenForTab()) {
489 return FEB_TYPE_NONE;
490 } else if (IsMouseLocked()) {
491 return FEB_TYPE_FULLSCREEN_MOUSELOCK_EXIT_INSTRUCTION;
492 } else if (IsMouseLockRequested()) {
493 return FEB_TYPE_MOUSELOCK_BUTTONS;
494 } else {
495 return FEB_TYPE_FULLSCREEN_EXIT_INSTRUCTION;
497 } else { // Full screen not yet accepted.
498 if (IsMouseLockRequested()) {
499 return FEB_TYPE_FULLSCREEN_MOUSELOCK_BUTTONS;
500 } else {
501 return FEB_TYPE_FULLSCREEN_BUTTONS;
504 } else { // Not tab full screen.
505 if (IsMouseLocked()) {
506 return FEB_TYPE_MOUSELOCK_EXIT_INSTRUCTION;
507 } else if (IsMouseLockRequested()) {
508 return FEB_TYPE_MOUSELOCK_BUTTONS;
509 } else {
510 if (!extension_caused_fullscreen_.is_empty()) {
511 return FEB_TYPE_BROWSER_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION;
512 } else if (toggled_into_fullscreen_ && !app_mode) {
513 return FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION;
514 } else {
515 return FEB_TYPE_NONE;
519 NOTREACHED();
520 return FEB_TYPE_NONE;
523 void FullscreenController::UpdateNotificationRegistrations() {
524 if (fullscreened_tab_ && mouse_lock_tab_)
525 DCHECK(fullscreened_tab_ == mouse_lock_tab_);
527 WebContents* tab = fullscreened_tab_ ? fullscreened_tab_ : mouse_lock_tab_;
529 if (tab && registrar_.IsEmpty()) {
530 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
531 content::Source<content::NavigationController>(&tab->GetController()));
532 } else if (!tab && !registrar_.IsEmpty()) {
533 registrar_.RemoveAll();
537 void FullscreenController::PostFullscreenChangeNotification(
538 bool is_fullscreen) {
539 base::MessageLoop::current()->PostTask(
540 FROM_HERE,
541 base::Bind(&FullscreenController::NotifyFullscreenChange,
542 ptr_factory_.GetWeakPtr(),
543 is_fullscreen));
546 void FullscreenController::NotifyFullscreenChange(bool is_fullscreen) {
547 content::NotificationService::current()->Notify(
548 chrome::NOTIFICATION_FULLSCREEN_CHANGED,
549 content::Source<FullscreenController>(this),
550 content::Details<bool>(&is_fullscreen));
553 void FullscreenController::NotifyTabOfExitIfNecessary() {
554 if (fullscreened_tab_) {
555 RenderViewHost* rvh = fullscreened_tab_->GetRenderViewHost();
556 SetFullscreenedTab(NULL);
557 state_prior_to_tab_fullscreen_ = STATE_INVALID;
558 tab_fullscreen_accepted_ = false;
559 if (rvh)
560 rvh->ExitFullscreen();
563 if (mouse_lock_tab_) {
564 if (IsMouseLockRequested()) {
565 mouse_lock_tab_->GotResponseToLockMouseRequest(false);
566 NotifyMouseLockChange();
567 } else {
568 UnlockMouse();
570 SetMouseLockTab(NULL);
571 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
574 UpdateFullscreenExitBubbleContent();
577 void FullscreenController::NotifyMouseLockChange() {
578 content::NotificationService::current()->Notify(
579 chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
580 content::Source<FullscreenController>(this),
581 content::NotificationService::NoDetails());
584 void FullscreenController::ToggleFullscreenModeInternal(
585 FullscreenInternalOption option) {
586 #if defined(OS_WIN)
587 // When in Metro snap mode, toggling in and out of fullscreen is prevented.
588 if (IsInMetroSnapMode())
589 return;
590 #endif
592 bool enter_fullscreen = !window_->IsFullscreen();
593 #if defined(OS_MACOSX)
594 // When a Mac user requests a toggle they may be toggling between
595 // FullscreenWithoutChrome and FullscreenWithChrome.
596 if (!IsFullscreenForTabOrPending()) {
597 if (option == BROWSER_WITH_CHROME)
598 enter_fullscreen |= window_->IsFullscreenWithoutChrome();
599 else
600 enter_fullscreen |= window_->IsFullscreenWithChrome();
602 #endif
604 // In kiosk mode, we always want to be fullscreen. When the browser first
605 // starts we're not yet fullscreen, so let the initial toggle go through.
606 if (chrome::IsRunningInAppMode() && window_->IsFullscreen())
607 return;
609 #if !defined(OS_MACOSX)
610 // Do not enter fullscreen mode if disallowed by pref. This prevents the user
611 // from manually entering fullscreen mode and also disables kiosk mode on
612 // desktop platforms.
613 if (enter_fullscreen &&
614 !profile_->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed)) {
615 return;
617 #endif
619 if (enter_fullscreen)
620 EnterFullscreenModeInternal(option);
621 else
622 ExitFullscreenModeInternal();
625 void FullscreenController::EnterFullscreenModeInternal(
626 FullscreenInternalOption option) {
627 toggled_into_fullscreen_ = true;
628 GURL url;
629 if (option == TAB) {
630 url = browser_->tab_strip_model()->GetActiveWebContents()->GetURL();
631 tab_fullscreen_accepted_ =
632 GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW;
633 } else {
634 if (!extension_caused_fullscreen_.is_empty())
635 url = extension_caused_fullscreen_;
638 if (option == BROWSER)
639 content::RecordAction(UserMetricsAction("ToggleFullscreen"));
640 // TODO(scheib): Record metrics for WITH_CHROME, without counting transitions
641 // from tab fullscreen out to browser with chrome.
643 #if defined(OS_MACOSX)
644 if (option == BROWSER_WITH_CHROME) {
645 CHECK(chrome::mac::SupportsSystemFullscreen());
646 window_->EnterFullscreenWithChrome();
647 } else {
648 #else
650 #endif
651 window_->EnterFullscreen(url, GetFullscreenExitBubbleType());
654 UpdateFullscreenExitBubbleContent();
656 // Once the window has become fullscreen it'll call back to
657 // WindowFullscreenStateChanged(). We don't do this immediately as
658 // BrowserWindow::EnterFullscreen() asks for bookmark_bar_state_, so we let
659 // the BrowserWindow invoke WindowFullscreenStateChanged when appropriate.
662 void FullscreenController::ExitFullscreenModeInternal() {
663 toggled_into_fullscreen_ = false;
664 #if defined(OS_MACOSX)
665 // Mac windows report a state change instantly, and so we must also clear
666 // state_prior_to_tab_fullscreen_ to match them else other logic using
667 // state_prior_to_tab_fullscreen_ will be incorrect.
668 NotifyTabOfExitIfNecessary();
669 #endif
670 window_->ExitFullscreen();
671 extension_caused_fullscreen_ = GURL();
673 UpdateFullscreenExitBubbleContent();
676 void FullscreenController::SetFullscreenedTab(WebContents* tab) {
677 fullscreened_tab_ = tab;
678 UpdateNotificationRegistrations();
681 void FullscreenController::SetMouseLockTab(WebContents* tab) {
682 mouse_lock_tab_ = tab;
683 UpdateNotificationRegistrations();
686 void FullscreenController::ExitTabFullscreenOrMouseLockIfNecessary() {
687 if (IsFullscreenForTabOrPending())
688 ToggleFullscreenModeForTab(fullscreened_tab_, false);
689 else
690 NotifyTabOfExitIfNecessary();
693 void FullscreenController::UpdateFullscreenExitBubbleContent() {
694 GURL url = GetFullscreenExitBubbleURL();
695 FullscreenExitBubbleType bubble_type = GetFullscreenExitBubbleType();
697 // If bubble displays buttons, unlock mouse to allow pressing them.
698 if (fullscreen_bubble::ShowButtonsForType(bubble_type) && IsMouseLocked())
699 UnlockMouse();
701 window_->UpdateFullscreenExitBubbleContent(url, bubble_type);
704 ContentSetting
705 FullscreenController::GetFullscreenSetting(const GURL& url) const {
706 if (IsPrivilegedFullscreenForTab() || url.SchemeIsFile())
707 return CONTENT_SETTING_ALLOW;
709 return profile_->GetHostContentSettingsMap()->GetContentSetting(url, url,
710 CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string());
713 ContentSetting
714 FullscreenController::GetMouseLockSetting(const GURL& url) const {
715 if (IsPrivilegedFullscreenForTab() || url.SchemeIsFile())
716 return CONTENT_SETTING_ALLOW;
718 HostContentSettingsMap* settings_map = profile_->GetHostContentSettingsMap();
719 return settings_map->GetContentSetting(url, url,
720 CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string());
723 bool FullscreenController::IsPrivilegedFullscreenForTab() const {
724 const bool embedded_widget_present =
725 fullscreened_tab_ &&
726 fullscreened_tab_->GetFullscreenRenderWidgetHostView() &&
727 IsFullscreenWithinTabPossible();
728 return embedded_widget_present || is_privileged_fullscreen_for_testing_;
731 void FullscreenController::SetPrivilegedFullscreenForTesting(
732 bool is_privileged) {
733 is_privileged_fullscreen_for_testing_ = is_privileged;
736 bool FullscreenController::IsFullscreenWithinTabPossible() const {
737 return implicit_cast<const content::WebContentsDelegate*>(browser_)->
738 EmbedsFullscreenWidget();
741 bool FullscreenController::MaybeToggleFullscreenForCapturedTab(
742 WebContents* web_contents, bool enter_fullscreen) {
743 if (!IsFullscreenWithinTabPossible())
744 return false;
746 if (enter_fullscreen) {
747 if (web_contents->GetCapturerCount() > 0) {
748 captured_tabs_.insert(web_contents);
749 return true;
751 } else {
752 const std::set<const WebContents*>::iterator it =
753 captured_tabs_.find(web_contents);
754 if (it != captured_tabs_.end()) {
755 captured_tabs_.erase(it);
756 return true;
760 return false;
763 bool FullscreenController::IsFullscreenForCapturedTab(
764 const WebContents* web_contents) const {
765 if (captured_tabs_.find(web_contents) != captured_tabs_.end()) {
766 DCHECK(IsFullscreenWithinTabPossible());
767 DCHECK_NE(fullscreened_tab_, web_contents);
768 return true;
770 return false;
773 void FullscreenController::UnlockMouse() {
774 if (!mouse_lock_tab_)
775 return;
776 content::RenderWidgetHostView* mouse_lock_view =
777 (fullscreened_tab_ == mouse_lock_tab_ && IsPrivilegedFullscreenForTab()) ?
778 mouse_lock_tab_->GetFullscreenRenderWidgetHostView() : NULL;
779 if (!mouse_lock_view) {
780 RenderViewHost* const rvh = mouse_lock_tab_->GetRenderViewHost();
781 if (rvh)
782 mouse_lock_view = rvh->GetView();
784 if (mouse_lock_view)
785 mouse_lock_view->UnlockMouse();