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