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