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