Home | History | Annotate | Download | only in ui
      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 
    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 
    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
    341 Browser* Browser::Create(Profile* profile) {
    342   Browser* browser = new Browser(TYPE_NORMAL, profile);
    343   browser->InitBrowserWindow();
    344   return browser;
    345 }
    346 
    347 // static
    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
    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
    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
    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 
    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 
    467 const std::vector<std::wstring>& Browser::user_data_dir_profiles() const {
    468   return g_browser_process->user_data_dir_profiles();
    469 }
    470 
    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 
    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 
    487 bool Browser::HasFindBarController() const {
    488   return find_bar_controller_.get() != NULL;
    489 }
    490 
    491 ///////////////////////////////////////////////////////////////////////////////
    492 // Browser, Creation Helpers:
    493 
    494 // static
    495 void Browser::OpenEmptyWindow(Profile* profile) {
    496   Browser* browser = Browser::Create(profile);
    497   browser->AddBlankTab(true);
    498   browser->window()->Show();
    499 }
    500 
    501 // static
    502 void Browser::OpenWindowWithRestoredTabs(Profile* profile) {
    503   TabRestoreService* service = profile->GetTabRestoreService();
    504   if (service)
    505     service->RestoreMostRecentEntry(NULL);
    506 }
    507 
    508 // static
    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
    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
    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 
    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
    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
    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
    700 void Browser::OpenHistoryWindow(Profile* profile) {
    701   Browser* browser = Browser::Create(profile);
    702   browser->ShowHistoryTab();
    703   browser->window()->Show();
    704 }
    705 
    706 // static
    707 void Browser::OpenDownloadsWindow(Profile* profile) {
    708   Browser* browser = Browser::Create(profile);
    709   browser->ShowDownloadsTab();
    710   browser->window()->Show();
    711 }
    712 
    713 // static
    714 void Browser::OpenHelpWindow(Profile* profile) {
    715   Browser* browser = Browser::Create(profile);
    716   browser->OpenHelpTab();
    717   browser->window()->Show();
    718 }
    719 
    720 // static
    721 void Browser::OpenOptionsWindow(Profile* profile) {
    722   Browser* browser = Browser::Create(profile);
    723   browser->OpenOptionsDialog();
    724   browser->window()->Show();
    725 }
    726 
    727 // static
    728 void Browser::OpenClearBrowingDataDialogWindow(Profile* profile) {
    729   Browser* browser = Browser::Create(profile);
    730   browser->OpenClearBrowsingDataDialog();
    731   browser->window()->Show();
    732 }
    733 
    734 // static
    735 void Browser::OpenImportSettingsDialogWindow(Profile* profile) {
    736   Browser* browser = Browser::Create(profile);
    737   browser->OpenImportSettingsDialog();
    738   browser->window()->Show();
    739 }
    740 
    741 // static
    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
    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 
    760 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 
    769 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 
    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 
    786 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.
    808 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 
    825 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 
    832 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
    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 
    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 
    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 
    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 
    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 
    957 int Browser::tab_count() const {
    958   return tab_handler_->GetTabStripModel()->count();
    959 }
    960 
    961 int Browser::active_index() const {
    962   return tab_handler_->GetTabStripModel()->active_index();
    963 }
    964 
    965 int Browser::GetIndexOfController(
    966     const NavigationController* controller) const {
    967   return tab_handler_->GetTabStripModel()->GetIndexOfController(controller);
    968 }
    969 
    970 TabContentsWrapper* Browser::GetSelectedTabContentsWrapper() const {
    971   return tabstrip_model()->GetSelectedTabContents();
    972 }
    973 TabContentsWrapper* Browser::GetTabContentsWrapperAt(int index) const {
    974   return tabstrip_model()->GetTabContentsAt(index);
    975 }
    976 
    977 TabContents* Browser::GetSelectedTabContents() const {
    978   TabContentsWrapper* wrapper = GetSelectedTabContentsWrapper();
    979   if (wrapper)
    980     return wrapper->tab_contents();
    981   return NULL;
    982 }
    983 
    984 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 
    991 void Browser::ActivateTabAt(int index, bool user_gesture) {
    992   tab_handler_->GetTabStripModel()->ActivateTabAt(index, user_gesture);
    993 }
    994 
    995 bool Browser::IsTabPinned(int index) const {
    996   return tabstrip_model()->IsTabPinned(index);
    997 }
    998 
    999 void Browser::CloseAllTabs() {
   1000   tab_handler_->GetTabStripModel()->CloseAllTabs();
   1001 }
   1002 
   1003 ////////////////////////////////////////////////////////////////////////////////
   1004 // Browser, Tab adding/showing functions:
   1005 
   1006 bool Browser::IsTabStripEditable() const {
   1007   return window()->IsTabStripEditable();
   1008 }
   1009 
   1010 int Browser::GetIndexForInsertionDuringRestore(int relative_index) {
   1011   return (tab_handler_->GetTabStripModel()->insertion_policy() ==
   1012       TabStripModel::INSERT_AFTER) ? tab_count() : relative_index;
   1013 }
   1014 
   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 
   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 
   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 
   1037 void Browser::CloseTabContents(TabContents* contents) {
   1038   CloseContents(contents);
   1039 }
   1040 
   1041 void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate,
   1042                                     gfx::NativeWindow parent_window) {
   1043   ShowHtmlDialog(delegate, parent_window);
   1044 }
   1045 
   1046 void Browser::BrowserRenderWidgetShowing() {
   1047   RenderWidgetShowing();
   1048 }
   1049 
   1050 void Browser::BookmarkBarSizeChanged(bool is_animating) {
   1051   window_->ToolbarSizeChanged(is_animating);
   1052 }
   1053 
   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 
   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 
   1120 bool Browser::CanRestoreTab() {
   1121   return command_updater_.IsCommandEnabled(IDC_RESTORE_TAB);
   1122 }
   1123 
   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 
   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 
   1142 void Browser::ShowSingletonTab(const GURL& url) {
   1143   browser::NavigateParams params(GetSingletonTabNavigateParams(url));
   1144   browser::Navigate(&params);
   1145 }
   1146 
   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 
   1202 bool Browser::ShouldOpenNewTabForWindowDisposition(
   1203     WindowOpenDisposition disposition) {
   1204   return (disposition == NEW_FOREGROUND_TAB ||
   1205           disposition == NEW_BACKGROUND_TAB);
   1206 }
   1207 
   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 
   1221 void Browser::UpdateTabStripModelInsertionPolicy() {
   1222   tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ?
   1223       TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER);
   1224 }
   1225 
   1226 void Browser::UseVerticalTabsChanged() {
   1227   UpdateTabStripModelInsertionPolicy();
   1228   window()->ToggleTabStripMode();
   1229 }
   1230 
   1231 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 
   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 
   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 
   1293 void Browser::GoForward(WindowOpenDisposition disposition) {
   1294   UserMetrics::RecordAction(UserMetricsAction("Forward"), profile_);
   1295   if (GetSelectedTabContentsWrapper()->controller().CanGoForward())
   1296     GetOrCloneTabForDisposition(disposition)->controller().GoForward();
   1297 }
   1298 
   1299 void Browser::Reload(WindowOpenDisposition disposition) {
   1300   UserMetrics::RecordAction(UserMetricsAction("Reload"), profile_);
   1301   ReloadInternal(disposition, false);
   1302 }
   1303 
   1304 void Browser::ReloadIgnoringCache(WindowOpenDisposition disposition) {
   1305   UserMetrics::RecordAction(UserMetricsAction("ReloadIgnoringCache"), profile_);
   1306   ReloadInternal(disposition, true);
   1307 }
   1308 
   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 
   1330 void Browser::Home(WindowOpenDisposition disposition) {
   1331   UserMetrics::RecordAction(UserMetricsAction("Home"), profile_);
   1332   OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
   1333 }
   1334 
   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 
   1376 void Browser::Stop() {
   1377   UserMetrics::RecordAction(UserMetricsAction("Stop"), profile_);
   1378   GetSelectedTabContentsWrapper()->tab_contents()->Stop();
   1379 }
   1380 
   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 
   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 
   1407 void Browser::CloseWindow() {
   1408   UserMetrics::RecordAction(UserMetricsAction("CloseWindow"), profile_);
   1409   window_->Close();
   1410 }
   1411 
   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 
   1429 void Browser::CloseTab() {
   1430   UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator"),
   1431                             profile_);
   1432   if (CanCloseTab())
   1433     tab_handler_->GetTabStripModel()->CloseSelectedTabs();
   1434 }
   1435 
   1436 void Browser::SelectNextTab() {
   1437   UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_);
   1438   tab_handler_->GetTabStripModel()->SelectNextTab();
   1439 }
   1440 
   1441 void Browser::SelectPreviousTab() {
   1442   UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_);
   1443   tab_handler_->GetTabStripModel()->SelectPreviousTab();
   1444 }
   1445 
   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 
   1460 void Browser::MoveTabNext() {
   1461   UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_);
   1462   tab_handler_->GetTabStripModel()->MoveTabNext();
   1463 }
   1464 
   1465 void Browser::MoveTabPrevious() {
   1466   UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_);
   1467   tab_handler_->GetTabStripModel()->MoveTabPrevious();
   1468 }
   1469 
   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 
   1478 void Browser::SelectLastTab() {
   1479   UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_);
   1480   tab_handler_->GetTabStripModel()->SelectLastTab();
   1481 }
   1482 
   1483 void Browser::DuplicateTab() {
   1484   UserMetrics::RecordAction(UserMetricsAction("Duplicate"), profile_);
   1485   DuplicateContentsAt(active_index());
   1486 }
   1487 
   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 
   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 
   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 
   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)
   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 
   1564 void Browser::ShowKeyboardOverlay() {
   1565   window_->ShowKeyboardOverlay(window_->GetNativeHandle());
   1566 }
   1567 #endif
   1568 
   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 
   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 
   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 
   1627 void Browser::ViewSelectedSource() {
   1628   ViewSource(GetSelectedTabContentsWrapper());
   1629 }
   1630 
   1631 void Browser::ShowFindBar() {
   1632   GetFindBarController()->Show();
   1633 }
   1634 
   1635 bool Browser::SupportsWindowFeature(WindowFeature feature) const {
   1636   return SupportsWindowFeatureImpl(feature, true);
   1637 }
   1638 
   1639 bool Browser::CanSupportWindowFeature(WindowFeature feature) const {
   1640   return SupportsWindowFeatureImpl(feature, false);
   1641 }
   1642 
   1643 void Browser::EmailPageLocation() {
   1644   UserMetrics::RecordAction(UserMetricsAction("EmailPageLocation"), profile_);
   1645   GetSelectedTabContents()->EmailPageLocation();
   1646 }
   1647 
   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 
   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 
   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 
   1691 void Browser::Cut() {
   1692   UserMetrics::RecordAction(UserMetricsAction("Cut"), profile_);
   1693   window()->Cut();
   1694 }
   1695 
   1696 void Browser::Copy() {
   1697   UserMetrics::RecordAction(UserMetricsAction("Copy"), profile_);
   1698   window()->Copy();
   1699 }
   1700 
   1701 void Browser::Paste() {
   1702   UserMetrics::RecordAction(UserMetricsAction("Paste"), profile_);
   1703   window()->Paste();
   1704 }
   1705 
   1706 void Browser::Find() {
   1707   UserMetrics::RecordAction(UserMetricsAction("Find"), profile_);
   1708   FindInPage(false, false);
   1709 }
   1710 
   1711 void Browser::FindNext() {
   1712   UserMetrics::RecordAction(UserMetricsAction("FindNext"), profile_);
   1713   FindInPage(true, true);
   1714 }
   1715 
   1716 void Browser::FindPrevious() {
   1717   UserMetrics::RecordAction(UserMetricsAction("FindPrevious"), profile_);
   1718   FindInPage(true, false);
   1719 }
   1720 
   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 
   1734 void Browser::FocusToolbar() {
   1735   UserMetrics::RecordAction(UserMetricsAction("FocusToolbar"), profile_);
   1736   window_->FocusToolbar();
   1737 }
   1738 
   1739 void Browser::FocusAppMenu() {
   1740   UserMetrics::RecordAction(UserMetricsAction("FocusAppMenu"), profile_);
   1741   window_->FocusAppMenu();
   1742 }
   1743 
   1744 void Browser::FocusLocationBar() {
   1745   UserMetrics::RecordAction(UserMetricsAction("FocusLocation"), profile_);
   1746   window_->SetFocusToLocationBar(true);
   1747 }
   1748 
   1749 void Browser::FocusBookmarksToolbar() {
   1750   UserMetrics::RecordAction(UserMetricsAction("FocusBookmarksToolbar"),
   1751                             profile_);
   1752   window_->FocusBookmarksToolbar();
   1753 }
   1754 
   1755 void Browser::FocusChromeOSStatus() {
   1756   UserMetrics::RecordAction(UserMetricsAction("FocusChromeOSStatus"), profile_);
   1757   window_->FocusChromeOSStatus();
   1758 }
   1759 
   1760 void Browser::FocusNextPane() {
   1761   UserMetrics::RecordAction(UserMetricsAction("FocusNextPane"), profile_);
   1762   window_->RotatePaneFocus(true);
   1763 }
   1764 
   1765 void Browser::FocusPreviousPane() {
   1766   UserMetrics::RecordAction(UserMetricsAction("FocusPreviousPane"), profile_);
   1767   window_->RotatePaneFocus(false);
   1768 }
   1769 
   1770 void Browser::FocusSearch() {
   1771   // TODO(beng): replace this with FocusLocationBar
   1772   UserMetrics::RecordAction(UserMetricsAction("FocusSearch"), profile_);
   1773   window_->GetLocationBar()->FocusSearch();
   1774 }
   1775 
   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 
   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 
   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 
   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 
   1848 void Browser::OpenBugReportDialog() {
   1849   UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_);
   1850   browser::ShowHtmlBugReportView(this);
   1851 }
   1852 
   1853 void Browser::ToggleBookmarkBar() {
   1854   UserMetrics::RecordAction(UserMetricsAction("ShowBookmarksBar"), profile_);
   1855   window_->ToggleBookmarkBar();
   1856 }
   1857 
   1858 void Browser::OpenBookmarkManager() {
   1859   UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"), profile_);
   1860   ShowBookmarkManagerTab();
   1861 }
   1862 
   1863 void Browser::ShowAppMenu() {
   1864   // We record the user metric for this event in WrenchMenu::RunMenu.
   1865   window_->ShowAppMenu();
   1866 }
   1867 
   1868 void Browser::ShowBookmarkManagerTab() {
   1869   UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks"), profile_);
   1870   ShowSingletonTab(GURL(chrome::kChromeUIBookmarksURL));
   1871 }
   1872 
   1873 void Browser::ShowHistoryTab() {
   1874   UserMetrics::RecordAction(UserMetricsAction("ShowHistory"), profile_);
   1875   ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL));
   1876 }
   1877 
   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 
   1888 void Browser::ShowExtensionsTab() {
   1889   UserMetrics::RecordAction(UserMetricsAction("ShowExtensions"), profile_);
   1890   ShowSingletonTab(GURL(chrome::kChromeUIExtensionsURL));
   1891 }
   1892 
   1893 void Browser::ShowAboutConflictsTab() {
   1894   UserMetrics::RecordAction(UserMetricsAction("AboutConflicts"), profile_);
   1895   ShowSingletonTab(GURL(chrome::kChromeUIConflictsURL));
   1896 }
   1897 
   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 
   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 
   1920 void Browser::OpenClearBrowsingDataDialog() {
   1921   UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg"),
   1922                             profile_);
   1923   ShowOptionsTab(chrome::kClearBrowserDataSubPage);
   1924 }
   1925 
   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 
   1934 void Browser::OpenPasswordManager() {
   1935   UserMetrics::RecordAction(UserMetricsAction("Options_ShowPasswordManager"),
   1936                             profile_);
   1937   ShowOptionsTab(chrome::kPasswordManagerSubPage);
   1938 }
   1939 
   1940 void Browser::OpenImportSettingsDialog() {
   1941   UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_);
   1942   ShowOptionsTab(chrome::kImportDataSubPage);
   1943 }
   1944 
   1945 void Browser::OpenInstantConfirmDialog() {
   1946   ShowOptionsTab(chrome::kInstantConfirmPage);
   1947 }
   1948 
   1949 void Browser::OpenSyncMyBookmarksDialog() {
   1950   sync_ui_util::OpenSyncMyBookmarksDialog(
   1951       profile_, this, ProfileSyncService::START_FROM_WRENCH);
   1952 }
   1953 
   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 
   1963 void Browser::OpenUpdateChromeDialog() {
   1964   UserMetrics::RecordAction(UserMetricsAction("UpdateChrome"), profile_);
   1965   window_->ShowUpdateChromeDialog();
   1966 }
   1967 
   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 
   1974 void Browser::OpenThemeGalleryTabAndActivate() {
   1975   AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)),
   1976                         PageTransition::LINK);
   1977 }
   1978 
   1979 void Browser::OpenPrivacyDashboardTabAndActivate() {
   1980   OpenURL(GURL(kPrivacyDashboardUrl), GURL(),
   1981           NEW_FOREGROUND_TAB, PageTransition::LINK);
   1982   window_->Activate();
   1983 }
   1984 
   1985 void Browser::OpenAutofillHelpTabAndActivate() {
   1986   GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kAutofillHelpUrl));
   1987   AddSelectedTabWithURL(help_url, PageTransition::LINK);
   1988 }
   1989 
   1990 void Browser::OpenSearchEngineOptionsDialog() {
   1991   UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines"), profile_);
   1992   ShowOptionsTab(chrome::kSearchEnginesSubPage);
   1993 }
   1994 
   1995 #if defined(OS_CHROMEOS)
   1996 void Browser::OpenFileManager() {
   1997   UserMetrics::RecordAction(UserMetricsAction("OpenFileManager"));
   1998   ShowSingletonTab(FileManagerUtil::GetFileBrowserUrl());
   1999 }
   2000 
   2001 void Browser::OpenSystemOptionsDialog() {
   2002   UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog"),
   2003                             profile_);
   2004   ShowOptionsTab(chrome::kSystemOptionsSubPage);
   2005 }
   2006 
   2007 void Browser::OpenInternetOptionsDialog() {
   2008   UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog"),
   2009                             profile_);
   2010   ShowOptionsTab(chrome::kInternetOptionsSubPage);
   2011 }
   2012 
   2013 void Browser::OpenLanguageOptionsDialog() {
   2014   UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog"),
   2015                             profile_);
   2016   ShowOptionsTab(chrome::kLanguageOptionsSubPage);
   2017 }
   2018 
   2019 void Browser::OpenSystemTabAndActivate() {
   2020   OpenURL(GURL(chrome::kChromeUISystemInfoURL), GURL(),
   2021           NEW_FOREGROUND_TAB, PageTransition::LINK);
   2022   window_->Activate();
   2023 }
   2024 
   2025 void Browser::OpenMobilePlanTabAndActivate() {
   2026   OpenURL(GURL(chrome::kChromeUIMobileSetupURL), GURL(),
   2027           NEW_FOREGROUND_TAB, PageTransition::LINK);
   2028   window_->Activate();
   2029 }
   2030 #endif
   2031 
   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
   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
   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
   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
   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
   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 
   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 
   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 
   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 
   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 
   2399 int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) {
   2400   if (disposition)
   2401     *disposition = last_blocked_command_disposition_;
   2402   return last_blocked_command_id_;
   2403 }
   2404 
   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 
   2433 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 
   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 
   2472 void Browser::ExecuteCommand(int id) {
   2473   ExecuteCommandWithDisposition(id, CURRENT_TAB);
   2474 }
   2475 
   2476 ///////////////////////////////////////////////////////////////////////////////
   2477 // Browser, TabHandlerDelegate implementation:
   2478 
   2479 Profile* Browser::GetProfile() const {
   2480   return profile();
   2481 }
   2482 
   2483 Browser* Browser::AsBrowser() {
   2484   return this;
   2485 }
   2486 
   2487 ///////////////////////////////////////////////////////////////////////////////
   2488 // Browser, TabStripModelDelegate implementation:
   2489 
   2490 TabContentsWrapper* Browser::AddBlankTab(bool foreground) {
   2491   return AddBlankTabAt(-1, foreground);
   2492 }
   2493 
   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 
   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 
   2533 int Browser::GetDragActions() const {
   2534   return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ?
   2535       TabStripModelDelegate::TAB_MOVE_ACTION : 0);
   2536 }
   2537 
   2538 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 
   2554 bool Browser::CanDuplicateContentsAt(int index) {
   2555   NavigationController& nc = GetTabContentsAt(index)->controller();
   2556   return nc.tab_contents() && nc.GetLastCommittedEntry();
   2557 }
   2558 
   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 
   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 
   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 
   2637 bool Browser::RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) {
   2638   return Browser::RunUnloadEventsHelper(contents->tab_contents());
   2639 }
   2640 
   2641 bool Browser::CanReloadContents(TabContents* source) const {
   2642   return type() != TYPE_DEVTOOLS;
   2643 }
   2644 
   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 
   2657 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 
   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 
   2678 bool Browser::CanCloseTab() const {
   2679   TabCloseableStateWatcher* watcher =
   2680       g_browser_process->tab_closeable_state_watcher();
   2681   return !watcher || watcher->CanCloseTab(this);
   2682 }
   2683 
   2684 void Browser::ToggleUseVerticalTabs() {
   2685   use_vertical_tabs_.SetValue(!UseVerticalTabs());
   2686   UseVerticalTabsChanged();
   2687 }
   2688 
   2689 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 
   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 
   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 
   2734 void Browser::TabDetachedAt(TabContentsWrapper* contents, int index) {
   2735   TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH);
   2736 }
   2737 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   2941 void Browser::ActivateContents(TabContents* contents) {
   2942   tab_handler_->GetTabStripModel()->ActivateTabAt(
   2943       tab_handler_->GetTabStripModel()->GetWrapperIndex(contents), false);
   2944   window_->Activate();
   2945 }
   2946 
   2947 void Browser::DeactivateContents(TabContents* contents) {
   2948   window_->Deactivate();
   2949 }
   2950 
   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 
   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 
   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 
   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 
   3015 bool Browser::IsPopup(const TabContents* source) const {
   3016   // A non-tabbed BROWSER is an unconstrained popup.
   3017   return !!(type() & TYPE_POPUP);
   3018 }
   3019 
   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 
   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 
   3043 void Browser::UpdateDownloadShelfVisibility(bool visible) {
   3044   if (GetStatusBubble())
   3045     GetStatusBubble()->UpdateDownloadShelfVisibility(visible);
   3046 }
   3047 
   3048 bool Browser::UseVerticalTabs() const {
   3049   return use_vertical_tabs_.GetValue();
   3050 }
   3051 
   3052 void Browser::ContentsZoomChange(bool zoom_in) {
   3053   ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
   3054 }
   3055 
   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 
   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 
   3073 void Browser::TabContentsFocused(TabContents* tab_content) {
   3074   window_->TabContentsFocused(tab_content);
   3075 }
   3076 
   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 
   3085 bool Browser::IsApplication() const {
   3086   return (type_ & TYPE_APP) != 0;
   3087 }
   3088 
   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 
   3105 bool Browser::ShouldDisplayURLField() {
   3106   return !IsApplication();
   3107 }
   3108 
   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 
   3141 void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
   3142                              gfx::NativeWindow parent_window) {
   3143   window_->ShowHTMLDialog(delegate, parent_window);
   3144 }
   3145 
   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 
   3157 void Browser::RenderWidgetShowing() {
   3158   window_->DisableInactiveFrame();
   3159 }
   3160 
   3161 int Browser::GetExtraRenderViewHeight() const {
   3162   return window_->GetExtraRenderViewHeight();
   3163 }
   3164 
   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 
   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 
   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 
   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 
   3231 bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
   3232                                      bool* is_keyboard_shortcut) {
   3233   return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut);
   3234 }
   3235 
   3236 void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
   3237   window()->HandleKeyboardEvent(event);
   3238 }
   3239 
   3240 void Browser::ShowRepostFormWarningDialog(TabContents *tab_contents) {
   3241   window()->ShowRepostFormWarningDialog(tab_contents);
   3242 }
   3243 
   3244 void Browser::ShowContentSettingsPage(ContentSettingsType content_type) {
   3245   ShowOptionsTab(
   3246       chrome::kContentSettingsExceptionsSubPage + std::string(kHashMark) +
   3247       ContentSettingsHandler::ContentSettingsTypeToGroupName(content_type));
   3248 }
   3249 
   3250 void Browser::ShowCollectedCookiesDialog(TabContents *tab_contents) {
   3251   window()->ShowCollectedCookiesDialog(tab_contents);
   3252 }
   3253 
   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 
   3261 void Browser::ContentRestrictionsChanged(TabContents* source) {
   3262   UpdateCommandsForContentRestrictionState();
   3263 }
   3264 
   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 
   3276 void Browser::URLStarredChanged(TabContentsWrapper* source, bool starred) {
   3277   if (source == GetSelectedTabContentsWrapper())
   3278     window_->SetStarredState(starred);
   3279 }
   3280 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   3492 void Browser::PrepareForInstant() {
   3493   window_->PrepareForInstant();
   3494 }
   3495 
   3496 void Browser::ShowInstant(TabContentsWrapper* preview_contents) {
   3497   DCHECK(instant_->tab_contents() == GetSelectedTabContentsWrapper());
   3498   window_->ShowInstant(preview_contents);
   3499 }
   3500 
   3501 void Browser::HideInstant() {
   3502   window_->HideInstant(instant_->is_active());
   3503 }
   3504 
   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 
   3525 void Browser::SetSuggestedText(const string16& text,
   3526                                InstantCompleteBehavior behavior) {
   3527   window()->GetLocationBar()->SetSuggestedText(text, behavior);
   3528 }
   3529 
   3530 gfx::Rect Browser::GetInstantBounds() {
   3531   return window()->GetInstantBounds();
   3532 }
   3533 
   3534 ///////////////////////////////////////////////////////////////////////////////
   3535 // Browser, protected:
   3536 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   3815 void Browser::UpdateToolbar(bool should_restore_state) {
   3816   window_->UpdateToolbar(GetSelectedTabContentsWrapper(), should_restore_state);
   3817 }
   3818 
   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 
   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 
   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 
   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 
   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 
   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 
   4039 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 
   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 
   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 
   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 
   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 
   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
   4194 Browser* Browser::GetTabbedBrowser(Profile* profile, bool match_incognito) {
   4195   return BrowserList::FindBrowserWithType(profile, TYPE_NORMAL,
   4196                                           match_incognito);
   4197 }
   4198 
   4199 // static
   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 
   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 
   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 
   4228 void Browser::CloseFrame() {
   4229   window_->Close();
   4230 }
   4231 
   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
   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 
   4289 void Browser::TabRestoreServiceChanged(TabRestoreService* service) {
   4290   command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
   4291                                         !service->entries().empty());
   4292 }
   4293 
   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.
   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 
   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 
   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 
   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 
   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