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_commands.h" 6 7 #include "base/command_line.h" 8 #include "base/metrics/histogram.h" 9 #include "base/prefs/pref_service.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/app/chrome_command_ids.h" 12 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 13 #include "chrome/browser/browser_process.h" 14 #include "chrome/browser/browsing_data/browsing_data_helper.h" 15 #include "chrome/browser/browsing_data/browsing_data_remover.h" 16 #include "chrome/browser/chrome_notification_types.h" 17 #include "chrome/browser/chrome_page_zoom.h" 18 #include "chrome/browser/devtools/devtools_window.h" 19 #include "chrome/browser/dom_distiller/tab_utils.h" 20 #include "chrome/browser/extensions/api/commands/command_service.h" 21 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 22 #include "chrome/browser/extensions/tab_helper.h" 23 #include "chrome/browser/favicon/favicon_tab_helper.h" 24 #include "chrome/browser/lifetime/application_lifetime.h" 25 #include "chrome/browser/platform_util.h" 26 #include "chrome/browser/prefs/incognito_mode_prefs.h" 27 #include "chrome/browser/profiles/profile.h" 28 #include "chrome/browser/rlz/rlz.h" 29 #include "chrome/browser/search/search.h" 30 #include "chrome/browser/sessions/session_service_factory.h" 31 #include "chrome/browser/sessions/tab_restore_service.h" 32 #include "chrome/browser/sessions/tab_restore_service_delegate.h" 33 #include "chrome/browser/sessions/tab_restore_service_factory.h" 34 #include "chrome/browser/signin/signin_header_helper.h" 35 #include "chrome/browser/translate/chrome_translate_client.h" 36 #include "chrome/browser/ui/accelerator_utils.h" 37 #include "chrome/browser/ui/bookmarks/bookmark_utils.h" 38 #include "chrome/browser/ui/browser.h" 39 #include "chrome/browser/ui/browser_command_controller.h" 40 #include "chrome/browser/ui/browser_dialogs.h" 41 #include "chrome/browser/ui/browser_instant_controller.h" 42 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h" 43 #include "chrome/browser/ui/browser_tabstrip.h" 44 #include "chrome/browser/ui/browser_window.h" 45 #include "chrome/browser/ui/chrome_pages.h" 46 #include "chrome/browser/ui/find_bar/find_bar.h" 47 #include "chrome/browser/ui/find_bar/find_bar_controller.h" 48 #include "chrome/browser/ui/find_bar/find_tab_helper.h" 49 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h" 50 #include "chrome/browser/ui/location_bar/location_bar.h" 51 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" 52 #include "chrome/browser/ui/search/search_tab_helper.h" 53 #include "chrome/browser/ui/status_bubble.h" 54 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" 55 #include "chrome/browser/ui/tabs/tab_strip_model.h" 56 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h" 57 #include "chrome/browser/ui/zoom/zoom_controller.h" 58 #include "chrome/browser/upgrade_detector.h" 59 #include "chrome/browser/web_applications/web_app.h" 60 #include "chrome/common/chrome_switches.h" 61 #include "chrome/common/chrome_version_info.h" 62 #include "chrome/common/content_restriction.h" 63 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 64 #include "chrome/common/pref_names.h" 65 #include "components/bookmarks/browser/bookmark_model.h" 66 #include "components/bookmarks/browser/bookmark_utils.h" 67 #include "components/google/core/browser/google_util.h" 68 #include "components/translate/core/browser/language_state.h" 69 #include "components/web_modal/popup_manager.h" 70 #include "content/public/browser/devtools_agent_host.h" 71 #include "content/public/browser/navigation_controller.h" 72 #include "content/public/browser/navigation_entry.h" 73 #include "content/public/browser/notification_service.h" 74 #include "content/public/browser/page_navigator.h" 75 #include "content/public/browser/render_view_host.h" 76 #include "content/public/browser/render_widget_host_view.h" 77 #include "content/public/browser/user_metrics.h" 78 #include "content/public/browser/web_contents.h" 79 #include "content/public/common/renderer_preferences.h" 80 #include "content/public/common/url_constants.h" 81 #include "content/public/common/url_utils.h" 82 #include "content/public/common/user_agent.h" 83 #include "net/base/escape.h" 84 #include "ui/events/keycodes/keyboard_codes.h" 85 86 #if defined(OS_WIN) 87 #include "chrome/browser/ui/metro_pin_tab_helper_win.h" 88 #endif 89 90 #if defined(ENABLE_EXTENSIONS) 91 #include "extensions/browser/extension_registry.h" 92 #include "extensions/browser/extension_system.h" 93 #include "extensions/common/extension.h" 94 #include "extensions/common/extension_set.h" 95 #endif 96 97 #if defined(ENABLE_PRINTING) 98 #if defined(ENABLE_FULL_PRINTING) 99 #include "chrome/browser/printing/print_preview_dialog_controller.h" 100 #include "chrome/browser/printing/print_view_manager.h" 101 #else 102 #include "chrome/browser/printing/print_view_manager_basic.h" 103 #endif // defined(ENABLE_FULL_PRINTING) 104 #endif // defined(ENABLE_PRINTING) 105 106 namespace { 107 const char kOsOverrideForTabletSite[] = "Linux; Android 4.0.3"; 108 } 109 110 using base::UserMetricsAction; 111 using content::NavigationController; 112 using content::NavigationEntry; 113 using content::OpenURLParams; 114 using content::Referrer; 115 using content::SSLStatus; 116 using content::WebContents; 117 118 namespace chrome { 119 namespace { 120 121 bool CanBookmarkCurrentPageInternal(const Browser* browser, 122 bool check_remove_bookmark_ui) { 123 BookmarkModel* model = 124 BookmarkModelFactory::GetForProfile(browser->profile()); 125 return browser_defaults::bookmarks_enabled && 126 browser->profile()->GetPrefs()->GetBoolean( 127 bookmarks::prefs::kEditBookmarksEnabled) && 128 model && model->loaded() && browser->is_type_tabbed() && 129 (!check_remove_bookmark_ui || 130 !chrome::ShouldRemoveBookmarkThisPageUI(browser->profile())); 131 } 132 133 bool GetBookmarkOverrideCommand( 134 Profile* profile, 135 const extensions::Extension** extension, 136 extensions::Command* command, 137 extensions::CommandService::ExtensionCommandType* command_type) { 138 #if defined(ENABLE_EXTENSIONS) 139 DCHECK(extension); 140 DCHECK(command); 141 DCHECK(command_type); 142 143 ui::Accelerator bookmark_page_accelerator = 144 chrome::GetPrimaryChromeAcceleratorForCommandId(IDC_BOOKMARK_PAGE); 145 if (bookmark_page_accelerator.key_code() == ui::VKEY_UNKNOWN) 146 return false; 147 148 extensions::CommandService* command_service = 149 extensions::CommandService::Get(profile); 150 const extensions::ExtensionSet& extension_set = 151 extensions::ExtensionRegistry::Get(profile)->enabled_extensions(); 152 for (extensions::ExtensionSet::const_iterator i = extension_set.begin(); 153 i != extension_set.end(); 154 ++i) { 155 extensions::Command prospective_command; 156 extensions::CommandService::ExtensionCommandType prospective_command_type; 157 if (command_service->GetBoundExtensionCommand((*i)->id(), 158 bookmark_page_accelerator, 159 &prospective_command, 160 &prospective_command_type)) { 161 *extension = i->get(); 162 *command = prospective_command; 163 *command_type = prospective_command_type; 164 return true; 165 } 166 } 167 #endif 168 169 return false; 170 } 171 172 void BookmarkCurrentPageInternal(Browser* browser) { 173 content::RecordAction(UserMetricsAction("Star")); 174 175 BookmarkModel* model = 176 BookmarkModelFactory::GetForProfile(browser->profile()); 177 if (!model || !model->loaded()) 178 return; // Ignore requests until bookmarks are loaded. 179 180 GURL url; 181 base::string16 title; 182 WebContents* web_contents = 183 browser->tab_strip_model()->GetActiveWebContents(); 184 GetURLAndTitleToBookmark(web_contents, &url, &title); 185 bool is_bookmarked_by_any = model->IsBookmarked(url); 186 if (!is_bookmarked_by_any && 187 web_contents->GetBrowserContext()->IsOffTheRecord()) { 188 // If we're incognito the favicon may not have been saved. Save it now 189 // so that bookmarks have an icon for the page. 190 FaviconTabHelper::FromWebContents(web_contents)->SaveFavicon(); 191 } 192 bool was_bookmarked_by_user = bookmarks::IsBookmarkedByUser(model, url); 193 bookmarks::AddIfNotBookmarked(model, url, title); 194 bool is_bookmarked_by_user = bookmarks::IsBookmarkedByUser(model, url); 195 // Make sure the model actually added a bookmark before showing the star. A 196 // bookmark isn't created if the url is invalid. 197 if (browser->window()->IsActive() && is_bookmarked_by_user) { 198 // Only show the bubble if the window is active, otherwise we may get into 199 // weird situations where the bubble is deleted as soon as it is shown. 200 browser->window()->ShowBookmarkBubble(url, was_bookmarked_by_user); 201 } 202 } 203 204 // Based on |disposition|, creates a new tab as necessary, and returns the 205 // appropriate tab to navigate. If that tab is the current tab, reverts the 206 // location bar contents, since all browser-UI-triggered navigations should 207 // revert any omnibox edits in the current tab. 208 WebContents* GetTabAndRevertIfNecessary(Browser* browser, 209 WindowOpenDisposition disposition) { 210 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 211 switch (disposition) { 212 case NEW_FOREGROUND_TAB: 213 case NEW_BACKGROUND_TAB: { 214 WebContents* new_tab = current_tab->Clone(); 215 browser->tab_strip_model()->AddWebContents( 216 new_tab, -1, ui::PAGE_TRANSITION_LINK, 217 (disposition == NEW_FOREGROUND_TAB) ? 218 TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE); 219 return new_tab; 220 } 221 case NEW_WINDOW: { 222 WebContents* new_tab = current_tab->Clone(); 223 Browser* new_browser = new Browser(Browser::CreateParams( 224 browser->profile(), browser->host_desktop_type())); 225 new_browser->tab_strip_model()->AddWebContents( 226 new_tab, -1, ui::PAGE_TRANSITION_LINK, 227 TabStripModel::ADD_ACTIVE); 228 new_browser->window()->Show(); 229 return new_tab; 230 } 231 default: 232 browser->window()->GetLocationBar()->Revert(); 233 return current_tab; 234 } 235 } 236 237 void ReloadInternal(Browser* browser, 238 WindowOpenDisposition disposition, 239 bool ignore_cache) { 240 // As this is caused by a user action, give the focus to the page. 241 // 242 // Also notify RenderViewHostDelegate of the user gesture; this is 243 // normally done in Browser::Navigate, but a reload bypasses Navigate. 244 WebContents* new_tab = GetTabAndRevertIfNecessary(browser, disposition); 245 new_tab->UserGestureDone(); 246 if (!new_tab->FocusLocationBarByDefault()) 247 new_tab->Focus(); 248 if (ignore_cache) 249 new_tab->GetController().ReloadIgnoringCache(true); 250 else 251 new_tab->GetController().Reload(true); 252 } 253 254 bool IsShowingWebContentsModalDialog(Browser* browser) { 255 WebContents* web_contents = 256 browser->tab_strip_model()->GetActiveWebContents(); 257 if (!web_contents) 258 return false; 259 260 // In test code we may not have a popup manager. 261 if (!browser->popup_manager()) 262 return false; 263 264 // TODO(gbillock): This is currently called in production by the CanPrint 265 // method, and may be too restrictive if we allow print preview to overlap. 266 // Re-assess how to queue print preview after we know more about popup 267 // management policy. 268 return browser->popup_manager()->IsWebModalDialogActive(web_contents); 269 } 270 271 bool PrintPreviewShowing(const Browser* browser) { 272 #if defined(ENABLE_FULL_PRINTING) 273 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); 274 printing::PrintPreviewDialogController* controller = 275 printing::PrintPreviewDialogController::GetInstance(); 276 return controller && (controller->GetPrintPreviewForContents(contents) || 277 controller->is_creating_print_preview_dialog()); 278 #else 279 return false; 280 #endif 281 } 282 283 } // namespace 284 285 bool IsCommandEnabled(Browser* browser, int command) { 286 return browser->command_controller()->command_updater()->IsCommandEnabled( 287 command); 288 } 289 290 bool SupportsCommand(Browser* browser, int command) { 291 return browser->command_controller()->command_updater()->SupportsCommand( 292 command); 293 } 294 295 bool ExecuteCommand(Browser* browser, int command) { 296 return browser->command_controller()->command_updater()->ExecuteCommand( 297 command); 298 } 299 300 bool ExecuteCommandWithDisposition(Browser* browser, 301 int command, 302 WindowOpenDisposition disposition) { 303 return browser->command_controller()->command_updater()-> 304 ExecuteCommandWithDisposition(command, disposition); 305 } 306 307 void UpdateCommandEnabled(Browser* browser, int command, bool enabled) { 308 browser->command_controller()->command_updater()->UpdateCommandEnabled( 309 command, enabled); 310 } 311 312 void AddCommandObserver(Browser* browser, 313 int command, 314 CommandObserver* observer) { 315 browser->command_controller()->command_updater()->AddCommandObserver( 316 command, observer); 317 } 318 319 void RemoveCommandObserver(Browser* browser, 320 int command, 321 CommandObserver* observer) { 322 browser->command_controller()->command_updater()->RemoveCommandObserver( 323 command, observer); 324 } 325 326 int GetContentRestrictions(const Browser* browser) { 327 int content_restrictions = 0; 328 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 329 if (current_tab) { 330 CoreTabHelper* core_tab_helper = 331 CoreTabHelper::FromWebContents(current_tab); 332 content_restrictions = core_tab_helper->content_restrictions(); 333 NavigationEntry* last_committed_entry = 334 current_tab->GetController().GetLastCommittedEntry(); 335 if (!content::IsSavableURL( 336 last_committed_entry ? last_committed_entry->GetURL() : GURL()) || 337 current_tab->ShowingInterstitialPage()) 338 content_restrictions |= CONTENT_RESTRICTION_SAVE; 339 if (current_tab->ShowingInterstitialPage()) 340 content_restrictions |= CONTENT_RESTRICTION_PRINT; 341 } 342 return content_restrictions; 343 } 344 345 void NewEmptyWindow(Profile* profile, HostDesktopType desktop_type) { 346 bool incognito = profile->IsOffTheRecord(); 347 PrefService* prefs = profile->GetPrefs(); 348 if (incognito) { 349 if (IncognitoModePrefs::GetAvailability(prefs) == 350 IncognitoModePrefs::DISABLED) { 351 incognito = false; 352 } 353 } else if (profile->IsGuestSession() || 354 (browser_defaults::kAlwaysOpenIncognitoWindow && 355 IncognitoModePrefs::ShouldLaunchIncognito( 356 *CommandLine::ForCurrentProcess(), prefs))) { 357 incognito = true; 358 } 359 360 if (incognito) { 361 content::RecordAction(UserMetricsAction("NewIncognitoWindow")); 362 OpenEmptyWindow(profile->GetOffTheRecordProfile(), desktop_type); 363 } else { 364 content::RecordAction(UserMetricsAction("NewWindow")); 365 SessionService* session_service = 366 SessionServiceFactory::GetForProfileForSessionRestore( 367 profile->GetOriginalProfile()); 368 if (!session_service || 369 !session_service->RestoreIfNecessary(std::vector<GURL>())) { 370 OpenEmptyWindow(profile->GetOriginalProfile(), desktop_type); 371 } 372 } 373 } 374 375 Browser* OpenEmptyWindow(Profile* profile, HostDesktopType desktop_type) { 376 Browser* browser = new Browser( 377 Browser::CreateParams(Browser::TYPE_TABBED, profile, desktop_type)); 378 AddTabAt(browser, GURL(), -1, true); 379 browser->window()->Show(); 380 return browser; 381 } 382 383 void OpenWindowWithRestoredTabs(Profile* profile, 384 HostDesktopType host_desktop_type) { 385 TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile); 386 if (service) 387 service->RestoreMostRecentEntry(NULL, host_desktop_type); 388 } 389 390 void OpenURLOffTheRecord(Profile* profile, 391 const GURL& url, 392 chrome::HostDesktopType desktop_type) { 393 ScopedTabbedBrowserDisplayer displayer(profile->GetOffTheRecordProfile(), 394 desktop_type); 395 AddSelectedTabWithURL(displayer.browser(), url, 396 ui::PAGE_TRANSITION_LINK); 397 } 398 399 bool CanGoBack(const Browser* browser) { 400 return browser->tab_strip_model()->GetActiveWebContents()-> 401 GetController().CanGoBack(); 402 } 403 404 void GoBack(Browser* browser, WindowOpenDisposition disposition) { 405 content::RecordAction(UserMetricsAction("Back")); 406 407 if (CanGoBack(browser)) { 408 WebContents* current_tab = 409 browser->tab_strip_model()->GetActiveWebContents(); 410 WebContents* new_tab = GetTabAndRevertIfNecessary(browser, disposition); 411 // If we are on an interstitial page and clone the tab, it won't be copied 412 // to the new tab, so we don't need to go back. 413 if ((new_tab == current_tab) || !current_tab->ShowingInterstitialPage()) 414 new_tab->GetController().GoBack(); 415 } 416 } 417 418 bool CanGoForward(const Browser* browser) { 419 return browser->tab_strip_model()->GetActiveWebContents()-> 420 GetController().CanGoForward(); 421 } 422 423 void GoForward(Browser* browser, WindowOpenDisposition disposition) { 424 content::RecordAction(UserMetricsAction("Forward")); 425 if (CanGoForward(browser)) { 426 GetTabAndRevertIfNecessary(browser, disposition)-> 427 GetController().GoForward(); 428 } 429 } 430 431 bool NavigateToIndexWithDisposition(Browser* browser, 432 int index, 433 WindowOpenDisposition disposition) { 434 NavigationController* controller = 435 &GetTabAndRevertIfNecessary(browser, disposition)->GetController(); 436 if (index < 0 || index >= controller->GetEntryCount()) 437 return false; 438 controller->GoToIndex(index); 439 return true; 440 } 441 442 void Reload(Browser* browser, WindowOpenDisposition disposition) { 443 content::RecordAction(UserMetricsAction("Reload")); 444 ReloadInternal(browser, disposition, false); 445 } 446 447 void ReloadIgnoringCache(Browser* browser, WindowOpenDisposition disposition) { 448 content::RecordAction(UserMetricsAction("ReloadIgnoringCache")); 449 ReloadInternal(browser, disposition, true); 450 } 451 452 bool CanReload(const Browser* browser) { 453 return !browser->is_devtools(); 454 } 455 456 void Home(Browser* browser, WindowOpenDisposition disposition) { 457 content::RecordAction(UserMetricsAction("Home")); 458 459 std::string extra_headers; 460 #if defined(ENABLE_RLZ) && !defined(OS_IOS) 461 // If the home page is a Google home page, add the RLZ header to the request. 462 PrefService* pref_service = browser->profile()->GetPrefs(); 463 if (pref_service) { 464 if (google_util::IsGoogleHomePageUrl( 465 GURL(pref_service->GetString(prefs::kHomePage)))) { 466 extra_headers = RLZTracker::GetAccessPointHttpHeader( 467 RLZTracker::ChromeHomePage()); 468 } 469 } 470 #endif // defined(ENABLE_RLZ) && !defined(OS_IOS) 471 472 GURL url = browser->profile()->GetHomePage(); 473 474 #if defined(ENABLE_EXTENSIONS) 475 // Streamlined hosted apps should return to their launch page when the home 476 // button is pressed. 477 if (browser->is_app()) { 478 const extensions::Extension* extension = 479 extensions::ExtensionRegistry::Get(browser->profile()) 480 ->GetExtensionById( 481 web_app::GetExtensionIdFromApplicationName(browser->app_name()), 482 extensions::ExtensionRegistry::EVERYTHING); 483 if (!extension) 484 return; 485 486 url = extensions::AppLaunchInfo::GetLaunchWebURL(extension); 487 } 488 #endif 489 490 OpenURLParams params( 491 url, Referrer(), disposition, 492 ui::PageTransitionFromInt( 493 ui::PAGE_TRANSITION_AUTO_BOOKMARK | 494 ui::PAGE_TRANSITION_HOME_PAGE), 495 false); 496 params.extra_headers = extra_headers; 497 browser->OpenURL(params); 498 } 499 500 void OpenCurrentURL(Browser* browser) { 501 content::RecordAction(UserMetricsAction("LoadURL")); 502 LocationBar* location_bar = browser->window()->GetLocationBar(); 503 if (!location_bar) 504 return; 505 506 GURL url(location_bar->GetDestinationURL()); 507 508 ui::PageTransition page_transition = location_bar->GetPageTransition(); 509 ui::PageTransition page_transition_without_qualifier( 510 ui::PageTransitionStripQualifier(page_transition)); 511 WindowOpenDisposition open_disposition = 512 location_bar->GetWindowOpenDisposition(); 513 // A PAGE_TRANSITION_TYPED means the user has typed a URL. We do not want to 514 // open URLs with instant_controller since in some cases it disregards it 515 // and performs a search instead. For example, when using CTRL-Enter, the 516 // location_bar is aware of the URL but instant is not. 517 // Instant should also not handle PAGE_TRANSITION_RELOAD because its knowledge 518 // of the omnibox text may be stale if the user focuses in the omnibox and 519 // presses enter without typing anything. 520 if (page_transition_without_qualifier != ui::PAGE_TRANSITION_TYPED && 521 page_transition_without_qualifier != ui::PAGE_TRANSITION_RELOAD && 522 browser->instant_controller() && 523 browser->instant_controller()->OpenInstant(open_disposition, url)) 524 return; 525 526 NavigateParams params(browser, url, page_transition); 527 params.disposition = open_disposition; 528 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least 529 // inherit the opener. In some cases the tabstrip will determine the group 530 // should be inherited, in which case the group is inherited instead of the 531 // opener. 532 params.tabstrip_add_types = 533 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER; 534 Navigate(¶ms); 535 536 #if defined(ENABLE_EXTENSIONS) 537 DCHECK(extensions::ExtensionSystem::Get( 538 browser->profile())->extension_service()); 539 const extensions::Extension* extension = 540 extensions::ExtensionRegistry::Get(browser->profile()) 541 ->enabled_extensions().GetAppByURL(url); 542 if (extension) { 543 CoreAppLauncherHandler::RecordAppLaunchType( 544 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION, 545 extension->GetType()); 546 } 547 #endif 548 } 549 550 void Stop(Browser* browser) { 551 content::RecordAction(UserMetricsAction("Stop")); 552 browser->tab_strip_model()->GetActiveWebContents()->Stop(); 553 } 554 555 void NewWindow(Browser* browser) { 556 NewEmptyWindow(browser->profile()->GetOriginalProfile(), 557 browser->host_desktop_type()); 558 } 559 560 void NewIncognitoWindow(Browser* browser) { 561 NewEmptyWindow(browser->profile()->GetOffTheRecordProfile(), 562 browser->host_desktop_type()); 563 } 564 565 void CloseWindow(Browser* browser) { 566 content::RecordAction(UserMetricsAction("CloseWindow")); 567 browser->window()->Close(); 568 } 569 570 void NewTab(Browser* browser) { 571 content::RecordAction(UserMetricsAction("NewTab")); 572 // TODO(asvitkine): This is invoked programmatically from several places. 573 // Audit the code and change it so that the histogram only gets collected for 574 // user-initiated commands. 575 UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND, 576 TabStripModel::NEW_TAB_ENUM_COUNT); 577 578 if (browser->is_type_tabbed()) { 579 AddTabAt(browser, GURL(), -1, true); 580 browser->tab_strip_model()->GetActiveWebContents()->RestoreFocus(); 581 } else { 582 ScopedTabbedBrowserDisplayer displayer(browser->profile(), 583 browser->host_desktop_type()); 584 Browser* b = displayer.browser(); 585 AddTabAt(b, GURL(), -1, true); 586 b->window()->Show(); 587 // The call to AddBlankTabAt above did not set the focus to the tab as its 588 // window was not active, so we have to do it explicitly. 589 // See http://crbug.com/6380. 590 b->tab_strip_model()->GetActiveWebContents()->RestoreFocus(); 591 } 592 } 593 594 void CloseTab(Browser* browser) { 595 content::RecordAction(UserMetricsAction("CloseTab_Accelerator")); 596 browser->tab_strip_model()->CloseSelectedTabs(); 597 } 598 599 bool CanZoomIn(content::WebContents* contents) { 600 ZoomController* zoom_controller = ZoomController::FromWebContents(contents); 601 return zoom_controller->GetZoomPercent() != 602 contents->GetMaximumZoomPercent() + 1; 603 } 604 605 bool CanZoomOut(content::WebContents* contents) { 606 ZoomController* zoom_controller = ZoomController::FromWebContents(contents); 607 return zoom_controller->GetZoomPercent() != 608 contents->GetMinimumZoomPercent(); 609 } 610 611 bool ActualSize(content::WebContents* contents) { 612 ZoomController* zoom_controller = ZoomController::FromWebContents(contents); 613 return zoom_controller->GetZoomPercent() != 100.0f; 614 } 615 616 TabStripModelDelegate::RestoreTabType GetRestoreTabType( 617 const Browser* browser) { 618 TabRestoreService* service = 619 TabRestoreServiceFactory::GetForProfile(browser->profile()); 620 if (!service || service->entries().empty()) 621 return TabStripModelDelegate::RESTORE_NONE; 622 if (service->entries().front()->type == TabRestoreService::WINDOW) 623 return TabStripModelDelegate::RESTORE_WINDOW; 624 return TabStripModelDelegate::RESTORE_TAB; 625 } 626 627 void SelectNextTab(Browser* browser) { 628 content::RecordAction(UserMetricsAction("SelectNextTab")); 629 browser->tab_strip_model()->SelectNextTab(); 630 } 631 632 void SelectPreviousTab(Browser* browser) { 633 content::RecordAction(UserMetricsAction("SelectPrevTab")); 634 browser->tab_strip_model()->SelectPreviousTab(); 635 } 636 637 void MoveTabNext(Browser* browser) { 638 content::RecordAction(UserMetricsAction("MoveTabNext")); 639 browser->tab_strip_model()->MoveTabNext(); 640 } 641 642 void MoveTabPrevious(Browser* browser) { 643 content::RecordAction(UserMetricsAction("MoveTabPrevious")); 644 browser->tab_strip_model()->MoveTabPrevious(); 645 } 646 647 void SelectNumberedTab(Browser* browser, int index) { 648 if (index < browser->tab_strip_model()->count()) { 649 content::RecordAction(UserMetricsAction("SelectNumberedTab")); 650 browser->tab_strip_model()->ActivateTabAt(index, true); 651 } 652 } 653 654 void SelectLastTab(Browser* browser) { 655 content::RecordAction(UserMetricsAction("SelectLastTab")); 656 browser->tab_strip_model()->SelectLastTab(); 657 } 658 659 void DuplicateTab(Browser* browser) { 660 content::RecordAction(UserMetricsAction("Duplicate")); 661 DuplicateTabAt(browser, browser->tab_strip_model()->active_index()); 662 } 663 664 bool CanDuplicateTab(const Browser* browser) { 665 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); 666 return contents && contents->GetController().GetLastCommittedEntry(); 667 } 668 669 WebContents* DuplicateTabAt(Browser* browser, int index) { 670 WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(index); 671 CHECK(contents); 672 WebContents* contents_dupe = contents->Clone(); 673 674 bool pinned = false; 675 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) { 676 // If this is a tabbed browser, just create a duplicate tab inside the same 677 // window next to the tab being duplicated. 678 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents); 679 pinned = browser->tab_strip_model()->IsTabPinned(index); 680 int add_types = TabStripModel::ADD_ACTIVE | 681 TabStripModel::ADD_INHERIT_GROUP | 682 (pinned ? TabStripModel::ADD_PINNED : 0); 683 browser->tab_strip_model()->InsertWebContentsAt( 684 index + 1, contents_dupe, add_types); 685 } else { 686 Browser* new_browser = NULL; 687 if (browser->is_app() && !browser->is_type_popup()) { 688 new_browser = new Browser( 689 Browser::CreateParams::CreateForApp(browser->app_name(), 690 browser->is_trusted_source(), 691 gfx::Rect(), 692 browser->profile(), 693 browser->host_desktop_type())); 694 } else { 695 new_browser = new Browser( 696 Browser::CreateParams(browser->type(), browser->profile(), 697 browser->host_desktop_type())); 698 } 699 // Preserve the size of the original window. The new window has already 700 // been given an offset by the OS, so we shouldn't copy the old bounds. 701 BrowserWindow* new_window = new_browser->window(); 702 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), 703 browser->window()->GetRestoredBounds().size())); 704 705 // We need to show the browser now. Otherwise ContainerWin assumes the 706 // WebContents is invisible and won't size it. 707 new_browser->window()->Show(); 708 709 // The page transition below is only for the purpose of inserting the tab. 710 new_browser->tab_strip_model()->AddWebContents( 711 contents_dupe, -1, 712 ui::PAGE_TRANSITION_LINK, 713 TabStripModel::ADD_ACTIVE); 714 } 715 716 SessionService* session_service = 717 SessionServiceFactory::GetForProfileIfExisting(browser->profile()); 718 if (session_service) 719 session_service->TabRestored(contents_dupe, pinned); 720 return contents_dupe; 721 } 722 723 bool CanDuplicateTabAt(Browser* browser, int index) { 724 content::NavigationController& nc = 725 browser->tab_strip_model()->GetWebContentsAt(index)->GetController(); 726 return nc.GetWebContents() && nc.GetLastCommittedEntry(); 727 } 728 729 void ConvertPopupToTabbedBrowser(Browser* browser) { 730 content::RecordAction(UserMetricsAction("ShowAsTab")); 731 TabStripModel* tab_strip = browser->tab_strip_model(); 732 WebContents* contents = 733 tab_strip->DetachWebContentsAt(tab_strip->active_index()); 734 Browser* b = new Browser(Browser::CreateParams(browser->profile(), 735 browser->host_desktop_type())); 736 b->tab_strip_model()->AppendWebContents(contents, true); 737 b->window()->Show(); 738 } 739 740 void Exit() { 741 content::RecordAction(UserMetricsAction("Exit")); 742 chrome::AttemptUserExit(); 743 } 744 745 void BookmarkCurrentPage(Browser* browser) { 746 DCHECK(!chrome::ShouldRemoveBookmarkThisPageUI(browser->profile())); 747 748 const extensions::Extension* extension = NULL; 749 extensions::Command command; 750 extensions::CommandService::ExtensionCommandType command_type; 751 if (GetBookmarkOverrideCommand(browser->profile(), 752 &extension, 753 &command, 754 &command_type)) { 755 switch (command_type) { 756 case extensions::CommandService::NAMED: 757 browser->window()->ExecuteExtensionCommand(extension, command); 758 break; 759 case extensions::CommandService::BROWSER_ACTION: 760 case extensions::CommandService::PAGE_ACTION: 761 // BookmarkCurrentPage is called through a user gesture, so it is safe 762 // to grant the active tab permission. 763 extensions::ExtensionActionAPI::Get(browser->profile())-> 764 ShowExtensionActionPopup(extension, browser, true); 765 break; 766 } 767 return; 768 } 769 770 BookmarkCurrentPageInternal(browser); 771 } 772 773 bool CanBookmarkCurrentPage(const Browser* browser) { 774 return CanBookmarkCurrentPageInternal(browser, true); 775 } 776 777 void BookmarkAllTabs(Browser* browser) { 778 chrome::ShowBookmarkAllTabsDialog(browser); 779 } 780 781 bool CanBookmarkAllTabs(const Browser* browser) { 782 return browser->tab_strip_model()->count() > 1 && 783 !chrome::ShouldRemoveBookmarkOpenPagesUI(browser->profile()) && 784 CanBookmarkCurrentPageInternal(browser, false); 785 } 786 787 void Translate(Browser* browser) { 788 if (!browser->window()->IsActive()) 789 return; 790 791 WebContents* web_contents = 792 browser->tab_strip_model()->GetActiveWebContents(); 793 ChromeTranslateClient* chrome_translate_client = 794 ChromeTranslateClient::FromWebContents(web_contents); 795 796 translate::TranslateStep step = translate::TRANSLATE_STEP_BEFORE_TRANSLATE; 797 if (chrome_translate_client) { 798 if (chrome_translate_client->GetLanguageState().translation_pending()) 799 step = translate::TRANSLATE_STEP_TRANSLATING; 800 else if (chrome_translate_client->GetLanguageState().IsPageTranslated()) 801 step = translate::TRANSLATE_STEP_AFTER_TRANSLATE; 802 } 803 browser->window()->ShowTranslateBubble( 804 web_contents, step, translate::TranslateErrors::NONE, true); 805 } 806 807 void ManagePasswordsForPage(Browser* browser) { 808 if (!browser->window()->IsActive()) 809 return; 810 811 WebContents* web_contents = 812 browser->tab_strip_model()->GetActiveWebContents(); 813 chrome::ShowManagePasswordsBubble(web_contents); 814 } 815 816 void TogglePagePinnedToStartScreen(Browser* browser) { 817 #if defined(OS_WIN) 818 MetroPinTabHelper::FromWebContents( 819 browser->tab_strip_model()->GetActiveWebContents())-> 820 TogglePinnedToStartScreen(); 821 #endif 822 } 823 824 void SavePage(Browser* browser) { 825 content::RecordAction(UserMetricsAction("SavePage")); 826 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 827 if (current_tab && current_tab->GetContentsMimeType() == "application/pdf") 828 content::RecordAction(UserMetricsAction("PDF.SavePage")); 829 current_tab->OnSavePage(); 830 } 831 832 bool CanSavePage(const Browser* browser) { 833 // LocalState can be NULL in tests. 834 if (g_browser_process->local_state() && 835 !g_browser_process->local_state()->GetBoolean( 836 prefs::kAllowFileSelectionDialogs)) { 837 return false; 838 } 839 return !browser->is_devtools() && 840 !(GetContentRestrictions(browser) & CONTENT_RESTRICTION_SAVE); 841 } 842 843 void ShowFindBar(Browser* browser) { 844 browser->GetFindBarController()->Show(); 845 } 846 847 void ShowWebsiteSettings(Browser* browser, 848 content::WebContents* web_contents, 849 const GURL& url, 850 const SSLStatus& ssl) { 851 browser->window()->ShowWebsiteSettings( 852 Profile::FromBrowserContext(web_contents->GetBrowserContext()), 853 web_contents, url, ssl); 854 } 855 856 void Print(Browser* browser) { 857 #if defined(ENABLE_PRINTING) 858 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); 859 860 #if defined(ENABLE_FULL_PRINTING) 861 printing::PrintViewManager* print_view_manager = 862 printing::PrintViewManager::FromWebContents(contents); 863 if (!browser->profile()->GetPrefs()->GetBoolean( 864 prefs::kPrintPreviewDisabled)) { 865 print_view_manager->PrintPreviewNow(false); 866 return; 867 } 868 #else // ENABLE_FULL_PRINTING 869 printing::PrintViewManagerBasic* print_view_manager = 870 printing::PrintViewManagerBasic::FromWebContents(contents); 871 #endif // ENABLE_FULL_PRINTING 872 873 #if !defined(DISABLE_BASIC_PRINTING) 874 print_view_manager->PrintNow(); 875 #endif // DISABLE_BASIC_PRINTING 876 877 #endif // defined(ENABLE_PRINTING) 878 } 879 880 bool CanPrint(Browser* browser) { 881 // Do not print when printing is disabled via pref or policy. 882 // Do not print when a constrained window is showing. It's confusing. 883 // TODO(gbillock): Need to re-assess the call to 884 // IsShowingWebContentsModalDialog after a popup management policy is 885 // refined -- we will probably want to just queue the print request, not 886 // block it. 887 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) && 888 !(IsShowingWebContentsModalDialog(browser) || 889 GetContentRestrictions(browser) & CONTENT_RESTRICTION_PRINT); 890 } 891 892 #if !defined(DISABLE_BASIC_PRINTING) 893 void BasicPrint(Browser* browser) { 894 #if defined(ENABLE_FULL_PRINTING) 895 printing::PrintViewManager* print_view_manager = 896 printing::PrintViewManager::FromWebContents( 897 browser->tab_strip_model()->GetActiveWebContents()); 898 print_view_manager->BasicPrint(); 899 #endif 900 } 901 902 bool CanBasicPrint(Browser* browser) { 903 // If printing is not disabled via pref or policy, it is always possible to 904 // advanced print when the print preview is visible. The exception to this 905 // is under Win8 ash, since showing the advanced print dialog will open it 906 // modally on the Desktop and hang the browser. 907 #if defined(OS_WIN) 908 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) 909 return false; 910 #endif 911 912 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) && 913 (PrintPreviewShowing(browser) || CanPrint(browser)); 914 } 915 #endif // !DISABLE_BASIC_PRINTING 916 917 void EmailPageLocation(Browser* browser) { 918 content::RecordAction(UserMetricsAction("EmailPageLocation")); 919 WebContents* wc = browser->tab_strip_model()->GetActiveWebContents(); 920 DCHECK(wc); 921 922 std::string title = net::EscapeQueryParamValue( 923 base::UTF16ToUTF8(wc->GetTitle()), false); 924 std::string page_url = net::EscapeQueryParamValue(wc->GetURL().spec(), false); 925 std::string mailto = std::string("mailto:?subject=Fwd:%20") + 926 title + "&body=%0A%0A" + page_url; 927 platform_util::OpenExternal(browser->profile(), GURL(mailto)); 928 } 929 930 bool CanEmailPageLocation(const Browser* browser) { 931 return browser->toolbar_model()->ShouldDisplayURL() && 932 browser->tab_strip_model()->GetActiveWebContents()->GetURL().is_valid(); 933 } 934 935 void Cut(Browser* browser) { 936 content::RecordAction(UserMetricsAction("Cut")); 937 browser->window()->Cut(); 938 } 939 940 void Copy(Browser* browser) { 941 content::RecordAction(UserMetricsAction("Copy")); 942 browser->window()->Copy(); 943 } 944 945 void Paste(Browser* browser) { 946 content::RecordAction(UserMetricsAction("Paste")); 947 browser->window()->Paste(); 948 } 949 950 void Find(Browser* browser) { 951 content::RecordAction(UserMetricsAction("Find")); 952 FindInPage(browser, false, false); 953 } 954 955 void FindNext(Browser* browser) { 956 content::RecordAction(UserMetricsAction("FindNext")); 957 FindInPage(browser, true, true); 958 } 959 960 void FindPrevious(Browser* browser) { 961 content::RecordAction(UserMetricsAction("FindPrevious")); 962 FindInPage(browser, true, false); 963 } 964 965 void FindInPage(Browser* browser, bool find_next, bool forward_direction) { 966 ShowFindBar(browser); 967 if (find_next) { 968 base::string16 find_text; 969 FindTabHelper* find_helper = FindTabHelper::FromWebContents( 970 browser->tab_strip_model()->GetActiveWebContents()); 971 #if defined(OS_MACOSX) 972 // We always want to search for the current contents of the find bar on 973 // OS X. For regular profile it's always the current find pboard. For 974 // Incognito window it's the newest value of the find pboard content and 975 // user-typed text. 976 FindBar* find_bar = browser->GetFindBarController()->find_bar(); 977 find_text = find_bar->GetFindText(); 978 #endif 979 find_helper->StartFinding(find_text, forward_direction, false); 980 } 981 } 982 983 void Zoom(Browser* browser, content::PageZoom zoom) { 984 chrome_page_zoom::Zoom(browser->tab_strip_model()->GetActiveWebContents(), 985 zoom); 986 } 987 988 void FocusToolbar(Browser* browser) { 989 content::RecordAction(UserMetricsAction("FocusToolbar")); 990 browser->window()->FocusToolbar(); 991 } 992 993 void FocusLocationBar(Browser* browser) { 994 content::RecordAction(UserMetricsAction("FocusLocation")); 995 browser->window()->SetFocusToLocationBar(true); 996 } 997 998 void FocusSearch(Browser* browser) { 999 // TODO(beng): replace this with FocusLocationBar 1000 content::RecordAction(UserMetricsAction("FocusSearch")); 1001 browser->window()->GetLocationBar()->FocusSearch(); 1002 } 1003 1004 void FocusAppMenu(Browser* browser) { 1005 content::RecordAction(UserMetricsAction("FocusAppMenu")); 1006 browser->window()->FocusAppMenu(); 1007 } 1008 1009 void FocusBookmarksToolbar(Browser* browser) { 1010 content::RecordAction(UserMetricsAction("FocusBookmarksToolbar")); 1011 browser->window()->FocusBookmarksToolbar(); 1012 } 1013 1014 void FocusInfobars(Browser* browser) { 1015 content::RecordAction(UserMetricsAction("FocusInfobars")); 1016 browser->window()->FocusInfobars(); 1017 } 1018 1019 void FocusNextPane(Browser* browser) { 1020 content::RecordAction(UserMetricsAction("FocusNextPane")); 1021 browser->window()->RotatePaneFocus(true); 1022 } 1023 1024 void FocusPreviousPane(Browser* browser) { 1025 content::RecordAction(UserMetricsAction("FocusPreviousPane")); 1026 browser->window()->RotatePaneFocus(false); 1027 } 1028 1029 void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) { 1030 if (action.type() == DevToolsToggleAction::kShowConsole) 1031 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole")); 1032 else 1033 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow")); 1034 DevToolsWindow::ToggleDevToolsWindow(browser, action); 1035 } 1036 1037 bool CanOpenTaskManager() { 1038 #if defined(ENABLE_TASK_MANAGER) 1039 return true; 1040 #else 1041 return false; 1042 #endif 1043 } 1044 1045 void OpenTaskManager(Browser* browser) { 1046 #if defined(ENABLE_TASK_MANAGER) 1047 content::RecordAction(UserMetricsAction("TaskManager")); 1048 chrome::ShowTaskManager(browser); 1049 #else 1050 NOTREACHED(); 1051 #endif 1052 } 1053 1054 void OpenFeedbackDialog(Browser* browser) { 1055 content::RecordAction(UserMetricsAction("Feedback")); 1056 chrome::ShowFeedbackPage(browser, std::string(), std::string()); 1057 } 1058 1059 void ToggleBookmarkBar(Browser* browser) { 1060 content::RecordAction(UserMetricsAction("ShowBookmarksBar")); 1061 ToggleBookmarkBarWhenVisible(browser->profile()); 1062 } 1063 1064 void ShowAppMenu(Browser* browser) { 1065 // We record the user metric for this event in WrenchMenu::RunMenu. 1066 browser->window()->ShowAppMenu(); 1067 } 1068 1069 void ShowAvatarMenu(Browser* browser) { 1070 browser->window()->ShowAvatarBubbleFromAvatarButton( 1071 BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT, 1072 signin::ManageAccountsParams()); 1073 } 1074 1075 void OpenUpdateChromeDialog(Browser* browser) { 1076 if (UpgradeDetector::GetInstance()->is_outdated_install()) { 1077 content::NotificationService::current()->Notify( 1078 chrome::NOTIFICATION_OUTDATED_INSTALL, 1079 content::NotificationService::AllSources(), 1080 content::NotificationService::NoDetails()); 1081 } else if (UpgradeDetector::GetInstance()->is_outdated_install_no_au()) { 1082 content::NotificationService::current()->Notify( 1083 chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU, 1084 content::NotificationService::AllSources(), 1085 content::NotificationService::NoDetails()); 1086 } else { 1087 content::RecordAction(UserMetricsAction("UpdateChrome")); 1088 browser->window()->ShowUpdateChromeDialog(); 1089 } 1090 } 1091 1092 void ToggleSpeechInput(Browser* browser) { 1093 SearchTabHelper* search_tab_helper = 1094 SearchTabHelper::FromWebContents( 1095 browser->tab_strip_model()->GetActiveWebContents()); 1096 // |search_tab_helper| can be null in unit tests. 1097 if (search_tab_helper) 1098 search_tab_helper->ToggleVoiceSearch(); 1099 } 1100 1101 void DistillCurrentPage(Browser* browser) { 1102 DistillCurrentPageAndView(browser->tab_strip_model()->GetActiveWebContents()); 1103 } 1104 1105 bool CanRequestTabletSite(WebContents* current_tab) { 1106 return current_tab && 1107 current_tab->GetController().GetLastCommittedEntry() != NULL; 1108 } 1109 1110 bool IsRequestingTabletSite(Browser* browser) { 1111 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 1112 if (!current_tab) 1113 return false; 1114 content::NavigationEntry* entry = 1115 current_tab->GetController().GetLastCommittedEntry(); 1116 if (!entry) 1117 return false; 1118 return entry->GetIsOverridingUserAgent(); 1119 } 1120 1121 void ToggleRequestTabletSite(Browser* browser) { 1122 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 1123 if (!current_tab) 1124 return; 1125 NavigationController& controller = current_tab->GetController(); 1126 NavigationEntry* entry = controller.GetLastCommittedEntry(); 1127 if (!entry) 1128 return; 1129 if (entry->GetIsOverridingUserAgent()) { 1130 entry->SetIsOverridingUserAgent(false); 1131 } else { 1132 entry->SetIsOverridingUserAgent(true); 1133 chrome::VersionInfo version_info; 1134 std::string product; 1135 if (version_info.is_valid()) 1136 product = version_info.ProductNameAndVersionForUserAgent(); 1137 current_tab->SetUserAgentOverride(content::BuildUserAgentFromOSAndProduct( 1138 kOsOverrideForTabletSite, product)); 1139 } 1140 controller.ReloadOriginalRequestURL(true); 1141 } 1142 1143 void ToggleFullscreenMode(Browser* browser) { 1144 DCHECK(browser); 1145 browser->fullscreen_controller()->ToggleBrowserFullscreenMode(); 1146 } 1147 1148 void ClearCache(Browser* browser) { 1149 BrowsingDataRemover* remover = 1150 BrowsingDataRemover::CreateForUnboundedRange(browser->profile()); 1151 remover->Remove(BrowsingDataRemover::REMOVE_CACHE, 1152 BrowsingDataHelper::UNPROTECTED_WEB); 1153 // BrowsingDataRemover takes care of deleting itself when done. 1154 } 1155 1156 bool IsDebuggerAttachedToCurrentTab(Browser* browser) { 1157 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); 1158 return contents ? 1159 content::DevToolsAgentHost::IsDebuggerAttached(contents) : false; 1160 } 1161 1162 void ViewSource(Browser* browser, WebContents* contents) { 1163 DCHECK(contents); 1164 1165 // Use the last committed entry, since the pending entry hasn't loaded yet and 1166 // won't be copied into the cloned tab. 1167 NavigationEntry* entry = contents->GetController().GetLastCommittedEntry(); 1168 if (!entry) 1169 return; 1170 1171 ViewSource(browser, contents, entry->GetURL(), entry->GetPageState()); 1172 } 1173 1174 void ViewSource(Browser* browser, 1175 WebContents* contents, 1176 const GURL& url, 1177 const content::PageState& page_state) { 1178 content::RecordAction(UserMetricsAction("ViewSource")); 1179 DCHECK(contents); 1180 1181 WebContents* view_source_contents = contents->Clone(); 1182 DCHECK(view_source_contents->GetController().CanPruneAllButLastCommitted()); 1183 view_source_contents->GetController().PruneAllButLastCommitted(); 1184 NavigationEntry* last_committed_entry = 1185 view_source_contents->GetController().GetLastCommittedEntry(); 1186 if (!last_committed_entry) 1187 return; 1188 1189 GURL view_source_url = 1190 GURL(content::kViewSourceScheme + std::string(":") + url.spec()); 1191 last_committed_entry->SetVirtualURL(view_source_url); 1192 1193 // Do not restore scroller position. 1194 last_committed_entry->SetPageState(page_state.RemoveScrollOffset()); 1195 1196 // Do not restore title, derive it from the url. 1197 last_committed_entry->SetTitle(base::string16()); 1198 1199 // Now show view-source entry. 1200 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) { 1201 // If this is a tabbed browser, just create a duplicate tab inside the same 1202 // window next to the tab being duplicated. 1203 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents); 1204 int add_types = TabStripModel::ADD_ACTIVE | 1205 TabStripModel::ADD_INHERIT_GROUP; 1206 browser->tab_strip_model()->InsertWebContentsAt( 1207 index + 1, 1208 view_source_contents, 1209 add_types); 1210 } else { 1211 Browser* b = new Browser( 1212 Browser::CreateParams(Browser::TYPE_TABBED, browser->profile(), 1213 browser->host_desktop_type())); 1214 1215 // Preserve the size of the original window. The new window has already 1216 // been given an offset by the OS, so we shouldn't copy the old bounds. 1217 BrowserWindow* new_window = b->window(); 1218 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), 1219 browser->window()->GetRestoredBounds().size())); 1220 1221 // We need to show the browser now. Otherwise ContainerWin assumes the 1222 // WebContents is invisible and won't size it. 1223 b->window()->Show(); 1224 1225 // The page transition below is only for the purpose of inserting the tab. 1226 b->tab_strip_model()->AddWebContents(view_source_contents, -1, 1227 ui::PAGE_TRANSITION_LINK, 1228 TabStripModel::ADD_ACTIVE); 1229 } 1230 1231 SessionService* session_service = 1232 SessionServiceFactory::GetForProfileIfExisting(browser->profile()); 1233 if (session_service) 1234 session_service->TabRestored(view_source_contents, false); 1235 } 1236 1237 void ViewSelectedSource(Browser* browser) { 1238 ViewSource(browser, browser->tab_strip_model()->GetActiveWebContents()); 1239 } 1240 1241 bool CanViewSource(const Browser* browser) { 1242 return !browser->is_devtools() && 1243 browser->tab_strip_model()->GetActiveWebContents()->GetController(). 1244 CanViewSource(); 1245 } 1246 1247 void CreateApplicationShortcuts(Browser* browser) { 1248 content::RecordAction(UserMetricsAction("CreateShortcut")); 1249 extensions::TabHelper::FromWebContents( 1250 browser->tab_strip_model()->GetActiveWebContents())-> 1251 CreateApplicationShortcuts(); 1252 } 1253 1254 void CreateBookmarkAppFromCurrentWebContents(Browser* browser) { 1255 content::RecordAction(UserMetricsAction("CreateHostedApp")); 1256 extensions::TabHelper::FromWebContents( 1257 browser->tab_strip_model()->GetActiveWebContents())-> 1258 CreateHostedAppFromWebContents(); 1259 } 1260 1261 bool CanCreateApplicationShortcuts(const Browser* browser) { 1262 return extensions::TabHelper::FromWebContents( 1263 browser->tab_strip_model()->GetActiveWebContents())-> 1264 CanCreateApplicationShortcuts(); 1265 } 1266 1267 bool CanCreateBookmarkApp(const Browser* browser) { 1268 return extensions::TabHelper::FromWebContents( 1269 browser->tab_strip_model()->GetActiveWebContents()) 1270 ->CanCreateBookmarkApp(); 1271 } 1272 1273 void ConvertTabToAppWindow(Browser* browser, 1274 content::WebContents* contents) { 1275 const GURL& url = contents->GetController().GetLastCommittedEntry()->GetURL(); 1276 std::string app_name = web_app::GenerateApplicationNameFromURL(url); 1277 1278 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents); 1279 if (index >= 0) 1280 browser->tab_strip_model()->DetachWebContentsAt(index); 1281 1282 Browser* app_browser = new Browser( 1283 Browser::CreateParams::CreateForApp(app_name, 1284 true /* trusted_source */, 1285 gfx::Rect(), 1286 browser->profile(), 1287 browser->host_desktop_type())); 1288 app_browser->tab_strip_model()->AppendWebContents(contents, true); 1289 1290 contents->GetMutableRendererPrefs()->can_accept_load_drops = false; 1291 contents->GetRenderViewHost()->SyncRendererPrefs(); 1292 app_browser->window()->Show(); 1293 } 1294 1295 } // namespace chrome 1296