Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / browser_commands.cc
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