Home | History | Annotate | Download | only in fullscreen
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
      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"
     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 "extensions/common/extension.h"
     29 
     30 #if defined(OS_MACOSX)
     31 #include "base/mac/mac_util.h"
     32 #else
     33 #include "base/prefs/pref_service.h"
     34 #include "chrome/common/pref_names.h"
     35 #endif
     36 
     37 using content::RenderViewHost;
     38 using content::UserMetricsAction;
     39 using content::WebContents;
     40 
     41 FullscreenController::FullscreenController(Browser* browser)
     42     : browser_(browser),
     43       window_(browser->window()),
     44       profile_(browser->profile()),
     45       fullscreened_tab_(NULL),
     46       state_prior_to_tab_fullscreen_(STATE_INVALID),
     47       tab_fullscreen_accepted_(false),
     48       toggled_into_fullscreen_(false),
     49       mouse_lock_tab_(NULL),
     50       mouse_lock_state_(MOUSELOCK_NOT_REQUESTED),
     51       reentrant_window_state_change_call_check_(false),
     52       is_privileged_fullscreen_for_testing_(false),
     53       ptr_factory_(this) {
     54   DCHECK(window_);
     55   DCHECK(profile_);
     56 }
     57 
     58 FullscreenController::~FullscreenController() {
     59 }
     60 
     61 bool FullscreenController::IsFullscreenForBrowser() const {
     62   return window_->IsFullscreen() && !IsFullscreenCausedByTab();
     63 }
     64 
     65 void FullscreenController::ToggleFullscreenMode() {
     66   extension_caused_fullscreen_ = GURL();
     67   ToggleFullscreenModeInternal(BROWSER);
     68 }
     69 
     70 bool FullscreenController::IsFullscreenForTabOrPending() const {
     71   return fullscreened_tab_ != NULL;
     72 }
     73 
     74 bool FullscreenController::IsFullscreenForTabOrPending(
     75     const WebContents* web_contents) const {
     76   if (web_contents != fullscreened_tab_)
     77     return false;
     78   DCHECK(web_contents == browser_->tab_strip_model()->GetActiveWebContents());
     79   return true;
     80 }
     81 
     82 bool FullscreenController::IsFullscreenCausedByTab() const {
     83   return state_prior_to_tab_fullscreen_ == STATE_NORMAL;
     84 }
     85 
     86 void FullscreenController::ToggleFullscreenModeForTab(WebContents* web_contents,
     87                                                       bool enter_fullscreen) {
     88   if (fullscreened_tab_) {
     89     if (web_contents != fullscreened_tab_)
     90       return;
     91   } else if (
     92       web_contents != browser_->tab_strip_model()->GetActiveWebContents()) {
     93     return;
     94   }
     95   if (IsFullscreenForTabOrPending() == enter_fullscreen)
     96     return;
     97 
     98 #if defined(OS_WIN)
     99   // For now, avoid breaking when initiating full screen tab mode while in
    100   // a metro snap.
    101   // TODO(robertshield): Find a way to reconcile tab-initiated fullscreen
    102   //                     modes with metro snap.
    103   if (IsInMetroSnapMode())
    104     return;
    105 #endif
    106 
    107   bool in_browser_or_tab_fullscreen_mode = window_->IsFullscreen();
    108   bool window_is_fullscreen_with_chrome = false;
    109 #if defined(OS_MACOSX)
    110   window_is_fullscreen_with_chrome = window_->IsFullscreenWithChrome();
    111 #endif
    112 
    113   if (enter_fullscreen) {
    114     SetFullscreenedTab(web_contents);
    115     if (!in_browser_or_tab_fullscreen_mode) {
    116       state_prior_to_tab_fullscreen_ = STATE_NORMAL;
    117       ToggleFullscreenModeInternal(TAB);
    118     } else if (window_is_fullscreen_with_chrome) {
    119 #if defined(OS_MACOSX)
    120       state_prior_to_tab_fullscreen_ = STATE_BROWSER_FULLSCREEN_WITH_CHROME;
    121       EnterFullscreenModeInternal(TAB);
    122 #else
    123       NOTREACHED();
    124 #endif
    125     } else {
    126       state_prior_to_tab_fullscreen_ = STATE_BROWSER_FULLSCREEN_NO_CHROME;
    127 
    128       // We need to update the fullscreen exit bubble, e.g., going from browser
    129       // fullscreen to tab fullscreen will need to show different content.
    130       const GURL& url = web_contents->GetURL();
    131       if (!tab_fullscreen_accepted_) {
    132         tab_fullscreen_accepted_ =
    133             GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW;
    134       }
    135       UpdateFullscreenExitBubbleContent();
    136 
    137       // This is only a change between Browser and Tab fullscreen. We generate
    138       // a fullscreen notification now because there is no window change.
    139       PostFullscreenChangeNotification(true);
    140     }
    141   } else {
    142     if (in_browser_or_tab_fullscreen_mode) {
    143       if (IsFullscreenCausedByTab()) {
    144         ToggleFullscreenModeInternal(TAB);
    145       } else {
    146 #if defined(OS_MACOSX)
    147         if (state_prior_to_tab_fullscreen_ ==
    148             STATE_BROWSER_FULLSCREEN_WITH_CHROME) {
    149           EnterFullscreenModeInternal(BROWSER_WITH_CHROME);
    150         } else {
    151           // Clear the bubble URL, which forces the Mac UI to redraw.
    152           UpdateFullscreenExitBubbleContent();
    153         }
    154 #endif
    155         // If currently there is a tab in "tab fullscreen" mode and fullscreen
    156         // was not caused by it (i.e., previously it was in "browser fullscreen"
    157         // mode), we need to switch back to "browser fullscreen" mode. In this
    158         // case, all we have to do is notifying the tab that it has exited "tab
    159         // fullscreen" mode.
    160         NotifyTabOfExitIfNecessary();
    161 
    162         // This is only a change between Browser and Tab fullscreen. We generate
    163         // a fullscreen notification now because there is no window change.
    164         PostFullscreenChangeNotification(true);
    165       }
    166     }
    167   }
    168 }
    169 
    170 void FullscreenController::ToggleFullscreenModeWithExtension(
    171     const GURL& extension_url) {
    172   // |extension_caused_fullscreen_| will be reset if this causes fullscreen to
    173   // exit.
    174   extension_caused_fullscreen_ = extension_url;
    175   ToggleFullscreenModeInternal(BROWSER);
    176 }
    177 
    178 bool FullscreenController::IsInMetroSnapMode() {
    179 #if defined(OS_WIN)
    180   return window_->IsInMetroSnapMode();
    181 #else
    182   return false;
    183 #endif
    184 }
    185 
    186 #if defined(OS_WIN)
    187 void FullscreenController::SetMetroSnapMode(bool enable) {
    188   reentrant_window_state_change_call_check_ = false;
    189 
    190   toggled_into_fullscreen_ = false;
    191   window_->SetMetroSnapMode(enable);
    192 
    193   // FullscreenController unit tests for metro snap assume that on Windows calls
    194   // to WindowFullscreenStateChanged are reentrant. If that assumption is
    195   // invalidated, the tests must be updated to maintain coverage.
    196   CHECK(reentrant_window_state_change_call_check_);
    197 }
    198 #endif  // defined(OS_WIN)
    199 
    200 #if defined(OS_MACOSX)
    201 void FullscreenController::ToggleFullscreenWithChrome() {
    202   // This method cannot be called if simplified fullscreen is enabled.
    203   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    204   DCHECK(!command_line->HasSwitch(switches::kEnableSimplifiedFullscreen));
    205   ToggleFullscreenModeInternal(BROWSER_WITH_CHROME);
    206 }
    207 #endif
    208 
    209 bool FullscreenController::IsMouseLockRequested() const {
    210   return mouse_lock_state_ == MOUSELOCK_REQUESTED;
    211 }
    212 
    213 bool FullscreenController::IsMouseLocked() const {
    214   return mouse_lock_state_ == MOUSELOCK_ACCEPTED ||
    215          mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY;
    216 }
    217 
    218 void FullscreenController::RequestToLockMouse(WebContents* web_contents,
    219                                               bool user_gesture,
    220                                               bool last_unlocked_by_target) {
    221   DCHECK(!IsMouseLocked());
    222   NotifyMouseLockChange();
    223 
    224   // Must have a user gesture to prevent misbehaving sites from constantly
    225   // re-locking the mouse. Exceptions are when the page has unlocked
    226   // (i.e. not the user), or if we're in tab fullscreen (user gesture required
    227   // for that)
    228   if (!last_unlocked_by_target && !user_gesture &&
    229       !IsFullscreenForTabOrPending(web_contents)) {
    230     web_contents->GotResponseToLockMouseRequest(false);
    231     return;
    232   }
    233   SetMouseLockTab(web_contents);
    234   FullscreenExitBubbleType bubble_type = GetFullscreenExitBubbleType();
    235 
    236   switch (GetMouseLockSetting(web_contents->GetURL())) {
    237     case CONTENT_SETTING_ALLOW:
    238       // If bubble already displaying buttons we must not lock the mouse yet,
    239       // or it would prevent pressing those buttons. Instead, merge the request.
    240       if (!IsPrivilegedFullscreenForTab() &&
    241           fullscreen_bubble::ShowButtonsForType(bubble_type)) {
    242         mouse_lock_state_ = MOUSELOCK_REQUESTED;
    243       } else {
    244         // Lock mouse.
    245         if (web_contents->GotResponseToLockMouseRequest(true)) {
    246           if (last_unlocked_by_target) {
    247             mouse_lock_state_ = MOUSELOCK_ACCEPTED_SILENTLY;
    248           } else {
    249             mouse_lock_state_ = MOUSELOCK_ACCEPTED;
    250           }
    251         } else {
    252           SetMouseLockTab(NULL);
    253           mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
    254         }
    255       }
    256       break;
    257     case CONTENT_SETTING_BLOCK:
    258       web_contents->GotResponseToLockMouseRequest(false);
    259       SetMouseLockTab(NULL);
    260       mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
    261       break;
    262     case CONTENT_SETTING_ASK:
    263       mouse_lock_state_ = MOUSELOCK_REQUESTED;
    264       break;
    265     default:
    266       NOTREACHED();
    267   }
    268   UpdateFullscreenExitBubbleContent();
    269 }
    270 
    271 void FullscreenController::OnTabDeactivated(WebContents* web_contents) {
    272   if (web_contents == fullscreened_tab_ || web_contents == mouse_lock_tab_)
    273     ExitTabFullscreenOrMouseLockIfNecessary();
    274 }
    275 
    276 void FullscreenController::OnTabClosing(WebContents* web_contents) {
    277   if (web_contents == fullscreened_tab_ || web_contents == mouse_lock_tab_) {
    278     ExitTabFullscreenOrMouseLockIfNecessary();
    279     // The call to exit fullscreen may result in asynchronous notification of
    280     // fullscreen state change (e.g., on Linux). We don't want to rely on it
    281     // to call NotifyTabOfExitIfNecessary(), because at that point
    282     // |fullscreened_tab_| may not be valid. Instead, we call it here to clean
    283     // up tab fullscreen related state.
    284     NotifyTabOfExitIfNecessary();
    285   }
    286 }
    287 
    288 void FullscreenController::WindowFullscreenStateChanged() {
    289   reentrant_window_state_change_call_check_ = true;
    290 
    291   bool exiting_fullscreen = !window_->IsFullscreen();
    292 
    293   PostFullscreenChangeNotification(!exiting_fullscreen);
    294   if (exiting_fullscreen) {
    295     toggled_into_fullscreen_ = false;
    296     extension_caused_fullscreen_ = GURL();
    297     NotifyTabOfExitIfNecessary();
    298   }
    299   if (exiting_fullscreen) {
    300     window_->GetDownloadShelf()->Unhide();
    301   } else {
    302     window_->GetDownloadShelf()->Hide();
    303     if (window_->GetStatusBubble())
    304       window_->GetStatusBubble()->Hide();
    305   }
    306 }
    307 
    308 bool FullscreenController::HandleUserPressedEscape() {
    309   if (IsFullscreenForTabOrPending() ||
    310       IsMouseLocked() || IsMouseLockRequested()) {
    311     ExitTabFullscreenOrMouseLockIfNecessary();
    312     return true;
    313   }
    314 
    315   return false;
    316 }
    317 
    318 void FullscreenController::ExitTabOrBrowserFullscreenToPreviousState() {
    319   if (IsFullscreenForTabOrPending())
    320     ExitTabFullscreenOrMouseLockIfNecessary();
    321   else if (IsFullscreenForBrowser())
    322     ExitFullscreenModeInternal();
    323 }
    324 
    325 void FullscreenController::OnAcceptFullscreenPermission() {
    326   FullscreenExitBubbleType bubble_type = GetFullscreenExitBubbleType();
    327   bool mouse_lock = false;
    328   bool fullscreen = false;
    329   fullscreen_bubble::PermissionRequestedByType(bubble_type, &fullscreen,
    330                                                &mouse_lock);
    331   DCHECK(!(fullscreen && tab_fullscreen_accepted_));
    332   DCHECK(!(mouse_lock && IsMouseLocked()));
    333 
    334   HostContentSettingsMap* settings_map = profile_->GetHostContentSettingsMap();
    335 
    336   GURL url = GetFullscreenExitBubbleURL();
    337   ContentSettingsPattern pattern = ContentSettingsPattern::FromURL(url);
    338 
    339   if (mouse_lock && !IsMouseLocked()) {
    340     DCHECK(IsMouseLockRequested());
    341     // TODO(markusheintz): We should allow patterns for all possible URLs here.
    342     if (pattern.IsValid()) {
    343       settings_map->SetContentSetting(
    344           pattern, ContentSettingsPattern::Wildcard(),
    345           CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string(),
    346           CONTENT_SETTING_ALLOW);
    347     }
    348 
    349     if (mouse_lock_tab_ &&
    350         mouse_lock_tab_->GotResponseToLockMouseRequest(true)) {
    351       mouse_lock_state_ = MOUSELOCK_ACCEPTED;
    352     } else {
    353       mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
    354       SetMouseLockTab(NULL);
    355     }
    356     NotifyMouseLockChange();
    357   }
    358 
    359   if (fullscreen && !tab_fullscreen_accepted_) {
    360     DCHECK(fullscreened_tab_);
    361     if (pattern.IsValid()) {
    362       settings_map->SetContentSetting(
    363           pattern, ContentSettingsPattern::Wildcard(),
    364           CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string(),
    365           CONTENT_SETTING_ALLOW);
    366     }
    367     tab_fullscreen_accepted_ = true;
    368   }
    369   UpdateFullscreenExitBubbleContent();
    370 }
    371 
    372 void FullscreenController::OnDenyFullscreenPermission() {
    373   if (!fullscreened_tab_ && !mouse_lock_tab_)
    374     return;
    375 
    376   if (IsMouseLockRequested()) {
    377     mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
    378     if (mouse_lock_tab_)
    379       mouse_lock_tab_->GotResponseToLockMouseRequest(false);
    380     SetMouseLockTab(NULL);
    381     NotifyMouseLockChange();
    382 
    383     // UpdateFullscreenExitBubbleContent() must be called, but to avoid
    384     // duplicate calls we do so only if not adjusting the fullscreen state
    385     // below, which also calls UpdateFullscreenExitBubbleContent().
    386     if (!IsFullscreenForTabOrPending())
    387       UpdateFullscreenExitBubbleContent();
    388   }
    389 
    390   if (IsFullscreenForTabOrPending())
    391     ExitTabFullscreenOrMouseLockIfNecessary();
    392 }
    393 
    394 void FullscreenController::LostMouseLock() {
    395   mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
    396   SetMouseLockTab(NULL);
    397   NotifyMouseLockChange();
    398   UpdateFullscreenExitBubbleContent();
    399 }
    400 
    401 void FullscreenController::Observe(int type,
    402     const content::NotificationSource& source,
    403     const content::NotificationDetails& details) {
    404   switch (type) {
    405     case content::NOTIFICATION_NAV_ENTRY_COMMITTED:
    406       if (content::Details<content::LoadCommittedDetails>(details)->
    407               is_navigation_to_different_page()) {
    408         ExitTabFullscreenOrMouseLockIfNecessary();
    409       }
    410       break;
    411 
    412     default:
    413       NOTREACHED() << "Got a notification we didn't register for.";
    414   }
    415 }
    416 
    417 GURL FullscreenController::GetFullscreenExitBubbleURL() const {
    418   if (fullscreened_tab_)
    419     return fullscreened_tab_->GetURL();
    420   else if (mouse_lock_tab_)
    421     return mouse_lock_tab_->GetURL();
    422   else if (!extension_caused_fullscreen_.is_empty())
    423     return extension_caused_fullscreen_;
    424   else
    425     return GURL();
    426 }
    427 
    428 FullscreenExitBubbleType FullscreenController::GetFullscreenExitBubbleType()
    429     const {
    430   // In kiosk and exclusive app mode we always want to be fullscreen and do not
    431   // want to show exit instructions for browser mode fullscreen.
    432   bool app_mode = false;
    433 #if !defined(OS_MACOSX)  // App mode (kiosk) is not available on Mac yet.
    434   app_mode = chrome::IsRunningInAppMode();
    435 #endif
    436 
    437   if (mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY) {
    438     return FEB_TYPE_NONE;
    439   }
    440 
    441   if (fullscreened_tab_) {
    442     if (tab_fullscreen_accepted_) {
    443       if (IsPrivilegedFullscreenForTab()) {
    444         return FEB_TYPE_NONE;
    445       } else if (IsMouseLocked()) {
    446         return FEB_TYPE_FULLSCREEN_MOUSELOCK_EXIT_INSTRUCTION;
    447       } else if (IsMouseLockRequested()) {
    448         return FEB_TYPE_MOUSELOCK_BUTTONS;
    449       } else {
    450         return FEB_TYPE_FULLSCREEN_EXIT_INSTRUCTION;
    451       }
    452     } else {  // Full screen not yet accepted.
    453       if (IsMouseLockRequested()) {
    454         return FEB_TYPE_FULLSCREEN_MOUSELOCK_BUTTONS;
    455       } else {
    456         return FEB_TYPE_FULLSCREEN_BUTTONS;
    457       }
    458     }
    459   } else {  // Not tab full screen.
    460     if (IsMouseLocked()) {
    461       return FEB_TYPE_MOUSELOCK_EXIT_INSTRUCTION;
    462     } else if (IsMouseLockRequested()) {
    463       return FEB_TYPE_MOUSELOCK_BUTTONS;
    464     } else {
    465       if (!extension_caused_fullscreen_.is_empty()) {
    466         return FEB_TYPE_BROWSER_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION;
    467       } else if (toggled_into_fullscreen_ && !app_mode) {
    468         return FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION;
    469       } else {
    470         return FEB_TYPE_NONE;
    471       }
    472     }
    473   }
    474   NOTREACHED();
    475   return FEB_TYPE_NONE;
    476 }
    477 
    478 void FullscreenController::UpdateNotificationRegistrations() {
    479   if (fullscreened_tab_ && mouse_lock_tab_)
    480     DCHECK(fullscreened_tab_ == mouse_lock_tab_);
    481 
    482   WebContents* tab = fullscreened_tab_ ? fullscreened_tab_ : mouse_lock_tab_;
    483 
    484   if (tab && registrar_.IsEmpty()) {
    485     registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
    486         content::Source<content::NavigationController>(&tab->GetController()));
    487   } else if (!tab && !registrar_.IsEmpty()) {
    488     registrar_.RemoveAll();
    489   }
    490 }
    491 
    492 void FullscreenController::PostFullscreenChangeNotification(
    493     bool is_fullscreen) {
    494   base::MessageLoop::current()->PostTask(
    495       FROM_HERE,
    496       base::Bind(&FullscreenController::NotifyFullscreenChange,
    497                  ptr_factory_.GetWeakPtr(),
    498                  is_fullscreen));
    499 }
    500 
    501 void FullscreenController::NotifyFullscreenChange(bool is_fullscreen) {
    502   content::NotificationService::current()->Notify(
    503       chrome::NOTIFICATION_FULLSCREEN_CHANGED,
    504       content::Source<FullscreenController>(this),
    505       content::Details<bool>(&is_fullscreen));
    506 }
    507 
    508 void FullscreenController::NotifyTabOfExitIfNecessary() {
    509   if (fullscreened_tab_) {
    510     RenderViewHost* rvh = fullscreened_tab_->GetRenderViewHost();
    511     SetFullscreenedTab(NULL);
    512     state_prior_to_tab_fullscreen_ = STATE_INVALID;
    513     tab_fullscreen_accepted_ = false;
    514     if (rvh)
    515       rvh->ExitFullscreen();
    516   }
    517 
    518   if (mouse_lock_tab_) {
    519     if (IsMouseLockRequested()) {
    520       mouse_lock_tab_->GotResponseToLockMouseRequest(false);
    521       NotifyMouseLockChange();
    522     } else {
    523       UnlockMouse();
    524     }
    525     SetMouseLockTab(NULL);
    526     mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
    527   }
    528 
    529   UpdateFullscreenExitBubbleContent();
    530 }
    531 
    532 void FullscreenController::NotifyMouseLockChange() {
    533   content::NotificationService::current()->Notify(
    534       chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
    535       content::Source<FullscreenController>(this),
    536       content::NotificationService::NoDetails());
    537 }
    538 
    539 void FullscreenController::ToggleFullscreenModeInternal(
    540     FullscreenInternalOption option) {
    541 #if defined(OS_WIN)
    542   // When in Metro snap mode, toggling in and out of fullscreen is prevented.
    543   if (IsInMetroSnapMode())
    544     return;
    545 #endif
    546 
    547   bool enter_fullscreen = !window_->IsFullscreen();
    548 #if defined(OS_MACOSX)
    549   // When a Mac user requests a toggle they may be toggling between
    550   // FullscreenWithoutChrome and FullscreenWithChrome.
    551   if (!IsFullscreenForTabOrPending()) {
    552     if (option == BROWSER_WITH_CHROME)
    553       enter_fullscreen |= window_->IsFullscreenWithoutChrome();
    554     else
    555       enter_fullscreen |= window_->IsFullscreenWithChrome();
    556   }
    557 #endif
    558 
    559   // In kiosk mode, we always want to be fullscreen. When the browser first
    560   // starts we're not yet fullscreen, so let the initial toggle go through.
    561   if (chrome::IsRunningInAppMode() && window_->IsFullscreen())
    562     return;
    563 
    564 #if !defined(OS_MACOSX)
    565   // Do not enter fullscreen mode if disallowed by pref. This prevents the user
    566   // from manually entering fullscreen mode and also disables kiosk mode on
    567   // desktop platforms.
    568   if (enter_fullscreen &&
    569       !profile_->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed)) {
    570     return;
    571   }
    572 #endif
    573 
    574   if (enter_fullscreen)
    575     EnterFullscreenModeInternal(option);
    576   else
    577     ExitFullscreenModeInternal();
    578 }
    579 
    580 void FullscreenController::EnterFullscreenModeInternal(
    581     FullscreenInternalOption option) {
    582   toggled_into_fullscreen_ = true;
    583   GURL url;
    584   if (option == TAB) {
    585     url = browser_->tab_strip_model()->GetActiveWebContents()->GetURL();
    586     tab_fullscreen_accepted_ =
    587         GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW;
    588   } else {
    589     if (!extension_caused_fullscreen_.is_empty())
    590       url = extension_caused_fullscreen_;
    591   }
    592 
    593   if (option == BROWSER)
    594     content::RecordAction(UserMetricsAction("ToggleFullscreen"));
    595   // TODO(scheib): Record metrics for WITH_CHROME, without counting transitions
    596   // from tab fullscreen out to browser with chrome.
    597 
    598 #if defined(OS_MACOSX)
    599   if (option == BROWSER_WITH_CHROME) {
    600     CHECK(chrome::mac::SupportsSystemFullscreen());
    601     window_->EnterFullscreenWithChrome();
    602   } else {
    603 #else
    604   {
    605 #endif
    606     window_->EnterFullscreen(url, GetFullscreenExitBubbleType());
    607   }
    608 
    609   UpdateFullscreenExitBubbleContent();
    610 
    611   // Once the window has become fullscreen it'll call back to
    612   // WindowFullscreenStateChanged(). We don't do this immediately as
    613   // BrowserWindow::EnterFullscreen() asks for bookmark_bar_state_, so we let
    614   // the BrowserWindow invoke WindowFullscreenStateChanged when appropriate.
    615 }
    616 
    617 void FullscreenController::ExitFullscreenModeInternal() {
    618   toggled_into_fullscreen_ = false;
    619 #if defined(OS_MACOSX)
    620   // Mac windows report a state change instantly, and so we must also clear
    621   // state_prior_to_tab_fullscreen_ to match them else other logic using
    622   // state_prior_to_tab_fullscreen_ will be incorrect.
    623   NotifyTabOfExitIfNecessary();
    624 #endif
    625   window_->ExitFullscreen();
    626   extension_caused_fullscreen_ = GURL();
    627 
    628   UpdateFullscreenExitBubbleContent();
    629 }
    630 
    631 void FullscreenController::SetFullscreenedTab(WebContents* tab) {
    632   fullscreened_tab_ = tab;
    633   UpdateNotificationRegistrations();
    634 }
    635 
    636 void FullscreenController::SetMouseLockTab(WebContents* tab) {
    637   mouse_lock_tab_ = tab;
    638   UpdateNotificationRegistrations();
    639 }
    640 
    641 void FullscreenController::ExitTabFullscreenOrMouseLockIfNecessary() {
    642   if (IsFullscreenForTabOrPending())
    643     ToggleFullscreenModeForTab(fullscreened_tab_, false);
    644   else
    645     NotifyTabOfExitIfNecessary();
    646 }
    647 
    648 void FullscreenController::UpdateFullscreenExitBubbleContent() {
    649   GURL url = GetFullscreenExitBubbleURL();
    650   FullscreenExitBubbleType bubble_type = GetFullscreenExitBubbleType();
    651 
    652   // If bubble displays buttons, unlock mouse to allow pressing them.
    653   if (fullscreen_bubble::ShowButtonsForType(bubble_type) && IsMouseLocked())
    654     UnlockMouse();
    655 
    656   window_->UpdateFullscreenExitBubbleContent(url, bubble_type);
    657 }
    658 
    659 ContentSetting
    660 FullscreenController::GetFullscreenSetting(const GURL& url) const {
    661   if (IsPrivilegedFullscreenForTab() || url.SchemeIsFile())
    662     return CONTENT_SETTING_ALLOW;
    663 
    664   return profile_->GetHostContentSettingsMap()->GetContentSetting(url, url,
    665       CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string());
    666 }
    667 
    668 ContentSetting
    669 FullscreenController::GetMouseLockSetting(const GURL& url) const {
    670   if (IsPrivilegedFullscreenForTab() || url.SchemeIsFile())
    671     return CONTENT_SETTING_ALLOW;
    672 
    673   HostContentSettingsMap* settings_map = profile_->GetHostContentSettingsMap();
    674   return settings_map->GetContentSetting(url, url,
    675       CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string());
    676 }
    677 
    678 bool FullscreenController::IsPrivilegedFullscreenForTab() const {
    679   const bool embedded_widget_present =
    680       fullscreened_tab_ &&
    681       fullscreened_tab_->GetFullscreenRenderWidgetHostView() &&
    682       implicit_cast<const content::WebContentsDelegate*>(browser_)->
    683           EmbedsFullscreenWidget();
    684   return embedded_widget_present || is_privileged_fullscreen_for_testing_;
    685 }
    686 
    687 void FullscreenController::SetPrivilegedFullscreenForTesting(
    688     bool is_privileged) {
    689   is_privileged_fullscreen_for_testing_ = is_privileged;
    690 }
    691 
    692 void FullscreenController::UnlockMouse() {
    693   if (!mouse_lock_tab_)
    694     return;
    695   content::RenderWidgetHostView* mouse_lock_view =
    696       (fullscreened_tab_ == mouse_lock_tab_ && IsPrivilegedFullscreenForTab()) ?
    697       mouse_lock_tab_->GetFullscreenRenderWidgetHostView() : NULL;
    698   if (!mouse_lock_view) {
    699     RenderViewHost* const rvh = mouse_lock_tab_->GetRenderViewHost();
    700     if (rvh)
    701       mouse_lock_view = rvh->GetView();
    702   }
    703   if (mouse_lock_view)
    704     mouse_lock_view->UnlockMouse();
    705 }
    706