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 33 using content::RenderViewHost; 34 using content::UserMetricsAction; 35 using content::WebContents; 36 37 FullscreenController::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 53 FullscreenController::~FullscreenController() { 54 } 55 56 bool FullscreenController::IsFullscreenForBrowser() const { 57 return window_->IsFullscreen() && !IsFullscreenCausedByTab(); 58 } 59 60 void FullscreenController::ToggleFullscreenMode() { 61 extension_caused_fullscreen_ = GURL(); 62 ToggleFullscreenModeInternal(BROWSER); 63 } 64 65 bool FullscreenController::IsFullscreenForTabOrPending() const { 66 return fullscreened_tab_ != NULL; 67 } 68 69 bool 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 77 bool FullscreenController::IsFullscreenCausedByTab() const { 78 return state_prior_to_tab_fullscreen_ == STATE_NORMAL; 79 } 80 81 void 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 165 void 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 173 bool 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) 182 void 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) 196 void 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 204 bool FullscreenController::IsMouseLockRequested() const { 205 return mouse_lock_state_ == MOUSELOCK_REQUESTED; 206 } 207 208 bool FullscreenController::IsMouseLocked() const { 209 return mouse_lock_state_ == MOUSELOCK_ACCEPTED || 210 mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY; 211 } 212 213 void 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 265 void FullscreenController::OnTabDeactivated(WebContents* web_contents) { 266 if (web_contents == fullscreened_tab_ || web_contents == mouse_lock_tab_) 267 ExitTabFullscreenOrMouseLockIfNecessary(); 268 } 269 270 void 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 282 void 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 299 bool FullscreenController::HandleUserPressedEscape() { 300 if (IsFullscreenForTabOrPending() || 301 IsMouseLocked() || IsMouseLockRequested()) { 302 ExitTabFullscreenOrMouseLockIfNecessary(); 303 return true; 304 } 305 306 return false; 307 } 308 309 void FullscreenController::ExitTabOrBrowserFullscreenToPreviousState() { 310 if (IsFullscreenForTabOrPending()) 311 ExitTabFullscreenOrMouseLockIfNecessary(); 312 else if (IsFullscreenForBrowser()) 313 ExitFullscreenModeInternal(); 314 } 315 316 void 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 363 void 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 385 void FullscreenController::LostMouseLock() { 386 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED; 387 SetMouseLockTab(NULL); 388 NotifyMouseLockChange(); 389 UpdateFullscreenExitBubbleContent(); 390 } 391 392 void 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 408 GURL 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 419 FullscreenExitBubbleType 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 467 void 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 481 void 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 490 void 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 497 void 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 522 void 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. 530 void 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 561 void 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 598 void 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 612 void FullscreenController::SetFullscreenedTab(WebContents* tab) { 613 fullscreened_tab_ = tab; 614 UpdateNotificationRegistrations(); 615 } 616 617 void FullscreenController::SetMouseLockTab(WebContents* tab) { 618 mouse_lock_tab_ = tab; 619 UpdateNotificationRegistrations(); 620 } 621 622 void FullscreenController::ExitTabFullscreenOrMouseLockIfNecessary() { 623 if (IsFullscreenForTabOrPending()) 624 ToggleFullscreenModeForTab(fullscreened_tab_, false); 625 else 626 NotifyTabOfExitIfNecessary(); 627 } 628 629 void 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 645 ContentSetting 646 FullscreenController::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 654 ContentSetting 655 FullscreenController::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