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