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