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