Home | History | Annotate | Download | only in ui
      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(&params);
    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