1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/plugins/plugin_infobar_delegates.h" 6 7 #include "base/path_service.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/content_settings/host_content_settings_map.h" 10 #include "chrome/browser/google/google_util.h" 11 #include "chrome/browser/infobars/infobar_service.h" 12 #include "chrome/browser/lifetime/application_lifetime.h" 13 #include "chrome/browser/plugins/chrome_plugin_service_filter.h" 14 #include "chrome/browser/plugins/plugin_metadata.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/shell_integration.h" 17 #include "chrome/browser/ui/browser_commands.h" 18 #include "chrome/common/render_messages.h" 19 #include "chrome/common/url_constants.h" 20 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/render_process_host.h" 22 #include "content/public/browser/render_view_host.h" 23 #include "content/public/browser/user_metrics.h" 24 #include "content/public/browser/web_contents.h" 25 #include "grit/generated_resources.h" 26 #include "grit/locale_settings.h" 27 #include "grit/theme_resources.h" 28 #include "ui/base/l10n/l10n_util.h" 29 30 #if defined(ENABLE_PLUGIN_INSTALLATION) 31 #if defined(OS_WIN) 32 #include "base/win/metro.h" 33 #endif 34 #include "chrome/browser/plugins/plugin_installer.h" 35 #endif 36 37 #if defined(OS_WIN) 38 #include <shellapi.h> 39 #include "ui/base/win/shell.h" 40 #endif 41 42 using content::UserMetricsAction; 43 44 45 // PluginInfoBarDelegate ------------------------------------------------------ 46 47 PluginInfoBarDelegate::PluginInfoBarDelegate(InfoBarService* infobar_service, 48 const std::string& identifier) 49 : ConfirmInfoBarDelegate(infobar_service), 50 identifier_(identifier) { 51 } 52 53 PluginInfoBarDelegate::~PluginInfoBarDelegate() { 54 } 55 56 bool PluginInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) { 57 web_contents()->OpenURL(content::OpenURLParams( 58 GURL(GetLearnMoreURL()), content::Referrer(), 59 (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, 60 content::PAGE_TRANSITION_LINK, false)); 61 return false; 62 } 63 64 void PluginInfoBarDelegate::LoadBlockedPlugins() { 65 content::RenderViewHost* host = web_contents()->GetRenderViewHost(); 66 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins( 67 host->GetProcess()->GetID()); 68 host->Send(new ChromeViewMsg_LoadBlockedPlugins( 69 host->GetRoutingID(), identifier_)); 70 } 71 72 int PluginInfoBarDelegate::GetIconID() const { 73 return IDR_INFOBAR_PLUGIN_INSTALL; 74 } 75 76 string16 PluginInfoBarDelegate::GetLinkText() const { 77 return l10n_util::GetStringUTF16(IDS_LEARN_MORE); 78 } 79 80 81 // UnauthorizedPluginInfoBarDelegate ------------------------------------------ 82 83 // static 84 void UnauthorizedPluginInfoBarDelegate::Create( 85 InfoBarService* infobar_service, 86 HostContentSettingsMap* content_settings, 87 const string16& name, 88 const std::string& identifier) { 89 infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>( 90 new UnauthorizedPluginInfoBarDelegate(infobar_service, content_settings, 91 name, identifier))); 92 93 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Shown")); 94 std::string utf8_name(UTF16ToUTF8(name)); 95 if (utf8_name == PluginMetadata::kJavaGroupName) { 96 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Shown.Java")); 97 } else if (utf8_name == PluginMetadata::kQuickTimeGroupName) { 98 content::RecordAction( 99 UserMetricsAction("BlockedPluginInfobar.Shown.QuickTime")); 100 } else if (utf8_name == PluginMetadata::kShockwaveGroupName) { 101 content::RecordAction( 102 UserMetricsAction("BlockedPluginInfobar.Shown.Shockwave")); 103 } else if (utf8_name == PluginMetadata::kRealPlayerGroupName) { 104 content::RecordAction( 105 UserMetricsAction("BlockedPluginInfobar.Shown.RealPlayer")); 106 } else if (utf8_name == PluginMetadata::kWindowsMediaPlayerGroupName) { 107 content::RecordAction( 108 UserMetricsAction("BlockedPluginInfobar.Shown.WindowsMediaPlayer")); 109 } 110 } 111 112 UnauthorizedPluginInfoBarDelegate::UnauthorizedPluginInfoBarDelegate( 113 InfoBarService* infobar_service, 114 HostContentSettingsMap* content_settings, 115 const string16& name, 116 const std::string& identifier) 117 : PluginInfoBarDelegate(infobar_service, identifier), 118 content_settings_(content_settings), 119 name_(name) { 120 } 121 122 UnauthorizedPluginInfoBarDelegate::~UnauthorizedPluginInfoBarDelegate() { 123 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Closed")); 124 } 125 126 std::string UnauthorizedPluginInfoBarDelegate::GetLearnMoreURL() const { 127 return chrome::kBlockedPluginLearnMoreURL; 128 } 129 130 string16 UnauthorizedPluginInfoBarDelegate::GetMessageText() const { 131 return l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, name_); 132 } 133 134 string16 UnauthorizedPluginInfoBarDelegate::GetButtonLabel( 135 InfoBarButton button) const { 136 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 137 IDS_PLUGIN_ENABLE_TEMPORARILY : IDS_PLUGIN_ENABLE_ALWAYS); 138 } 139 140 bool UnauthorizedPluginInfoBarDelegate::Accept() { 141 content::RecordAction( 142 UserMetricsAction("BlockedPluginInfobar.AllowThisTime")); 143 LoadBlockedPlugins(); 144 return true; 145 } 146 147 bool UnauthorizedPluginInfoBarDelegate::Cancel() { 148 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.AlwaysAllow")); 149 const GURL& url = web_contents()->GetURL(); 150 content_settings_->AddExceptionForURL(url, url, CONTENT_SETTINGS_TYPE_PLUGINS, 151 std::string(), CONTENT_SETTING_ALLOW); 152 LoadBlockedPlugins(); 153 return true; 154 } 155 156 void UnauthorizedPluginInfoBarDelegate::InfoBarDismissed() { 157 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Dismissed")); 158 } 159 160 bool UnauthorizedPluginInfoBarDelegate::LinkClicked( 161 WindowOpenDisposition disposition) { 162 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.LearnMore")); 163 return PluginInfoBarDelegate::LinkClicked(disposition); 164 } 165 166 167 #if defined(ENABLE_PLUGIN_INSTALLATION) 168 169 // OutdatedPluginInfoBarDelegate ---------------------------------------------- 170 171 void OutdatedPluginInfoBarDelegate::Create( 172 InfoBarService* infobar_service, 173 PluginInstaller* installer, 174 scoped_ptr<PluginMetadata> plugin_metadata) { 175 // Copy the name out of |plugin_metadata| now, since the Pass() call below 176 // will make it impossible to get at. 177 string16 name(plugin_metadata->name()); 178 infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>( 179 new OutdatedPluginInfoBarDelegate( 180 infobar_service, installer, plugin_metadata.Pass(), 181 l10n_util::GetStringFUTF16( 182 (installer->state() == PluginInstaller::INSTALLER_STATE_IDLE) ? 183 IDS_PLUGIN_OUTDATED_PROMPT : IDS_PLUGIN_DOWNLOADING, 184 name)))); 185 } 186 187 OutdatedPluginInfoBarDelegate::OutdatedPluginInfoBarDelegate( 188 InfoBarService* infobar_service, 189 PluginInstaller* installer, 190 scoped_ptr<PluginMetadata> plugin_metadata, 191 const string16& message) 192 : PluginInfoBarDelegate(infobar_service, plugin_metadata->identifier()), 193 WeakPluginInstallerObserver(installer), 194 plugin_metadata_(plugin_metadata.Pass()), 195 message_(message) { 196 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Shown")); 197 std::string name = UTF16ToUTF8(plugin_metadata_->name()); 198 if (name == PluginMetadata::kJavaGroupName) { 199 content::RecordAction( 200 UserMetricsAction("OutdatedPluginInfobar.Shown.Java")); 201 } else if (name == PluginMetadata::kQuickTimeGroupName) { 202 content::RecordAction( 203 UserMetricsAction("OutdatedPluginInfobar.Shown.QuickTime")); 204 } else if (name == PluginMetadata::kShockwaveGroupName) { 205 content::RecordAction( 206 UserMetricsAction("OutdatedPluginInfobar.Shown.Shockwave")); 207 } else if (name == PluginMetadata::kRealPlayerGroupName) { 208 content::RecordAction( 209 UserMetricsAction("OutdatedPluginInfobar.Shown.RealPlayer")); 210 } else if (name == PluginMetadata::kSilverlightGroupName) { 211 content::RecordAction( 212 UserMetricsAction("OutdatedPluginInfobar.Shown.Silverlight")); 213 } else if (name == PluginMetadata::kAdobeReaderGroupName) { 214 content::RecordAction( 215 UserMetricsAction("OutdatedPluginInfobar.Shown.Reader")); 216 } 217 } 218 219 OutdatedPluginInfoBarDelegate::~OutdatedPluginInfoBarDelegate() { 220 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Closed")); 221 } 222 223 std::string OutdatedPluginInfoBarDelegate::GetLearnMoreURL() const { 224 return chrome::kOutdatedPluginLearnMoreURL; 225 } 226 227 string16 OutdatedPluginInfoBarDelegate::GetMessageText() const { 228 return message_; 229 } 230 231 string16 OutdatedPluginInfoBarDelegate::GetButtonLabel( 232 InfoBarButton button) const { 233 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 234 IDS_PLUGIN_UPDATE : IDS_PLUGIN_ENABLE_TEMPORARILY); 235 } 236 237 bool OutdatedPluginInfoBarDelegate::Accept() { 238 DCHECK_EQ(PluginInstaller::INSTALLER_STATE_IDLE, installer()->state()); 239 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Update")); 240 // A call to any of |OpenDownloadURL()| or |StartInstalling()| will 241 // result in deleting ourselves. Accordingly, we make sure to 242 // not pass a reference to an object that can go away. 243 GURL plugin_url(plugin_metadata_->plugin_url()); 244 if (plugin_metadata_->url_for_display()) 245 installer()->OpenDownloadURL(plugin_url, web_contents()); 246 else 247 installer()->StartInstalling(plugin_url, web_contents()); 248 return false; 249 } 250 251 bool OutdatedPluginInfoBarDelegate::Cancel() { 252 content::RecordAction( 253 UserMetricsAction("OutdatedPluginInfobar.AllowThisTime")); 254 LoadBlockedPlugins(); 255 return true; 256 } 257 258 void OutdatedPluginInfoBarDelegate::InfoBarDismissed() { 259 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Dismissed")); 260 } 261 262 bool OutdatedPluginInfoBarDelegate::LinkClicked( 263 WindowOpenDisposition disposition) { 264 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.LearnMore")); 265 return PluginInfoBarDelegate::LinkClicked(disposition); 266 } 267 268 void OutdatedPluginInfoBarDelegate::DownloadStarted() { 269 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, 270 plugin_metadata_->name())); 271 } 272 273 void OutdatedPluginInfoBarDelegate::DownloadError(const std::string& message) { 274 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR_SHORT, 275 plugin_metadata_->name())); 276 } 277 278 void OutdatedPluginInfoBarDelegate::DownloadCancelled() { 279 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED, 280 plugin_metadata_->name())); 281 } 282 283 void OutdatedPluginInfoBarDelegate::DownloadFinished() { 284 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_UPDATING, 285 plugin_metadata_->name())); 286 } 287 288 void OutdatedPluginInfoBarDelegate::OnlyWeakObserversLeft() { 289 if (owner()) 290 owner()->RemoveInfoBar(this); 291 } 292 293 void OutdatedPluginInfoBarDelegate::ReplaceWithInfoBar( 294 const string16& message) { 295 // Return early if the message doesn't change. This is important in case the 296 // PluginInstaller is still iterating over its observers (otherwise we would 297 // keep replacing infobar delegates infinitely). 298 if ((message_ == message) || !owner()) 299 return; 300 PluginInstallerInfoBarDelegate::Replace( 301 this, installer(), plugin_metadata_->Clone(), false, message); 302 } 303 304 305 // PluginInstallerInfoBarDelegate --------------------------------------------- 306 307 void PluginInstallerInfoBarDelegate::Create( 308 InfoBarService* infobar_service, 309 PluginInstaller* installer, 310 scoped_ptr<PluginMetadata> plugin_metadata, 311 const InstallCallback& callback) { 312 string16 name(plugin_metadata->name()); 313 #if defined(OS_WIN) 314 if (base::win::IsMetroProcess()) { 315 PluginMetroModeInfoBarDelegate::Create( 316 infobar_service, PluginMetroModeInfoBarDelegate::MISSING_PLUGIN, name); 317 return; 318 } 319 #endif 320 infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>( 321 new PluginInstallerInfoBarDelegate( 322 infobar_service, installer, plugin_metadata.Pass(), callback, true, 323 l10n_util::GetStringFUTF16( 324 (installer->state() == PluginInstaller::INSTALLER_STATE_IDLE) ? 325 IDS_PLUGININSTALLER_INSTALLPLUGIN_PROMPT : 326 IDS_PLUGIN_DOWNLOADING, 327 name)))); 328 329 } 330 331 void PluginInstallerInfoBarDelegate::Replace( 332 InfoBarDelegate* infobar, 333 PluginInstaller* installer, 334 scoped_ptr<PluginMetadata> plugin_metadata, 335 bool new_install, 336 const string16& message) { 337 DCHECK(infobar->owner()); 338 infobar->owner()->ReplaceInfoBar(infobar, scoped_ptr<InfoBarDelegate>( 339 new PluginInstallerInfoBarDelegate( 340 infobar->owner(), installer, plugin_metadata.Pass(), 341 PluginInstallerInfoBarDelegate::InstallCallback(), new_install, 342 message))); 343 } 344 345 PluginInstallerInfoBarDelegate::PluginInstallerInfoBarDelegate( 346 InfoBarService* infobar_service, 347 PluginInstaller* installer, 348 scoped_ptr<PluginMetadata> plugin_metadata, 349 const InstallCallback& callback, 350 bool new_install, 351 const string16& message) 352 : ConfirmInfoBarDelegate(infobar_service), 353 WeakPluginInstallerObserver(installer), 354 plugin_metadata_(plugin_metadata.Pass()), 355 callback_(callback), 356 new_install_(new_install), 357 message_(message) { 358 } 359 360 PluginInstallerInfoBarDelegate::~PluginInstallerInfoBarDelegate() { 361 } 362 363 int PluginInstallerInfoBarDelegate::GetIconID() const { 364 return IDR_INFOBAR_PLUGIN_INSTALL; 365 } 366 367 string16 PluginInstallerInfoBarDelegate::GetMessageText() const { 368 return message_; 369 } 370 371 int PluginInstallerInfoBarDelegate::GetButtons() const { 372 return callback_.is_null() ? BUTTON_NONE : BUTTON_OK; 373 } 374 375 string16 PluginInstallerInfoBarDelegate::GetButtonLabel( 376 InfoBarButton button) const { 377 DCHECK_EQ(BUTTON_OK, button); 378 return l10n_util::GetStringUTF16(IDS_PLUGININSTALLER_INSTALLPLUGIN_BUTTON); 379 } 380 381 bool PluginInstallerInfoBarDelegate::Accept() { 382 callback_.Run(plugin_metadata_.get()); 383 return false; 384 } 385 386 string16 PluginInstallerInfoBarDelegate::GetLinkText() const { 387 return l10n_util::GetStringUTF16(new_install_ ? 388 IDS_PLUGININSTALLER_PROBLEMSINSTALLING : 389 IDS_PLUGININSTALLER_PROBLEMSUPDATING); 390 } 391 392 bool PluginInstallerInfoBarDelegate::LinkClicked( 393 WindowOpenDisposition disposition) { 394 GURL url(plugin_metadata_->help_url()); 395 if (url.is_empty()) { 396 url = google_util::AppendGoogleLocaleParam(GURL( 397 "https://www.google.com/support/chrome/bin/answer.py?answer=142064")); 398 } 399 web_contents()->OpenURL(content::OpenURLParams( 400 url, content::Referrer(), 401 (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, 402 content::PAGE_TRANSITION_LINK, false)); 403 return false; 404 } 405 406 void PluginInstallerInfoBarDelegate::DownloadStarted() { 407 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, 408 plugin_metadata_->name())); 409 } 410 411 void PluginInstallerInfoBarDelegate::DownloadCancelled() { 412 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED, 413 plugin_metadata_->name())); 414 } 415 416 void PluginInstallerInfoBarDelegate::DownloadError(const std::string& message) { 417 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR_SHORT, 418 plugin_metadata_->name())); 419 } 420 421 void PluginInstallerInfoBarDelegate::DownloadFinished() { 422 ReplaceWithInfoBar( 423 l10n_util::GetStringFUTF16( 424 new_install_ ? IDS_PLUGIN_INSTALLING : IDS_PLUGIN_UPDATING, 425 plugin_metadata_->name())); 426 } 427 428 void PluginInstallerInfoBarDelegate::OnlyWeakObserversLeft() { 429 if (owner()) 430 owner()->RemoveInfoBar(this); 431 } 432 433 void PluginInstallerInfoBarDelegate::ReplaceWithInfoBar( 434 const string16& message) { 435 // Return early if the message doesn't change. This is important in case the 436 // PluginInstaller is still iterating over its observers (otherwise we would 437 // keep replacing infobar delegates infinitely). 438 if ((message_ == message) || !owner()) 439 return; 440 Replace(this, installer(), plugin_metadata_->Clone(), new_install_, message); 441 } 442 443 444 #if defined(OS_WIN) 445 446 // PluginMetroModeInfoBarDelegate --------------------------------------------- 447 448 // static 449 void PluginMetroModeInfoBarDelegate::Create( 450 InfoBarService* infobar_service, 451 PluginMetroModeInfoBarDelegate::Mode mode, 452 const string16& name) { 453 infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>( 454 new PluginMetroModeInfoBarDelegate(infobar_service, mode, name))); 455 } 456 457 PluginMetroModeInfoBarDelegate::PluginMetroModeInfoBarDelegate( 458 InfoBarService* infobar_service, 459 PluginMetroModeInfoBarDelegate::Mode mode, 460 const string16& name) 461 : ConfirmInfoBarDelegate(infobar_service), 462 mode_(mode), 463 name_(name) { 464 } 465 466 PluginMetroModeInfoBarDelegate::~PluginMetroModeInfoBarDelegate() { 467 } 468 469 int PluginMetroModeInfoBarDelegate::GetIconID() const { 470 return IDR_INFOBAR_PLUGIN_INSTALL; 471 } 472 473 string16 PluginMetroModeInfoBarDelegate::GetMessageText() const { 474 return l10n_util::GetStringFUTF16((mode_ == MISSING_PLUGIN) ? 475 IDS_METRO_MISSING_PLUGIN_PROMPT : IDS_METRO_NPAPI_PLUGIN_PROMPT, name_); 476 } 477 478 int PluginMetroModeInfoBarDelegate::GetButtons() const { 479 return (mode_ == MISSING_PLUGIN) ? BUTTON_OK : (BUTTON_OK | BUTTON_CANCEL); 480 } 481 482 string16 PluginMetroModeInfoBarDelegate::GetButtonLabel( 483 InfoBarButton button) const { 484 if (button == BUTTON_CANCEL) 485 return l10n_util::GetStringUTF16(IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL); 486 return l10n_util::GetStringUTF16((mode_ == MISSING_PLUGIN) ? 487 IDS_WIN8_DESKTOP_RESTART : IDS_WIN8_RESTART); 488 } 489 490 void LaunchDesktopInstanceHelper(const string16& url) { 491 base::FilePath exe_path; 492 if (!PathService::Get(base::FILE_EXE, &exe_path)) 493 return; 494 base::FilePath shortcut_path( 495 ShellIntegration::GetStartMenuShortcut(exe_path)); 496 497 SHELLEXECUTEINFO sei = { sizeof(sei) }; 498 sei.fMask = SEE_MASK_FLAG_LOG_USAGE; 499 sei.nShow = SW_SHOWNORMAL; 500 sei.lpFile = shortcut_path.value().c_str(); 501 sei.lpDirectory = L""; 502 sei.lpParameters = url.c_str(); 503 ShellExecuteEx(&sei); 504 } 505 506 bool PluginMetroModeInfoBarDelegate::Accept() { 507 #if defined(USE_AURA) && defined(USE_ASH) 508 // We need to PostTask as there is some IO involved. 509 content::BrowserThread::PostTask( 510 content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE, 511 base::Bind(&LaunchDesktopInstanceHelper, 512 UTF8ToUTF16(web_contents()->GetURL().spec()))); 513 #else 514 chrome::AttemptRestartWithModeSwitch(); 515 #endif 516 return true; 517 } 518 519 bool PluginMetroModeInfoBarDelegate::Cancel() { 520 DCHECK_EQ(DESKTOP_MODE_REQUIRED, mode_); 521 Profile::FromBrowserContext(web_contents()->GetBrowserContext())-> 522 GetHostContentSettingsMap()->SetContentSetting( 523 ContentSettingsPattern::FromURL(web_contents()->GetURL()), 524 ContentSettingsPattern::Wildcard(), 525 CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP, std::string(), 526 CONTENT_SETTING_BLOCK); 527 return true; 528 } 529 530 string16 PluginMetroModeInfoBarDelegate::GetLinkText() const { 531 return l10n_util::GetStringUTF16(IDS_LEARN_MORE); 532 } 533 534 bool PluginMetroModeInfoBarDelegate::LinkClicked( 535 WindowOpenDisposition disposition) { 536 web_contents()->OpenURL(content::OpenURLParams( 537 GURL((mode_ == MISSING_PLUGIN) ? 538 "https://support.google.com/chrome/?p=ib_display_in_desktop" : 539 "https://support.google.com/chrome/?p=ib_redirect_to_desktop"), 540 content::Referrer(), 541 (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, 542 content::PAGE_TRANSITION_LINK, false)); 543 return false; 544 } 545 546 #endif // defined(OS_WIN) 547 548 #endif // defined(ENABLE_PLUGIN_INSTALLATION) 549