diff options
21 files changed, 745 insertions, 35 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 1e1fd1c..549867c9 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -539,10 +539,13 @@ are declared in build/common.gypi. Input &methods </message> <message name="IDS_CONTENT_CONTEXT_PLUGIN_RUN" desc="The name of the Run command on the blocked plugin context menu"> - Run this plugin + Run this plug-in </message> <message name="IDS_CONTENT_CONTEXT_PLUGIN_HIDE" desc="The name of the Hide command on the blocked plugin context menu"> - Hide this plugin + Hide this plug-in + </message> + <message name="IDS_CONTENT_CONTEXT_PLUGIN_INSTALL" desc="The name of the Install command on the missing plugin context menu"> + Install missing plug-in </message> <message name="IDS_CONTENT_CONTEXT_SPEECH_INPUT_MENU" desc="The name of the Speech input options submenu in the content area context menu"> Voice recognition options @@ -754,10 +757,13 @@ are declared in build/common.gypi. Input &Methods </message> <message name="IDS_CONTENT_CONTEXT_PLUGIN_RUN" desc="In Title Case: The name of the Run command on the blocked plugin context menu"> - Run This Plugin + Run This Plug-in </message> <message name="IDS_CONTENT_CONTEXT_PLUGIN_HIDE" desc="In Title Case: The name of the Hide command on the blocked plugin context menu"> - Hide This Plugin + Hide This Plug-in + </message> + <message name="IDS_CONTENT_CONTEXT_PLUGIN_INSTALL" desc="The name of the Install command on the missing plugin context menu"> + Install Missing Plug-in </message> <message name="IDS_CONTENT_CONTEXT_SPEECH_INPUT_MENU" desc="In Title Case: The name of the Speech input options submenu in the content area context menu"> Voice Recognition Options @@ -5032,9 +5038,15 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_PLUGIN_NOT_AUTHORIZED" desc="The placeholder text for a plug-in that requires user permission to run."> The <ph name="PLUGIN_NAME">$1<ex>Java</ex></ph> plug-in needs your permission to run. </message> - <message name="IDS_PLUGIN_NOT_FOUND" desc="The placeholder text for a plug-in that is not installed."> + <message name="IDS_PLUGIN_NOT_FOUND" desc="The placeholder text for an unknown plug-in that is not installed."> No plug-in available to display this content. </message> + <message name="IDS_PLUGIN_SEARCHING" desc="The placeholder text when searching for a missing plug-in."> + Looking for plug-in... + </message> + <message name="IDS_PLUGIN_FOUND" desc="The placeholder text for a known plug-in that is not installed."> + The <ph name="PLUGIN_NAME">$1<ex>Quicktime</ex></ph> plug-in is required to display this content. + </message> <message name="IDS_PLUGIN_DISABLED" desc="The placeholder text for a disabled plug-in."> The <ph name="PLUGIN_NAME">$1<ex>Flash</ex></ph> plug-in has been disabled. To re-enable it, please go to <ph name="CHROME_PLUGINS_LINK">chrome://plugins</ph>. </message> @@ -9393,6 +9405,9 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_PLUGININSTALLER_MISSINGPLUGIN_PROMPT" desc="Info Bar message to prompt installing missing plugin"> An additional plug-in is required to display some elements on this page. </message> + <message name="IDS_PLUGININSTALLER_INSTALLPLUGIN_PROMPT" desc="Info Bar message to prompt installing missing plugin"> + The <ph name="PLUGIN_NAME">$1<ex>Quicktime</ex></ph> plug-in is required to display some elements on this page. + </message> <message name="IDS_PLUGININSTALLER_INSTALLPLUGIN_BUTTON" desc="Info Bar button to install missing plugin"> Install plug-in... </message> diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 630f21a..fa9a07c 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -86,6 +86,12 @@ <include name="IDR_NOTIFICATION_ICON_HTML" file="resources\notification_icon.html" type="BINDATA" /> <include name="IDR_PLUGINS_HTML" file="resources\plugins.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_PLUGINS_JS" file="resources\plugins.js" type="BINDATA" /> + <if expr="is_win"> + <include name="IDR_PLUGIN_DB_JSON" file="resources\plugins_win.json" type="BINDATA" /> + </if> + <if expr="is_macosx"> + <include name="IDR_PLUGIN_DB_JSON" file="resources\plugins_mac.json" type="BINDATA" /> + </if> <include name="IDR_POLICY_CSS" file="resources\policy.css" type="BINDATA"/> <include name="IDR_POLICY_HTML" file="resources\policy.html" flattenhtml="true" allowexternalscript="true" type="BINDATA"/> <include name="IDR_POLICY_JS" file="resources\policy.js" type="BINDATA"/> diff --git a/chrome/browser/chrome_plugin_message_filter.cc b/chrome/browser/chrome_plugin_message_filter.cc index fee4c01..9d9677b 100644 --- a/chrome/browser/chrome_plugin_message_filter.cc +++ b/chrome/browser/chrome_plugin_message_filter.cc @@ -93,7 +93,6 @@ void ChromePluginMessageFilter::OnDownloadUrlOnFileThread( context, BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); } - #endif void ChromePluginMessageFilter::OnGetPluginFinderUrl( @@ -136,8 +135,10 @@ void ChromePluginMessageFilter::HandleMissingPluginStatus( InfoBarTabHelper* infobar_helper = tcw->infobar_tab_helper(); if (status == webkit::npapi::default_plugin::MISSING_PLUGIN_AVAILABLE) { - infobar_helper->AddInfoBar( - new PluginInstallerInfoBarDelegate(infobar_helper, window)); + infobar_helper->AddInfoBar(new PluginInstallerInfoBarDelegate( + infobar_helper, string16(), GURL(), + base::Bind(&ChromePluginMessageFilter::InstallMissingPlugin, + base::Unretained(window)))); return; } @@ -157,3 +158,15 @@ void ChromePluginMessageFilter::HandleMissingPluginStatus( NOTIMPLEMENTED(); #endif // OS_WIN } + +// static +void ChromePluginMessageFilter::InstallMissingPlugin(gfx::NativeWindow window) { +#if defined(OS_WIN) + ::PostMessage(window, + webkit::npapi::default_plugin::kInstallMissingPluginMessage, + 0, + 0); +#else + NOTIMPLEMENTED(); +#endif // OS_WIN +} diff --git a/chrome/browser/chrome_plugin_message_filter.h b/chrome/browser/chrome_plugin_message_filter.h index 08bc147..67642ca 100644 --- a/chrome/browser/chrome_plugin_message_filter.h +++ b/chrome/browser/chrome_plugin_message_filter.h @@ -52,12 +52,13 @@ class ChromePluginMessageFilter : public IPC::ChannelProxy::MessageFilter, int render_view_id, gfx::NativeWindow window); - // static static void HandleMissingPluginStatus(int status, int render_process_id, int render_view_id, gfx::NativeWindow window); + static void InstallMissingPlugin(gfx::NativeWindow window); + PluginProcessHost* process_; DISALLOW_COPY_AND_ASSIGN(ChromePluginMessageFilter); diff --git a/chrome/browser/plugin_finder.cc b/chrome/browser/plugin_finder.cc new file mode 100644 index 0000000..eee7757 --- /dev/null +++ b/chrome/browser/plugin_finder.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/plugin_finder.h" + +#include "base/bind.h" +#include "base/json/json_reader.h" +#include "base/message_loop.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/common/pref_names.h" +#include "content/public/browser/browser_thread.h" +#include "googleurl/src/gurl.h" +#include "grit/browser_resources.h" +#include "ui/base/resource/resource_bundle.h" + +PluginFinder* PluginFinder::GetInstance() { + return Singleton<PluginFinder>::get(); +} + +PluginFinder::PluginFinder() { +#if defined(OS_WIN) || defined(OS_MACOSX) + base::StringPiece json_resource( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_PLUGIN_DB_JSON)); + bool allow_trailing_comma = false; + std::string error_str; + scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( + json_resource.as_string(), + allow_trailing_comma, + NULL, + &error_str)); + DLOG_IF(ERROR, !value.get()) << error_str; + if (value->IsType(base::Value::TYPE_DICTIONARY)) { + base::DictionaryValue* dict = + static_cast<base::DictionaryValue*>(value.get()); + base::ListValue* list = NULL; + dict->GetList("plugins", &list); + plugin_list_.reset(list->DeepCopy()); + } + DCHECK(plugin_list_.get()); +#endif + if (!plugin_list_.get()) + plugin_list_.reset(new base::ListValue()); +} + +PluginFinder::~PluginFinder() { +} + +void PluginFinder::FindPlugin( + const std::string& mime_type, + const std::string& language, + const FindPluginCallback& found_callback, + const base::Closure& not_found_callback) { + if (g_browser_process->local_state()->GetBoolean( + prefs::kDisablePluginFinder)) { + MessageLoop::current()->PostTask(FROM_HERE, not_found_callback); + return; + } + for (ListValue::const_iterator plugin_it = plugin_list_->begin(); + plugin_it != plugin_list_->end(); ++plugin_it) { + if (!(*plugin_it)->IsType(base::Value::TYPE_DICTIONARY)) { + NOTREACHED(); + continue; + } + const base::DictionaryValue* plugin = + static_cast<const base::DictionaryValue*>(*plugin_it); + std::string language_str; + bool success = plugin->GetString("lang", &language_str); + DCHECK(success); + if (language_str != language) + continue; + ListValue* mime_types = NULL; + success = plugin->GetList("mime_types", &mime_types); + DCHECK(success); + for (ListValue::const_iterator mime_type_it = mime_types->begin(); + mime_type_it != mime_types->end(); ++mime_type_it) { + std::string mime_type_str; + success = (*mime_type_it)->GetAsString(&mime_type_str); + DCHECK(success); + if (mime_type_str == mime_type) { + std::string url; + success = plugin->GetString("url", &url); + DCHECK(success); + string16 name; + success = plugin->GetString("name", &name); + DCHECK(success); + bool display_url = false; + plugin->GetBoolean("displayurl", &display_url); + MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(found_callback, GURL(url), name, display_url)); + return; + } + } + } + MessageLoop::current()->PostTask(FROM_HERE, not_found_callback); +} + diff --git a/chrome/browser/plugin_finder.h b/chrome/browser/plugin_finder.h new file mode 100644 index 0000000..e9b18d0 --- /dev/null +++ b/chrome/browser/plugin_finder.h @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PLUGIN_FINDER_H_ +#define CHROME_BROWSER_PLUGIN_FINDER_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/singleton.h" +#include "base/string16.h" + +namespace base { +class ListValue; +} + +class GURL; + +class PluginFinder { + public: + // If |display_url| is false, |plugin_url| is the URL of the download page for + // the plug-in, which should be opened in a new tab. If it is true, + // |plugin_url| is the URL of the plug-in installer binary, which can be + // directly downloaded. + typedef base::Callback<void(GURL /* plugin_url */, + string16 /* name */, + bool /* display_url */)> FindPluginCallback; + + static PluginFinder* GetInstance(); + + // Finds a plug-in for the given MIME type and language (specified as an IETF + // language tag, i.e. en-US) and calls one of the two passed in callbacks, + // depending on whether a plug-in is found. + void FindPlugin(const std::string& mime_type, + const std::string& language, + const FindPluginCallback& found_callback, + const base::Closure& not_found_callback); + + private: + friend struct DefaultSingletonTraits<PluginFinder>; + + PluginFinder(); + ~PluginFinder(); + + scoped_ptr<base::ListValue> plugin_list_; + + DISALLOW_COPY_AND_ASSIGN(PluginFinder); +}; + +#endif // CHROME_BROWSER_PLUGIN_FINDER_H_ diff --git a/chrome/browser/plugin_installer_infobar_delegate.cc b/chrome/browser/plugin_installer_infobar_delegate.cc index 02b8f2d..01f054b 100644 --- a/chrome/browser/plugin_installer_infobar_delegate.cc +++ b/chrome/browser/plugin_installer_infobar_delegate.cc @@ -13,12 +13,16 @@ #include "grit/theme_resources_standard.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -#include "webkit/plugins/npapi/default_plugin_shared.h" PluginInstallerInfoBarDelegate::PluginInstallerInfoBarDelegate( - InfoBarTabHelper* infobar_helper, gfx::NativeWindow window) + InfoBarTabHelper* infobar_helper, + const string16& plugin_name, + const GURL& learn_more_url, + const base::Closure& callback) : ConfirmInfoBarDelegate(infobar_helper), - window_(window) { + plugin_name_(plugin_name), + learn_more_url_(learn_more_url), + callback_(callback) { } PluginInstallerInfoBarDelegate::~PluginInstallerInfoBarDelegate() { @@ -35,7 +39,11 @@ PluginInstallerInfoBarDelegate* } string16 PluginInstallerInfoBarDelegate::GetMessageText() const { - return l10n_util::GetStringUTF16(IDS_PLUGININSTALLER_MISSINGPLUGIN_PROMPT); + // TODO(bauerb): Remove this check when removing the default plug-in. + return plugin_name_.empty() ? + l10n_util::GetStringUTF16(IDS_PLUGININSTALLER_MISSINGPLUGIN_PROMPT) : + l10n_util::GetStringFUTF16(IDS_PLUGININSTALLER_INSTALLPLUGIN_PROMPT, + plugin_name_); } int PluginInstallerInfoBarDelegate::GetButtons() const { @@ -49,13 +57,7 @@ string16 PluginInstallerInfoBarDelegate::GetButtonLabel( } bool PluginInstallerInfoBarDelegate::Accept() { - // TODO(PORT) for other platforms. -#if defined(OS_WIN) - ::PostMessage(window_, - webkit::npapi::default_plugin::kInstallMissingPluginMessage, - 0, - 0); -#endif + callback_.Run(); return true; } @@ -65,9 +67,14 @@ string16 PluginInstallerInfoBarDelegate::GetLinkText() const { bool PluginInstallerInfoBarDelegate::LinkClicked( WindowOpenDisposition disposition) { - owner()->tab_contents()->OpenURL(google_util::AppendGoogleLocaleParam(GURL( - "https://www.google.com/support/chrome/bin/answer.py?answer=142064")), - GURL(), + GURL url(learn_more_url_); + // TODO(bauerb): Remove this check when removing the default plug-in. + if (url.is_empty()) { + url = google_util::AppendGoogleLocaleParam(GURL( + "https://www.google.com/support/chrome/bin/answer.py?answer=142064")); + } + owner()->tab_contents()->OpenURL( + url, GURL(), (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, content::PAGE_TRANSITION_LINK); return false; diff --git a/chrome/browser/plugin_installer_infobar_delegate.h b/chrome/browser/plugin_installer_infobar_delegate.h index 519b73a..3d2f68f 100644 --- a/chrome/browser/plugin_installer_infobar_delegate.h +++ b/chrome/browser/plugin_installer_infobar_delegate.h @@ -6,15 +6,20 @@ #define CHROME_BROWSER_PLUGIN_INSTALLER_INFOBAR_DELEGATE_H_ #pragma once +#include "base/callback.h" #include "chrome/browser/tab_contents/confirm_infobar_delegate.h" -#include "ui/gfx/native_widget_types.h" +#include "googleurl/src/gurl.h" // The main purpose for this class is to popup/close the infobar when there is // a missing plugin. class PluginInstallerInfoBarDelegate : public ConfirmInfoBarDelegate { public: + // Shows an infobar asking whether to install the plugin with the name + // |plugin_name|. When the user accepts, |callback| is called. PluginInstallerInfoBarDelegate(InfoBarTabHelper* infobar_helper, - gfx::NativeWindow window); + const string16& plugin_name, + const GURL& learn_more_url, + const base::Closure& callback); private: virtual ~PluginInstallerInfoBarDelegate(); @@ -30,7 +35,9 @@ class PluginInstallerInfoBarDelegate : public ConfirmInfoBarDelegate { virtual string16 GetLinkText() const OVERRIDE; virtual bool LinkClicked(WindowOpenDisposition disposition) OVERRIDE; - gfx::NativeWindow window_; + string16 plugin_name_; + GURL learn_more_url_; + base::Closure callback_; DISALLOW_COPY_AND_ASSIGN(PluginInstallerInfoBarDelegate); }; diff --git a/chrome/browser/plugin_observer.cc b/chrome/browser/plugin_observer.cc index 8c78fcb..73d9a75 100644 --- a/chrome/browser/plugin_observer.cc +++ b/chrome/browser/plugin_observer.cc @@ -4,10 +4,14 @@ #include "chrome/browser/plugin_observer.h" +#include "base/bind.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/host_content_settings_map.h" #include "chrome/browser/google/google_util.h" #include "chrome/browser/infobars/infobar_tab_helper.h" +#include "chrome/browser/plugin_finder.h" +#include "chrome/browser/plugin_installer_infobar_delegate.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/confirm_infobar_delegate.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" @@ -282,6 +286,7 @@ bool OutdatedPluginInfoBarDelegate::LinkClicked( PluginObserver::PluginObserver(TabContentsWrapper* tab_contents) : TabContentsObserver(tab_contents->tab_contents()), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), tab_contents_(tab_contents) { } @@ -292,6 +297,8 @@ bool PluginObserver::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(PluginObserver, message) IPC_MESSAGE_HANDLER(ChromeViewHostMsg_BlockedOutdatedPlugin, OnBlockedOutdatedPlugin) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FindMissingPlugin, + OnFindMissingPlugin) IPC_MESSAGE_UNHANDLED(return false) IPC_END_MESSAGE_MAP() @@ -308,3 +315,45 @@ void PluginObserver::OnBlockedOutdatedPlugin(const string16& name, name)) : new OutdatedPluginInfoBarDelegate(infobar_helper, name, update_url)); } + +void PluginObserver::OnFindMissingPlugin(int placeholder_id, + const std::string& mime_type) { + PluginFinder* plugin_finder = PluginFinder::GetInstance(); + std::string lang = "en-US"; // Oh yes. + plugin_finder->FindPlugin( + mime_type, lang, + base::Bind(&PluginObserver::FoundMissingPlugin, + weak_ptr_factory_.GetWeakPtr(), placeholder_id, mime_type), + base::Bind(&PluginObserver::DidNotFindMissingPlugin, + weak_ptr_factory_.GetWeakPtr(), placeholder_id, mime_type)); +} + +void PluginObserver::FoundMissingPlugin(int placeholder_id, + const std::string& mime_type, + const GURL& url, + const string16& name, + bool display_url) { + Send(new ChromeViewMsg_FoundMissingPlugin(placeholder_id, name)); + InfoBarTabHelper* infobar_helper = tab_contents_->infobar_tab_helper(); + infobar_helper->AddInfoBar(new PluginInstallerInfoBarDelegate( + infobar_helper, + name, + GURL(), // TODO(bauerb): Get URL from JSON file. + base::Bind(&PluginObserver::InstallMissingPlugin, + weak_ptr_factory_.GetWeakPtr(), url, display_url))); +} + +void PluginObserver::DidNotFindMissingPlugin(int placeholder_id, + const std::string& mime_type) { + Send(new ChromeViewMsg_DidNotFindMissingPlugin(placeholder_id)); +} + +void PluginObserver::InstallMissingPlugin(const GURL& url, + bool display_url) { + if (display_url) { + tab_contents()->OpenURL(url, tab_contents()->GetURL(), NEW_FOREGROUND_TAB, + content::PAGE_TRANSITION_TYPED); + } else { + NOTIMPLEMENTED(); + } +} diff --git a/chrome/browser/plugin_observer.h b/chrome/browser/plugin_observer.h index 082a180..a8a2706 100644 --- a/chrome/browser/plugin_observer.h +++ b/chrome/browser/plugin_observer.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_PLUGIN_OBSERVER_H_ #pragma once +#include "base/memory/weak_ptr.h" #include "content/browser/tab_contents/tab_contents_observer.h" class GURL; @@ -22,6 +23,18 @@ class PluginObserver : public TabContentsObserver { private: void OnBlockedOutdatedPlugin(const string16& name, const GURL& update_url); + void OnFindMissingPlugin(int placeholder_id, const std::string& mime_type); + + void FoundMissingPlugin(int placeholder_id, + const std::string& mime_type, + const GURL& url, + const string16& name, + bool display_url); + void DidNotFindMissingPlugin(int placeholder_id, + const std::string& mime_type); + void InstallMissingPlugin(const GURL& url, bool display_url); + + base::WeakPtrFactory<PluginObserver> weak_ptr_factory_; TabContentsWrapper* tab_contents_; scoped_ptr<InfoBarDelegate> plugin_installer_; // Lazily created. diff --git a/chrome/browser/resources/plugins_mac.json b/chrome/browser/resources/plugins_mac.json new file mode 100644 index 0000000..1f0a456 --- /dev/null +++ b/chrome/browser/resources/plugins_mac.json @@ -0,0 +1,173 @@ +{ + "plugins": [ + { + "mime_types": [ + "application/x-java-applet", + "application/x-java-applet,version=1.1", + "application/x-java-applet,version=1.1.1", + "application/x-java-applet,version=1.1.2", + "application/x-java-applet,version=1.1.3", + "application/x-java-applet,version=1.2", + "application/x-java-applet,version=1.2.1", + "application/x-java-applet,version=1.2.2", + "application/x-java-applet,version=1.3", + "application/x-java-applet,version=1.3.1", + "application/x-java-applet,version=1.4", + "application/x-java-applet,version=1.4.1", + "application/x-java-applet,version=1.4.2", + "application/x-java-applet,version=1.5", + "application/x-java-applet,version=1.6", + "application/x-java-bean", + "application/x-java-bean,version=1.1", + "application/x-java-bean,version=1.1.1", + "application/x-java-bean,version=1.1.2", + "application/x-java-bean,version=1.1.3", + "application/x-java-bean,version=1.2", + "application/x-java-bean,version=1.2.1", + "application/x-java-bean,version=1.2.2", + "application/x-java-bean,version=1.3", + "application/x-java-bean,version=1.3.1", + "application/x-java-bean,version=1.4", + "application/x-java-bean,version=1.4.1", + "application/x-java-bean,version=1.4.2", + "application/x-java-bean,version=1.5", + "application/x-java-bean,version=1.6", + "application/x-java-vm" + ], + "lang": "en-US", + "name": "Java(TM)", + "url": "http://java.com/en/download/apple_manual.jsp", + "displayurl": true + }, + { + "mime_types": [ + "audio/vnd.rn-realaudio", + "video/vnd.rn-realvideo", + "audio/x-pn-realaudio-plugin", + "audio/x-pn-realaudio" + ], + "lang": "en-US", + "name": "RealPlayer", + "url": "http://www.real.com/realplayer/download", + "displayurl": true + }, + { + "mime_types": [ + "application/futuresplash", + "application/x-shockwave-flash" + ], + "lang": "en-US", + "name": "Adobe Flash Player", + "url": "http://get.adobe.com/flashplayer/", + "displayurl": true + }, + { + "mime_types": [ + "application/x-director" + ], + "lang": "en-US", + "name": "Adobe Shockwave Player", + "url": "http://www.adobe.com/shockwave/download/", + "displayurl": true + }, + { + "mime_types": [ + "application/pdf", + "application/vnd.adobe.x-mars", + "application/vnd.adobe.xdp+xml", + "application/vnd.adobe.xfd+xml", + "application/vnd.adobe.xfdf", + "application/vnd.fdf" + ], + "lang": "en-US", + "name": "Adobe Reader", + "url": "http://get.adobe.com/reader/", + "displayurl": true + }, + { + "mime_types": [ + "application/sdp", + "application/x-mpeg", + "application/x-rtsp", + "application/x-sdp", + "audio/3ggp", + "audio/3ggp2", + "audio/aac", + "audio/ac3", + "audio/aiff", + "audio/amr", + "audio/basic", + "audio/mid", + "audio/midi", + "audio/mp4", + "audio/mpeg", + "audio/vnd.qcelp", + "audio/wav", + "audio/x-aac", + "audio/x-ac3", + "audio/x-aiff", + "audio/x-caf", + "audio/x-gsm", + "audio/x-m4a", + "audio/x-m4b", + "audio/x-m4p", + "audio/x-midi", + "audio/x-mpeg", + "audio/x-wav", + "image/jp2", + "image/jpeg2000", + "image/jpeg2000-image", + "image/pict", + "image/png", + "image/x-jpeg2000-image", + "image/x-macpaint", + "image/x-pict", + "image/x-png", + "image/x-quicktime", + "image/x-sgi", + "image/x-targa", + "video/3ggp", + "video/3ggp2", + "video/flc", + "video/mp4", + "video/mpeg", + "video/quicktime", + "video/sd-video", + "video/x-m4v", + "video/x-mpeg" + ], + "lang": "en-US", + "name": "QuickTime Player", + "url": "http://www.apple.com/quicktime/download/", + "displayurl": true + }, + { + "mime_types": [ + "application/asx", + "application/x-mplayer2", + "application/x-ms-wmp", + "audio/x-ms-wax", + "audio/x-ms-wma", + "video/x-ms-asf", + "video/x-ms-asf-plugin", + "video/x-ms-wm", + "video/x-ms-wmv", + "video/x-ms-wvx" + ], + "lang": "en-US", + "name": "Flip4Mac", + "url": "http://www.telestream.net/flip4mac-wmv/overview.htm", + "displayurl": true + }, + { + "mime_types": [ + "video/divx", + "video/x-matroska" + ], + "lang": "en-US", + "name": "DivX Web Player", + "url": "http://www.divx.com/en/downloads/divx/mac", + "displayurl": true + } + ] +}
\ No newline at end of file diff --git a/chrome/browser/resources/plugins_win.json b/chrome/browser/resources/plugins_win.json new file mode 100644 index 0000000..0549c6c --- /dev/null +++ b/chrome/browser/resources/plugins_win.json @@ -0,0 +1,166 @@ +{ + "plugins": [ + { + "mime_types": [ + "application/x-java-applet", + "application/x-java-applet,version=1.1", + "application/x-java-applet,version=1.1.1", + "application/x-java-applet,version=1.1.2", + "application/x-java-applet,version=1.1.3", + "application/x-java-applet,version=1.2", + "application/x-java-applet,version=1.2.1", + "application/x-java-applet,version=1.2.2", + "application/x-java-applet,version=1.3", + "application/x-java-applet,version=1.3.1", + "application/x-java-applet,version=1.4", + "application/x-java-applet,version=1.4.1", + "application/x-java-applet,version=1.4.2", + "application/x-java-applet,version=1.5", + "application/x-java-applet,version=1.6", + "application/x-java-bean", + "application/x-java-bean,version=1.1", + "application/x-java-bean,version=1.1.1", + "application/x-java-bean,version=1.1.2", + "application/x-java-bean,version=1.1.3", + "application/x-java-bean,version=1.2", + "application/x-java-bean,version=1.2.1", + "application/x-java-bean,version=1.2.2", + "application/x-java-bean,version=1.3", + "application/x-java-bean,version=1.3.1", + "application/x-java-bean,version=1.4", + "application/x-java-bean,version=1.4.1", + "application/x-java-bean,version=1.4.2", + "application/x-java-bean,version=1.5", + "application/x-java-bean,version=1.6", + "application/x-java-vm" + ], + "lang": "en-US", + "name": "Java(TM)", + "url": "http://java.com/download", + "displayurl": true + }, + { + "mime_types": [ + "audio/vnd.rn-realaudio", + "video/vnd.rn-realvideo", + "audio/x-pn-realaudio-plugin", + "audio/x-pn-realaudio" + ], + "lang": "en-US", + "name": "RealPlayer", + "url": "http://forms.real.com/real/realone/download.html?type=rpsp_us" + }, + { + "mime_types": [ + "application/futuresplash", + "application/x-shockwave-flash" + ], + "lang": "en-US", + "name": "Adobe Flash Player", + "url": "http://fpdownload.adobe.com/get/flashplayer/current/install_flash_player.exe" + }, + { + "mime_types": [ + "application/x-director" + ], + "lang": "en-US", + "name": "Adobe Shockwave Player", + "url": "http://fpdownload.macromedia.com/get/shockwave/default/english/win95nt/latest/Shockwave_Installer_Slim.exe" + }, + { + "mime_types": [ + "application/pdf", + "application/vnd.adobe.x-mars", + "application/vnd.adobe.xdp+xml", + "application/vnd.adobe.xfd+xml", + "application/vnd.adobe.xfdf", + "application/vnd.fdf" + ], + "lang": "en-US", + "name": "Adobe Reader", + "url": "http://ardownload.adobe.com/pub/adobe/reader/win/9.x/9.1/enu/AdbeRdr910_en_US.exe" + }, + { + "mime_types": [ + "application/sdp", + "application/x-mpeg", + "application/x-rtsp", + "application/x-sdp", + "audio/3ggp", + "audio/3ggp2", + "audio/aac", + "audio/ac3", + "audio/aiff", + "audio/amr", + "audio/basic", + "audio/mid", + "audio/midi", + "audio/mp4", + "audio/mpeg", + "audio/vnd.qcelp", + "audio/wav", + "audio/x-aac", + "audio/x-ac3", + "audio/x-aiff", + "audio/x-caf", + "audio/x-gsm", + "audio/x-m4a", + "audio/x-m4b", + "audio/x-m4p", + "audio/x-midi", + "audio/x-mpeg", + "audio/x-wav", + "image/jp2", + "image/jpeg2000", + "image/jpeg2000-image", + "image/pict", + "image/png", + "image/x-jpeg2000-image", + "image/x-macpaint", + "image/x-pict", + "image/x-png", + "image/x-quicktime", + "image/x-sgi", + "image/x-targa", + "video/3ggp", + "video/3ggp2", + "video/flc", + "video/mp4", + "video/mpeg", + "video/quicktime", + "video/sd-video", + "video/x-m4v", + "video/x-mpeg" + ], + "lang": "en-US", + "name": "QuickTime Player", + "url": "http://appldnld.apple.com.edgesuite.net/content.info.apple.com/QuickTime/061-6118.20090601.Pq3V9/QuickTimeInstaller.exe" + }, + { + "mime_types": [ + "application/asx", + "application/x-mplayer2", + "application/x-ms-wmp", + "audio/x-ms-wax", + "audio/x-ms-wma", + "video/x-ms-asf", + "video/x-ms-asf-plugin", + "video/x-ms-wm", + "video/x-ms-wmv", + "video/x-ms-wvx" + ], + "lang": "en-US", + "name": "Windows Media Player", + "url": "http://port25.technet.com/videos/downloads/wmpfirefoxplugin.exe" + }, + { + "mime_types": [ + "video/divx", + "video/x-matroska" + ], + "lang": "en-US", + "name": "DivX Web Player", + "url": "http://download.divx.com/player/divxdotcom/DivXWebPlayerInstaller.exe" + } + ] +}
\ No newline at end of file diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 5f298da..8e6f2a0 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1725,6 +1725,8 @@ 'browser/plugin_data_remover_helper.h', 'browser/plugin_download_helper.cc', 'browser/plugin_download_helper.h', + 'browser/plugin_finder.cc', + 'browser/plugin_finder.h', 'browser/plugin_installer_infobar_delegate.cc', 'browser/plugin_installer_infobar_delegate.h', 'browser/plugin_observer.cc', @@ -4173,8 +4175,6 @@ ['exclude', '^browser/platform_util_win.cc'], ['exclude', '^browser/plugin_download_helper.cc'], ['exclude', '^browser/plugin_download_helper.h'], - ['exclude', '^browser/plugin_installer_infobar_delegate.cc'], - ['exclude', '^browser/plugin_installer_infobar_delegate.h'], ['exclude', '^browser/renderer_host/render_widget_host_view_views*'], ['exclude', '^browser/tab_contents/web_drag_source_win.cc'], ['exclude', '^browser/tab_contents/web_drag_source_win.h'], diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index a4e5bea..cdaa14d 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -423,6 +423,21 @@ IPC_SYNC_MESSAGE_CONTROL4_3(ChromeViewHostMsg_GetPluginInfo, webkit::WebPluginInfo /* plugin */, std::string /* actual_mime_type */) +// Tells the browser to search for a plug-in that can handle the given MIME +// type. The result will be sent asynchronously to the routing ID +// |placeholder_id|. +IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_FindMissingPlugin, + int /* placeholder_id */, + std::string /* mime_type */) + +// Notifies a missing plug-in placeholder that a plug-in with name |plugin_name| +// has been found. +IPC_MESSAGE_ROUTED1(ChromeViewMsg_FoundMissingPlugin, + string16 /* plugin_name */) + +// Notifies a missing plug-in placeholder that no plug-in has been found. +IPC_MESSAGE_ROUTED0(ChromeViewMsg_DidNotFindMissingPlugin) + // Specifies the URL as the first parameter (a wstring) and thumbnail as // binary data as the second parameter. IPC_MESSAGE_ROUTED3(ChromeViewHostMsg_Thumbnail, diff --git a/chrome/renderer/plugins/missing_plugin.cc b/chrome/renderer/plugins/missing_plugin.cc index 9773414..6b8acf9 100644 --- a/chrome/renderer/plugins/missing_plugin.cc +++ b/chrome/renderer/plugins/missing_plugin.cc @@ -4,20 +4,26 @@ #include "chrome/renderer/plugins/missing_plugin.h" +#include "base/json/string_escape.h" #include "base/string_piece.h" #include "base/string_util.h" +#include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/common/jstemplate_builder.h" +#include "chrome/common/render_messages.h" #include "chrome/renderer/custom_menu_commands.h" #include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" #include "grit/generated_resources.h" #include "grit/renderer_resources.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebMenuItemInfo.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "webkit/plugins/npapi/plugin_group.h" @@ -28,9 +34,11 @@ using WebKit::WebMenuItemInfo; using WebKit::WebPlugin; using WebKit::WebPluginParams; using WebKit::WebPoint; +using WebKit::WebScriptSource; using WebKit::WebString; using WebKit::WebVector; using content::RenderThread; +using content::RenderView; using webkit::WebViewPlugin; namespace { @@ -38,7 +46,7 @@ const MissingPlugin* g_last_active_menu = NULL; } // static -WebViewPlugin* MissingPlugin::Create(content::RenderView* render_view, +WebViewPlugin* MissingPlugin::Create(RenderView* render_view, WebFrame* frame, const WebPluginParams& params) { const base::StringPiece template_html( @@ -46,27 +54,32 @@ WebViewPlugin* MissingPlugin::Create(content::RenderView* render_view, IDR_BLOCKED_PLUGIN_HTML)); DictionaryValue values; - values.SetString("message", l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_FOUND)); + values.SetString("message", l10n_util::GetStringUTF8(IDS_PLUGIN_SEARCHING)); // "t" is the id of the templates root node. std::string html_data = jstemplate_builder::GetI18nTemplateHtml(template_html, &values); // |missing_plugin| will destroy itself when its WebViewPlugin is going away. - MissingPlugin* missing_plugin = new MissingPlugin(render_view, frame, params, - html_data); + MissingPlugin* missing_plugin = new MissingPlugin( + render_view, frame, params, html_data); return missing_plugin->plugin(); } -MissingPlugin::MissingPlugin(content::RenderView* render_view, +MissingPlugin::MissingPlugin(RenderView* render_view, WebFrame* frame, const WebPluginParams& params, const std::string& html_data) : PluginPlaceholder(render_view, frame, params, html_data), - mime_type_(params.mimeType) { + mime_type_(params.mimeType), + placeholder_routing_id_(RenderThread::Get()->GenerateRoutingID()) { + RenderThread::Get()->AddRoute(placeholder_routing_id_, this); + RenderThread::Get()->Send(new ChromeViewHostMsg_FindMissingPlugin( + routing_id(), placeholder_routing_id_, mime_type_.utf8())); } MissingPlugin::~MissingPlugin() { + RenderThread::Get()->RemoveRoute(placeholder_routing_id_); } void MissingPlugin::BindWebFrame(WebFrame* frame) { @@ -111,6 +124,41 @@ void MissingPlugin::ShowContextMenu(const WebKit::WebMouseEvent& event) { g_last_active_menu = this; } +bool MissingPlugin::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(MissingPlugin, message) + IPC_MESSAGE_HANDLER(ChromeViewMsg_FoundMissingPlugin, + OnFoundMissingPlugin) + IPC_MESSAGE_HANDLER(ChromeViewMsg_DidNotFindMissingPlugin, + OnDidNotFindMissingPlugin) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; +} + +void MissingPlugin::OnFoundMissingPlugin(const string16& plugin_name) { + SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_FOUND, plugin_name)); +} + +void MissingPlugin::OnDidNotFindMissingPlugin() { + SetMessage(l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_FOUND)); +} + +void MissingPlugin::SetMessage(const string16& message) { + message_ = message; + if (!plugin()->web_view()->mainFrame()->isLoading()) + UpdateMessage(); +} + +void MissingPlugin::UpdateMessage() { + DCHECK(!plugin()->web_view()->mainFrame()->isLoading()); + std::string script = "window.setMessage(" + + base::GetDoubleQuotedJson(message_) + ")"; + plugin()->web_view()->mainFrame()->executeScript( + WebScriptSource(ASCIIToUTF16(script))); +} + void MissingPlugin::ContextMenuAction(unsigned id) { if (g_last_active_menu != this) return; @@ -122,3 +170,7 @@ void MissingPlugin::ContextMenuAction(unsigned id) { } } +void MissingPlugin::DidFinishLoading() { + if (message_.length() > 0) + UpdateMessage(); +} diff --git a/chrome/renderer/plugins/missing_plugin.h b/chrome/renderer/plugins/missing_plugin.h index 7b3351f..399cfbd 100644 --- a/chrome/renderer/plugins/missing_plugin.h +++ b/chrome/renderer/plugins/missing_plugin.h @@ -6,9 +6,14 @@ #define CHROME_RENDERER_PLUGINS_MISSING_PLUGIN_H_ #pragma once +#include "base/string16.h" #include "chrome/renderer/plugins/plugin_placeholder.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" +namespace content { +class RenderThread; +} + class MissingPlugin : public PluginPlaceholder { public: // Creates a new WebViewPlugin with a MissingPlugin as a delegate. @@ -27,14 +32,30 @@ class MissingPlugin : public PluginPlaceholder { // WebViewPlugin::Delegate methods: virtual void BindWebFrame(WebKit::WebFrame* frame) OVERRIDE; virtual void ShowContextMenu(const WebKit::WebMouseEvent&) OVERRIDE; + virtual void DidFinishLoading() OVERRIDE; + + // IPC::Channel::Listener methods: + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; // content::RenderViewObserver methods: virtual void ContextMenuAction(unsigned id) OVERRIDE; void HideCallback(const CppArgumentList& args, CppVariant* result); + void OnFoundMissingPlugin(const string16& plugin_name); + void OnDidNotFindMissingPlugin(); + + void SetMessage(const string16& message); + void UpdateMessage(); + WebKit::WebString mime_type_; + // |routing_id()| is the routing ID of our associated RenderView, but we have + // a separate routing ID for messages specific to this placeholder. + int32 placeholder_routing_id_; + + string16 message_; + DISALLOW_COPY_AND_ASSIGN(MissingPlugin); }; diff --git a/chrome/renderer/plugins/plugin_placeholder.cc b/chrome/renderer/plugins/plugin_placeholder.cc index 4bc97a6..ffc9523 100644 --- a/chrome/renderer/plugins/plugin_placeholder.cc +++ b/chrome/renderer/plugins/plugin_placeholder.cc @@ -124,3 +124,6 @@ void PluginPlaceholder::WillDestroyPlugin() { void PluginPlaceholder::ShowContextMenu(const WebMouseEvent& event) { } + +void PluginPlaceholder::DidFinishLoading() { +} diff --git a/chrome/renderer/plugins/plugin_placeholder.h b/chrome/renderer/plugins/plugin_placeholder.h index 009d300..fde0c47 100644 --- a/chrome/renderer/plugins/plugin_placeholder.h +++ b/chrome/renderer/plugins/plugin_placeholder.h @@ -44,6 +44,7 @@ class PluginPlaceholder : public content::RenderViewObserver, virtual void BindWebFrame(WebKit::WebFrame* frame) OVERRIDE; virtual void WillDestroyPlugin() OVERRIDE; virtual void ShowContextMenu(const WebKit::WebMouseEvent& event) OVERRIDE; + virtual void DidFinishLoading() OVERRIDE; private: WebKit::WebFrame* frame_; diff --git a/chrome/renderer/resources/blocked_plugin.html b/chrome/renderer/resources/blocked_plugin.html index 6f8e8620..92fe9d0 100644 --- a/chrome/renderer/resources/blocked_plugin.html +++ b/chrome/renderer/resources/blocked_plugin.html @@ -5,6 +5,9 @@ function debug(msg) { document.getElementById('debug').textContent = msg; } +function setMessage(msg) { + document.getElementById('message').textContent = msg; +} </script> <style> body { @@ -76,7 +79,7 @@ p { <div i18n-values="title:name" id="outer"> <div id="inner"> <div><img id="plugin_icon" src="plugin_blocked.png" /></div> -<h1 i18n-content="message">PLUGIN_BLOCKED</h1> +<h1 id="message" i18n-content="message"></h1> <p id="debug"> </p> </div> <div id="close" i18n-values="title:hide" onclick="plugin.hide();" /> diff --git a/webkit/plugins/webview_plugin.cc b/webkit/plugins/webview_plugin.cc index f43fc2c..5098564 100644 --- a/webkit/plugins/webview_plugin.cc +++ b/webkit/plugins/webview_plugin.cc @@ -243,6 +243,11 @@ WebURLError WebViewPlugin::cancelledError(WebFrame* frame, return error; } +void WebViewPlugin::didFinishLoad(WebFrame* frame) { + if (delegate_) + delegate_->DidFinishLoading(); +} + void WebViewPlugin::didReceiveResponse(WebFrame* frame, unsigned identifier, const WebURLResponse& response) { diff --git a/webkit/plugins/webview_plugin.h b/webkit/plugins/webview_plugin.h index 1d2a35d..7146d98 100644 --- a/webkit/plugins/webview_plugin.h +++ b/webkit/plugins/webview_plugin.h @@ -46,6 +46,9 @@ class WebViewPlugin: public WebKit::WebPlugin, public WebKit::WebViewClient, // Called upon a context menu event. virtual void ShowContextMenu(const WebKit::WebMouseEvent&) = 0; + + // Called when the WebFrame finished loading. + virtual void DidFinishLoading() = 0; }; explicit WebViewPlugin(Delegate* delegate); @@ -126,6 +129,8 @@ class WebViewPlugin: public WebKit::WebPlugin, public WebKit::WebViewClient, virtual WebKit::WebURLError cancelledError( WebKit::WebFrame* frame, const WebKit::WebURLRequest& request); + virtual void didFinishLoad(WebKit::WebFrame*); + // This method is defined in WebPlugin as well as in WebFrameClient, but with // different parameters. We only care about implementing the WebPlugin // version, so we implement this method and call the default in WebFrameClient |