• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.h"
6 
7 #if defined(OS_WIN)
8 #include <shellapi.h>
9 #include <windows.h>
10 #endif  // OS_WIN
11 
12 #include <algorithm>
13 #include <string>
14 
15 #include "base/base_paths.h"
16 #include "base/command_line.h"
17 #include "base/logging.h"
18 #include "base/metrics/histogram.h"
19 #include "base/path_service.h"
20 #include "base/string_util.h"
21 #include "base/threading/thread.h"
22 #include "base/threading/thread_restrictions.h"
23 #include "base/time.h"
24 #include "base/utf_string_conversions.h"
25 #include "chrome/app/chrome_command_ids.h"
26 #include "chrome/browser/autofill/autofill_manager.h"
27 #include "chrome/browser/background_contents_service.h"
28 #include "chrome/browser/bookmarks/bookmark_model.h"
29 #include "chrome/browser/bookmarks/bookmark_utils.h"
30 #include "chrome/browser/browser_process.h"
31 #include "chrome/browser/browser_shutdown.h"
32 #include "chrome/browser/browser_url_handler.h"
33 #include "chrome/browser/character_encoding.h"
34 #include "chrome/browser/debugger/devtools_manager.h"
35 #include "chrome/browser/debugger/devtools_toggle_action.h"
36 #include "chrome/browser/debugger/devtools_window.h"
37 #include "chrome/browser/download/download_item.h"
38 #include "chrome/browser/download/download_item_model.h"
39 #include "chrome/browser/download/download_manager.h"
40 #include "chrome/browser/download/download_shelf.h"
41 #include "chrome/browser/download/download_started_animation.h"
42 #include "chrome/browser/download/save_package.h"
43 #include "chrome/browser/extensions/crx_installer.h"
44 #include "chrome/browser/extensions/extension_browser_event_router.h"
45 #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h"
46 #include "chrome/browser/extensions/extension_host.h"
47 #include "chrome/browser/extensions/extension_prefs.h"
48 #include "chrome/browser/extensions/extension_service.h"
49 #include "chrome/browser/extensions/extension_tab_helper.h"
50 #include "chrome/browser/extensions/extension_tabs_module.h"
51 #include "chrome/browser/first_run/first_run.h"
52 #include "chrome/browser/google/google_url_tracker.h"
53 #include "chrome/browser/google/google_util.h"
54 #include "chrome/browser/instant/instant_controller.h"
55 #include "chrome/browser/instant/instant_unload_handler.h"
56 #include "chrome/browser/metrics/user_metrics.h"
57 #include "chrome/browser/net/browser_url_util.h"
58 #include "chrome/browser/net/url_fixer_upper.h"
59 #include "chrome/browser/notifications/notification_ui_manager.h"
60 #include "chrome/browser/platform_util.h"
61 #include "chrome/browser/prefs/pref_service.h"
62 #include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
63 #include "chrome/browser/printing/print_preview_tab_controller.h"
64 #include "chrome/browser/profiles/profile.h"
65 #include "chrome/browser/sessions/session_service.h"
66 #include "chrome/browser/sessions/session_types.h"
67 #include "chrome/browser/sessions/tab_restore_service.h"
68 #include "chrome/browser/sync/profile_sync_service.h"
69 #include "chrome/browser/sync/sync_ui_util.h"
70 #include "chrome/browser/tab_closeable_state_watcher.h"
71 #include "chrome/browser/tab_contents/background_contents.h"
72 #include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h"
73 #include "chrome/browser/tabs/tab_finder.h"
74 #include "chrome/browser/tabs/tab_strip_model.h"
75 #include "chrome/browser/ui/browser_list.h"
76 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
77 #include "chrome/browser/ui/browser_window.h"
78 #include "chrome/browser/ui/download/download_tab_helper.h"
79 #include "chrome/browser/ui/find_bar/find_bar.h"
80 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
81 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
82 #include "chrome/browser/ui/omnibox/location_bar.h"
83 #include "chrome/browser/ui/options/options_window.h"
84 #include "chrome/browser/ui/panels/panel.h"
85 #include "chrome/browser/ui/panels/panel_manager.h"
86 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
87 #include "chrome/browser/ui/status_bubble.h"
88 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
89 #include "chrome/browser/ui/tabs/dock_info.h"
90 #include "chrome/browser/ui/tabs/tab_menu_model.h"
91 #include "chrome/browser/ui/web_applications/web_app_ui.h"
92 #include "chrome/browser/ui/webui/active_downloads_ui.h"
93 #include "chrome/browser/ui/webui/bug_report_ui.h"
94 #include "chrome/browser/ui/webui/options/content_settings_handler.h"
95 #include "chrome/browser/ui/window_sizer.h"
96 #include "chrome/browser/upgrade_detector.h"
97 #include "chrome/browser/web_applications/web_app.h"
98 #include "chrome/common/chrome_constants.h"
99 #include "chrome/common/chrome_switches.h"
100 #include "chrome/common/content_restriction.h"
101 #include "chrome/common/extensions/extension.h"
102 #include "chrome/common/extensions/extension_constants.h"
103 #include "chrome/common/pref_names.h"
104 #include "chrome/common/profiling.h"
105 #include "chrome/common/url_constants.h"
106 #include "chrome/common/web_apps.h"
107 #include "content/browser/host_zoom_map.h"
108 #include "content/browser/renderer_host/render_view_host.h"
109 #include "content/browser/site_instance.h"
110 #include "content/browser/tab_contents/interstitial_page.h"
111 #include "content/browser/tab_contents/navigation_controller.h"
112 #include "content/browser/tab_contents/navigation_entry.h"
113 #include "content/browser/tab_contents/tab_contents.h"
114 #include "content/browser/tab_contents/tab_contents_view.h"
115 #include "content/common/notification_service.h"
116 #include "content/common/page_transition_types.h"
117 #include "grit/chromium_strings.h"
118 #include "grit/generated_resources.h"
119 #include "grit/locale_settings.h"
120 #include "net/base/cookie_monster.h"
121 #include "net/base/net_util.h"
122 #include "net/base/registry_controlled_domain.h"
123 #include "net/base/static_cookie_policy.h"
124 #include "net/url_request/url_request_context.h"
125 #include "ui/base/animation/animation.h"
126 #include "ui/base/l10n/l10n_util.h"
127 #include "ui/gfx/point.h"
128 #include "webkit/glue/webkit_glue.h"
129 #include "webkit/glue/window_open_disposition.h"
130 
131 #if defined(OS_WIN)
132 #include "app/win/shell.h"
133 #include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h"
134 #include "chrome/browser/shell_integration.h"
135 #include "chrome/browser/ssl/ssl_error_info.h"
136 #include "chrome/browser/task_manager/task_manager.h"
137 #include "chrome/browser/ui/view_ids.h"
138 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
139 #endif  // OS_WIN
140 
141 #if defined(OS_MACOSX)
142 #include "chrome/browser/ui/cocoa/find_pasteboard.h"
143 #endif
144 
145 #if defined(OS_CHROMEOS)
146 #include "chrome/browser/chromeos/boot_times_loader.h"
147 #include "chrome/browser/extensions/file_manager_util.h"
148 #endif
149 
150 using base::TimeDelta;
151 
152 ///////////////////////////////////////////////////////////////////////////////
153 
154 namespace {
155 
156 // The URL to be loaded to display Help.
157 const char kHelpContentUrl[] =
158 #if defined(OS_CHROMEOS)
159   #if defined(OFFICIAL_BUILD)
160       "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html";
161   #else
162       "https://www.google.com/support/chromeos/";
163   #endif
164 #else
165     "https://www.google.com/support/chrome/";
166 #endif
167 
168 // The URL to be opened when the Help link on the Autofill dialog is clicked.
169 const char kAutofillHelpUrl[] =
170 #if defined(OS_CHROMEOS)
171     "https://www.google.com/support/chromeos/bin/answer.py?answer=142893";
172 #else
173     "https://www.google.com/support/chrome/bin/answer.py?answer=142893";
174 #endif
175 
176 // The URL to be loaded to display the "Report a broken page" form.
177 const char kBrokenPageUrl[] =
178     "https://www.google.com/support/chrome/bin/request.py?contact_type="
179     "broken_website&format=inproduct&p.page_title=$1&p.page_url=$2";
180 
181 // The URL for the privacy dashboard.
182 const char kPrivacyDashboardUrl[] = "https://www.google.com/dashboard";
183 
184 // How long we wait before updating the browser chrome while loading a page.
185 const int kUIUpdateCoalescingTimeMS = 200;
186 
187 const char kHashMark[] = "#";
188 
189 #if defined(OS_CHROMEOS)
190 // If a popup window is bigger than this fraction of the screen on chrome os,
191 // turn it into a tab
192 const float kPopupMaxWidthFactor = 0.5;
193 const float kPopupMaxHeightFactor = 0.6;
194 #endif
195 
196 }  // namespace
197 
198 extern bool g_log_bug53991;
199 
200 ///////////////////////////////////////////////////////////////////////////////
201 // Browser, Constructors, Creation, Showing:
202 
Browser(Type type,Profile * profile)203 Browser::Browser(Type type, Profile* profile)
204     : type_(type),
205       profile_(profile),
206       window_(NULL),
207       ALLOW_THIS_IN_INITIALIZER_LIST(
208           tab_handler_(TabHandler::CreateTabHandler(this))),
209       command_updater_(this),
210       toolbar_model_(this),
211       chrome_updater_factory_(this),
212       is_attempting_to_close_browser_(false),
213       cancel_download_confirmation_state_(NOT_PROMPTED),
214       maximized_state_(MAXIMIZED_STATE_DEFAULT),
215       method_factory_(this),
216       block_command_execution_(false),
217       last_blocked_command_id_(-1),
218       last_blocked_command_disposition_(CURRENT_TAB),
219       pending_web_app_action_(NONE),
220       ALLOW_THIS_IN_INITIALIZER_LIST(
221           tab_restore_service_delegate_(
222               new BrowserTabRestoreServiceDelegate(this))) {
223   registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED,
224                  NotificationService::AllSources());
225   registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
226                  NotificationService::AllSources());
227   registrar_.Add(this, NotificationType::EXTENSION_LOADED,
228                  NotificationService::AllSources());
229   registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
230                  NotificationService::AllSources());
231   registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED,
232                  NotificationService::AllSources());
233   registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
234                  NotificationService::AllSources());
235   registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
236                  NotificationService::AllSources());
237 
238   // Need to know when to alert the user of theme install delay.
239   registrar_.Add(this, NotificationType::EXTENSION_READY_FOR_INSTALL,
240                  NotificationService::AllSources());
241 
242   // NOTE: These prefs all need to be explicitly destroyed in the destructor
243   // or you'll get a nasty surprise when you run the incognito tests.
244   PrefService* local_state = g_browser_process->local_state();
245   if (local_state)
246     printing_enabled_.Init(prefs::kPrintingEnabled, local_state, this);
247   dev_tools_disabled_.Init(prefs::kDevToolsDisabled,
248                            profile_->GetPrefs(), this);
249   incognito_mode_allowed_.Init(prefs::kIncognitoEnabled,
250                                profile_->GetPrefs(), this);
251   edit_bookmarks_enabled_.Init(prefs::kEditBookmarksEnabled,
252                                profile_->GetPrefs(), this);
253 
254   InitCommandState();
255   BrowserList::AddBrowser(this);
256 
257   encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
258                              profile_->GetPrefs(), NULL);
259   use_vertical_tabs_.Init(prefs::kUseVerticalTabs, profile_->GetPrefs(), this);
260   instant_enabled_.Init(prefs::kInstantEnabled, profile_->GetPrefs(), this);
261   if (!TabMenuModel::AreVerticalTabsEnabled()) {
262     // If vertical tabs aren't enabled, explicitly turn them off. Otherwise we
263     // might show vertical tabs but not show an option to turn them off.
264     use_vertical_tabs_.SetValue(false);
265   }
266   UpdateTabStripModelInsertionPolicy();
267 
268   tab_restore_service_ = profile->GetTabRestoreService();
269   if (tab_restore_service_) {
270     tab_restore_service_->AddObserver(this);
271     TabRestoreServiceChanged(tab_restore_service_);
272   }
273 
274   if (profile_->GetProfileSyncService())
275     profile_->GetProfileSyncService()->AddObserver(this);
276 
277   CreateInstantIfNecessary();
278 
279   // Make sure TabFinder has been created. This does nothing if TabFinder is
280   // not enabled.
281   TabFinder::GetInstance();
282 }
283 
~Browser()284 Browser::~Browser() {
285   VLOG_IF(1, g_log_bug53991) << "~Browser: " << profile_->IsOffTheRecord()
286                              << "; stillActive="
287                              << BrowserList::IsOffTheRecordSessionActive();
288 
289   if (profile_->GetProfileSyncService())
290     profile_->GetProfileSyncService()->RemoveObserver(this);
291 
292   BrowserList::RemoveBrowser(this);
293 
294 #if defined(OS_WIN) || defined(OS_LINUX)
295   if (!BrowserList::HasBrowserWithProfile(profile_)) {
296     // We're the last browser window with this profile. We need to nuke the
297     // TabRestoreService, which will start the shutdown of the
298     // NavigationControllers and allow for proper shutdown. If we don't do this
299     // chrome won't shutdown cleanly, and may end up crashing when some
300     // thread tries to use the IO thread (or another thread) that is no longer
301     // valid.
302     // This isn't a valid assumption for Mac OS, as it stays running after
303     // the last browser has closed. The Mac equivalent is in its app
304     // controller.
305     profile_->ResetTabRestoreService();
306   }
307 #endif
308 
309   SessionService* session_service = profile_->GetSessionService();
310   if (session_service)
311     session_service->WindowClosed(session_id_);
312 
313   TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
314   if (tab_restore_service)
315     tab_restore_service->BrowserClosed(tab_restore_service_delegate());
316 
317   encoding_auto_detect_.Destroy();
318   printing_enabled_.Destroy();
319   dev_tools_disabled_.Destroy();
320   incognito_mode_allowed_.Destroy();
321   instant_enabled_.Destroy();
322   use_vertical_tabs_.Destroy();
323   edit_bookmarks_enabled_.Destroy();
324 
325   if (profile_->IsOffTheRecord() &&
326       !BrowserList::IsOffTheRecordSessionActive()) {
327     // An incognito profile is no longer needed, this indirectly
328     // frees its cache and cookies.
329     profile_->GetOriginalProfile()->DestroyOffTheRecordProfile();
330   }
331 
332   // There may be pending file dialogs, we need to tell them that we've gone
333   // away so they don't try and call back to us.
334   if (select_file_dialog_.get())
335     select_file_dialog_->ListenerDestroyed();
336 
337   TabRestoreServiceDestroyed(tab_restore_service_);
338 }
339 
340 // static
Create(Profile * profile)341 Browser* Browser::Create(Profile* profile) {
342   Browser* browser = new Browser(TYPE_NORMAL, profile);
343   browser->InitBrowserWindow();
344   return browser;
345 }
346 
347 // static
CreateForPopup(Type type,Profile * profile,TabContents * new_contents,const gfx::Rect & initial_bounds)348 Browser* Browser::CreateForPopup(Type type,
349                                  Profile* profile,
350                                  TabContents* new_contents,
351                                  const gfx::Rect& initial_bounds) {
352   DCHECK(type & TYPE_POPUP);
353   Browser* browser = new Browser(type, profile);
354   browser->set_override_bounds(initial_bounds);
355   browser->InitBrowserWindow();
356   TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents);
357   browser->tabstrip_model()->AppendTabContents(wrapper, true);
358   return browser;
359 }
360 
361 // static
CreateForType(Type type,Profile * profile)362 Browser* Browser::CreateForType(Type type, Profile* profile) {
363   Browser* browser = new Browser(type, profile);
364   browser->InitBrowserWindow();
365   return browser;
366 }
367 
368 // static
CreateForApp(const std::string & app_name,const gfx::Size & window_size,Profile * profile,bool is_panel)369 Browser* Browser::CreateForApp(const std::string& app_name,
370                                const gfx::Size& window_size,
371                                Profile* profile,
372                                bool is_panel) {
373   Browser::Type type = TYPE_APP;
374 
375   if (is_panel) {
376     if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) {
377       type = TYPE_APP_PANEL;
378     } else {
379       // TYPE_APP_PANEL is the logical choice.  However, the panel UI
380       // is not fully implemented.  See crbug/55943.
381       type = TYPE_APP_POPUP;
382     }
383   }
384 
385   Browser* browser = new Browser(type, profile);
386   browser->app_name_ = app_name;
387 
388   if (!window_size.IsEmpty()) {
389     gfx::Rect initial_pos(window_size);
390     browser->set_override_bounds(initial_pos);
391   }
392 
393   browser->InitBrowserWindow();
394 
395   return browser;
396 }
397 
398 // static
CreateForDevTools(Profile * profile)399 Browser* Browser::CreateForDevTools(Profile* profile) {
400   Browser* browser = new Browser(TYPE_DEVTOOLS, profile);
401   browser->app_name_ = DevToolsWindow::kDevToolsApp;
402   browser->InitBrowserWindow();
403   return browser;
404 }
405 
InitBrowserWindow()406 void Browser::InitBrowserWindow() {
407   DCHECK(!window_);
408 
409   window_ = CreateBrowserWindow();
410 
411 #if defined(OS_WIN)
412   {
413     // TODO: This might hit the disk
414     //   http://code.google.com/p/chromium/issues/detail?id=61638
415     base::ThreadRestrictions::ScopedAllowIO allow_io;
416 
417     // Set the app user model id for this application to that of the application
418     // name.  See http://crbug.com/7028.
419     app::win::SetAppIdForWindow(
420         type_ & TYPE_APP ?
421         ShellIntegration::GetAppId(UTF8ToWide(app_name_), profile_->GetPath()) :
422         ShellIntegration::GetChromiumAppId(profile_->GetPath()),
423         window()->GetNativeHandle());
424   }
425 #endif
426 
427   NotificationService::current()->Notify(
428       NotificationType::BROWSER_WINDOW_READY,
429       Source<Browser>(this),
430       NotificationService::NoDetails());
431 
432   // Show the First Run information bubble if we've been told to.
433   PrefService* local_state = g_browser_process->local_state();
434   if (!local_state)
435     return;
436   if (local_state->FindPreference(prefs::kShouldShowFirstRunBubble) &&
437       local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
438     FirstRun::BubbleType bubble_type = FirstRun::LARGE_BUBBLE;
439     if (local_state->
440         FindPreference(prefs::kShouldUseOEMFirstRunBubble) &&
441         local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble)) {
442       bubble_type = FirstRun::OEM_BUBBLE;
443     } else if (local_state->
444         FindPreference(prefs::kShouldUseMinimalFirstRunBubble) &&
445         local_state->GetBoolean(prefs::kShouldUseMinimalFirstRunBubble)) {
446       bubble_type = FirstRun::MINIMAL_BUBBLE;
447     }
448     // Reset the preference so we don't show the bubble for subsequent windows.
449     local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
450     window_->GetLocationBar()->ShowFirstRunBubble(bubble_type);
451   }
452   if (local_state->FindPreference(
453       prefs::kAutofillPersonalDataManagerFirstRun) &&
454       local_state->GetBoolean(prefs::kAutofillPersonalDataManagerFirstRun)) {
455     // Notify PDM that this is a first run.
456 #if defined(OS_WIN)
457     ImportAutofillDataWin(profile_->GetPersonalDataManager());
458 #endif  // defined(OS_WIN)
459     // Reset the preference so we don't call it again for subsequent windows.
460     local_state->ClearPref(prefs::kAutofillPersonalDataManagerFirstRun);
461   }
462 }
463 
464 ///////////////////////////////////////////////////////////////////////////////
465 // Getters & Setters
466 
user_data_dir_profiles() const467 const std::vector<std::wstring>& Browser::user_data_dir_profiles() const {
468   return g_browser_process->user_data_dir_profiles();
469 }
470 
set_user_data_dir_profiles(const std::vector<std::wstring> & profiles)471 void Browser::set_user_data_dir_profiles(
472     const std::vector<std::wstring>& profiles) {
473   g_browser_process->user_data_dir_profiles() = profiles;
474 }
475 
GetFindBarController()476 FindBarController* Browser::GetFindBarController() {
477   if (!find_bar_controller_.get()) {
478     FindBar* find_bar = BrowserWindow::CreateFindBar(this);
479     find_bar_controller_.reset(new FindBarController(find_bar));
480     find_bar->SetFindBarController(find_bar_controller_.get());
481     find_bar_controller_->ChangeTabContents(GetSelectedTabContentsWrapper());
482     find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true);
483   }
484   return find_bar_controller_.get();
485 }
486 
HasFindBarController() const487 bool Browser::HasFindBarController() const {
488   return find_bar_controller_.get() != NULL;
489 }
490 
491 ///////////////////////////////////////////////////////////////////////////////
492 // Browser, Creation Helpers:
493 
494 // static
OpenEmptyWindow(Profile * profile)495 void Browser::OpenEmptyWindow(Profile* profile) {
496   Browser* browser = Browser::Create(profile);
497   browser->AddBlankTab(true);
498   browser->window()->Show();
499 }
500 
501 // static
OpenWindowWithRestoredTabs(Profile * profile)502 void Browser::OpenWindowWithRestoredTabs(Profile* profile) {
503   TabRestoreService* service = profile->GetTabRestoreService();
504   if (service)
505     service->RestoreMostRecentEntry(NULL);
506 }
507 
508 // static
OpenURLOffTheRecord(Profile * profile,const GURL & url)509 void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
510   Browser* browser = GetOrCreateTabbedBrowser(
511       profile->GetOffTheRecordProfile());
512   browser->AddSelectedTabWithURL(url, PageTransition::LINK);
513   browser->window()->Show();
514 }
515 
516 // static
OpenApplication(Profile * profile,const Extension * extension,extension_misc::LaunchContainer container,TabContents * existing_tab)517 TabContents* Browser::OpenApplication(
518     Profile* profile,
519     const Extension* extension,
520     extension_misc::LaunchContainer container,
521     TabContents* existing_tab) {
522   TabContents* tab = NULL;
523   ExtensionPrefs* prefs = profile->GetExtensionService()->extension_prefs();
524   prefs->SetActiveBit(extension->id(), true);
525 
526   UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100);
527 
528   switch (container) {
529     case extension_misc::LAUNCH_WINDOW:
530     case extension_misc::LAUNCH_PANEL:
531       tab = Browser::OpenApplicationWindow(profile, extension, container,
532                                            GURL(), NULL);
533       break;
534     case extension_misc::LAUNCH_TAB: {
535       tab = Browser::OpenApplicationTab(profile, extension, existing_tab);
536       break;
537     }
538     default:
539       NOTREACHED();
540       break;
541   }
542   return tab;
543 }
544 
545 // static
OpenApplicationWindow(Profile * profile,const Extension * extension,extension_misc::LaunchContainer container,const GURL & url_input,Browser ** app_browser)546 TabContents* Browser::OpenApplicationWindow(
547     Profile* profile,
548     const Extension* extension,
549     extension_misc::LaunchContainer container,
550     const GURL& url_input,
551     Browser** app_browser) {
552   GURL url;
553   if (!url_input.is_empty()) {
554     if (extension)
555       DCHECK(extension->web_extent().ContainsURL(url_input));
556     url = url_input;
557   } else {
558     DCHECK(extension);  // Empty url and no extension.  Nothing to open.
559     url = extension->GetFullLaunchURL();
560   }
561 
562   std::string app_name;
563   if (extension)
564     app_name =
565         web_app::GenerateApplicationNameFromExtensionId(extension->id());
566   else
567     app_name = web_app::GenerateApplicationNameFromURL(url);
568 
569   RegisterAppPrefs(app_name, profile);
570 
571   bool as_panel = extension && (container == extension_misc::LAUNCH_PANEL);
572 
573   gfx::Size window_size;
574   if (extension)
575     window_size.SetSize(extension->launch_width(),
576                         extension->launch_height());
577 
578   Browser* browser = Browser::CreateForApp(app_name, window_size, profile,
579                                            as_panel);
580 
581   if (app_browser)
582     *app_browser = browser;
583 
584   TabContentsWrapper* wrapper =
585       browser->AddSelectedTabWithURL(url, PageTransition::START_PAGE);
586   TabContents* contents = wrapper->tab_contents();
587   contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
588   contents->render_view_host()->SyncRendererPrefs();
589   browser->window()->Show();
590 
591   // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial
592   //                focus explicitly.
593   contents->view()->SetInitialFocus();
594   return contents;
595 }
596 
OpenAppShortcutWindow(Profile * profile,const GURL & url,bool update_shortcut)597 TabContents* Browser::OpenAppShortcutWindow(Profile* profile,
598                                             const GURL& url,
599                                             bool update_shortcut) {
600   Browser* app_browser;
601   TabContents* tab = OpenApplicationWindow(
602       profile,
603       NULL,  // this is a URL app.  No extension.
604       extension_misc::LAUNCH_WINDOW,
605       url,
606       &app_browser);
607 
608   if (!tab)
609     return NULL;
610 
611   if (update_shortcut) {
612     // Set UPDATE_SHORTCUT as the pending web app action. This action is picked
613     // up in LoadingStateChanged to schedule a GetApplicationInfo. And when
614     // the web app info is available, TabContents notifies Browser via
615     // OnDidGetApplicationInfo, which calls
616     // web_app::UpdateShortcutForTabContents when it sees UPDATE_SHORTCUT as
617     // pending web app action.
618     app_browser->pending_web_app_action_ = UPDATE_SHORTCUT;
619   }
620   return tab;
621 }
622 
623 // static
OpenApplicationTab(Profile * profile,const Extension * extension,TabContents * existing_tab)624 TabContents* Browser::OpenApplicationTab(Profile* profile,
625                                          const Extension* extension,
626                                          TabContents* existing_tab) {
627   Browser* browser =
628       BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL, false);
629   TabContents* contents = NULL;
630   if (!browser)
631     return contents;
632 
633   // Check the prefs for overridden mode.
634   ExtensionService* extensions_service = profile->GetExtensionService();
635   DCHECK(extensions_service);
636 
637   ExtensionPrefs::LaunchType launch_type =
638       extensions_service->extension_prefs()->GetLaunchType(
639           extension->id(), ExtensionPrefs::LAUNCH_DEFAULT);
640   UMA_HISTOGRAM_ENUMERATION("Extensions.AppTabLaunchType", launch_type, 100);
641   int add_type = TabStripModel::ADD_ACTIVE;
642   if (launch_type == ExtensionPrefs::LAUNCH_PINNED)
643     add_type |= TabStripModel::ADD_PINNED;
644 
645   // For extensions lacking launch urls, determine a reasonable fallback.
646   GURL extension_url = extension->GetFullLaunchURL();
647   if (!extension_url.is_valid()) {
648     extension_url = extension->options_url();
649     if (!extension_url.is_valid())
650       extension_url = GURL(chrome::kChromeUIExtensionsURL);
651   }
652 
653   // TODO(erikkay): START_PAGE doesn't seem like the right transition in all
654   // cases.
655   browser::NavigateParams params(browser, extension_url,
656                                  PageTransition::START_PAGE);
657   params.tabstrip_add_types = add_type;
658 
659   // Launch the application in the existing TabContents, if it was supplied.
660   if (existing_tab) {
661     TabStripModel* model = browser->tabstrip_model();
662     int tab_index = model->GetWrapperIndex(existing_tab);
663 
664     existing_tab->OpenURL(extension->GetFullLaunchURL(), existing_tab->GetURL(),
665                           CURRENT_TAB, PageTransition::LINK);
666     if (params.tabstrip_add_types & TabStripModel::ADD_PINNED) {
667       model->SetTabPinned(tab_index, true);
668       tab_index = model->GetWrapperIndex(existing_tab);
669     }
670     if (params.tabstrip_add_types & TabStripModel::ADD_ACTIVE)
671       model->ActivateTabAt(tab_index, true);
672 
673     contents = existing_tab;
674   } else {
675     params.disposition = NEW_FOREGROUND_TAB;
676     browser::Navigate(&params);
677     contents = params.target_contents->tab_contents();
678   }
679 
680   // TODO(skerner):  If we are already in full screen mode, and the user
681   // set the app to open as a regular or pinned tab, what should happen?
682   // Today we open the tab, but stay in full screen mode.  Should we leave
683   // full screen mode in this case?
684   if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN &&
685       !browser->window()->IsFullscreen())
686     browser->ToggleFullscreenMode();
687 
688   return contents;
689 }
690 
691 // static
OpenBookmarkManagerWindow(Profile * profile)692 void Browser::OpenBookmarkManagerWindow(Profile* profile) {
693   Browser* browser = Browser::Create(profile);
694   browser->ShowBookmarkManagerTab();
695   browser->window()->Show();
696 }
697 
698 #if defined(OS_MACOSX)
699 // static
OpenHistoryWindow(Profile * profile)700 void Browser::OpenHistoryWindow(Profile* profile) {
701   Browser* browser = Browser::Create(profile);
702   browser->ShowHistoryTab();
703   browser->window()->Show();
704 }
705 
706 // static
OpenDownloadsWindow(Profile * profile)707 void Browser::OpenDownloadsWindow(Profile* profile) {
708   Browser* browser = Browser::Create(profile);
709   browser->ShowDownloadsTab();
710   browser->window()->Show();
711 }
712 
713 // static
OpenHelpWindow(Profile * profile)714 void Browser::OpenHelpWindow(Profile* profile) {
715   Browser* browser = Browser::Create(profile);
716   browser->OpenHelpTab();
717   browser->window()->Show();
718 }
719 
720 // static
OpenOptionsWindow(Profile * profile)721 void Browser::OpenOptionsWindow(Profile* profile) {
722   Browser* browser = Browser::Create(profile);
723   browser->OpenOptionsDialog();
724   browser->window()->Show();
725 }
726 
727 // static
OpenClearBrowingDataDialogWindow(Profile * profile)728 void Browser::OpenClearBrowingDataDialogWindow(Profile* profile) {
729   Browser* browser = Browser::Create(profile);
730   browser->OpenClearBrowsingDataDialog();
731   browser->window()->Show();
732 }
733 
734 // static
OpenImportSettingsDialogWindow(Profile * profile)735 void Browser::OpenImportSettingsDialogWindow(Profile* profile) {
736   Browser* browser = Browser::Create(profile);
737   browser->OpenImportSettingsDialog();
738   browser->window()->Show();
739 }
740 
741 // static
OpenInstantConfirmDialogWindow(Profile * profile)742 void Browser::OpenInstantConfirmDialogWindow(Profile* profile) {
743   Browser* browser = Browser::Create(profile);
744   browser->OpenInstantConfirmDialog();
745   browser->window()->Show();
746 }
747 #endif
748 
749 // static
OpenExtensionsWindow(Profile * profile)750 void Browser::OpenExtensionsWindow(Profile* profile) {
751   Browser* browser = Browser::Create(profile);
752   browser->ShowExtensionsTab();
753   browser->window()->Show();
754 }
755 
756 
757 ///////////////////////////////////////////////////////////////////////////////
758 // Browser, State Storage and Retrieval for UI:
759 
GetWindowPlacementKey() const760 std::string Browser::GetWindowPlacementKey() const {
761   std::string name(prefs::kBrowserWindowPlacement);
762   if (!app_name_.empty()) {
763     name.append("_");
764     name.append(app_name_);
765   }
766   return name;
767 }
768 
ShouldSaveWindowPlacement() const769 bool Browser::ShouldSaveWindowPlacement() const {
770   // Only save the window placement of popups if they are restored.
771   return (type() & TYPE_POPUP) == 0 || browser_defaults::kRestorePopups;
772 }
773 
SaveWindowPlacement(const gfx::Rect & bounds,bool maximized)774 void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
775   // Save to the session storage service, used when reloading a past session.
776   // Note that we don't want to be the ones who cause lazy initialization of
777   // the session service. This function gets called during initial window
778   // showing, and we don't want to bring in the session service this early.
779   if (profile()->HasSessionService()) {
780     SessionService* session_service = profile()->GetSessionService();
781     if (session_service)
782       session_service->SetWindowBounds(session_id_, bounds, maximized);
783   }
784 }
785 
GetSavedWindowBounds() const786 gfx::Rect Browser::GetSavedWindowBounds() const {
787   const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
788   bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
789   bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
790   if (record_mode || playback_mode) {
791     // In playback/record mode we always fix the size of the browser and
792     // move it to (0,0).  The reason for this is two reasons:  First we want
793     // resize/moves in the playback to still work, and Second we want
794     // playbacks to work (as much as possible) on machines w/ different
795     // screen sizes.
796     return gfx::Rect(0, 0, 800, 600);
797   }
798 
799   gfx::Rect restored_bounds = override_bounds_;
800   bool maximized;
801   WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, this,
802                                       &restored_bounds, &maximized);
803   return restored_bounds;
804 }
805 
806 // TODO(beng): obtain maximized state some other way so we don't need to go
807 //             through all this hassle.
GetSavedMaximizedState() const808 bool Browser::GetSavedMaximizedState() const {
809   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized))
810     return true;
811 
812   if (maximized_state_ == MAXIMIZED_STATE_MAXIMIZED)
813     return true;
814   if (maximized_state_ == MAXIMIZED_STATE_UNMAXIMIZED)
815     return false;
816 
817   // An explicit maximized state was not set. Query the window sizer.
818   gfx::Rect restored_bounds;
819   bool maximized = false;
820   WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, this,
821                                       &restored_bounds, &maximized);
822   return maximized;
823 }
824 
GetCurrentPageIcon() const825 SkBitmap Browser::GetCurrentPageIcon() const {
826   TabContents* contents = GetSelectedTabContents();
827   // |contents| can be NULL since GetCurrentPageIcon() is called by the window
828   // during the window's creation (before tabs have been added).
829   return contents ? contents->GetFavicon() : SkBitmap();
830 }
831 
GetWindowTitleForCurrentTab() const832 string16 Browser::GetWindowTitleForCurrentTab() const {
833   TabContents* contents = GetSelectedTabContents();
834   string16 title;
835 
836   // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the
837   // window during the window's creation (before tabs have been added).
838   if (contents) {
839     title = contents->GetTitle();
840     FormatTitleForDisplay(&title);
841   }
842   if (title.empty())
843     title = TabContentsWrapper::GetDefaultTitle();
844 
845 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
846   // On Mac or ChromeOS, we don't want to suffix the page title with
847   // the application name.
848   return title;
849 #elif defined(OS_WIN) || defined(OS_LINUX)
850   int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT;
851   // Don't append the app name to window titles on app frames and app popups
852   if (type_ & TYPE_APP)
853     string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO;
854   return l10n_util::GetStringFUTF16(string_id, title);
855 #endif
856 }
857 
858 // static
FormatTitleForDisplay(string16 * title)859 void Browser::FormatTitleForDisplay(string16* title) {
860   size_t current_index = 0;
861   size_t match_index;
862   while ((match_index = title->find(L'\n', current_index)) != string16::npos) {
863     title->replace(match_index, 1, string16());
864     current_index = match_index;
865   }
866 }
867 
868 ///////////////////////////////////////////////////////////////////////////////
869 // Browser, OnBeforeUnload handling:
870 
TabsNeedBeforeUnloadFired()871 bool Browser::TabsNeedBeforeUnloadFired() {
872   if (tabs_needing_before_unload_fired_.empty()) {
873     for (int i = 0; i < tab_count(); ++i) {
874       TabContents* contents = GetTabContentsAt(i);
875       if (contents->NeedToFireBeforeUnload())
876         tabs_needing_before_unload_fired_.insert(contents);
877     }
878   }
879   return !tabs_needing_before_unload_fired_.empty();
880 }
881 
ShouldCloseWindow()882 bool Browser::ShouldCloseWindow() {
883   if (!CanCloseWithInProgressDownloads())
884     return false;
885 
886   if (HasCompletedUnloadProcessing())
887     return IsClosingPermitted();
888 
889   is_attempting_to_close_browser_ = true;
890 
891   if (!TabsNeedBeforeUnloadFired())
892     return IsClosingPermitted();
893 
894   ProcessPendingTabs();
895   return false;
896 }
897 
OnWindowClosing()898 void Browser::OnWindowClosing() {
899   if (!ShouldCloseWindow())
900     return;
901 
902   bool exiting = false;
903 
904   // Application should shutdown on last window close if the user is explicitly
905   // trying to quit, or if there is nothing keeping the browser alive (such as
906   // AppController on the Mac, or BackgroundContentsService for background
907   // pages).
908   bool should_quit_if_last_browser =
909       browser_shutdown::IsTryingToQuit() || !BrowserList::WillKeepAlive();
910 
911   if (should_quit_if_last_browser && BrowserList::size() == 1) {
912     browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
913     exiting = true;
914   }
915 
916   // Don't use HasSessionService here, we want to force creation of the
917   // session service so that user can restore what was open.
918   SessionService* session_service = profile()->GetSessionService();
919   if (session_service)
920     session_service->WindowClosing(session_id());
921 
922   TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
923   if (tab_restore_service && type() == TYPE_NORMAL && tab_count())
924     tab_restore_service->BrowserClosing(tab_restore_service_delegate());
925 
926   // TODO(sky): convert session/tab restore to use notification.
927   NotificationService::current()->Notify(
928       NotificationType::BROWSER_CLOSING,
929       Source<Browser>(this),
930       Details<bool>(&exiting));
931 
932   CloseAllTabs();
933 }
934 
935 ////////////////////////////////////////////////////////////////////////////////
936 // In-progress download termination handling:
937 
InProgressDownloadResponse(bool cancel_downloads)938 void Browser::InProgressDownloadResponse(bool cancel_downloads) {
939   if (cancel_downloads) {
940     cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
941     CloseWindow();
942     return;
943   }
944 
945   // Sets the confirmation state to NOT_PROMPTED so that if the user tries to
946   // close again we'll show the warning again.
947   cancel_download_confirmation_state_ = NOT_PROMPTED;
948 
949   // Show the download page so the user can figure-out what downloads are still
950   // in-progress.
951   ShowDownloadsTab();
952 }
953 
954 ////////////////////////////////////////////////////////////////////////////////
955 // Browser, TabStripModel pass-thrus:
956 
tab_count() const957 int Browser::tab_count() const {
958   return tab_handler_->GetTabStripModel()->count();
959 }
960 
active_index() const961 int Browser::active_index() const {
962   return tab_handler_->GetTabStripModel()->active_index();
963 }
964 
GetIndexOfController(const NavigationController * controller) const965 int Browser::GetIndexOfController(
966     const NavigationController* controller) const {
967   return tab_handler_->GetTabStripModel()->GetIndexOfController(controller);
968 }
969 
GetSelectedTabContentsWrapper() const970 TabContentsWrapper* Browser::GetSelectedTabContentsWrapper() const {
971   return tabstrip_model()->GetSelectedTabContents();
972 }
GetTabContentsWrapperAt(int index) const973 TabContentsWrapper* Browser::GetTabContentsWrapperAt(int index) const {
974   return tabstrip_model()->GetTabContentsAt(index);
975 }
976 
GetSelectedTabContents() const977 TabContents* Browser::GetSelectedTabContents() const {
978   TabContentsWrapper* wrapper = GetSelectedTabContentsWrapper();
979   if (wrapper)
980     return wrapper->tab_contents();
981   return NULL;
982 }
983 
GetTabContentsAt(int index) const984 TabContents* Browser::GetTabContentsAt(int index) const {
985   TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index);
986   if (wrapper)
987     return wrapper->tab_contents();
988   return NULL;
989 }
990 
ActivateTabAt(int index,bool user_gesture)991 void Browser::ActivateTabAt(int index, bool user_gesture) {
992   tab_handler_->GetTabStripModel()->ActivateTabAt(index, user_gesture);
993 }
994 
IsTabPinned(int index) const995 bool Browser::IsTabPinned(int index) const {
996   return tabstrip_model()->IsTabPinned(index);
997 }
998 
CloseAllTabs()999 void Browser::CloseAllTabs() {
1000   tab_handler_->GetTabStripModel()->CloseAllTabs();
1001 }
1002 
1003 ////////////////////////////////////////////////////////////////////////////////
1004 // Browser, Tab adding/showing functions:
1005 
IsTabStripEditable() const1006 bool Browser::IsTabStripEditable() const {
1007   return window()->IsTabStripEditable();
1008 }
1009 
GetIndexForInsertionDuringRestore(int relative_index)1010 int Browser::GetIndexForInsertionDuringRestore(int relative_index) {
1011   return (tab_handler_->GetTabStripModel()->insertion_policy() ==
1012       TabStripModel::INSERT_AFTER) ? tab_count() : relative_index;
1013 }
1014 
AddSelectedTabWithURL(const GURL & url,PageTransition::Type transition)1015 TabContentsWrapper* Browser::AddSelectedTabWithURL(const GURL& url,
1016                                             PageTransition::Type transition) {
1017   browser::NavigateParams params(this, url, transition);
1018   params.disposition = NEW_FOREGROUND_TAB;
1019   browser::Navigate(&params);
1020   return params.target_contents;
1021 }
1022 
AddTab(TabContentsWrapper * tab_contents,PageTransition::Type type)1023 TabContents* Browser::AddTab(TabContentsWrapper* tab_contents,
1024                              PageTransition::Type type) {
1025   tab_handler_->GetTabStripModel()->AddTabContents(
1026       tab_contents, -1, type, TabStripModel::ADD_ACTIVE);
1027   return tab_contents->tab_contents();
1028 }
1029 
AddTabContents(TabContents * new_contents,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture)1030 void Browser::AddTabContents(TabContents* new_contents,
1031                              WindowOpenDisposition disposition,
1032                              const gfx::Rect& initial_pos,
1033                              bool user_gesture) {
1034   AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture);
1035 }
1036 
CloseTabContents(TabContents * contents)1037 void Browser::CloseTabContents(TabContents* contents) {
1038   CloseContents(contents);
1039 }
1040 
BrowserShowHtmlDialog(HtmlDialogUIDelegate * delegate,gfx::NativeWindow parent_window)1041 void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate,
1042                                     gfx::NativeWindow parent_window) {
1043   ShowHtmlDialog(delegate, parent_window);
1044 }
1045 
BrowserRenderWidgetShowing()1046 void Browser::BrowserRenderWidgetShowing() {
1047   RenderWidgetShowing();
1048 }
1049 
BookmarkBarSizeChanged(bool is_animating)1050 void Browser::BookmarkBarSizeChanged(bool is_animating) {
1051   window_->ToolbarSizeChanged(is_animating);
1052 }
1053 
AddRestoredTab(const std::vector<TabNavigation> & navigations,int tab_index,int selected_navigation,const std::string & extension_app_id,bool select,bool pin,bool from_last_session,SessionStorageNamespace * session_storage_namespace)1054 TabContents* Browser::AddRestoredTab(
1055     const std::vector<TabNavigation>& navigations,
1056     int tab_index,
1057     int selected_navigation,
1058     const std::string& extension_app_id,
1059     bool select,
1060     bool pin,
1061     bool from_last_session,
1062     SessionStorageNamespace* session_storage_namespace) {
1063   TabContentsWrapper* wrapper = TabContentsFactory(profile(), NULL,
1064       MSG_ROUTING_NONE,
1065       GetSelectedTabContents(),
1066       session_storage_namespace);
1067   TabContents* new_tab = wrapper->tab_contents();
1068   wrapper->extension_tab_helper()->SetExtensionAppById(extension_app_id);
1069   new_tab->controller().RestoreFromState(navigations, selected_navigation,
1070                                          from_last_session);
1071 
1072   int add_types = select ? TabStripModel::ADD_ACTIVE :
1073       TabStripModel::ADD_NONE;
1074   if (pin) {
1075     tab_index = std::min(tab_index, tabstrip_model()->IndexOfFirstNonMiniTab());
1076     add_types |= TabStripModel::ADD_PINNED;
1077   }
1078   tab_handler_->GetTabStripModel()->InsertTabContentsAt(tab_index, wrapper,
1079                                                         add_types);
1080   if (select) {
1081     window_->Activate();
1082   } else {
1083     // We set the size of the view here, before WebKit does its initial
1084     // layout.  If we don't, the initial layout of background tabs will be
1085     // performed with a view width of 0, which may cause script outputs and
1086     // anchor link location calculations to be incorrect even after a new
1087     // layout with proper view dimensions. TabStripModel::AddTabContents()
1088     // contains similar logic.
1089     new_tab->view()->SizeContents(window_->GetRestoredBounds().size());
1090     new_tab->HideContents();
1091   }
1092   if (profile_->HasSessionService()) {
1093     SessionService* session_service = profile_->GetSessionService();
1094     if (session_service)
1095       session_service->TabRestored(&new_tab->controller(), pin);
1096   }
1097   return new_tab;
1098 }
1099 
ReplaceRestoredTab(const std::vector<TabNavigation> & navigations,int selected_navigation,bool from_last_session,const std::string & extension_app_id,SessionStorageNamespace * session_storage_namespace)1100 void Browser::ReplaceRestoredTab(
1101     const std::vector<TabNavigation>& navigations,
1102     int selected_navigation,
1103     bool from_last_session,
1104     const std::string& extension_app_id,
1105     SessionStorageNamespace* session_storage_namespace) {
1106   TabContentsWrapper* wrapper = TabContentsFactory(profile(), NULL,
1107       MSG_ROUTING_NONE,
1108       GetSelectedTabContents(),
1109       session_storage_namespace);
1110   wrapper->extension_tab_helper()->SetExtensionAppById(extension_app_id);
1111   TabContents* replacement = wrapper->tab_contents();
1112   replacement->controller().RestoreFromState(navigations, selected_navigation,
1113                                              from_last_session);
1114 
1115   tab_handler_->GetTabStripModel()->ReplaceNavigationControllerAt(
1116       tab_handler_->GetTabStripModel()->active_index(),
1117       wrapper);
1118 }
1119 
CanRestoreTab()1120 bool Browser::CanRestoreTab() {
1121   return command_updater_.IsCommandEnabled(IDC_RESTORE_TAB);
1122 }
1123 
NavigateToIndexWithDisposition(int index,WindowOpenDisposition disp)1124 bool Browser::NavigateToIndexWithDisposition(int index,
1125                                              WindowOpenDisposition disp) {
1126   NavigationController& controller =
1127       GetOrCloneTabForDisposition(disp)->controller();
1128   if (index < 0 || index >= controller.entry_count())
1129     return false;
1130   controller.GoToIndex(index);
1131   return true;
1132 }
1133 
GetSingletonTabNavigateParams(const GURL & url)1134 browser::NavigateParams Browser::GetSingletonTabNavigateParams(
1135     const GURL& url) {
1136   browser::NavigateParams params(this, url, PageTransition::AUTO_BOOKMARK);
1137   params.disposition = SINGLETON_TAB;
1138   params.window_action = browser::NavigateParams::SHOW_WINDOW;
1139   return params;
1140 }
1141 
ShowSingletonTab(const GURL & url)1142 void Browser::ShowSingletonTab(const GURL& url) {
1143   browser::NavigateParams params(GetSingletonTabNavigateParams(url));
1144   browser::Navigate(&params);
1145 }
1146 
UpdateCommandsForFullscreenMode(bool is_fullscreen)1147 void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) {
1148 #if !defined(OS_MACOSX)
1149   const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen;
1150 #else
1151   const bool show_main_ui = (type() == TYPE_NORMAL);
1152 #endif
1153 
1154   bool main_not_fullscreen_or_popup =
1155       show_main_ui && !is_fullscreen && (type() & TYPE_POPUP) == 0;
1156 
1157   // Navigation commands
1158   command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
1159 
1160   // Window management commands
1161   command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB,
1162       (type() & TYPE_POPUP) && !is_fullscreen);
1163 
1164   // Focus various bits of UI
1165   command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
1166   command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui);
1167   command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
1168   command_updater_.UpdateCommandEnabled(
1169       IDC_FOCUS_MENU_BAR, main_not_fullscreen_or_popup);
1170   command_updater_.UpdateCommandEnabled(
1171       IDC_FOCUS_NEXT_PANE, main_not_fullscreen_or_popup);
1172   command_updater_.UpdateCommandEnabled(
1173       IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen_or_popup);
1174   command_updater_.UpdateCommandEnabled(
1175       IDC_FOCUS_BOOKMARKS, main_not_fullscreen_or_popup);
1176   command_updater_.UpdateCommandEnabled(
1177       IDC_FOCUS_CHROMEOS_STATUS, main_not_fullscreen_or_popup);
1178 
1179   // Show various bits of UI
1180   command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
1181   command_updater_.UpdateCommandEnabled(IDC_FEEDBACK, show_main_ui);
1182   command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR,
1183       browser_defaults::bookmarks_enabled && show_main_ui);
1184   command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui);
1185   command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS,
1186       show_main_ui && profile_->IsSyncAccessible());
1187 
1188   command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui);
1189   command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
1190   command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
1191   command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
1192   command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui);
1193   command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, show_main_ui);
1194 #if defined (ENABLE_PROFILING) && !defined(NO_TCMALLOC)
1195   command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui);
1196 #endif
1197 }
1198 
1199 ///////////////////////////////////////////////////////////////////////////////
1200 // Browser, Assorted browser commands:
1201 
ShouldOpenNewTabForWindowDisposition(WindowOpenDisposition disposition)1202 bool Browser::ShouldOpenNewTabForWindowDisposition(
1203     WindowOpenDisposition disposition) {
1204   return (disposition == NEW_FOREGROUND_TAB ||
1205           disposition == NEW_BACKGROUND_TAB);
1206 }
1207 
GetOrCloneTabForDisposition(WindowOpenDisposition disposition)1208 TabContents* Browser::GetOrCloneTabForDisposition(
1209        WindowOpenDisposition disposition) {
1210   TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper();
1211   if (ShouldOpenNewTabForWindowDisposition(disposition)) {
1212     current_tab = current_tab->Clone();
1213     tab_handler_->GetTabStripModel()->AddTabContents(
1214         current_tab, -1, PageTransition::LINK,
1215         disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE :
1216                                             TabStripModel::ADD_NONE);
1217   }
1218   return current_tab->tab_contents();
1219 }
1220 
UpdateTabStripModelInsertionPolicy()1221 void Browser::UpdateTabStripModelInsertionPolicy() {
1222   tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ?
1223       TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER);
1224 }
1225 
UseVerticalTabsChanged()1226 void Browser::UseVerticalTabsChanged() {
1227   UpdateTabStripModelInsertionPolicy();
1228   window()->ToggleTabStripMode();
1229 }
1230 
SupportsWindowFeatureImpl(WindowFeature feature,bool check_fullscreen) const1231 bool Browser::SupportsWindowFeatureImpl(WindowFeature feature,
1232                                         bool check_fullscreen) const {
1233   // On Mac, fullscreen mode has most normal things (in a slide-down panel). On
1234   // other platforms, we hide some controls when in fullscreen mode.
1235   bool hide_ui_for_fullscreen = false;
1236 #if !defined(OS_MACOSX)
1237   hide_ui_for_fullscreen = check_fullscreen && window_ &&
1238       window_->IsFullscreen();
1239 #endif
1240 
1241   unsigned int features = FEATURE_INFOBAR | FEATURE_SIDEBAR;
1242 
1243 #if !defined(OS_CHROMEOS)
1244   // Chrome OS opens a FileBrowse pop up instead of using download shelf.
1245   // So FEATURE_DOWNLOADSHELF is only added for non-chromeos platforms.
1246   features |= FEATURE_DOWNLOADSHELF;
1247 #endif  // !defined(OS_CHROMEOS)
1248 
1249   if (type() == TYPE_NORMAL) {
1250     features |= FEATURE_BOOKMARKBAR;
1251   }
1252 
1253   if (!hide_ui_for_fullscreen) {
1254     if (type() != TYPE_NORMAL)
1255       features |= FEATURE_TITLEBAR;
1256 
1257     if (type() == TYPE_NORMAL)
1258       features |= FEATURE_TABSTRIP;
1259 
1260     if (type() == TYPE_NORMAL)
1261       features |= FEATURE_TOOLBAR;
1262 
1263     if ((type() & Browser::TYPE_APP) == 0)
1264       features |= FEATURE_LOCATIONBAR;
1265   }
1266   return !!(features & feature);
1267 }
1268 
IsClosingPermitted()1269 bool Browser::IsClosingPermitted() {
1270   TabCloseableStateWatcher* watcher =
1271       g_browser_process->tab_closeable_state_watcher();
1272   bool can_close = !watcher || watcher->CanCloseBrowser(this);
1273   if (!can_close && is_attempting_to_close_browser_)
1274     CancelWindowClose();
1275   return can_close;
1276 }
1277 
GoBack(WindowOpenDisposition disposition)1278 void Browser::GoBack(WindowOpenDisposition disposition) {
1279   UserMetrics::RecordAction(UserMetricsAction("Back"), profile_);
1280 
1281   TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper();
1282   if (current_tab->controller().CanGoBack()) {
1283     TabContents* new_tab = GetOrCloneTabForDisposition(disposition);
1284     // If we are on an interstitial page and clone the tab, it won't be copied
1285     // to the new tab, so we don't need to go back.
1286     if (current_tab->tab_contents()->showing_interstitial_page() &&
1287         (new_tab != current_tab->tab_contents()))
1288       return;
1289     new_tab->controller().GoBack();
1290   }
1291 }
1292 
GoForward(WindowOpenDisposition disposition)1293 void Browser::GoForward(WindowOpenDisposition disposition) {
1294   UserMetrics::RecordAction(UserMetricsAction("Forward"), profile_);
1295   if (GetSelectedTabContentsWrapper()->controller().CanGoForward())
1296     GetOrCloneTabForDisposition(disposition)->controller().GoForward();
1297 }
1298 
Reload(WindowOpenDisposition disposition)1299 void Browser::Reload(WindowOpenDisposition disposition) {
1300   UserMetrics::RecordAction(UserMetricsAction("Reload"), profile_);
1301   ReloadInternal(disposition, false);
1302 }
1303 
ReloadIgnoringCache(WindowOpenDisposition disposition)1304 void Browser::ReloadIgnoringCache(WindowOpenDisposition disposition) {
1305   UserMetrics::RecordAction(UserMetricsAction("ReloadIgnoringCache"), profile_);
1306   ReloadInternal(disposition, true);
1307 }
1308 
ReloadInternal(WindowOpenDisposition disposition,bool ignore_cache)1309 void Browser::ReloadInternal(WindowOpenDisposition disposition,
1310                              bool ignore_cache) {
1311   // If we are showing an interstitial, treat this as an OpenURL.
1312   TabContents* current_tab = GetSelectedTabContents();
1313   if (current_tab && current_tab->showing_interstitial_page()) {
1314     NavigationEntry* entry = current_tab->controller().GetActiveEntry();
1315     DCHECK(entry);  // Should exist if interstitial is showing.
1316     OpenURL(entry->url(), GURL(), disposition, PageTransition::RELOAD);
1317     return;
1318   }
1319 
1320   // As this is caused by a user action, give the focus to the page.
1321   TabContents* tab = GetOrCloneTabForDisposition(disposition);
1322   if (!tab->FocusLocationBarByDefault())
1323     tab->Focus();
1324   if (ignore_cache)
1325     tab->controller().ReloadIgnoringCache(true);
1326   else
1327     tab->controller().Reload(true);
1328 }
1329 
Home(WindowOpenDisposition disposition)1330 void Browser::Home(WindowOpenDisposition disposition) {
1331   UserMetrics::RecordAction(UserMetricsAction("Home"), profile_);
1332   OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
1333 }
1334 
OpenCurrentURL()1335 void Browser::OpenCurrentURL() {
1336   UserMetrics::RecordAction(UserMetricsAction("LoadURL"), profile_);
1337   LocationBar* location_bar = window_->GetLocationBar();
1338   if (!location_bar)
1339     return;
1340 
1341   WindowOpenDisposition open_disposition =
1342       location_bar->GetWindowOpenDisposition();
1343   if (OpenInstant(open_disposition))
1344     return;
1345 
1346   GURL url(WideToUTF8(location_bar->GetInputString()));
1347 
1348   if (open_disposition == CURRENT_TAB && TabFinder::IsEnabled()) {
1349     Browser* existing_browser = NULL;
1350     TabContents* existing_tab = TabFinder::GetInstance()->FindTab(
1351         this, url, &existing_browser);
1352     if (existing_tab) {
1353       existing_browser->ActivateContents(existing_tab);
1354       return;
1355     }
1356   }
1357 
1358   browser::NavigateParams params(this, url, location_bar->GetPageTransition());
1359   params.disposition = open_disposition;
1360   // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
1361   // inherit the opener. In some cases the tabstrip will determine the group
1362   // should be inherited, in which case the group is inherited instead of the
1363   // opener.
1364   params.tabstrip_add_types =
1365       TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER;
1366   browser::Navigate(&params);
1367 
1368   DCHECK(profile_->GetExtensionService());
1369   if (profile_->GetExtensionService()->IsInstalledApp(url)) {
1370     UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram,
1371                               extension_misc::APP_LAUNCH_OMNIBOX_LOCATION,
1372                               extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
1373   }
1374 }
1375 
Stop()1376 void Browser::Stop() {
1377   UserMetrics::RecordAction(UserMetricsAction("Stop"), profile_);
1378   GetSelectedTabContentsWrapper()->tab_contents()->Stop();
1379 }
1380 
NewWindow()1381 void Browser::NewWindow() {
1382   if (browser_defaults::kAlwaysOpenIncognitoWindow &&
1383       CommandLine::ForCurrentProcess()->HasSwitch(switches::kIncognito) &&
1384       incognito_mode_allowed_.GetValue()) {
1385     NewIncognitoWindow();
1386     return;
1387   }
1388   UserMetrics::RecordAction(UserMetricsAction("NewWindow"), profile_);
1389   SessionService* session_service =
1390       profile_->GetOriginalProfile()->GetSessionService();
1391   if (!session_service ||
1392       !session_service->RestoreIfNecessary(std::vector<GURL>())) {
1393     Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
1394   }
1395 }
1396 
NewIncognitoWindow()1397 void Browser::NewIncognitoWindow() {
1398   if (!incognito_mode_allowed_.GetValue()) {
1399     NewWindow();
1400     return;
1401   }
1402 
1403   UserMetrics::RecordAction(UserMetricsAction("NewIncognitoWindow"), profile_);
1404   Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
1405 }
1406 
CloseWindow()1407 void Browser::CloseWindow() {
1408   UserMetrics::RecordAction(UserMetricsAction("CloseWindow"), profile_);
1409   window_->Close();
1410 }
1411 
NewTab()1412 void Browser::NewTab() {
1413   UserMetrics::RecordAction(UserMetricsAction("NewTab"), profile_);
1414 
1415   if (type() == TYPE_NORMAL) {
1416     AddBlankTab(true);
1417     GetSelectedTabContentsWrapper()->view()->RestoreFocus();
1418   } else {
1419     Browser* b = GetOrCreateTabbedBrowser(profile_);
1420     b->AddBlankTab(true);
1421     b->window()->Show();
1422     // The call to AddBlankTab above did not set the focus to the tab as its
1423     // window was not active, so we have to do it explicitly.
1424     // See http://crbug.com/6380.
1425     b->GetSelectedTabContentsWrapper()->view()->RestoreFocus();
1426   }
1427 }
1428 
CloseTab()1429 void Browser::CloseTab() {
1430   UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator"),
1431                             profile_);
1432   if (CanCloseTab())
1433     tab_handler_->GetTabStripModel()->CloseSelectedTabs();
1434 }
1435 
SelectNextTab()1436 void Browser::SelectNextTab() {
1437   UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_);
1438   tab_handler_->GetTabStripModel()->SelectNextTab();
1439 }
1440 
SelectPreviousTab()1441 void Browser::SelectPreviousTab() {
1442   UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_);
1443   tab_handler_->GetTabStripModel()->SelectPreviousTab();
1444 }
1445 
OpenTabpose()1446 void Browser::OpenTabpose() {
1447 #if defined(OS_MACOSX)
1448   if (!CommandLine::ForCurrentProcess()->HasSwitch(
1449         switches::kEnableExposeForTabs)) {
1450     return;
1451   }
1452 
1453   UserMetrics::RecordAction(UserMetricsAction("OpenTabpose"), profile_);
1454   window()->OpenTabpose();
1455 #else
1456   NOTREACHED();
1457 #endif
1458 }
1459 
MoveTabNext()1460 void Browser::MoveTabNext() {
1461   UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_);
1462   tab_handler_->GetTabStripModel()->MoveTabNext();
1463 }
1464 
MoveTabPrevious()1465 void Browser::MoveTabPrevious() {
1466   UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_);
1467   tab_handler_->GetTabStripModel()->MoveTabPrevious();
1468 }
1469 
SelectNumberedTab(int index)1470 void Browser::SelectNumberedTab(int index) {
1471   if (index < tab_count()) {
1472     UserMetrics::RecordAction(UserMetricsAction("SelectNumberedTab"),
1473                               profile_);
1474     tab_handler_->GetTabStripModel()->ActivateTabAt(index, true);
1475   }
1476 }
1477 
SelectLastTab()1478 void Browser::SelectLastTab() {
1479   UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_);
1480   tab_handler_->GetTabStripModel()->SelectLastTab();
1481 }
1482 
DuplicateTab()1483 void Browser::DuplicateTab() {
1484   UserMetrics::RecordAction(UserMetricsAction("Duplicate"), profile_);
1485   DuplicateContentsAt(active_index());
1486 }
1487 
RestoreTab()1488 void Browser::RestoreTab() {
1489   UserMetrics::RecordAction(UserMetricsAction("RestoreTab"), profile_);
1490   TabRestoreService* service = profile_->GetTabRestoreService();
1491   if (!service)
1492     return;
1493 
1494   service->RestoreMostRecentEntry(tab_restore_service_delegate());
1495 }
1496 
WriteCurrentURLToClipboard()1497 void Browser::WriteCurrentURLToClipboard() {
1498   // TODO(ericu): There isn't currently a metric for this.  Should there be?
1499   // We don't appear to track the action when it comes from the
1500   // RenderContextViewMenu.
1501 
1502   TabContents* contents = GetSelectedTabContents();
1503   if (!contents->ShouldDisplayURL())
1504     return;
1505 
1506   chrome_browser_net::WriteURLToClipboard(
1507       contents->GetURL(),
1508       profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
1509       g_browser_process->clipboard());
1510 }
1511 
ConvertPopupToTabbedBrowser()1512 void Browser::ConvertPopupToTabbedBrowser() {
1513   UserMetrics::RecordAction(UserMetricsAction("ShowAsTab"), profile_);
1514   int tab_strip_index = tab_handler_->GetTabStripModel()->active_index();
1515   TabContentsWrapper* contents =
1516       tab_handler_->GetTabStripModel()->DetachTabContentsAt(tab_strip_index);
1517   Browser* browser = Browser::Create(profile_);
1518   browser->tabstrip_model()->AppendTabContents(contents, true);
1519   browser->window()->Show();
1520 }
1521 
ToggleFullscreenMode()1522 void Browser::ToggleFullscreenMode() {
1523 #if !defined(OS_MACOSX)
1524   // In kiosk mode, we always want to be fullscreen. When the browser first
1525   // starts we're not yet fullscreen, so let the initial toggle go through.
1526   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode) &&
1527       window_->IsFullscreen())
1528     return;
1529 #endif
1530 
1531   UserMetrics::RecordAction(UserMetricsAction("ToggleFullscreen"), profile_);
1532   window_->SetFullscreen(!window_->IsFullscreen());
1533   // On Linux, setting fullscreen mode is an async call to the X server, which
1534   // may or may not support fullscreen mode.
1535 #if !defined(OS_LINUX)
1536   UpdateCommandsForFullscreenMode(window_->IsFullscreen());
1537 #endif
1538 }
1539 
1540 #if defined(OS_CHROMEOS)
Search()1541 void Browser::Search() {
1542   // If the NTP is showing, close it.
1543   if (StartsWithASCII(GetSelectedTabContents()->GetURL().spec(),
1544                        chrome::kChromeUINewTabURL, true)) {
1545     CloseTab();
1546     return;
1547   }
1548 
1549   // Exit fullscreen to show omnibox.
1550   if (window_->IsFullscreen()) {
1551     ToggleFullscreenMode();
1552     // ToggleFullscreenMode is asynchronous, so we don't have omnibox
1553     // visible at this point. Wait for next event cycle which toggles
1554     // the visibility of omnibox before creating new tab.
1555     MessageLoop::current()->PostTask(
1556         FROM_HERE, method_factory_.NewRunnableMethod(&Browser::Search));
1557     return;
1558   }
1559 
1560   // Otherwise just open it.
1561   NewTab();
1562 }
1563 
ShowKeyboardOverlay()1564 void Browser::ShowKeyboardOverlay() {
1565   window_->ShowKeyboardOverlay(window_->GetNativeHandle());
1566 }
1567 #endif
1568 
Exit()1569 void Browser::Exit() {
1570   UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
1571 #if defined(OS_CHROMEOS)
1572   chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false);
1573   // Write /tmp/uptime-logout-started as well.
1574   const char kLogoutStarted[] = "logout-started";
1575   chromeos::BootTimesLoader::Get()->RecordCurrentStats(kLogoutStarted);
1576 
1577   // Login screen should show up in owner's locale.
1578   PrefService* state = g_browser_process->local_state();
1579   if (state) {
1580     std::string owner_locale = state->GetString(prefs::kOwnerLocale);
1581     if (!owner_locale.empty() &&
1582         state->GetString(prefs::kApplicationLocale) != owner_locale &&
1583         !state->IsManagedPreference(prefs::kApplicationLocale)) {
1584       state->SetString(prefs::kApplicationLocale, owner_locale);
1585       state->ScheduleSavePersistentPrefs();
1586     }
1587   }
1588 #endif
1589   BrowserList::Exit();
1590 }
1591 
BookmarkCurrentPage()1592 void Browser::BookmarkCurrentPage() {
1593   UserMetrics::RecordAction(UserMetricsAction("Star"), profile_);
1594 
1595   BookmarkModel* model = profile()->GetBookmarkModel();
1596   if (!model || !model->IsLoaded())
1597     return;  // Ignore requests until bookmarks are loaded.
1598 
1599   GURL url;
1600   string16 title;
1601   TabContents* tab = GetSelectedTabContents();
1602   bookmark_utils::GetURLAndTitleToBookmark(tab, &url, &title);
1603   bool was_bookmarked = model->IsBookmarked(url);
1604   if (!was_bookmarked && profile_->IsOffTheRecord()) {
1605     // If we're incognito the favicon may not have been saved. Save it now
1606     // so that bookmarks have an icon for the page.
1607     tab->SaveFavicon();
1608   }
1609   model->SetURLStarred(url, title, true);
1610   // Make sure the model actually added a bookmark before showing the star. A
1611   // bookmark isn't created if the url is invalid.
1612   if (window_->IsActive() && model->IsBookmarked(url)) {
1613     // Only show the bubble if the window is active, otherwise we may get into
1614     // weird situations were the bubble is deleted as soon as it is shown.
1615     window_->ShowBookmarkBubble(url, was_bookmarked);
1616   }
1617 }
1618 
SavePage()1619 void Browser::SavePage() {
1620   UserMetrics::RecordAction(UserMetricsAction("SavePage"), profile_);
1621   TabContents* current_tab = GetSelectedTabContents();
1622   if (current_tab && current_tab->contents_mime_type() == "application/pdf")
1623     UserMetrics::RecordAction(UserMetricsAction("PDF.SavePage"), profile_);
1624   GetSelectedTabContentsWrapper()->download_tab_helper()->OnSavePage();
1625 }
1626 
ViewSelectedSource()1627 void Browser::ViewSelectedSource() {
1628   ViewSource(GetSelectedTabContentsWrapper());
1629 }
1630 
ShowFindBar()1631 void Browser::ShowFindBar() {
1632   GetFindBarController()->Show();
1633 }
1634 
SupportsWindowFeature(WindowFeature feature) const1635 bool Browser::SupportsWindowFeature(WindowFeature feature) const {
1636   return SupportsWindowFeatureImpl(feature, true);
1637 }
1638 
CanSupportWindowFeature(WindowFeature feature) const1639 bool Browser::CanSupportWindowFeature(WindowFeature feature) const {
1640   return SupportsWindowFeatureImpl(feature, false);
1641 }
1642 
EmailPageLocation()1643 void Browser::EmailPageLocation() {
1644   UserMetrics::RecordAction(UserMetricsAction("EmailPageLocation"), profile_);
1645   GetSelectedTabContents()->EmailPageLocation();
1646 }
1647 
Print()1648 void Browser::Print() {
1649   UserMetrics::RecordAction(UserMetricsAction("PrintPreview"), profile_);
1650   if (CommandLine::ForCurrentProcess()->HasSwitch(
1651       switches::kEnablePrintPreview)) {
1652     printing::PrintPreviewTabController::PrintPreview(
1653         GetSelectedTabContents());
1654   } else {
1655     GetSelectedTabContentsWrapper()->print_view_manager()->PrintNow();
1656   }
1657 }
1658 
ToggleEncodingAutoDetect()1659 void Browser::ToggleEncodingAutoDetect() {
1660   UserMetrics::RecordAction(UserMetricsAction("AutoDetectChange"), profile_);
1661   encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
1662   // If "auto detect" is turned on, then any current override encoding
1663   // is cleared. This also implicitly performs a reload.
1664   // OTOH, if "auto detect" is turned off, we don't change the currently
1665   // active encoding.
1666   if (encoding_auto_detect_.GetValue()) {
1667     TabContents* contents = GetSelectedTabContents();
1668     if (contents)
1669       contents->ResetOverrideEncoding();
1670   }
1671 }
1672 
OverrideEncoding(int encoding_id)1673 void Browser::OverrideEncoding(int encoding_id) {
1674   UserMetrics::RecordAction(UserMetricsAction("OverrideEncoding"), profile_);
1675   const std::string selected_encoding =
1676       CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
1677   TabContents* contents = GetSelectedTabContents();
1678   if (!selected_encoding.empty() && contents)
1679      contents->SetOverrideEncoding(selected_encoding);
1680   // Update the list of recently selected encodings.
1681   std::string new_selected_encoding_list;
1682   if (CharacterEncoding::UpdateRecentlySelectedEncoding(
1683         profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
1684         encoding_id,
1685         &new_selected_encoding_list)) {
1686     profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
1687                                     new_selected_encoding_list);
1688   }
1689 }
1690 
Cut()1691 void Browser::Cut() {
1692   UserMetrics::RecordAction(UserMetricsAction("Cut"), profile_);
1693   window()->Cut();
1694 }
1695 
Copy()1696 void Browser::Copy() {
1697   UserMetrics::RecordAction(UserMetricsAction("Copy"), profile_);
1698   window()->Copy();
1699 }
1700 
Paste()1701 void Browser::Paste() {
1702   UserMetrics::RecordAction(UserMetricsAction("Paste"), profile_);
1703   window()->Paste();
1704 }
1705 
Find()1706 void Browser::Find() {
1707   UserMetrics::RecordAction(UserMetricsAction("Find"), profile_);
1708   FindInPage(false, false);
1709 }
1710 
FindNext()1711 void Browser::FindNext() {
1712   UserMetrics::RecordAction(UserMetricsAction("FindNext"), profile_);
1713   FindInPage(true, true);
1714 }
1715 
FindPrevious()1716 void Browser::FindPrevious() {
1717   UserMetrics::RecordAction(UserMetricsAction("FindPrevious"), profile_);
1718   FindInPage(true, false);
1719 }
1720 
Zoom(PageZoom::Function zoom_function)1721 void Browser::Zoom(PageZoom::Function zoom_function) {
1722   static const UserMetricsAction kActions[] = {
1723                       UserMetricsAction("ZoomMinus"),
1724                       UserMetricsAction("ZoomNormal"),
1725                       UserMetricsAction("ZoomPlus")
1726                       };
1727 
1728   UserMetrics::RecordAction(kActions[zoom_function - PageZoom::ZOOM_OUT],
1729                             profile_);
1730   TabContentsWrapper* tab_contents = GetSelectedTabContentsWrapper();
1731   tab_contents->render_view_host()->Zoom(zoom_function);
1732 }
1733 
FocusToolbar()1734 void Browser::FocusToolbar() {
1735   UserMetrics::RecordAction(UserMetricsAction("FocusToolbar"), profile_);
1736   window_->FocusToolbar();
1737 }
1738 
FocusAppMenu()1739 void Browser::FocusAppMenu() {
1740   UserMetrics::RecordAction(UserMetricsAction("FocusAppMenu"), profile_);
1741   window_->FocusAppMenu();
1742 }
1743 
FocusLocationBar()1744 void Browser::FocusLocationBar() {
1745   UserMetrics::RecordAction(UserMetricsAction("FocusLocation"), profile_);
1746   window_->SetFocusToLocationBar(true);
1747 }
1748 
FocusBookmarksToolbar()1749 void Browser::FocusBookmarksToolbar() {
1750   UserMetrics::RecordAction(UserMetricsAction("FocusBookmarksToolbar"),
1751                             profile_);
1752   window_->FocusBookmarksToolbar();
1753 }
1754 
FocusChromeOSStatus()1755 void Browser::FocusChromeOSStatus() {
1756   UserMetrics::RecordAction(UserMetricsAction("FocusChromeOSStatus"), profile_);
1757   window_->FocusChromeOSStatus();
1758 }
1759 
FocusNextPane()1760 void Browser::FocusNextPane() {
1761   UserMetrics::RecordAction(UserMetricsAction("FocusNextPane"), profile_);
1762   window_->RotatePaneFocus(true);
1763 }
1764 
FocusPreviousPane()1765 void Browser::FocusPreviousPane() {
1766   UserMetrics::RecordAction(UserMetricsAction("FocusPreviousPane"), profile_);
1767   window_->RotatePaneFocus(false);
1768 }
1769 
FocusSearch()1770 void Browser::FocusSearch() {
1771   // TODO(beng): replace this with FocusLocationBar
1772   UserMetrics::RecordAction(UserMetricsAction("FocusSearch"), profile_);
1773   window_->GetLocationBar()->FocusSearch();
1774 }
1775 
OpenFile()1776 void Browser::OpenFile() {
1777   UserMetrics::RecordAction(UserMetricsAction("OpenFile"), profile_);
1778 #if defined(OS_CHROMEOS) && !defined(FILE_MANAGER_EXTENSION)
1779   FileBrowseUI::OpenPopup(profile_,
1780                           "",
1781                           FileBrowseUI::kPopupWidth,
1782                           FileBrowseUI::kPopupHeight);
1783 #else
1784   if (!select_file_dialog_.get())
1785     select_file_dialog_ = SelectFileDialog::Create(this);
1786 
1787   const FilePath directory = profile_->last_selected_directory();
1788 
1789   // TODO(beng): figure out how to juggle this.
1790   gfx::NativeWindow parent_window = window_->GetNativeHandle();
1791   select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
1792                                   string16(), directory,
1793                                   NULL, 0, FILE_PATH_LITERAL(""),
1794                                   GetSelectedTabContents(),
1795                                   parent_window, NULL);
1796 #endif
1797 }
1798 
OpenCreateShortcutsDialog()1799 void Browser::OpenCreateShortcutsDialog() {
1800   UserMetrics::RecordAction(UserMetricsAction("CreateShortcut"), profile_);
1801 #if defined(OS_WIN) || defined(OS_LINUX)
1802   TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper();
1803   DCHECK(current_tab &&
1804       web_app::IsValidUrl(current_tab->tab_contents()->GetURL())) <<
1805           "Menu item should be disabled.";
1806 
1807   NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry();
1808   if (!entry)
1809     return;
1810 
1811   // RVH's GetApplicationInfo should not be called before it returns.
1812   DCHECK(pending_web_app_action_ == NONE);
1813   pending_web_app_action_ = CREATE_SHORTCUT;
1814 
1815   // Start fetching web app info for CreateApplicationShortcut dialog and show
1816   // the dialog when the data is available in OnDidGetApplicationInfo.
1817   current_tab->extension_tab_helper()->GetApplicationInfo(entry->page_id());
1818 #else
1819   NOTIMPLEMENTED();
1820 #endif
1821 }
1822 
ToggleDevToolsWindow(DevToolsToggleAction action)1823 void Browser::ToggleDevToolsWindow(DevToolsToggleAction action) {
1824   std::string uma_string;
1825   switch (action) {
1826     case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
1827       uma_string = "DevTools_ToggleConsole";
1828       break;
1829     case DEVTOOLS_TOGGLE_ACTION_NONE:
1830     case DEVTOOLS_TOGGLE_ACTION_INSPECT:
1831     default:
1832       uma_string = "DevTools_ToggleWindow";
1833       break;
1834   }
1835   UserMetrics::RecordAction(UserMetricsAction(uma_string.c_str()), profile_);
1836   DevToolsManager::GetInstance()->ToggleDevToolsWindow(
1837       GetSelectedTabContentsWrapper()->render_view_host(), action);
1838 }
1839 
OpenTaskManager(bool highlight_background_resources)1840 void Browser::OpenTaskManager(bool highlight_background_resources) {
1841   UserMetrics::RecordAction(UserMetricsAction("TaskManager"), profile_);
1842   if (highlight_background_resources)
1843     window_->ShowBackgroundPages();
1844   else
1845     window_->ShowTaskManager();
1846 }
1847 
OpenBugReportDialog()1848 void Browser::OpenBugReportDialog() {
1849   UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_);
1850   browser::ShowHtmlBugReportView(this);
1851 }
1852 
ToggleBookmarkBar()1853 void Browser::ToggleBookmarkBar() {
1854   UserMetrics::RecordAction(UserMetricsAction("ShowBookmarksBar"), profile_);
1855   window_->ToggleBookmarkBar();
1856 }
1857 
OpenBookmarkManager()1858 void Browser::OpenBookmarkManager() {
1859   UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"), profile_);
1860   ShowBookmarkManagerTab();
1861 }
1862 
ShowAppMenu()1863 void Browser::ShowAppMenu() {
1864   // We record the user metric for this event in WrenchMenu::RunMenu.
1865   window_->ShowAppMenu();
1866 }
1867 
ShowBookmarkManagerTab()1868 void Browser::ShowBookmarkManagerTab() {
1869   UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks"), profile_);
1870   ShowSingletonTab(GURL(chrome::kChromeUIBookmarksURL));
1871 }
1872 
ShowHistoryTab()1873 void Browser::ShowHistoryTab() {
1874   UserMetrics::RecordAction(UserMetricsAction("ShowHistory"), profile_);
1875   ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL));
1876 }
1877 
ShowDownloadsTab()1878 void Browser::ShowDownloadsTab() {
1879   UserMetrics::RecordAction(UserMetricsAction("ShowDownloads"), profile_);
1880   if (window()) {
1881     DownloadShelf* shelf = window()->GetDownloadShelf();
1882     if (shelf->IsShowing())
1883       shelf->Close();
1884   }
1885   ShowSingletonTab(GURL(chrome::kChromeUIDownloadsURL));
1886 }
1887 
ShowExtensionsTab()1888 void Browser::ShowExtensionsTab() {
1889   UserMetrics::RecordAction(UserMetricsAction("ShowExtensions"), profile_);
1890   ShowSingletonTab(GURL(chrome::kChromeUIExtensionsURL));
1891 }
1892 
ShowAboutConflictsTab()1893 void Browser::ShowAboutConflictsTab() {
1894   UserMetrics::RecordAction(UserMetricsAction("AboutConflicts"), profile_);
1895   ShowSingletonTab(GURL(chrome::kChromeUIConflictsURL));
1896 }
1897 
ShowBrokenPageTab(TabContents * contents)1898 void Browser::ShowBrokenPageTab(TabContents* contents) {
1899   UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_);
1900   string16 page_title = contents->GetTitle();
1901   NavigationEntry* entry = contents->controller().GetActiveEntry();
1902   if (!entry)
1903     return;
1904   std::string page_url = entry->url().spec();
1905   std::vector<std::string> subst;
1906   subst.push_back(UTF16ToASCII(page_title));
1907   subst.push_back(page_url);
1908   std::string report_page_url =
1909       ReplaceStringPlaceholders(kBrokenPageUrl, subst, NULL);
1910   ShowSingletonTab(GURL(report_page_url));
1911 }
1912 
ShowOptionsTab(const std::string & sub_page)1913 void Browser::ShowOptionsTab(const std::string& sub_page) {
1914   GURL url(chrome::kChromeUISettingsURL + sub_page);
1915   browser::NavigateParams params(GetSingletonTabNavigateParams(url));
1916   params.path_behavior = browser::NavigateParams::IGNORE_AND_NAVIGATE;
1917   browser::Navigate(&params);
1918 }
1919 
OpenClearBrowsingDataDialog()1920 void Browser::OpenClearBrowsingDataDialog() {
1921   UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg"),
1922                             profile_);
1923   ShowOptionsTab(chrome::kClearBrowserDataSubPage);
1924 }
1925 
OpenOptionsDialog()1926 void Browser::OpenOptionsDialog() {
1927   UserMetrics::RecordAction(UserMetricsAction("ShowOptions"), profile_);
1928   GURL url(chrome::kChromeUISettingsURL);
1929   browser::NavigateParams params(GetSingletonTabNavigateParams(url));
1930   params.path_behavior = browser::NavigateParams::IGNORE_AND_STAY_PUT;
1931   browser::Navigate(&params);
1932 }
1933 
OpenPasswordManager()1934 void Browser::OpenPasswordManager() {
1935   UserMetrics::RecordAction(UserMetricsAction("Options_ShowPasswordManager"),
1936                             profile_);
1937   ShowOptionsTab(chrome::kPasswordManagerSubPage);
1938 }
1939 
OpenImportSettingsDialog()1940 void Browser::OpenImportSettingsDialog() {
1941   UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_);
1942   ShowOptionsTab(chrome::kImportDataSubPage);
1943 }
1944 
OpenInstantConfirmDialog()1945 void Browser::OpenInstantConfirmDialog() {
1946   ShowOptionsTab(chrome::kInstantConfirmPage);
1947 }
1948 
OpenSyncMyBookmarksDialog()1949 void Browser::OpenSyncMyBookmarksDialog() {
1950   sync_ui_util::OpenSyncMyBookmarksDialog(
1951       profile_, this, ProfileSyncService::START_FROM_WRENCH);
1952 }
1953 
OpenAboutChromeDialog()1954 void Browser::OpenAboutChromeDialog() {
1955   UserMetrics::RecordAction(UserMetricsAction("AboutChrome"), profile_);
1956 #if defined(OS_CHROMEOS)
1957   ShowSingletonTab(GURL(chrome::kChromeUIAboutURL));
1958 #else
1959   window_->ShowAboutChromeDialog();
1960 #endif
1961 }
1962 
OpenUpdateChromeDialog()1963 void Browser::OpenUpdateChromeDialog() {
1964   UserMetrics::RecordAction(UserMetricsAction("UpdateChrome"), profile_);
1965   window_->ShowUpdateChromeDialog();
1966 }
1967 
OpenHelpTab()1968 void Browser::OpenHelpTab() {
1969   GURL help_url(kHelpContentUrl);
1970   GURL localized_help_url = google_util::AppendGoogleLocaleParam(help_url);
1971   AddSelectedTabWithURL(localized_help_url, PageTransition::AUTO_BOOKMARK);
1972 }
1973 
OpenThemeGalleryTabAndActivate()1974 void Browser::OpenThemeGalleryTabAndActivate() {
1975   AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)),
1976                         PageTransition::LINK);
1977 }
1978 
OpenPrivacyDashboardTabAndActivate()1979 void Browser::OpenPrivacyDashboardTabAndActivate() {
1980   OpenURL(GURL(kPrivacyDashboardUrl), GURL(),
1981           NEW_FOREGROUND_TAB, PageTransition::LINK);
1982   window_->Activate();
1983 }
1984 
OpenAutofillHelpTabAndActivate()1985 void Browser::OpenAutofillHelpTabAndActivate() {
1986   GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kAutofillHelpUrl));
1987   AddSelectedTabWithURL(help_url, PageTransition::LINK);
1988 }
1989 
OpenSearchEngineOptionsDialog()1990 void Browser::OpenSearchEngineOptionsDialog() {
1991   UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines"), profile_);
1992   ShowOptionsTab(chrome::kSearchEnginesSubPage);
1993 }
1994 
1995 #if defined(OS_CHROMEOS)
OpenFileManager()1996 void Browser::OpenFileManager() {
1997   UserMetrics::RecordAction(UserMetricsAction("OpenFileManager"));
1998   ShowSingletonTab(FileManagerUtil::GetFileBrowserUrl());
1999 }
2000 
OpenSystemOptionsDialog()2001 void Browser::OpenSystemOptionsDialog() {
2002   UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog"),
2003                             profile_);
2004   ShowOptionsTab(chrome::kSystemOptionsSubPage);
2005 }
2006 
OpenInternetOptionsDialog()2007 void Browser::OpenInternetOptionsDialog() {
2008   UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog"),
2009                             profile_);
2010   ShowOptionsTab(chrome::kInternetOptionsSubPage);
2011 }
2012 
OpenLanguageOptionsDialog()2013 void Browser::OpenLanguageOptionsDialog() {
2014   UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog"),
2015                             profile_);
2016   ShowOptionsTab(chrome::kLanguageOptionsSubPage);
2017 }
2018 
OpenSystemTabAndActivate()2019 void Browser::OpenSystemTabAndActivate() {
2020   OpenURL(GURL(chrome::kChromeUISystemInfoURL), GURL(),
2021           NEW_FOREGROUND_TAB, PageTransition::LINK);
2022   window_->Activate();
2023 }
2024 
OpenMobilePlanTabAndActivate()2025 void Browser::OpenMobilePlanTabAndActivate() {
2026   OpenURL(GURL(chrome::kChromeUIMobileSetupURL), GURL(),
2027           NEW_FOREGROUND_TAB, PageTransition::LINK);
2028   window_->Activate();
2029 }
2030 #endif
2031 
OpenPluginsTabAndActivate()2032 void Browser::OpenPluginsTabAndActivate() {
2033   OpenURL(GURL(chrome::kAboutPluginsURL), GURL(),
2034           NEW_FOREGROUND_TAB, PageTransition::LINK);
2035   window_->Activate();
2036 }
2037 
2038 ///////////////////////////////////////////////////////////////////////////////
2039 
2040 // static
SetNewHomePagePrefs(PrefService * prefs)2041 void Browser::SetNewHomePagePrefs(PrefService* prefs) {
2042   const PrefService::Preference* home_page_pref =
2043       prefs->FindPreference(prefs::kHomePage);
2044   if (home_page_pref &&
2045       !home_page_pref->IsManaged() &&
2046       !prefs->HasPrefPath(prefs::kHomePage)) {
2047     prefs->SetString(prefs::kHomePage,
2048         GoogleURLTracker::kDefaultGoogleHomepage);
2049   }
2050   const PrefService::Preference* home_page_is_new_tab_page_pref =
2051       prefs->FindPreference(prefs::kHomePageIsNewTabPage);
2052   if (home_page_is_new_tab_page_pref &&
2053       !home_page_is_new_tab_page_pref->IsManaged() &&
2054       !prefs->HasPrefPath(prefs::kHomePageIsNewTabPage))
2055     prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false);
2056 }
2057 
2058 // static
RegisterPrefs(PrefService * prefs)2059 void Browser::RegisterPrefs(PrefService* prefs) {
2060   prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
2061   prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1);
2062   prefs->RegisterIntegerPref(prefs::kMultipleProfilePrefMigration, 0);
2063   prefs->RegisterBooleanPref(prefs::kAllowFileSelectionDialogs, true);
2064   // Educated guess: Chrome has a bundled Flash version supporting
2065   // clearing LSO data, Chromium hasn't.
2066 #if defined(GOOGLE_CHROME_BUILD)
2067   prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, true);
2068 #else
2069   prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, false);
2070 #endif
2071 }
2072 
2073 // static
RegisterUserPrefs(PrefService * prefs)2074 void Browser::RegisterUserPrefs(PrefService* prefs) {
2075   prefs->RegisterStringPref(prefs::kHomePage,
2076                             chrome::kChromeUINewTabURL);
2077   prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
2078   prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
2079 #if defined(OS_MACOSX)
2080   // This really belongs in platform code, but there's no good place to
2081   // initialize it between the time when the AppController is created
2082   // (where there's no profile) and the time the controller gets another
2083   // crack at the start of the main event loop. By that time, BrowserInit
2084   // has already created the browser window, and it's too late: we need the
2085   // pref to be already initialized. Doing it here also saves us from having
2086   // to hard-code pref registration in the several unit tests that use
2087   // this preference.
2088   prefs->RegisterBooleanPref(prefs::kConfirmToQuitEnabled, false);
2089   prefs->RegisterBooleanPref(prefs::kShowUpdatePromotionInfoBar, true);
2090 #endif
2091   prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
2092   prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
2093   prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
2094   prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
2095   prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
2096   prefs->RegisterBooleanPref(prefs::kDeleteFormData, false);
2097   prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
2098   prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true);
2099   prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true);
2100   prefs->RegisterBooleanPref(prefs::kWebAppCreateOnDesktop, true);
2101   prefs->RegisterBooleanPref(prefs::kWebAppCreateInAppsMenu, true);
2102   prefs->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, true);
2103   prefs->RegisterBooleanPref(prefs::kUseVerticalTabs, false);
2104   prefs->RegisterBooleanPref(prefs::kEnableTranslate, true);
2105   prefs->RegisterBooleanPref(prefs::kEnableBookmarkBar, true);
2106   prefs->RegisterBooleanPref(prefs::kRemotingHasSetupCompleted, false);
2107   prefs->RegisterStringPref(prefs::kCloudPrintEmail, std::string());
2108   prefs->RegisterBooleanPref(prefs::kCloudPrintProxyEnabled, true);
2109   prefs->RegisterBooleanPref(prefs::kDevToolsDisabled, false);
2110   prefs->RegisterBooleanPref(prefs::kIncognitoEnabled, true);
2111   prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1);
2112   prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
2113   prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement);
2114   // We need to register the type of these preferences in order to query
2115   // them even though they're typically only controlled via policy or command
2116   // line switches.
2117   prefs->RegisterBooleanPref(prefs::kDisable3DAPIs, false);
2118   prefs->RegisterBooleanPref(prefs::kPluginsAllowOutdated, false);
2119   prefs->RegisterBooleanPref(prefs::kEnableHyperlinkAuditing, true);
2120   prefs->RegisterBooleanPref(prefs::kEnableReferrers, true);
2121 }
2122 
2123 // static
RunUnloadEventsHelper(TabContents * contents)2124 bool Browser::RunUnloadEventsHelper(TabContents* contents) {
2125   // If the TabContents is not connected yet, then there's no unload
2126   // handler we can fire even if the TabContents has an unload listener.
2127   // One case where we hit this is in a tab that has an infinite loop
2128   // before load.
2129   if (contents->NeedToFireBeforeUnload()) {
2130     // If the page has unload listeners, then we tell the renderer to fire
2131     // them. Once they have fired, we'll get a message back saying whether
2132     // to proceed closing the page or not, which sends us back to this method
2133     // with the NeedToFireBeforeUnload bit cleared.
2134     contents->render_view_host()->FirePageBeforeUnload(false);
2135     return true;
2136   }
2137   return false;
2138 }
2139 
2140 // static
GetBrowserForController(const NavigationController * controller,int * index_result)2141 Browser* Browser::GetBrowserForController(
2142     const NavigationController* controller, int* index_result) {
2143   BrowserList::const_iterator it;
2144   for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
2145     int index = (*it)->tab_handler_->GetTabStripModel()->GetIndexOfController(
2146         controller);
2147     if (index != TabStripModel::kNoTab) {
2148       if (index_result)
2149         *index_result = index;
2150       return *it;
2151     }
2152   }
2153 
2154   return NULL;
2155 }
2156 
ExecuteCommandWithDisposition(int id,WindowOpenDisposition disposition)2157 void Browser::ExecuteCommandWithDisposition(
2158   int id, WindowOpenDisposition disposition) {
2159   // No commands are enabled if there is not yet any selected tab.
2160   // TODO(pkasting): It seems like we should not need this, because either
2161   // most/all commands should not have been enabled yet anyway or the ones that
2162   // are enabled should be global, or safe themselves against having no selected
2163   // tab.  However, Ben says he tried removing this before and got lots of
2164   // crashes, e.g. from Windows sending WM_COMMANDs at random times during
2165   // window construction.  This probably could use closer examination someday.
2166   if (!GetSelectedTabContentsWrapper())
2167     return;
2168 
2169   DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command "
2170                                                 << id;
2171 
2172   // If command execution is blocked then just record the command and return.
2173   if (block_command_execution_) {
2174     // We actually only allow no more than one blocked command, otherwise some
2175     // commands maybe lost.
2176     DCHECK_EQ(last_blocked_command_id_, -1);
2177     last_blocked_command_id_ = id;
2178     last_blocked_command_disposition_ = disposition;
2179     return;
2180   }
2181 
2182   // The order of commands in this switch statement must match the function
2183   // declaration order in browser.h!
2184   switch (id) {
2185     // Navigation commands
2186     case IDC_BACK:                  GoBack(disposition);              break;
2187     case IDC_FORWARD:               GoForward(disposition);           break;
2188     case IDC_RELOAD:                Reload(disposition);              break;
2189     case IDC_RELOAD_IGNORING_CACHE: ReloadIgnoringCache(disposition); break;
2190     case IDC_HOME:                  Home(disposition);                break;
2191     case IDC_OPEN_CURRENT_URL:      OpenCurrentURL();                 break;
2192     case IDC_STOP:                  Stop();                           break;
2193 
2194      // Window management commands
2195     case IDC_NEW_WINDOW:            NewWindow();                      break;
2196     case IDC_NEW_INCOGNITO_WINDOW:  NewIncognitoWindow();             break;
2197     case IDC_CLOSE_WINDOW:          CloseWindow();                    break;
2198     case IDC_NEW_TAB:               NewTab();                         break;
2199     case IDC_CLOSE_TAB:             CloseTab();                       break;
2200     case IDC_SELECT_NEXT_TAB:       SelectNextTab();                  break;
2201     case IDC_SELECT_PREVIOUS_TAB:   SelectPreviousTab();              break;
2202     case IDC_TABPOSE:               OpenTabpose();                    break;
2203     case IDC_MOVE_TAB_NEXT:         MoveTabNext();                    break;
2204     case IDC_MOVE_TAB_PREVIOUS:     MoveTabPrevious();                break;
2205     case IDC_SELECT_TAB_0:
2206     case IDC_SELECT_TAB_1:
2207     case IDC_SELECT_TAB_2:
2208     case IDC_SELECT_TAB_3:
2209     case IDC_SELECT_TAB_4:
2210     case IDC_SELECT_TAB_5:
2211     case IDC_SELECT_TAB_6:
2212     case IDC_SELECT_TAB_7:          SelectNumberedTab(id - IDC_SELECT_TAB_0);
2213                                                                       break;
2214     case IDC_SELECT_LAST_TAB:       SelectLastTab();                  break;
2215     case IDC_DUPLICATE_TAB:         DuplicateTab();                   break;
2216     case IDC_RESTORE_TAB:           RestoreTab();                     break;
2217     case IDC_COPY_URL:              WriteCurrentURLToClipboard();     break;
2218     case IDC_SHOW_AS_TAB:           ConvertPopupToTabbedBrowser();    break;
2219     case IDC_FULLSCREEN:            ToggleFullscreenMode();           break;
2220     case IDC_EXIT:                  Exit();                           break;
2221     case IDC_TOGGLE_VERTICAL_TABS:  ToggleUseVerticalTabs();          break;
2222 #if defined(OS_CHROMEOS)
2223     case IDC_SEARCH:                Search();                         break;
2224     case IDC_SHOW_KEYBOARD_OVERLAY: ShowKeyboardOverlay();            break;
2225 #endif
2226 
2227     // Page-related commands
2228     case IDC_SAVE_PAGE:             SavePage();                       break;
2229     case IDC_BOOKMARK_PAGE:         BookmarkCurrentPage();            break;
2230     case IDC_BOOKMARK_ALL_TABS:     BookmarkAllTabs();                break;
2231     case IDC_VIEW_SOURCE:           ViewSelectedSource();             break;
2232     case IDC_EMAIL_PAGE_LOCATION:   EmailPageLocation();              break;
2233     case IDC_PRINT:                 Print();                          break;
2234     case IDC_ENCODING_AUTO_DETECT:  ToggleEncodingAutoDetect();       break;
2235     case IDC_ENCODING_UTF8:
2236     case IDC_ENCODING_UTF16LE:
2237     case IDC_ENCODING_ISO88591:
2238     case IDC_ENCODING_WINDOWS1252:
2239     case IDC_ENCODING_GBK:
2240     case IDC_ENCODING_GB18030:
2241     case IDC_ENCODING_BIG5HKSCS:
2242     case IDC_ENCODING_BIG5:
2243     case IDC_ENCODING_KOREAN:
2244     case IDC_ENCODING_SHIFTJIS:
2245     case IDC_ENCODING_ISO2022JP:
2246     case IDC_ENCODING_EUCJP:
2247     case IDC_ENCODING_THAI:
2248     case IDC_ENCODING_ISO885915:
2249     case IDC_ENCODING_MACINTOSH:
2250     case IDC_ENCODING_ISO88592:
2251     case IDC_ENCODING_WINDOWS1250:
2252     case IDC_ENCODING_ISO88595:
2253     case IDC_ENCODING_WINDOWS1251:
2254     case IDC_ENCODING_KOI8R:
2255     case IDC_ENCODING_KOI8U:
2256     case IDC_ENCODING_ISO88597:
2257     case IDC_ENCODING_WINDOWS1253:
2258     case IDC_ENCODING_ISO88594:
2259     case IDC_ENCODING_ISO885913:
2260     case IDC_ENCODING_WINDOWS1257:
2261     case IDC_ENCODING_ISO88593:
2262     case IDC_ENCODING_ISO885910:
2263     case IDC_ENCODING_ISO885914:
2264     case IDC_ENCODING_ISO885916:
2265     case IDC_ENCODING_WINDOWS1254:
2266     case IDC_ENCODING_ISO88596:
2267     case IDC_ENCODING_WINDOWS1256:
2268     case IDC_ENCODING_ISO88598:
2269     case IDC_ENCODING_ISO88598I:
2270     case IDC_ENCODING_WINDOWS1255:
2271     case IDC_ENCODING_WINDOWS1258:  OverrideEncoding(id);             break;
2272 
2273     // Clipboard commands
2274     case IDC_CUT:                   Cut();                            break;
2275     case IDC_COPY:                  Copy();                           break;
2276     case IDC_PASTE:                 Paste();                          break;
2277 
2278     // Find-in-page
2279     case IDC_FIND:                  Find();                           break;
2280     case IDC_FIND_NEXT:             FindNext();                       break;
2281     case IDC_FIND_PREVIOUS:         FindPrevious();                   break;
2282 
2283     // Zoom
2284     case IDC_ZOOM_PLUS:             Zoom(PageZoom::ZOOM_IN);          break;
2285     case IDC_ZOOM_NORMAL:           Zoom(PageZoom::RESET);            break;
2286     case IDC_ZOOM_MINUS:            Zoom(PageZoom::ZOOM_OUT);         break;
2287 
2288     // Focus various bits of UI
2289     case IDC_FOCUS_TOOLBAR:         FocusToolbar();                   break;
2290     case IDC_FOCUS_LOCATION:        FocusLocationBar();               break;
2291     case IDC_FOCUS_SEARCH:          FocusSearch();                    break;
2292     case IDC_FOCUS_MENU_BAR:        FocusAppMenu();                   break;
2293     case IDC_FOCUS_BOOKMARKS:       FocusBookmarksToolbar();          break;
2294     case IDC_FOCUS_CHROMEOS_STATUS: FocusChromeOSStatus();            break;
2295     case IDC_FOCUS_NEXT_PANE:       FocusNextPane();                  break;
2296     case IDC_FOCUS_PREVIOUS_PANE:   FocusPreviousPane();              break;
2297 
2298     // Show various bits of UI
2299     case IDC_OPEN_FILE:             OpenFile();                       break;
2300     case IDC_CREATE_SHORTCUTS:      OpenCreateShortcutsDialog();      break;
2301     case IDC_DEV_TOOLS:             ToggleDevToolsWindow(
2302                                         DEVTOOLS_TOGGLE_ACTION_NONE);
2303                                     break;
2304     case IDC_DEV_TOOLS_CONSOLE:     ToggleDevToolsWindow(
2305                                         DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
2306                                     break;
2307     case IDC_DEV_TOOLS_INSPECT:     ToggleDevToolsWindow(
2308                                         DEVTOOLS_TOGGLE_ACTION_INSPECT);
2309                                     break;
2310     case IDC_TASK_MANAGER:          OpenTaskManager(false);           break;
2311     case IDC_VIEW_BACKGROUND_PAGES: OpenTaskManager(true);            break;
2312     case IDC_FEEDBACK:              OpenBugReportDialog();            break;
2313 
2314     case IDC_SHOW_BOOKMARK_BAR:     ToggleBookmarkBar();              break;
2315     case IDC_PROFILING_ENABLED:     Profiling::Toggle();              break;
2316 
2317     case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager();            break;
2318     case IDC_SHOW_APP_MENU:         ShowAppMenu();                    break;
2319     case IDC_SHOW_HISTORY:          ShowHistoryTab();                 break;
2320     case IDC_SHOW_DOWNLOADS:        ShowDownloadsTab();               break;
2321     case IDC_MANAGE_EXTENSIONS:     ShowExtensionsTab();              break;
2322     case IDC_SYNC_BOOKMARKS:        OpenSyncMyBookmarksDialog();      break;
2323     case IDC_OPTIONS:               OpenOptionsDialog();              break;
2324     case IDC_EDIT_SEARCH_ENGINES:   OpenSearchEngineOptionsDialog();  break;
2325     case IDC_VIEW_PASSWORDS:        OpenPasswordManager();            break;
2326     case IDC_CLEAR_BROWSING_DATA:   OpenClearBrowsingDataDialog();    break;
2327     case IDC_IMPORT_SETTINGS:       OpenImportSettingsDialog();       break;
2328     case IDC_ABOUT:                 OpenAboutChromeDialog();          break;
2329     case IDC_UPGRADE_DIALOG:        OpenUpdateChromeDialog();         break;
2330     case IDC_VIEW_INCOMPATIBILITIES: ShowAboutConflictsTab();         break;
2331     case IDC_HELP_PAGE:             OpenHelpTab();                    break;
2332 #if defined(OS_CHROMEOS)
2333     case IDC_FILE_MANAGER:          OpenFileManager();                break;
2334     case IDC_SYSTEM_OPTIONS:        OpenSystemOptionsDialog();        break;
2335     case IDC_INTERNET_OPTIONS:      OpenInternetOptionsDialog();      break;
2336     case IDC_LANGUAGE_OPTIONS:      OpenLanguageOptionsDialog();      break;
2337 #endif
2338 
2339     default:
2340       LOG(WARNING) << "Received Unimplemented Command: " << id;
2341       break;
2342   }
2343 }
2344 
ExecuteCommandIfEnabled(int id)2345 bool Browser::ExecuteCommandIfEnabled(int id) {
2346   if (command_updater_.SupportsCommand(id) &&
2347       command_updater_.IsCommandEnabled(id)) {
2348     ExecuteCommand(id);
2349     return true;
2350   }
2351   return false;
2352 }
2353 
IsReservedCommandOrKey(int command_id,const NativeWebKeyboardEvent & event)2354 bool Browser::IsReservedCommandOrKey(int command_id,
2355                                      const NativeWebKeyboardEvent& event) {
2356 #if defined(OS_CHROMEOS)
2357   // Chrome OS's top row of keys produces F1-10.  Make sure that web pages
2358   // aren't able to block Chrome from performing the standard actions for F1-F4
2359   // (F5-7 are grabbed by other X clients and hence don't need this protection,
2360   // and F8-10 are handled separately in Chrome via a GDK event filter, but
2361   // let's future-proof this).
2362   ui::KeyboardCode key_code =
2363       static_cast<ui::KeyboardCode>(event.windowsKeyCode);
2364   if (key_code == ui::VKEY_F1 ||
2365       key_code == ui::VKEY_F2 ||
2366       key_code == ui::VKEY_F3 ||
2367       key_code == ui::VKEY_F4 ||
2368       key_code == ui::VKEY_F5 ||
2369       key_code == ui::VKEY_F6 ||
2370       key_code == ui::VKEY_F7 ||
2371       key_code == ui::VKEY_F8 ||
2372       key_code == ui::VKEY_F9 ||
2373       key_code == ui::VKEY_F10) {
2374     return true;
2375   }
2376 #endif
2377 
2378   return command_id == IDC_CLOSE_TAB ||
2379          command_id == IDC_CLOSE_WINDOW ||
2380          command_id == IDC_NEW_INCOGNITO_WINDOW ||
2381          command_id == IDC_NEW_TAB ||
2382          command_id == IDC_NEW_WINDOW ||
2383          command_id == IDC_RESTORE_TAB ||
2384          command_id == IDC_SELECT_NEXT_TAB ||
2385          command_id == IDC_SELECT_PREVIOUS_TAB ||
2386          command_id == IDC_TABPOSE ||
2387          command_id == IDC_EXIT ||
2388          command_id == IDC_SEARCH;
2389 }
2390 
SetBlockCommandExecution(bool block)2391 void Browser::SetBlockCommandExecution(bool block) {
2392   block_command_execution_ = block;
2393   if (block) {
2394     last_blocked_command_id_ = -1;
2395     last_blocked_command_disposition_ = CURRENT_TAB;
2396   }
2397 }
2398 
GetLastBlockedCommand(WindowOpenDisposition * disposition)2399 int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) {
2400   if (disposition)
2401     *disposition = last_blocked_command_disposition_;
2402   return last_blocked_command_id_;
2403 }
2404 
UpdateUIForNavigationInTab(TabContentsWrapper * contents,PageTransition::Type transition,bool user_initiated)2405 void Browser::UpdateUIForNavigationInTab(TabContentsWrapper* contents,
2406                                          PageTransition::Type transition,
2407                                          bool user_initiated) {
2408   tabstrip_model()->TabNavigating(contents, transition);
2409 
2410   bool contents_is_selected = contents == GetSelectedTabContentsWrapper();
2411   if (user_initiated && contents_is_selected && window()->GetLocationBar()) {
2412     // Forcibly reset the location bar if the url is going to change in the
2413     // current tab, since otherwise it won't discard any ongoing user edits,
2414     // since it doesn't realize this is a user-initiated action.
2415     window()->GetLocationBar()->Revert();
2416   }
2417 
2418   if (GetStatusBubble())
2419     GetStatusBubble()->Hide();
2420 
2421   // Update the location bar. This is synchronous. We specifically don't
2422   // update the load state since the load hasn't started yet and updating it
2423   // will put it out of sync with the actual state like whether we're
2424   // displaying a favicon, which controls the throbber. If we updated it here,
2425   // the throbber will show the default favicon for a split second when
2426   // navigating away from the new tab page.
2427   ScheduleUIUpdate(contents->tab_contents(), TabContents::INVALIDATE_URL);
2428 
2429   if (contents_is_selected)
2430     contents->tab_contents()->Focus();
2431 }
2432 
GetHomePage() const2433 GURL Browser::GetHomePage() const {
2434   // --homepage overrides any preferences.
2435   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
2436   if (command_line.HasSwitch(switches::kHomePage)) {
2437     // TODO(evanm): clean up usage of DIR_CURRENT.
2438     //   http://code.google.com/p/chromium/issues/detail?id=60630
2439     // For now, allow this code to call getcwd().
2440     base::ThreadRestrictions::ScopedAllowIO allow_io;
2441 
2442     FilePath browser_directory;
2443     PathService::Get(base::DIR_CURRENT, &browser_directory);
2444     GURL home_page(URLFixerUpper::FixupRelativeFile(browser_directory,
2445         command_line.GetSwitchValuePath(switches::kHomePage)));
2446     if (home_page.is_valid())
2447       return home_page;
2448   }
2449 
2450   if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
2451     return GURL(chrome::kChromeUINewTabURL);
2452   GURL home_page(URLFixerUpper::FixupURL(
2453       profile_->GetPrefs()->GetString(prefs::kHomePage),
2454       std::string()));
2455   if (!home_page.is_valid())
2456     return GURL(chrome::kChromeUINewTabURL);
2457   return home_page;
2458 }
2459 
2460 ///////////////////////////////////////////////////////////////////////////////
2461 // Browser, PageNavigator implementation:
2462 
OpenURL(const GURL & url,const GURL & referrer,WindowOpenDisposition disposition,PageTransition::Type transition)2463 void Browser::OpenURL(const GURL& url, const GURL& referrer,
2464                       WindowOpenDisposition disposition,
2465                       PageTransition::Type transition) {
2466   OpenURLFromTab(NULL, url, referrer, disposition, transition);
2467 }
2468 
2469 ///////////////////////////////////////////////////////////////////////////////
2470 // Browser, CommandUpdater::CommandUpdaterDelegate implementation:
2471 
ExecuteCommand(int id)2472 void Browser::ExecuteCommand(int id) {
2473   ExecuteCommandWithDisposition(id, CURRENT_TAB);
2474 }
2475 
2476 ///////////////////////////////////////////////////////////////////////////////
2477 // Browser, TabHandlerDelegate implementation:
2478 
GetProfile() const2479 Profile* Browser::GetProfile() const {
2480   return profile();
2481 }
2482 
AsBrowser()2483 Browser* Browser::AsBrowser() {
2484   return this;
2485 }
2486 
2487 ///////////////////////////////////////////////////////////////////////////////
2488 // Browser, TabStripModelDelegate implementation:
2489 
AddBlankTab(bool foreground)2490 TabContentsWrapper* Browser::AddBlankTab(bool foreground) {
2491   return AddBlankTabAt(-1, foreground);
2492 }
2493 
AddBlankTabAt(int index,bool foreground)2494 TabContentsWrapper* Browser::AddBlankTabAt(int index, bool foreground) {
2495   // Time new tab page creation time.  We keep track of the timing data in
2496   // TabContents, but we want to include the time it takes to create the
2497   // TabContents object too.
2498   base::TimeTicks new_tab_start_time = base::TimeTicks::Now();
2499   browser::NavigateParams params(this, GURL(chrome::kChromeUINewTabURL),
2500                                  PageTransition::TYPED);
2501   params.disposition = foreground ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
2502   params.tabstrip_index = index;
2503   browser::Navigate(&params);
2504   params.target_contents->tab_contents()->set_new_tab_start_time(
2505       new_tab_start_time);
2506   return params.target_contents;
2507 }
2508 
CreateNewStripWithContents(TabContentsWrapper * detached_contents,const gfx::Rect & window_bounds,const DockInfo & dock_info,bool maximize)2509 Browser* Browser::CreateNewStripWithContents(
2510     TabContentsWrapper* detached_contents,
2511     const gfx::Rect& window_bounds,
2512     const DockInfo& dock_info,
2513     bool maximize) {
2514   DCHECK(CanSupportWindowFeature(FEATURE_TABSTRIP));
2515 
2516   gfx::Rect new_window_bounds = window_bounds;
2517   if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
2518     dock_info.AdjustOtherWindowBounds();
2519 
2520   // Create an empty new browser window the same size as the old one.
2521   Browser* browser = new Browser(TYPE_NORMAL, profile_);
2522   browser->set_override_bounds(new_window_bounds);
2523   browser->set_maximized_state(
2524       maximize ? MAXIMIZED_STATE_MAXIMIZED : MAXIMIZED_STATE_UNMAXIMIZED);
2525   browser->InitBrowserWindow();
2526   browser->tabstrip_model()->AppendTabContents(detached_contents, true);
2527   // Make sure the loading state is updated correctly, otherwise the throbber
2528   // won't start if the page is loading.
2529   browser->LoadingStateChanged(detached_contents->tab_contents());
2530   return browser;
2531 }
2532 
GetDragActions() const2533 int Browser::GetDragActions() const {
2534   return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ?
2535       TabStripModelDelegate::TAB_MOVE_ACTION : 0);
2536 }
2537 
CreateTabContentsForURL(const GURL & url,const GURL & referrer,Profile * profile,PageTransition::Type transition,bool defer_load,SiteInstance * instance) const2538 TabContentsWrapper* Browser::CreateTabContentsForURL(
2539     const GURL& url, const GURL& referrer, Profile* profile,
2540     PageTransition::Type transition, bool defer_load,
2541     SiteInstance* instance) const {
2542   TabContentsWrapper* contents = TabContentsFactory(profile, instance,
2543       MSG_ROUTING_NONE,
2544       GetSelectedTabContents(), NULL);
2545   if (!defer_load) {
2546     // Load the initial URL before adding the new tab contents to the tab strip
2547     // so that the tab contents has navigation state.
2548     contents->controller().LoadURL(url, referrer, transition);
2549   }
2550 
2551   return contents;
2552 }
2553 
CanDuplicateContentsAt(int index)2554 bool Browser::CanDuplicateContentsAt(int index) {
2555   NavigationController& nc = GetTabContentsAt(index)->controller();
2556   return nc.tab_contents() && nc.GetLastCommittedEntry();
2557 }
2558 
DuplicateContentsAt(int index)2559 void Browser::DuplicateContentsAt(int index) {
2560   TabContentsWrapper* contents = GetTabContentsWrapperAt(index);
2561   CHECK(contents);
2562   TabContentsWrapper* contents_dupe = contents->Clone();
2563   TabContents* new_contents = contents_dupe->tab_contents();
2564 
2565   bool pinned = false;
2566   if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
2567     // If this is a tabbed browser, just create a duplicate tab inside the same
2568     // window next to the tab being duplicated.
2569     int index = tab_handler_->GetTabStripModel()->
2570         GetIndexOfTabContents(contents);
2571     pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index);
2572     int add_types = TabStripModel::ADD_ACTIVE |
2573         TabStripModel::ADD_INHERIT_GROUP |
2574         (pinned ? TabStripModel::ADD_PINNED : 0);
2575     tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1,
2576                                                           contents_dupe,
2577                                                           add_types);
2578   } else {
2579     Browser* browser = NULL;
2580     if (type_ & TYPE_APP) {
2581       CHECK_EQ((type_ & TYPE_POPUP), 0);
2582       CHECK_NE(type_, TYPE_APP_PANEL);
2583       browser = Browser::CreateForApp(app_name_, gfx::Size(), profile_,
2584                                       false);
2585     } else if (type_ == TYPE_POPUP) {
2586       browser = Browser::CreateForType(TYPE_POPUP, profile_);
2587     }
2588 
2589     // Preserve the size of the original window. The new window has already
2590     // been given an offset by the OS, so we shouldn't copy the old bounds.
2591     BrowserWindow* new_window = browser->window();
2592     new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
2593                           window()->GetRestoredBounds().size()));
2594 
2595     // We need to show the browser now.  Otherwise ContainerWin assumes the
2596     // TabContents is invisible and won't size it.
2597     browser->window()->Show();
2598 
2599     // The page transition below is only for the purpose of inserting the tab.
2600     browser->AddTab(contents_dupe, PageTransition::LINK);
2601   }
2602 
2603   if (profile_->HasSessionService()) {
2604     SessionService* session_service = profile_->GetSessionService();
2605     if (session_service)
2606       session_service->TabRestored(&new_contents->controller(), pinned);
2607   }
2608 }
2609 
CloseFrameAfterDragSession()2610 void Browser::CloseFrameAfterDragSession() {
2611 #if defined(OS_WIN) || defined(OS_LINUX)
2612   // This is scheduled to run after we return to the message loop because
2613   // otherwise the frame will think the drag session is still active and ignore
2614   // the request.
2615   // TODO(port): figure out what is required here in a cross-platform world
2616   MessageLoop::current()->PostTask(
2617       FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame));
2618 #endif
2619 }
2620 
CreateHistoricalTab(TabContentsWrapper * contents)2621 void Browser::CreateHistoricalTab(TabContentsWrapper* contents) {
2622   // We don't create historical tabs for incognito windows or windows without
2623   // profiles.
2624   if (!profile() || profile()->IsOffTheRecord() ||
2625       !profile()->GetTabRestoreService()) {
2626     return;
2627   }
2628 
2629   // We only create historical tab entries for tabbed browser windows.
2630   if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
2631     profile()->GetTabRestoreService()->CreateHistoricalTab(
2632         &contents->controller(),
2633         tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents));
2634   }
2635 }
2636 
RunUnloadListenerBeforeClosing(TabContentsWrapper * contents)2637 bool Browser::RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) {
2638   return Browser::RunUnloadEventsHelper(contents->tab_contents());
2639 }
2640 
CanReloadContents(TabContents * source) const2641 bool Browser::CanReloadContents(TabContents* source) const {
2642   return type() != TYPE_DEVTOOLS;
2643 }
2644 
CanCloseContentsAt(int index)2645 bool Browser::CanCloseContentsAt(int index) {
2646   if (!CanCloseTab())
2647     return false;
2648   if (tab_handler_->GetTabStripModel()->count() > 1)
2649     return true;
2650   // We are closing the last tab for this browser. Make sure to check for
2651   // in-progress downloads.
2652   // Note that the next call when it returns false will ask the user for
2653   // confirmation before closing the browser if the user decides so.
2654   return CanCloseWithInProgressDownloads();
2655 }
2656 
CanBookmarkAllTabs() const2657 bool Browser::CanBookmarkAllTabs() const {
2658   BookmarkModel* model = profile()->GetBookmarkModel();
2659   return (model && model->IsLoaded()) &&
2660          tab_count() > 1 &&
2661          edit_bookmarks_enabled_.GetValue();
2662 }
2663 
BookmarkAllTabs()2664 void Browser::BookmarkAllTabs() {
2665   BookmarkModel* model = profile()->GetBookmarkModel();
2666   DCHECK(model && model->IsLoaded());
2667 
2668   BookmarkEditor::EditDetails details;
2669   details.type = BookmarkEditor::EditDetails::NEW_FOLDER;
2670   bookmark_utils::GetURLsForOpenTabs(this, &(details.urls));
2671   DCHECK(!details.urls.empty());
2672 
2673   BookmarkEditor::Show(window()->GetNativeHandle(), profile_,
2674                        model->GetParentForNewNodes(),  details,
2675                        BookmarkEditor::SHOW_TREE);
2676 }
2677 
CanCloseTab() const2678 bool Browser::CanCloseTab() const {
2679   TabCloseableStateWatcher* watcher =
2680       g_browser_process->tab_closeable_state_watcher();
2681   return !watcher || watcher->CanCloseTab(this);
2682 }
2683 
ToggleUseVerticalTabs()2684 void Browser::ToggleUseVerticalTabs() {
2685   use_vertical_tabs_.SetValue(!UseVerticalTabs());
2686   UseVerticalTabsChanged();
2687 }
2688 
LargeIconsPermitted() const2689 bool Browser::LargeIconsPermitted() const {
2690   // We don't show the big icons in tabs for TYPE_EXTENSION_APP windows because
2691   // for those windows, we already have a big icon in the top-left outside any
2692   // tab. Having big tab icons too looks kinda redonk.
2693   return true;
2694 }
2695 
2696 ///////////////////////////////////////////////////////////////////////////////
2697 // Browser, TabStripModelObserver implementation:
2698 
TabInsertedAt(TabContentsWrapper * contents,int index,bool foreground)2699 void Browser::TabInsertedAt(TabContentsWrapper* contents,
2700                             int index,
2701                             bool foreground) {
2702   SetAsDelegate(contents, this);
2703   contents->controller().SetWindowID(session_id());
2704 
2705   // Each renderer holds the ID of the window that hosts it. Notify the
2706   // renderer that the window ID changed.
2707   contents->render_view_host()->UpdateBrowserWindowId(
2708       contents->controller().window_id().id());
2709 
2710   SyncHistoryWithTabs(index);
2711 
2712   // Make sure the loading state is updated correctly, otherwise the throbber
2713   // won't start if the page is loading.
2714   LoadingStateChanged(contents->tab_contents());
2715 
2716   // If the tab crashes in the beforeunload or unload handler, it won't be
2717   // able to ack. But we know we can close it.
2718   registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
2719                  Source<TabContentsWrapper>(contents));
2720 }
2721 
TabClosingAt(TabStripModel * tab_strip_model,TabContentsWrapper * contents,int index)2722 void Browser::TabClosingAt(TabStripModel* tab_strip_model,
2723                            TabContentsWrapper* contents,
2724                            int index) {
2725   NotificationService::current()->Notify(
2726       NotificationType::TAB_CLOSING,
2727       Source<NavigationController>(&contents->controller()),
2728       NotificationService::NoDetails());
2729 
2730   // Sever the TabContents' connection back to us.
2731   SetAsDelegate(contents, NULL);
2732 }
2733 
TabDetachedAt(TabContentsWrapper * contents,int index)2734 void Browser::TabDetachedAt(TabContentsWrapper* contents, int index) {
2735   TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH);
2736 }
2737 
TabDeselected(TabContentsWrapper * contents)2738 void Browser::TabDeselected(TabContentsWrapper* contents) {
2739   if (instant())
2740     instant()->DestroyPreviewContents();
2741 
2742   // Save what the user's currently typing, so it can be restored when we
2743   // switch back to this tab.
2744   window_->GetLocationBar()->SaveStateToContents(contents->tab_contents());
2745 }
2746 
TabSelectedAt(TabContentsWrapper * old_contents,TabContentsWrapper * new_contents,int index,bool user_gesture)2747 void Browser::TabSelectedAt(TabContentsWrapper* old_contents,
2748                             TabContentsWrapper* new_contents,
2749                             int index,
2750                             bool user_gesture) {
2751   if (old_contents == new_contents)
2752     return;
2753 
2754   // On some platforms we want to automatically reload tabs that are
2755   // killed when the user selects them.
2756   if (user_gesture && new_contents->tab_contents()->crashed_status() ==
2757         base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
2758     const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
2759     if (parsed_command_line.HasSwitch(switches::kReloadKilledTabs)) {
2760       Reload(CURRENT_TAB);
2761       return;
2762     }
2763   }
2764 
2765   // If we have any update pending, do it now.
2766   if (!chrome_updater_factory_.empty() && old_contents)
2767     ProcessPendingUIUpdates();
2768 
2769   // Propagate the profile to the location bar.
2770   UpdateToolbar(true);
2771 
2772   // Update reload/stop state.
2773   UpdateReloadStopState(new_contents->tab_contents()->is_loading(), true);
2774 
2775   // Update commands to reflect current state.
2776   UpdateCommandsForTabState();
2777 
2778   // Reset the status bubble.
2779   StatusBubble* status_bubble = GetStatusBubble();
2780   if (status_bubble) {
2781     status_bubble->Hide();
2782 
2783     // Show the loading state (if any).
2784     status_bubble->SetStatus(GetSelectedTabContentsWrapper()->GetStatusText());
2785   }
2786 
2787   if (HasFindBarController()) {
2788     find_bar_controller_->ChangeTabContents(new_contents);
2789     find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true);
2790   }
2791 
2792   // Update sessions. Don't force creation of sessions. If sessions doesn't
2793   // exist, the change will be picked up by sessions when created.
2794   if (profile_->HasSessionService()) {
2795     SessionService* session_service = profile_->GetSessionService();
2796     if (session_service && !tab_handler_->GetTabStripModel()->closing_all()) {
2797       session_service->SetSelectedTabInWindow(
2798           session_id(), tab_handler_->GetTabStripModel()->active_index());
2799     }
2800   }
2801 }
2802 
TabMoved(TabContentsWrapper * contents,int from_index,int to_index)2803 void Browser::TabMoved(TabContentsWrapper* contents,
2804                        int from_index,
2805                        int to_index) {
2806   DCHECK(from_index >= 0 && to_index >= 0);
2807   // Notify the history service.
2808   SyncHistoryWithTabs(std::min(from_index, to_index));
2809 }
2810 
TabReplacedAt(TabStripModel * tab_strip_model,TabContentsWrapper * old_contents,TabContentsWrapper * new_contents,int index)2811 void Browser::TabReplacedAt(TabStripModel* tab_strip_model,
2812                             TabContentsWrapper* old_contents,
2813                             TabContentsWrapper* new_contents,
2814                             int index) {
2815   TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE);
2816   TabInsertedAt(new_contents, index,
2817                 (index == tab_handler_->GetTabStripModel()->active_index()));
2818 
2819   int entry_count = new_contents->controller().entry_count();
2820   if (entry_count > 0) {
2821     // Send out notification so that observers are updated appropriately.
2822     new_contents->controller().NotifyEntryChanged(
2823         new_contents->controller().GetEntryAtIndex(entry_count - 1),
2824         entry_count - 1);
2825   }
2826 
2827   SessionService* session_service = profile()->GetSessionService();
2828   if (session_service) {
2829     // The new_contents may end up with a different navigation stack. Force
2830     // the session service to update itself.
2831     session_service->TabRestored(
2832         &new_contents->controller(),
2833         tab_handler_->GetTabStripModel()->IsTabPinned(index));
2834   }
2835 
2836   DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
2837   if (devtools_manager)  // NULL in unit tests.
2838     devtools_manager->TabReplaced(old_contents, new_contents);
2839 }
2840 
TabPinnedStateChanged(TabContentsWrapper * contents,int index)2841 void Browser::TabPinnedStateChanged(TabContentsWrapper* contents, int index) {
2842   if (!profile()->HasSessionService())
2843     return;
2844   SessionService* session_service = profile()->GetSessionService();
2845   if (session_service) {
2846     session_service->SetPinnedState(
2847         session_id(),
2848         GetTabContentsAt(index)->controller().session_id(),
2849         tab_handler_->GetTabStripModel()->IsTabPinned(index));
2850   }
2851 }
2852 
TabStripEmpty()2853 void Browser::TabStripEmpty() {
2854   // Close the frame after we return to the message loop (not immediately,
2855   // otherwise it will destroy this object before the stack has a chance to
2856   // cleanly unwind.)
2857   // Note: This will be called several times if TabStripEmpty is called several
2858   //       times. This is because it does not close the window if tabs are
2859   //       still present.
2860   // NOTE: If you change to be immediate (no invokeLater) then you'll need to
2861   //       update BrowserList::CloseAllBrowsers.
2862   MessageLoop::current()->PostTask(
2863       FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame));
2864 }
2865 
2866 ///////////////////////////////////////////////////////////////////////////////
2867 // Browser, TabContentsDelegate implementation:
2868 
OpenURLFromTab(TabContents * source,const GURL & url,const GURL & referrer,WindowOpenDisposition disposition,PageTransition::Type transition)2869 void Browser::OpenURLFromTab(TabContents* source,
2870                              const GURL& url,
2871                              const GURL& referrer,
2872                              WindowOpenDisposition disposition,
2873                              PageTransition::Type transition) {
2874   browser::NavigateParams params(this, url, transition);
2875   params.source_contents =
2876     tabstrip_model()->GetTabContentsAt(
2877       tabstrip_model()->GetWrapperIndex(source));
2878   params.referrer = referrer;
2879   params.disposition = disposition;
2880   params.tabstrip_add_types = TabStripModel::ADD_NONE;
2881   params.window_action = browser::NavigateParams::SHOW_WINDOW;
2882   browser::Navigate(&params);
2883 }
2884 
NavigationStateChanged(const TabContents * source,unsigned changed_flags)2885 void Browser::NavigationStateChanged(const TabContents* source,
2886                                      unsigned changed_flags) {
2887   // Only update the UI when something visible has changed.
2888   if (changed_flags)
2889     ScheduleUIUpdate(source, changed_flags);
2890 
2891   // We don't schedule updates to commands since they will only change once per
2892   // navigation, so we don't have to worry about flickering.
2893   if (changed_flags & TabContents::INVALIDATE_URL)
2894     UpdateCommandsForTabState();
2895 }
2896 
AddNewContents(TabContents * source,TabContents * new_contents,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture)2897 void Browser::AddNewContents(TabContents* source,
2898                              TabContents* new_contents,
2899                              WindowOpenDisposition disposition,
2900                              const gfx::Rect& initial_pos,
2901                              bool user_gesture) {
2902   // No code for this yet
2903   DCHECK(disposition != SAVE_TO_DISK);
2904   // Can't create a new contents for the current tab - invalid case.
2905   DCHECK(disposition != CURRENT_TAB);
2906 
2907   // TODO(beng): This belongs behind the platform-specific View interface.
2908   //             That's why it's there. http://crbug.com/78853
2909 #if defined(OS_CHROMEOS)
2910   if (disposition == NEW_POPUP) {
2911     // If the popup is bigger than a given factor of the screen, then
2912     // turn it into a foreground tab (on chrome os only)
2913     // Also check for width or height == 0, which would otherwise indicate
2914     // a tab sized popup window.
2915     GdkScreen* screen = gdk_screen_get_default();
2916     int max_width = gdk_screen_get_width(screen) * kPopupMaxWidthFactor;
2917     int max_height = gdk_screen_get_height(screen) * kPopupMaxHeightFactor;
2918     if (initial_pos.width() > max_width || initial_pos.width() == 0 ||
2919         initial_pos.height() > max_height || initial_pos.height() == 0) {
2920       disposition = NEW_FOREGROUND_TAB;
2921     }
2922   }
2923 #endif
2924 
2925   TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents);
2926   browser::NavigateParams params(this, wrapper);
2927   params.source_contents =
2928       tabstrip_model()->GetTabContentsAt(
2929           tabstrip_model()->GetWrapperIndex(source));
2930   params.disposition = disposition;
2931   params.window_bounds = initial_pos;
2932   // If we create a popup or panel from a non user-gesture, don't activate
2933   // the new window / panel.
2934   if (disposition == NEW_POPUP && !user_gesture)
2935     params.window_action = browser::NavigateParams::SHOW_WINDOW_INACTIVE;
2936   else
2937     params.window_action = browser::NavigateParams::SHOW_WINDOW;
2938   browser::Navigate(&params);
2939 }
2940 
ActivateContents(TabContents * contents)2941 void Browser::ActivateContents(TabContents* contents) {
2942   tab_handler_->GetTabStripModel()->ActivateTabAt(
2943       tab_handler_->GetTabStripModel()->GetWrapperIndex(contents), false);
2944   window_->Activate();
2945 }
2946 
DeactivateContents(TabContents * contents)2947 void Browser::DeactivateContents(TabContents* contents) {
2948   window_->Deactivate();
2949 }
2950 
LoadingStateChanged(TabContents * source)2951 void Browser::LoadingStateChanged(TabContents* source) {
2952   window_->UpdateLoadingAnimations(
2953       tab_handler_->GetTabStripModel()->TabsAreLoading());
2954   window_->UpdateTitleBar();
2955 
2956   TabContents* selected_contents = GetSelectedTabContents();
2957   if (source == selected_contents) {
2958     UpdateReloadStopState(source->is_loading(), false);
2959     if (GetStatusBubble()) {
2960       GetStatusBubble()->SetStatus(
2961           GetSelectedTabContentsWrapper()->GetStatusText());
2962     }
2963 
2964     if (!source->is_loading() &&
2965         pending_web_app_action_ == UPDATE_SHORTCUT) {
2966       // Schedule a shortcut update when web application info is available if
2967       // last committed entry is not NULL. Last committed entry could be NULL
2968       // when an interstitial page is injected (e.g. bad https certificate,
2969       // malware site etc). When this happens, we abort the shortcut update.
2970       NavigationEntry* entry = source->controller().GetLastCommittedEntry();
2971       if (entry) {
2972         TabContentsWrapper::GetCurrentWrapperForContents(source)->
2973             extension_tab_helper()->GetApplicationInfo(entry->page_id());
2974       } else {
2975         pending_web_app_action_ = NONE;
2976       }
2977     }
2978   }
2979 }
2980 
CloseContents(TabContents * source)2981 void Browser::CloseContents(TabContents* source) {
2982   if (is_attempting_to_close_browser_) {
2983     // If we're trying to close the browser, just clear the state related to
2984     // waiting for unload to fire. Don't actually try to close the tab as it
2985     // will go down the slow shutdown path instead of the fast path of killing
2986     // all the renderer processes.
2987     ClearUnloadState(source, true);
2988     return;
2989   }
2990 
2991   int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source);
2992   if (index == TabStripModel::kNoTab) {
2993     NOTREACHED() << "CloseContents called for tab not in our strip";
2994     return;
2995   }
2996   tab_handler_->GetTabStripModel()->CloseTabContentsAt(
2997       index,
2998       TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
2999 }
3000 
MoveContents(TabContents * source,const gfx::Rect & pos)3001 void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
3002   if ((type() & TYPE_POPUP) == 0) {
3003     NOTREACHED() << "moving invalid browser type";
3004     return;
3005   }
3006   window_->SetBounds(pos);
3007 }
3008 
DetachContents(TabContents * source)3009 void Browser::DetachContents(TabContents* source) {
3010   int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source);
3011   if (index >= 0)
3012     tab_handler_->GetTabStripModel()->DetachTabContentsAt(index);
3013 }
3014 
IsPopup(const TabContents * source) const3015 bool Browser::IsPopup(const TabContents* source) const {
3016   // A non-tabbed BROWSER is an unconstrained popup.
3017   return !!(type() & TYPE_POPUP);
3018 }
3019 
ContentsMouseEvent(TabContents * source,const gfx::Point & location,bool motion)3020 void Browser::ContentsMouseEvent(
3021     TabContents* source, const gfx::Point& location, bool motion) {
3022   if (!GetStatusBubble())
3023     return;
3024 
3025   if (source == GetSelectedTabContents()) {
3026     GetStatusBubble()->MouseMoved(location, !motion);
3027     if (!motion)
3028       GetStatusBubble()->SetURL(GURL(), string16());
3029   }
3030 }
3031 
UpdateTargetURL(TabContents * source,const GURL & url)3032 void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
3033   if (!GetStatusBubble())
3034     return;
3035 
3036   if (source == GetSelectedTabContents()) {
3037     PrefService* prefs = profile_->GetPrefs();
3038     GetStatusBubble()->SetURL(
3039         url, UTF8ToUTF16(prefs->GetString(prefs::kAcceptLanguages)));
3040   }
3041 }
3042 
UpdateDownloadShelfVisibility(bool visible)3043 void Browser::UpdateDownloadShelfVisibility(bool visible) {
3044   if (GetStatusBubble())
3045     GetStatusBubble()->UpdateDownloadShelfVisibility(visible);
3046 }
3047 
UseVerticalTabs() const3048 bool Browser::UseVerticalTabs() const {
3049   return use_vertical_tabs_.GetValue();
3050 }
3051 
ContentsZoomChange(bool zoom_in)3052 void Browser::ContentsZoomChange(bool zoom_in) {
3053   ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
3054 }
3055 
OnContentSettingsChange(TabContents * source)3056 void Browser::OnContentSettingsChange(TabContents* source) {
3057   if (source == GetSelectedTabContents()) {
3058     LocationBar* location_bar = window()->GetLocationBar();
3059     if (location_bar)
3060       location_bar->UpdateContentSettingsIcons();
3061   }
3062 }
3063 
SetTabContentBlocked(TabContents * contents,bool blocked)3064 void Browser::SetTabContentBlocked(TabContents* contents, bool blocked) {
3065   int index = tabstrip_model()->GetWrapperIndex(contents);
3066   if (index == TabStripModel::kNoTab) {
3067     NOTREACHED();
3068     return;
3069   }
3070   tabstrip_model()->SetTabBlocked(index, blocked);
3071 }
3072 
TabContentsFocused(TabContents * tab_content)3073 void Browser::TabContentsFocused(TabContents* tab_content) {
3074   window_->TabContentsFocused(tab_content);
3075 }
3076 
TakeFocus(bool reverse)3077 bool Browser::TakeFocus(bool reverse) {
3078   NotificationService::current()->Notify(
3079       NotificationType::FOCUS_RETURNED_TO_BROWSER,
3080       Source<Browser>(this),
3081       NotificationService::NoDetails());
3082   return false;
3083 }
3084 
IsApplication() const3085 bool Browser::IsApplication() const {
3086   return (type_ & TYPE_APP) != 0;
3087 }
3088 
ConvertContentsToApplication(TabContents * contents)3089 void Browser::ConvertContentsToApplication(TabContents* contents) {
3090   const GURL& url = contents->controller().GetActiveEntry()->url();
3091   std::string app_name = web_app::GenerateApplicationNameFromURL(url);
3092   RegisterAppPrefs(app_name, contents->profile());
3093 
3094   DetachContents(contents);
3095   Browser* app_browser = Browser::CreateForApp(
3096       app_name, gfx::Size(), profile_, false);
3097   TabContentsWrapper* wrapper = new TabContentsWrapper(contents);
3098   app_browser->tabstrip_model()->AppendTabContents(wrapper, true);
3099 
3100   contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
3101   contents->render_view_host()->SyncRendererPrefs();
3102   app_browser->window()->Show();
3103 }
3104 
ShouldDisplayURLField()3105 bool Browser::ShouldDisplayURLField() {
3106   return !IsApplication();
3107 }
3108 
BeforeUnloadFired(TabContents * tab,bool proceed,bool * proceed_to_fire_unload)3109 void Browser::BeforeUnloadFired(TabContents* tab,
3110                                 bool proceed,
3111                                 bool* proceed_to_fire_unload) {
3112   if (!is_attempting_to_close_browser_) {
3113     *proceed_to_fire_unload = proceed;
3114     if (!proceed)
3115       tab->set_closed_by_user_gesture(false);
3116     return;
3117   }
3118 
3119   if (!proceed) {
3120     CancelWindowClose();
3121     *proceed_to_fire_unload = false;
3122     tab->set_closed_by_user_gesture(false);
3123     return;
3124   }
3125 
3126   if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) {
3127     // Now that beforeunload has fired, put the tab on the queue to fire
3128     // unload.
3129     tabs_needing_unload_fired_.insert(tab);
3130     ProcessPendingTabs();
3131     // We want to handle firing the unload event ourselves since we want to
3132     // fire all the beforeunload events before attempting to fire the unload
3133     // events should the user cancel closing the browser.
3134     *proceed_to_fire_unload = false;
3135     return;
3136   }
3137 
3138   *proceed_to_fire_unload = true;
3139 }
3140 
ShowHtmlDialog(HtmlDialogUIDelegate * delegate,gfx::NativeWindow parent_window)3141 void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
3142                              gfx::NativeWindow parent_window) {
3143   window_->ShowHTMLDialog(delegate, parent_window);
3144 }
3145 
SetFocusToLocationBar(bool select_all)3146 void Browser::SetFocusToLocationBar(bool select_all) {
3147   // Two differences between this and FocusLocationBar():
3148   // (1) This doesn't get recorded in user metrics, since it's called
3149   //     internally.
3150   // (2) This checks whether the location bar can be focused, and if not, clears
3151   //     the focus.  FocusLocationBar() is only reached when the location bar is
3152   //     focusable, but this may be reached at other times, e.g. while in
3153   //     fullscreen mode, where we need to leave focus in a consistent state.
3154   window_->SetFocusToLocationBar(select_all);
3155 }
3156 
RenderWidgetShowing()3157 void Browser::RenderWidgetShowing() {
3158   window_->DisableInactiveFrame();
3159 }
3160 
GetExtraRenderViewHeight() const3161 int Browser::GetExtraRenderViewHeight() const {
3162   return window_->GetExtraRenderViewHeight();
3163 }
3164 
OnStartDownload(DownloadItem * download,TabContents * tab)3165 void Browser::OnStartDownload(DownloadItem* download, TabContents* tab) {
3166   if (!window())
3167     return;
3168 
3169 #if defined(OS_CHROMEOS)
3170   // Don't show content browser for extension/theme downloads from gallery.
3171   if (download->is_extension_install()) {
3172     ExtensionService* service = profile_->GetExtensionService();
3173     if (service && service->IsDownloadFromGallery(download->url(),
3174                                                   download->referrer_url())) {
3175       return;
3176     }
3177   }
3178   // Open the Active Downloads ui for chromeos.
3179   ActiveDownloadsUI::OpenPopup(profile_);
3180 #else
3181   // GetDownloadShelf creates the download shelf if it was not yet created.
3182   window()->GetDownloadShelf()->AddDownload(new DownloadItemModel(download));
3183 
3184   // Don't show the animation for "Save file" downloads.
3185   if (download->total_bytes() <= 0)
3186     return;
3187 
3188   // For non-theme extensions, we don't show the download animation.
3189   if (download->is_extension_install() &&
3190       !ExtensionService::IsDownloadFromMiniGallery(download->url()))
3191     return;
3192 
3193   TabContents* current_tab = GetSelectedTabContents();
3194   // We make this check for the case of minimized windows, unit tests, etc.
3195   if (platform_util::IsVisible(current_tab->GetNativeView()) &&
3196       ui::Animation::ShouldRenderRichAnimation()) {
3197     DownloadStartedAnimation::Show(current_tab);
3198   }
3199 #endif
3200 
3201   // If the download occurs in a new tab, close it
3202   if (tab->controller().IsInitialNavigation() &&
3203       GetConstrainingContents(tab) == tab && tab_count() > 1) {
3204     CloseContents(tab);
3205   }
3206 }
3207 
ShowPageInfo(Profile * profile,const GURL & url,const NavigationEntry::SSLStatus & ssl,bool show_history)3208 void Browser::ShowPageInfo(Profile* profile,
3209                            const GURL& url,
3210                            const NavigationEntry::SSLStatus& ssl,
3211                            bool show_history) {
3212   window()->ShowPageInfo(profile, url, ssl, show_history);
3213 }
3214 
ViewSourceForTab(TabContents * source,const GURL & page_url)3215 void Browser::ViewSourceForTab(TabContents* source, const GURL& page_url) {
3216   DCHECK(source);
3217   int index = tabstrip_model()->GetWrapperIndex(source);
3218   TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index);
3219   ViewSource(wrapper);
3220 }
3221 
ViewSourceForFrame(TabContents * source,const GURL & frame_url,const std::string & frame_content_state)3222 void Browser::ViewSourceForFrame(TabContents* source,
3223                                  const GURL& frame_url,
3224                                  const std::string& frame_content_state) {
3225   DCHECK(source);
3226   int index = tabstrip_model()->GetWrapperIndex(source);
3227   TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index);
3228   ViewSource(wrapper, frame_url, frame_content_state);
3229 }
3230 
PreHandleKeyboardEvent(const NativeWebKeyboardEvent & event,bool * is_keyboard_shortcut)3231 bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
3232                                      bool* is_keyboard_shortcut) {
3233   return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut);
3234 }
3235 
HandleKeyboardEvent(const NativeWebKeyboardEvent & event)3236 void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
3237   window()->HandleKeyboardEvent(event);
3238 }
3239 
ShowRepostFormWarningDialog(TabContents * tab_contents)3240 void Browser::ShowRepostFormWarningDialog(TabContents *tab_contents) {
3241   window()->ShowRepostFormWarningDialog(tab_contents);
3242 }
3243 
ShowContentSettingsPage(ContentSettingsType content_type)3244 void Browser::ShowContentSettingsPage(ContentSettingsType content_type) {
3245   ShowOptionsTab(
3246       chrome::kContentSettingsExceptionsSubPage + std::string(kHashMark) +
3247       ContentSettingsHandler::ContentSettingsTypeToGroupName(content_type));
3248 }
3249 
ShowCollectedCookiesDialog(TabContents * tab_contents)3250 void Browser::ShowCollectedCookiesDialog(TabContents *tab_contents) {
3251   window()->ShowCollectedCookiesDialog(tab_contents);
3252 }
3253 
ShouldAddNavigationToHistory(const history::HistoryAddPageArgs & add_page_args,NavigationType::Type navigation_type)3254 bool Browser::ShouldAddNavigationToHistory(
3255     const history::HistoryAddPageArgs& add_page_args,
3256     NavigationType::Type navigation_type) {
3257   // Don't update history if running as app.
3258   return !IsApplication();
3259 }
3260 
ContentRestrictionsChanged(TabContents * source)3261 void Browser::ContentRestrictionsChanged(TabContents* source) {
3262   UpdateCommandsForContentRestrictionState();
3263 }
3264 
WorkerCrashed()3265 void Browser::WorkerCrashed() {
3266   TabContents* tab_contents = GetSelectedTabContents();
3267   if (!tab_contents)
3268     return;
3269   tab_contents->AddInfoBar(new SimpleAlertInfoBarDelegate(tab_contents, NULL,
3270       l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT), true));
3271 }
3272 
3273 ///////////////////////////////////////////////////////////////////////////////
3274 // Browser, TabContentsWrapperDelegate implementation:
3275 
URLStarredChanged(TabContentsWrapper * source,bool starred)3276 void Browser::URLStarredChanged(TabContentsWrapper* source, bool starred) {
3277   if (source == GetSelectedTabContentsWrapper())
3278     window_->SetStarredState(starred);
3279 }
3280 
OnDidGetApplicationInfo(TabContentsWrapper * source,int32 page_id)3281 void Browser::OnDidGetApplicationInfo(TabContentsWrapper* source,
3282                                       int32 page_id) {
3283   if (GetSelectedTabContentsWrapper() != source)
3284     return;
3285 
3286   NavigationEntry* entry = source->controller().GetLastCommittedEntry();
3287   if (!entry || (entry->page_id() != page_id))
3288     return;
3289 
3290   switch (pending_web_app_action_) {
3291     case CREATE_SHORTCUT: {
3292       window()->ShowCreateWebAppShortcutsDialog(source);
3293       break;
3294     }
3295     case UPDATE_SHORTCUT: {
3296       web_app::UpdateShortcutForTabContents(source);
3297       break;
3298     }
3299     default:
3300       NOTREACHED();
3301       break;
3302   }
3303 
3304   pending_web_app_action_ = NONE;
3305 }
3306 
OnInstallApplication(TabContentsWrapper * source,const WebApplicationInfo & web_app)3307 void Browser::OnInstallApplication(TabContentsWrapper* source,
3308                                    const WebApplicationInfo& web_app) {
3309   ExtensionService* extensions_service = profile()->GetExtensionService();
3310   if (!extensions_service)
3311     return;
3312 
3313   scoped_refptr<CrxInstaller> installer(
3314       new CrxInstaller(extensions_service,
3315                        extensions_service->show_extensions_prompts() ?
3316                        new ExtensionInstallUI(profile()) : NULL));
3317   installer->InstallWebApp(web_app);
3318 }
3319 
3320 ///////////////////////////////////////////////////////////////////////////////
3321 // Browser, SearchEngineTabHelperDelegate implementation:
3322 
ConfirmSetDefaultSearchProvider(TabContents * tab_contents,TemplateURL * template_url,TemplateURLModel * template_url_model)3323 void Browser::ConfirmSetDefaultSearchProvider(
3324     TabContents* tab_contents,
3325     TemplateURL* template_url,
3326     TemplateURLModel* template_url_model) {
3327   window()->ConfirmSetDefaultSearchProvider(tab_contents, template_url,
3328                                             template_url_model);
3329 }
3330 
ConfirmAddSearchProvider(const TemplateURL * template_url,Profile * profile)3331 void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url,
3332                                        Profile* profile) {
3333   window()->ConfirmAddSearchProvider(template_url, profile);
3334 }
3335 
3336 ///////////////////////////////////////////////////////////////////////////////
3337 // Browser, SelectFileDialog::Listener implementation:
3338 
FileSelected(const FilePath & path,int index,void * params)3339 void Browser::FileSelected(const FilePath& path, int index, void* params) {
3340   profile_->set_last_selected_directory(path.DirName());
3341   GURL file_url = net::FilePathToFileURL(path);
3342   if (!file_url.is_empty())
3343     OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
3344 }
3345 
3346 ///////////////////////////////////////////////////////////////////////////////
3347 // Browser, NotificationObserver implementation:
3348 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)3349 void Browser::Observe(NotificationType type,
3350                       const NotificationSource& source,
3351                       const NotificationDetails& details) {
3352   switch (type.value) {
3353     case NotificationType::TAB_CONTENTS_DISCONNECTED:
3354       if (is_attempting_to_close_browser_) {
3355         // Pass in false so that we delay processing. We need to delay the
3356         // processing as it may close the tab, which is currently on the call
3357         // stack above us.
3358         ClearUnloadState(Source<TabContents>(source).ptr(), false);
3359       }
3360       break;
3361 
3362     case NotificationType::SSL_VISIBLE_STATE_CHANGED:
3363       // When the current tab's SSL state changes, we need to update the URL
3364       // bar to reflect the new state. Note that it's possible for the selected
3365       // tab contents to be NULL. This is because we listen for all sources
3366       // (NavigationControllers) for convenience, so the notification could
3367       // actually be for a different window while we're doing asynchronous
3368       // closing of this one.
3369       if (GetSelectedTabContents() &&
3370           &GetSelectedTabContents()->controller() ==
3371           Source<NavigationController>(source).ptr())
3372         UpdateToolbar(false);
3373       break;
3374 
3375     case NotificationType::EXTENSION_UPDATE_DISABLED: {
3376       // Show the UI if the extension was disabled for escalated permissions.
3377       Profile* profile = Source<Profile>(source).ptr();
3378       if (profile_->IsSameProfile(profile)) {
3379         ExtensionService* service = profile->GetExtensionService();
3380         DCHECK(service);
3381         const Extension* extension = Details<const Extension>(details).ptr();
3382         if (service->extension_prefs()->DidExtensionEscalatePermissions(
3383                 extension->id()))
3384           ShowExtensionDisabledUI(service, profile_, extension);
3385       }
3386       break;
3387     }
3388 
3389     case NotificationType::EXTENSION_UNLOADED: {
3390       window()->GetLocationBar()->UpdatePageActions();
3391 
3392       // Close any tabs from the unloaded extension.
3393       const Extension* extension =
3394           Details<UnloadedExtensionInfo>(details)->extension;
3395       TabStripModel* model = tab_handler_->GetTabStripModel();
3396       for (int i = model->count() - 1; i >= 0; --i) {
3397         TabContents* tc = model->GetTabContentsAt(i)->tab_contents();
3398         if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) &&
3399             tc->GetURL().host() == extension->id()) {
3400           CloseTabContents(tc);
3401         }
3402       }
3403 
3404       break;
3405     }
3406 
3407     case NotificationType::EXTENSION_PROCESS_TERMINATED: {
3408       window()->GetLocationBar()->InvalidatePageActions();
3409       break;
3410     }
3411 
3412     case NotificationType::EXTENSION_UNINSTALLED:
3413     case NotificationType::EXTENSION_LOADED:
3414       window()->GetLocationBar()->UpdatePageActions();
3415       break;
3416 
3417     case NotificationType::BROWSER_THEME_CHANGED:
3418       window()->UserChangedTheme();
3419       break;
3420 
3421     case NotificationType::EXTENSION_READY_FOR_INSTALL: {
3422       // Handle EXTENSION_READY_FOR_INSTALL for last active normal browser.
3423       if (BrowserList::FindBrowserWithType(profile(),
3424                                            Browser::TYPE_NORMAL,
3425                                            true) != this)
3426         break;
3427 
3428       // We only want to show the loading dialog for themes, but we don't want
3429       // to wait until unpack to find out an extension is a theme, so we test
3430       // the download_url GURL instead. This means that themes in the extensions
3431       // gallery won't get the loading dialog.
3432       GURL download_url = *(Details<GURL>(details).ptr());
3433       if (ExtensionService::IsDownloadFromMiniGallery(download_url))
3434         window()->ShowThemeInstallBubble();
3435       break;
3436     }
3437 
3438     case NotificationType::PREF_CHANGED: {
3439       const std::string& pref_name = *Details<std::string>(details).ptr();
3440       if (pref_name == prefs::kUseVerticalTabs) {
3441         UseVerticalTabsChanged();
3442       } else if (pref_name == prefs::kPrintingEnabled) {
3443         UpdatePrintingState(0);
3444       } else if (pref_name == prefs::kInstantEnabled) {
3445         if (!InstantController::IsEnabled(profile())) {
3446           if (instant()) {
3447             instant()->DestroyPreviewContents();
3448             instant_.reset();
3449             instant_unload_handler_.reset();
3450           }
3451         } else {
3452           CreateInstantIfNecessary();
3453         }
3454       } else if (pref_name == prefs::kDevToolsDisabled) {
3455         UpdateCommandsForDevTools();
3456         if (dev_tools_disabled_.GetValue())
3457           g_browser_process->devtools_manager()->CloseAllClientHosts();
3458       } else if (pref_name == prefs::kIncognitoEnabled) {
3459         break;  // No further action is required.
3460       } else if (pref_name == prefs::kEditBookmarksEnabled) {
3461         UpdateCommandsForBookmarkEditing();
3462       } else {
3463         NOTREACHED();
3464       }
3465       break;
3466     }
3467 
3468     default:
3469       NOTREACHED() << "Got a notification we didn't register for.";
3470   }
3471 }
3472 
3473 ///////////////////////////////////////////////////////////////////////////////
3474 // Browser, ProfileSyncServiceObserver implementation:
3475 
OnStateChanged()3476 void Browser::OnStateChanged() {
3477   DCHECK(profile_->GetProfileSyncService());
3478 
3479 #if !defined(OS_MACOSX)
3480   const bool show_main_ui = (type() == TYPE_NORMAL) && !window_->IsFullscreen();
3481 #else
3482   const bool show_main_ui = (type() == TYPE_NORMAL);
3483 #endif
3484 
3485   command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS,
3486       show_main_ui && profile_->IsSyncAccessible());
3487 }
3488 
3489 ///////////////////////////////////////////////////////////////////////////////
3490 // Browser, InstantDelegate implementation:
3491 
PrepareForInstant()3492 void Browser::PrepareForInstant() {
3493   window_->PrepareForInstant();
3494 }
3495 
ShowInstant(TabContentsWrapper * preview_contents)3496 void Browser::ShowInstant(TabContentsWrapper* preview_contents) {
3497   DCHECK(instant_->tab_contents() == GetSelectedTabContentsWrapper());
3498   window_->ShowInstant(preview_contents);
3499 }
3500 
HideInstant()3501 void Browser::HideInstant() {
3502   window_->HideInstant(instant_->is_active());
3503 }
3504 
CommitInstant(TabContentsWrapper * preview_contents)3505 void Browser::CommitInstant(TabContentsWrapper* preview_contents) {
3506   TabContentsWrapper* tab_contents = instant_->tab_contents();
3507   int index =
3508       tab_handler_->GetTabStripModel()->GetIndexOfTabContents(tab_contents);
3509   DCHECK_NE(TabStripModel::kNoTab, index);
3510   // TabStripModel takes ownership of preview_contents.
3511   tab_handler_->GetTabStripModel()->ReplaceTabContentsAt(
3512       index, preview_contents);
3513   // InstantUnloadHandler takes ownership of tab_contents.
3514   instant_unload_handler_->RunUnloadListenersOrDestroy(tab_contents, index);
3515 
3516   GURL url = preview_contents->tab_contents()->GetURL();
3517   DCHECK(profile_->GetExtensionService());
3518   if (profile_->GetExtensionService()->IsInstalledApp(url)) {
3519     UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram,
3520                               extension_misc::APP_LAUNCH_OMNIBOX_INSTANT,
3521                               extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
3522   }
3523 }
3524 
SetSuggestedText(const string16 & text,InstantCompleteBehavior behavior)3525 void Browser::SetSuggestedText(const string16& text,
3526                                InstantCompleteBehavior behavior) {
3527   window()->GetLocationBar()->SetSuggestedText(text, behavior);
3528 }
3529 
GetInstantBounds()3530 gfx::Rect Browser::GetInstantBounds() {
3531   return window()->GetInstantBounds();
3532 }
3533 
3534 ///////////////////////////////////////////////////////////////////////////////
3535 // Browser, protected:
3536 
CreateBrowserWindow()3537 BrowserWindow* Browser::CreateBrowserWindow() {
3538   if (type() == Browser::TYPE_APP_PANEL &&
3539       CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels))
3540     return PanelManager::GetInstance()->CreatePanel(this);
3541 
3542   return BrowserWindow::CreateBrowserWindow(this);
3543 }
3544 
3545 
3546 ///////////////////////////////////////////////////////////////////////////////
3547 // Browser, Command and state updating (private):
3548 
InitCommandState()3549 void Browser::InitCommandState() {
3550   // All browser commands whose state isn't set automagically some other way
3551   // (like Back & Forward with initial page load) must have their state
3552   // initialized here, otherwise they will be forever disabled.
3553 
3554   // Navigation commands
3555   command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
3556   command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true);
3557 
3558   // Window management commands
3559   command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW, true);
3560   command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW,
3561                                         incognito_mode_allowed_.GetValue());
3562   command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
3563   command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true);
3564   command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
3565   command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
3566   command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, false);
3567   command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
3568   command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, true);
3569 
3570   // Page-related commands
3571   command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, true);
3572   command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
3573   command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
3574   command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
3575   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
3576   command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
3577   command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
3578   command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
3579   command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
3580   command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
3581   command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
3582   command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
3583   command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
3584   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
3585   command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
3586   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
3587   command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
3588   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
3589   command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
3590   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
3591   command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
3592   command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
3593   command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
3594   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
3595   command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
3596   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
3597   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
3598   command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
3599   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
3600   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
3601   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
3602   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
3603   command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
3604   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
3605   command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
3606   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
3607   command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true);
3608   command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
3609   command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
3610 
3611   // Zoom
3612   command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
3613   command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
3614   command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
3615   command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
3616 
3617   // Show various bits of UI
3618   command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
3619   command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
3620   UpdateCommandsForDevTools();
3621   command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
3622   command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
3623   command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER,
3624                                         browser_defaults::bookmarks_enabled);
3625   command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
3626   command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
3627   command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true);
3628 
3629 #if defined(OS_CHROMEOS)
3630   command_updater_.UpdateCommandEnabled(IDC_FILE_MANAGER, true);
3631   command_updater_.UpdateCommandEnabled(IDC_SEARCH, true);
3632   command_updater_.UpdateCommandEnabled(IDC_SHOW_KEYBOARD_OVERLAY, true);
3633   command_updater_.UpdateCommandEnabled(IDC_SYSTEM_OPTIONS, true);
3634   command_updater_.UpdateCommandEnabled(IDC_INTERNET_OPTIONS, true);
3635 #endif
3636 
3637   ExtensionService* extensions_service = profile()->GetExtensionService();
3638   bool enable_extensions =
3639       extensions_service && extensions_service->extensions_enabled();
3640   command_updater_.UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS,
3641                                         enable_extensions);
3642 
3643   // Initialize other commands based on the window type.
3644   bool normal_window = type() == TYPE_NORMAL;
3645   bool non_devtools_window = type() != TYPE_DEVTOOLS;
3646 
3647   // Navigation commands
3648   command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window);
3649 
3650   // Window management commands
3651   command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN,
3652       type() != TYPE_APP_PANEL);
3653   command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
3654   command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
3655                                         normal_window);
3656   command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, normal_window);
3657   command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, normal_window);
3658   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
3659   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
3660   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
3661   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
3662   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
3663   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
3664   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
3665   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
3666   command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
3667 #if defined(OS_MACOSX)
3668   command_updater_.UpdateCommandEnabled(IDC_TABPOSE, normal_window);
3669 #endif
3670 
3671   // Clipboard commands
3672   command_updater_.UpdateCommandEnabled(IDC_COPY_URL, non_devtools_window);
3673 
3674   // Find-in-page
3675   command_updater_.UpdateCommandEnabled(IDC_FIND, non_devtools_window);
3676   command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, non_devtools_window);
3677   command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, non_devtools_window);
3678 
3679   // Autofill
3680   command_updater_.UpdateCommandEnabled(IDC_AUTOFILL_DEFAULT,
3681                                         non_devtools_window);
3682 
3683   // Show various bits of UI
3684   command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window);
3685 
3686   // The upgrade entry and the view incompatibility entry should always be
3687   // enabled. Whether they are visible is a separate matter determined on menu
3688   // show.
3689   command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true);
3690   command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true);
3691 
3692   // View Background Pages entry is always enabled, but is hidden if there are
3693   // no background pages.
3694   command_updater_.UpdateCommandEnabled(IDC_VIEW_BACKGROUND_PAGES, true);
3695 
3696   // Initialize other commands whose state changes based on fullscreen mode.
3697   UpdateCommandsForFullscreenMode(false);
3698 
3699   UpdateCommandsForContentRestrictionState();
3700 
3701   UpdateCommandsForBookmarkEditing();
3702 }
3703 
UpdateCommandsForTabState()3704 void Browser::UpdateCommandsForTabState() {
3705   TabContents* current_tab = GetSelectedTabContents();
3706   TabContentsWrapper* current_tab_wrapper = GetSelectedTabContentsWrapper();
3707   if (!current_tab || !current_tab_wrapper)  // May be NULL during tab restore.
3708     return;
3709 
3710   // Navigation commands
3711   NavigationController& nc = current_tab->controller();
3712   command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack());
3713   command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward());
3714   command_updater_.UpdateCommandEnabled(IDC_RELOAD,
3715                                         CanReloadContents(current_tab));
3716   command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE,
3717                                         CanReloadContents(current_tab));
3718 
3719   // Window management commands
3720   bool non_app_window = !(type() & TYPE_APP);
3721   command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
3722       non_app_window && CanDuplicateContentsAt(active_index()));
3723 
3724   // Page-related commands
3725   window_->SetStarredState(current_tab_wrapper->is_starred());
3726   command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
3727       current_tab->controller().CanViewSource());
3728   command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION,
3729       current_tab->ShouldDisplayURL() && current_tab->GetURL().is_valid());
3730 
3731   // Changing the encoding is not possible on Chrome-internal webpages.
3732   // Instead of using GetURL here, we use url() (which is the "real" url of the
3733   // page) from the NavigationEntry because its reflects their origin rather
3734   // than the display one (returned by GetURL) which may be different (like
3735   // having "view-source:" on the front).
3736   NavigationEntry* active_entry = nc.GetActiveEntry();
3737   bool is_chrome_internal = (active_entry ?
3738       active_entry->url().SchemeIs(chrome::kChromeUIScheme) : false);
3739   command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
3740       !is_chrome_internal && SavePackage::IsSavableContents(
3741           current_tab->contents_mime_type()));
3742 
3743   // Show various bits of UI
3744   // TODO(pinkerton): Disable app-mode in the model until we implement it
3745   // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148
3746 #if !defined(OS_MACOSX)
3747   command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
3748       web_app::IsValidUrl(current_tab->GetURL()));
3749 #endif
3750 
3751   UpdateCommandsForContentRestrictionState();
3752   UpdateCommandsForBookmarkEditing();
3753 }
3754 
UpdateCommandsForContentRestrictionState()3755 void Browser::UpdateCommandsForContentRestrictionState() {
3756   int restrictions = 0;
3757   TabContents* current_tab = GetSelectedTabContents();
3758   if (current_tab) {
3759     restrictions = current_tab->content_restrictions();
3760     NavigationEntry* active_entry = current_tab->controller().GetActiveEntry();
3761     // See comment in UpdateCommandsForTabState about why we call url().
3762     if (!SavePackage::IsSavableURL(active_entry ? active_entry->url() : GURL()))
3763       restrictions |= CONTENT_RESTRICTION_SAVE;
3764   }
3765 
3766   command_updater_.UpdateCommandEnabled(
3767       IDC_COPY, !(restrictions & CONTENT_RESTRICTION_COPY));
3768   command_updater_.UpdateCommandEnabled(
3769       IDC_CUT, !(restrictions & CONTENT_RESTRICTION_CUT));
3770   command_updater_.UpdateCommandEnabled(
3771       IDC_PASTE, !(restrictions & CONTENT_RESTRICTION_PASTE));
3772   command_updater_.UpdateCommandEnabled(
3773       IDC_SAVE_PAGE, !(restrictions & CONTENT_RESTRICTION_SAVE));
3774   UpdatePrintingState(restrictions);
3775 }
3776 
UpdatePrintingState(int content_restrictions)3777 void Browser::UpdatePrintingState(int content_restrictions) {
3778   bool enabled = true;
3779   if (content_restrictions & CONTENT_RESTRICTION_PRINT) {
3780     enabled = false;
3781   } else if (g_browser_process->local_state()) {
3782     enabled = printing_enabled_.GetValue();
3783   }
3784   command_updater_.UpdateCommandEnabled(IDC_PRINT, enabled);
3785 }
3786 
UpdateReloadStopState(bool is_loading,bool force)3787 void Browser::UpdateReloadStopState(bool is_loading, bool force) {
3788   window_->UpdateReloadStopState(is_loading, force);
3789   command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
3790 }
3791 
UpdateCommandsForDevTools()3792 void Browser::UpdateCommandsForDevTools() {
3793   bool dev_tools_enabled = !dev_tools_disabled_.GetValue();
3794   command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS,
3795                                         dev_tools_enabled);
3796   command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE,
3797                                         dev_tools_enabled);
3798   command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT,
3799                                         dev_tools_enabled);
3800 }
3801 
UpdateCommandsForBookmarkEditing()3802 void Browser::UpdateCommandsForBookmarkEditing() {
3803   bool enabled = edit_bookmarks_enabled_.GetValue() &&
3804                  browser_defaults::bookmarks_enabled;
3805 
3806   command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE,
3807       enabled && type() == TYPE_NORMAL);
3808   command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS,
3809       enabled && CanBookmarkAllTabs());
3810 }
3811 
3812 ///////////////////////////////////////////////////////////////////////////////
3813 // Browser, UI update coalescing and handling (private):
3814 
UpdateToolbar(bool should_restore_state)3815 void Browser::UpdateToolbar(bool should_restore_state) {
3816   window_->UpdateToolbar(GetSelectedTabContentsWrapper(), should_restore_state);
3817 }
3818 
ScheduleUIUpdate(const TabContents * source,unsigned changed_flags)3819 void Browser::ScheduleUIUpdate(const TabContents* source,
3820                                unsigned changed_flags) {
3821   if (!source)
3822     return;
3823 
3824   // Do some synchronous updates.
3825   if (changed_flags & TabContents::INVALIDATE_URL &&
3826       source == GetSelectedTabContents()) {
3827     // Only update the URL for the current tab. Note that we do not update
3828     // the navigation commands since those would have already been updated
3829     // synchronously by NavigationStateChanged.
3830     UpdateToolbar(false);
3831     changed_flags &= ~TabContents::INVALIDATE_URL;
3832   }
3833   if (changed_flags & TabContents::INVALIDATE_LOAD) {
3834     // Update the loading state synchronously. This is so the throbber will
3835     // immediately start/stop, which gives a more snappy feel. We want to do
3836     // this for any tab so they start & stop quickly.
3837     tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
3838         tab_handler_->GetTabStripModel()->GetIndexOfController(
3839             &source->controller()),
3840         TabStripModelObserver::LOADING_ONLY);
3841     // The status bubble needs to be updated during INVALIDATE_LOAD too, but
3842     // we do that asynchronously by not stripping INVALIDATE_LOAD from
3843     // changed_flags.
3844   }
3845 
3846   if (changed_flags & TabContents::INVALIDATE_TITLE && !source->is_loading()) {
3847     // To correctly calculate whether the title changed while not loading
3848     // we need to process the update synchronously. This state only matters for
3849     // the TabStripModel, so we notify the TabStripModel now and notify others
3850     // asynchronously.
3851     tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
3852         tab_handler_->GetTabStripModel()->GetIndexOfController(
3853             &source->controller()),
3854         TabStripModelObserver::TITLE_NOT_LOADING);
3855   }
3856 
3857   if (changed_flags & TabContents::INVALIDATE_BOOKMARK_BAR) {
3858     window()->ShelfVisibilityChanged();
3859     changed_flags &= ~TabContents::INVALIDATE_BOOKMARK_BAR;
3860   }
3861 
3862   // If the only updates were synchronously handled above, we're done.
3863   if (changed_flags == 0)
3864     return;
3865 
3866   // Save the dirty bits.
3867   scheduled_updates_[source] |= changed_flags;
3868 
3869   if (chrome_updater_factory_.empty()) {
3870     // No task currently scheduled, start another.
3871     MessageLoop::current()->PostDelayedTask(
3872         FROM_HERE,
3873         chrome_updater_factory_.NewRunnableMethod(
3874             &Browser::ProcessPendingUIUpdates),
3875             kUIUpdateCoalescingTimeMS);
3876   }
3877 }
3878 
ProcessPendingUIUpdates()3879 void Browser::ProcessPendingUIUpdates() {
3880 #ifndef NDEBUG
3881   // Validate that all tabs we have pending updates for exist. This is scary
3882   // because the pending list must be kept in sync with any detached or
3883   // deleted tabs.
3884   for (UpdateMap::const_iterator i = scheduled_updates_.begin();
3885        i != scheduled_updates_.end(); ++i) {
3886     bool found = false;
3887     for (int tab = 0; tab < tab_count(); tab++) {
3888       if (GetTabContentsAt(tab) == i->first) {
3889         found = true;
3890         break;
3891       }
3892     }
3893     DCHECK(found);
3894   }
3895 #endif
3896 
3897   chrome_updater_factory_.RevokeAll();
3898 
3899   for (UpdateMap::const_iterator i = scheduled_updates_.begin();
3900        i != scheduled_updates_.end(); ++i) {
3901     // Do not dereference |contents|, it may be out-of-date!
3902     const TabContents* contents = i->first;
3903     unsigned flags = i->second;
3904 
3905     if (contents == GetSelectedTabContents()) {
3906       // Updates that only matter when the tab is selected go here.
3907 
3908       if (flags & TabContents::INVALIDATE_PAGE_ACTIONS) {
3909         LocationBar* location_bar = window()->GetLocationBar();
3910         if (location_bar)
3911           location_bar->UpdatePageActions();
3912       }
3913       // Updating the URL happens synchronously in ScheduleUIUpdate.
3914       if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble()) {
3915         GetStatusBubble()->SetStatus(
3916             GetSelectedTabContentsWrapper()->GetStatusText());
3917       }
3918 
3919       if (flags & (TabContents::INVALIDATE_TAB |
3920                    TabContents::INVALIDATE_TITLE)) {
3921 // TODO(pinkerton): Disable app-mode in the model until we implement it
3922 // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148
3923 #if !defined(OS_MACOSX)
3924         command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
3925             web_app::IsValidUrl(contents->GetURL()));
3926 #endif
3927         window_->UpdateTitleBar();
3928       }
3929     }
3930 
3931     // Updates that don't depend upon the selected state go here.
3932     if (flags & (TabContents::INVALIDATE_TAB | TabContents::INVALIDATE_TITLE)) {
3933       tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
3934           tab_handler_->GetTabStripModel()->GetWrapperIndex(contents),
3935           TabStripModelObserver::ALL);
3936     }
3937 
3938     // We don't need to process INVALIDATE_STATE, since that's not visible.
3939   }
3940 
3941   scheduled_updates_.clear();
3942 }
3943 
RemoveScheduledUpdatesFor(TabContents * contents)3944 void Browser::RemoveScheduledUpdatesFor(TabContents* contents) {
3945   if (!contents)
3946     return;
3947 
3948   UpdateMap::iterator i = scheduled_updates_.find(contents);
3949   if (i != scheduled_updates_.end())
3950     scheduled_updates_.erase(i);
3951 }
3952 
3953 
3954 ///////////////////////////////////////////////////////////////////////////////
3955 // Browser, Getters for UI (private):
3956 
GetStatusBubble()3957 StatusBubble* Browser::GetStatusBubble() {
3958 #if !defined(OS_MACOSX)
3959   // In kiosk mode, we want to always hide the status bubble.
3960   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
3961     return NULL;
3962 #endif
3963   return window_ ? window_->GetStatusBubble() : NULL;
3964 }
3965 
3966 ///////////////////////////////////////////////////////////////////////////////
3967 // Browser, Session restore functions (private):
3968 
SyncHistoryWithTabs(int index)3969 void Browser::SyncHistoryWithTabs(int index) {
3970   if (!profile()->HasSessionService())
3971     return;
3972   SessionService* session_service = profile()->GetSessionService();
3973   if (session_service) {
3974     for (int i = index; i < tab_count(); ++i) {
3975       TabContents* contents = GetTabContentsAt(i);
3976       if (contents) {
3977         session_service->SetTabIndexInWindow(
3978             session_id(), contents->controller().session_id(), i);
3979         session_service->SetPinnedState(
3980             session_id(),
3981             contents->controller().session_id(),
3982             tab_handler_->GetTabStripModel()->IsTabPinned(i));
3983       }
3984     }
3985   }
3986 }
3987 
3988 ///////////////////////////////////////////////////////////////////////////////
3989 // Browser, OnBeforeUnload handling (private):
3990 
ProcessPendingTabs()3991 void Browser::ProcessPendingTabs() {
3992   if (!is_attempting_to_close_browser_) {
3993     // Because we might invoke this after a delay it's possible for the value of
3994     // is_attempting_to_close_browser_ to have changed since we scheduled the
3995     // task.
3996     return;
3997   }
3998 
3999   if (HasCompletedUnloadProcessing()) {
4000     // We've finished all the unload events and can proceed to close the
4001     // browser.
4002     OnWindowClosing();
4003     return;
4004   }
4005 
4006   // Process beforeunload tabs first. When that queue is empty, process
4007   // unload tabs.
4008   if (!tabs_needing_before_unload_fired_.empty()) {
4009     TabContents* tab = *(tabs_needing_before_unload_fired_.begin());
4010     // Null check render_view_host here as this gets called on a PostTask and
4011     // the tab's render_view_host may have been nulled out.
4012     if (tab->render_view_host()) {
4013       tab->render_view_host()->FirePageBeforeUnload(false);
4014     } else {
4015       ClearUnloadState(tab, true);
4016     }
4017   } else if (!tabs_needing_unload_fired_.empty()) {
4018     // We've finished firing all beforeunload events and can proceed with unload
4019     // events.
4020     // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
4021     // somewhere around here so that we have accurate measurements of shutdown
4022     // time.
4023     // TODO(ojan): We can probably fire all the unload events in parallel and
4024     // get a perf benefit from that in the cases where the tab hangs in it's
4025     // unload handler or takes a long time to page in.
4026     TabContents* tab = *(tabs_needing_unload_fired_.begin());
4027     // Null check render_view_host here as this gets called on a PostTask and
4028     // the tab's render_view_host may have been nulled out.
4029     if (tab->render_view_host()) {
4030       tab->render_view_host()->ClosePage(false, -1, -1);
4031     } else {
4032       ClearUnloadState(tab, true);
4033     }
4034   } else {
4035     NOTREACHED();
4036   }
4037 }
4038 
HasCompletedUnloadProcessing() const4039 bool Browser::HasCompletedUnloadProcessing() const {
4040   return is_attempting_to_close_browser_ &&
4041       tabs_needing_before_unload_fired_.empty() &&
4042       tabs_needing_unload_fired_.empty();
4043 }
4044 
CancelWindowClose()4045 void Browser::CancelWindowClose() {
4046   // Closing of window can be canceled from:
4047   // - canceling beforeunload
4048   // - disallowing closing from IsClosingPermitted.
4049   DCHECK(is_attempting_to_close_browser_);
4050   tabs_needing_before_unload_fired_.clear();
4051   tabs_needing_unload_fired_.clear();
4052   is_attempting_to_close_browser_ = false;
4053 
4054   // Inform TabCloseableStateWatcher that closing of window has been canceled.
4055   TabCloseableStateWatcher* watcher =
4056       g_browser_process->tab_closeable_state_watcher();
4057   if (watcher)
4058     watcher->OnWindowCloseCanceled(this);
4059 }
4060 
RemoveFromSet(UnloadListenerSet * set,TabContents * tab)4061 bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
4062   DCHECK(is_attempting_to_close_browser_);
4063 
4064   UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab);
4065   if (iter != set->end()) {
4066     set->erase(iter);
4067     return true;
4068   }
4069   return false;
4070 }
4071 
ClearUnloadState(TabContents * tab,bool process_now)4072 void Browser::ClearUnloadState(TabContents* tab, bool process_now) {
4073   // Closing of browser could be canceled (via IsClosingPermitted) between the
4074   // time when request was initiated and when this method is called, so check
4075   // for is_attempting_to_close_browser_ flag before proceeding.
4076   if (is_attempting_to_close_browser_) {
4077     RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
4078     RemoveFromSet(&tabs_needing_unload_fired_, tab);
4079     if (process_now) {
4080       ProcessPendingTabs();
4081     } else {
4082       MessageLoop::current()->PostTask(
4083           FROM_HERE,
4084           method_factory_.NewRunnableMethod(&Browser::ProcessPendingTabs));
4085     }
4086   }
4087 }
4088 
4089 ///////////////////////////////////////////////////////////////////////////////
4090 // Browser, In-progress download termination handling (private):
4091 
CheckDownloadsInProgress(bool * normal_downloads_are_present,bool * incognito_downloads_are_present)4092 void Browser::CheckDownloadsInProgress(bool* normal_downloads_are_present,
4093                                        bool* incognito_downloads_are_present) {
4094   *normal_downloads_are_present = false;
4095   *incognito_downloads_are_present = false;
4096 
4097   // If there are no download in-progress, our job is done.
4098   DownloadManager* download_manager = NULL;
4099   // But first we need to check for the existance of the download manager, as
4100   // GetDownloadManager() will unnecessarily try to create one if it does not
4101   // exist.
4102   if (profile()->HasCreatedDownloadManager())
4103     download_manager = profile()->GetDownloadManager();
4104   if (profile()->IsOffTheRecord()) {
4105     // Browser is incognito and so download_manager if present is for incognito
4106     // downloads.
4107     *incognito_downloads_are_present =
4108         (download_manager && download_manager->in_progress_count() != 0);
4109     // Check original profile.
4110     if (profile()->GetOriginalProfile()->HasCreatedDownloadManager())
4111       download_manager = profile()->GetOriginalProfile()->GetDownloadManager();
4112   }
4113 
4114   *normal_downloads_are_present =
4115       (download_manager && download_manager->in_progress_count() != 0);
4116 }
4117 
CanCloseWithInProgressDownloads()4118 bool Browser::CanCloseWithInProgressDownloads() {
4119   if (cancel_download_confirmation_state_ != NOT_PROMPTED) {
4120     if (cancel_download_confirmation_state_ == WAITING_FOR_RESPONSE) {
4121       // We need to hear from the user before we can close.
4122       return false;
4123     }
4124     // RESPONSE_RECEIVED case, the user decided to go along with the closing.
4125     return true;
4126   }
4127   // Indicated that normal (non-incognito) downloads are pending.
4128   bool normal_downloads_are_present = false;
4129   bool incognito_downloads_are_present = false;
4130   CheckDownloadsInProgress(&normal_downloads_are_present,
4131                       &incognito_downloads_are_present);
4132   if (!normal_downloads_are_present && !incognito_downloads_are_present)
4133     return true;
4134 
4135   if (is_attempting_to_close_browser_)
4136     return true;
4137 
4138   if ((!normal_downloads_are_present && !profile()->IsOffTheRecord()) ||
4139       (!incognito_downloads_are_present && profile()->IsOffTheRecord()))
4140     return true;
4141 
4142   // Let's figure out if we are the last window for our profile.
4143   // Note that we cannot just use BrowserList::GetBrowserCount as browser
4144   // windows closing is delayed and the returned count might include windows
4145   // that are being closed.
4146   // The browser allowed to be closed only if:
4147   // 1. It is a regular browser and there are no regular downloads present or
4148   //    this is not the last regular browser window.
4149   // 2. It is an incognito browser and there are no incognito downloads present
4150   //    or this is not the last incognito browser window.
4151   int count = 0;
4152   for (BrowserList::const_iterator iter = BrowserList::begin();
4153        iter != BrowserList::end(); ++iter) {
4154     // Don't count this browser window or any other in the process of closing.
4155     // Only consider normal browser windows, not popups.
4156     Browser* const browser = *iter;
4157     if (browser == this
4158         || browser->is_attempting_to_close_browser_
4159         || browser->type() != Browser::TYPE_NORMAL)
4160       continue;
4161 
4162     // Verify that this is not the last non-incognito or incognito browser,
4163     // depending on the pending downloads.
4164     if (normal_downloads_are_present && !profile()->IsOffTheRecord() &&
4165         browser->profile()->IsOffTheRecord())
4166       continue;
4167     if (incognito_downloads_are_present && profile()->IsOffTheRecord() &&
4168         !browser->profile()->IsOffTheRecord())
4169       continue;
4170 
4171     // We test the original profile, because an incognito browser window keeps
4172     // the original profile alive (and its DownloadManager).
4173     // We also need to test explicitly the profile directly so that 2 incognito
4174     // profiles count as a match.
4175     if ((*iter)->profile() == profile() ||
4176         (*iter)->profile()->GetOriginalProfile() == profile())
4177       count++;
4178   }
4179   if (count > 0)
4180     return true;
4181 
4182   cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE;
4183   window_->ConfirmBrowserCloseWithPendingDownloads();
4184 
4185   // Return false so the browser does not close.  We'll close if the user
4186   // confirms in the dialog.
4187   return false;
4188 }
4189 
4190 ///////////////////////////////////////////////////////////////////////////////
4191 // Browser, Assorted utility functions (private):
4192 
4193 // static
GetTabbedBrowser(Profile * profile,bool match_incognito)4194 Browser* Browser::GetTabbedBrowser(Profile* profile, bool match_incognito) {
4195   return BrowserList::FindBrowserWithType(profile, TYPE_NORMAL,
4196                                           match_incognito);
4197 }
4198 
4199 // static
GetOrCreateTabbedBrowser(Profile * profile)4200 Browser* Browser::GetOrCreateTabbedBrowser(Profile* profile) {
4201   Browser* browser = GetTabbedBrowser(profile, false);
4202   if (!browser)
4203     browser = Browser::Create(profile);
4204   return browser;
4205 }
4206 
SetAsDelegate(TabContentsWrapper * tab,Browser * delegate)4207 void Browser::SetAsDelegate(TabContentsWrapper* tab, Browser* delegate) {
4208   tab->tab_contents()->set_delegate(delegate);
4209   tab->set_delegate(delegate);
4210   tab->search_engine_tab_helper()->set_delegate(delegate);
4211 }
4212 
FindInPage(bool find_next,bool forward_direction)4213 void Browser::FindInPage(bool find_next, bool forward_direction) {
4214   ShowFindBar();
4215   if (find_next) {
4216     string16 find_text;
4217 #if defined(OS_MACOSX)
4218     // We always want to search for the contents of the find pasteboard on OS X.
4219     find_text = GetFindPboardText();
4220 #endif
4221     GetSelectedTabContentsWrapper()->
4222         find_tab_helper()->StartFinding(find_text,
4223                                         forward_direction,
4224                                         false);  // Not case sensitive.
4225   }
4226 }
4227 
CloseFrame()4228 void Browser::CloseFrame() {
4229   window_->Close();
4230 }
4231 
TabDetachedAtImpl(TabContentsWrapper * contents,int index,DetachType type)4232 void Browser::TabDetachedAtImpl(TabContentsWrapper* contents, int index,
4233                                 DetachType type) {
4234   if (type == DETACH_TYPE_DETACH) {
4235     // Save the current location bar state, but only if the tab being detached
4236     // is the selected tab.  Because saving state can conditionally revert the
4237     // location bar, saving the current tab's location bar state to a
4238     // non-selected tab can corrupt both tabs.
4239     if (contents == GetSelectedTabContentsWrapper()) {
4240       LocationBar* location_bar = window()->GetLocationBar();
4241       if (location_bar)
4242         location_bar->SaveStateToContents(contents->tab_contents());
4243     }
4244 
4245     if (!tab_handler_->GetTabStripModel()->closing_all())
4246       SyncHistoryWithTabs(0);
4247   }
4248 
4249   SetAsDelegate(contents, NULL);
4250   RemoveScheduledUpdatesFor(contents->tab_contents());
4251 
4252   if (find_bar_controller_.get() &&
4253       index == tab_handler_->GetTabStripModel()->active_index()) {
4254     find_bar_controller_->ChangeTabContents(NULL);
4255   }
4256 
4257   if (is_attempting_to_close_browser_) {
4258     // If this is the last tab with unload handlers, then ProcessPendingTabs
4259     // would call back into the TabStripModel (which is invoking this method on
4260     // us). Avoid that by passing in false so that the call to
4261     // ProcessPendingTabs is delayed.
4262     ClearUnloadState(contents->tab_contents(), false);
4263   }
4264 
4265   registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
4266                     Source<TabContentsWrapper>(contents));
4267 }
4268 
4269 // static
RegisterAppPrefs(const std::string & app_name,Profile * profile)4270 void Browser::RegisterAppPrefs(const std::string& app_name, Profile* profile) {
4271   // A set of apps that we've already started.
4272   static std::set<std::string>* g_app_names = NULL;
4273 
4274   if (!g_app_names)
4275     g_app_names = new std::set<std::string>;
4276 
4277   // Only register once for each app name.
4278   if (g_app_names->find(app_name) != g_app_names->end())
4279     return;
4280   g_app_names->insert(app_name);
4281 
4282   // We need to register the window position pref.
4283   std::string window_pref(prefs::kBrowserWindowPlacement);
4284   window_pref.append("_");
4285   window_pref.append(app_name);
4286   profile->GetPrefs()->RegisterDictionaryPref(window_pref.c_str());
4287 }
4288 
TabRestoreServiceChanged(TabRestoreService * service)4289 void Browser::TabRestoreServiceChanged(TabRestoreService* service) {
4290   command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
4291                                         !service->entries().empty());
4292 }
4293 
TabRestoreServiceDestroyed(TabRestoreService * service)4294 void Browser::TabRestoreServiceDestroyed(TabRestoreService* service) {
4295   if (!tab_restore_service_)
4296     return;
4297 
4298   DCHECK_EQ(tab_restore_service_, service);
4299   tab_restore_service_->RemoveObserver(this);
4300   tab_restore_service_ = NULL;
4301 }
4302 
4303 // Centralized method for creating a TabContents, configuring and installing
4304 // all its supporting objects and observers.
TabContentsFactory(Profile * profile,SiteInstance * site_instance,int routing_id,const TabContents * base_tab_contents,SessionStorageNamespace * session_storage_namespace)4305 TabContentsWrapper* Browser::TabContentsFactory(
4306     Profile* profile,
4307     SiteInstance* site_instance,
4308     int routing_id,
4309     const TabContents* base_tab_contents,
4310     SessionStorageNamespace* session_storage_namespace) {
4311   TabContents* new_contents = new TabContents(profile, site_instance,
4312                                               routing_id, base_tab_contents,
4313                                               session_storage_namespace);
4314   TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents);
4315   return wrapper;
4316 }
4317 
OpenInstant(WindowOpenDisposition disposition)4318 bool Browser::OpenInstant(WindowOpenDisposition disposition) {
4319   if (!instant() || !instant()->is_active() || !instant()->IsCurrent() ||
4320       disposition == NEW_BACKGROUND_TAB) {
4321     // NEW_BACKGROUND_TAB results in leaving the omnibox open, so we don't
4322     // attempt to use the instant preview.
4323     return false;
4324   }
4325 
4326   if (disposition == CURRENT_TAB) {
4327     instant()->CommitCurrentPreview(INSTANT_COMMIT_PRESSED_ENTER);
4328     return true;
4329   }
4330   if (disposition == NEW_FOREGROUND_TAB) {
4331     TabContentsWrapper* preview_contents = instant()->ReleasePreviewContents(
4332         INSTANT_COMMIT_PRESSED_ENTER);
4333     // HideInstant is invoked after release so that InstantController is not
4334     // active when HideInstant asks it for its state.
4335     HideInstant();
4336     preview_contents->controller().PruneAllButActive();
4337     tab_handler_->GetTabStripModel()->AddTabContents(
4338         preview_contents,
4339         -1,
4340         instant()->last_transition_type(),
4341         TabStripModel::ADD_ACTIVE);
4342     instant()->CompleteRelease(preview_contents->tab_contents());
4343     return true;
4344   }
4345   // The omnibox currently doesn't use other dispositions, so we don't attempt
4346   // to handle them. If you hit this NOTREACHED file a bug and I'll (sky) add
4347   // support for the new disposition.
4348   NOTREACHED();
4349   return false;
4350 }
4351 
CreateInstantIfNecessary()4352 void Browser::CreateInstantIfNecessary() {
4353   if (type() == TYPE_NORMAL && InstantController::IsEnabled(profile()) &&
4354       !profile()->IsOffTheRecord()) {
4355     instant_.reset(new InstantController(profile_, this));
4356     instant_unload_handler_.reset(new InstantUnloadHandler(this));
4357   }
4358 }
4359 
ViewSource(TabContentsWrapper * contents)4360 void Browser::ViewSource(TabContentsWrapper* contents) {
4361   DCHECK(contents);
4362 
4363   NavigationEntry* active_entry = contents->controller().GetActiveEntry();
4364   if (!active_entry)
4365     return;
4366 
4367   ViewSource(contents, active_entry->url(), active_entry->content_state());
4368 }
4369 
ViewSource(TabContentsWrapper * contents,const GURL & url,const std::string & content_state)4370 void Browser::ViewSource(TabContentsWrapper* contents,
4371                          const GURL& url,
4372                          const std::string& content_state) {
4373   UserMetrics::RecordAction(UserMetricsAction("ViewSource"), profile_);
4374   DCHECK(contents);
4375 
4376   TabContentsWrapper* view_source_contents = contents->Clone();
4377   view_source_contents->controller().PruneAllButActive();
4378   NavigationEntry* active_entry =
4379       view_source_contents->controller().GetActiveEntry();
4380   if (!active_entry)
4381     return;
4382 
4383   GURL view_source_url = GURL(chrome::kViewSourceScheme + std::string(":") +
4384       url.spec());
4385   active_entry->set_virtual_url(view_source_url);
4386 
4387   // Do not restore scroller position.
4388   active_entry->set_content_state(
4389       webkit_glue::RemoveScrollOffsetFromHistoryState(content_state));
4390 
4391   // Do not restore title, derive it from the url.
4392   active_entry->set_title(string16());
4393 
4394   // Now show view-source entry.
4395   if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
4396     // If this is a tabbed browser, just create a duplicate tab inside the same
4397     // window next to the tab being duplicated.
4398     int index = tab_handler_->GetTabStripModel()->
4399         GetIndexOfTabContents(contents);
4400     int add_types = TabStripModel::ADD_ACTIVE |
4401         TabStripModel::ADD_INHERIT_GROUP;
4402     tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1,
4403                                                           view_source_contents,
4404                                                           add_types);
4405   } else {
4406     Browser* browser = Browser::CreateForType(TYPE_NORMAL, profile_);
4407 
4408     // Preserve the size of the original window. The new window has already
4409     // been given an offset by the OS, so we shouldn't copy the old bounds.
4410     BrowserWindow* new_window = browser->window();
4411     new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
4412                           window()->GetRestoredBounds().size()));
4413 
4414     // We need to show the browser now. Otherwise ContainerWin assumes the
4415     // TabContents is invisible and won't size it.
4416     browser->window()->Show();
4417 
4418     // The page transition below is only for the purpose of inserting the tab.
4419     browser->AddTab(view_source_contents, PageTransition::LINK);
4420   }
4421 
4422   if (profile_->HasSessionService()) {
4423     SessionService* session_service = profile_->GetSessionService();
4424     if (session_service)
4425       session_service->TabRestored(&view_source_contents->controller(), false);
4426   }
4427 }
4428