browser.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright 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/browser.h" 6 7#if defined(OS_WIN) 8#include <windows.h> 9#include <shellapi.h> 10#endif // defined(OS_WIN) 11 12#include <algorithm> 13#include <string> 14 15#include "base/base_paths.h" 16#include "base/bind.h" 17#include "base/command_line.h" 18#include "base/logging.h" 19#include "base/metrics/histogram.h" 20#include "base/path_service.h" 21#include "base/prefs/pref_service.h" 22#include "base/process/process_info.h" 23#include "base/strings/string_number_conversions.h" 24#include "base/strings/string_util.h" 25#include "base/strings/stringprintf.h" 26#include "base/strings/utf_string_conversions.h" 27#include "base/threading/thread.h" 28#include "base/threading/thread_restrictions.h" 29#include "base/time/time.h" 30#include "chrome/app/chrome_command_ids.h" 31#include "chrome/browser/app_mode/app_mode_utils.h" 32#include "chrome/browser/autofill/personal_data_manager_factory.h" 33#include "chrome/browser/background/background_contents_service.h" 34#include "chrome/browser/background/background_contents_service_factory.h" 35#include "chrome/browser/browser_process.h" 36#include "chrome/browser/browser_shutdown.h" 37#include "chrome/browser/character_encoding.h" 38#include "chrome/browser/chrome_notification_types.h" 39#include "chrome/browser/chrome_page_zoom.h" 40#include "chrome/browser/content_settings/host_content_settings_map.h" 41#include "chrome/browser/content_settings/tab_specific_content_settings.h" 42#include "chrome/browser/custom_handlers/protocol_handler_registry.h" 43#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" 44#include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h" 45#include "chrome/browser/custom_handlers/register_protocol_handler_permission_request.h" 46#include "chrome/browser/defaults.h" 47#include "chrome/browser/devtools/devtools_toggle_action.h" 48#include "chrome/browser/devtools/devtools_window.h" 49#include "chrome/browser/download/download_item_model.h" 50#include "chrome/browser/download/download_service.h" 51#include "chrome/browser/download/download_service_factory.h" 52#include "chrome/browser/download/download_shelf.h" 53#include "chrome/browser/extensions/browser_extension_window_controller.h" 54#include "chrome/browser/extensions/extension_service.h" 55#include "chrome/browser/extensions/tab_helper.h" 56#include "chrome/browser/favicon/favicon_tab_helper.h" 57#include "chrome/browser/file_select_helper.h" 58#include "chrome/browser/first_run/first_run.h" 59#include "chrome/browser/google/google_url_tracker.h" 60#include "chrome/browser/history/top_sites.h" 61#include "chrome/browser/infobars/infobar_service.h" 62#include "chrome/browser/infobars/simple_alert_infobar_delegate.h" 63#include "chrome/browser/lifetime/application_lifetime.h" 64#include "chrome/browser/notifications/notification_ui_manager.h" 65#include "chrome/browser/pepper_broker_infobar_delegate.h" 66#include "chrome/browser/prefs/incognito_mode_prefs.h" 67#include "chrome/browser/profiles/profile.h" 68#include "chrome/browser/profiles/profile_destroyer.h" 69#include "chrome/browser/profiles/profile_metrics.h" 70#include "chrome/browser/repost_form_warning_controller.h" 71#include "chrome/browser/search/search.h" 72#include "chrome/browser/sessions/session_service.h" 73#include "chrome/browser/sessions/session_service_factory.h" 74#include "chrome/browser/sessions/session_tab_helper.h" 75#include "chrome/browser/sessions/session_types.h" 76#include "chrome/browser/sessions/tab_restore_service.h" 77#include "chrome/browser/sessions/tab_restore_service_factory.h" 78#include "chrome/browser/sync/profile_sync_service.h" 79#include "chrome/browser/sync/profile_sync_service_factory.h" 80#include "chrome/browser/sync/sync_ui_util.h" 81#include "chrome/browser/tab_contents/background_contents.h" 82#include "chrome/browser/tab_contents/retargeting_details.h" 83#include "chrome/browser/tab_contents/tab_util.h" 84#include "chrome/browser/themes/theme_service.h" 85#include "chrome/browser/themes/theme_service_factory.h" 86#include "chrome/browser/translate/translate_tab_helper.h" 87#include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h" 88#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h" 89#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h" 90#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" 91#include "chrome/browser/ui/bookmarks/bookmark_utils.h" 92#include "chrome/browser/ui/browser_command_controller.h" 93#include "chrome/browser/ui/browser_commands.h" 94#include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" 95#include "chrome/browser/ui/browser_content_translate_driver_observer.h" 96#include "chrome/browser/ui/browser_dialogs.h" 97#include "chrome/browser/ui/browser_finder.h" 98#include "chrome/browser/ui/browser_instant_controller.h" 99#include "chrome/browser/ui/browser_iterator.h" 100#include "chrome/browser/ui/browser_list.h" 101#include "chrome/browser/ui/browser_navigator.h" 102#include "chrome/browser/ui/browser_tab_restore_service_delegate.h" 103#include "chrome/browser/ui/browser_tab_strip_model_delegate.h" 104#include "chrome/browser/ui/browser_tabstrip.h" 105#include "chrome/browser/ui/browser_toolbar_model_delegate.h" 106#include "chrome/browser/ui/browser_ui_prefs.h" 107#include "chrome/browser/ui/browser_window.h" 108#include "chrome/browser/ui/chrome_pages.h" 109#include "chrome/browser/ui/chrome_select_file_policy.h" 110#include "chrome/browser/ui/fast_unload_controller.h" 111#include "chrome/browser/ui/find_bar/find_bar.h" 112#include "chrome/browser/ui/find_bar/find_bar_controller.h" 113#include "chrome/browser/ui/find_bar/find_tab_helper.h" 114#include "chrome/browser/ui/fullscreen/fullscreen_controller.h" 115#include "chrome/browser/ui/global_error/global_error.h" 116#include "chrome/browser/ui/global_error/global_error_service.h" 117#include "chrome/browser/ui/global_error/global_error_service_factory.h" 118#include "chrome/browser/ui/media_utils.h" 119#include "chrome/browser/ui/omnibox/location_bar.h" 120#include "chrome/browser/ui/search/search_delegate.h" 121#include "chrome/browser/ui/search/search_model.h" 122#include "chrome/browser/ui/search/search_tab_helper.h" 123#include "chrome/browser/ui/search_engines/search_engine_tab_helper.h" 124#include "chrome/browser/ui/singleton_tabs.h" 125#include "chrome/browser/ui/status_bubble.h" 126#include "chrome/browser/ui/sync/browser_synced_window_delegate.h" 127#include "chrome/browser/ui/tab_contents/core_tab_helper.h" 128#include "chrome/browser/ui/tab_helpers.h" 129#include "chrome/browser/ui/tab_modal_confirm_dialog.h" 130#include "chrome/browser/ui/tabs/tab_menu_model.h" 131#include "chrome/browser/ui/tabs/tab_strip_model.h" 132#include "chrome/browser/ui/tabs/tab_strip_model_utils.h" 133#include "chrome/browser/ui/toolbar/toolbar_model_impl.h" 134#include "chrome/browser/ui/unload_controller.h" 135#include "chrome/browser/ui/validation_message_bubble.h" 136#include "chrome/browser/ui/website_settings/permission_bubble_manager.h" 137#include "chrome/browser/ui/webui/signin/login_ui_service.h" 138#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" 139#include "chrome/browser/ui/window_sizer/window_sizer.h" 140#include "chrome/browser/ui/zoom/zoom_controller.h" 141#include "chrome/browser/upgrade_detector.h" 142#include "chrome/browser/web_applications/web_app.h" 143#include "chrome/common/chrome_constants.h" 144#include "chrome/common/chrome_switches.h" 145#include "chrome/common/custom_handlers/protocol_handler.h" 146#include "chrome/common/net/url_fixer_upper.h" 147#include "chrome/common/pref_names.h" 148#include "chrome/common/profiling.h" 149#include "chrome/common/search_types.h" 150#include "chrome/common/url_constants.h" 151#include "components/bookmarks/browser/bookmark_model.h" 152#include "components/bookmarks/browser/bookmark_utils.h" 153#include "components/startup_metric_utils/startup_metric_utils.h" 154#include "components/web_modal/web_contents_modal_dialog_manager.h" 155#include "content/public/browser/devtools_manager.h" 156#include "content/public/browser/download_item.h" 157#include "content/public/browser/download_manager.h" 158#include "content/public/browser/interstitial_page.h" 159#include "content/public/browser/invalidate_type.h" 160#include "content/public/browser/navigation_controller.h" 161#include "content/public/browser/navigation_entry.h" 162#include "content/public/browser/notification_details.h" 163#include "content/public/browser/notification_service.h" 164#include "content/public/browser/plugin_service.h" 165#include "content/public/browser/render_process_host.h" 166#include "content/public/browser/render_view_host.h" 167#include "content/public/browser/render_widget_host_view.h" 168#include "content/public/browser/site_instance.h" 169#include "content/public/browser/user_metrics.h" 170#include "content/public/browser/web_contents.h" 171#include "content/public/common/content_switches.h" 172#include "content/public/common/page_zoom.h" 173#include "content/public/common/renderer_preferences.h" 174#include "content/public/common/webplugininfo.h" 175#include "extensions/browser/extension_prefs.h" 176#include "extensions/browser/extension_system.h" 177#include "extensions/common/constants.h" 178#include "extensions/common/extension.h" 179#include "extensions/common/manifest_handlers/background_info.h" 180#include "grit/chromium_strings.h" 181#include "grit/generated_resources.h" 182#include "grit/locale_settings.h" 183#include "grit/theme_resources.h" 184#include "net/base/filename_util.h" 185#include "net/base/registry_controlled_domains/registry_controlled_domain.h" 186#include "net/cookies/cookie_monster.h" 187#include "net/url_request/url_request_context.h" 188#include "third_party/WebKit/public/web/WebWindowFeatures.h" 189#include "ui/base/l10n/l10n_util.h" 190#include "ui/base/window_open_disposition.h" 191#include "ui/gfx/point.h" 192#include "ui/shell_dialogs/selected_file_info.h" 193 194#if defined(OS_WIN) 195#include "base/win/metro.h" 196#include "chrome/browser/ssl/ssl_error_info.h" 197#include "chrome/browser/task_manager/task_manager.h" 198#include "chrome/browser/ui/view_ids.h" 199#include "components/autofill/core/browser/autofill_ie_toolbar_import_win.h" 200#include "ui/base/win/shell.h" 201#endif // OS_WIN 202 203#if defined(OS_CHROMEOS) 204#include "chrome/browser/chromeos/drive/file_system_util.h" 205#endif 206 207#if defined(USE_ASH) 208#include "ash/ash_switches.h" 209#endif 210 211using base::TimeDelta; 212using base::UserMetricsAction; 213using content::NativeWebKeyboardEvent; 214using content::NavigationController; 215using content::NavigationEntry; 216using content::OpenURLParams; 217using content::PluginService; 218using content::Referrer; 219using content::RenderWidgetHostView; 220using content::SiteInstance; 221using content::WebContents; 222using extensions::Extension; 223using ui::WebDialogDelegate; 224using web_modal::WebContentsModalDialogManager; 225using blink::WebWindowFeatures; 226 227/////////////////////////////////////////////////////////////////////////////// 228 229namespace { 230 231// How long we wait before updating the browser chrome while loading a page. 232const int kUIUpdateCoalescingTimeMS = 200; 233 234BrowserWindow* CreateBrowserWindow(Browser* browser) { 235 return BrowserWindow::CreateBrowserWindow(browser); 236} 237 238// Is the fast tab unload experiment enabled? 239bool IsFastTabUnloadEnabled() { 240 return CommandLine::ForCurrentProcess()->HasSwitch( 241 switches::kEnableFastUnload); 242} 243 244} // namespace 245 246//////////////////////////////////////////////////////////////////////////////// 247// Browser, CreateParams: 248 249Browser::CreateParams::CreateParams(Profile* profile, 250 chrome::HostDesktopType host_desktop_type) 251 : type(TYPE_TABBED), 252 profile(profile), 253 host_desktop_type(host_desktop_type), 254 trusted_source(false), 255 initial_show_state(ui::SHOW_STATE_DEFAULT), 256 is_session_restore(false), 257 window(NULL) { 258} 259 260Browser::CreateParams::CreateParams(Type type, 261 Profile* profile, 262 chrome::HostDesktopType host_desktop_type) 263 : type(type), 264 profile(profile), 265 host_desktop_type(host_desktop_type), 266 trusted_source(false), 267 initial_show_state(ui::SHOW_STATE_DEFAULT), 268 is_session_restore(false), 269 window(NULL) { 270} 271 272// static 273Browser::CreateParams Browser::CreateParams::CreateForApp( 274 const std::string& app_name, 275 bool trusted_source, 276 const gfx::Rect& window_bounds, 277 Profile* profile, 278 chrome::HostDesktopType host_desktop_type) { 279 DCHECK(!app_name.empty()); 280 281 CreateParams params(TYPE_POPUP, profile, host_desktop_type); 282 params.app_name = app_name; 283 params.trusted_source = trusted_source; 284 params.initial_bounds = window_bounds; 285 286 return params; 287} 288 289// static 290Browser::CreateParams Browser::CreateParams::CreateForDevTools( 291 Profile* profile, 292 chrome::HostDesktopType host_desktop_type) { 293 CreateParams params(TYPE_POPUP, profile, host_desktop_type); 294 params.app_name = DevToolsWindow::kDevToolsApp; 295 params.trusted_source = true; 296 return params; 297} 298 299//////////////////////////////////////////////////////////////////////////////// 300// Browser, InterstitialObserver: 301 302class Browser::InterstitialObserver : public content::WebContentsObserver { 303 public: 304 InterstitialObserver(Browser* browser, content::WebContents* web_contents) 305 : WebContentsObserver(web_contents), 306 browser_(browser) { 307 } 308 309 using content::WebContentsObserver::web_contents; 310 311 virtual void DidAttachInterstitialPage() OVERRIDE { 312 browser_->UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE); 313 } 314 315 virtual void DidDetachInterstitialPage() OVERRIDE { 316 browser_->UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE); 317 } 318 319 private: 320 Browser* browser_; 321 322 DISALLOW_COPY_AND_ASSIGN(InterstitialObserver); 323}; 324 325/////////////////////////////////////////////////////////////////////////////// 326// Browser, Constructors, Creation, Showing: 327 328Browser::Browser(const CreateParams& params) 329 : type_(params.type), 330 profile_(params.profile), 331 window_(NULL), 332 tab_strip_model_delegate_(new chrome::BrowserTabStripModelDelegate(this)), 333 tab_strip_model_(new TabStripModel(tab_strip_model_delegate_.get(), 334 params.profile)), 335 app_name_(params.app_name), 336 is_trusted_source_(params.trusted_source), 337 cancel_download_confirmation_state_(NOT_PROMPTED), 338 override_bounds_(params.initial_bounds), 339 initial_show_state_(params.initial_show_state), 340 is_session_restore_(params.is_session_restore), 341 host_desktop_type_(BrowserWindow::AdjustHostDesktopType( 342 params.host_desktop_type)), 343 content_setting_bubble_model_delegate_( 344 new BrowserContentSettingBubbleModelDelegate(this)), 345 toolbar_model_delegate_(new BrowserToolbarModelDelegate(this)), 346 tab_restore_service_delegate_(new BrowserTabRestoreServiceDelegate(this)), 347 synced_window_delegate_(new BrowserSyncedWindowDelegate(this)), 348 bookmark_bar_state_(BookmarkBar::HIDDEN), 349 command_controller_(new chrome::BrowserCommandController(this)), 350 window_has_shown_(false), 351 chrome_updater_factory_(this), 352 weak_factory_(this), 353 translate_driver_observer_( 354 new BrowserContentTranslateDriverObserver(this)) { 355 // If this causes a crash then a window is being opened using a profile type 356 // that is disallowed by policy. The crash prevents the disabled window type 357 // from opening at all, but the path that triggered it should be fixed. 358 CHECK(IncognitoModePrefs::CanOpenBrowser(profile_)); 359 CHECK(!profile_->IsGuestSession() || profile_->IsOffTheRecord()) 360 << "Only off the record browser may be opened in guest mode"; 361 362 // TODO(jeremy): Move to initializer list once flag is removed. 363 if (IsFastTabUnloadEnabled()) 364 fast_unload_controller_.reset(new chrome::FastUnloadController(this)); 365 else 366 unload_controller_.reset(new chrome::UnloadController(this)); 367 368 if (!app_name_.empty()) 369 chrome::RegisterAppPrefs(app_name_, profile_); 370 tab_strip_model_->AddObserver(this); 371 372 toolbar_model_.reset(new ToolbarModelImpl(toolbar_model_delegate_.get())); 373 search_model_.reset(new SearchModel()); 374 search_delegate_.reset(new SearchDelegate(search_model_.get())); 375 376 registrar_.Add(this, 377 chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, 378 content::Source<Profile>(profile_->GetOriginalProfile())); 379 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, 380 content::Source<Profile>(profile_->GetOriginalProfile())); 381 registrar_.Add(this, 382 chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED, 383 content::Source<Profile>(profile_->GetOriginalProfile())); 384 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, 385 content::NotificationService::AllSources()); 386#if defined(ENABLE_THEMES) 387 registrar_.Add( 388 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED, 389 content::Source<ThemeService>( 390 ThemeServiceFactory::GetForProfile(profile_))); 391#endif 392 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 393 content::NotificationService::AllSources()); 394 395 profile_pref_registrar_.Init(profile_->GetPrefs()); 396 profile_pref_registrar_.Add( 397 prefs::kDevToolsDisabled, 398 base::Bind(&Browser::OnDevToolsDisabledChanged, base::Unretained(this))); 399 profile_pref_registrar_.Add( 400 prefs::kShowBookmarkBar, 401 base::Bind(&Browser::UpdateBookmarkBarState, base::Unretained(this), 402 BOOKMARK_BAR_STATE_CHANGE_PREF_CHANGE)); 403 404 BrowserList::AddBrowser(this); 405 406 // NOTE: These prefs all need to be explicitly destroyed in the destructor 407 // or you'll get a nasty surprise when you run the incognito tests. 408 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector, 409 profile_->GetPrefs()); 410 411 if (chrome::IsInstantExtendedAPIEnabled() && is_type_tabbed()) 412 instant_controller_.reset(new BrowserInstantController(this)); 413 414 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_INIT); 415 416 ProfileMetrics::LogProfileLaunch(profile_); 417 418 window_ = params.window ? params.window : CreateBrowserWindow(this); 419 420 // Create the extension window controller before sending notifications. 421 extension_window_controller_.reset( 422 new BrowserExtensionWindowController(this)); 423 424 SessionService* session_service = 425 SessionServiceFactory::GetForProfileForSessionRestore(profile_); 426 if (session_service) 427 session_service->WindowOpened(this); 428 429 // TODO(beng): Move BrowserList::AddBrowser() to the end of this function and 430 // replace uses of this with BL's notifications. 431 content::NotificationService::current()->Notify( 432 chrome::NOTIFICATION_BROWSER_WINDOW_READY, 433 content::Source<Browser>(this), 434 content::NotificationService::NoDetails()); 435 436 // TODO(beng): move to ChromeBrowserMain: 437 if (first_run::ShouldDoPersonalDataManagerFirstRun()) { 438#if defined(OS_WIN) 439 // Notify PDM that this is a first run. 440 ImportAutofillDataWin( 441 autofill::PersonalDataManagerFactory::GetForProfile(profile_)); 442#endif // defined(OS_WIN) 443 } 444 445 fullscreen_controller_.reset(new FullscreenController(this)); 446} 447 448Browser::~Browser() { 449 // Stop observing notifications before continuing with destruction. Profile 450 // destruction will unload extensions and reentrant calls to Browser:: should 451 // be avoided while it is being torn down. 452 registrar_.RemoveAll(); 453 454 // The tab strip should not have any tabs at this point. 455 DCHECK(tab_strip_model_->empty()); 456 tab_strip_model_->RemoveObserver(this); 457 458 // Destroy the BrowserCommandController before removing the browser, so that 459 // it doesn't act on any notifications that are sent as a result of removing 460 // the browser. 461 command_controller_.reset(); 462 BrowserList::RemoveBrowser(this); 463 464 SessionService* session_service = 465 SessionServiceFactory::GetForProfile(profile_); 466 if (session_service) 467 session_service->WindowClosed(session_id_); 468 469 TabRestoreService* tab_restore_service = 470 TabRestoreServiceFactory::GetForProfile(profile()); 471 if (tab_restore_service) 472 tab_restore_service->BrowserClosed(tab_restore_service_delegate()); 473 474#if !defined(OS_MACOSX) 475 if (!chrome::GetTotalBrowserCountForProfile(profile_)) { 476 // We're the last browser window with this profile. We need to nuke the 477 // TabRestoreService, which will start the shutdown of the 478 // NavigationControllers and allow for proper shutdown. If we don't do this 479 // chrome won't shutdown cleanly, and may end up crashing when some 480 // thread tries to use the IO thread (or another thread) that is no longer 481 // valid. 482 // This isn't a valid assumption for Mac OS, as it stays running after 483 // the last browser has closed. The Mac equivalent is in its app 484 // controller. 485 TabRestoreServiceFactory::ResetForProfile(profile_); 486 } 487#endif 488 489 profile_pref_registrar_.RemoveAll(); 490 491 encoding_auto_detect_.Destroy(); 492 493 // Destroy BrowserExtensionWindowController before the incognito profile 494 // is destroyed to make sure the chrome.windows.onRemoved event is sent. 495 extension_window_controller_.reset(); 496 497 // Destroy BrowserInstantController before the incongnito profile is destroyed 498 // because the InstantController destructor depends on this profile. 499 instant_controller_.reset(); 500 501 if (profile_->IsOffTheRecord() && 502 !BrowserList::IsOffTheRecordSessionActiveForProfile(profile_)) { 503 // An incognito profile is no longer needed, this indirectly frees 504 // its cache and cookies once it gets destroyed at the appropriate time. 505 ProfileDestroyer::DestroyProfileWhenAppropriate(profile_); 506 } 507 508 // There may be pending file dialogs, we need to tell them that we've gone 509 // away so they don't try and call back to us. 510 if (select_file_dialog_.get()) 511 select_file_dialog_->ListenerDestroyed(); 512 513 int num_downloads; 514 if (OkToCloseWithInProgressDownloads(&num_downloads) == 515 DOWNLOAD_CLOSE_BROWSER_SHUTDOWN && 516 !browser_defaults::kBrowserAliveWithNoWindows) { 517 DownloadService::CancelAllDownloads(); 518 } 519} 520 521/////////////////////////////////////////////////////////////////////////////// 522// Getters & Setters 523 524FindBarController* Browser::GetFindBarController() { 525 if (!find_bar_controller_.get()) { 526 FindBar* find_bar = window_->CreateFindBar(); 527 find_bar_controller_.reset(new FindBarController(find_bar)); 528 find_bar->SetFindBarController(find_bar_controller_.get()); 529 find_bar_controller_->ChangeWebContents( 530 tab_strip_model_->GetActiveWebContents()); 531 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); 532 } 533 return find_bar_controller_.get(); 534} 535 536bool Browser::HasFindBarController() const { 537 return find_bar_controller_.get() != NULL; 538} 539 540bool Browser::is_app() const { 541 return !app_name_.empty(); 542} 543 544bool Browser::is_devtools() const { 545 return app_name_ == DevToolsWindow::kDevToolsApp; 546} 547 548/////////////////////////////////////////////////////////////////////////////// 549// Browser, State Storage and Retrieval for UI: 550 551gfx::Image Browser::GetCurrentPageIcon() const { 552 WebContents* web_contents = tab_strip_model_->GetActiveWebContents(); 553 // |web_contents| can be NULL since GetCurrentPageIcon() is called by the 554 // window during the window's creation (before tabs have been added). 555 FaviconTabHelper* favicon_tab_helper = 556 web_contents ? FaviconTabHelper::FromWebContents(web_contents) : NULL; 557 return favicon_tab_helper ? favicon_tab_helper->GetFavicon() : gfx::Image(); 558} 559 560base::string16 Browser::GetWindowTitleForCurrentTab() const { 561 WebContents* contents = tab_strip_model_->GetActiveWebContents(); 562 base::string16 title; 563 564 // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the 565 // window during the window's creation (before tabs have been added). 566 if (contents) { 567 title = contents->GetTitle(); 568 FormatTitleForDisplay(&title); 569 } 570 if (title.empty()) 571 title = CoreTabHelper::GetDefaultTitle(); 572 573#if defined(OS_MACOSX) 574 // On Mac, we don't want to suffix the page title with 575 // the application name. 576 return title; 577#elif defined(USE_ASH) 578 // On Ash, we don't want to suffix the page title with the application name, 579 // but on Windows, where USE_ASH can also be true, we still want the prefix 580 // on desktop. 581 if (host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) 582 return title; 583#endif 584 // Don't append the app name to window titles on app frames and app popups 585 return is_app() ? 586 title : 587 l10n_util::GetStringFUTF16(IDS_BROWSER_WINDOW_TITLE_FORMAT, title); 588} 589 590// static 591void Browser::FormatTitleForDisplay(base::string16* title) { 592 size_t current_index = 0; 593 size_t match_index; 594 while ((match_index = title->find(L'\n', current_index)) != 595 base::string16::npos) { 596 title->replace(match_index, 1, base::string16()); 597 current_index = match_index; 598 } 599} 600 601/////////////////////////////////////////////////////////////////////////////// 602// Browser, OnBeforeUnload handling: 603 604bool Browser::ShouldCloseWindow() { 605 if (!CanCloseWithInProgressDownloads()) 606 return false; 607 608 if (IsFastTabUnloadEnabled()) 609 return fast_unload_controller_->ShouldCloseWindow(); 610 return unload_controller_->ShouldCloseWindow(); 611} 612 613bool Browser::CallBeforeUnloadHandlers( 614 const base::Callback<void(bool)>& on_close_confirmed) { 615 cancel_download_confirmation_state_ = RESPONSE_RECEIVED; 616 if (IsFastTabUnloadEnabled()) { 617 return fast_unload_controller_->CallBeforeUnloadHandlers( 618 on_close_confirmed); 619 } 620 return unload_controller_->CallBeforeUnloadHandlers(on_close_confirmed); 621} 622 623void Browser::ResetBeforeUnloadHandlers() { 624 cancel_download_confirmation_state_ = NOT_PROMPTED; 625 if (IsFastTabUnloadEnabled()) 626 fast_unload_controller_->ResetBeforeUnloadHandlers(); 627 else 628 unload_controller_->ResetBeforeUnloadHandlers(); 629} 630 631bool Browser::HasCompletedUnloadProcessing() const { 632 DCHECK(IsFastTabUnloadEnabled()); 633 return fast_unload_controller_->HasCompletedUnloadProcessing(); 634} 635 636bool Browser::IsAttemptingToCloseBrowser() const { 637 if (IsFastTabUnloadEnabled()) 638 return fast_unload_controller_->is_attempting_to_close_browser(); 639 return unload_controller_->is_attempting_to_close_browser(); 640} 641 642void Browser::OnWindowClosing() { 643 if (!ShouldCloseWindow()) 644 return; 645 646 // Application should shutdown on last window close if the user is explicitly 647 // trying to quit, or if there is nothing keeping the browser alive (such as 648 // AppController on the Mac, or BackgroundContentsService for background 649 // pages). 650 bool should_quit_if_last_browser = 651 browser_shutdown::IsTryingToQuit() || !chrome::WillKeepAlive(); 652 653 if (should_quit_if_last_browser && chrome::ShouldStartShutdown(this)) 654 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE); 655 656 // Don't use GetForProfileIfExisting here, we want to force creation of the 657 // session service so that user can restore what was open. 658 SessionService* session_service = 659 SessionServiceFactory::GetForProfile(profile()); 660 if (session_service) 661 session_service->WindowClosing(session_id()); 662 663 TabRestoreService* tab_restore_service = 664 TabRestoreServiceFactory::GetForProfile(profile()); 665 666#if defined(USE_AURA) 667 if (tab_restore_service && is_app() && !is_devtools()) 668 tab_restore_service->BrowserClosing(tab_restore_service_delegate()); 669#endif 670 671 if (tab_restore_service && is_type_tabbed() && tab_strip_model_->count()) 672 tab_restore_service->BrowserClosing(tab_restore_service_delegate()); 673 674 // TODO(sky): convert session/tab restore to use notification. 675 content::NotificationService::current()->Notify( 676 chrome::NOTIFICATION_BROWSER_CLOSING, 677 content::Source<Browser>(this), 678 content::NotificationService::NoDetails()); 679 680 if (!IsFastTabUnloadEnabled()) 681 tab_strip_model_->CloseAllTabs(); 682} 683 684//////////////////////////////////////////////////////////////////////////////// 685// In-progress download termination handling: 686 687void Browser::InProgressDownloadResponse(bool cancel_downloads) { 688 if (cancel_downloads) { 689 cancel_download_confirmation_state_ = RESPONSE_RECEIVED; 690 chrome::CloseWindow(this); 691 return; 692 } 693 694 // Sets the confirmation state to NOT_PROMPTED so that if the user tries to 695 // close again we'll show the warning again. 696 cancel_download_confirmation_state_ = NOT_PROMPTED; 697 698 // Show the download page so the user can figure-out what downloads are still 699 // in-progress. 700 chrome::ShowDownloads(this); 701 702 // Reset UnloadController::is_attempting_to_close_browser_ so that we don't 703 // prompt every time any tab is closed. http://crbug.com/305516 704 if (IsFastTabUnloadEnabled()) 705 fast_unload_controller_->CancelWindowClose(); 706 else 707 unload_controller_->CancelWindowClose(); 708} 709 710Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads( 711 int* num_downloads_blocking) const { 712 DCHECK(num_downloads_blocking); 713 *num_downloads_blocking = 0; 714 715 // If we're not running a full browser process with a profile manager 716 // (testing), it's ok to close the browser. 717 if (!g_browser_process->profile_manager()) 718 return DOWNLOAD_CLOSE_OK; 719 720 int total_download_count = 721 DownloadService::NonMaliciousDownloadCountAllProfiles(); 722 if (total_download_count == 0) 723 return DOWNLOAD_CLOSE_OK; // No downloads; can definitely close. 724 725 // Figure out how many windows are open total, and associated with this 726 // profile, that are relevant for the ok-to-close decision. 727 int profile_window_count = 0; 728 int total_window_count = 0; 729 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 730 // Don't count this browser window or any other in the process of closing. 731 Browser* const browser = *it; 732 // Window closing may be delayed, and windows that are in the process of 733 // closing don't count against our totals. 734 if (browser == this || browser->IsAttemptingToCloseBrowser()) 735 continue; 736 737 if (it->profile() == profile()) 738 profile_window_count++; 739 total_window_count++; 740 } 741 742 // If there aren't any other windows, we're at browser shutdown, 743 // which would cancel all current downloads. 744 if (total_window_count == 0) { 745 *num_downloads_blocking = total_download_count; 746 return DOWNLOAD_CLOSE_BROWSER_SHUTDOWN; 747 } 748 749 // If there aren't any other windows on our profile, and we're an incognito 750 // profile, and there are downloads associated with that profile, 751 // those downloads would be cancelled by our window (-> profile) close. 752 DownloadService* download_service = 753 DownloadServiceFactory::GetForBrowserContext(profile()); 754 if ((profile_window_count == 0) && 755 (download_service->NonMaliciousDownloadCount() > 0) && 756 profile()->IsOffTheRecord()) { 757 *num_downloads_blocking = download_service->NonMaliciousDownloadCount(); 758 return DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE; 759 } 760 761 // Those are the only conditions under which we will block shutdown. 762 return DOWNLOAD_CLOSE_OK; 763} 764 765//////////////////////////////////////////////////////////////////////////////// 766// Browser, Tab adding/showing functions: 767 768void Browser::WindowFullscreenStateChanged() { 769 fullscreen_controller_->WindowFullscreenStateChanged(); 770 command_controller_->FullscreenStateChanged(); 771 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TOGGLE_FULLSCREEN); 772} 773 774void Browser::VisibleSSLStateChanged(content::WebContents* web_contents) { 775 // When the current tab's SSL state changes, we need to update the URL 776 // bar to reflect the new state. 777 DCHECK(web_contents); 778 if (tab_strip_model_->GetActiveWebContents() == web_contents) 779 UpdateToolbar(false); 780} 781 782 783/////////////////////////////////////////////////////////////////////////////// 784// Browser, Assorted browser commands: 785 786void Browser::ToggleFullscreenModeWithExtension(const GURL& extension_url) { 787 fullscreen_controller_-> 788 ToggleBrowserFullscreenModeWithExtension(extension_url); 789} 790 791bool Browser::SupportsWindowFeature(WindowFeature feature) const { 792 return SupportsWindowFeatureImpl(feature, true); 793} 794 795bool Browser::CanSupportWindowFeature(WindowFeature feature) const { 796 return SupportsWindowFeatureImpl(feature, false); 797} 798 799void Browser::ToggleEncodingAutoDetect() { 800 content::RecordAction(UserMetricsAction("AutoDetectChange")); 801 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue()); 802 // If "auto detect" is turned on, then any current override encoding 803 // is cleared. This also implicitly performs a reload. 804 // OTOH, if "auto detect" is turned off, we don't change the currently 805 // active encoding. 806 if (encoding_auto_detect_.GetValue()) { 807 WebContents* contents = tab_strip_model_->GetActiveWebContents(); 808 if (contents) 809 contents->ResetOverrideEncoding(); 810 } 811} 812 813void Browser::OverrideEncoding(int encoding_id) { 814 content::RecordAction(UserMetricsAction("OverrideEncoding")); 815 const std::string selected_encoding = 816 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id); 817 WebContents* contents = tab_strip_model_->GetActiveWebContents(); 818 if (!selected_encoding.empty() && contents) 819 contents->SetOverrideEncoding(selected_encoding); 820 // Update the list of recently selected encodings. 821 std::string new_selected_encoding_list; 822 if (CharacterEncoding::UpdateRecentlySelectedEncoding( 823 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding), 824 encoding_id, 825 &new_selected_encoding_list)) { 826 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding, 827 new_selected_encoding_list); 828 } 829} 830 831void Browser::OpenFile() { 832 content::RecordAction(UserMetricsAction("OpenFile")); 833 select_file_dialog_ = ui::SelectFileDialog::Create( 834 this, new ChromeSelectFilePolicy( 835 tab_strip_model_->GetActiveWebContents())); 836 837 const base::FilePath directory = profile_->last_selected_directory(); 838 839 // TODO(beng): figure out how to juggle this. 840 gfx::NativeWindow parent_window = window_->GetNativeWindow(); 841 ui::SelectFileDialog::FileTypeInfo file_types; 842 file_types.support_drive = true; 843 select_file_dialog_->SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE, 844 base::string16(), 845 directory, 846 &file_types, 847 0, 848 base::FilePath::StringType(), 849 parent_window, 850 NULL); 851} 852 853void Browser::UpdateDownloadShelfVisibility(bool visible) { 854 if (GetStatusBubble()) 855 GetStatusBubble()->UpdateDownloadShelfVisibility(visible); 856} 857 858/////////////////////////////////////////////////////////////////////////////// 859 860void Browser::UpdateUIForNavigationInTab(WebContents* contents, 861 content::PageTransition transition, 862 bool user_initiated) { 863 tab_strip_model_->TabNavigating(contents, transition); 864 865 bool contents_is_selected = 866 contents == tab_strip_model_->GetActiveWebContents(); 867 if (user_initiated && contents_is_selected && window()->GetLocationBar()) { 868 // Forcibly reset the location bar if the url is going to change in the 869 // current tab, since otherwise it won't discard any ongoing user edits, 870 // since it doesn't realize this is a user-initiated action. 871 window()->GetLocationBar()->Revert(); 872 } 873 874 if (GetStatusBubble()) 875 GetStatusBubble()->Hide(); 876 877 // Update the location bar. This is synchronous. We specifically don't 878 // update the load state since the load hasn't started yet and updating it 879 // will put it out of sync with the actual state like whether we're 880 // displaying a favicon, which controls the throbber. If we updated it here, 881 // the throbber will show the default favicon for a split second when 882 // navigating away from the new tab page. 883 ScheduleUIUpdate(contents, content::INVALIDATE_TYPE_URL); 884 885 if (contents_is_selected) 886 contents->SetInitialFocus(); 887} 888 889/////////////////////////////////////////////////////////////////////////////// 890// Browser, PageNavigator implementation: 891 892WebContents* Browser::OpenURL(const OpenURLParams& params) { 893 return OpenURLFromTab(NULL, params); 894} 895 896/////////////////////////////////////////////////////////////////////////////// 897// Browser, TabStripModelObserver implementation: 898 899void Browser::TabInsertedAt(WebContents* contents, 900 int index, 901 bool foreground) { 902 SetAsDelegate(contents, this); 903 SessionTabHelper* session_tab_helper = 904 SessionTabHelper::FromWebContents(contents); 905 session_tab_helper->SetWindowID(session_id()); 906 907 content::NotificationService::current()->Notify( 908 chrome::NOTIFICATION_TAB_PARENTED, 909 content::Source<content::WebContents>(contents), 910 content::NotificationService::NoDetails()); 911 912 SyncHistoryWithTabs(index); 913 914 // Make sure the loading state is updated correctly, otherwise the throbber 915 // won't start if the page is loading. 916 LoadingStateChanged(contents, true); 917 918 interstitial_observers_.push_back(new InterstitialObserver(this, contents)); 919 920 SessionService* session_service = 921 SessionServiceFactory::GetForProfile(profile_); 922 if (session_service) { 923 session_service->TabInserted(contents); 924 int new_active_index = tab_strip_model_->active_index(); 925 if (index < new_active_index) 926 session_service->SetSelectedTabInWindow(session_id(), 927 new_active_index); 928 } 929} 930 931void Browser::TabClosingAt(TabStripModel* tab_strip_model, 932 WebContents* contents, 933 int index) { 934 fullscreen_controller_->OnTabClosing(contents); 935 SessionService* session_service = 936 SessionServiceFactory::GetForProfile(profile_); 937 if (session_service) 938 session_service->TabClosing(contents); 939 content::NotificationService::current()->Notify( 940 chrome::NOTIFICATION_TAB_CLOSING, 941 content::Source<NavigationController>(&contents->GetController()), 942 content::NotificationService::NoDetails()); 943 944 // Sever the WebContents' connection back to us. 945 SetAsDelegate(contents, NULL); 946} 947 948void Browser::TabDetachedAt(WebContents* contents, int index) { 949 // TabDetachedAt is called before TabStripModel has updated the 950 // active index. 951 int old_active_index = tab_strip_model_->active_index(); 952 if (index < old_active_index && !tab_strip_model_->closing_all()) { 953 SessionService* session_service = 954 SessionServiceFactory::GetForProfileIfExisting(profile_); 955 if (session_service) 956 session_service->SetSelectedTabInWindow(session_id(), 957 old_active_index - 1); 958 } 959 TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH); 960} 961 962void Browser::TabDeactivated(WebContents* contents) { 963 fullscreen_controller_->OnTabDeactivated(contents); 964 search_delegate_->OnTabDeactivated(contents); 965 SearchTabHelper::FromWebContents(contents)->OnTabDeactivated(); 966 967 // Save what the user's currently typing, so it can be restored when we 968 // switch back to this tab. 969 window_->GetLocationBar()->SaveStateToContents(contents); 970 971 if (instant_controller_) 972 instant_controller_->TabDeactivated(contents); 973} 974 975void Browser::ActiveTabChanged(WebContents* old_contents, 976 WebContents* new_contents, 977 int index, 978 int reason) { 979 content::RecordAction(UserMetricsAction("ActiveTabChanged")); 980 981 // Update the bookmark state, since the BrowserWindow may query it during 982 // OnActiveTabChanged() below. 983 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_SWITCH); 984 985 // Let the BrowserWindow do its handling. On e.g. views this changes the 986 // focused object, which should happen before we update the toolbar below, 987 // since the omnibox expects the correct element to already be focused when it 988 // is updated. 989 window_->OnActiveTabChanged(old_contents, new_contents, index, reason); 990 991 fullscreen_controller_->OnTabDetachedFromView(old_contents); 992 993 // Discarded tabs always get reloaded. 994 if (tab_strip_model_->IsTabDiscarded(index)) { 995 LOG(WARNING) << "Reloading discarded tab at " << index; 996 static int reload_count = 0; 997 UMA_HISTOGRAM_CUSTOM_COUNTS( 998 "Tabs.Discard.ReloadCount", ++reload_count, 1, 1000, 50); 999 chrome::Reload(this, CURRENT_TAB); 1000 } 1001 1002 // If we have any update pending, do it now. 1003 if (chrome_updater_factory_.HasWeakPtrs() && old_contents) 1004 ProcessPendingUIUpdates(); 1005 1006 // Propagate the profile to the location bar. 1007 UpdateToolbar((reason & CHANGE_REASON_REPLACED) == 0); 1008 1009 if (chrome::IsInstantExtendedAPIEnabled()) 1010 search_delegate_->OnTabActivated(new_contents); 1011 1012 // Update reload/stop state. 1013 command_controller_->LoadingStateChanged(new_contents->IsLoading(), true); 1014 1015 // Update commands to reflect current state. 1016 command_controller_->TabStateChanged(); 1017 1018 // Reset the status bubble. 1019 StatusBubble* status_bubble = GetStatusBubble(); 1020 if (status_bubble) { 1021 status_bubble->Hide(); 1022 1023 // Show the loading state (if any). 1024 status_bubble->SetStatus(CoreTabHelper::FromWebContents( 1025 tab_strip_model_->GetActiveWebContents())->GetStatusText()); 1026 } 1027 1028 if (HasFindBarController()) { 1029 find_bar_controller_->ChangeWebContents(new_contents); 1030 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); 1031 } 1032 1033 // Update sessions. Don't force creation of sessions. If sessions doesn't 1034 // exist, the change will be picked up by sessions when created. 1035 SessionService* session_service = 1036 SessionServiceFactory::GetForProfileIfExisting(profile_); 1037 if (session_service && !tab_strip_model_->closing_all()) { 1038 session_service->SetSelectedTabInWindow(session_id(), 1039 tab_strip_model_->active_index()); 1040 } 1041 1042 // This needs to be called after notifying SearchDelegate. 1043 if (instant_controller_) 1044 instant_controller_->ActiveTabChanged(); 1045 1046 autofill::TabAutofillManagerDelegate::FromWebContents(new_contents)-> 1047 TabActivated(); 1048 SearchTabHelper::FromWebContents(new_contents)->OnTabActivated(); 1049} 1050 1051void Browser::TabMoved(WebContents* contents, 1052 int from_index, 1053 int to_index) { 1054 DCHECK(from_index >= 0 && to_index >= 0); 1055 // Notify the history service. 1056 SyncHistoryWithTabs(std::min(from_index, to_index)); 1057} 1058 1059void Browser::TabReplacedAt(TabStripModel* tab_strip_model, 1060 WebContents* old_contents, 1061 WebContents* new_contents, 1062 int index) { 1063 TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE); 1064 fullscreen_controller_->OnTabClosing(old_contents); 1065 SessionService* session_service = 1066 SessionServiceFactory::GetForProfile(profile_); 1067 if (session_service) 1068 session_service->TabClosing(old_contents); 1069 TabInsertedAt(new_contents, 1070 index, 1071 (index == tab_strip_model_->active_index())); 1072 1073 int entry_count = new_contents->GetController().GetEntryCount(); 1074 if (entry_count > 0) { 1075 // Send out notification so that observers are updated appropriately. 1076 new_contents->GetController().NotifyEntryChanged( 1077 new_contents->GetController().GetEntryAtIndex(entry_count - 1), 1078 entry_count - 1); 1079 } 1080 1081 if (session_service) { 1082 // The new_contents may end up with a different navigation stack. Force 1083 // the session service to update itself. 1084 session_service->TabRestored(new_contents, 1085 tab_strip_model_->IsTabPinned(index)); 1086 } 1087} 1088 1089void Browser::TabPinnedStateChanged(WebContents* contents, int index) { 1090 SessionService* session_service = 1091 SessionServiceFactory::GetForProfileIfExisting(profile()); 1092 if (session_service) { 1093 SessionTabHelper* session_tab_helper = 1094 SessionTabHelper::FromWebContents(contents); 1095 session_service->SetPinnedState(session_id(), 1096 session_tab_helper->session_id(), 1097 tab_strip_model_->IsTabPinned(index)); 1098 } 1099} 1100 1101void Browser::TabStripEmpty() { 1102 // Close the frame after we return to the message loop (not immediately, 1103 // otherwise it will destroy this object before the stack has a chance to 1104 // cleanly unwind.) 1105 // Note: This will be called several times if TabStripEmpty is called several 1106 // times. This is because it does not close the window if tabs are 1107 // still present. 1108 base::MessageLoop::current()->PostTask( 1109 FROM_HERE, base::Bind(&Browser::CloseFrame, weak_factory_.GetWeakPtr())); 1110 1111 // Instant may have visible WebContents that need to be detached before the 1112 // window system closes. 1113 instant_controller_.reset(); 1114} 1115 1116bool Browser::CanOverscrollContent() const { 1117#if defined(USE_AURA) 1118 const std::string value = CommandLine::ForCurrentProcess()-> 1119 GetSwitchValueASCII(switches::kOverscrollHistoryNavigation); 1120 bool overscroll_enabled = value != "0"; 1121 if (!overscroll_enabled) 1122 return false; 1123 if (is_app() || is_devtools() || !is_type_tabbed()) 1124 return false; 1125 1126 // The detached bookmark bar has appearance of floating above the 1127 // web-contents. This does not play nicely with overscroll navigation 1128 // gestures. So disable overscroll navigation when the bookmark bar is in the 1129 // detached state and the overscroll effect moves the layers. 1130 if (value == "1" && bookmark_bar_state_ == BookmarkBar::DETACHED) 1131 return false; 1132 return true; 1133#else 1134 return false; 1135#endif 1136} 1137 1138bool Browser::ShouldPreserveAbortedURLs(WebContents* source) { 1139 // Allow failed URLs to stick around in the omnibox on the NTP, but not when 1140 // other pages have committed. 1141 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); 1142 if (!profile || !source->GetController().GetLastCommittedEntry()) 1143 return false; 1144 GURL committed_url(source->GetController().GetLastCommittedEntry()->GetURL()); 1145 return chrome::IsNTPURL(committed_url, profile); 1146} 1147 1148bool Browser::PreHandleKeyboardEvent(content::WebContents* source, 1149 const NativeWebKeyboardEvent& event, 1150 bool* is_keyboard_shortcut) { 1151 // Escape exits tabbed fullscreen mode. 1152 // TODO(koz): Write a test for this http://crbug.com/100441. 1153 if (event.windowsKeyCode == 27 && 1154 fullscreen_controller_->HandleUserPressedEscape()) { 1155 return true; 1156 } 1157 return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut); 1158} 1159 1160void Browser::HandleKeyboardEvent(content::WebContents* source, 1161 const NativeWebKeyboardEvent& event) { 1162 DevToolsWindow* devtools_window = 1163 DevToolsWindow::GetInstanceForInspectedWebContents(source); 1164 bool handled = false; 1165 if (devtools_window) 1166 handled = devtools_window->ForwardKeyboardEvent(event); 1167 1168 if (!handled) 1169 window()->HandleKeyboardEvent(event); 1170} 1171 1172bool Browser::TabsNeedBeforeUnloadFired() { 1173 if (IsFastTabUnloadEnabled()) 1174 return fast_unload_controller_->TabsNeedBeforeUnloadFired(); 1175 return unload_controller_->TabsNeedBeforeUnloadFired(); 1176} 1177 1178void Browser::OverscrollUpdate(int delta_y) { 1179 window_->OverscrollUpdate(delta_y); 1180} 1181 1182void Browser::ShowValidationMessage(content::WebContents* web_contents, 1183 const gfx::Rect& anchor_in_root_view, 1184 const base::string16& main_text, 1185 const base::string16& sub_text) { 1186 RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView(); 1187 if (rwhv) { 1188 validation_message_bubble_ = 1189 chrome::ValidationMessageBubble::CreateAndShow( 1190 rwhv->GetRenderWidgetHost(), 1191 anchor_in_root_view, 1192 main_text, 1193 sub_text); 1194 } 1195} 1196 1197void Browser::HideValidationMessage(content::WebContents* web_contents) { 1198 validation_message_bubble_.reset(); 1199} 1200 1201void Browser::MoveValidationMessage(content::WebContents* web_contents, 1202 const gfx::Rect& anchor_in_root_view) { 1203 if (!validation_message_bubble_) 1204 return; 1205 RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView(); 1206 if (rwhv) { 1207 validation_message_bubble_->SetPositionRelativeToAnchor( 1208 rwhv->GetRenderWidgetHost(), anchor_in_root_view); 1209 } 1210} 1211 1212bool Browser::PreHandleGestureEvent(content::WebContents* source, 1213 const blink::WebGestureEvent& event) { 1214 // Disable pinch zooming in undocked dev tools window due to poor UX. 1215 if (app_name() == DevToolsWindow::kDevToolsApp) 1216 return event.type == blink::WebGestureEvent::GesturePinchBegin || 1217 event.type == blink::WebGestureEvent::GesturePinchUpdate || 1218 event.type == blink::WebGestureEvent::GesturePinchEnd; 1219 1220 return false; 1221} 1222 1223bool Browser::IsMouseLocked() const { 1224 return fullscreen_controller_->IsMouseLocked(); 1225} 1226 1227void Browser::OnWindowDidShow() { 1228 if (window_has_shown_) 1229 return; 1230 window_has_shown_ = true; 1231 1232// CurrentProcessInfo::CreationTime() is missing on some platforms. 1233#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX) 1234 // Measure the latency from startup till the first browser window becomes 1235 // visible. 1236 static bool is_first_browser_window = true; 1237 if (is_first_browser_window && 1238 !startup_metric_utils::WasNonBrowserUIDisplayed()) { 1239 is_first_browser_window = false; 1240 const base::Time process_creation_time = 1241 base::CurrentProcessInfo::CreationTime(); 1242 1243 if (!process_creation_time.is_null()) { 1244 UMA_HISTOGRAM_LONG_TIMES( 1245 "Startup.BrowserWindowDisplay", 1246 base::Time::Now() - process_creation_time); 1247 } 1248 } 1249#endif // defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX) 1250 1251 // Nothing to do for non-tabbed windows. 1252 if (!is_type_tabbed()) 1253 return; 1254 1255 // Show any pending global error bubble. 1256 GlobalErrorService* service = 1257 GlobalErrorServiceFactory::GetForProfile(profile()); 1258 GlobalError* error = service->GetFirstGlobalErrorWithBubbleView(); 1259 if (error) 1260 error->ShowBubbleView(this); 1261} 1262 1263void Browser::ShowFirstRunBubble() { 1264 window()->GetLocationBar()->ShowFirstRunBubble(); 1265} 1266 1267void Browser::ShowDownload(content::DownloadItem* download) { 1268 if (!window()) 1269 return; 1270 1271 // If the download occurs in a new tab, and it's not a save page 1272 // download (started before initial navigation completed) close it. 1273 WebContents* source = download->GetWebContents(); 1274 if (source && source->GetController().IsInitialNavigation() && 1275 tab_strip_model_->count() > 1 && !download->IsSavePackageDownload()) { 1276 CloseContents(source); 1277 } 1278 1279 // Some (app downloads) are not supposed to appear on the shelf. 1280 if (!DownloadItemModel(download).ShouldShowInShelf()) 1281 return; 1282 1283 // GetDownloadShelf creates the download shelf if it was not yet created. 1284 DownloadShelf* shelf = window()->GetDownloadShelf(); 1285 shelf->AddDownload(download); 1286} 1287 1288/////////////////////////////////////////////////////////////////////////////// 1289// Browser, content::WebContentsDelegate implementation: 1290 1291WebContents* Browser::OpenURLFromTab(WebContents* source, 1292 const OpenURLParams& params) { 1293 chrome::NavigateParams nav_params(this, params.url, params.transition); 1294 FillNavigateParamsFromOpenURLParams(&nav_params, params); 1295 nav_params.source_contents = source; 1296 nav_params.tabstrip_add_types = TabStripModel::ADD_NONE; 1297 if (params.user_gesture) 1298 nav_params.window_action = chrome::NavigateParams::SHOW_WINDOW; 1299 nav_params.user_gesture = params.user_gesture; 1300 1301 PopupBlockerTabHelper* popup_blocker_helper = NULL; 1302 if (source) 1303 popup_blocker_helper = PopupBlockerTabHelper::FromWebContents(source); 1304 1305 if (popup_blocker_helper) { 1306 if ((params.disposition == NEW_POPUP || 1307 params.disposition == NEW_FOREGROUND_TAB || 1308 params.disposition == NEW_BACKGROUND_TAB || 1309 params.disposition == NEW_WINDOW) && 1310 !params.user_gesture && !CommandLine::ForCurrentProcess()->HasSwitch( 1311 switches::kDisablePopupBlocking)) { 1312 if (popup_blocker_helper->MaybeBlockPopup(nav_params, 1313 WebWindowFeatures())) { 1314 return NULL; 1315 } 1316 } 1317 } 1318 1319 chrome::Navigate(&nav_params); 1320 1321 return nav_params.target_contents; 1322} 1323 1324void Browser::NavigationStateChanged(const WebContents* source, 1325 unsigned changed_flags) { 1326 // Only update the UI when something visible has changed. 1327 if (changed_flags) 1328 ScheduleUIUpdate(source, changed_flags); 1329 1330 // We can synchronously update commands since they will only change once per 1331 // navigation, so we don't have to worry about flickering. We do, however, 1332 // need to update the command state early on load to always present usable 1333 // actions in the face of slow-to-commit pages. 1334 if (changed_flags & (content::INVALIDATE_TYPE_URL | 1335 content::INVALIDATE_TYPE_LOAD)) 1336 command_controller_->TabStateChanged(); 1337} 1338 1339void Browser::AddNewContents(WebContents* source, 1340 WebContents* new_contents, 1341 WindowOpenDisposition disposition, 1342 const gfx::Rect& initial_pos, 1343 bool user_gesture, 1344 bool* was_blocked) { 1345 chrome::AddWebContents(this, source, new_contents, disposition, initial_pos, 1346 user_gesture, was_blocked); 1347} 1348 1349void Browser::ActivateContents(WebContents* contents) { 1350 tab_strip_model_->ActivateTabAt( 1351 tab_strip_model_->GetIndexOfWebContents(contents), false); 1352 window_->Activate(); 1353} 1354 1355void Browser::DeactivateContents(WebContents* contents) { 1356 window_->Deactivate(); 1357} 1358 1359void Browser::LoadingStateChanged(WebContents* source, 1360 bool to_different_document) { 1361 window_->UpdateLoadingAnimations(tab_strip_model_->TabsAreLoading()); 1362 window_->UpdateTitleBar(); 1363 1364 WebContents* selected_contents = tab_strip_model_->GetActiveWebContents(); 1365 if (source == selected_contents) { 1366 bool is_loading = source->IsLoading() && to_different_document; 1367 command_controller_->LoadingStateChanged(is_loading, false); 1368 if (GetStatusBubble()) { 1369 GetStatusBubble()->SetStatus(CoreTabHelper::FromWebContents( 1370 tab_strip_model_->GetActiveWebContents())->GetStatusText()); 1371 } 1372 } 1373} 1374 1375void Browser::CloseContents(WebContents* source) { 1376 bool can_close_contents; 1377 if (IsFastTabUnloadEnabled()) 1378 can_close_contents = fast_unload_controller_->CanCloseContents(source); 1379 else 1380 can_close_contents = unload_controller_->CanCloseContents(source); 1381 1382 if (can_close_contents) 1383 chrome::CloseWebContents(this, source, true); 1384} 1385 1386void Browser::MoveContents(WebContents* source, const gfx::Rect& pos) { 1387 if (!IsPopupOrPanel(source)) { 1388 NOTREACHED() << "moving invalid browser type"; 1389 return; 1390 } 1391 window_->SetBounds(pos); 1392} 1393 1394bool Browser::IsPopupOrPanel(const WebContents* source) const { 1395 return is_type_popup(); 1396} 1397 1398void Browser::UpdateTargetURL(WebContents* source, int32 page_id, 1399 const GURL& url) { 1400 if (!GetStatusBubble()) 1401 return; 1402 1403 if (source == tab_strip_model_->GetActiveWebContents()) { 1404 PrefService* prefs = profile_->GetPrefs(); 1405 GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages)); 1406 } 1407} 1408 1409void Browser::ContentsMouseEvent( 1410 WebContents* source, const gfx::Point& location, bool motion) { 1411 if (!GetStatusBubble()) 1412 return; 1413 1414 if (source == tab_strip_model_->GetActiveWebContents()) { 1415 GetStatusBubble()->MouseMoved(location, !motion); 1416 if (!motion) 1417 GetStatusBubble()->SetURL(GURL(), std::string()); 1418 } 1419} 1420 1421void Browser::ContentsZoomChange(bool zoom_in) { 1422 chrome::ExecuteCommand(this, zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS); 1423} 1424 1425void Browser::WebContentsFocused(WebContents* contents) { 1426 window_->WebContentsFocused(contents); 1427} 1428 1429bool Browser::TakeFocus(content::WebContents* source, 1430 bool reverse) { 1431 content::NotificationService::current()->Notify( 1432 chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER, 1433 content::Source<Browser>(this), 1434 content::NotificationService::NoDetails()); 1435 return false; 1436} 1437 1438gfx::Rect Browser::GetRootWindowResizerRect() const { 1439 return window_->GetRootWindowResizerRect(); 1440} 1441 1442void Browser::BeforeUnloadFired(WebContents* web_contents, 1443 bool proceed, 1444 bool* proceed_to_fire_unload) { 1445 if (is_devtools() && DevToolsWindow::HandleBeforeUnload(web_contents, 1446 proceed, proceed_to_fire_unload)) 1447 return; 1448 1449 if (IsFastTabUnloadEnabled()) { 1450 *proceed_to_fire_unload = 1451 fast_unload_controller_->BeforeUnloadFired(web_contents, proceed); 1452 } else { 1453 *proceed_to_fire_unload = 1454 unload_controller_->BeforeUnloadFired(web_contents, proceed); 1455 } 1456} 1457 1458bool Browser::ShouldFocusLocationBarByDefault(WebContents* source) { 1459 const content::NavigationEntry* entry = 1460 source->GetController().GetActiveEntry(); 1461 if (entry) { 1462 GURL url = entry->GetURL(); 1463 GURL virtual_url = entry->GetVirtualURL(); 1464 if ((url.SchemeIs(content::kChromeUIScheme) && 1465 url.host() == chrome::kChromeUINewTabHost) || 1466 (virtual_url.SchemeIs(content::kChromeUIScheme) && 1467 virtual_url.host() == chrome::kChromeUINewTabHost)) { 1468 return true; 1469 } 1470 } 1471 1472 return chrome::NavEntryIsInstantNTP(source, entry); 1473} 1474 1475void Browser::SetFocusToLocationBar(bool select_all) { 1476 // Two differences between this and FocusLocationBar(): 1477 // (1) This doesn't get recorded in user metrics, since it's called 1478 // internally. 1479 // (2) This checks whether the location bar can be focused, and if not, clears 1480 // the focus. FocusLocationBar() is only reached when the location bar is 1481 // focusable, but this may be reached at other times, e.g. while in 1482 // fullscreen mode, where we need to leave focus in a consistent state. 1483 window_->SetFocusToLocationBar(select_all); 1484} 1485 1486int Browser::GetExtraRenderViewHeight() const { 1487 return window_->GetExtraRenderViewHeight(); 1488} 1489 1490void Browser::ViewSourceForTab(WebContents* source, const GURL& page_url) { 1491 DCHECK(source); 1492 chrome::ViewSource(this, source); 1493} 1494 1495void Browser::ViewSourceForFrame(WebContents* source, 1496 const GURL& frame_url, 1497 const content::PageState& frame_page_state) { 1498 DCHECK(source); 1499 chrome::ViewSource(this, source, frame_url, frame_page_state); 1500} 1501 1502void Browser::ShowRepostFormWarningDialog(WebContents* source) { 1503 TabModalConfirmDialog::Create(new RepostFormWarningController(source), 1504 source); 1505} 1506 1507bool Browser::ShouldCreateWebContents( 1508 WebContents* web_contents, 1509 int route_id, 1510 WindowContainerType window_container_type, 1511 const base::string16& frame_name, 1512 const GURL& target_url, 1513 const std::string& partition_id, 1514 content::SessionStorageNamespace* session_storage_namespace) { 1515 if (window_container_type == WINDOW_CONTAINER_TYPE_BACKGROUND) { 1516 // If a BackgroundContents is created, suppress the normal WebContents. 1517 return !MaybeCreateBackgroundContents(route_id, 1518 web_contents, 1519 frame_name, 1520 target_url, 1521 partition_id, 1522 session_storage_namespace); 1523 } 1524 1525 return true; 1526} 1527 1528void Browser::WebContentsCreated(WebContents* source_contents, 1529 int opener_render_frame_id, 1530 const base::string16& frame_name, 1531 const GURL& target_url, 1532 WebContents* new_contents) { 1533 // Adopt the WebContents now, so all observers are in place, as the network 1534 // requests for its initial navigation will start immediately. The WebContents 1535 // will later be inserted into this browser using Browser::Navigate via 1536 // AddNewContents. 1537 TabHelpers::AttachTabHelpers(new_contents); 1538 1539 // Notify. 1540 RetargetingDetails details; 1541 details.source_web_contents = source_contents; 1542 details.source_render_frame_id = opener_render_frame_id; 1543 details.target_url = target_url; 1544 details.target_web_contents = new_contents; 1545 details.not_yet_in_tabstrip = true; 1546 content::NotificationService::current()->Notify( 1547 chrome::NOTIFICATION_RETARGETING, 1548 content::Source<Profile>(profile_), 1549 content::Details<RetargetingDetails>(&details)); 1550} 1551 1552void Browser::RendererUnresponsive(WebContents* source) { 1553 // Ignore hangs if a tab is blocked. 1554 int index = tab_strip_model_->GetIndexOfWebContents(source); 1555 DCHECK_NE(TabStripModel::kNoTab, index); 1556 if (tab_strip_model_->IsTabBlocked(index)) 1557 return; 1558 1559 chrome::ShowHungRendererDialog(source); 1560} 1561 1562void Browser::RendererResponsive(WebContents* source) { 1563 chrome::HideHungRendererDialog(source); 1564} 1565 1566void Browser::WorkerCrashed(WebContents* source) { 1567 SimpleAlertInfoBarDelegate::Create( 1568 InfoBarService::FromWebContents(source), 1569 infobars::InfoBarDelegate::kNoIconID, 1570 l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT), true); 1571} 1572 1573void Browser::DidNavigateMainFramePostCommit(WebContents* web_contents) { 1574 if (web_contents == tab_strip_model_->GetActiveWebContents()) 1575 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE); 1576} 1577 1578void Browser::DidNavigateToPendingEntry(WebContents* web_contents) { 1579 if (web_contents == tab_strip_model_->GetActiveWebContents()) 1580 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE); 1581} 1582 1583content::JavaScriptDialogManager* Browser::GetJavaScriptDialogManager() { 1584 return GetJavaScriptDialogManagerInstance(); 1585} 1586 1587content::ColorChooser* Browser::OpenColorChooser( 1588 WebContents* web_contents, 1589 SkColor initial_color, 1590 const std::vector<content::ColorSuggestion>& suggestions) { 1591 return chrome::ShowColorChooser(web_contents, initial_color); 1592} 1593 1594void Browser::RunFileChooser(WebContents* web_contents, 1595 const content::FileChooserParams& params) { 1596 FileSelectHelper::RunFileChooser(web_contents, params); 1597} 1598 1599void Browser::EnumerateDirectory(WebContents* web_contents, 1600 int request_id, 1601 const base::FilePath& path) { 1602 FileSelectHelper::EnumerateDirectory(web_contents, request_id, path); 1603} 1604 1605bool Browser::EmbedsFullscreenWidget() const { 1606 return !CommandLine::ForCurrentProcess()-> 1607 HasSwitch(switches::kDisableFullscreenWithinTab); 1608} 1609 1610void Browser::ToggleFullscreenModeForTab(WebContents* web_contents, 1611 bool enter_fullscreen) { 1612 fullscreen_controller_->ToggleFullscreenModeForTab(web_contents, 1613 enter_fullscreen); 1614} 1615 1616bool Browser::IsFullscreenForTabOrPending( 1617 const WebContents* web_contents) const { 1618 return fullscreen_controller_->IsFullscreenForTabOrPending(web_contents); 1619} 1620 1621void Browser::RegisterProtocolHandler(WebContents* web_contents, 1622 const std::string& protocol, 1623 const GURL& url, 1624 bool user_gesture) { 1625 Profile* profile = 1626 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 1627 if (profile->IsOffTheRecord()) 1628 return; 1629 1630 ProtocolHandler handler = 1631 ProtocolHandler::CreateProtocolHandler(protocol, url); 1632 1633 ProtocolHandlerRegistry* registry = 1634 ProtocolHandlerRegistryFactory::GetForProfile(profile); 1635 if (registry->SilentlyHandleRegisterHandlerRequest(handler)) 1636 return; 1637 1638 TabSpecificContentSettings* tab_content_settings = 1639 TabSpecificContentSettings::FromWebContents(web_contents); 1640 if (!user_gesture && window_) { 1641 tab_content_settings->set_pending_protocol_handler(handler); 1642 tab_content_settings->set_previous_protocol_handler( 1643 registry->GetHandlerFor(handler.protocol())); 1644 window_->GetLocationBar()->UpdateContentSettingsIcons(); 1645 return; 1646 } 1647 1648 // Make sure content-setting icon is turned off in case the page does 1649 // ungestured and gestured RPH calls. 1650 if (window_) { 1651 tab_content_settings->ClearPendingProtocolHandler(); 1652 window_->GetLocationBar()->UpdateContentSettingsIcons(); 1653 } 1654 1655 PermissionBubbleManager* bubble_manager = 1656 PermissionBubbleManager::FromWebContents(web_contents); 1657 if (PermissionBubbleManager::Enabled() && bubble_manager) { 1658 bubble_manager->AddRequest( 1659 new RegisterProtocolHandlerPermissionRequest(registry, handler, 1660 url, user_gesture)); 1661 } else { 1662 RegisterProtocolHandlerInfoBarDelegate::Create( 1663 InfoBarService::FromWebContents(web_contents), registry, handler); 1664 } 1665} 1666 1667void Browser::UpdatePreferredSize(WebContents* source, 1668 const gfx::Size& pref_size) { 1669 window_->UpdatePreferredSize(source, pref_size); 1670} 1671 1672void Browser::ResizeDueToAutoResize(WebContents* source, 1673 const gfx::Size& new_size) { 1674 window_->ResizeDueToAutoResize(source, new_size); 1675} 1676 1677void Browser::FindReply(WebContents* web_contents, 1678 int request_id, 1679 int number_of_matches, 1680 const gfx::Rect& selection_rect, 1681 int active_match_ordinal, 1682 bool final_update) { 1683 FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents); 1684 if (!find_tab_helper) 1685 return; 1686 1687 find_tab_helper->HandleFindReply(request_id, 1688 number_of_matches, 1689 selection_rect, 1690 active_match_ordinal, 1691 final_update); 1692} 1693 1694void Browser::RequestToLockMouse(WebContents* web_contents, 1695 bool user_gesture, 1696 bool last_unlocked_by_target) { 1697 fullscreen_controller_->RequestToLockMouse(web_contents, 1698 user_gesture, 1699 last_unlocked_by_target); 1700} 1701 1702void Browser::LostMouseLock() { 1703 fullscreen_controller_->LostMouseLock(); 1704} 1705 1706void Browser::RequestMediaAccessPermission( 1707 content::WebContents* web_contents, 1708 const content::MediaStreamRequest& request, 1709 const content::MediaResponseCallback& callback) { 1710 ::RequestMediaAccessPermission(web_contents, profile_, request, callback); 1711} 1712 1713bool Browser::RequestPpapiBrokerPermission( 1714 WebContents* web_contents, 1715 const GURL& url, 1716 const base::FilePath& plugin_path, 1717 const base::Callback<void(bool)>& callback) { 1718 PepperBrokerInfoBarDelegate::Create(web_contents, url, plugin_path, callback); 1719 return true; 1720} 1721 1722gfx::Size Browser::GetSizeForNewRenderView(WebContents* web_contents) const { 1723 // When navigating away from NTP with unpinned bookmark bar, the bookmark bar 1724 // would disappear on non-NTP pages, resulting in a bigger size for the new 1725 // render view. 1726 gfx::Size size = web_contents->GetContainerBounds().size(); 1727 // Don't change render view size if bookmark bar is currently not detached, 1728 // or there's no pending entry, or navigating to a NTP page. 1729 if (size.IsEmpty() || bookmark_bar_state_ != BookmarkBar::DETACHED) 1730 return size; 1731 const NavigationEntry* pending_entry = 1732 web_contents->GetController().GetPendingEntry(); 1733 if (pending_entry && 1734 !chrome::IsNTPURL(pending_entry->GetVirtualURL(), profile_)) { 1735 size.Enlarge( 1736 0, window()->GetRenderViewHeightInsetWithDetachedBookmarkBar()); 1737 } 1738 return size; 1739} 1740 1741/////////////////////////////////////////////////////////////////////////////// 1742// Browser, CoreTabHelperDelegate implementation: 1743 1744void Browser::SwapTabContents(content::WebContents* old_contents, 1745 content::WebContents* new_contents, 1746 bool did_start_load, 1747 bool did_finish_load) { 1748 int index = tab_strip_model_->GetIndexOfWebContents(old_contents); 1749 DCHECK_NE(TabStripModel::kNoTab, index); 1750 tab_strip_model_->ReplaceWebContentsAt(index, new_contents); 1751} 1752 1753bool Browser::CanReloadContents(content::WebContents* web_contents) const { 1754 return chrome::CanReload(this); 1755} 1756 1757bool Browser::CanSaveContents(content::WebContents* web_contents) const { 1758 return chrome::CanSavePage(this); 1759} 1760 1761/////////////////////////////////////////////////////////////////////////////// 1762// Browser, SearchEngineTabHelperDelegate implementation: 1763 1764void Browser::ConfirmAddSearchProvider(TemplateURL* template_url, 1765 Profile* profile) { 1766 window()->ConfirmAddSearchProvider(template_url, profile); 1767} 1768 1769/////////////////////////////////////////////////////////////////////////////// 1770// Browser, SearchTabHelperDelegate implementation: 1771 1772void Browser::NavigateOnThumbnailClick(const GURL& url, 1773 WindowOpenDisposition disposition, 1774 content::WebContents* source_contents) { 1775 DCHECK(source_contents); 1776 // We're guaranteed that AUTO_BOOKMARK is the right transition since this only 1777 // gets called to handle clicks in the new tab page (to navigate to most 1778 // visited item URLs) and in the search results page (to navigate to 1779 // privileged destinations (e.g. chrome://URLs)). 1780 // 1781 // TODO(kmadhusu): Page transitions to privileged destinations should be 1782 // marked as "LINK" instead of "AUTO_BOOKMARK"? 1783 chrome::NavigateParams params(this, url, 1784 content::PAGE_TRANSITION_AUTO_BOOKMARK); 1785 params.referrer = content::Referrer(); 1786 params.source_contents = source_contents; 1787 params.disposition = disposition; 1788 params.is_renderer_initiated = false; 1789 params.initiating_profile = profile_; 1790 chrome::Navigate(¶ms); 1791} 1792 1793void Browser::OnWebContentsInstantSupportDisabled( 1794 const content::WebContents* web_contents) { 1795 DCHECK(web_contents); 1796 if (tab_strip_model_->GetActiveWebContents() == web_contents) 1797 UpdateToolbar(false); 1798} 1799 1800OmniboxView* Browser::GetOmniboxView() { 1801 return window_->GetLocationBar()->GetOmniboxView(); 1802} 1803 1804std::set<std::string> Browser::GetOpenUrls() { 1805 history::TopSites* top_sites = profile_->GetTopSites(); 1806 if (!top_sites) // NULL for Incognito profiles. 1807 return std::set<std::string>(); 1808 1809 std::set<std::string> open_urls; 1810 chrome::GetOpenUrls(*tab_strip_model_, *top_sites, &open_urls); 1811 return open_urls; 1812} 1813 1814/////////////////////////////////////////////////////////////////////////////// 1815// Browser, web_modal::WebContentsModalDialogManagerDelegate implementation: 1816 1817void Browser::SetWebContentsBlocked(content::WebContents* web_contents, 1818 bool blocked) { 1819 int index = tab_strip_model_->GetIndexOfWebContents(web_contents); 1820 if (index == TabStripModel::kNoTab) { 1821 NOTREACHED(); 1822 return; 1823 } 1824 tab_strip_model_->SetTabBlocked(index, blocked); 1825 if (!blocked && tab_strip_model_->GetActiveWebContents() == web_contents) 1826 web_contents->Focus(); 1827} 1828 1829web_modal::WebContentsModalDialogHost* 1830Browser::GetWebContentsModalDialogHost() { 1831 return window_->GetWebContentsModalDialogHost(); 1832} 1833 1834/////////////////////////////////////////////////////////////////////////////// 1835// Browser, BookmarkTabHelperDelegate implementation: 1836 1837void Browser::URLStarredChanged(content::WebContents* web_contents, 1838 bool starred) { 1839 if (web_contents == tab_strip_model_->GetActiveWebContents()) 1840 window_->SetStarredState(starred); 1841} 1842 1843/////////////////////////////////////////////////////////////////////////////// 1844// Browser, ZoomObserver implementation: 1845 1846void Browser::OnZoomChanged(content::WebContents* source, 1847 bool can_show_bubble) { 1848 if (source == tab_strip_model_->GetActiveWebContents()) { 1849 // Only show the zoom bubble for zoom changes in the active window. 1850 window_->ZoomChangedForActiveTab(can_show_bubble && window_->IsActive() && 1851 !is_devtools()); 1852 } 1853} 1854 1855/////////////////////////////////////////////////////////////////////////////// 1856// Browser, ui::SelectFileDialog::Listener implementation: 1857 1858void Browser::FileSelected(const base::FilePath& path, int index, 1859 void* params) { 1860 FileSelectedWithExtraInfo(ui::SelectedFileInfo(path, path), index, params); 1861} 1862 1863void Browser::FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file_info, 1864 int index, 1865 void* params) { 1866 profile_->set_last_selected_directory(file_info.file_path.DirName()); 1867 1868 GURL url = net::FilePathToFileURL(file_info.local_path); 1869 1870#if defined(OS_CHROMEOS) 1871 drive::util::MaybeSetDriveURL(profile_, file_info.file_path, &url); 1872#endif 1873 1874 if (url.is_empty()) 1875 return; 1876 1877 OpenURL(OpenURLParams( 1878 url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false)); 1879} 1880 1881/////////////////////////////////////////////////////////////////////////////// 1882// Browser, content::NotificationObserver implementation: 1883 1884void Browser::Observe(int type, 1885 const content::NotificationSource& source, 1886 const content::NotificationDetails& details) { 1887 switch (type) { 1888 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: { 1889 chrome::UpdateCommandEnabled( 1890 this, 1891 IDC_BOOKMARK_PAGE, 1892 !chrome::ShouldRemoveBookmarkThisPageUI(profile_)); 1893 chrome::UpdateCommandEnabled( 1894 this, 1895 IDC_BOOKMARK_ALL_TABS, 1896 !chrome::ShouldRemoveBookmarkOpenPagesUI(profile_)); 1897 1898 if (window()->GetLocationBar()) 1899 window()->GetLocationBar()->UpdatePageActions(); 1900 1901 const extensions::UnloadedExtensionInfo* extension_info = 1902 content::Details<extensions::UnloadedExtensionInfo>(details).ptr(); 1903 1904 // Close any tabs from the unloaded extension, unless it's terminated, 1905 // in which case let the sad tabs remain. 1906 if (extension_info->reason != 1907 extensions::UnloadedExtensionInfo::REASON_TERMINATE) { 1908 const Extension* extension = extension_info->extension; 1909 // Iterate backwards as we may remove items while iterating. 1910 for (int i = tab_strip_model_->count() - 1; i >= 0; --i) { 1911 WebContents* web_contents = tab_strip_model_->GetWebContentsAt(i); 1912 // Two cases are handled here: 1913 // - The scheme check is for when an extension page is loaded in a 1914 // tab, e.g. chrome-extension://id/page.html. 1915 // - The extension_app check is for apps, which can have non-extension 1916 // schemes, e.g. https://mail.google.com if you have the Gmail app 1917 // installed. 1918 if ((web_contents->GetURL().SchemeIs(extensions::kExtensionScheme) && 1919 web_contents->GetURL().host() == extension->id()) || 1920 (extensions::TabHelper::FromWebContents( 1921 web_contents)->extension_app() == extension)) { 1922 tab_strip_model_->CloseWebContentsAt(i, TabStripModel::CLOSE_NONE); 1923 } 1924 } 1925 } 1926 break; 1927 } 1928 1929 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: { 1930 Profile* profile = content::Source<Profile>(source).ptr(); 1931 if (profile_->IsSameProfile(profile) && window()->GetLocationBar()) 1932 window()->GetLocationBar()->InvalidatePageActions(); 1933 break; 1934 } 1935 1936 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: 1937 chrome::UpdateCommandEnabled( 1938 this, 1939 IDC_BOOKMARK_PAGE, 1940 !chrome::ShouldRemoveBookmarkThisPageUI(profile_)); 1941 chrome::UpdateCommandEnabled( 1942 this, 1943 IDC_BOOKMARK_ALL_TABS, 1944 !chrome::ShouldRemoveBookmarkOpenPagesUI(profile_)); 1945 // fallthrough 1946 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED: 1947 // During window creation on Windows we may end up calling into 1948 // SHAppBarMessage, which internally spawns a nested message loop. This 1949 // makes it possible for us to end up here before window creation has 1950 // completed, at which point window_ is NULL. See 94752 for details. 1951 if (window() && window()->GetLocationBar()) 1952 window()->GetLocationBar()->UpdatePageActions(); 1953 break; 1954 1955#if defined(ENABLE_THEMES) 1956 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: 1957 window()->UserChangedTheme(); 1958 break; 1959#endif 1960 1961 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: { 1962 WebContents* web_contents = content::Source<WebContents>(source).ptr(); 1963 if (web_contents == tab_strip_model_->GetActiveWebContents()) { 1964 LocationBar* location_bar = window()->GetLocationBar(); 1965 if (location_bar) 1966 location_bar->UpdateContentSettingsIcons(); 1967 } 1968 break; 1969 } 1970 1971 default: 1972 NOTREACHED() << "Got a notification we didn't register for."; 1973 } 1974} 1975 1976/////////////////////////////////////////////////////////////////////////////// 1977// Browser, Command and state updating (private): 1978 1979void Browser::OnDevToolsDisabledChanged() { 1980 if (profile_->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled)) 1981 content::DevToolsManager::GetInstance()->CloseAllClientHosts(); 1982} 1983 1984/////////////////////////////////////////////////////////////////////////////// 1985// Browser, UI update coalescing and handling (private): 1986 1987void Browser::UpdateToolbar(bool should_restore_state) { 1988 window_->UpdateToolbar(should_restore_state ? 1989 tab_strip_model_->GetActiveWebContents() : NULL); 1990} 1991 1992void Browser::ScheduleUIUpdate(const WebContents* source, 1993 unsigned changed_flags) { 1994 DCHECK(source); 1995 int index = tab_strip_model_->GetIndexOfWebContents(source); 1996 DCHECK_NE(TabStripModel::kNoTab, index); 1997 1998 // Do some synchronous updates. 1999 if (changed_flags & content::INVALIDATE_TYPE_URL && 2000 source == tab_strip_model_->GetActiveWebContents()) { 2001 // Only update the URL for the current tab. Note that we do not update 2002 // the navigation commands since those would have already been updated 2003 // synchronously by NavigationStateChanged. 2004 UpdateToolbar(false); 2005 changed_flags &= ~content::INVALIDATE_TYPE_URL; 2006 } 2007 if (changed_flags & content::INVALIDATE_TYPE_LOAD) { 2008 // Update the loading state synchronously. This is so the throbber will 2009 // immediately start/stop, which gives a more snappy feel. We want to do 2010 // this for any tab so they start & stop quickly. 2011 tab_strip_model_->UpdateWebContentsStateAt( 2012 tab_strip_model_->GetIndexOfWebContents(source), 2013 TabStripModelObserver::LOADING_ONLY); 2014 // The status bubble needs to be updated during INVALIDATE_TYPE_LOAD too, 2015 // but we do that asynchronously by not stripping INVALIDATE_TYPE_LOAD from 2016 // changed_flags. 2017 } 2018 2019 if (changed_flags & content::INVALIDATE_TYPE_TITLE && !source->IsLoading()) { 2020 // To correctly calculate whether the title changed while not loading 2021 // we need to process the update synchronously. This state only matters for 2022 // the TabStripModel, so we notify the TabStripModel now and notify others 2023 // asynchronously. 2024 tab_strip_model_->UpdateWebContentsStateAt( 2025 tab_strip_model_->GetIndexOfWebContents(source), 2026 TabStripModelObserver::TITLE_NOT_LOADING); 2027 } 2028 2029 // If the only updates were synchronously handled above, we're done. 2030 if (changed_flags == 0) 2031 return; 2032 2033 // Save the dirty bits. 2034 scheduled_updates_[source] |= changed_flags; 2035 2036 if (!chrome_updater_factory_.HasWeakPtrs()) { 2037 // No task currently scheduled, start another. 2038 base::MessageLoop::current()->PostDelayedTask( 2039 FROM_HERE, 2040 base::Bind(&Browser::ProcessPendingUIUpdates, 2041 chrome_updater_factory_.GetWeakPtr()), 2042 base::TimeDelta::FromMilliseconds(kUIUpdateCoalescingTimeMS)); 2043 } 2044} 2045 2046void Browser::ProcessPendingUIUpdates() { 2047#ifndef NDEBUG 2048 // Validate that all tabs we have pending updates for exist. This is scary 2049 // because the pending list must be kept in sync with any detached or 2050 // deleted tabs. 2051 for (UpdateMap::const_iterator i = scheduled_updates_.begin(); 2052 i != scheduled_updates_.end(); ++i) { 2053 bool found = false; 2054 for (int tab = 0; tab < tab_strip_model_->count(); tab++) { 2055 if (tab_strip_model_->GetWebContentsAt(tab) == i->first) { 2056 found = true; 2057 break; 2058 } 2059 } 2060 DCHECK(found); 2061 } 2062#endif 2063 2064 chrome_updater_factory_.InvalidateWeakPtrs(); 2065 2066 for (UpdateMap::const_iterator i = scheduled_updates_.begin(); 2067 i != scheduled_updates_.end(); ++i) { 2068 // Do not dereference |contents|, it may be out-of-date! 2069 const WebContents* contents = i->first; 2070 unsigned flags = i->second; 2071 2072 if (contents == tab_strip_model_->GetActiveWebContents()) { 2073 // Updates that only matter when the tab is selected go here. 2074 2075 if (flags & content::INVALIDATE_TYPE_PAGE_ACTIONS) { 2076 LocationBar* location_bar = window()->GetLocationBar(); 2077 if (location_bar) 2078 location_bar->UpdatePageActions(); 2079 } 2080 // Updating the URL happens synchronously in ScheduleUIUpdate. 2081 if (flags & content::INVALIDATE_TYPE_LOAD && GetStatusBubble()) { 2082 GetStatusBubble()->SetStatus(CoreTabHelper::FromWebContents( 2083 tab_strip_model_->GetActiveWebContents())->GetStatusText()); 2084 } 2085 2086 if (flags & (content::INVALIDATE_TYPE_TAB | 2087 content::INVALIDATE_TYPE_TITLE)) { 2088 window_->UpdateTitleBar(); 2089 } 2090 } 2091 2092 // Updates that don't depend upon the selected state go here. 2093 if (flags & 2094 (content::INVALIDATE_TYPE_TAB | content::INVALIDATE_TYPE_TITLE)) { 2095 tab_strip_model_->UpdateWebContentsStateAt( 2096 tab_strip_model_->GetIndexOfWebContents(contents), 2097 TabStripModelObserver::ALL); 2098 } 2099 2100 // Update the bookmark bar. It may happen that the tab is crashed, and if 2101 // so, the bookmark bar should be hidden. 2102 if (flags & content::INVALIDATE_TYPE_TAB) 2103 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE); 2104 2105 // We don't need to process INVALIDATE_STATE, since that's not visible. 2106 } 2107 2108 scheduled_updates_.clear(); 2109} 2110 2111void Browser::RemoveScheduledUpdatesFor(WebContents* contents) { 2112 if (!contents) 2113 return; 2114 2115 UpdateMap::iterator i = scheduled_updates_.find(contents); 2116 if (i != scheduled_updates_.end()) 2117 scheduled_updates_.erase(i); 2118} 2119 2120/////////////////////////////////////////////////////////////////////////////// 2121// Browser, Getters for UI (private): 2122 2123StatusBubble* Browser::GetStatusBubble() { 2124 // In kiosk and exclusive app mode, we want to always hide the status bubble. 2125 if (chrome::IsRunningInAppMode()) 2126 return NULL; 2127 2128 return window_ ? window_->GetStatusBubble() : NULL; 2129} 2130 2131/////////////////////////////////////////////////////////////////////////////// 2132// Browser, Session restore functions (private): 2133 2134void Browser::SyncHistoryWithTabs(int index) { 2135 SessionService* session_service = 2136 SessionServiceFactory::GetForProfileIfExisting(profile()); 2137 if (session_service) { 2138 for (int i = index; i < tab_strip_model_->count(); ++i) { 2139 WebContents* web_contents = tab_strip_model_->GetWebContentsAt(i); 2140 if (web_contents) { 2141 SessionTabHelper* session_tab_helper = 2142 SessionTabHelper::FromWebContents(web_contents); 2143 session_service->SetTabIndexInWindow( 2144 session_id(), session_tab_helper->session_id(), i); 2145 session_service->SetPinnedState( 2146 session_id(), 2147 session_tab_helper->session_id(), 2148 tab_strip_model_->IsTabPinned(i)); 2149 } 2150 } 2151 } 2152} 2153 2154/////////////////////////////////////////////////////////////////////////////// 2155// Browser, In-progress download termination handling (private): 2156 2157bool Browser::CanCloseWithInProgressDownloads() { 2158 // If we've prompted, we need to hear from the user before we 2159 // can close. 2160 if (cancel_download_confirmation_state_ != NOT_PROMPTED) 2161 return cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE; 2162 2163 int num_downloads_blocking; 2164 Browser::DownloadClosePreventionType dialog_type = 2165 OkToCloseWithInProgressDownloads(&num_downloads_blocking); 2166 if (dialog_type == DOWNLOAD_CLOSE_OK) 2167 return true; 2168 2169 // Closing this window will kill some downloads; prompt to make sure 2170 // that's ok. 2171 cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE; 2172 window_->ConfirmBrowserCloseWithPendingDownloads( 2173 num_downloads_blocking, 2174 dialog_type, 2175 false, 2176 base::Bind(&Browser::InProgressDownloadResponse, 2177 weak_factory_.GetWeakPtr())); 2178 2179 // Return false so the browser does not close. We'll close if the user 2180 // confirms in the dialog. 2181 return false; 2182} 2183 2184/////////////////////////////////////////////////////////////////////////////// 2185// Browser, Assorted utility functions (private): 2186 2187void Browser::SetAsDelegate(WebContents* web_contents, Browser* delegate) { 2188 // WebContents... 2189 web_contents->SetDelegate(delegate); 2190 2191 // ...and all the helpers. 2192 BookmarkTabHelper::FromWebContents(web_contents)->set_delegate(delegate); 2193 WebContentsModalDialogManager::FromWebContents(web_contents)-> 2194 SetDelegate(delegate); 2195 CoreTabHelper::FromWebContents(web_contents)->set_delegate(delegate); 2196 SearchEngineTabHelper::FromWebContents(web_contents)->set_delegate(delegate); 2197 SearchTabHelper::FromWebContents(web_contents)->set_delegate(delegate); 2198 ZoomController::FromWebContents(web_contents)->set_observer(delegate); 2199 TranslateTabHelper* translate_tab_helper = 2200 TranslateTabHelper::FromWebContents(web_contents); 2201 translate_tab_helper->translate_driver().set_observer( 2202 delegate ? delegate->translate_driver_observer_.get() : NULL); 2203} 2204 2205void Browser::CloseFrame() { 2206 window_->Close(); 2207} 2208 2209void Browser::TabDetachedAtImpl(content::WebContents* contents, 2210 int index, 2211 DetachType type) { 2212 if (type == DETACH_TYPE_DETACH) { 2213 // Save the current location bar state, but only if the tab being detached 2214 // is the selected tab. Because saving state can conditionally revert the 2215 // location bar, saving the current tab's location bar state to a 2216 // non-selected tab can corrupt both tabs. 2217 if (contents == tab_strip_model_->GetActiveWebContents()) { 2218 LocationBar* location_bar = window()->GetLocationBar(); 2219 if (location_bar) 2220 location_bar->SaveStateToContents(contents); 2221 } 2222 2223 if (!tab_strip_model_->closing_all()) 2224 SyncHistoryWithTabs(0); 2225 } 2226 2227 SetAsDelegate(contents, NULL); 2228 RemoveScheduledUpdatesFor(contents); 2229 2230 if (find_bar_controller_.get() && index == tab_strip_model_->active_index()) { 2231 find_bar_controller_->ChangeWebContents(NULL); 2232 } 2233 2234 // Stop observing search model changes for this tab. 2235 search_delegate_->OnTabDetached(contents); 2236 2237 for (size_t i = 0; i < interstitial_observers_.size(); i++) { 2238 if (interstitial_observers_[i]->web_contents() != contents) 2239 continue; 2240 2241 delete interstitial_observers_[i]; 2242 interstitial_observers_.erase(interstitial_observers_.begin() + i); 2243 return; 2244 } 2245} 2246 2247bool Browser::ShouldShowLocationBar() const { 2248 // Tabbed browser always show a location bar. 2249 if (is_type_tabbed()) 2250 return true; 2251 2252 if (is_app()) { 2253 if (CommandLine::ForCurrentProcess()->HasSwitch( 2254 switches::kEnableStreamlinedHostedApps)) { 2255 // If kEnableStreamlinedHostedApps is true, show the location bar for 2256 // bookmark apps. 2257 ExtensionService* service = 2258 extensions::ExtensionSystem::Get(profile_)->extension_service(); 2259 const extensions::Extension* extension = 2260 service ? service->GetInstalledExtension( 2261 web_app::GetExtensionIdFromApplicationName(app_name())) 2262 : NULL; 2263 return (!extension || extension->from_bookmark()) && 2264 app_name() != DevToolsWindow::kDevToolsApp; 2265 } else { 2266 return false; 2267 } 2268 } 2269 2270 // Trusted app windows and system windows never show a location bar. 2271 return !is_trusted_source(); 2272} 2273 2274bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, 2275 bool check_fullscreen) const { 2276 bool hide_ui_for_fullscreen = check_fullscreen && ShouldHideUIForFullscreen(); 2277 2278 unsigned int features = FEATURE_INFOBAR | FEATURE_DOWNLOADSHELF; 2279 2280 if (is_type_tabbed()) 2281 features |= FEATURE_BOOKMARKBAR; 2282 2283 if (!hide_ui_for_fullscreen) { 2284 if (!is_type_tabbed()) 2285 features |= FEATURE_TITLEBAR; 2286 2287 if (is_type_tabbed()) 2288 features |= FEATURE_TABSTRIP; 2289 2290 if (is_type_tabbed()) 2291 features |= FEATURE_TOOLBAR; 2292 2293 if (ShouldShowLocationBar()) 2294 features |= FEATURE_LOCATIONBAR; 2295 } 2296 return !!(features & feature); 2297} 2298 2299void Browser::UpdateBookmarkBarState(BookmarkBarStateChangeReason reason) { 2300 BookmarkBar::State state; 2301 // The bookmark bar is always hidden for Guest Sessions and in fullscreen 2302 // mode, unless on the new tab page. 2303 if (profile_->IsGuestSession()) { 2304 state = BookmarkBar::HIDDEN; 2305 } else if (browser_defaults::bookmarks_enabled && 2306 profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) && 2307 !ShouldHideUIForFullscreen()) { 2308 state = BookmarkBar::SHOW; 2309 } else { 2310 WebContents* web_contents = tab_strip_model_->GetActiveWebContents(); 2311 BookmarkTabHelper* bookmark_tab_helper = 2312 web_contents ? BookmarkTabHelper::FromWebContents(web_contents) : NULL; 2313 if (bookmark_tab_helper && bookmark_tab_helper->ShouldShowBookmarkBar()) 2314 state = BookmarkBar::DETACHED; 2315 else 2316 state = BookmarkBar::HIDDEN; 2317 } 2318 2319 if (state == bookmark_bar_state_) 2320 return; 2321 2322 bookmark_bar_state_ = state; 2323 2324 if (!window_) 2325 return; // This is called from the constructor when window_ is NULL. 2326 2327 if (reason == BOOKMARK_BAR_STATE_CHANGE_TAB_SWITCH) { 2328 // Don't notify BrowserWindow on a tab switch as at the time this is invoked 2329 // BrowserWindow hasn't yet switched tabs. The BrowserWindow implementations 2330 // end up querying state once they process the tab switch. 2331 return; 2332 } 2333 2334 bool shouldAnimate = reason == BOOKMARK_BAR_STATE_CHANGE_PREF_CHANGE; 2335 window_->BookmarkBarStateChanged(shouldAnimate ? 2336 BookmarkBar::ANIMATE_STATE_CHANGE : 2337 BookmarkBar::DONT_ANIMATE_STATE_CHANGE); 2338} 2339 2340bool Browser::ShouldHideUIForFullscreen() const { 2341 // Windows and GTK remove the top controls in fullscreen, but Mac and Ash 2342 // keep the controls in a slide-down panel. 2343 return window_ && window_->ShouldHideUIForFullscreen(); 2344} 2345 2346bool Browser::MaybeCreateBackgroundContents( 2347 int route_id, 2348 WebContents* opener_web_contents, 2349 const base::string16& frame_name, 2350 const GURL& target_url, 2351 const std::string& partition_id, 2352 content::SessionStorageNamespace* session_storage_namespace) { 2353 GURL opener_url = opener_web_contents->GetURL(); 2354 ExtensionService* extensions_service = 2355 extensions::ExtensionSystem::Get(profile_)->extension_service(); 2356 2357 if (!opener_url.is_valid() || 2358 frame_name.empty() || 2359 !extensions_service || 2360 !extensions_service->is_ready()) 2361 return false; 2362 2363 // Only hosted apps have web extents, so this ensures that only hosted apps 2364 // can create BackgroundContents. We don't have to check for background 2365 // permission as that is checked in RenderMessageFilter when the CreateWindow 2366 // message is processed. 2367 const Extension* extension = 2368 extensions_service->extensions()->GetHostedAppByURL(opener_url); 2369 if (!extension) 2370 return false; 2371 2372 // No BackgroundContents allowed if BackgroundContentsService doesn't exist. 2373 BackgroundContentsService* service = 2374 BackgroundContentsServiceFactory::GetForProfile(profile_); 2375 if (!service) 2376 return false; 2377 2378 // Ensure that we're trying to open this from the extension's process. 2379 SiteInstance* opener_site_instance = opener_web_contents->GetSiteInstance(); 2380 extensions::ProcessMap* process_map = extensions::ProcessMap::Get(profile_); 2381 if (!opener_site_instance->GetProcess() || 2382 !process_map->Contains( 2383 extension->id(), opener_site_instance->GetProcess()->GetID())) { 2384 return false; 2385 } 2386 2387 // Only allow a single background contents per app. 2388 bool allow_js_access = extensions::BackgroundInfo::AllowJSAccess(extension); 2389 BackgroundContents* existing = 2390 service->GetAppBackgroundContents(base::ASCIIToUTF16(extension->id())); 2391 if (existing) { 2392 // For non-scriptable background contents, ignore the request altogether, 2393 // (returning true, so that a regular WebContents isn't created either). 2394 if (!allow_js_access) 2395 return true; 2396 // For scriptable background pages, if one already exists, close it (even 2397 // if it was specified in the manifest). 2398 delete existing; 2399 } 2400 2401 // If script access is not allowed, create the the background contents in a 2402 // new SiteInstance, so that a separate process is used. 2403 scoped_refptr<content::SiteInstance> site_instance = 2404 allow_js_access ? 2405 opener_site_instance : 2406 content::SiteInstance::Create(opener_web_contents->GetBrowserContext()); 2407 2408 // Passed all the checks, so this should be created as a BackgroundContents. 2409 BackgroundContents* contents = 2410 service->CreateBackgroundContents(site_instance.get(), 2411 route_id, 2412 profile_, 2413 frame_name, 2414 base::ASCIIToUTF16(extension->id()), 2415 partition_id, 2416 session_storage_namespace); 2417 2418 // When a separate process is used, the original renderer cannot access the 2419 // new window later, thus we need to navigate the window now. 2420 if (contents && !allow_js_access) { 2421 contents->web_contents()->GetController().LoadURL( 2422 target_url, 2423 content::Referrer(), 2424 content::PAGE_TRANSITION_LINK, 2425 std::string()); // No extra headers. 2426 } 2427 2428 return contents != NULL; 2429} 2430