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