summaryrefslogtreecommitdiffstats
path: root/webkit/glue/plugins
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
commitf5b16fed647e941aa66933178da85db2860d639b (patch)
treef00e9856c04aad3b558a140955e7674add33f051 /webkit/glue/plugins
parent920c091ac3ee15079194c82ae8a7a18215f3f23c (diff)
downloadchromium_src-f5b16fed647e941aa66933178da85db2860d639b.zip
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.gz
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.bz2
Add webkit to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/plugins')
-rw-r--r--webkit/glue/plugins/mozilla_extensions.cc395
-rw-r--r--webkit/glue/plugins/mozilla_extensions.h124
-rw-r--r--webkit/glue/plugins/nphostapi.h302
-rw-r--r--webkit/glue/plugins/plugin_data_stream.cc68
-rw-r--r--webkit/glue/plugins/plugin_data_stream.h66
-rw-r--r--webkit/glue/plugins/plugin_host.cc877
-rw-r--r--webkit/glue/plugins/plugin_host.h107
-rw-r--r--webkit/glue/plugins/plugin_instance.cc463
-rw-r--r--webkit/glue/plugins/plugin_instance.h288
-rw-r--r--webkit/glue/plugins/plugin_lib.cc433
-rw-r--r--webkit/glue/plugins/plugin_lib.h163
-rw-r--r--webkit/glue/plugins/plugin_list.cc500
-rw-r--r--webkit/glue/plugins/plugin_list.h197
-rw-r--r--webkit/glue/plugins/plugin_stream.cc323
-rw-r--r--webkit/glue/plugins/plugin_stream.h136
-rw-r--r--webkit/glue/plugins/plugin_stream_url.cc104
-rw-r--r--webkit/glue/plugins/plugin_stream_url.h84
-rw-r--r--webkit/glue/plugins/plugin_string_stream.cc56
-rw-r--r--webkit/glue/plugins/plugin_string_stream.h62
-rw-r--r--webkit/glue/plugins/test/SConscript109
-rw-r--r--webkit/glue/plugins/test/npapi_constants.cc35
-rw-r--r--webkit/glue/plugins/test/npapi_constants.h44
-rw-r--r--webkit/glue/plugins/test/npapi_test.cc92
-rw-r--r--webkit/glue/plugins/test/npapi_test.def6
-rw-r--r--webkit/glue/plugins/test/npapi_test.rc102
-rw-r--r--webkit/glue/plugins/test/npapi_test_plugin.vcproj256
-rw-r--r--webkit/glue/plugins/test/plugin_arguments_test.cc92
-rw-r--r--webkit/glue/plugins/test/plugin_arguments_test.h69
-rw-r--r--webkit/glue/plugins/test/plugin_client.cc300
-rw-r--r--webkit/glue/plugins/test/plugin_client.h71
-rw-r--r--webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc67
-rw-r--r--webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h56
-rw-r--r--webkit/glue/plugins/test/plugin_execute_script_delete_test.cc53
-rw-r--r--webkit/glue/plugins/test/plugin_execute_script_delete_test.h50
-rw-r--r--webkit/glue/plugins/test/plugin_get_javascript_url_test.cc134
-rw-r--r--webkit/glue/plugins/test/plugin_get_javascript_url_test.h63
-rw-r--r--webkit/glue/plugins/test/plugin_geturl_test.cc253
-rw-r--r--webkit/glue/plugins/test/plugin_geturl_test.h71
-rw-r--r--webkit/glue/plugins/test/plugin_new_fails_test.cc43
-rw-r--r--webkit/glue/plugins/test/plugin_new_fails_test.h46
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc189
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_lifetime_test.h96
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_proxy_test.cc68
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_proxy_test.h53
-rw-r--r--webkit/glue/plugins/test/plugin_test.cc160
-rw-r--r--webkit/glue/plugins/test/plugin_test.h153
-rw-r--r--webkit/glue/plugins/test/plugin_window_size_test.cc67
-rw-r--r--webkit/glue/plugins/test/plugin_window_size_test.h50
-rw-r--r--webkit/glue/plugins/test/resource.h14
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.cc1081
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h287
51 files changed, 8978 insertions, 0 deletions
diff --git a/webkit/glue/plugins/mozilla_extensions.cc b/webkit/glue/plugins/mozilla_extensions.cc
new file mode 100644
index 0000000..efda1df
--- /dev/null
+++ b/webkit/glue/plugins/mozilla_extensions.cc
@@ -0,0 +1,395 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <windows.h>
+#include <Winhttp.h>
+
+#include <algorithm>
+
+#include "webkit/glue/plugins/mozilla_extensions.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_proxy_service.h"
+#include "net/http/http_proxy_resolver_winhttp.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+
+#define QI_SUPPORTS_IID(iid, iface) \
+ QI_SUPPORTS_IID_(iid, iface::GetIID(), iface)
+
+#define QI_SUPPORTS_IID_(src_iid, iface_iid, iface) \
+ if (iid.Equals(iface_iid)) { \
+ AddRef(); \
+ *result = static_cast<iface*>(this); \
+ return NS_OK; \
+ }
+
+namespace NPAPI
+{
+
+void MozillaExtensionApi::DetachFromInstance() {
+ plugin_instance_ = NULL;
+}
+
+bool MozillaExtensionApi::FindProxyForUrl(const char* url,
+ std::string* proxy) {
+ bool result = false;
+
+ if ((!url) || (!proxy)) {
+ NOTREACHED();
+ return result;
+ }
+
+ net::HttpProxyResolverWinHttp proxy_resolver;
+ net::HttpProxyService proxy_service(&proxy_resolver);
+ net::HttpProxyInfo proxy_info;
+
+ if (proxy_service.ResolveProxy(GURL(std::string(url)),
+ &proxy_info,
+ NULL,
+ NULL) == net::OK) {
+ if (!proxy_info.is_direct()) {
+ std::wstring winhttp_proxy = proxy_info.proxy_server();
+
+ // Winhttp returns proxy in the the following format:
+ // - HTTP proxy: "111.111.111.111:11"
+ // -.SOCKS proxy: "socks=111.111.111.111:11"
+ // - Mixed proxy: "http=111.111.111.111:11; socks=222.222.222.222:22"
+ //
+ // We need to translate this into the following format:
+ // i) "DIRECT" -- no proxy
+ // ii) "PROXY xxx.xxx.xxx.xxx" -- use proxy
+ // iii) "SOCKS xxx.xxx.xxx.xxx" -- use SOCKS
+ // iv) Mixed. e.g. "PROXY 111.111.111.111;PROXY 112.112.112.112",
+ // "PROXY 111.111.111.111;SOCKS 112.112.112.112"....
+ StringToLowerASCII(winhttp_proxy);
+ if (std::wstring::npos == winhttp_proxy.find(L'=')) {
+ // Proxy is in the form: "111.111.111.111:11"
+ winhttp_proxy.insert(0, L"http ");
+ } else {
+ // Proxy is in the following form.
+ // -.SOCKS proxy: "socks=111.111.111.111:11"
+ // - Mixed proxy: "http=111.111.111.111:11; socks=222.222.222.222:22"
+ // in this case just replace the '=' with a space
+ std::replace_if(winhttp_proxy.begin(),
+ winhttp_proxy.end(),
+ std::bind2nd(std::equal_to<wchar_t>(), L'='), L' ');
+ }
+
+ *proxy = WideToASCII(std::wstring(winhttp_proxy));
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+// nsISupports implementation
+NS_IMETHODIMP MozillaExtensionApi::QueryInterface(REFNSIID iid,
+ void** result) {
+ static const nsIID knsISupportsIID = NS_ISUPPORTS_IID;
+ QI_SUPPORTS_IID_(iid, knsISupportsIID, nsIServiceManager)
+ QI_SUPPORTS_IID(iid, nsIServiceManager)
+ QI_SUPPORTS_IID(iid, nsIPluginManager)
+ QI_SUPPORTS_IID(iid, nsIPluginManager2)
+ QI_SUPPORTS_IID(iid, nsICookieStorage)
+
+ NOTREACHED();
+ return NS_ERROR_NO_INTERFACE;
+}
+
+NS_IMETHODIMP_(nsrefcnt) MozillaExtensionApi::AddRef(void) {
+ return InterlockedIncrement(reinterpret_cast<LONG*>(&ref_count_));
+}
+
+NS_IMETHODIMP_(nsrefcnt) MozillaExtensionApi::Release(void) {
+ DCHECK(static_cast<int>(ref_count_) > 0);
+ if (InterlockedDecrement(reinterpret_cast<LONG*>(&ref_count_)) == 0) {
+ delete this;
+ return 0;
+ }
+
+ return ref_count_;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::GetService(REFNSIID class_guid,
+ REFNSIID iid,
+ void** result) {
+
+ static const nsIID kPluginManagerCID = NS_PLUGINMANAGER_CID;
+ static const nsIID kCookieStorageCID = NS_COOKIESTORAGE_CID;
+
+ nsresult rv = NS_ERROR_FAILURE;
+
+ if ((class_guid.Equals(kPluginManagerCID)) ||
+ (class_guid.Equals(kCookieStorageCID))) {
+ rv = QueryInterface(iid, result);
+ }
+
+ DCHECK(rv == NS_OK);
+ return rv;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::GetServiceByContractID(
+ const char* contract_id,
+ REFNSIID iid,
+ void** result) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::IsServiceInstantiated(REFNSIID class_guid,
+ REFNSIID iid,
+ PRBool* result) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::IsServiceInstantiatedByContractID(
+ const char* contract_id,
+ REFNSIID iid,
+ PRBool* result) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+
+NS_IMETHODIMP MozillaExtensionApi::GetValue(nsPluginManagerVariable variable,
+ void * value) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::ReloadPlugins(PRBool reloadPages) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::UserAgent(
+ const char** resultingAgentString) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::GetURL(
+ nsISupports* pluginInst,
+ const char* url,
+ const char* target,
+ nsIPluginStreamListener* streamListener,
+ const char* altHost,
+ const char* referrer,
+ PRBool forceJSEnabled) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::PostURL(
+ nsISupports* pluginInst,
+ const char* url,
+ unsigned int postDataLen,
+ const char* postData,
+ PRBool isFile,
+ const char* target,
+ nsIPluginStreamListener* streamListener,
+ const char* altHost,
+ const char* referrer,
+ PRBool forceJSEnabled ,
+ unsigned int postHeadersLength,
+ const char* postHeaders) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::RegisterPlugin(
+ REFNSIID aCID,
+ const char *aPluginName,
+ const char *aDescription,
+ const char * * aMimeTypes,
+ const char * * aMimeDescriptions,
+ const char * * aFileExtensions,
+ PRInt32 aCount) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::UnregisterPlugin(REFNSIID aCID) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::GetURLWithHeaders(
+ nsISupports* pluginInst,
+ const char* url,
+ const char* target /* = NULL */,
+ nsIPluginStreamListener* streamListener /* = NULL */,
+ const char* altHost /* = NULL */,
+ const char* referrer /* = NULL */,
+ PRBool forceJSEnabled /* = PR_FALSE */,
+ PRUint32 getHeadersLength /* = 0 */,
+ const char* getHeaders /* = NULL */){
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+// nsIPluginManager2
+NS_IMETHODIMP MozillaExtensionApi::BeginWaitCursor() {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::EndWaitCursor() {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::SupportsURLProtocol(const char* aProtocol,
+ PRBool* aResult) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::NotifyStatusChange(nsIPlugin* aPlugin,
+ nsresult aStatus) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::FindProxyForURL(
+ const char* aURL,
+ char** aResult) {
+ std::string proxy = "DIRECT";
+ FindProxyForUrl(aURL, &proxy);
+
+ // Allocate this using the NPAPI allocator. The plugin will call
+ // NPN_Free to free this.
+ char* result = static_cast<char*>(NPN_MemAlloc(proxy.length() + 1));
+ strncpy(result, proxy.c_str(), proxy.length() + 1);
+
+ *aResult = result;
+ return NS_OK;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::RegisterWindow(
+ nsIEventHandler* handler,
+ nsPluginPlatformWindowRef window) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::UnregisterWindow(
+ nsIEventHandler* handler,
+ nsPluginPlatformWindowRef win) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::AllocateMenuID(nsIEventHandler* aHandler,
+ PRBool aIsSubmenu,
+ PRInt16 *aResult) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::DeallocateMenuID(nsIEventHandler* aHandler,
+ PRInt16 aMenuID) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::HasAllocatedMenuID(nsIEventHandler* aHandler,
+ PRInt16 aMenuID,
+ PRBool* aResult) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+// nsICookieStorage
+NS_IMETHODIMP MozillaExtensionApi::GetCookie(
+ const char* url,
+ void* cookie_buffer,
+ PRUint32& buffer_size) {
+ if ((!url) || (!cookie_buffer)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (!plugin_instance_)
+ return NS_ERROR_FAILURE;
+
+ WebPlugin* webplugin = plugin_instance_->webplugin();
+ if (!webplugin)
+ return NS_ERROR_FAILURE;
+
+ // Bypass third-party cookie blocking by using the url as the policy_url.
+ GURL cookies_url((std::string(url)));
+ std::string cookies = webplugin->GetCookies(cookies_url, cookies_url);
+
+ if (cookies.empty())
+ return NS_ERROR_FAILURE;
+
+ if(cookies.length() >= buffer_size)
+ return NS_ERROR_FAILURE;
+
+ strncpy(static_cast<char*>(cookie_buffer),
+ cookies.c_str(),
+ cookies.length() + 1);
+
+ buffer_size = cookies.length();
+ return NS_OK;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::SetCookie(
+ const char* url,
+ const void* cookie_buffer,
+ PRUint32 buffer_size){
+ if ((!url) || (!cookie_buffer) || (!buffer_size)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (!plugin_instance_)
+ return NS_ERROR_FAILURE;
+
+ WebPlugin* webplugin = plugin_instance_->webplugin();
+ if (!webplugin)
+ return NS_ERROR_FAILURE;
+
+ std::string cookie(static_cast<const char*>(cookie_buffer),
+ buffer_size);
+ GURL cookies_url((std::string(url)));
+ webplugin->SetCookie(cookies_url,
+ cookies_url,
+ cookie);
+ return NS_OK;
+}
+
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/mozilla_extensions.h b/webkit/glue/plugins/mozilla_extensions.h
new file mode 100644
index 0000000..737f9fe9
--- /dev/null
+++ b/webkit/glue/plugins/mozilla_extensions.h
@@ -0,0 +1,124 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGINS_MOZILLA_EXTENSIONS_H__
+#define WEBKIT_GLUE_PLUGINS_MOZILLA_EXTENSIONS_H__
+
+#include <windows.h>
+
+// Include npapi first to avoid definition clashes due to
+// XP_WIN
+#include "third_party/npapi/bindings/npapi.h"
+
+#include "third_party/mozilla/include/nsIServiceManager.h"
+#include "third_party/mozilla/include/nsIPluginManager2.h"
+#include "third_party/mozilla/include/nsICookieStorage.h"
+#include "third_party/mozilla/include/nsError.h"
+
+#include "base/ref_counted.h"
+
+// NS_DECL_NSIPLUGINMANAGER doesn't include methods described as "C++" in the
+// nsIPluginManager.idl.
+#define NS_DECL_NSIPLUGINMANAGER_FIXED \
+ NS_DECL_NSIPLUGINMANAGER \
+ NS_IMETHOD \
+ GetURL(nsISupports* pluginInst, \
+ const char* url, \
+ const char* target = NULL, \
+ nsIPluginStreamListener* streamListener = NULL, \
+ const char* altHost = NULL, \
+ const char* referrer = NULL, \
+ PRBool forceJSEnabled = PR_FALSE); \
+ NS_IMETHOD \
+ PostURL(nsISupports* pluginInst, \
+ const char* url, \
+ PRUint32 postDataLen, \
+ const char* postData, \
+ PRBool isFile = PR_FALSE, \
+ const char* target = NULL, \
+ nsIPluginStreamListener* streamListener = NULL, \
+ const char* altHost = NULL, \
+ const char* referrer = NULL, \
+ PRBool forceJSEnabled = PR_FALSE, \
+ PRUint32 postHeadersLength = 0, \
+ const char* postHeaders = NULL); \
+ NS_IMETHOD \
+ GetURLWithHeaders(nsISupports* pluginInst, \
+ const char* url, \
+ const char* target = NULL, \
+ nsIPluginStreamListener* streamListener = NULL, \
+ const char* altHost = NULL, \
+ const char* referrer = NULL, \
+ PRBool forceJSEnabled = PR_FALSE, \
+ PRUint32 getHeadersLength = 0, \
+ const char* getHeaders = NULL);
+
+// Avoid dependence on the nsIsupportsImpl.h and so on.
+#ifndef NS_DECL_ISUPPORTS
+#define NS_DECL_ISUPPORTS \
+ NS_IMETHOD QueryInterface(REFNSIID aIID, \
+ void** aInstancePtr); \
+ NS_IMETHOD_(nsrefcnt) AddRef(void); \
+ NS_IMETHOD_(nsrefcnt) Release(void);
+#endif // NS_DECL_ISUPPORTS
+
+namespace NPAPI
+{
+
+class PluginInstance;
+
+// Implementation of extended Mozilla interfaces needed to support
+// Sun's new Java plugin.
+class MozillaExtensionApi : public nsIServiceManager,
+ public nsIPluginManager2,
+ public nsICookieStorage {
+ public:
+ MozillaExtensionApi(PluginInstance* plugin_instance) :
+ plugin_instance_(plugin_instance), ref_count_(0) {
+ }
+
+ void DetachFromInstance();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISERVICEMANAGER
+ NS_DECL_NSIPLUGINMANAGER_FIXED
+ NS_DECL_NSIPLUGINMANAGER2
+ NS_DECL_NSICOOKIESTORAGE
+
+ protected:
+ bool FindProxyForUrl(const char* url, std::string* proxy);
+
+ protected:
+ scoped_refptr<NPAPI::PluginInstance> plugin_instance_;
+ unsigned long ref_count_;
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGINS_MOZILLA_EXTENSIONS_H__
diff --git a/webkit/glue/plugins/nphostapi.h b/webkit/glue/plugins/nphostapi.h
new file mode 100644
index 0000000..a248fd6
--- /dev/null
+++ b/webkit/glue/plugins/nphostapi.h
@@ -0,0 +1,302 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// TODO: Did not implement JRIGlobalRef function yet. Not sure if this is used?
+
+#ifndef WEBKIT_GLUE_PLUGIN_NPHOSTAPI_H__
+#define WEBKIT_GLUE_PLUGIN_NPHOSTAPI_H__
+
+#include "bindings/npapi.h"
+#include "bindings/npruntime.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// NPAPI NPP Function Pointers
+//
+typedef NPError (*NPP_NewProcPtr)(NPMIMEType pluginType,
+ NPP instance,
+ uint16 mode,
+ int16 argc,
+ char* argn[],
+ char* argv[],
+ NPSavedData* saved);
+typedef NPError (*NPP_DestroyProcPtr)(NPP instance,
+ NPSavedData** save);
+typedef NPError (*NPP_SetWindowProcPtr)(NPP instance,
+ NPWindow* window);
+typedef NPError (*NPP_NewStreamProcPtr)(NPP instance,
+ NPMIMEType type,
+ NPStream* stream,
+ NPBool seekable,
+ uint16* stype);
+typedef NPError (*NPP_DestroyStreamProcPtr)(NPP instance,
+ NPStream* stream,
+ NPReason reason);
+typedef int32 (*NPP_WriteReadyProcPtr)(NPP instance,
+ NPStream* stream);
+typedef int32 (*NPP_WriteProcPtr)(NPP instance,
+ NPStream* stream,
+ int32 offset,
+ int32 len,
+ void* buffer);
+typedef void (*NPP_StreamAsFileProcPtr)(NPP instance,
+ NPStream* stream,
+ const char* fname);
+typedef void (*NPP_PrintProcPtr)(NPP instance,
+ NPPrint* platformPrint);
+typedef int16 (*NPP_HandleEventProcPtr)(NPP instance,
+ void* event);
+typedef void (*NPP_URLNotifyProcPtr)(NPP instance,
+ const char* url,
+ NPReason reason,
+ void* notifyData);
+typedef void* JRIGlobalRef; //not using this right now
+typedef NPError (*NPP_GetValueProcPtr)(NPP instance,
+ NPPVariable variable,
+ void *ret_alue);
+typedef NPError (*NPP_SetValueProcPtr)(NPP instance,
+ NPNVariable variable,
+ void *ret_alue);
+
+//
+// NPAPI NPN Function Pointers
+//
+typedef NPError (*NPN_GetURLProcPtr)(NPP instance,
+ const char* URL,
+ const char* window);
+typedef NPError (*NPN_PostURLProcPtr)(NPP instance,
+ const char* URL,
+ const char* window,
+ uint32 len,
+ const char* buf,
+ NPBool file);
+typedef NPError (*NPN_RequestReadProcPtr)(NPStream* stream,
+ NPByteRange* rangeList);
+typedef NPError (*NPN_NewStreamProcPtr)(NPP instance,
+ NPMIMEType type,
+ const char* window,
+ NPStream** stream);
+typedef int32 (*NPN_WriteProcPtr)(NPP instance,
+ NPStream* stream,
+ int32 len,
+ void* buffer);
+typedef NPError (*NPN_DestroyStreamProcPtr)(NPP instance,
+ NPStream* stream,
+ NPReason reason);
+typedef void (*NPN_StatusProcPtr)(NPP instance,
+ const char* message);
+typedef const char* (*NPN_UserAgentProcPtr)(NPP instance);
+typedef void* (*NPN_MemAllocProcPtr)(uint32 size);
+typedef void (*NPN_MemFreeProcPtr)(void* ptr);
+typedef uint32 (*NPN_MemFlushProcPtr)(uint32 size);
+typedef void (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages);
+
+typedef void* (*NPN_GetJavaEnvProcPtr)(void);
+typedef void* (*NPN_GetJavaPeerProcPtr)(NPP instance);
+
+typedef NPError (*NPN_GetURLNotifyProcPtr)(NPP instance,
+ const char* URL,
+ const char* window,
+ void* notifyData);
+typedef NPError (*NPN_PostURLNotifyProcPtr)(NPP instance,
+ const char* URL,
+ const char* window,
+ uint32 len,
+ const char* buf,
+ NPBool file,
+ void* notifyData);
+typedef NPError (*NPN_GetValueProcPtr)(NPP instance,
+ NPNVariable variable,
+ void *ret_value);
+typedef NPError (*NPN_SetValueProcPtr)(NPP instance,
+ NPPVariable variable,
+ void *value);
+typedef void (*NPN_InvalidateRectProcPtr)(NPP instance,
+ NPRect *rect);
+typedef void (*NPN_InvalidateRegionProcPtr)(NPP instance,
+ NPRegion region);
+typedef void (*NPN_ForceRedrawProcPtr)(NPP instance);
+
+typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant);
+
+typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr) (const NPUTF8 *name);
+typedef void (*NPN_GetStringIdentifiersProcPtr) (const NPUTF8 **names,
+ int32_t nameCount,
+ NPIdentifier *identifiers);
+typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr) (int32_t intid);
+typedef int32_t (*NPN_IntFromIdentifierProcPtr) (NPIdentifier identifier);
+typedef bool (*NPN_IdentifierIsStringProcPtr) (NPIdentifier identifier);
+typedef NPUTF8 * (*NPN_UTF8FromIdentifierProcPtr) (NPIdentifier identifier);
+
+typedef NPObject* (*NPN_CreateObjectProcPtr) (NPP,
+ NPClass *aClass);
+typedef NPObject* (*NPN_RetainObjectProcPtr) (NPObject *obj);
+typedef void (*NPN_ReleaseObjectProcPtr) (NPObject *obj);
+typedef bool (*NPN_InvokeProcPtr) (NPP npp,
+ NPObject *obj,
+ NPIdentifier methodName,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result);
+typedef bool (*NPN_InvokeDefaultProcPtr) (NPP npp,
+ NPObject *obj,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result);
+typedef bool (*NPN_EvaluateProcPtr) (NPP npp,
+ NPObject *obj,
+ NPString *script,
+ NPVariant *result);
+typedef bool (*NPN_GetPropertyProcPtr) (NPP npp,
+ NPObject *obj,
+ NPIdentifier propertyName,
+ NPVariant *result);
+typedef bool (*NPN_SetPropertyProcPtr) (NPP npp,
+ NPObject *obj,
+ NPIdentifier propertyName,
+ const NPVariant *value);
+typedef bool (*NPN_HasPropertyProcPtr) (NPP,
+ NPObject *npobj,
+ NPIdentifier propertyName);
+typedef bool (*NPN_HasMethodProcPtr) (NPP npp,
+ NPObject *npobj,
+ NPIdentifier methodName);
+typedef bool (*NPN_RemovePropertyProcPtr) (NPP npp,
+ NPObject *obj,
+ NPIdentifier propertyName);
+typedef void (*NPN_SetExceptionProcPtr) (NPObject *obj,
+ const NPUTF8 *message);
+typedef void (*NPN_PushPopupsEnabledStateProcPtr)(NPP npp,
+ NPBool enabled);
+typedef void (*NPN_PopPopupsEnabledStateProcPtr)(NPP npp);
+typedef bool (*NPN_EnumerateProcPtr)(NPP npp,
+ NPObject *obj,
+ NPIdentifier **identifier,
+ uint32_t *count);
+typedef void (*NPN_PluginThreadAsyncCallProcPtr)(NPP instance,
+ void (*func)(void *),
+ void *userData);
+typedef bool (*NPN_ConstructProcPtr)(NPP npp,
+ NPObject* obj,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result);
+
+//
+// NPAPI Function table of NPP functions (functions provided by plugin to host)
+//
+typedef struct _NPPluginFuncs {
+ unsigned short size;
+ unsigned short version;
+ NPP_NewProcPtr newp;
+ NPP_DestroyProcPtr destroy;
+ NPP_SetWindowProcPtr setwindow;
+ NPP_NewStreamProcPtr newstream;
+ NPP_DestroyStreamProcPtr destroystream;
+ NPP_StreamAsFileProcPtr asfile;
+ NPP_WriteReadyProcPtr writeready;
+ NPP_WriteProcPtr write;
+ NPP_PrintProcPtr print;
+ NPP_HandleEventProcPtr event;
+ NPP_URLNotifyProcPtr urlnotify;
+ JRIGlobalRef javaClass;
+ NPP_GetValueProcPtr getvalue;
+ NPP_SetValueProcPtr setvalue;
+} NPPluginFuncs;
+
+//
+// NPAPI Function table NPN functions (functions provided by host to plugin)
+//
+typedef struct _NPNetscapeFuncs {
+ uint16 size;
+ uint16 version;
+ NPN_GetURLProcPtr geturl;
+ NPN_PostURLProcPtr posturl;
+ NPN_RequestReadProcPtr requestread;
+ NPN_NewStreamProcPtr newstream;
+ NPN_WriteProcPtr write;
+ NPN_DestroyStreamProcPtr destroystream;
+ NPN_StatusProcPtr status;
+ NPN_UserAgentProcPtr uagent;
+ NPN_MemAllocProcPtr memalloc;
+ NPN_MemFreeProcPtr memfree;
+ NPN_MemFlushProcPtr memflush;
+ NPN_ReloadPluginsProcPtr reloadplugins;
+ NPN_GetJavaEnvProcPtr getJavaEnv;
+ NPN_GetJavaPeerProcPtr getJavaPeer;
+ NPN_GetURLNotifyProcPtr geturlnotify;
+ NPN_PostURLNotifyProcPtr posturlnotify;
+ NPN_GetValueProcPtr getvalue;
+ NPN_SetValueProcPtr setvalue;
+ NPN_InvalidateRectProcPtr invalidaterect;
+ NPN_InvalidateRegionProcPtr invalidateregion;
+ NPN_ForceRedrawProcPtr forceredraw;
+
+ NPN_GetStringIdentifierProcPtr getstringidentifier;
+ NPN_GetStringIdentifiersProcPtr getstringidentifiers;
+ NPN_GetIntIdentifierProcPtr getintidentifier;
+ NPN_IdentifierIsStringProcPtr identifierisstring;
+ NPN_UTF8FromIdentifierProcPtr utf8fromidentifier;
+ NPN_IntFromIdentifierProcPtr intfromidentifier;
+ NPN_CreateObjectProcPtr createobject;
+ NPN_RetainObjectProcPtr retainobject;
+ NPN_ReleaseObjectProcPtr releaseobject;
+ NPN_InvokeProcPtr invoke;
+ NPN_InvokeDefaultProcPtr invokeDefault;
+ NPN_EvaluateProcPtr evaluate;
+ NPN_GetPropertyProcPtr getproperty;
+ NPN_SetPropertyProcPtr setproperty;
+ NPN_RemovePropertyProcPtr removeproperty;
+ NPN_HasPropertyProcPtr hasproperty;
+ NPN_HasMethodProcPtr hasmethod;
+ NPN_ReleaseVariantValueProcPtr releasevariantvalue;
+ NPN_SetExceptionProcPtr setexception;
+ NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate;
+ NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate;
+ NPN_EnumerateProcPtr enumerate;
+ NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall;
+ NPN_ConstructProcPtr construct;
+} NPNetscapeFuncs;
+
+//
+// NPAPI DLL entry points
+//
+typedef NPError (__stdcall * NP_InitializeFunc)(NPNetscapeFuncs* pFuncs);
+typedef NPError (__stdcall * NP_GetEntryPointsFunc)(NPPluginFuncs* pFuncs);
+typedef NPError (__stdcall * NP_ShutdownFunc)(void);
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBKIT_GLUE_PLUGIN_NPHOSTAPI_H__
diff --git a/webkit/glue/plugins/plugin_data_stream.cc b/webkit/glue/plugins/plugin_data_stream.cc
new file mode 100644
index 0000000..bb7ee0b
--- /dev/null
+++ b/webkit/glue/plugins/plugin_data_stream.cc
@@ -0,0 +1,68 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/plugin_data_stream.h"
+
+namespace NPAPI {
+
+PluginDataStream::PluginDataStream(PluginInstance *instance,
+ const std::string& url,
+ const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified)
+ : PluginStream(instance, url.c_str(), false, 0),
+ mime_type_(mime_type),
+ headers_(headers),
+ expected_length_(expected_length),
+ last_modified_(last_modified),
+ stream_open_failed_(false) {
+}
+
+PluginDataStream::~PluginDataStream() {
+}
+
+void PluginDataStream::SendToPlugin(const char* buffer, int length) {
+ if (stream_open_failed_)
+ return;
+
+ if (!open()) {
+ if (!Open(mime_type_, headers_, expected_length_, last_modified_)) {
+ stream_open_failed_ = true;
+ return;
+ }
+ }
+
+ // TODO(iyengar) - check if it was not fully sent, and figure out a
+ // backup plan.
+ int written = Write(buffer, length);
+ DCHECK(written == length);
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_data_stream.h b/webkit/glue/plugins/plugin_data_stream.h
new file mode 100644
index 0000000..64cc3b1
--- /dev/null
+++ b/webkit/glue/plugins/plugin_data_stream.h
@@ -0,0 +1,66 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_DATA_STREAM_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_DATA_STREAM_H__
+
+#include "webkit/glue/plugins/plugin_stream.h"
+
+namespace NPAPI {
+
+class PluginInstance;
+
+// A NPAPI stream based on data received from the renderer.
+class PluginDataStream : public PluginStream {
+ public:
+ // Create a new stream for sending to the plugin.
+ PluginDataStream(PluginInstance *instance, const std::string& url,
+ const std::string& mime_type, const std::string& headers,
+ uint32 expected_length, uint32 last_modified);
+ virtual ~PluginDataStream();
+
+ // Initiates the sending of data to the plugin.
+ void SendToPlugin(const char* buffer, int length);
+
+ private:
+ std::string mime_type_;
+ std::string headers_;
+ uint32 expected_length_;
+ uint32 last_modified_;
+ // This flag when set serves as an indicator that subsequent
+ // data coming from the renderer should not be handed off to the plugin.
+ bool stream_open_failed_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginDataStream);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_DATA_STREAM_H__
+
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc
new file mode 100644
index 0000000..63cd6ca
--- /dev/null
+++ b/webkit/glue/plugins/plugin_host.cc
@@ -0,0 +1,877 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/plugin_host.h"
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "webkit/default_plugin/default_plugin_shared.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/glue/plugins/plugin_stream_url.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+extern "C" {
+
+// FindInstance()
+// Finds a PluginInstance from an NPP.
+// The caller must take a reference if needed.
+NPAPI::PluginInstance* FindInstance(NPP id) {
+ if (id == NULL) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return (NPAPI::PluginInstance *)id->ndata;
+}
+
+namespace NPAPI
+{
+scoped_refptr<PluginHost> PluginHost::singleton_;
+
+static const int kFlashMessageThrottleDelayMs = 10;
+
+PluginHost::PluginHost()
+#pragma warning(suppress: 4355) // can use this
+ : throttle_factory_(this) {
+ InitializeHostFuncs();
+}
+
+PluginHost::~PluginHost() {
+}
+
+PluginHost *PluginHost::Singleton() {
+ if (singleton_.get() == NULL) {
+ singleton_ = new PluginHost();
+ }
+
+ DCHECK(singleton_.get() != NULL);
+ return singleton_;
+}
+
+void PluginHost::InitializeHostFuncs() {
+ memset(&host_funcs_, 0, sizeof(host_funcs_));
+ host_funcs_.size = sizeof(host_funcs_);
+ host_funcs_.version = (NP_VERSION_MAJOR << 8) | (NP_VERSION_MINOR);
+
+ // The "basic" functions
+ host_funcs_.geturl = &NPN_GetURL;
+ host_funcs_.posturl = &NPN_PostURL;
+ host_funcs_.requestread = &NPN_RequestRead;
+ host_funcs_.newstream = &NPN_NewStream;
+ host_funcs_.write = &NPN_Write;
+ host_funcs_.destroystream = &NPN_DestroyStream;
+ host_funcs_.status = &NPN_Status;
+ host_funcs_.uagent = &NPN_UserAgent;
+ host_funcs_.memalloc = &NPN_MemAlloc;
+ host_funcs_.memfree = &NPN_MemFree;
+ host_funcs_.memflush = &NPN_MemFlush;
+ host_funcs_.reloadplugins = &NPN_ReloadPlugins;
+
+ // We don't implement java yet
+ host_funcs_.getJavaEnv = &NPN_GetJavaEnv;
+ host_funcs_.getJavaPeer = &NPN_GetJavaPeer;
+
+ // Advanced functions we implement
+ host_funcs_.geturlnotify = &NPN_GetURLNotify;
+ host_funcs_.posturlnotify = &NPN_PostURLNotify;
+ host_funcs_.getvalue = &NPN_GetValue;
+ host_funcs_.setvalue = &NPN_SetValue;
+ host_funcs_.invalidaterect = &NPN_InvalidateRect;
+ host_funcs_.invalidateregion = &NPN_InvalidateRegion;
+ host_funcs_.forceredraw = &NPN_ForceRedraw;
+
+ // These come from the Javascript Engine
+ host_funcs_.getstringidentifier = NPN_GetStringIdentifier;
+ host_funcs_.getstringidentifiers = NPN_GetStringIdentifiers;
+ host_funcs_.getintidentifier = NPN_GetIntIdentifier;
+ host_funcs_.identifierisstring = NPN_IdentifierIsString;
+ host_funcs_.utf8fromidentifier = NPN_UTF8FromIdentifier;
+ host_funcs_.intfromidentifier = NPN_IntFromIdentifier;
+ host_funcs_.createobject = NPN_CreateObject;
+ host_funcs_.retainobject = NPN_RetainObject;
+ host_funcs_.releaseobject = NPN_ReleaseObject;
+ host_funcs_.invoke = NPN_Invoke;
+ host_funcs_.invokeDefault = NPN_InvokeDefault;
+ host_funcs_.evaluate = NPN_Evaluate;
+ host_funcs_.getproperty = NPN_GetProperty;
+ host_funcs_.setproperty = NPN_SetProperty;
+ host_funcs_.removeproperty = NPN_RemoveProperty;
+ host_funcs_.hasproperty = NPN_HasProperty;
+ host_funcs_.hasmethod = NPN_HasMethod;
+ host_funcs_.releasevariantvalue = NPN_ReleaseVariantValue;
+ host_funcs_.setexception = NPN_SetException;
+ host_funcs_.pushpopupsenabledstate = &NPN_PushPopupsEnabledState;
+ host_funcs_.poppopupsenabledstate = &NPN_PopPopupsEnabledState;
+ host_funcs_.enumerate = &NPN_Enumerate;
+ host_funcs_.pluginthreadasynccall = &NPN_PluginThreadAsyncCall;
+ host_funcs_.construct = &NPN_Construct;
+
+}
+
+void PluginHost::PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides) {
+ // When running in the plugin process, we need to patch the NPN functions
+ // that the plugin calls to interact with NPObjects that we give. Otherwise
+ // the plugin will call the v8 NPN functions, which won't work since we have
+ // an NPObjectProxy and not a real v8 implementation.
+ if (overrides->invoke)
+ host_funcs_.invoke = overrides->invoke;
+
+ if (overrides->invokeDefault)
+ host_funcs_.invokeDefault = overrides->invokeDefault;
+
+ if (overrides->evaluate)
+ host_funcs_.evaluate = overrides->evaluate;
+
+ if (overrides->getproperty)
+ host_funcs_.getproperty = overrides->getproperty;
+
+ if (overrides->setproperty)
+ host_funcs_.setproperty = overrides->setproperty;
+
+ if (overrides->removeproperty)
+ host_funcs_.removeproperty = overrides->removeproperty;
+
+ if (overrides->hasproperty)
+ host_funcs_.hasproperty = overrides->hasproperty;
+
+ if (overrides->hasmethod)
+ host_funcs_.hasmethod = overrides->hasmethod;
+
+ if (overrides->setexception)
+ host_funcs_.setexception = overrides->setexception;
+
+ if (overrides->enumerate)
+ host_funcs_.enumerate = overrides->enumerate;
+}
+
+void PluginHost::InvalidateRect(NPP id, NPRect* invalidRect) {
+ if (!invalidRect) {
+ NOTREACHED();
+ return;
+ }
+
+ // Invalidates specified drawing area prior to repainting or refreshing a
+ // windowless plugin
+
+ // Before a windowless plugin can refresh part of its drawing area, it must
+ // first invalidate it. This function causes the NPP_HandleEvent method to
+ // pass an update event or a paint message to the plug-in. After calling
+ // this method, the plug-in recieves a paint message asynchronously.
+
+ // The browser redraws invalid areas of the document and any windowless
+ // plug-ins at regularly timed intervals. To force a paint message, the
+ // plug-in can call NPN_ForceRedraw after calling this method.
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ DCHECK(plugin.get() != NULL);
+
+ if (plugin.get() && plugin->webplugin()) {
+ if (plugin->throttle_invalidate()) {
+ // We need to track plugin invalidates on a per instance basis.
+ ThrottledInvalidates plugin_instance_invalidates;
+ InstanceThrottledInvalidatesMap::iterator invalidate_index =
+ instance_throttled_invalidates_.find(id);
+ if (invalidate_index != instance_throttled_invalidates_.end()) {
+ plugin_instance_invalidates = (*invalidate_index).second;
+ }
+
+ bool throttle_active =
+ (plugin_instance_invalidates.throttled_invalidates.size() > 0);
+
+ gfx::Rect rect(invalidRect->left,
+ invalidRect->top,
+ invalidRect->right - invalidRect->left,
+ invalidRect->bottom - invalidRect->top);
+
+ plugin_instance_invalidates.throttled_invalidates.push_back(rect);
+
+ if (!throttle_active) {
+ // We hold a reference to the plugin instance to avoid race conditions
+ // due to the instance being released before the OnInvalidateRect
+ // function is invoked.
+ plugin->AddRef();
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ throttle_factory_.NewRunnableMethod(&PluginHost::OnInvalidateRect,
+ id, plugin.get()),
+ kFlashMessageThrottleDelayMs);
+ }
+ instance_throttled_invalidates_[id] = plugin_instance_invalidates;
+ } else {
+ gfx::Rect rect(invalidRect->left,
+ invalidRect->top,
+ invalidRect->right - invalidRect->left,
+ invalidRect->bottom - invalidRect->top);
+ plugin->webplugin()->InvalidateRect(rect);
+ }
+ }
+}
+
+bool PluginHost::SetPostData(const char *buf,
+ uint32 length,
+ std::vector<std::string>* names,
+ std::vector<std::string>* values,
+ std::vector<char>* body) {
+ // Use a state table to do the parsing. Whitespace must be
+ // trimmed after the fact if desired. In our case, we actually
+ // don't care about the whitespace, because we're just going to
+ // pass this back into another POST. This function strips out the
+ // "Content-length" header and does not append it to the request.
+
+ //
+ // This parser takes action only on state changes.
+ //
+ // Transition table:
+ // : \n NULL Other
+ // 0 GetHeader 1 2 4 0
+ // 1 GetValue 1 0 3 1
+ // 2 GetData 2 2 3 2
+ // 3 DONE
+ // 4 ERR
+ //
+ enum { INPUT_COLON=0, INPUT_NEWLINE, INPUT_NULL, INPUT_OTHER };
+ enum { GETNAME, GETVALUE, GETDATA, DONE, ERR };
+ int statemachine[3][4] = { { GETVALUE, GETDATA, ERR, GETNAME },
+ { GETVALUE, GETNAME, DONE, GETVALUE },
+ { GETDATA, GETDATA, DONE, GETDATA } };
+ std::string name, value;
+ char *ptr = (char*)buf;
+ char *start = ptr;
+ int state = GETNAME; // initial state
+ bool done = false;
+ bool err = false;
+ do {
+ int input;
+
+ // Translate the current character into an input
+ // for the state table.
+ switch (*ptr) {
+ case ':' :
+ input = INPUT_COLON;
+ break;
+ case '\n':
+ input = INPUT_NEWLINE;
+ break;
+ case 0 :
+ input = INPUT_NULL;
+ break;
+ default :
+ input = INPUT_OTHER;
+ break;
+ }
+
+ int newstate = statemachine[state][input];
+
+ // Take action based on the new state.
+ if (state != newstate) {
+ switch (newstate) {
+ case GETNAME:
+ // Got a value.
+ value = std::string(start, ptr - start);
+ TrimWhitespace(value, TRIM_ALL, &value);
+ // If the name field is empty, we'll skip this header
+ // but we won't error out.
+ if (!name.empty() && name != "content-length") {
+ names->push_back(name);
+ values->push_back(value);
+ }
+ start = ptr + 1;
+ break;
+ case GETVALUE:
+ // Got a header.
+ name = StringToLowerASCII(std::string(start, ptr - start));
+ TrimWhitespace(name, TRIM_ALL, &name);
+ start = ptr + 1;
+ break;
+ case GETDATA:
+ {
+ // Finished headers, now get body.
+ start = ptr + 1;
+ size_t previous_size = body->size();
+ size_t new_body_size = length - static_cast<int>(start - buf);
+ body->resize(previous_size + new_body_size);
+ if (!body->empty())
+ memcpy(&body->front() + previous_size, start, new_body_size);
+ done = true;
+ break;
+ }
+ case ERR:
+ // error
+ err = true;
+ done = true;
+ break;
+ }
+ }
+ state = newstate;
+ ptr++;
+ } while (!done);
+
+ return !err;
+}
+
+void PluginHost::OnInvalidateRect(NPP id, PluginInstance* instance) {
+ if (!instance) {
+ NOTREACHED();
+ return;
+ }
+
+ InstanceThrottledInvalidatesMap::iterator invalidate_index =
+ instance_throttled_invalidates_.find(id);
+ if (invalidate_index == instance_throttled_invalidates_.end()) {
+ NOTREACHED();
+ instance->Release();
+ return;
+ }
+
+ ThrottledInvalidates plugin_instance_invalidates =
+ (*invalidate_index).second;
+
+ if (instance->webplugin()) {
+ for (unsigned int throttle_index = 0;
+ throttle_index <
+ plugin_instance_invalidates.throttled_invalidates.size();
+ throttle_index++) {
+ instance->webplugin()->InvalidateRect(
+ plugin_instance_invalidates.throttled_invalidates[throttle_index]);
+ }
+ }
+
+ instance->Release();
+ instance_throttled_invalidates_.erase(invalidate_index);
+}
+
+} // namespace NPAPI
+
+// Allocates memory from the host's memory space.
+void* NPN_MemAlloc(uint32 size) {
+ scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton();
+ if (host != NULL) {
+ // Note: We must use the same allocator/deallocator
+ // that is used by the javascript library, as some of the
+ // JS APIs will pass memory to the plugin which the plugin
+ // will attempt to free.
+ return malloc(size);
+ }
+ return NULL;
+}
+
+// Deallocates memory from the host's memory space
+void NPN_MemFree(void* ptr) {
+ scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton();
+ if (host != NULL) {
+ if (ptr != NULL && ptr != (void*)-1) {
+ free(ptr);
+ }
+ }
+}
+
+// Requests that the host free a specified amount of memory.
+uint32 NPN_MemFlush(uint32 size) {
+ // This is not relevant on Windows; MAC specific
+ return size;
+}
+
+// This is for dynamic discovery of new plugins.
+// Should force a re-scan of the plugins directory to load new ones.
+void NPN_ReloadPlugins(NPBool reloadPages) {
+ // TODO: implement me
+}
+
+// Requests a range of bytes for a seekable stream.
+NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList) {
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+}
+
+static bool IsJavaScriptUrl(const std::string& url) {
+ return StartsWithASCII(url, "javascript:", false);
+}
+
+// Generic form of GetURL for common code between
+// GetURL() and GetURLNotify().
+static NPError GetURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ bool notify,
+ void* notify_data) {
+ if (!url)
+ return NPERR_INVALID_URL;
+
+ bool is_javascript_url = IsJavaScriptUrl(url);
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get()) {
+ plugin->webplugin()->HandleURLRequest("GET",
+ is_javascript_url,
+ target,
+ 0,
+ 0,
+ false,
+ notify,
+ url,
+ notify_data,
+ plugin->popups_allowed());
+ } else {
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+ return NPERR_NO_ERROR;
+}
+
+// Requests creation of a new stream with the contents of the
+// specified URL; gets notification of the result.
+NPError NPN_GetURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ void* notify_data) {
+ // This is identical to NPN_GetURL, but after finishing, the
+ // browser will call NPP_URLNotify to inform the plugin that
+ // it has completed.
+
+ // According to the NPAPI documentation, if target == _self
+ // or a parent to _self, the browser should return NPERR_INVALID_PARAM,
+ // because it can't notify the plugin once deleted. This is
+ // absolutely false; firefox doesn't do this, and Flash relies on
+ // being able to use this.
+
+ // Also according to the NPAPI documentation, we should return
+ // NPERR_INVALID_URL if the url requested is not valid. However,
+ // this would require that we synchronously start fetching the
+ // URL. That just isn't practical. As such, there really is
+ // no way to return this error. From looking at the Firefox
+ // implementation, it doesn't look like Firefox does this either.
+
+ return GetURLNotify(id, url, target, true, notify_data);
+}
+
+NPError NPN_GetURL(NPP id, const char* url, const char* target) {
+ // Notes:
+ // Request from the Plugin to fetch content either for the plugin
+ // or to be placed into a browser window.
+ //
+ // If target == null, the browser fetches content and streams to plugin.
+ // otherwise, the browser loads content into an existing browser frame.
+ // If the target is the window/frame containing the plugin, the plugin
+ // may be destroyed.
+ // If the target is _blank, a mailto: or news: url open content in a new
+ // browser window
+ // If the target is _self, no other instance of the plugin is created. The
+ // plugin continues to operate in its own window
+
+ return GetURLNotify(id, url, target, false, 0);
+}
+
+// Generic form of PostURL for common code between
+// PostURL() and PostURLNotify().
+static NPError PostURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ uint32 len,
+ const char* buf,
+ NPBool file,
+ bool notify,
+ void* notify_data) {
+ if (!url)
+ return NPERR_INVALID_URL;
+
+ if (file) {
+ // Unfortunately, our WebKit requests can support files which
+ // contain *only* data. But the files from NPAPI contain
+ // headers + data! So, we need to read the file, extract
+ // the headers, write the data back to a new file, and then
+ // finally we can post the file. TODO: Implement me!
+ // TODO: implement me
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ bool is_javascript_url = IsJavaScriptUrl(url);
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get()) {
+ // The post data sent by a plugin contains both headers
+ // and post data. Example:
+ // Content-type: text/html
+ // Content-length: 200
+ //
+ // <200 bytes of content here>
+ //
+ // Unfortunately, our stream needs these broken apart,
+ // so we need to parse the data and set headers and data
+ // separately.
+ plugin->webplugin()->HandleURLRequest("POST",
+ is_javascript_url,
+ target,
+ len,
+ buf,
+ file ? true : false,
+ notify,
+ url,
+ notify_data,
+ plugin->popups_allowed());
+ return NPERR_NO_ERROR;
+ } else {
+ NOTREACHED();
+ }
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPN_PostURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ uint32 len,
+ const char* buf,
+ NPBool file,
+ void* notify_data) {
+ return PostURLNotify(id, url, target, len, buf, file, true, notify_data);
+}
+
+NPError NPN_PostURL(NPP id,
+ const char* url,
+ const char* target,
+ uint32 len,
+ const char* buf,
+ NPBool file) {
+ // POSTs data to an URL, either from a temp file or a buffer.
+ // If file is true, buf contains a temp file (which host will delete after
+ // completing), and len contains the length of the filename.
+ // If file is false, buf contains the data to send, and len contains the
+ // length of the buffer
+ //
+ // If target is null,
+ // server response is returned to the plugin
+ // If target is _current, _self, or _top,
+ // server response is written to the plugin window and plugin is unloaded.
+ // If target is _new or _blank,
+ // server response is written to a new browser window
+ // If target is an existing frame,
+ // server response goes to that frame.
+ //
+ // For protocols other than FTP
+ // file uploads must be line-end converted from \r\n to \n
+ //
+ // Note: you cannot specify headers (even a blank line) in a memory buffer,
+ // use NPN_PostURLNotify
+
+ return PostURLNotify(id, url, target, len, buf, file, false, 0);
+}
+
+NPError NPN_NewStream(NPP id,
+ NPMIMEType type,
+ const char* target,
+ NPStream** stream) {
+ // Requests creation of a new data stream produced by the plugin,
+ // consumed by the browser.
+ //
+ // Browser should put this stream into a window target.
+ //
+
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+}
+
+int32 NPN_Write(NPP id, NPStream* stream, int32 len, void* buffer) {
+ // Writes data to an existing Plugin-created stream.
+
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPN_DestroyStream(NPP id, NPStream* stream, NPReason reason) {
+ // Destroys a stream (could be created by plugin or browser).
+ //
+ // Reasons:
+ // NPRES_DONE - normal completion
+ // NPRES_USER_BREAK - user terminated
+ // NPRES_NETWORK_ERROR - network error (all errors fit here?)
+ //
+ //
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get() == NULL) {
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ return plugin->NPP_DestroyStream(stream, reason);
+}
+
+const char* NPN_UserAgent(NPP id) {
+ // Flash passes in a null id during the NP_initialize call. We need to
+ // default to the Mozilla user agent if we don't have an NPP instance or
+ // else Flash won't request windowless mode.
+ if (id) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get() && !plugin->use_mozilla_user_agent())
+ return webkit_glue::GetDefaultUserAgent().c_str();
+ }
+
+ static const char *UA = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061103 Firefox/2.0a1";
+ return UA;
+}
+
+void NPN_Status(NPP id, const char* message) {
+ // Displays a message on the status line of the browser window.
+
+ // TODO: implement me
+}
+
+void NPN_InvalidateRect(NPP id, NPRect *invalidRect) {
+ scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton();
+ if (host != NULL) {
+ host->InvalidateRect(id, invalidRect);
+ }
+}
+
+void NPN_InvalidateRegion(NPP id, NPRegion invalidRegion) {
+ // Invalidates a specified drawing region prior to repainting
+ // or refreshing a window-less plugin.
+ //
+ // Similar to NPN_InvalidateRect.
+
+ // TODO: implement me
+}
+
+void NPN_ForceRedraw(NPP id) {
+ // Forces repaint for a windowless plug-in.
+ //
+ // Once a value has been invalidated with NPN_InvalidateRect/
+ // NPN_InvalidateRegion, ForceRedraw can be used to force a paint message.
+ //
+ // The plugin will receive a WM_PAINT message, the lParam of the WM_PAINT
+ // message holds a pointer to an NPRect that is the bounding box of the
+ // update area.
+ // Since the plugin and browser share the same HDC, before drawing, the
+ // plugin is responsible fro saving the current HDC settings, setting up
+ // its own environment, drawing, and restoring the HDC to the previous
+ // settings. The HDC settings must be restored whenever control returns
+ // back to the browser, either before returning from NPP_HandleEvent or
+ // before calling a drawing-related netscape method.
+ //
+
+ // TODO: implement me
+}
+
+NPError NPN_GetValue(NPP id, NPNVariable variable, void *value) {
+ // Allows the plugin to query the browser for information
+ //
+ // Variables:
+ // NPNVxDisplay (unix only)
+ // NPNVxtAppContext (unix only)
+ // NPNVnetscapeWindow (win only) - Gets the native window on which the
+ // plug-in drawing occurs, returns HWND
+ // NPNVjavascriptEnabledBool: tells whether Javascript is enabled
+ // NPNVasdEnabledBool: tells whether SmartUpdate is enabled
+ // NPNVOfflineBool: tells whether offline-mode is enabled
+
+ NPError rv = NPERR_GENERIC_ERROR;
+
+ switch (variable) {
+ case NPNVWindowNPObject:
+ {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ NPObject *np_object = plugin->webplugin()->GetWindowScriptNPObject();
+ // Return value is expected to be retained, as
+ // described here:
+ // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
+ if (np_object) {
+ NPN_RetainObject(np_object);
+ void **v = (void **)value;
+ *v = np_object;
+ rv = NPERR_NO_ERROR;
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
+ case NPNVPluginElementNPObject:
+ {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ NPObject *np_object = plugin->webplugin()->GetPluginElement();
+ // Return value is expected to be retained, as
+ // described here:
+ // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
+ if (np_object) {
+ NPN_RetainObject(np_object);
+ void **v = (void **)value;
+ *v = np_object;
+ rv = NPERR_NO_ERROR;
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
+ case NPNVnetscapeWindow:
+ {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ HWND handle = plugin->window_handle();
+ *((void**)value) = (void*)handle;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case NPNVjavascriptEnabledBool:
+ {
+ // yes, JS is enabled.
+ *((void**)value) = (void*)1;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case NPNVserviceManager:
+ {
+ NPAPI::PluginInstance* instance =
+ NPAPI::PluginInstance::GetInitializingInstance();
+ if (instance) {
+ instance->GetServiceManager(reinterpret_cast<void**>(value));
+ } else {
+ NOTREACHED();
+ }
+
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case default_plugin::kMissingPluginStatusStart +
+ default_plugin::MISSING_PLUGIN_AVAILABLE:
+ // fall through
+ case default_plugin::kMissingPluginStatusStart +
+ default_plugin::MISSING_PLUGIN_USER_STARTED_DOWNLOAD:
+ {
+ // This is a hack for the default plugin to send notification to renderer.
+ // Because we will check if the plugin is default plugin, we don't need
+ // to worry about future standard change that may conflict with the
+ // variable definition.
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin->plugin_lib()->plugin_info().file == kDefaultPluginDllName)
+ plugin->webplugin()->OnMissingPluginStatus(
+ variable - default_plugin::kMissingPluginStatusStart);
+ break;
+ }
+ default:
+ {
+ // TODO: implement me
+ break;
+ }
+ }
+ return rv;
+}
+
+NPError NPN_SetValue(NPP id, NPPVariable variable, void *value) {
+ // Allows the plugin to set various modes
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ switch(variable)
+ {
+ case NPPVpluginWindowBool:
+ {
+ // Sets windowless mode for display of the plugin
+ // Note: the documentation at http://developer.mozilla.org/en/docs/NPN_SetValue
+ // is wrong. When value is NULL, the mode is set to true. This is the same
+ // way Mozilla works.
+ bool mode = (value == 0);
+ plugin->set_windowless(mode);
+ return NPERR_NO_ERROR;
+ }
+ case NPPVpluginTransparentBool:
+ {
+ // Sets transparent mode for display of the plugin
+ //
+ // Transparent plugins require the browser to paint the background
+ // before having the plugin paint. By default, windowless plugins
+ // are transparent. Making a windowless plugin opaque means that
+ // the plugin does not require the browser to paint the background.
+ //
+ bool mode = (value != 0);
+ plugin->set_transparent(mode);
+ return NPERR_NO_ERROR;
+ }
+ case NPPVjavascriptPushCallerBool:
+ // Specifies whether you are pushing or popping the JSContext off
+ // the stack
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+ case NPPVpluginKeepLibraryInMemory:
+ // Tells browser that plugin dll should live longer than usual.
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+ default:
+ // TODO: implement me
+ break;
+ }
+
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+}
+
+void *NPN_GetJavaEnv() {
+ // TODO: implement me
+ return NULL;
+}
+
+void *NPN_GetJavaPeer(NPP) {
+ // TODO: implement me
+ return NULL;
+}
+
+void NPN_PushPopupsEnabledState(NPP id, NPBool enabled) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ plugin->PushPopupsEnabledState(enabled);
+ }
+}
+
+void NPN_PopPopupsEnabledState(NPP id) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ plugin->PopPopupsEnabledState();
+ }
+}
+
+void NPN_PluginThreadAsyncCall(NPP id,
+ void (*func)(void *),
+ void *userData) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ plugin->PluginThreadAsyncCall(func, userData);
+ }
+}
+
+bool NPN_Construct(NPP npp,
+ NPObject* obj,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result) {
+ NOTREACHED();
+ return false;
+}
+
+} // extern "C"
diff --git a/webkit/glue/plugins/plugin_host.h b/webkit/glue/plugins/plugin_host.h
new file mode 100644
index 0000000..61f03c5
--- /dev/null
+++ b/webkit/glue/plugins/plugin_host.h
@@ -0,0 +1,107 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// TODO: Need mechanism to cleanup the static instance
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_HOST_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_HOST_H__
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "base/ref_counted.h"
+#include "base/gfx/rect.h"
+#include "base/task.h"
+#include "webkit/glue/plugins/nphostapi.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+namespace NPAPI
+{
+class PluginInstance;
+
+// The Plugin Host implements the NPN_xxx functions for NPAPI plugins.
+// These are the functions exposed from the Plugin Host for use
+// by the Plugin.
+//
+// The PluginHost is managed as a singleton. This isn't strictly
+// necessary, but since the callback functions are all global C
+// functions, there is really no point in having per-instance PluginHosts.
+class PluginHost : public base::RefCounted<PluginHost> {
+ public:
+ // Access the single PluginHost instance. Callers
+ // must call deref() when finished with the object.
+ static PluginHost *Singleton();
+ virtual ~PluginHost();
+
+ // The table of functions provided to the plugin.
+ NPNetscapeFuncs *host_functions() { return &host_funcs_; }
+
+ // Helper function for parsing post headers, and applying attributes
+ // to the stream. NPAPI post data include headers + data combined.
+ // This function parses it out and adds it to the stream in a WebKit
+ // style.
+ static bool SetPostData(const char *buf,
+ uint32 length,
+ std::vector<std::string>* names,
+ std::vector<std::string>* values,
+ std::vector<char>* body);
+
+ void PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides);
+
+ // Handles invalidateRect requests for windowless plugins.
+ void InvalidateRect(NPP id, NPRect* invalidRect);
+
+ private:
+ PluginHost();
+ void InitializeHostFuncs();
+ // For certain plugins like flash we need to throttle invalidateRect
+ // requests as they are made at a high frequency.
+ void OnInvalidateRect(NPP id, PluginInstance* instance);
+
+ static scoped_refptr<PluginHost> singleton_;
+ NPNetscapeFuncs host_funcs_;
+ DISALLOW_EVIL_CONSTRUCTORS(PluginHost);
+
+ // This structure keeps track of individual plugin instance invalidates.
+ struct ThrottledInvalidates {
+ std::vector<gfx::Rect> throttled_invalidates;
+ };
+
+ // We need to track throttled invalidate rects on a per plugin instance
+ // basis.
+ typedef std::map<NPP, ThrottledInvalidates> InstanceThrottledInvalidatesMap;
+ InstanceThrottledInvalidatesMap instance_throttled_invalidates_;
+
+ ScopedRunnableMethodFactory<PluginHost> throttle_factory_;
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_HOST_H__
diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc
new file mode 100644
index 0000000..62e1357
--- /dev/null
+++ b/webkit/glue/plugins/plugin_instance.cc
@@ -0,0 +1,463 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/plugin_instance.h"
+
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "base/thread_local_storage.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/plugin_data_stream.h"
+#include "webkit/glue/plugins/plugin_host.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "webkit/glue/plugins/plugin_stream_url.h"
+#include "webkit/glue/plugins/plugin_string_stream.h"
+#include "webkit/glue/plugins/mozilla_extensions.h"
+#include "net/base/escape.h"
+
+namespace NPAPI
+{
+int PluginInstance::plugin_instance_tls_index_ = ThreadLocalStorage::Alloc();
+
+PluginInstance::PluginInstance(PluginLib *plugin, const std::string &mime_type)
+ : plugin_(plugin),
+ npp_(0),
+ host_(PluginHost::Singleton()),
+ npp_functions_(plugin->functions()),
+ hwnd_(0),
+ windowless_(false),
+ transparent_(true),
+ mime_type_(mime_type),
+ webplugin_(0),
+ use_mozilla_user_agent_(false),
+ message_loop_(MessageLoop::current()),
+ load_manually_(false),
+ throttle_invalidate_(false),
+ get_notify_data_(NULL),
+ in_close_streams_(false) {
+ npp_ = new NPP_t();
+ npp_->ndata = 0;
+ npp_->pdata = 0;
+
+ memset(&zero_padding_, 0, sizeof(zero_padding_));
+ DCHECK(message_loop_);
+}
+
+PluginInstance::~PluginInstance() {
+ CloseStreams();
+
+ if (npp_ != 0) {
+ delete npp_;
+ npp_ = 0;
+ }
+
+ if (plugin_)
+ plugin_->CloseInstance();
+}
+
+PluginStreamUrl *PluginInstance::CreateStream(int resource_id,
+ const std::string &url,
+ const std::string &mime_type,
+ bool notify_needed,
+ void *notify_data) {
+ PluginStreamUrl *stream = new PluginStreamUrl(
+ resource_id, GURL(url), this, notify_needed, notify_data);
+
+ AddStream(stream);
+ return stream;
+}
+
+void PluginInstance::SendStream(const std::string &url,
+ bool notify_needed,
+ void *notify_data) {
+ if (notify_needed) {
+ host_->host_functions()->geturlnotify(npp(), url.c_str(), NULL,
+ notify_data);
+ } else {
+ host_->host_functions()->geturl(npp(), url.c_str(), NULL);
+ }
+}
+
+void PluginInstance::AddStream(PluginStream* stream) {
+ open_streams_.push_back(stream);
+}
+
+void PluginInstance::RemoveStream(PluginStream* stream) {
+ if (in_close_streams_)
+ return;
+
+ std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
+ for (stream_index = open_streams_.begin();
+ stream_index != open_streams_.end(); ++stream_index) {
+ if (*stream_index == stream) {
+ open_streams_.erase(stream_index);
+ break;
+ }
+ }
+}
+
+bool PluginInstance::IsValidStream(const NPStream* stream) {
+ std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
+ for (stream_index = open_streams_.begin();
+ stream_index != open_streams_.end(); ++stream_index) {
+ if ((*stream_index)->stream() == stream)
+ return true;
+ }
+
+ return false;
+}
+
+void PluginInstance::CloseStreams() {
+ in_close_streams_ = true;
+ for (unsigned int index = 0; index < open_streams_.size(); ++index) {
+ // Close all streams on the way down.
+ open_streams_[index]->Close(NPRES_USER_BREAK);
+ }
+ open_streams_.clear();
+ in_close_streams_ = false;
+}
+
+bool PluginInstance::HandleEvent(UINT message, WPARAM wParam, LPARAM lParam) {
+ if (!windowless_)
+ return false;
+
+ NPEvent windowEvent;
+ windowEvent.event = message;
+ windowEvent.lParam = static_cast<uint32>(lParam);
+ windowEvent.wParam = static_cast<uint32>(wParam);
+ return NPP_HandleEvent(&windowEvent) != 0;
+}
+
+bool PluginInstance::Start(const GURL& url,
+ char** const param_names,
+ char** const param_values,
+ int param_count,
+ bool load_manually) {
+ load_manually_ = load_manually;
+ instance_url_ = url;
+ unsigned short mode = load_manually_ ? NP_FULL : NP_EMBED;
+ npp_->ndata = this;
+
+ NPError err = NPP_New(mode, param_count,
+ const_cast<char **>(param_names), const_cast<char **>(param_values));
+ return err == NPERR_NO_ERROR;
+}
+
+NPObject *PluginInstance::GetPluginScriptableObject() {
+ NPObject *value;
+ NPError error = NPP_GetValue(NPPVpluginScriptableNPObject, &value);
+ if (error != NPERR_NO_ERROR)
+ return NULL;
+ return value;
+}
+
+void PluginInstance::SetURLLoadData(const GURL& url,
+ void* notify_data) {
+ get_url_ = url;
+ get_notify_data_ = notify_data;
+}
+
+// WebPluginLoadDelegate methods
+void PluginInstance::DidFinishLoadWithReason(NPReason reason) {
+ if (!get_url_.is_empty()) {
+ NPP_URLNotify(get_url_.spec().c_str(), reason, get_notify_data_);
+ }
+
+ get_url_ = GURL();
+ get_notify_data_ = NULL;
+}
+
+// NPAPI methods
+NPError PluginInstance::NPP_New(unsigned short mode,
+ short argc,
+ char *argn[],
+ char *argv[]) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->newp != 0);
+ DCHECK(argc >= 0);
+
+ if (npp_functions_->newp != 0) {
+ return npp_functions_->newp(
+ (NPMIMEType)mime_type_.c_str(), npp_, mode, argc, argn, argv, NULL);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+void PluginInstance::NPP_Destroy() {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->newp != 0);
+
+ if (npp_functions_->destroy != 0) {
+ NPSavedData *savedData = 0;
+ npp_functions_->destroy(npp_, &savedData);
+
+ // TODO: Support savedData. Technically, these need to be
+ // saved on a per-URL basis, and then only passed
+ // to new instances of the plugin at the same URL.
+ // Sounds like a huge security risk. When we do support
+ // these, we should pass them back to the PluginLib
+ // to be stored there.
+ DCHECK(savedData == 0);
+ }
+
+ // Clean up back references to this instance if any
+ if (mozilla_extenstions_) {
+ mozilla_extenstions_->DetachFromInstance();
+ mozilla_extenstions_ = NULL;
+ }
+}
+
+NPError PluginInstance::NPP_SetWindow(NPWindow *window) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->setwindow != 0);
+
+ if (npp_functions_->setwindow != 0) {
+ return npp_functions_->setwindow(npp_, window);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+NPError PluginInstance::NPP_NewStream(NPMIMEType type,
+ NPStream *stream,
+ NPBool seekable,
+ unsigned short *stype) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->newstream != 0);
+ if (npp_functions_->newstream != 0) {
+ return npp_functions_->newstream(npp_, type, stream, seekable, stype);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+NPError PluginInstance::NPP_DestroyStream(NPStream *stream, NPReason reason) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->destroystream != 0);
+
+ if (stream == NULL || (stream->ndata == NULL) ||
+ !IsValidStream(stream))
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ if (npp_functions_->destroystream != 0) {
+ NPError result = npp_functions_->destroystream(npp_, stream, reason);
+ stream->ndata = NULL;
+ return result;
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+int PluginInstance::NPP_WriteReady(NPStream *stream) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->writeready != 0);
+ if (npp_functions_->writeready != 0) {
+ return npp_functions_->writeready(npp_, stream);
+ }
+ return NULL;
+}
+
+int PluginInstance::NPP_Write(NPStream *stream,
+ int offset,
+ int len,
+ void *buffer) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->write != 0);
+ if (npp_functions_->write != 0) {
+ return npp_functions_->write(npp_, stream, offset, len, buffer);
+ }
+ return NULL;
+}
+
+void PluginInstance::NPP_StreamAsFile(NPStream *stream, const char *fname) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->asfile != 0);
+ if (npp_functions_->asfile != 0) {
+ npp_functions_->asfile(npp_, stream, fname);
+ }
+}
+
+void PluginInstance::NPP_URLNotify(const char *url,
+ NPReason reason,
+ void *notifyData) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->urlnotify != 0);
+ if (npp_functions_->urlnotify != 0) {
+ npp_functions_->urlnotify(npp_, url, reason, notifyData);
+ }
+}
+
+NPError PluginInstance::NPP_GetValue(NPPVariable variable, void *value) {
+ DCHECK(npp_functions_ != 0);
+ // getvalue is NULL for Shockwave
+ if (npp_functions_->getvalue != 0) {
+ return npp_functions_->getvalue(npp_, variable, value);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+NPError PluginInstance::NPP_SetValue(NPNVariable variable, void *value) {
+ DCHECK(npp_functions_ != 0);
+ if (npp_functions_->setvalue != 0) {
+ return npp_functions_->setvalue(npp_, variable, value);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+short PluginInstance::NPP_HandleEvent(NPEvent *event) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->event != 0);
+ if (npp_functions_->event != 0) {
+ return npp_functions_->event(npp_, (void*)event);
+ }
+ return false;
+}
+
+bool PluginInstance::NPP_Print(NPPrint* platform_print) {
+ DCHECK(npp_functions_ != 0);
+ if (npp_functions_->print != 0) {
+ npp_functions_->print(npp_, platform_print);
+ return true;
+ }
+ return false;
+}
+
+void PluginInstance::SendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success,
+ bool notify_needed,
+ int notify_data) {
+ if (success) {
+ PluginStringStream *stream =
+ new PluginStringStream(this, url, notify_needed,
+ reinterpret_cast<void*>(notify_data));
+ AddStream(stream);
+ stream->SendToPlugin(WideToUTF8(result), "text/html");
+ } else {
+ // NOTE: Sending an empty stream here will crash MacroMedia
+ // Flash 9. Just send the URL Notify.
+ if (notify_needed) {
+ this->NPP_URLNotify(url.c_str(), NPRES_DONE,
+ reinterpret_cast<void*>(notify_data));
+ }
+ }
+}
+
+void PluginInstance::DidReceiveManualResponse(const std::string& url,
+ const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified) {
+ DCHECK(load_manually_);
+ std::string response_url = url;
+ if (response_url.empty()) {
+ response_url = instance_url_.spec();
+ }
+
+ plugin_data_stream_ = new PluginDataStream(this, response_url, mime_type,
+ headers, expected_length,
+ last_modified);
+ AddStream(plugin_data_stream_.get());
+}
+
+void PluginInstance::DidReceiveManualData(const char* buffer, int length) {
+ DCHECK(load_manually_);
+ DCHECK(plugin_data_stream_.get() != NULL);
+ plugin_data_stream_->SendToPlugin(buffer, length);
+}
+
+void PluginInstance::DidFinishManualLoading() {
+ DCHECK(load_manually_);
+ DCHECK(plugin_data_stream_);
+ plugin_data_stream_->Close(NPRES_DONE);
+ RemoveStream(plugin_data_stream_.get());
+ plugin_data_stream_ = NULL;
+}
+
+void PluginInstance::DidManualLoadFail() {
+ DCHECK(load_manually_);
+ DCHECK(plugin_data_stream_);
+ plugin_data_stream_->Close(NPRES_NETWORK_ERR);
+ RemoveStream(plugin_data_stream_.get());
+ plugin_data_stream_ = NULL;
+}
+
+void PluginInstance::PluginThreadAsyncCall(void (*func)(void *),
+ void *userData) {
+ message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &PluginInstance::OnPluginThreadAsyncCall, func, userData));
+}
+
+void PluginInstance::OnPluginThreadAsyncCall(void (*func)(void *),
+ void *userData) {
+ // We are invoking an arbitrary callback provided by a third
+ // party plugin. It's better to wrap this into an exception
+ // block to protect us from crashes.
+ __try {
+ func(userData);
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ // Maybe we can disable a crashing plugin.
+ // But for now, just continue.
+ }
+}
+
+PluginInstance* PluginInstance::SetInitializingInstance(
+ PluginInstance* instance) {
+ PluginInstance* old_instance =
+ static_cast<PluginInstance*>(
+ ThreadLocalStorage::Get(plugin_instance_tls_index_));
+ ThreadLocalStorage::Set(plugin_instance_tls_index_, instance);
+ return old_instance;
+}
+
+PluginInstance* PluginInstance::GetInitializingInstance() {
+ PluginInstance* instance =
+ static_cast<PluginInstance*>(
+ ThreadLocalStorage::Get(plugin_instance_tls_index_));
+ return instance;}
+
+NPError PluginInstance::GetServiceManager(void** service_manager) {
+ if (!mozilla_extenstions_) {
+ mozilla_extenstions_ = new MozillaExtensionApi(this);
+ }
+
+ DCHECK(mozilla_extenstions_);
+ mozilla_extenstions_->QueryInterface(nsIServiceManager::GetIID(),
+ service_manager);
+ return NPERR_NO_ERROR;
+}
+
+void PluginInstance::PushPopupsEnabledState(bool enabled) {
+ popups_enabled_stack_.push(enabled);
+}
+
+void PluginInstance::PopPopupsEnabledState() {
+ popups_enabled_stack_.pop();
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_instance.h b/webkit/glue/plugins/plugin_instance.h
new file mode 100644
index 0000000..5743c24
--- /dev/null
+++ b/webkit/glue/plugins/plugin_instance.h
@@ -0,0 +1,288 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// TODO: Need to deal with NPAPI's NPSavedData.
+// I haven't seen plugins use it yet.
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__
+
+#include <string>
+#include <vector>
+#include <stack>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "webkit/glue/plugins/nphostapi.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+class WebPlugin;
+class MessageLoop;
+
+namespace NPAPI
+{
+class PluginLib;
+class PluginHost;
+class PluginStream;
+class PluginStreamUrl;
+class PluginDataStream;
+class MozillaExtensionApi;
+
+// A PluginInstance is an active, running instance of a Plugin.
+// A single plugin may have many PluginInstances.
+class PluginInstance : public base::RefCounted<PluginInstance> {
+ public:
+ // Create a new instance of a plugin. The PluginInstance
+ // will hold a reference to the plugin.
+ PluginInstance(PluginLib *plugin, const std::string &mime_type);
+ virtual ~PluginInstance();
+
+ // Activates the instance by calling NPP_New.
+ // This should be called after our instance is all
+ // setup from the host side and we are ready to receive
+ // requests from the plugin. We must not call any
+ // functions on the plugin instance until start has
+ // been called.
+ //
+ // url: The instance URL.
+ // param_names: the list of names of attributes passed via the
+ // element.
+ // param_values: the list of values corresponding to param_names
+ // param_count: number of attributes
+ // load_manually: if true indicates that the plugin data would be passed
+ // from webkit. if false indicates that the plugin should
+ // download the data.
+ // This also controls whether the plugin is instantiated as
+ // a full page plugin (NP_FULL) or embedded (NP_EMBED)
+ //
+ bool Start(const GURL& url,
+ char** const param_names,
+ char** const param_values,
+ int param_count,
+ bool load_manually);
+
+ // NPAPI's instance identifier for this instance
+ NPP npp() { return npp_; }
+
+ // Get/Set for the instance's HWND.
+ HWND window_handle() { return hwnd_; }
+ void set_window_handle(HWND value) { hwnd_ = value; }
+
+ // Get/Set whether this instance is in Windowless mode.
+ // Default is false.
+ bool windowless() { return windowless_; }
+ void set_windowless(bool value) { windowless_ = value; }
+
+ // Get/Set whether this instance is transparent.
+ // This only applies to windowless plugins. Transparent
+ // plugins require that webkit paint the background.
+ // Default is true.
+ bool transparent() { return transparent_; }
+ void set_transparent(bool value) { transparent_ = value; }
+
+ // Get/Set the WebPlugin associated with this instance
+ WebPlugin* webplugin() { return webplugin_; }
+ void set_web_plugin(WebPlugin* webplugin) { webplugin_ = webplugin; }
+
+ // Get the mimeType for this plugin stream
+ const std::string &mime_type() { return mime_type_; }
+
+ NPAPI::PluginLib* plugin_lib() { return plugin_; }
+
+ // Handles a windows native message which this PluginInstance should deal
+ // with. Returns true if the event is handled, false otherwise.
+ bool HandleEvent(UINT message, WPARAM wParam, LPARAM lParam);
+
+ // Creates a stream for sending an URL. If notify_needed
+ // is true, it will send a notification to the plugin
+ // when the stream is complete; otherwise it will not.
+ // Set object_url to true if the load is for the object tag's
+ // url, or false if it's for a url that the plugin
+ // fetched through NPN_GetUrl[Notify].
+ PluginStreamUrl *CreateStream(int resource_id,
+ const std::string &url,
+ const std::string &mime_type,
+ bool notify_needed,
+ void *notify_data);
+
+ // Convenience function for sending a stream from a URL to this instance.
+ // URL can be a relative or a fully qualified url.
+ void SendStream(const std::string& url, bool notify_needed,
+ void* notify_data);
+ // For each instance, we track all streams. When the
+ // instance closes, all remaining streams are also
+ // closed. All streams associated with this instance
+ // should call AddStream so that they can be cleaned
+ // up when the instance shuts down.
+ void AddStream(PluginStream* stream);
+
+ // This is called when a stream is closed. We remove the stream from the
+ // list, which releases the reference maintained to the stream.
+ void RemoveStream(PluginStream* stream);
+
+ // Closes all open streams on this instance.
+ void CloseStreams();
+
+ // Have the plugin create it's script object.
+ NPObject *GetPluginScriptableObject();
+
+ // WebViewDelegate methods that we implement. This is for handling
+ // callbacks during getURLNotify.
+ virtual void DidFinishLoadWithReason(NPReason reason);
+
+ // Helper method to set some persistent data for getURLNotify since
+ // resource fetches happen async.
+ void SetURLLoadData(const GURL& url, void* notify_data);
+
+ // If true, send the Mozilla user agent instead of Chrome's to the plugin.
+ bool use_mozilla_user_agent() { return use_mozilla_user_agent_; }
+ void set_use_mozilla_user_agent() { use_mozilla_user_agent_ = true; }
+
+ bool throttle_invalidate() const { return throttle_invalidate_; }
+ void set_throttle_invalidate(bool throttle_invalidate) {
+ throttle_invalidate_ = throttle_invalidate;
+ }
+
+ // Helper that implements NPN_PluginThreadAsyncCall semantics
+ void PluginThreadAsyncCall(void (*func)(void *),
+ void *userData);
+
+ //
+ // NPAPI methods for calling the Plugin Instance
+ //
+ NPError NPP_New(unsigned short, short, char *[], char *[]);
+ NPError NPP_SetWindow(NPWindow *);
+ NPError NPP_NewStream(NPMIMEType, NPStream *, NPBool, unsigned short *);
+ NPError NPP_DestroyStream(NPStream *, NPReason);
+ int NPP_WriteReady(NPStream *);
+ int NPP_Write(NPStream *, int, int, void *);
+ void NPP_StreamAsFile(NPStream *, const char *);
+ void NPP_URLNotify(const char *, NPReason, void *);
+ NPError NPP_GetValue(NPPVariable, void *);
+ NPError NPP_SetValue(NPNVariable, void *);
+ short NPP_HandleEvent(NPEvent *);
+ void NPP_Destroy();
+ bool NPP_Print(NPPrint* platform_print);
+
+ void SendJavaScriptStream(const std::string& url, const std::wstring& result,
+ bool success, bool notify_needed, int notify_data);
+
+ void DidReceiveManualResponse(const std::string& url,
+ const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified);
+ void DidReceiveManualData(const char* buffer, int length);
+ void DidFinishManualLoading();
+ void DidManualLoadFail();
+
+ NPError GetServiceManager(void** service_manager);
+
+ static PluginInstance* SetInitializingInstance(PluginInstance* instance);
+ static PluginInstance* GetInitializingInstance();
+
+ void PushPopupsEnabledState(bool enabled);
+ void PopPopupsEnabledState();
+
+ bool popups_allowed() const {
+ return popups_enabled_stack_.empty() ? false : popups_enabled_stack_.top();
+ }
+
+ private:
+ void OnPluginThreadAsyncCall(void (*func)(void *),
+ void *userData);
+ bool IsValidStream(const NPStream* stream);
+
+ // This is a hack to get the real player plugin to work with chrome
+ // The real player plugin dll(nppl3260) when loaded by firefox is loaded via
+ // the NS COM API which is analogous to win32 COM. So the NPAPI functions in
+ // the plugin are invoked via an interface by firefox. The plugin instance
+ // handle which is passed to every NPAPI method is owned by the real player
+ // plugin, i.e. it expects the ndata member to point to a structure which
+ // it knows about. Eventually it dereferences this structure and compares
+ // a member variable at offset 0x24(Version 6.0.11.2888) /2D (Version
+ // 6.0.11.3088) with 0 and on failing this check, takes a different code
+ // path which causes a crash. Safari and Opera work with version 6.0.11.2888
+ // by chance as their ndata structure contains a 0 at the location which real
+ // player checks:(. They crash with version 6.0.11.3088 as well. The
+ // following member just adds a 96 byte padding to our PluginInstance class
+ // which is passed in the ndata member. This magic number works correctly on
+ // Vista with UAC on or off :(.
+ // NOTE: Please dont change the ordering of the member variables
+ // New members should be added after this padding array.
+ // TODO(iyengar) : Disassemble the Realplayer ndata structure and look into
+ // the possiblity of conforming to it (http://b/issue?id=936667). We
+ // could also log a bug with Real, which would save the effort.
+ uint8 zero_padding_[96];
+ scoped_refptr<NPAPI::PluginLib> plugin_;
+ NPP npp_;
+ scoped_refptr<PluginHost> host_;
+ NPPluginFuncs* npp_functions_;
+ std::vector<scoped_refptr<PluginStream> > open_streams_;
+ HWND hwnd_;
+ bool windowless_;
+ bool transparent_;
+ WebPlugin* webplugin_;
+ std::string mime_type_;
+ GURL get_url_;
+ void* get_notify_data_;
+ bool use_mozilla_user_agent_;
+ scoped_refptr<MozillaExtensionApi> mozilla_extenstions_;
+ MessageLoop* message_loop_;
+ // Using TLS to store PluginInstance object during its creation.
+ // We need to pass this instance to the service manager
+ // (MozillaExtensionApi) created as a result of NPN_GetValue
+ // in the context of NP_Initialize.
+ static int plugin_instance_tls_index_;
+ scoped_refptr<PluginDataStream> plugin_data_stream_;
+ GURL instance_url_;
+
+ // This flag if true indicates that the plugin data would be passed from
+ // webkit. if false indicates that the plugin should download the data.
+ bool load_manually_;
+
+ // This flag indicates if the NPN_InvalidateRect calls made by the
+ // plugin need to be throttled.
+ bool throttle_invalidate_;
+
+ // Stack indicating if popups are to be enabled for the outgoing
+ // NPN_GetURL/NPN_GetURLNotify calls.
+ std::stack<bool> popups_enabled_stack_;
+
+ // True if in CloseStreams().
+ bool in_close_streams_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginInstance);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__ \ No newline at end of file
diff --git a/webkit/glue/plugins/plugin_lib.cc b/webkit/glue/plugins/plugin_lib.cc
new file mode 100644
index 0000000..bf36152
--- /dev/null
+++ b/webkit/glue/plugins/plugin_lib.cc
@@ -0,0 +1,433 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+
+#include "webkit/glue/plugins/plugin_lib.h"
+
+#include "base/file_util.h"
+#include "base/file_version_info.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/stats_counters.h"
+#include "base/string_util.h"
+#include "base/task.h"
+#include "webkit/activex_shim/npp_impl.h"
+#include "webkit/default_plugin/plugin_main.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/plugins/plugin_host.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "net/base/mime_util.h"
+
+
+namespace NPAPI
+{
+
+const wchar_t kPluginLibrariesLoadedCounter[] = L"PluginLibrariesLoaded";
+const wchar_t kPluginInstancesActiveCounter[] = L"PluginInstancesActive";
+
+PluginLib::PluginMap* PluginLib::loaded_libs_;
+
+PluginLib* PluginLib::CreatePluginLib(const std::wstring& filename) {
+ // We can only have one PluginLib object per plugin as it controls the per
+ // instance function calls (i.e. NP_Initialize and NP_Shutdown). So we keep
+ // a (non-ref counted) map of PluginLib objects.
+ if (!loaded_libs_)
+ loaded_libs_ = new PluginMap();
+
+ PluginMap::const_iterator iter = loaded_libs_->find(filename);
+ if (iter != loaded_libs_->end())
+ return iter->second;
+
+ static const InternalPluginInfo activex_shim_info = {
+ {kActiveXShimFileName,
+ L"ActiveX Plug-in",
+ L"ActiveX Plug-in provides a shim to support ActiveX controls",
+ L"1, 0, 0, 1",
+ L"application/x-oleobject|application/oleobject|"
+ L"application/x-ms-wmp|application/asx|video/x-ms-asf-plugin|"
+ L"application/x-mplayer2|video/x-ms-asf|video/x-ms-wm|audio/x-ms-wma|"
+ L"audio/x-ms-wax|video/x-ms-wmv|video/x-ms-wvx",
+ L"*|*|*|*|*|*|asf,asx,*|wm,*|wma,*|wax,*|wmv,*|wvx,*",
+ L""
+ },
+ activex_shim::ActiveX_Shim_NP_GetEntryPoints,
+ activex_shim::ActiveX_Shim_NP_Initialize,
+ activex_shim::ActiveX_Shim_NP_Shutdown
+ };
+
+ static const InternalPluginInfo default_null_plugin_info = {
+ {kDefaultPluginDllName,
+ L"Default Plug-in",
+ L"Provides functionality for installing third-party plug-ins",
+ L"1, 0, 0, 1",
+ L"*",
+ L"",
+ L""
+ },
+ default_plugin::NP_GetEntryPoints,
+ default_plugin::NP_Initialize,
+ default_plugin::NP_Shutdown
+ };
+
+ WebPluginInfo* info = NULL;
+ const InternalPluginInfo* internal_plugin_info = NULL;
+ if (filename == activex_shim_info.version_info.file_name) {
+ info = CreateWebPluginInfo(activex_shim_info.version_info);
+ internal_plugin_info = &activex_shim_info;
+ } else if (filename == default_null_plugin_info.version_info.file_name) {
+ info = CreateWebPluginInfo(default_null_plugin_info.version_info);
+ internal_plugin_info = &default_null_plugin_info;
+ } else {
+ info = ReadWebPluginInfo(filename);
+ if (!info) {
+ DLOG(INFO) << "This file isn't a valid NPAPI plugin: " << filename;
+ return NULL;
+ }
+ }
+
+ return new PluginLib(info, internal_plugin_info);
+}
+
+void PluginLib::UnloadAllPlugins() {
+ if (loaded_libs_) {
+ PluginMap::iterator lib_index;
+ for (lib_index = loaded_libs_->begin(); lib_index != loaded_libs_->end();
+ ++lib_index) {
+ lib_index->second->Unload();
+ }
+ delete loaded_libs_;
+ loaded_libs_ = NULL;
+ }
+}
+
+void PluginLib::ShutdownAllPlugins() {
+ if (loaded_libs_) {
+ PluginMap::iterator lib_index;
+ for (lib_index = loaded_libs_->begin(); lib_index != loaded_libs_->end();
+ ++lib_index) {
+ lib_index->second->Shutdown();
+ }
+ }
+}
+
+PluginLib::PluginLib(WebPluginInfo* info,
+ const InternalPluginInfo* internal_plugin_info)
+ : web_plugin_info_(info),
+ module_(0),
+ initialized_(false),
+ saved_data_(0),
+ instance_count_(0) {
+ StatsCounter(kPluginLibrariesLoadedCounter).Increment();
+ memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_));
+
+ (*loaded_libs_)[info->file] = this;
+ if (internal_plugin_info) {
+ internal_ = true;
+ NP_Initialize_ = internal_plugin_info->np_initialize;
+ NP_GetEntryPoints_ = internal_plugin_info->np_getentrypoints;
+ NP_Shutdown_ = internal_plugin_info->np_shutdown;
+ } else {
+ internal_ = false;
+ }
+}
+
+PluginLib::~PluginLib() {
+ StatsCounter(kPluginLibrariesLoadedCounter).Decrement();
+ if (saved_data_ != 0) {
+ // TODO - delete the savedData object here
+ }
+}
+
+NPPluginFuncs *PluginLib::functions() {
+ return &plugin_funcs_;
+}
+
+bool PluginLib::SupportsType(const std::string &mime_type,
+ bool allow_wildcard) {
+ // Webkit will ask for a plugin to handle empty mime types.
+ if (mime_type.empty())
+ return false;
+
+ for (size_t i = 0; i < web_plugin_info_->mime_types.size(); ++i) {
+ const WebPluginMimeType& mime_info = web_plugin_info_->mime_types[i];
+ if (mime_util::MatchesMimeType(mime_info.mime_type, mime_type)) {
+ if (!allow_wildcard && (mime_info.mime_type == "*")) {
+ continue;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+NPError PluginLib::NP_Initialize() {
+ if (initialized_)
+ return NPERR_NO_ERROR;
+
+ if (!Load())
+ return NPERR_MODULE_LOAD_FAILED_ERROR;
+
+ PluginHost *host = PluginHost::Singleton();
+ if (host == 0)
+ return NPERR_GENERIC_ERROR;
+
+ NPError rv = NP_Initialize_(host->host_functions());
+ initialized_ = (rv == NPERR_NO_ERROR);
+ return rv;
+}
+
+void PluginLib::NP_Shutdown(void) {
+ DCHECK(initialized_);
+ NP_Shutdown_();
+}
+
+PluginInstance *PluginLib::CreateInstance(const std::string &mime_type) {
+ PluginInstance *new_instance = new PluginInstance(this, mime_type);
+ instance_count_++;
+ StatsCounter(kPluginInstancesActiveCounter).Increment();
+ DCHECK(new_instance != 0);
+ return new_instance;
+}
+
+void PluginLib::CloseInstance() {
+ StatsCounter(kPluginInstancesActiveCounter).Decrement();
+ instance_count_--;
+ // If a plugin is running in its own process it will get unloaded on process
+ // shutdown.
+ if ((instance_count_ == 0) &&
+ webkit_glue::IsPluginRunningInRendererProcess()) {
+ Unload();
+ loaded_libs_->erase(web_plugin_info_->file);
+ if (loaded_libs_->empty()) {
+ delete loaded_libs_;
+ loaded_libs_ = NULL;
+ }
+ }
+}
+
+bool PluginLib::Load() {
+ bool rv = false;
+ HMODULE module = 0;
+
+ if (!internal_) {
+ if (module_ != 0)
+ return rv;
+
+ module = LoadPluginHelper(web_plugin_info_->file);
+ if (module == 0)
+ return rv;
+
+ rv = true; // assume success now
+
+ NP_Initialize_ = (NP_InitializeFunc)GetProcAddress(
+ module, "NP_Initialize");
+ if (NP_Initialize_ == 0)
+ rv = false;
+
+ NP_GetEntryPoints_ = (NP_GetEntryPointsFunc)GetProcAddress(
+ module, "NP_GetEntryPoints");
+ if (NP_GetEntryPoints_ == 0)
+ rv = false;
+
+ NP_Shutdown_ = (NP_ShutdownFunc)GetProcAddress(
+ module, "NP_Shutdown");
+ if (NP_Shutdown_ == 0)
+ rv = false;
+ } else {
+ rv = true;
+ }
+
+ if (rv) {
+ plugin_funcs_.size = sizeof(plugin_funcs_);
+ plugin_funcs_.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+ if (NP_GetEntryPoints_(&plugin_funcs_) != NPERR_NO_ERROR)
+ rv = false;
+ }
+
+ if (!internal_) {
+ if (rv)
+ module_ = module;
+ else
+ FreeLibrary(module);
+ }
+
+ return rv;
+}
+
+HMODULE PluginLib::LoadPluginHelper(const std::wstring plugin_file) {
+ // Switch the current directory to the plugin directory as the plugin
+ // may have dependencies on dlls in this directory.
+ bool restore_directory = false;
+ std::wstring current_directory;
+ if (PathService::Get(base::DIR_CURRENT, &current_directory)) {
+ std::wstring plugin_path = file_util::GetDirectoryFromPath(
+ plugin_file);
+ if (!plugin_path.empty()) {
+ PathService::SetCurrentDirectory(plugin_path);
+ restore_directory = true;
+ }
+ }
+
+ HMODULE module = LoadLibrary(plugin_file.c_str());
+ if (restore_directory)
+ PathService::SetCurrentDirectory(current_directory);
+
+ return module;
+}
+
+// This class implements delayed NP_Shutdown and FreeLibrary on the plugin dll.
+class FreePluginLibraryTask : public Task {
+ public:
+ FreePluginLibraryTask(HMODULE module, NP_ShutdownFunc shutdown_func)
+ : module_(module),
+ NP_Shutdown_(shutdown_func) {
+ }
+
+ ~FreePluginLibraryTask() {}
+
+ void Run() {
+ if (NP_Shutdown_)
+ NP_Shutdown_();
+
+ if (module_) {
+ FreeLibrary(module_);
+ module_ = NULL;
+ }
+ }
+
+ private:
+ HMODULE module_;
+ NP_ShutdownFunc NP_Shutdown_;
+ DISALLOW_EVIL_CONSTRUCTORS(FreePluginLibraryTask);
+};
+
+void PluginLib::Unload() {
+ if (!internal_ && module_) {
+ // In case of single process mode, a plugin can delete itself
+ // by executing a script. So delay the unloading of the DLL
+ // so that the plugin will have a chance to unwind.
+ bool defer_unload = webkit_glue::IsPluginRunningInRendererProcess();
+
+#if USE(JAVASCRIPTCORE_BINDINGS)
+ // The plugin NPAPI instances may still be around. Delay the
+ // NP_Shutdown and FreeLibrary calls at least till the next
+ // peek message.
+ defer_unload = true;
+#endif
+
+ if (defer_unload) {
+ FreePluginLibraryTask* free_library_task =
+ new FreePluginLibraryTask(module_, NP_Shutdown_);
+ MessageLoop::current()->PostTask(FROM_HERE, free_library_task);
+ } else {
+ Shutdown();
+ FreeLibrary(module_);
+ }
+
+ module_ = 0;
+ }
+}
+
+void PluginLib::Shutdown() {
+ if (initialized_ && !internal_) {
+ NP_Shutdown();
+ initialized_ = false;
+ }
+}
+
+WebPluginInfo* PluginLib::CreateWebPluginInfo(const PluginVersionInfo& pvi) {
+ std::vector<std::string> mime_types, file_extensions;
+ std::vector<std::wstring> descriptions;
+ SplitString(WideToNativeMB(pvi.mime_types), '|', &mime_types);
+ SplitString(WideToNativeMB(pvi.file_extents), '|', &file_extensions);
+ SplitString(pvi.file_open_names, '|', &descriptions);
+
+ if (mime_types.empty())
+ return NULL;
+
+ WebPluginInfo *info = new WebPluginInfo();
+ info->name = pvi.product_name;
+ info->desc = pvi.file_description;
+ info->version = pvi.file_version;
+ info->file = StringToLowerASCII(pvi.file_name);
+
+ for (size_t i = 0; i < mime_types.size(); ++i) {
+ WebPluginMimeType mime_type;
+ mime_type.mime_type = StringToLowerASCII(mime_types[i]);
+ if (file_extensions.size() > i)
+ SplitString(file_extensions[i], ',', &mime_type.file_extensions);
+
+ if (descriptions.size() > i) {
+ mime_type.description = descriptions[i];
+
+ // Remove the extension list from the description.
+ size_t ext = mime_type.description.find(L"(*");
+ if (ext != std::wstring::npos) {
+ if (ext > 1 && mime_type.description[ext -1] == ' ')
+ ext--;
+
+ mime_type.description.erase(ext);
+ }
+ }
+
+ info->mime_types.push_back(mime_type);
+ }
+
+ return info;
+}
+
+WebPluginInfo* PluginLib::ReadWebPluginInfo(const std::wstring &filename) {
+ // On windows, the way we get the mime types for the library is
+ // to check the version information in the DLL itself. This
+ // will be a string of the format: <type1>|<type2>|<type3>|...
+ // For example:
+ // video/quicktime|audio/aiff|image/jpeg
+ scoped_ptr<FileVersionInfo> version_info(
+ FileVersionInfo::CreateFileVersionInfo(filename));
+ if (!version_info.get())
+ return NULL;
+
+ PluginVersionInfo pvi;
+ version_info->GetValue(L"MIMEType", &pvi.mime_types);
+ version_info->GetValue(L"FileExtents", &pvi.file_extents);
+ version_info->GetValue(L"FileOpenName", &pvi.file_open_names);
+ pvi.product_name = version_info->product_name();
+ pvi.file_description = version_info->file_description();
+ pvi.file_version = version_info->file_version();
+ pvi.file_name = filename;
+
+ return CreateWebPluginInfo(pvi);
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_lib.h b/webkit/glue/plugins/plugin_lib.h
new file mode 100644
index 0000000..798b2ea
--- /dev/null
+++ b/webkit/glue/plugins/plugin_lib.h
@@ -0,0 +1,163 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_LIB_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_LIB_H__
+
+#include <hash_map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "webkit/glue/plugins/nphostapi.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+struct WebPluginInfo;
+
+namespace NPAPI
+{
+
+class PluginInstance;
+
+// This struct fully describes a plugin. For dll plugins, it's read in from
+// the version info of the dll; For internal plugins, it's predefined.
+struct PluginVersionInfo {
+ std::wstring file_name;
+ std::wstring product_name;
+ std::wstring file_description;
+ std::wstring file_version;
+ std::wstring mime_types;
+ std::wstring file_extents;
+ std::wstring file_open_names;
+};
+
+// This struct contains information of an internal plugin and addresses of
+// entry functions.
+struct InternalPluginInfo {
+ PluginVersionInfo version_info;
+ NP_GetEntryPointsFunc np_getentrypoints;
+ NP_InitializeFunc np_initialize;
+ NP_ShutdownFunc np_shutdown;
+};
+
+// A PluginLib is a single NPAPI Plugin Library, and is the lifecycle
+// manager for new PluginInstances.
+class PluginLib : public base::RefCounted<PluginLib> {
+ public:
+ virtual ~PluginLib();
+ static PluginLib* CreatePluginLib(const std::wstring& filename);
+
+ // Unloads all the loaded plugin dlls and cleans up the plugin map.
+ static void UnloadAllPlugins();
+
+ // Shuts down all loaded plugin instances.
+ static void ShutdownAllPlugins();
+
+ // Get the Plugin's function pointer table.
+ NPPluginFuncs *functions();
+
+ // Returns true if this Plugin supports a given mime-type.
+ // mime_type should be all lower case.
+ bool SupportsType(const std::string &mime_type, bool allow_wildcard);
+
+ // Creates a new instance of this plugin.
+ PluginInstance *CreateInstance(const std::string &mime_type);
+
+ // Called by the instance when the instance is tearing down.
+ void CloseInstance();
+
+ // Gets information about this plugin and the mime types that it
+ // supports.
+ const WebPluginInfo& plugin_info() { return *web_plugin_info_; }
+
+ //
+ // NPAPI functions
+ //
+
+ // NPAPI method to initialize a Plugin.
+ // Initialize can be safely called multiple times
+ NPError NP_Initialize();
+
+ // NPAPI method to shutdown a Plugin.
+ void NP_Shutdown(void);
+
+ // Helper function to load a plugin.
+ // Returns the module handle on success.
+ static HMODULE LoadPluginHelper(const std::wstring plugin_file);
+
+ int instance_count() const { return instance_count_; }
+
+ private:
+ // Creates a new PluginLib. The WebPluginInfo object is owned by this
+ // object. If internal_plugin_info is not NULL, this Lib is an internal
+ // plugin thus doesn't need to load dll.
+ PluginLib(WebPluginInfo* info,
+ const InternalPluginInfo* internal_plugin_info);
+
+ // Attempts to load the plugin from the DLL.
+ // Returns true if it is a legitimate plugin, false otherwise
+ bool Load();
+
+ // Unloading the plugin DLL.
+ void Unload();
+
+ // Shutdown the plugin DLL.
+ void Shutdown();
+
+ // Returns a WebPluginInfo structure given a plugin's path. Returns NULL if
+ // the dll couldn't be found, or if it's not a plugin.
+ static WebPluginInfo* ReadWebPluginInfo(const std::wstring &filename);
+ // Creates WebPluginInfo structure based on read in or built in
+ // PluginVersionInfo.
+ static WebPluginInfo* CreateWebPluginInfo(const PluginVersionInfo& info);
+
+ bool internal_; // Whether this an internal plugin.
+ scoped_ptr<WebPluginInfo> web_plugin_info_; // supported mime types, description
+ HMODULE module_; // the opened DLL handle
+ NPPluginFuncs plugin_funcs_; // the struct of plugin side functions
+ bool initialized_; // is the plugin initialized
+ NPSavedData *saved_data_; // persisted plugin info for NPAPI
+ int instance_count_; // count of plugins in use
+
+ // A map of all the insantiated plugins.
+ typedef stdext::hash_map<std::wstring, scoped_refptr<PluginLib> > PluginMap;
+ static PluginMap* loaded_libs_;
+
+ // C-style function pointers
+ NP_InitializeFunc NP_Initialize_;
+ NP_GetEntryPointsFunc NP_GetEntryPoints_;
+ NP_ShutdownFunc NP_Shutdown_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginLib);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_LIB_H__
diff --git a/webkit/glue/plugins/plugin_list.cc b/webkit/glue/plugins/plugin_list.cc
new file mode 100644
index 0000000..8c8deef
--- /dev/null
+++ b/webkit/glue/plugins/plugin_list.cc
@@ -0,0 +1,500 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <algorithm>
+#include <tchar.h>
+
+#include "webkit/glue/plugins/plugin_list.h"
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/registry.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "webkit/activex_shim/activex_shared.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "googleurl/src/gurl.h"
+
+namespace NPAPI
+{
+
+scoped_refptr<PluginList> PluginList::singleton_;
+
+static const TCHAR kRegistryApps[] =
+ _T("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths");
+static const TCHAR kRegistryFirefox[] = _T("firefox.exe");
+static const TCHAR kRegistryAcrobat[] = _T("AcroRd32.exe");
+static const TCHAR kRegistryWindowsMedia[] = _T("wmplayer.exe");
+static const TCHAR kRegistryQuickTime[] = _T("QuickTimePlayer.exe");
+static const TCHAR kRegistryPath[] = _T("Path");
+static const TCHAR kRegistryMozillaPlugins[] = _T("SOFTWARE\\MozillaPlugins");
+static const TCHAR kRegistryFirefoxInstalled[] =
+ _T("SOFTWARE\\Mozilla\\Mozilla Firefox");
+static const TCHAR kMozillaActiveXPlugin[] = _T("npmozax.dll");
+static const TCHAR kNewWMPPlugin[] = _T("np-mswmp.dll");
+static const TCHAR kOldWMPPlugin[] = _T("npdsplay.dll");
+static const TCHAR kRegistryJava[] =
+ _T("Software\\JavaSoft\\Java Runtime Environment");
+static const TCHAR kRegistryBrowserJavaVersion[] = _T("BrowserJavaVersion");
+static const TCHAR kRegistryCurrentJavaVersion[] = _T("CurrentVersion");
+static const TCHAR kRegistryJavaHome[] = _T("JavaHome");
+
+// Extra registry paths to search.
+static std::vector<std::wstring>* extra_plugin_paths_ = NULL;
+
+PluginList* PluginList::Singleton() {
+ if (singleton_.get() == NULL) {
+ singleton_ = new PluginList();
+ singleton_->LoadPlugins(false);
+ }
+
+ return singleton_;
+}
+
+void PluginList::AddExtraPluginPath(const std::wstring& plugin_path) {
+ DCHECK(!singleton_.get() || !singleton_->plugins_loaded_);
+
+ if (!extra_plugin_paths_)
+ extra_plugin_paths_ = new std::vector<std::wstring>;
+ extra_plugin_paths_->push_back(plugin_path);
+}
+
+PluginList::PluginList() :
+ plugins_loaded_(false) {
+ CommandLine command_line;
+ dont_load_new_wmp_ = command_line.HasSwitch(kUseOldWMPPluginSwitch);
+ use_internal_activex_shim_ =
+ !command_line.HasSwitch(kNoNativeActiveXShimSwitch);
+}
+
+PluginList::~PluginList() {
+ plugins_.clear();
+}
+
+void PluginList::LoadPlugins(bool refresh) {
+ if (plugins_loaded_ && !refresh)
+ return;
+
+ plugins_.clear();
+ plugins_loaded_ = true;
+
+ TimeTicks start_time = TimeTicks::Now();
+
+ LoadInternalPlugins();
+
+ // Load any plugins listed in the registry
+ if (extra_plugin_paths_) {
+ for (size_t i = 0; i < extra_plugin_paths_->size(); ++i) {
+ LoadPlugin((*extra_plugin_paths_)[i]);
+ }
+ }
+
+ // Load from the application-specific area
+ LoadPlugins(GetPluginAppDirectory());
+
+ // Load from the executable area
+ LoadPlugins(GetPluginExeDirectory());
+
+ // Load Java
+ LoadJavaPlugin();
+
+ // Load firefox plugins too. This is mainly to try to locate
+ // a pre-installed Flash player.
+ LoadFirefoxPlugins();
+
+ // Firefox hard-codes the paths of some popular plugins to ensure that
+ // the plugins are found. We are going to copy this as well.
+ LoadAcrobatPlugins();
+ LoadQuicktimePlugins();
+ LoadWindowsMediaPlugins();
+
+ if (webkit_glue::IsDefaultPluginEnabled()) {
+ scoped_refptr<PluginLib> default_plugin = PluginLib::CreatePluginLib(
+ kDefaultPluginDllName);
+ plugins_.push_back(default_plugin);
+ }
+
+ TimeTicks end_time = TimeTicks::Now();
+ TimeDelta elapsed = end_time - start_time;
+ DLOG(INFO) << "Loaded plugin list in " << elapsed.InMilliseconds() << " ms.";
+}
+
+void PluginList::LoadPlugins(const std::wstring &path) {
+ WIN32_FIND_DATA find_file_data;
+ HANDLE find_handle;
+
+ std::wstring dir = path;
+ // FindFirstFile requires that you specify a wildcard for directories.
+ dir.append(L"\\NP*.DLL");
+
+ find_handle = FindFirstFile(dir.c_str(), &find_file_data);
+ if (find_handle == INVALID_HANDLE_VALUE)
+ return;
+
+ do {
+ if (!(find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ std::wstring filename = path;
+ filename.append(L"\\");
+ filename.append(find_file_data.cFileName);
+
+ LoadPlugin(filename);
+ }
+ } while (FindNextFile(find_handle, &find_file_data) != 0);
+
+ DCHECK(GetLastError() == ERROR_NO_MORE_FILES);
+ FindClose(find_handle);
+}
+
+void PluginList::LoadPlugin(const std::wstring &path) {
+ std::wstring path_lc = StringToLowerASCII(path);
+ if (!ShouldLoadPlugin(file_util::GetFilenameFromPath(path_lc)))
+ return;
+
+ scoped_refptr<PluginLib> new_plugin = PluginLib::CreatePluginLib(path_lc);
+ if (!new_plugin.get())
+ return;
+
+ const WebPluginInfo& plugin_info = new_plugin->plugin_info();
+ for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) {
+ // TODO: don't load global handlers for now.
+ // WebKit hands to the Plugin before it tries
+ // to handle mimeTypes on its own.
+ const std::string &mime_type = plugin_info.mime_types[i].mime_type;
+ if (mime_type == "*" ) {
+#ifndef NDEBUG
+ // Make an exception for NPSPY.
+ if (plugin_info.file.find(L"npspy.dll") != std::wstring::npos) {
+ // Put it at the beginning so it's used before the real plugin.
+ plugins_.insert(plugins_.begin(), new_plugin.get());
+ }
+#endif
+ continue;
+ }
+
+ if (!SupportsType(mime_type))
+ plugins_.push_back(new_plugin);
+ }
+}
+
+bool PluginList::ShouldLoadPlugin(const std::wstring& filename) {
+ // Depends on XPCOM.
+ if (filename == kMozillaActiveXPlugin)
+ return false;
+
+ // We will use activex shim to handle embeded wmp media.
+ if (use_internal_activex_shim_) {
+ if (filename == kNewWMPPlugin || filename == kOldWMPPlugin)
+ return false;
+ } else {
+ // If both the new and old WMP plugins exist, only load the new one.
+ if (filename == kNewWMPPlugin) {
+ if (dont_load_new_wmp_)
+ return false;
+
+ int old_plugin = FindPluginFile(kOldWMPPlugin);
+ if (old_plugin != -1)
+ plugins_.erase(plugins_.begin() + old_plugin);
+ } else if (filename == kOldWMPPlugin) {
+ if (FindPluginFile(kNewWMPPlugin) != -1)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void PluginList::LoadInternalPlugins() {
+ if (use_internal_activex_shim_) {
+ scoped_refptr<PluginLib> new_plugin = PluginLib::CreatePluginLib(
+ kActiveXShimFileName);
+ plugins_.push_back(new_plugin);
+ }
+}
+
+int PluginList::FindPluginFile(const std::wstring& filename) {
+ for (size_t i = 0; i < plugins_.size(); ++i) {
+ if (file_util::GetFilenameFromPath(plugins_[i]->plugin_info().file) ==
+ filename) {
+ return static_cast<int>(i);
+ }
+ }
+
+ return -1;
+}
+
+PluginLib* PluginList::FindPlugin(const std::string& mime_type,
+ const std::string& clsid,
+ bool allow_wildcard) {
+ DCHECK(mime_type == StringToLowerASCII(mime_type));
+
+ for (size_t idx = 0; idx < plugins_.size(); ++idx) {
+ if (plugins_[idx]->SupportsType(mime_type, allow_wildcard)) {
+ if (!clsid.empty() &&
+ plugins_[idx]->plugin_info().file == kActiveXShimFileName) {
+ // Special handling for ActiveX shim. If ActiveX is not installed, we
+ // should use the default plugin to show the installation UI.
+ if (!activex_shim::IsActiveXInstalled(clsid))
+ continue;
+ }
+ return plugins_[idx];
+ }
+ }
+
+ return NULL;
+}
+
+PluginLib* PluginList::FindPlugin(const GURL &url, std::string* actual_mime_type) {
+ std::wstring path = NativeMBToWide(url.path());
+ std::wstring extension_wide = file_util::GetFileExtensionFromPath(path);
+ if (extension_wide.empty())
+ return NULL;;
+
+ std::string extension = StringToLowerASCII(WideToNativeMB(extension_wide));
+
+ for (size_t idx = 0; idx < plugins_.size(); ++idx) {
+ if (SupportsExtension(plugins_[idx]->plugin_info(), extension, actual_mime_type)) {
+ return plugins_[idx];
+ }
+ }
+
+ return NULL;
+}
+
+bool PluginList::SupportsType(const std::string &mime_type) {
+ DCHECK(mime_type == StringToLowerASCII(mime_type));
+ bool allow_wildcard = true;
+ return (FindPlugin(mime_type, "", allow_wildcard ) != 0);
+}
+
+bool PluginList::SupportsExtension(const WebPluginInfo& info,
+ const std::string &extension,
+ std::string* actual_mime_type) {
+ for (size_t i = 0; i < info.mime_types.size(); ++i) {
+ const WebPluginMimeType& mime_type = info.mime_types[i];
+ for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) {
+ if (mime_type.file_extensions[j] == extension) {
+ if (actual_mime_type)
+ *actual_mime_type = mime_type.mime_type;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool PluginList::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) {
+ if (refresh)
+ LoadPlugins(true);
+
+ plugins->resize(plugins_.size());
+ for (size_t i = 0; i < plugins->size(); ++i)
+ (*plugins)[i] = plugins_[i]->plugin_info();
+
+ return true;
+}
+
+bool PluginList::GetPluginInfo(const GURL& url,
+ const std::string& mime_type,
+ const std::string& clsid,
+ bool allow_wildcard,
+ WebPluginInfo* info,
+ std::string* actual_mime_type) {
+ scoped_refptr<PluginLib> plugin = FindPlugin(mime_type, clsid,
+ allow_wildcard);
+
+ if (plugin.get() == NULL ||
+ (plugin->plugin_info().file == kDefaultPluginDllName && clsid.empty())) {
+ scoped_refptr<PluginLib> default_plugin = plugin;
+ plugin = FindPlugin(url, actual_mime_type);
+ // url matches may not return the default plugin if no match is found.
+ if (plugin.get() == NULL && default_plugin.get() != NULL)
+ plugin = default_plugin;
+ }
+
+ if (plugin.get() == NULL)
+ return false;
+
+ *info = plugin->plugin_info();
+ return true;
+}
+
+bool PluginList::GetPluginInfoByDllPath(const std::wstring& dll_path,
+ WebPluginInfo* info) {
+ for (size_t i = 0; i < plugins_.size(); ++i) {
+ if (wcsicmp(plugins_[i]->plugin_info().file.c_str(),
+ dll_path.c_str()) == 0) {
+ *info = plugins_[i]->plugin_info();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void PluginList::Shutdown() {
+ // TODO
+}
+
+std::wstring PluginList::GetPluginAppDirectory() {
+ std::wstring app_path;
+ if (webkit_glue::GetApplicationDirectory(&app_path))
+ app_path.append(L"\\plugins");
+
+ return app_path;
+}
+
+std::wstring PluginList::GetPluginExeDirectory() {
+ std::wstring exe_path;
+ if (webkit_glue::GetExeDirectory(&exe_path))
+ exe_path.append(L"\\plugins");
+
+ return exe_path;
+}
+
+// Gets the installed path for a registered app.
+static bool GetInstalledPath(const TCHAR* app, std::wstring* out) {
+ std::wstring reg_path(kRegistryApps);
+ reg_path.append(L"\\");
+ reg_path.append(app);
+
+ RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str());
+ return key.ReadValue(kRegistryPath, out);
+}
+
+// Enumerate through the registry key to find all installed FireFox paths.
+// FireFox 3 beta and version 2 can coexist. See bug: 1025003
+static void GetFirefoxInstalledPaths(std::vector<std::wstring>* out) {
+ RegistryKeyIterator it(HKEY_LOCAL_MACHINE, kRegistryFirefoxInstalled);
+ for (; it.Valid(); ++it) {
+ std::wstring full_path = std::wstring(kRegistryFirefoxInstalled) + L"\\" +
+ it.Name() + L"\\Main";
+ RegKey key(HKEY_LOCAL_MACHINE, full_path.c_str(), KEY_READ);
+ std::wstring install_dir;
+ if (!key.ReadValue(L"Install Directory", &install_dir))
+ continue;
+ out->push_back(install_dir);
+ }
+}
+
+void PluginList::LoadFirefoxPlugins() {
+ std::vector<std::wstring> paths;
+ GetFirefoxInstalledPaths(&paths);
+ for (unsigned int i = 0; i < paths.size(); ++i) {
+ std::wstring path = paths[i] + L"\\plugins";
+ LoadPlugins(path);
+ }
+
+ LoadPluginsInRegistryFolder(HKEY_CURRENT_USER, kRegistryMozillaPlugins);
+ LoadPluginsInRegistryFolder(HKEY_LOCAL_MACHINE, kRegistryMozillaPlugins);
+
+ std::wstring firefox_app_data_plugin_path;
+ if (PathService::Get(base::DIR_APP_DATA, &firefox_app_data_plugin_path)) {
+ firefox_app_data_plugin_path += L"\\Mozilla\\plugins";
+ LoadPlugins(firefox_app_data_plugin_path);
+ }
+}
+
+void PluginList::LoadAcrobatPlugins() {
+ std::wstring path;
+ if (GetInstalledPath(kRegistryAcrobat, &path)) {
+ path.append(L"\\Browser");
+ LoadPlugins(path);
+ }
+}
+
+void PluginList::LoadQuicktimePlugins() {
+ std::wstring path;
+ if (GetInstalledPath(kRegistryQuickTime, &path)) {
+ path.append(L"\\plugins");
+ LoadPlugins(path);
+ }
+}
+
+void PluginList::LoadWindowsMediaPlugins() {
+ std::wstring path;
+ if (GetInstalledPath(kRegistryWindowsMedia, &path)) {
+ LoadPlugins(path);
+ }
+}
+
+void PluginList::LoadJavaPlugin() {
+ // Load the new NPAPI Java plugin
+ // 1. Open the main JRE key under HKLM
+ RegKey java_key(HKEY_LOCAL_MACHINE, kRegistryJava, KEY_QUERY_VALUE);
+
+ // 2. Read the current Java version
+ std::wstring java_version;
+ if (!java_key.ReadValue(kRegistryBrowserJavaVersion, &java_version))
+ java_key.ReadValue(kRegistryCurrentJavaVersion, &java_version);
+
+ if (!java_version.empty()) {
+ java_key.OpenKey(java_version.c_str(), KEY_QUERY_VALUE);
+
+ // 3. Install path of the JRE binaries is specified in "JavaHome"
+ // value under the Java version key.
+ std::wstring java_plugin_directory;
+ if (java_key.ReadValue(kRegistryJavaHome, &java_plugin_directory)) {
+
+ // 4. The new plugin resides under the 'bin/new_plugin'
+ // subdirectory.
+ DCHECK(!java_plugin_directory.empty());
+ java_plugin_directory.append(L"\\bin\\new_plugin");
+
+ // 5. We don't know the exact name of the DLL but it's in the form
+ // NP*.dll so just invoke LoadPlugins on this path.
+ LoadPlugins(java_plugin_directory);
+ }
+ }
+}
+
+void PluginList::LoadPluginsInRegistryFolder(
+ HKEY root_key,
+ const std::wstring& registry_folder) {
+ for (RegistryKeyIterator iter(root_key, registry_folder.c_str());
+ iter.Valid(); ++iter) {
+ // Use the registry to gather plugin across the file system.
+ std::wstring reg_path = registry_folder;
+ reg_path.append(L"\\");
+ reg_path.append(iter.Name());
+ RegKey key(root_key, reg_path.c_str());
+
+ std::wstring path;
+ if (key.ReadValue(kRegistryPath, &path))
+ LoadPlugin(path);
+ }
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_list.h b/webkit/glue/plugins/plugin_list.h
new file mode 100644
index 0000000..1176ad8
--- /dev/null
+++ b/webkit/glue/plugins/plugin_list.h
@@ -0,0 +1,197 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// TODO: Need mechanism to cleanup the static instance
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_LIST_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_LIST_H__
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "webkit/glue/webplugin.h"
+
+class GURL;
+
+namespace NPAPI
+{
+
+// Used by plugins_test when testing the older WMP plugin to force the new
+// plugin to not get loaded.
+#define kUseOldWMPPluginSwitch L"use-old-wmp"
+// Used for testing ActiveX shim. By default it's off. If this flag is specified
+// we will use the native ActiveX shim.
+#define kNoNativeActiveXShimSwitch L"no-activex"
+// Internal file name for activex shim, used as a unique identifier.
+#define kActiveXShimFileName L"activex-shim"
+
+#define kDefaultPluginDllName L"default_plugin"
+
+class PluginLib;
+class PluginInstance;
+
+// The PluginList is responsible for loading our NPAPI based plugins.
+// It loads plugins from a known directory by looking for DLLs
+// which start with "NP", and checking to see if they are valid
+// NPAPI libraries.
+class PluginList : public base::RefCounted<PluginList> {
+ public:
+ // Gets the one instance of the PluginList.
+ //
+ // Accessing the singleton causes the PluginList to look on
+ // disk for existing plugins. It does not actually load
+ // libraries, that will only happen when you initialize
+ // the plugin for the first time.
+ static PluginList* Singleton();
+
+ // Add an extra plugin to load when we actually do the loading. This is
+ // static because we want to be able to add to it without searching the disk
+ // for plugins. Must be called before the plugins have been loaded.
+ static void AddExtraPluginPath(const std::wstring& plugin_path);
+
+ virtual ~PluginList();
+
+ // Find a plugin to by mime type, and clsid.
+ // If clsid is empty, we will just find the plugin that supports mime type.
+ // Otherwise, if mime_type is application/x-oleobject etc that supported by
+ // by our activex shim, we need to check if the specified ActiveX exists.
+ // If not we will not return the activex shim, instead we will let the
+ // default plugin handle activex installation.
+ // The allow_wildcard parameter controls whether this function returns
+ // plugins which support wildcard mime types (* as the mime type)
+ PluginLib* FindPlugin(const std::string &mime_type, const std::string& clsid,
+ bool allow_wildcard);
+
+ // Find a plugin to by extension. Returns the corresponding mime type
+ PluginLib* FindPlugin(const GURL &url, std::string* actual_mime_type);
+
+ // Check if we have any plugin for a given type.
+ // mime_type must be all lowercase.
+ bool SupportsType(const std::string &mime_type);
+
+ // Returns true if the given WebPluginInfo supports a given file extension.
+ // extension should be all lower case.
+ // If mime_type is not NULL, it will be set to the mime type if found.
+ // The mime type which corresponds to the extension is optionally returned
+ // back.
+ static bool SupportsExtension(const WebPluginInfo& info,
+ const std::string &extension,
+ std::string* actual_mime_type);
+
+ // Shutdown all plugins. Should be called at process teardown.
+ void Shutdown();
+
+ // Get all the plugins
+ bool GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins);
+
+ // Returns true if a plugin is found for the given url and mime type.
+ // The mime type which corresponds to the URL is optionally returned
+ // back.
+ // The allow_wildcard parameter controls whether this function returns
+ // plugins which support wildcard mime types (* as the mime type)
+ bool GetPluginInfo(const GURL& url,
+ const std::string& mime_type,
+ const std::string& clsid,
+ bool allow_wildcard,
+ WebPluginInfo* info,
+ std::string* actual_mime_type);
+
+ // Get plugin info by plugin dll path. Returns true if the plugin is found and
+ // WebPluginInfo has been filled in |info|
+ bool GetPluginInfoByDllPath(const std::wstring& dll_path,
+ WebPluginInfo* info);
+ private:
+ // Constructors are private for singletons
+ PluginList();
+
+ // Load all plugins from the default plugins directory
+ void LoadPlugins(bool refresh);
+
+ // Load all plugins from a specific directory
+ void LoadPlugins(const std::wstring &path);
+
+ // Load a specific plugin with full path. filename can be mixed case.
+ void LoadPlugin(const std::wstring &filename);
+
+ // Returns true if we should load the given plugin, or false otherwise.
+ // filename must be lower case.
+ bool ShouldLoadPlugin(const std::wstring& filename);
+
+ // Load internal plugins. Right now there is only one: activex_shim.
+ void LoadInternalPlugins();
+
+ // Find a plugin by filename. Returns -1 if it's not found, otherwise its
+ // index in plugins_. filename needs to be lower case.
+ int FindPluginFile(const std::wstring& filename);
+
+ // The application path where we expect to find plugins.
+ static std::wstring GetPluginAppDirectory();
+
+ // The executable path where we expect to find plugins.
+ static std::wstring GetPluginExeDirectory();
+
+ // Load plugins from the Firefox install path. This is kind of
+ // a kludge, but it helps us locate the flash player for users that
+ // already have it for firefox. Not having to download yet-another-plugin
+ // is a good thing.
+ void LoadFirefoxPlugins();
+
+ // Hardcoded logic to detect and load acrobat plugins
+ void LoadAcrobatPlugins();
+
+ // Hardcoded logic to detect and load quicktime plugins
+ void LoadQuicktimePlugins();
+
+ // Hardcoded logic to detect and load Windows Media Player plugins
+ void LoadWindowsMediaPlugins();
+
+ // Hardcoded logic to detect and load Java plugins
+ void LoadJavaPlugin();
+
+ // Search the registry at the given path and load plugins listed there.
+ void LoadPluginsInRegistryFolder(HKEY root_key,
+ const std::wstring& registry_folder);
+
+ // true if we shouldn't load the new WMP plugin.
+ bool dont_load_new_wmp_;
+
+ bool use_internal_activex_shim_;
+
+ static scoped_refptr<PluginList> singleton_;
+ bool plugins_loaded_;
+ std::vector<scoped_refptr<PluginLib> > plugins_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginList);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_LIST_H__
diff --git a/webkit/glue/plugins/plugin_stream.cc b/webkit/glue/plugins/plugin_stream.cc
new file mode 100644
index 0000000..9f41ac9
--- /dev/null
+++ b/webkit/glue/plugins/plugin_stream.cc
@@ -0,0 +1,323 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// TODO : Support NP_ASFILEONLY mode
+// TODO : Support NP_SEEK mode
+// TODO : Support SEEKABLE=true in NewStream
+
+#include "webkit/glue/plugins/plugin_stream.h"
+
+#include "base/string_util.h"
+#include "base/message_loop.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/webkit_glue.h"
+#include "googleurl/src/gurl.h"
+
+namespace NPAPI {
+
+PluginStream::PluginStream(
+ PluginInstance *instance,
+ const char *url,
+ bool need_notify,
+ void *notify_data)
+ : instance_(instance),
+ bytes_sent_(0),
+ notify_needed_(need_notify),
+ notify_data_(notify_data),
+ close_on_write_data_(false),
+ opened_(false),
+ requested_plugin_mode_(NP_NORMAL),
+ temp_file_handle_(INVALID_HANDLE_VALUE) {
+ memset(&stream_, 0, sizeof(stream_));
+ stream_.url = _strdup(url);
+ temp_file_name_[0] = '\0';
+}
+
+PluginStream::~PluginStream() {
+ // always cleanup our temporary files.
+ CleanupTempFile();
+
+ free(const_cast<char*>(stream_.url));
+}
+
+void PluginStream::UpdateUrl(const char* url) {
+ DCHECK(!opened_);
+ free(const_cast<char*>(stream_.url));
+ stream_.url = _strdup(url);
+}
+
+bool PluginStream::Open(const std::string &mime_type,
+ const std::string &headers,
+ uint32 length,
+ uint32 last_modified) {
+ headers_ = headers;
+ NPP id = instance_->npp();
+ stream_.end = length;
+ stream_.lastmodified = last_modified;
+ stream_.pdata = 0;
+ stream_.ndata = id->ndata;
+ stream_.notifyData = notify_data_;
+ if (!headers_.empty())
+ stream_.headers = headers_.c_str();
+
+ const char *char_mime_type = "application/x-unknown-content-type";
+ std::string temp_mime_type;
+ if (!mime_type.empty()) {
+ char_mime_type = mime_type.c_str();
+ } else {
+ GURL gurl(stream_.url);
+ std::wstring path(UTF8ToWide(gurl.path()));
+ if (webkit_glue::GetMimeTypeFromFile(path, &temp_mime_type))
+ char_mime_type = temp_mime_type.c_str();
+ }
+
+ // Silverlight expects a valid mime type
+ DCHECK(strlen(char_mime_type) != 0);
+ NPError err = instance_->NPP_NewStream((NPMIMEType)char_mime_type,
+ &stream_, false,
+ &requested_plugin_mode_);
+ if (err != NPERR_NO_ERROR)
+ return false;
+
+ opened_ = true;
+
+ // If the plugin has requested certain modes, then we need a copy
+ // of this file on disk. Open it and save it as we go.
+ if (requested_plugin_mode_ == NP_ASFILEONLY ||
+ requested_plugin_mode_ == NP_ASFILE ||
+ requested_plugin_mode_ == NP_SEEK) {
+ if (OpenTempFile() == false)
+ return false;
+ }
+
+ return true;
+}
+
+int PluginStream::Write(const char *buffer, const int length) {
+ // There may be two streams to write to - the plugin and the file.
+ // It is unclear what to do if we cannot write to both. The rules of
+ // this function are that the plugin must consume at least as many
+ // bytes as returned by the WriteReady call. So, we will attempt to
+ // write that many to both streams. If we can't write that many bytes
+ // to each stream, we'll return failure.
+
+ DCHECK(opened_);
+ if (WriteToFile(buffer, length) && WriteToPlugin(buffer, length))
+ return length;
+
+ return -1;
+}
+
+bool PluginStream::WriteToFile(const char *buf, const int length) {
+ // For ASFILEONLY, ASFILE, and SEEK modes, we need to write
+ // to the disk
+ if (temp_file_handle_ != INVALID_HANDLE_VALUE &&
+ (requested_plugin_mode_ == NP_SEEK ||
+ requested_plugin_mode_ == NP_ASFILE ||
+ requested_plugin_mode_ == NP_ASFILEONLY) ) {
+ int totalBytesWritten = 0;
+ DWORD bytes;
+ do {
+ if (WriteFile(temp_file_handle_, buf, length, &bytes, 0) == FALSE)
+ break;
+ totalBytesWritten += bytes;
+ } while (bytes > 0 && totalBytesWritten < length);
+
+ if (totalBytesWritten != length)
+ return false;
+ }
+
+ return true;
+}
+
+bool PluginStream::WriteToPlugin(const char *buf, const int length) {
+ // For NORMAL and ASFILE modes, we send the data to the plugin now
+ if (requested_plugin_mode_ != NP_NORMAL &&
+ requested_plugin_mode_ != NP_ASFILE)
+ return true;
+
+ int written = TryWriteToPlugin(buf, length);
+ if (written == -1)
+ return false;
+
+ if (written < length) {
+ // Buffer the remaining data.
+ size_t remaining = length - written;
+ size_t previous_size = delivery_data_.size();
+ delivery_data_.resize(previous_size + remaining);
+ memcpy(&delivery_data_[previous_size], buf + written, remaining);
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &PluginStream::OnDelayDelivery));
+ }
+
+ return true;
+}
+
+void PluginStream::OnDelayDelivery() {
+ // It is possible that the plugin stream may have closed before the task
+ // was hit.
+ if (!opened_) {
+ return;
+ }
+
+ int size = static_cast<int>(delivery_data_.size());
+ int written = TryWriteToPlugin(&delivery_data_.front(), size);
+ if (written > 0) {
+ // Remove the data that we already wrote.
+ delivery_data_.erase(delivery_data_.begin(),
+ delivery_data_.begin() + written);
+ }
+}
+
+int PluginStream::TryWriteToPlugin(const char *buf, const int length) {
+ bool result = true;
+ int byte_offset = 0;
+
+ while (byte_offset < length) {
+ int bytes_remaining = length - byte_offset;
+ int bytes_to_write = instance_->NPP_WriteReady(&stream_);
+ if (bytes_to_write > bytes_remaining)
+ bytes_to_write = bytes_remaining;
+
+ if (bytes_to_write == 0)
+ return byte_offset;
+
+ int bytesSent = instance_->NPP_Write(&stream_,
+ bytes_sent_,
+ bytes_to_write,
+ const_cast<char*>(buf + byte_offset));
+ if (bytesSent < bytes_to_write) {
+ // We couldn't write all the bytes. This is an error.
+ return -1;
+ }
+ bytes_sent_ += bytesSent;
+ byte_offset += bytesSent;
+ }
+
+ if (close_on_write_data_)
+ Close(NPRES_DONE);
+
+ return length;
+}
+
+void PluginStream::WriteAsFile() {
+ if (requested_plugin_mode_ == NP_ASFILE ||
+ requested_plugin_mode_ == NP_ASFILEONLY)
+ instance_->NPP_StreamAsFile(&stream_, temp_file_name_);
+}
+
+bool PluginStream::Close(NPReason reason) {
+ if (opened_ == true) {
+ opened_ = false;
+
+ if (delivery_data_.size()) {
+ if (reason == NPRES_DONE) {
+ // There is more data to be streamed, don't destroy the stream now.
+ close_on_write_data_ = true;
+ return true;
+ } else {
+ // Stop any pending data from being streamed
+ delivery_data_.resize(0);
+ }
+ }
+
+ // If we have a temp file, be sure to close it.
+ // Also, allow the plugin to access it now.
+ if (temp_file_handle_ != INVALID_HANDLE_VALUE) {
+ CloseTempFile();
+ WriteAsFile();
+ }
+
+ if (stream_.ndata != NULL) {
+ // Stream hasn't been closed yet.
+ NPError err = instance_->NPP_DestroyStream(&stream_, reason);
+ DCHECK(err == NPERR_NO_ERROR);
+ }
+ }
+
+ Notify(reason);
+ return true;
+}
+
+bool PluginStream::OpenTempFile() {
+ DCHECK(temp_file_handle_ == INVALID_HANDLE_VALUE);
+
+ // The reason for using all the Ascii versions of these filesystem
+ // calls is that the filename which we pass back to the plugin
+ // via NPAPI is an ascii filename. Otherwise, we'd use wide-chars.
+ //
+ // TODO:
+ // This is a bug in NPAPI itself, and it needs to be fixed.
+ // The case which will fail is if a user has a multibyte name,
+ // but has the system locale set to english. GetTempPathA will
+ // return junk in this case, causing us to be unable to open the
+ // file.
+
+ char temp_directory[MAX_PATH];
+ if (GetTempPathA(MAX_PATH, temp_directory) == 0)
+ return false;
+ if (GetTempFileNameA(temp_directory, "npstream", 0, temp_file_name_) == 0)
+ return false;
+ temp_file_handle_ = CreateFileA(temp_file_name_,
+ FILE_ALL_ACCESS,
+ FILE_SHARE_READ,
+ 0,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ 0);
+ if (temp_file_handle_ == INVALID_HANDLE_VALUE) {
+ temp_file_name_[0] = '\0';
+ return false;
+ }
+ return true;
+}
+
+void PluginStream::CloseTempFile() {
+ if (temp_file_handle_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(temp_file_handle_);
+ temp_file_handle_ = INVALID_HANDLE_VALUE;
+ }
+}
+
+void PluginStream::CleanupTempFile() {
+ CloseTempFile();
+ if (temp_file_name_[0] != '\0') {
+ DeleteFileA(temp_file_name_);
+ temp_file_name_[0] = '\0';
+ }
+}
+
+void PluginStream::Notify(NPReason reason) {
+ if (notify_needed_) {
+ instance_->NPP_URLNotify(stream_.url, reason, notify_data_);
+ notify_needed_ = false;
+ }
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_stream.h b/webkit/glue/plugins/plugin_stream.h
new file mode 100644
index 0000000..e4b99ba
--- /dev/null
+++ b/webkit/glue/plugins/plugin_stream.h
@@ -0,0 +1,136 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_H__
+
+#include <string>
+#include <vector>
+
+#include "base/ref_counted.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+
+namespace NPAPI {
+
+class PluginInstance;
+
+// Base class for a NPAPI stream. Tracks basic elements
+// of a stream for NPAPI notifications and stream position.
+class PluginStream : public base::RefCounted<PluginStream> {
+ public:
+ // Create a new PluginStream object. If needNotify is true, then the
+ // plugin will be notified when the stream has been fully sent.
+ PluginStream(PluginInstance *instance,
+ const char *url,
+ bool need_notify,
+ void *notify_data);
+ virtual ~PluginStream();
+
+ // In case of a redirect, this can be called to update the url. But it must
+ // be called before Open().
+ void UpdateUrl(const char* url);
+
+ // Opens the stream to the Plugin.
+ // If the mime-type is not specified, we'll try to find one based on the
+ // mime-types table and the extension (if any) in the URL.
+ // If the size of the stream is known, use length to set the size. If
+ // not known, set length to 0.
+ bool Open(const std::string &mime_type,
+ const std::string &headers,
+ uint32 length,
+ uint32 last_modified);
+
+ // Writes to the stream.
+ int Write(const char *buf, const int len);
+
+ // Write the result as a file.
+ void WriteAsFile();
+
+ // Notify the plugin that a stream is complete.
+ void Notify(NPReason reason);
+
+ // Close the stream.
+ virtual bool Close(NPReason reason);
+
+ const NPStream* stream() const {
+ return &stream_;
+ }
+
+ protected:
+ PluginInstance* instance() { return instance_.get(); }
+ // Check if the stream is open.
+ bool open() { return opened_; }
+
+ private:
+ // Open a temporary file for this stream.
+ // If successful, will set temp_file_name_, temp_file_handle_, and
+ // return true.
+ bool OpenTempFile();
+
+ // Closes the temporary file if it is open.
+ void CloseTempFile();
+
+ // Closes the temporary file if it is open and deletes the file.
+ void CleanupTempFile();
+
+ // Sends the data to the file if it's open.
+ bool WriteToFile(const char *buf, const int length);
+
+ // Sends the data to the plugin. If it's not ready, handles buffering it
+ // and retrying later.
+ bool WriteToPlugin(const char *buf, const int length);
+
+ // Send the data to the plugin, returning how many bytes it accepted, or -1
+ // if an error occurred.
+ int TryWriteToPlugin(const char *buf, const int length);
+
+ // The callback which calls TryWriteToPlugin.
+ void OnDelayDelivery();
+
+ private:
+ NPStream stream_;
+ std::string headers_;
+ scoped_refptr<PluginInstance> instance_;
+ int bytes_sent_;
+ bool notify_needed_;
+ void * notify_data_;
+ bool close_on_write_data_;
+ uint16 requested_plugin_mode_;
+ bool opened_;
+ char temp_file_name_[MAX_PATH];
+ HANDLE temp_file_handle_;
+ std::vector<char> delivery_data_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginStream);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_H__
diff --git a/webkit/glue/plugins/plugin_stream_url.cc b/webkit/glue/plugins/plugin_stream_url.cc
new file mode 100644
index 0000000..9400f2c
--- /dev/null
+++ b/webkit/glue/plugins/plugin_stream_url.cc
@@ -0,0 +1,104 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/plugin_stream_url.h"
+
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/plugins/plugin_host.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+
+namespace NPAPI {
+
+PluginStreamUrl::PluginStreamUrl(
+ int resource_id,
+ const GURL &url,
+ PluginInstance *instance,
+ bool notify_needed,
+ void *notify_data)
+ : PluginStream(instance, url.spec().c_str(), notify_needed, notify_data),
+ url_(url),
+ id_(resource_id) {
+}
+
+PluginStreamUrl::~PluginStreamUrl() {
+}
+
+bool PluginStreamUrl::Close(NPReason reason) {
+ if (id_ != 0) {
+ if (instance()->webplugin()) {
+ instance()->webplugin()->CancelResource(id_);
+ }
+
+ id_ = 0;
+ }
+
+ bool result = PluginStream::Close(reason);
+ instance()->RemoveStream(this);
+ return result;
+}
+
+void PluginStreamUrl::WillSendRequest(const GURL& url) {
+ url_ = url;
+ UpdateUrl(url.spec().c_str());
+}
+
+void PluginStreamUrl::DidReceiveResponse(const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified,
+ bool* cancel) {
+
+ bool opened = Open(mime_type,
+ headers,
+ expected_length,
+ last_modified);
+ if (!opened) {
+ instance()->RemoveStream(this);
+ *cancel = true;
+ }
+}
+
+void PluginStreamUrl::DidReceiveData(const char* buffer, int length) {
+ if (!open())
+ return;
+
+ if (length > 0)
+ Write(const_cast<char*>(buffer), length);
+}
+
+void PluginStreamUrl::DidFinishLoading() {
+ Close(NPRES_DONE);
+}
+
+void PluginStreamUrl::DidFail() {
+ Close(NPRES_NETWORK_ERR);
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_stream_url.h b/webkit/glue/plugins/plugin_stream_url.h
new file mode 100644
index 0000000..b6b5b3b
--- /dev/null
+++ b/webkit/glue/plugins/plugin_stream_url.h
@@ -0,0 +1,84 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__
+
+
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/plugins/plugin_stream.h"
+#include "googleurl/src/gurl.h"
+
+namespace NPAPI {
+
+class PluginInstance;
+
+// A NPAPI Stream based on a URL.
+class PluginStreamUrl : public PluginStream,
+ public WebPluginResourceClient {
+ public:
+ // Create a new stream for sending to the plugin by fetching
+ // a URL. If notifyNeeded is set, then the plugin will be notified
+ // when the stream has been fully sent to the plugin. Initialize
+ // must be called before the object is used.
+ PluginStreamUrl(int resource_id,
+ const GURL &url,
+ PluginInstance *instance,
+ bool notify_needed,
+ void *notify_data);
+ virtual ~PluginStreamUrl();
+
+ // Stop sending the stream to the client.
+ // Overrides the base Close so we can cancel our fetching the URL if
+ // it is still loading.
+ bool Close(NPReason reason);
+
+ //
+ // WebPluginResourceClient methods
+ //
+ void WillSendRequest(const GURL& url);
+ void DidReceiveResponse(const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified,
+ bool* cancel);
+ void DidReceiveData(const char* buffer, int length);
+ void DidFinishLoading();
+ void DidFail();
+
+ private:
+ GURL url_;
+ int id_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginStreamUrl);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__ \ No newline at end of file
diff --git a/webkit/glue/plugins/plugin_string_stream.cc b/webkit/glue/plugins/plugin_string_stream.cc
new file mode 100644
index 0000000..c32f5ab
--- /dev/null
+++ b/webkit/glue/plugins/plugin_string_stream.cc
@@ -0,0 +1,56 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/plugin_string_stream.h"
+
+namespace NPAPI {
+
+PluginStringStream::PluginStringStream(
+ PluginInstance *instance,
+ const std::string &url,
+ bool notify_needed,
+ void *notify_data)
+ : PluginStream(instance, url.c_str(), notify_needed, notify_data) {
+}
+
+PluginStringStream::~PluginStringStream() {
+}
+
+void PluginStringStream::SendToPlugin(const std::string &data,
+ const std::string &mime_type) {
+ int length = static_cast<int>(data.length());
+ if (Open(mime_type, std::string(), length, 0)) {
+ // TODO - check if it was not fully sent, and figure out a backup plan.
+ int written = Write(data.c_str(), length);
+ NPReason reason = written == length ? NPRES_DONE : NPRES_NETWORK_ERR;
+ Close(reason);
+ }
+}
+
+}
diff --git a/webkit/glue/plugins/plugin_string_stream.h b/webkit/glue/plugins/plugin_string_stream.h
new file mode 100644
index 0000000..8c2e2c6
--- /dev/null
+++ b/webkit/glue/plugins/plugin_string_stream.h
@@ -0,0 +1,62 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_STRING_STREAM_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_STRING_STREAM_H__
+
+#include "webkit/glue/plugins/plugin_stream.h"
+
+namespace NPAPI {
+
+class PluginInstance;
+
+// An NPAPI stream from a string.
+class PluginStringStream : public PluginStream {
+ public:
+ // Create a new stream for sending to the plugin.
+ // If notify_needed, will notify the plugin after the data has
+ // all been sent.
+ PluginStringStream(PluginInstance *instance,
+ const std::string &url,
+ bool notify_needed,
+ void *notify_data);
+ virtual ~PluginStringStream();
+
+ // Initiates the sending of data to the plugin.
+ void SendToPlugin(const std::string &data,
+ const std::string &mime_type);
+
+ private:
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginStringStream);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_STRING_STREAM_H__
diff --git a/webkit/glue/plugins/test/SConscript b/webkit/glue/plugins/test/SConscript
new file mode 100644
index 0000000..f8113f6
--- /dev/null
+++ b/webkit/glue/plugins/test/SConscript
@@ -0,0 +1,109 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Import('env', 'env_res')
+
+env = env.Clone()
+env_res = env_res.Clone()
+
+input_files = [
+ 'npapi_constants.cc',
+ 'npapi_test.cc',
+ env_res.RES('npapi_test.rc'),
+ 'plugin_arguments_test.cc',
+ 'plugin_client.cc',
+ 'plugin_delete_plugin_in_stream_test.cc',
+ 'plugin_execute_script_delete_test.cc',
+ 'plugin_get_javascript_url_test.cc',
+ 'plugin_geturl_test.cc',
+ 'plugin_new_fails_test.cc',
+ 'plugin_npobject_lifetime_test.cc',
+ 'plugin_npobject_proxy_test.cc',
+ 'plugin_test.cc',
+ 'plugin_window_size_test.cc',
+ 'npapi_test.def',
+
+ env.File('$BASE_DIR/base.lib'),
+]
+
+env.Append(
+ CCFLAGS = [
+ '/TP',
+ '/wd4800',
+ '/wd4503',
+ '/wd4819',
+ ],
+
+ LIBS = [
+ 'comctl32.lib',
+ 'shlwapi.lib',
+ 'rpcrt4.lib',
+ 'winmm.lib',
+ 'wininet.lib',
+ 'version.lib',
+ 'msimg32.lib',
+ 'ws2_32.lib',
+ 'usp10.lib',
+ 'psapi.lib',
+ 'kernel32.lib',
+ 'user32.lib',
+ 'gdi32.lib',
+ 'winspool.lib',
+ 'comdlg32.lib',
+ 'advapi32.lib',
+ 'shell32.lib',
+ 'ole32.lib',
+ 'oleaut32.lib',
+ 'uuid.lib',
+ 'odbc32.lib',
+ 'odbccp32.lib',
+
+ 'delayimp.lib',
+ ],
+
+ LINKFLAGS = [
+ '/DELAYLOAD:"dwmapi.dll"',
+ '/DELAYLOAD:"uxtheme.dll"',
+ '/FIXED:No',
+ '/SUBSYSTEM:CONSOLE',
+ '/MACHINE:X86',
+ '/safeseh',
+ '/dynamicbase',
+ '/ignore:4199',
+ '/nxcompat',
+ ],
+)
+
+dll = env.SharedLibrary(['npapi_test_plugin',
+ 'npapi_test_plugin.ilk',
+ 'npapi_test_plugin.pdb'],
+ input_files)
+
+i = env.Install('$TARGET_ROOT', dll)
+env.Alias('webkit', i)
diff --git a/webkit/glue/plugins/test/npapi_constants.cc b/webkit/glue/plugins/test/npapi_constants.cc
new file mode 100644
index 0000000..eadd9e0
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_constants.cc
@@ -0,0 +1,35 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/test/npapi_constants.h"
+
+namespace NPAPIClient {
+const char kTestCompleteCookie[] = "status";
+const char kTestCompleteSuccess[] = "OK";
+}
diff --git a/webkit/glue/plugins/test/npapi_constants.h b/webkit/glue/plugins/test/npapi_constants.h
new file mode 100644
index 0000000..0894e7a
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_constants.h
@@ -0,0 +1,44 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Constants for the NPAPI test
+
+#ifndef WEBKIT_PORT_PLUGINS_TEST_NPAPI_CONSTANTS_H__
+#define WEBKIT_PORT_PLUGINS_TEST_NPAPI_CONSTANTS_H__
+
+namespace NPAPIClient {
+// The name of the cookie which will be used to communicate between
+// the plugin and the test harness.
+extern const char kTestCompleteCookie[];
+
+// The cookie value which will be sent to the client upon successful
+// test.
+extern const char kTestCompleteSuccess[];
+}
+#endif // WEBKIT_PORT_PLUGINS_TEST_NPAPI_CONSTANTS_H__
diff --git a/webkit/glue/plugins/test/npapi_test.cc b/webkit/glue/plugins/test/npapi_test.cc
new file mode 100644
index 0000000..4272dd4
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_test.cc
@@ -0,0 +1,92 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// npapitest
+//
+// This is a NPAPI Plugin Program which is used to test the Browser's NPAPI
+// host implementation. It is used in conjunction with the npapi_unittest.
+//
+// As a NPAPI Plugin, you can invoke it by creating a web page of the following
+// type:
+//
+// <embed src="content-to-load" type="application/vnd.npapi-test"
+// name="test-name">
+//
+// arguments:
+// src: This is the initial content which will be sent to the plugin.
+// type: Must be "application/vnd.npapi-test"
+// name: The testcase to run when invoked
+// id: The id of the test being run (for testing concurrent plugins)
+//
+// The Plugin drives the actual test, calling host functions and validating the
+// Host callbacks which it receives. It is the duty of the plugin to record
+// all errors.
+//
+// To indicate test completion, the plugin expects the containing HTML page to
+// implement two javascript functions:
+// onSuccess(string testname);
+// onFailure(string testname, string results);
+// The HTML host pages used in this test will then set a document cookie
+// which the automated test framework can poll for and discover that the
+// test has completed.
+//
+//
+// TESTS
+// When the PluginClient receives a NPP_New callback from the browser,
+// it looks at the "name" argument which is passed in. It verifies that
+// the name matches a known test, and instantiates that test. The test is
+// a subclass of PluginTest.
+//
+//
+
+#include <windows.h>
+#include "webkit/glue/plugins/test/plugin_client.h"
+
+BOOL WINAPI DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) {
+ return TRUE;
+}
+
+extern "C" {
+NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
+ return NPAPIClient::PluginClient::GetEntryPoints(pFuncs);
+}
+
+NPError WINAPI NP_Initialize(NPNetscapeFuncs* pFuncs) {
+ return NPAPIClient::PluginClient::Initialize(pFuncs);
+}
+
+NPError WINAPI NP_Shutdown() {
+ return NPAPIClient::PluginClient::Shutdown();
+}
+} // extern "C"
+
+namespace WebCore {
+ const char* currentTextBreakLocaleID() { return "en_us"; }
+} \ No newline at end of file
diff --git a/webkit/glue/plugins/test/npapi_test.def b/webkit/glue/plugins/test/npapi_test.def
new file mode 100644
index 0000000..4481c16
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_test.def
@@ -0,0 +1,6 @@
+LIBRARY npapi_test_plugin
+
+EXPORTS
+ NP_GetEntryPoints @1
+ NP_Initialize @2
+ NP_Shutdown @3
diff --git a/webkit/glue/plugins/test/npapi_test.rc b/webkit/glue/plugins/test/npapi_test.rc
new file mode 100644
index 0000000..a337ce6
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_test.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "FileDescription", "npapites Dynamic Link Library"
+ VALUE "FileVersion", "1, 0, 0, 1"
+ VALUE "InternalName", "npapites"
+ VALUE "LegalCopyright", "Copyright (C) 2007"
+ VALUE "OriginalFilename", "npapites.dll"
+ VALUE "ProductName", " npapites Dynamic Link Library"
+ VALUE "ProductVersion", "1, 0, 0, 1"
+ VALUE "MIMEType", "application/vnd.npapi-test\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/webkit/glue/plugins/test/npapi_test_plugin.vcproj b/webkit/glue/plugins/test/npapi_test_plugin.vcproj
new file mode 100644
index 0000000..ffcd76c
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_test_plugin.vcproj
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="npapi_test_plugin"
+ ProjectGUID="{0D04AEC1-6B68-492C-BCCF-808DFD69ABC6}"
+ RootNamespace="npapi_test"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops;..\..\..\build\webkit_common.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib"
+ ModuleDefinitionFile="npapi_test.def"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops;..\..\..\build\webkit_common.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib"
+ ModuleDefinitionFile="npapi_test.def"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\npapi_constants.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\npapi_constants.h"
+ >
+ </File>
+ <File
+ RelativePath=".\npapi_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\npapi_test.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_arguments_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_arguments_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_client.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_client.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_delete_plugin_in_stream_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_delete_plugin_in_stream_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_execute_script_delete_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_execute_script_delete_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_get_javascript_url_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_get_javascript_url_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_geturl_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_geturl_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_new_fails_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_new_fails_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_npobject_lifetime_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_npobject_lifetime_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_npobject_proxy_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_npobject_proxy_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_window_size_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_window_size_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/webkit/glue/plugins/test/plugin_arguments_test.cc b/webkit/glue/plugins/test/plugin_arguments_test.cc
new file mode 100644
index 0000000..dfd34e4
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_arguments_test.cc
@@ -0,0 +1,92 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+#include "webkit/glue/plugins/test/plugin_arguments_test.h"
+
+namespace NPAPIClient {
+
+PluginArgumentsTest::PluginArgumentsTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError PluginArgumentsTest::New(uint16 mode, int16 argc,
+ const char* argn[], const char* argv[],
+ NPSavedData* saved) {
+ // mode: should be the string either "NP_EMBED" or "NP_FULL",
+ // depending on the mode passed in.
+ // count: the count of "val" arguments. If the value is
+ // 2, then we'll find arguments "val1" and "val2". If
+ // the value is 0, then there will be no "val" arguments.
+ // size: each val string will be this size * the value's
+ // index. E.g if size is "10", val1 will be 10bytes,
+ // and val2 will be 20bytes.
+ const char *mode_string = GetArgValue("mode", argc, argn, argv);
+ ExpectAsciiStringNotEqual(mode_string, (const char *)NULL);
+ if (mode_string != NULL) {
+ std::string mode_dep_string = mode_string;
+ if (mode == NP_EMBED)
+ ExpectStringLowerCaseEqual(mode_dep_string, "np_embed");
+ else if (mode == NP_FULL)
+ ExpectStringLowerCaseEqual(mode_dep_string, "np_full");
+ }
+
+ const char *count_string = GetArgValue("count", argc, argn, argv);
+ if (count_string != NULL) {
+ int max_args = atoi(count_string);
+
+ const char *size_string = GetArgValue("size", argc, argn, argv);
+ ExpectAsciiStringNotEqual(size_string, (const char *)NULL);
+ if (size_string != NULL) {
+ int size = atoi(size_string);
+
+ for (int index = 1; index <= max_args; index++) {
+ char arg_name[MAX_PATH]; // Use MAX_PATH for Max Name Length
+ StringCchPrintfA(arg_name, sizeof(arg_name), "%s%d", "val", index);
+ const char *val_string = GetArgValue(arg_name, argc, argn, argv);
+ ExpectAsciiStringNotEqual(val_string, (const char*)NULL);
+ if (val_string != NULL)
+ ExpectIntegerEqual((int)strlen(val_string), (index*size));
+ }
+ }
+ }
+
+ return PluginTest::New(mode, argc, argn, argv, saved);
+}
+
+NPError PluginArgumentsTest::SetWindow(NPWindow* pNPWindow) {
+ // This test just tests the arguments. We're done now.
+ this->SignalTestCompleted();
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_arguments_test.h b/webkit/glue/plugins/test/plugin_arguments_test.h
new file mode 100644
index 0000000..57d9e6f
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_arguments_test.h
@@ -0,0 +1,69 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_ARGUMENTS_TEST_H__
+#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_ARGUMENTS_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The PluginArgumentsTest test that we properly receive arguments
+// intended for the plugin.
+//
+// This is basically overkill for testing that the arguments passed
+// to the plugin match what we expect.
+//
+// We expect to find the following arguments:
+// mode: should be the string either "NP_EMBED" or "NP_FULL",
+// depending on the mode passed in.
+// count: the count of "val" arguments. If the value is
+// 2, then we'll find arguments "val1" and "val2". If
+// the value is 0, then there will be no "val" arguments.
+// size: each val string will be this size * the value's
+// index. E.g if size is "10", val1 will be 10bytes,
+// and val2 will be 20bytes.
+//
+class PluginArgumentsTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginArgumentsTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // Initialize this PluginTest based on the arguments from NPP_New.
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_ARGUMENTS_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_client.cc b/webkit/glue/plugins/test/plugin_client.cc
new file mode 100644
index 0000000..d8d409e
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_client.cc
@@ -0,0 +1,300 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/test/plugin_client.h"
+#include "webkit/glue/plugins/test/plugin_arguments_test.h"
+#include "webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h"
+#include "webkit/glue/plugins/test/plugin_execute_script_delete_test.h"
+#include "webkit/glue/plugins/test/plugin_get_javascript_url_test.h"
+#include "webkit/glue/plugins/test/plugin_geturl_test.h"
+#include "webkit/glue/plugins/test/plugin_new_fails_test.h"
+#include "webkit/glue/plugins/test/plugin_npobject_lifetime_test.h"
+#include "webkit/glue/plugins/test/plugin_npobject_proxy_test.h"
+#include "webkit/glue/plugins/test/plugin_window_size_test.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+namespace NPAPIClient {
+
+NPNetscapeFuncs* PluginClient::host_functions_;
+
+NPError PluginClient::GetEntryPoints(NPPluginFuncs* pFuncs) {
+ if (pFuncs == NULL)
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ if (pFuncs->size < sizeof(NPPluginFuncs))
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ pFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+ pFuncs->newp = NPP_New;
+ pFuncs->destroy = NPP_Destroy;
+ pFuncs->setwindow = NPP_SetWindow;
+ pFuncs->newstream = NPP_NewStream;
+ pFuncs->destroystream = NPP_DestroyStream;
+ pFuncs->asfile = NPP_StreamAsFile;
+ pFuncs->writeready = NPP_WriteReady;
+ pFuncs->write = NPP_Write;
+ pFuncs->print = NPP_Print;
+ pFuncs->event = NPP_HandleEvent;
+ pFuncs->urlnotify = NPP_URLNotify;
+ pFuncs->getvalue = NPP_GetValue;
+ pFuncs->setvalue = NPP_SetValue;
+ pFuncs->javaClass = NPP_GetJavaClass;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginClient::Initialize(NPNetscapeFuncs* pFuncs) {
+ if (pFuncs == NULL) {
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+ }
+
+ if (HIBYTE(pFuncs->version) > NP_VERSION_MAJOR) {
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ }
+
+ host_functions_ = pFuncs;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginClient::Shutdown() {
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
+
+extern "C" {
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode,
+ int16 argc, char* argn[], char* argv[], NPSavedData* saved) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ // We look at the test name requested via the plugin arguments. We match
+ // that against a given test and try to instantiate it.
+
+ // lookup the name parameter
+ int name_index = 0;
+ for (name_index = 0; name_index < argc; name_index++)
+ if (_stricmp(argn[name_index], "name") == 0)
+ break;
+
+ if (name_index >= argc)
+ return NPERR_GENERIC_ERROR; // no name found
+
+ NPError ret = NPERR_GENERIC_ERROR;
+ bool windowless_plugin = false;
+
+ NPAPIClient::PluginTest *new_test = NULL;
+ if (_stricmp(argv[name_index], "arguments") == 0) {
+ new_test = new NPAPIClient::PluginArgumentsTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "geturl") == 0) {
+ new_test = new NPAPIClient::PluginGetURLTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "npobject_proxy") == 0) {
+ new_test = new NPAPIClient::NPObjectProxyTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "execute_script_delete_in_paint") == 0) {
+ new_test = new NPAPIClient::ExecuteScriptDeleteTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ windowless_plugin = true;
+ } else if (_stricmp(argv[name_index], "getjavascripturl") == 0) {
+ new_test = new NPAPIClient::ExecuteGetJavascriptUrlTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "checkwindowrect") == 0) {
+ new_test = new NPAPIClient::PluginWindowSizeTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "self_delete_plugin_stream") == 0) {
+ new_test = new NPAPIClient::DeletePluginInStreamTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "npobject_lifetime_test") == 0) {
+ new_test = new NPAPIClient::NPObjectLifetimeTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index],
+ "npobject_lifetime_test_second_instance") == 0) {
+ new_test = new NPAPIClient::NPObjectLifetimeTestInstance2(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "new_fails") == 0) {
+ new_test = new NPAPIClient::NewFailsTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index],
+ "npobject_delete_plugin_in_evaluate") == 0) {
+ new_test = new NPAPIClient::NPObjectDeletePluginInNPN_Evaluate(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else {
+ // If we don't have a test case for this, create a
+ // generic one which basically never fails.
+ new_test = new NPAPIClient::PluginTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ }
+
+ if (new_test) {
+ ret = new_test->New(mode, argc, (const char**)argn,
+ (const char**)argv, saved);
+ if ((ret == NPERR_NO_ERROR) && windowless_plugin) {
+ NPAPIClient::PluginClient::HostFunctions()->setvalue(
+ instance, NPPVpluginWindowBool, NULL);
+ }
+ }
+
+ return ret;
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData** save) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+ delete plugin;
+
+ // XXXMB - do work here.
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_SetWindow(NPP instance, NPWindow* pNPWindow) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ if (pNPWindow->window == NULL) {
+ return NPERR_NO_ERROR;
+ }
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->SetWindow(pNPWindow);
+}
+
+NPError NPP_NewStream(NPP instance, NPMIMEType type,
+ NPStream* stream, NPBool seekable, uint16* stype) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->NewStream(type, stream, seekable, stype);
+}
+
+int32 NPP_WriteReady(NPP instance, NPStream *stream) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->WriteReady(stream);
+}
+
+int32 NPP_Write(NPP instance, NPStream *stream, int32 offset,
+ int32 len, void *buffer) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->Write(stream, offset, len, buffer);
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->DestroyStream(stream, reason);
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {
+ if (instance == NULL)
+ return;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->StreamAsFile(stream, fname);
+}
+
+void NPP_Print(NPP instance, NPPrint* printInfo) {
+ if (instance == NULL)
+ return;
+
+ // XXXMB - do work here.
+}
+
+void NPP_URLNotify(NPP instance, const char* url, NPReason reason,
+ void* notifyData) {
+ if (instance == NULL)
+ return;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->URLNotify(url, reason, notifyData);
+}
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ // XXXMB - do work here.
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ // XXXMB - do work here.
+ return NPERR_GENERIC_ERROR;
+}
+
+int16 NPP_HandleEvent(NPP instance, void* event) {
+ if (instance == NULL)
+ return 0;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->HandleEvent(event);
+}
+
+void* NPP_GetJavaClass(void) {
+ // XXXMB - do work here.
+ return NULL;
+}
+} // extern "C"
+
+
+
+
diff --git a/webkit/glue/plugins/test/plugin_client.h b/webkit/glue/plugins/test/plugin_client.h
new file mode 100644
index 0000000..70df0fe
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_client.h
@@ -0,0 +1,71 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_CLIENT_H__
+#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_CLIENT_H__
+
+#include "webkit/glue/plugins/nphostapi.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+namespace NPAPIClient {
+
+// A PluginClient is a NPAPI Plugin. This class contains
+// the bootstrapping functions used by the browser to load
+// the plugin.
+class PluginClient {
+ public:
+ // Although not documented in the NPAPI specification, this function
+ // gets the list of entry points in the NPAPI Plugin (client) for the
+ // NPAPI Host to call.
+ static NPError GetEntryPoints(NPPluginFuncs* pFuncs);
+
+ // The browser calls this function only once: when a plug-in is loaded,
+ // before the first instance is created. This is the first function that
+ // the browser calls. NP_Initialize tells the plug-in that the browser has
+ // loaded it and provides global initialization. Allocate any memory or
+ // resources shared by all instances of your plug-in at this time.
+ static NPError Initialize(NPNetscapeFuncs* pFuncs);
+
+ // The browser calls this function once after the last instance of your
+ // plug-in is destroyed, before unloading the plug-in library itself. Use
+ // NP_Shutdown to delete any data allocated in NP_Initialize to be shared
+ // by all instances of a plug-in.
+ static NPError Shutdown();
+
+ // The table of functions provided by the host.
+ static NPNetscapeFuncs *HostFunctions() { return host_functions_; }
+
+ private:
+ static NPNetscapeFuncs* host_functions_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_CLIENT_H__
+
diff --git a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc
new file mode 100644
index 0000000..86fd917
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc
@@ -0,0 +1,67 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h"
+
+#include "webkit/glue/plugins/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+#define kUrl "javascript:window.location+\"\""
+#define kUrlStreamId 1
+
+DeletePluginInStreamTest::DeletePluginInStreamTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ test_started_(false) {
+}
+
+NPError DeletePluginInStreamTest::SetWindow(NPWindow* pNPWindow) {
+ if (!test_started_) {
+ std::string url = "self_delete_plugin_stream.html";
+ HostFunctions()->geturlnotify(id(), url.c_str(), NULL,
+ reinterpret_cast<void*>(kUrlStreamId));
+ test_started_ = true;
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError DeletePluginInStreamTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ NPIdentifier delete_id = HostFunctions()->getstringidentifier("DeletePluginWithinScript");
+
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
+
+ NPVariant rv;
+ HostFunctions()->invoke(id(), window_obj, delete_id, NULL, 0, &rv);
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h
new file mode 100644
index 0000000..8eeaefb
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h
@@ -0,0 +1,56 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests
+class DeletePluginInStreamTest : public PluginTest {
+ public:
+ // Constructor.
+ DeletePluginInStreamTest(NPP id, NPNetscapeFuncs *host_functions);
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ private:
+ bool test_started_;
+ std::string self_url_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H
+
diff --git a/webkit/glue/plugins/test/plugin_execute_script_delete_test.cc b/webkit/glue/plugins/test/plugin_execute_script_delete_test.cc
new file mode 100644
index 0000000..c18c91c
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_execute_script_delete_test.cc
@@ -0,0 +1,53 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#define STRSAFE_NO_DEPRECATE
+#include "webkit/glue/plugins/test/plugin_execute_script_delete_test.h"
+#include "webkit/glue/plugins/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+ExecuteScriptDeleteTest::ExecuteScriptDeleteTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+int16 ExecuteScriptDeleteTest::HandleEvent(void* event) {
+ NPEvent* np_event = reinterpret_cast<NPEvent*>(event);
+ if (WM_PAINT == np_event->event ) {
+ NPNetscapeFuncs* browser = NPAPIClient::PluginClient::HostFunctions();
+ NPUTF8* urlString = "javascript:DeletePluginWithinScript()";
+ NPUTF8* targetString = NULL;
+ browser->geturl(id(), urlString, targetString);
+ SignalTestCompleted();
+ }
+ // If this test failed, then we'd have crashed by now.
+ return PluginTest::HandleEvent(event);
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_execute_script_delete_test.h b/webkit/glue/plugins/test/plugin_execute_script_delete_test.h
new file mode 100644
index 0000000..fe3c6ecf
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_execute_script_delete_test.h
@@ -0,0 +1,50 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests the case where a plugin instance is deleted by invoking
+// a javascript function in the context of a paint event.
+class ExecuteScriptDeleteTest : public PluginTest {
+ public:
+ // Constructor.
+ ExecuteScriptDeleteTest(NPP id, NPNetscapeFuncs *host_functions);
+ // NPAPI HandleEvent handler
+ virtual int16 HandleEvent(void* event);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H
+
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc b/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc
new file mode 100644
index 0000000..1b6f1bd
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc
@@ -0,0 +1,134 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/test/plugin_get_javascript_url_test.h"
+
+
+// url for "self".
+#define SELF_URL "javascript:window.location+\"\""
+// The identifier for the self url stream.
+#define SELF_URL_STREAM_ID 1
+
+// The identifier for the fetched url stream.
+#define FETCHED_URL_STREAM_ID 2
+
+// The maximum chunk size of stream data.
+#define STREAM_CHUNK 197
+
+namespace NPAPIClient {
+
+ExecuteGetJavascriptUrlTest::ExecuteGetJavascriptUrlTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ test_started_(false) {
+}
+
+NPError ExecuteGetJavascriptUrlTest::SetWindow(NPWindow* pNPWindow) {
+ if (!test_started_) {
+ std::string url = SELF_URL;
+ HostFunctions()->geturlnotify(id(), url.c_str(), "_top",
+ reinterpret_cast<void*>(SELF_URL_STREAM_ID));
+ test_started_ = true;
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError ExecuteGetJavascriptUrlTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+int32 ExecuteGetJavascriptUrlTest::WriteReady(NPStream *stream) {
+ return STREAM_CHUNK;
+}
+
+int32 ExecuteGetJavascriptUrlTest::Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ if (stream == NULL)
+ SetError("Write got null stream");
+ if (len < 0 || len > STREAM_CHUNK)
+ SetError("Write got bogus stream chunk size");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ self_url_.append(static_cast<char*>(buffer), len);
+ break;
+ default:
+ SetError("Unexpected write callback");
+ break;
+ }
+ // Pretend that we took all the data.
+ return len;
+}
+
+
+NPError ExecuteGetJavascriptUrlTest::DestroyStream(NPStream *stream, NPError reason) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+void ExecuteGetJavascriptUrlTest::URLNotify(const char* url, NPReason reason, void* data) {
+ unsigned long stream_id = PtrToUlong(data);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ if (strcmp(url, SELF_URL) != 0)
+ SetError("URLNotify reported incorrect url for SELF_URL");
+ if (self_url_.empty())
+ SetError("Failed to obtain window location.");
+ SignalTestCompleted();
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url_test.h b/webkit/glue/plugins/test/plugin_get_javascript_url_test.h
new file mode 100644
index 0000000..33b627e
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_get_javascript_url_test.h
@@ -0,0 +1,63 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests NPP_GetURLNotify for a javascript URL with _top
+// as the target frame.
+class ExecuteGetJavascriptUrlTest : public PluginTest {
+ public:
+ // Constructor.
+ ExecuteGetJavascriptUrlTest(NPP id, NPNetscapeFuncs *host_functions);
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+
+ private:
+ bool test_started_;
+ std::string self_url_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H
+
diff --git a/webkit/glue/plugins/test/plugin_geturl_test.cc b/webkit/glue/plugins/test/plugin_geturl_test.cc
new file mode 100644
index 0000000..33a2f17
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_geturl_test.cc
@@ -0,0 +1,253 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/test/plugin_geturl_test.h"
+
+// url for "self". The %22%22 is to make a statement for javascript to
+// evaluate and return.
+#define SELF_URL "javascript:window.location+\"\""
+
+// The identifier for the self url stream.
+#define SELF_URL_STREAM_ID 1
+
+// The identifier for the fetched url stream.
+#define FETCHED_URL_STREAM_ID 2
+
+// url for testing GetURL with a bogus URL.
+#define BOGUS_URL "bogoproto:///x:/asdf.xysdhffieasdf.asdhj/"
+
+// The identifier for the bogus url stream.
+#define BOGUS_URL_STREAM_ID 3
+
+// The maximum chunk size of stream data.
+#define STREAM_CHUNK 197
+
+namespace NPAPIClient {
+
+PluginGetURLTest::PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ tests_started_(false),
+ tests_in_progress_(0),
+ test_file_handle_(INVALID_HANDLE_VALUE) {
+}
+
+NPError PluginGetURLTest::SetWindow(NPWindow* pNPWindow) {
+ if (!tests_started_) {
+ tests_started_ = true;
+
+ tests_in_progress_++;
+
+ std::string url = SELF_URL;
+ HostFunctions()->geturlnotify(id(), url.c_str(), NULL,
+ reinterpret_cast<void*>(SELF_URL_STREAM_ID));
+
+ tests_in_progress_++;
+ std::string bogus_url = BOGUS_URL;
+ HostFunctions()->geturlnotify(id(), bogus_url.c_str(), NULL,
+ reinterpret_cast<void*>(BOGUS_URL_STREAM_ID));
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginGetURLTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ break;
+ case FETCHED_URL_STREAM_ID:
+ {
+ std::string filename = self_url_;
+ if (filename.find("file:///", 0) != 0) {
+ SetError("Test expects a file-url.");
+ break;
+ }
+
+ filename = filename.substr(8); // remove "file:///"
+
+ test_file_handle_ = CreateFileA(filename.c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (test_file_handle_ == INVALID_HANDLE_VALUE)
+ SetError("Could not open source file");
+ }
+ break;
+ case BOGUS_URL_STREAM_ID:
+ SetError("Unexpected NewStream for BOGUS_URL");
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+int32 PluginGetURLTest::WriteReady(NPStream *stream) {
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ if (stream_id == BOGUS_URL_STREAM_ID)
+ SetError("Received WriteReady for BOGUS_URL");
+
+ return STREAM_CHUNK;
+}
+
+int32 PluginGetURLTest::Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ if (stream == NULL)
+ SetError("Write got null stream");
+ if (len < 0 || len > STREAM_CHUNK)
+ SetError("Write got bogus stream chunk size");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ self_url_.append(static_cast<char*>(buffer), len);
+ break;
+ case FETCHED_URL_STREAM_ID:
+ {
+ char read_buffer[STREAM_CHUNK];
+ DWORD bytes = 0;
+ if (!ReadFile(test_file_handle_, read_buffer, len,
+ &bytes, NULL))
+ SetError("Could not read data from source file");
+ // Technically, readfile could return fewer than len
+ // bytes. But this is not likely.
+ if (bytes != len)
+ SetError("Did not read correct bytelength from source file");
+ if (memcmp(read_buffer, buffer, len))
+ SetError("Content mismatch between data and source!");
+ }
+ break;
+ case BOGUS_URL_STREAM_ID:
+ SetError("Unexpected write callback for BOGUS_URL");
+ break;
+ default:
+ SetError("Unexpected write callback");
+ break;
+ }
+ // Pretend that we took all the data.
+ return len;
+}
+
+
+NPError PluginGetURLTest::DestroyStream(NPStream *stream, NPError reason) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ case FETCHED_URL_STREAM_ID:
+ {
+ char read_buffer[STREAM_CHUNK];
+ DWORD bytes = 0;
+ if (!ReadFile(test_file_handle_, read_buffer, sizeof(read_buffer),
+ &bytes, NULL))
+ SetError("Could not read data from source file");
+ if (bytes != 0)
+ SetError("Data and source mismatch on length");
+ CloseHandle(test_file_handle_);
+ }
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+void PluginGetURLTest::StreamAsFile(NPStream* stream, const char* fname) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+}
+
+void PluginGetURLTest::URLNotify(const char* url, NPReason reason, void* data) {
+ if (!tests_in_progress_) {
+ SetError("URLNotify received after tests completed");
+ return;
+ }
+
+ if (!url) {
+ SetError("URLNotify received NULL url");
+ return;
+ }
+
+ unsigned long stream_id = PtrToUlong(data);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ if (strcmp(url, SELF_URL) != 0)
+ SetError("URLNotify reported incorrect url for SELF_URL");
+
+ // We have our stream url. Go fetch it.
+ HostFunctions()->geturlnotify(id(), self_url_.c_str(), NULL,
+ reinterpret_cast<void*>(FETCHED_URL_STREAM_ID));
+ break;
+ case FETCHED_URL_STREAM_ID:
+ if (!url || strcmp(url, self_url_.c_str()) != 0)
+ SetError("URLNotify reported incorrect url for FETCHED_URL");
+ tests_in_progress_--;
+ break;
+ case BOGUS_URL_STREAM_ID:
+ if (reason != NPRES_NETWORK_ERR) {
+ std::string err = "BOGUS_URL received unexpected URLNotify status: ";
+ char buf[10];
+ _itoa_s(reason, buf, 10, 10);
+ err.append(buf);
+ SetError(err);
+ }
+ tests_in_progress_--;
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+
+ if (tests_in_progress_ == 0)
+ SignalTestCompleted();
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_geturl_test.h b/webkit/glue/plugins/test/plugin_geturl_test.h
new file mode 100644
index 0000000..07e41aa
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_geturl_test.h
@@ -0,0 +1,71 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_GETURL_TEST_H__
+#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_GETURL_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The PluginGetURLTest test functionality of the NPN_GetURL
+// and NPN_GetURLNotify methods.
+//
+// This test first discovers it's URL by sending a GetURL request
+// for 'javascript:top.location'. After receiving that, the
+// test will request the url itself (again via GetURL).
+class PluginGetURLTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void StreamAsFile(NPStream* stream, const char* fname);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+
+ private:
+ bool tests_started_;
+ int tests_in_progress_;
+ std::string self_url_;
+ HANDLE test_file_handle_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_GETURL_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_new_fails_test.cc b/webkit/glue/plugins/test/plugin_new_fails_test.cc
new file mode 100644
index 0000000..382bf4e
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_new_fails_test.cc
@@ -0,0 +1,43 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/test/plugin_new_fails_test.h"
+
+namespace NPAPIClient {
+
+NewFailsTest::NewFailsTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError NewFailsTest::New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved) {
+ return NPERR_GENERIC_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_new_fails_test.h b/webkit/glue/plugins/test/plugin_new_fails_test.h
new file mode 100644
index 0000000..e864553
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_new_fails_test.h
@@ -0,0 +1,46 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PLUGIN_NEW_FAILS_TEST_H__
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PLUGIN_NEW_FAILS_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+class NewFailsTest : public PluginTest {
+ public:
+ NewFailsTest(NPP id, NPNetscapeFuncs *host_functions);
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PLUGIN_NPP_NEW_FAILS_TEST_H__
diff --git a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
new file mode 100644
index 0000000..24cc9e9
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
@@ -0,0 +1,189 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/test/plugin_npobject_lifetime_test.h"
+
+namespace NPAPIClient {
+
+const int kNPObjectLifetimeTimer = 100;
+const int kNPObjectLifetimeTimerElapse = 2000;
+
+NPObject* NPObjectLifetimeTestInstance2::plugin_instance_object_ = NULL;
+
+NPObjectDeletePluginInNPN_Evaluate*
+ NPObjectDeletePluginInNPN_Evaluate::g_npn_evaluate_test_instance_ = NULL;
+
+NPObjectLifetimeTest::NPObjectLifetimeTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ other_plugin_instance_object_(NULL) {
+}
+
+NPError NPObjectLifetimeTest::SetWindow(NPWindow* pNPWindow) {
+ HWND window_handle = reinterpret_cast<HWND>(pNPWindow->window);
+ if (!::GetProp(window_handle, L"Plugin_Instance")) {
+ ::SetProp(window_handle, L"Plugin_Instance", this);
+ // We attempt to retreive the NPObject for the plugin instance identified
+ // by the NPObjectLifetimeTestInstance2 class as it may not have been
+ // instantiated yet.
+ SetTimer(window_handle, kNPObjectLifetimeTimer, kNPObjectLifetimeTimerElapse,
+ TimerProc);
+ }
+ return NPERR_NO_ERROR;
+}
+
+void CALLBACK NPObjectLifetimeTest::TimerProc(
+ HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds) {
+
+ KillTimer(window, kNPObjectLifetimeTimer);
+ NPObjectLifetimeTest* this_instance =
+ reinterpret_cast<NPObjectLifetimeTest*>
+ (::GetProp(window, L"Plugin_Instance"));
+
+ this_instance->other_plugin_instance_object_ =
+ NPObjectLifetimeTestInstance2::plugin_instance_object_;
+ this_instance->HostFunctions()->retainobject(
+ this_instance->other_plugin_instance_object_);
+
+ NPString script;
+ script.UTF8Characters = "javascript:DeleteSecondPluginInstance()";
+ script.UTF8Length = static_cast<uint32_t>(strlen(script.UTF8Characters));
+
+ this_instance->HostFunctions()->geturlnotify(
+ this_instance->id(), "javascript:DeleteSecondPluginInstance()", NULL,
+ reinterpret_cast<void*>(1));
+}
+
+void NPObjectLifetimeTest::URLNotify(const char* url, NPReason reason,
+ void* data) {
+ // Create a "location" identifier.
+ NPIdentifier identifier = HostFunctions()->getstringidentifier("location");
+ // Declare a local variant value.
+ NPVariant variantValue;
+ // Get the location property from the window object (which is another object).
+ bool b1 = HostFunctions()->getproperty(id(), other_plugin_instance_object_,
+ identifier, &variantValue );
+ HostFunctions()->releaseobject(other_plugin_instance_object_);
+ other_plugin_instance_object_ = NULL;
+ // If this test failed, then we'd have crashed by now.
+ SignalTestCompleted();
+}
+
+NPObjectLifetimeTestInstance2::NPObjectLifetimeTestInstance2(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPObjectLifetimeTestInstance2::~NPObjectLifetimeTestInstance2() {
+ if (plugin_instance_object_) {
+ HostFunctions()->releaseobject(plugin_instance_object_);
+ plugin_instance_object_ = NULL;
+ }
+}
+
+NPError NPObjectLifetimeTestInstance2::SetWindow(NPWindow* pNPWindow) {
+ if (!plugin_instance_object_) {
+ if (!HostFunctions()->getvalue(id(), NPNVWindowNPObject,
+ &plugin_instance_object_)) {
+ SetError("Failed to get NPObject for plugin instance2");
+ SignalTestCompleted();
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+
+NPObjectDeletePluginInNPN_Evaluate::NPObjectDeletePluginInNPN_Evaluate(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ plugin_instance_object_(NULL),
+ npn_evaluate_timer_proc_set_(false) {
+ g_npn_evaluate_test_instance_ = this;
+}
+
+NPObjectDeletePluginInNPN_Evaluate::~NPObjectDeletePluginInNPN_Evaluate() {
+ if (plugin_instance_object_) {
+ HostFunctions()->releaseobject(plugin_instance_object_);
+ plugin_instance_object_ = NULL;
+ }
+}
+
+NPError NPObjectDeletePluginInNPN_Evaluate::SetWindow(NPWindow* np_window) {
+ if (!::IsWindowVisible(reinterpret_cast<HWND>(np_window->window)))
+ return NPERR_NO_ERROR;
+
+ HWND window_handle = reinterpret_cast<HWND>(np_window->window);
+ // We setup a timerproc to invoke NPN_Evaluate to destroy this plugin
+ // instance. This is to ensure that we don't destroy the plugin instance
+ // while it is being used in webkit as this leads to crashes and is a
+ // more accurate representation of the renderer crash as described in
+ // http://b/issue?id=1134683.
+ if (!npn_evaluate_timer_proc_set_) {
+ npn_evaluate_timer_proc_set_ = true;
+ SetTimer(window_handle, kNPObjectLifetimeTimer, kNPObjectLifetimeTimerElapse,
+ TimerProc);
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+void CALLBACK NPObjectDeletePluginInNPN_Evaluate::TimerProc(
+ HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds) {
+
+ KillTimer(window, kNPObjectLifetimeTimer);
+ NPObject *window_obj = NULL;
+ g_npn_evaluate_test_instance_->HostFunctions()->getvalue(
+ g_npn_evaluate_test_instance_->id(), NPNVWindowNPObject,
+ &window_obj);
+
+ if (!window_obj) {
+ g_npn_evaluate_test_instance_->SetError(
+ "Failed to get NPObject for plugin instance2");
+ g_npn_evaluate_test_instance_->SignalTestCompleted();
+ return;
+ }
+
+ std::string script = "javascript:DeletePluginWithinScript()";
+ NPString script_string;
+ script_string.UTF8Characters = script.c_str();
+ script_string.UTF8Length =
+ static_cast<unsigned int>(script.length());
+
+ NPVariant result_var;
+ NPError result = g_npn_evaluate_test_instance_->HostFunctions()->evaluate(
+ g_npn_evaluate_test_instance_->id(), window_obj,
+ &script_string, &result_var);
+ // If this test failed we would have crashed by now.
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h
new file mode 100644
index 0000000..2a5d808
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h
@@ -0,0 +1,96 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H__
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The NPObjectLifeTime class tests the case where a plugin has an NPObject
+// which points to a different plugin instance on a different frame in the
+// page and whether refcounts on this npobject are valid when the source frame
+// is destroyed.
+class NPObjectLifetimeTest : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectLifetimeTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+
+ protected:
+ NPObject* other_plugin_instance_object_;
+ static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds);
+};
+
+// The NPObjectLifetimeTestInstance2 class represents the plugin instance
+// which is deleted by the NPObjectLifeTime class via a javascript function.
+class NPObjectLifetimeTestInstance2 : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectLifetimeTestInstance2(NPP id, NPNetscapeFuncs *host_functions);
+ ~NPObjectLifetimeTestInstance2();
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ protected:
+ static NPObject* plugin_instance_object_;
+ friend class NPObjectLifetimeTest;
+
+};
+
+// The NPObjectLifeTime class tests the case where a plugin instance is
+// destroyed in NPN_Evaluate
+class NPObjectDeletePluginInNPN_Evaluate : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectDeletePluginInNPN_Evaluate(NPP id, NPNetscapeFuncs *host_functions);
+ ~NPObjectDeletePluginInNPN_Evaluate();
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+
+ protected:
+ NPObject* plugin_instance_object_;
+ static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds);
+ private:
+ bool npn_evaluate_timer_proc_set_;
+ static NPObjectDeletePluginInNPN_Evaluate* g_npn_evaluate_test_instance_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc b/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc
new file mode 100644
index 0000000..e7fa2fb
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc
@@ -0,0 +1,68 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+#include "webkit/glue/plugins/test/plugin_npobject_proxy_test.h"
+
+namespace NPAPIClient {
+
+NPObjectProxyTest::NPObjectProxyTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError NPObjectProxyTest::SetWindow(NPWindow* pNPWindow) {
+ NPIdentifier document_id = HostFunctions()->getstringidentifier("document");
+ NPIdentifier create_text_node_id = HostFunctions()->getstringidentifier("createTextNode");
+ NPIdentifier append_child_id = HostFunctions()->getstringidentifier("appendChild");
+
+ NPVariant docv;
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
+
+ HostFunctions()->getproperty(id(), window_obj, document_id, &docv);
+ NPObject *doc = NPVARIANT_TO_OBJECT(docv);
+
+ NPVariant strv;
+#pragma warning(suppress: 4267)
+ STRINGZ_TO_NPVARIANT("div", strv);
+
+ NPVariant textv;
+ HostFunctions()->invoke(id(), doc, create_text_node_id, &strv, 1, &textv);
+
+ NPVariant v;
+ HostFunctions()->invoke(id(), doc, append_child_id, &textv, 1, &v);
+
+ // If this test failed, then we'd have crashed by now.
+ SignalTestCompleted();
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_npobject_proxy_test.h b/webkit/glue/plugins/test/plugin_npobject_proxy_test.h
new file mode 100644
index 0000000..e5c94d4
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_npobject_proxy_test.h
@@ -0,0 +1,53 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H__
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The NPObjectProxyTest tests that when we proxy an NPObject that is itself
+// a proxy, we don't create a new proxy but instead just use the original
+// pointer.
+
+class NPObjectProxyTest : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectProxyTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_test.cc b/webkit/glue/plugins/test/plugin_test.cc
new file mode 100644
index 0000000..043fef9
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_test.cc
@@ -0,0 +1,160 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+#include "webkit/glue/plugins/test/npapi_constants.h"
+
+namespace NPAPIClient {
+
+PluginTest::PluginTest(NPP id, NPNetscapeFuncs *host_functions) {
+ id_ = id;
+ id_->pdata = this;
+ host_functions_ = host_functions;
+}
+
+NPError PluginTest::New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved) {
+ test_name_ = this->GetArgValue("name", argc, argn, argv);
+ test_id_ = this->GetArgValue("id", argc, argn, argv);
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginTest::SetWindow(NPWindow* pNPWindow) {
+ return NPERR_NO_ERROR;
+}
+
+// It's a shame I have to implement URLEncode. But, using webkit's
+// or using chrome's means a ball of string of dlls and dependencies that
+// is very very long. After spending far too much time on it,
+// I'll just encode it myself. Too bad Microsoft doesn't implement
+// this in a reusable way either. Both webkit and chrome will
+// end up using libicu, which is a string of dependencies we don't
+// want.
+
+inline BYTE toHex(const BYTE &x) {
+ return x > 9 ? x + 55: x + 48;
+}
+
+std::string URLEncode(const std::string &sIn) {
+ std::string sOut;
+
+ const size_t length = sIn.length();
+ for (size_t idx = 0; idx < length;) {
+ const char ch = sIn.at(idx);
+ if (isalnum(ch)) {
+ sOut.append(1, ch);
+ } else if (isspace(ch) && ((ch != '\n') && (ch != '\r'))) {
+ sOut.append(1, '+');
+ } else {
+ sOut.append(1, '%');
+ sOut.append(1, toHex(ch>>4));
+ sOut.append(1, toHex(ch%16));
+ }
+ idx++;
+ }
+ return sOut;
+}
+
+void PluginTest::SignalTestCompleted() {
+ // To signal test completion, we expect a couple of
+ // javascript functions to be defined in the webpage
+ // which hosts this plugin:
+ // onSuccess(test_name, test_id)
+ // onFailure(test_name, test_id, error_message)
+ std::string script_result;
+ std::string script_url;
+ if (Succeeded()) {
+ script_url.append("onSuccess(\"");
+ script_url.append(test_name_);
+ script_url.append("\",\"");
+ script_url.append(test_id_);
+ script_url.append("\");");
+ } else {
+ script_url.append("onFailure(\"");
+ script_url.append(test_name_);
+ script_url.append("\",\"");
+ script_url.append(test_id_);
+ script_url.append("\",\"");
+ script_url.append(test_status_);
+ script_url.append("\");");
+ }
+ script_url = URLEncode(script_url);
+ script_result.append("javascript:");
+ script_result.append(script_url);
+ host_functions_->geturl(id_, script_result.c_str(), "_self");
+}
+
+const char *PluginTest::GetArgValue(const char *name, const int16 argc,
+ const char *argn[], const char *argv[]) {
+ for (int idx = 0; idx < argc; idx++)
+ if (_stricmp(argn[idx], name) == 0)
+ return argv[idx];
+ return NULL;
+}
+
+void PluginTest::SetError(const std::string &msg) {
+ test_status_.append(msg);
+}
+
+NPError PluginTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ // There is no default action here.
+ return NPERR_NO_ERROR;
+}
+
+int32 PluginTest::WriteReady(NPStream *stream) {
+ // Take data in small chunks
+ return 4096;
+}
+
+int32 PluginTest::Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ // Pretend that we took all the data.
+ return len;
+}
+
+NPError PluginTest::DestroyStream(NPStream *stream, NPError reason) {
+ // There is no default action.
+ return NPERR_NO_ERROR;
+}
+
+void PluginTest::StreamAsFile(NPStream* stream, const char* fname) {
+ // There is no default action.
+}
+
+void PluginTest::URLNotify(const char* url, NPReason reason, void* data) {
+ // There is no default action
+}
+
+int16 PluginTest::HandleEvent(void* event) {
+ // There is no default action
+ return 0;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_test.h b/webkit/glue/plugins/test/plugin_test.h
new file mode 100644
index 0000000..0cdc1b7
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_test.h
@@ -0,0 +1,153 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H__
+#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H__
+
+#include <string>
+
+#include "base/string_util.h"
+#include "webkit/glue/plugins/nphostapi.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+namespace NPAPIClient {
+
+// A PluginTest represents an instance of the plugin, which in
+// our case is a test case.
+class PluginTest {
+ public:
+ // Constructor.
+ PluginTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // Destructor
+ virtual ~PluginTest() {}
+
+ //
+ // NPAPI Functions
+ //
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void StreamAsFile(NPStream* stream, const char* fname);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+ virtual int16 HandleEvent(void* event);
+ // Returns true if the test has not had any errors.
+ bool Succeeded() { return test_status_.length() == 0; }
+
+ // Sets an error for the test case. Appends the msg to the
+ // error that will be returned from the test.
+ void SetError(const std::string &msg);
+
+ // Expect two string values are equal, and if not, logs an
+ // appropriate error about it.
+ void ExpectStringLowerCaseEqual(const std::string &val1, const std::string &val2) {
+ if (!LowerCaseEqualsASCII(val1, val2.c_str())) {
+ std::string err;
+ err = "Expected Equal for '";
+ err.append(val1);
+ err.append("' and '");
+ err.append(val2);
+ err.append("'");
+ SetError(err);
+ }
+ };
+
+ // Expect two values to not be equal, and if they are
+ // logs an appropriate error about it.
+ void ExpectAsciiStringNotEqual(const char *val1, const char *val2) {
+ if (val1 == val2) {
+ std::string err;
+ err = "Expected Not Equal for '";
+ err.append(val1);
+ err.append("' and '");
+ err.append(val2);
+ err.append("'");
+ SetError(err);
+ }
+ }
+ // Expect two integer values are equal, and if not, logs an
+ // appropriate error about it.
+ void ExpectIntegerEqual(int val1, int val2) {
+ if (val1 != val2) {
+ std::string err;
+ char buf[64]; // what's the right size?
+ err = "Expected Equal for '";
+ sprintf_s(buf, "%d", val1);
+ err.append(buf);
+ err.append("' and '");
+ sprintf_s(buf, "%d", val2);
+ err.append(buf);
+ err.append("'");
+ SetError(err);
+ }
+ }
+
+
+ protected:
+ // Signals to the Test that invoked us that the test is
+ // completed. This is done by forcing the plugin to
+ // set a cookie in the browser window, which the test program
+ // is waiting for. Note - because this is done by
+ // using javascript, the browser must have the frame
+ // setup before the plugin calls this function. So plugin
+ // tests MUST NOT call this function prior to having
+ // received the SetWindow() callback from the browser.
+ void SignalTestCompleted();
+
+ // Helper function to lookup names in the input array.
+ // If the name is found, returns the value, otherwise
+ // returns NULL.
+ const char *GetArgValue(const char *name, const int16 argc,
+ const char *argn[], const char *argv[]);
+
+ // Access to the list of functions provided
+ // by the NPAPI host.
+ NPNetscapeFuncs *HostFunctions() { return host_functions_; }
+
+ // The NPP Identifier for this plugin instance.
+ NPP id() { return id_; }
+
+ private:
+ NPP id_;
+ NPNetscapeFuncs * host_functions_;
+ std::string test_name_;
+ std::string test_id_;
+ std::string test_status_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_window_size_test.cc b/webkit/glue/plugins/test/plugin_window_size_test.cc
new file mode 100644
index 0000000..33aeafa
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_window_size_test.cc
@@ -0,0 +1,67 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/test/plugin_window_size_test.h"
+#include "webkit/glue/plugins/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+PluginWindowSizeTest::PluginWindowSizeTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError PluginWindowSizeTest::SetWindow(NPWindow* pNPWindow) {
+ if (!pNPWindow ||
+ !::IsWindow(reinterpret_cast<HWND>(pNPWindow->window))) {
+ SetError("Invalid arguments passed in");
+ return NPERR_INVALID_PARAM;
+ }
+
+ RECT window_rect = {0};
+ window_rect.left = pNPWindow->x;
+ window_rect.top = pNPWindow->y;
+ window_rect.right = pNPWindow->width;
+ window_rect.bottom = pNPWindow->height;
+
+ if (!::IsRectEmpty(&window_rect)) {
+ RECT client_rect = {0};
+ ::GetClientRect(reinterpret_cast<HWND>(pNPWindow->window),
+ &client_rect);
+ if (::IsRectEmpty(&client_rect)) {
+ SetError("The client rect of the plugin window is empty. Test failed");
+ }
+
+ SignalTestCompleted();
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_window_size_test.h b/webkit/glue/plugins/test/plugin_window_size_test.h
new file mode 100644
index 0000000..13b50aa
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_window_size_test.h
@@ -0,0 +1,50 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOW_SIZE_TEST_H
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOW_SIZE_TEST_H
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests whether the plugin window has a non zero rect
+// on the second SetWindow call.
+class PluginWindowSizeTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginWindowSizeTest(NPP id, NPNetscapeFuncs *host_functions);
+ // NPAPI SetWindow handler
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOW_SIZE_TEST_H
+
diff --git a/webkit/glue/plugins/test/resource.h b/webkit/glue/plugins/test/resource.h
new file mode 100644
index 0000000..2f2bf3b
--- /dev/null
+++ b/webkit/glue/plugins/test/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by npapitest.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.cc b/webkit/glue/plugins/webplugin_delegate_impl.cc
new file mode 100644
index 0000000..774cad7
--- /dev/null
+++ b/webkit/glue/plugins/webplugin_delegate_impl.cc
@@ -0,0 +1,1081 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "webkit/glue/plugins/webplugin_delegate_impl.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/gfx/point.h"
+#include "base/stats_counters.h"
+#include "webkit/default_plugin/plugin_impl.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/glue/plugins/plugin_stream_url.h"
+
+static StatsCounter windowless_queue(L"Plugin.ThrottleQueue");
+
+static const wchar_t kNativeWindowClassName[] = L"NativeWindowClass";
+static const wchar_t kWebPluginDelegateProperty[] =
+ L"WebPluginDelegateProperty";
+static const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom";
+static const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation";
+static const wchar_t kPluginOrigProc[] = L"OriginalPtr";
+static const wchar_t kPluginFlashThrottle[] = L"FlashThrottle";
+
+// The fastest we are willing to process WM_USER+1 events for Flash.
+// Flash can easily exceed the limits of our CPU if we don't throttle it.
+// The throttle has been chosen by testing various delays and compromising
+// on acceptable Flash performance and reasonable CPU consumption.
+//
+// I'd like to make the throttle delay variable, based on the amount of
+// time currently required to paint Flash plugins. There isn't a good
+// way to count the time spent in aggregate plugin painting, however, so
+// this seems to work well enough.
+static const int kFlashWMUSERMessageThrottleDelayMs = 5;
+
+std::list<MSG> WebPluginDelegateImpl::throttle_queue_;
+
+WebPluginDelegateImpl* WebPluginDelegateImpl::current_plugin_instance_ = NULL;
+
+WebPluginDelegateImpl* WebPluginDelegateImpl::Create(
+ const std::wstring& filename,
+ const std::string& mime_type,
+ HWND containing_window) {
+ scoped_refptr<NPAPI::PluginLib> plugin =
+ NPAPI::PluginLib::CreatePluginLib(filename);
+ if (plugin.get() == NULL)
+ return NULL;
+
+ NPError err = plugin->NP_Initialize();
+ if (err != NPERR_NO_ERROR)
+ return NULL;
+
+ scoped_refptr<NPAPI::PluginInstance> instance =
+ plugin->CreateInstance(mime_type);
+ return new WebPluginDelegateImpl(containing_window, instance.get());
+}
+
+bool WebPluginDelegateImpl::IsPluginDelegateWindow(HWND window) {
+ // We use a buffer that is one char longer than we need to detect cases where
+ // kNativeWindowClassName is a prefix of the given window's class name. It
+ // happens that GetClassNameW will just silently truncate the class name to
+ // fit into the given buffer.
+ wchar_t class_name[arraysize(kNativeWindowClassName) + 1];
+ if (!GetClassNameW(window, class_name, arraysize(class_name)))
+ return false;
+ return wcscmp(class_name, kNativeWindowClassName) == 0;
+}
+
+bool WebPluginDelegateImpl::GetPluginNameFromWindow(
+ HWND window, std::wstring *plugin_name) {
+ if (NULL == plugin_name) {
+ return false;
+ }
+ if (!IsPluginDelegateWindow(window)) {
+ return false;
+ }
+ ATOM plugin_name_atom = reinterpret_cast<ATOM>(
+ GetPropW(window, kPluginNameAtomProperty));
+ if (plugin_name_atom != 0) {
+ WCHAR plugin_name_local[MAX_PATH] = {0};
+ GlobalGetAtomNameW(plugin_name_atom,
+ plugin_name_local,
+ ARRAYSIZE(plugin_name_local));
+ *plugin_name = plugin_name_local;
+ return true;
+ }
+ return false;
+}
+
+bool WebPluginDelegateImpl::IsDummyActivationWindow(HWND window) {
+ if (!IsWindow(window))
+ return false;
+
+ wchar_t window_title[MAX_PATH + 1] = {0};
+ if (GetWindowText(window, window_title, arraysize(window_title))) {
+ return (0 == lstrcmpiW(window_title, kDummyActivationWindowName));
+ }
+ return false;
+}
+
+LRESULT CALLBACK WebPluginDelegateImpl::HandleEventMessageFilterHook(
+ int code, WPARAM wParam, LPARAM lParam) {
+
+ DCHECK(current_plugin_instance_);
+ current_plugin_instance_->OnModalLoopEntered();
+ return CallNextHookEx(NULL, code, wParam, lParam);
+}
+
+WebPluginDelegateImpl::WebPluginDelegateImpl(
+ HWND containing_window,
+ NPAPI::PluginInstance *instance)
+ : parent_(containing_window),
+ instance_(instance),
+ quirks_(0),
+ plugin_(NULL),
+ windowless_(false),
+ windowed_handle_(NULL),
+ windowed_did_set_window_(false),
+ windowless_needs_set_window_(true),
+ plugin_wnd_proc_(NULL),
+ last_message_(0),
+ is_calling_wndproc(false),
+ initial_plugin_resize_done_(false),
+ dummy_window_for_activation_(NULL),
+ handle_event_message_filter_hook_(NULL),
+ handle_event_pump_messages_event_(NULL),
+ handle_event_depth_(0),
+ user_gesture_message_posted_(false),
+#pragma warning(suppress: 4355) // can use this
+ user_gesture_msg_factory_(this),
+ load_manually_(false),
+ first_geometry_update_(true) {
+ memset(&window_, 0, sizeof(window_));
+
+ const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
+ std::wstring filename = file_util::GetFilenameFromPath(plugin_info.file);
+
+ if (instance_->mime_type() == "application/x-shockwave-flash" ||
+ filename == L"npswf32.dll") {
+ // Flash only requests windowless plugins if we return a Mozilla user
+ // agent.
+ instance_->set_use_mozilla_user_agent();
+ instance_->set_throttle_invalidate(true);
+ quirks_ |= PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE;
+ } else if (plugin_info.name.find(L"Windows Media Player") !=
+ std::wstring::npos) {
+ // Windows Media Player needs two NPP_SetWindow calls.
+ quirks_ |= PLUGIN_QUIRK_SETWINDOW_TWICE;
+ } else if (instance_->mime_type() == "audio/x-pn-realaudio-plugin" ||
+ filename == L"nppl3260.dll") {
+ quirks_ |= PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY;
+ } else if (plugin_info.name.find(L"VLC Multimedia Plugin") !=
+ std::wstring::npos) {
+ // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window
+ // handle
+ quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY;
+ // VLC 0.8.6d and 0.8.6e crash if multiple instances are created.
+ quirks_ |= PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES;
+ }
+}
+
+WebPluginDelegateImpl::~WebPluginDelegateImpl() {
+ if (::IsWindow(dummy_window_for_activation_)) {
+ ::DestroyWindow(dummy_window_for_activation_);
+ }
+
+ DestroyInstance();
+
+ if (!windowless_)
+ WindowedDestroyWindow();
+
+ if (handle_event_pump_messages_event_) {
+ CloseHandle(handle_event_pump_messages_event_);
+ }
+}
+
+void WebPluginDelegateImpl::PluginDestroyed() {
+ delete this;
+}
+
+bool WebPluginDelegateImpl::Initialize(const GURL& url,
+ char** argn,
+ char** argv,
+ int argc,
+ WebPlugin* plugin,
+ bool load_manually) {
+ plugin_ = plugin;
+
+ instance_->set_web_plugin(plugin);
+ NPAPI::PluginInstance* old_instance =
+ NPAPI::PluginInstance::SetInitializingInstance(instance_);
+
+ if (quirks_ & PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES) {
+ NPAPI::PluginLib* plugin_lib = instance()->plugin_lib();
+ if (plugin_lib->instance_count() > 1) {
+ return false;
+ }
+ }
+
+ bool start_result = instance_->Start(url, argn, argv, argc, load_manually);
+
+ NPAPI::PluginInstance::SetInitializingInstance(old_instance);
+
+ if (!start_result)
+ return false;
+
+ windowless_ = instance_->windowless();
+ if (windowless_) {
+ // For windowless plugins we should set the containing window handle
+ // as the instance window handle. This is what Safari does. Not having
+ // a valid window handle causes subtle bugs with plugins which retreive
+ // the window handle and validate the same. The window handle can be
+ // retreived via NPN_GetValue of NPNVnetscapeWindow.
+ instance_->set_window_handle(parent_);
+ CreateDummyWindowForActivation();
+ handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
+ } else {
+ if (!WindowedCreatePlugin())
+ return false;
+ }
+
+ plugin->SetWindow(windowed_handle_, handle_event_pump_messages_event_);
+
+ load_manually_ = load_manually;
+ plugin_url_ = url.spec();
+ return true;
+}
+
+void WebPluginDelegateImpl::DestroyInstance() {
+ if (instance_ && (instance_->npp()->ndata != NULL)) {
+ // Shutdown all streams before destroying so that
+ // no streams are left "in progress". Need to do
+ // this before calling set_web_plugin(NULL) because the
+ // instance uses the helper to do the download.
+ instance_->CloseStreams();
+
+ window_.window = NULL;
+ if (!(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) {
+ instance_->NPP_SetWindow(&window_);
+ }
+
+ instance_->NPP_Destroy();
+
+ instance_->set_web_plugin(NULL);
+
+ instance_ = 0;
+ }
+}
+
+void WebPluginDelegateImpl::UpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ if (windowless_) {
+ window_.window =
+ reinterpret_cast<void *>(::GetDC(instance_->window_handle()));
+ WindowlessUpdateGeometry(window_rect, clip_rect);
+ ::ReleaseDC(instance_->window_handle(),
+ reinterpret_cast<HDC>(window_.window));
+ } else {
+ WindowedUpdateGeometry(window_rect, clip_rect, visible);
+ }
+
+ // Initiate a download on the plugin url. This should be done for the
+ // first update geometry sequence.
+ if (first_geometry_update_) {
+ first_geometry_update_ = false;
+ // An empty url corresponds to an EMBED tag with no src attribute.
+ if (!load_manually_ && !plugin_url_.empty()) {
+ instance_->SendStream(plugin_url_.c_str(), false, NULL);
+ }
+ }
+}
+
+void WebPluginDelegateImpl::Paint(HDC hdc, const gfx::Rect& rect) {
+ if (windowless_)
+ WindowlessPaint(hdc, rect);
+}
+
+void WebPluginDelegateImpl::Print(HDC hdc) {
+ // Disabling the call to NPP_Print as it causes a crash in
+ // flash in some cases. In any case this does not work as expected
+ // as the EMF meta file dc passed in needs to be created with the
+ // the plugin window dc as its sibling dc and the window rect
+ // in .01 mm units.
+#if 0
+ NPPrint npprint;
+ npprint.mode = NP_EMBED;
+ npprint.print.embedPrint.platformPrint = reinterpret_cast<void*>(hdc);
+ npprint.print.embedPrint.window = window_;
+ instance()->NPP_Print(&npprint);
+#endif
+}
+
+NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
+ return instance_->GetPluginScriptableObject();
+}
+
+void WebPluginDelegateImpl::DidFinishLoadWithReason(NPReason reason) {
+ instance()->DidFinishLoadWithReason(reason);
+}
+
+int WebPluginDelegateImpl::GetProcessId() {
+ // We are in process, so the plugin pid is this current process pid.
+ return ::GetCurrentProcessId();
+}
+
+HWND WebPluginDelegateImpl::GetWindowHandle() {
+ return instance()->window_handle();
+}
+
+void WebPluginDelegateImpl::SendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success,
+ bool notify_needed,
+ int notify_data) {
+ instance()->SendJavaScriptStream(url, result, success, notify_needed,
+ notify_data);
+}
+
+void WebPluginDelegateImpl::DidReceiveManualResponse(
+ const std::string& url, const std::string& mime_type,
+ const std::string& headers, uint32 expected_length, uint32 last_modified) {
+ instance()->DidReceiveManualResponse(url, mime_type, headers,
+ expected_length, last_modified);
+}
+
+void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
+ int length) {
+ instance()->DidReceiveManualData(buffer, length);
+}
+
+void WebPluginDelegateImpl::DidFinishManualLoading() {
+ instance()->DidFinishManualLoading();
+}
+
+void WebPluginDelegateImpl::DidManualLoadFail() {
+ instance()->DidManualLoadFail();
+}
+
+std::wstring WebPluginDelegateImpl::GetPluginPath() {
+ return instance()->plugin_lib()->plugin_info().file;
+}
+
+void WebPluginDelegateImpl::InstallMissingPlugin() {
+ NPEvent evt;
+ evt.event = PluginInstallerImpl::kInstallMissingPluginMessage;
+ evt.lParam = 0;
+ evt.wParam = 0;
+ instance()->NPP_HandleEvent(&evt);
+}
+
+void WebPluginDelegateImpl::WindowedUpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ if (WindowedReposition(window_rect, clip_rect, visible) ||
+ !windowed_did_set_window_) {
+ // Let the plugin know that it has been moved
+ WindowedSetWindow();
+ }
+}
+
+bool WebPluginDelegateImpl::WindowedCreatePlugin() {
+ DCHECK(!windowed_handle_);
+
+ RegisterNativeWindowClass();
+
+ // The window will be sized and shown later.
+ windowed_handle_ = CreateWindowEx(
+ WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
+ kNativeWindowClassName,
+ 0,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ 0,
+ 0,
+ 0,
+ 0,
+ parent_,
+ 0,
+ GetModuleHandle(NULL),
+ 0);
+ if (windowed_handle_ == 0)
+ return false;
+
+ BOOL result = SetProp(windowed_handle_, kWebPluginDelegateProperty, this);
+ DCHECK(result == TRUE) << "SetProp failed, last error = " << GetLastError();
+ // Get the name of the plugin, create an atom and set that in a window
+ // property. Use an atom so that other processes can access the name of
+ // the plugin that this window is hosting
+ if (instance_ != NULL) {
+ NPAPI::PluginLib* plugin_lib = instance()->plugin_lib();
+ if (plugin_lib != NULL) {
+ std::wstring plugin_name = plugin_lib->plugin_info().name;
+ if (!plugin_name.empty()) {
+ ATOM plugin_name_atom = GlobalAddAtomW(plugin_name.c_str());
+ DCHECK(0 != plugin_name_atom);
+ result = SetProp(windowed_handle_,
+ kPluginNameAtomProperty,
+ reinterpret_cast<HANDLE>(plugin_name_atom));
+ DCHECK(result == TRUE) << "SetProp failed, last error = " <<
+ GetLastError();
+ }
+ }
+ }
+
+ // Calling SetWindowLongPtrA here makes the window proc ASCII, which is
+ // required by at least the Shockwave Director plug-in.
+ SetWindowLongPtrA(
+ windowed_handle_, GWL_WNDPROC, reinterpret_cast<LONG>(DefWindowProcA));
+
+ return true;
+}
+
+void WebPluginDelegateImpl::WindowedDestroyWindow() {
+ if (windowed_handle_ != NULL) {
+ // Unsubclass the window.
+ WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
+ GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
+ if (current_wnd_proc == NativeWndProc) {
+ SetWindowLongPtr(windowed_handle_,
+ GWLP_WNDPROC,
+ reinterpret_cast<LONG>(plugin_wnd_proc_));
+ }
+
+ DestroyWindow(windowed_handle_);
+ windowed_handle_ = 0;
+ }
+}
+
+// Erase all messages in the queue destined for a particular window.
+// When windows are closing, callers should use this function to clear
+// the queue.
+// static
+void WebPluginDelegateImpl::ClearThrottleQueueForWindow(HWND window) {
+ std::list<MSG>::iterator it;
+ for (it = throttle_queue_.begin(); it != throttle_queue_.end(); ) {
+ if (it->hwnd == window) {
+ it = throttle_queue_.erase(it);
+ windowless_queue.Decrement();
+ } else {
+ it++;
+ }
+ }
+}
+
+// Delayed callback for processing throttled messages.
+// Throttled messages are aggregated globally across all plugins.
+// static
+void WebPluginDelegateImpl::OnThrottleMessage() {
+ // The current algorithm walks the list and processes the first
+ // message it finds for each plugin. It is important to service
+ // all active plugins with each pass through the throttle, otherwise
+ // we see video jankiness.
+ std::map<HWND, int> processed;
+
+ std::list<MSG>::iterator it = throttle_queue_.begin();
+ while (it != throttle_queue_.end()) {
+ const MSG& msg = *it;
+ if (processed.find(msg.hwnd) == processed.end()) {
+ WNDPROC proc = reinterpret_cast<WNDPROC>(msg.time);
+ CallWindowProc(proc, msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ processed[msg.hwnd] = 1;
+ it = throttle_queue_.erase(it);
+ windowless_queue.Decrement();
+ } else {
+ it++;
+ }
+ }
+
+ if (throttle_queue_.size() > 0)
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ NewRunnableFunction(&WebPluginDelegateImpl::OnThrottleMessage),
+ kFlashWMUSERMessageThrottleDelayMs);
+}
+
+// Schedule a windows message for delivery later.
+// static
+void WebPluginDelegateImpl::ThrottleMessage(WNDPROC proc, HWND hwnd,
+ UINT message, WPARAM wParam,
+ LPARAM lParam) {
+ MSG msg;
+ msg.time = reinterpret_cast<DWORD>(proc);
+ msg.hwnd = hwnd;
+ msg.message = message;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ throttle_queue_.push_back(msg);
+ windowless_queue.Increment();
+
+ if (throttle_queue_.size() == 1) {
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ NewRunnableFunction(&WebPluginDelegateImpl::OnThrottleMessage),
+ kFlashWMUSERMessageThrottleDelayMs);
+ }
+}
+
+// We go out of our way to find the hidden windows created by Flash for
+// windowless plugins. We throttle the rate at which they deliver messages
+// so that they will not consume outrageous amounts of CPU.
+// static
+LRESULT CALLBACK WebPluginDelegateImpl::FlashWindowlessWndProc(HWND hwnd,
+ UINT message, WPARAM wparam, LPARAM lparam) {
+ WNDPROC old_proc = reinterpret_cast<WNDPROC>(GetProp(hwnd, kPluginOrigProc));
+ DCHECK(old_proc);
+
+ switch (message) {
+ case WM_NCDESTROY: {
+ WebPluginDelegateImpl::ClearThrottleQueueForWindow(hwnd);
+ break;
+ }
+ // Flash may flood the message queue with WM_USER+1 message causing 100% CPU
+ // usage. See https://bugzilla.mozilla.org/show_bug.cgi?id=132759. We
+ // prevent this by throttling the messages.
+ case WM_USER + 1: {
+ WebPluginDelegateImpl::ThrottleMessage(old_proc, hwnd, message, wparam,
+ lparam);
+ return TRUE;
+ }
+ default: {
+ break;
+ }
+ }
+ return CallWindowProc(old_proc, hwnd, message, wparam, lparam);
+}
+
+// Callback for enumerating the Flash windows.
+BOOL CALLBACK EnumFlashWindows(HWND window, LPARAM arg) {
+ WNDPROC wnd_proc = reinterpret_cast<WNDPROC>(arg);
+ TCHAR class_name[1024];
+ if (!RealGetWindowClass(window, class_name,
+ sizeof(class_name)/sizeof(TCHAR))) {
+ LOG(ERROR) << "RealGetWindowClass failure: " << GetLastError();
+ return FALSE;
+ }
+
+ if (wcscmp(class_name, L"SWFlash_PlaceholderX"))
+ return TRUE;
+
+ WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
+ GetWindowLongPtr(window, GWLP_WNDPROC));
+ if (current_wnd_proc != wnd_proc) {
+ WNDPROC old_flash_proc = reinterpret_cast<WNDPROC>(SetWindowLongPtr(
+ window, GWLP_WNDPROC,
+ reinterpret_cast<LONG>(wnd_proc)));
+ DCHECK(old_flash_proc);
+ BOOL result = SetProp(window, kPluginOrigProc, old_flash_proc);
+ if (!result) {
+ LOG(ERROR) << "SetProp failed, last error = " << GetLastError();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+bool WebPluginDelegateImpl::CreateDummyWindowForActivation() {
+ DCHECK(!dummy_window_for_activation_);
+ dummy_window_for_activation_ = CreateWindowEx(
+ 0,
+ L"Static",
+ kDummyActivationWindowName,
+ WS_CHILD,
+ 0,
+ 0,
+ 0,
+ 0,
+ parent_,
+ 0,
+ GetModuleHandle(NULL),
+ 0);
+
+ if (dummy_window_for_activation_ == 0)
+ return false;
+
+ // Flash creates background windows which use excessive CPU in our
+ // environment; we wrap these windows and throttle them so that they don't
+ // get out of hand.
+ if (!EnumThreadWindows(::GetCurrentThreadId(), EnumFlashWindows,
+ reinterpret_cast<LPARAM>(
+ &WebPluginDelegateImpl::FlashWindowlessWndProc))) {
+ // Log that this happened. Flash will still work; it just means the
+ // throttle isn't installed (and Flash will use more CPU).
+ NOTREACHED();
+ LOG(ERROR) << "Failed to wrap all windowless Flash windows";
+ }
+ return true;
+}
+
+void WebPluginDelegateImpl::MoveWindow(HWND window,
+ const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ HRGN hrgn = ::CreateRectRgn(clip_rect.x(),
+ clip_rect.y(),
+ clip_rect.right(),
+ clip_rect.bottom());
+
+ // Note: System will own the hrgn after we call SetWindowRgn,
+ // so we don't need to call DeleteObject(hrgn)
+ ::SetWindowRgn(window, hrgn, FALSE);
+
+ // Move the window now, but do not paint it. We expect to be painted later,
+ // when our parent window paints.
+ unsigned long flags = SWP_NOREDRAW;
+ if (visible)
+ flags |= SWP_SHOWWINDOW;
+ else
+ flags |= SWP_HIDEWINDOW;
+
+ ::SetWindowPos(window,
+ NULL,
+ window_rect.x(),
+ window_rect.y(),
+ window_rect.width(),
+ window_rect.height(),
+ flags);
+}
+
+bool WebPluginDelegateImpl::WindowedReposition(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ if (!windowed_handle_) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (window_rect_ == window_rect && clip_rect_ == clip_rect &&
+ initial_plugin_resize_done_)
+ return false;
+
+ window_rect_ = window_rect;
+ clip_rect_ = clip_rect;
+
+ if (!initial_plugin_resize_done_) {
+ // We need to ensure that the plugin process continues to reposition
+ // the plugin window until we receive an indication that it is now visible.
+ // Subsequent repositions will be done by the browser.
+ if (visible)
+ initial_plugin_resize_done_ = true;
+ // We created the window with 0 width and height since we didn't know it
+ // at the time. Now that we know the geometry, we we can update its size
+ // since the browser only calls SetWindowPos when scrolling occurs.
+ MoveWindow(windowed_handle_, window_rect, clip_rect, visible);
+ // Ensure that the entire window gets repainted.
+ ::InvalidateRect(windowed_handle_, NULL, FALSE);
+ }
+
+ return true;
+}
+
+void WebPluginDelegateImpl::WindowedSetWindow() {
+ if (!instance_)
+ return;
+
+ if (!windowed_handle_) {
+ NOTREACHED();
+ return;
+ }
+
+ instance()->set_window_handle(windowed_handle_);
+
+ DCHECK(!instance()->windowless());
+
+ window_.clipRect.top = clip_rect_.y();
+ window_.clipRect.left = clip_rect_.x();
+ window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
+ window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
+ window_.height = window_rect_.height();
+ window_.width = window_rect_.width();
+ window_.x = window_rect_.x();
+ window_.y = window_rect_.y();
+
+ window_.window = windowed_handle_;
+ window_.type = NPWindowTypeWindow;
+
+ // Reset this flag before entering the instance in case of side-effects.
+ windowed_did_set_window_ = true;
+
+ NPError err = instance()->NPP_SetWindow(&window_);
+ if (quirks_ & PLUGIN_QUIRK_SETWINDOW_TWICE)
+ instance()->NPP_SetWindow(&window_);
+
+ WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
+ GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
+ if (current_wnd_proc != NativeWndProc) {
+ plugin_wnd_proc_ = reinterpret_cast<WNDPROC>(SetWindowLongPtr(
+ windowed_handle_, GWLP_WNDPROC, reinterpret_cast<LONG>(NativeWndProc)));
+ }
+}
+
+ATOM WebPluginDelegateImpl::RegisterNativeWindowClass() {
+ static bool have_registered_window_class = false;
+ if (have_registered_window_class == true)
+ return true;
+
+ have_registered_window_class = true;
+
+ WNDCLASSEX wcex;
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_DBLCLKS;
+ wcex.lpfnWndProc = DefWindowProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = GetModuleHandle(NULL);
+ wcex.hIcon = 0;
+ wcex.hCursor = 0;
+ // Some plugins like windows media player 11 create child windows parented
+ // by our plugin window, where the media content is rendered. These plugins
+ // dont implement WM_ERASEBKGND, which causes painting issues, when the
+ // window where the media is rendered is moved around. DefWindowProc does
+ // implement WM_ERASEBKGND correctly if we have a valid background brush.
+ wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = kNativeWindowClassName;
+ wcex.hIconSm = 0;
+
+ return RegisterClassEx(&wcex);
+}
+
+LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc(
+ HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
+ WebPluginDelegateImpl* delegate = reinterpret_cast<WebPluginDelegateImpl*>(
+ GetProp(hwnd, kWebPluginDelegateProperty));
+ if (!delegate) {
+ NOTREACHED();
+ return 0;
+ }
+
+ if (message == delegate->last_message_ &&
+ delegate->quirks() & PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY &&
+ delegate->is_calling_wndproc) {
+ // Real may go into a state where it recursively dispatches the same event
+ // when subclassed. See https://bugzilla.mozilla.org/show_bug.cgi?id=192914
+ // We only do the recursive check for Real because it's possible and valid
+ // for a plugin to synchronously dispatch a message to itself such that it
+ // looks like it's in recursion.
+ return TRUE;
+ }
+
+ switch (message) {
+ case WM_NCDESTROY: {
+ RemoveProp(hwnd, kWebPluginDelegateProperty);
+ ATOM plugin_name_atom = reinterpret_cast <ATOM>(
+ RemoveProp(hwnd, kPluginNameAtomProperty));
+ if (plugin_name_atom != 0)
+ GlobalDeleteAtom(plugin_name_atom);
+ ClearThrottleQueueForWindow(hwnd);
+ break;
+ }
+ // Flash may flood the message queue with WM_USER+1 message causing 100% CPU
+ // usage. See https://bugzilla.mozilla.org/show_bug.cgi?id=132759. We
+ // prevent this by throttling the messages.
+ case WM_USER + 1: {
+ if (delegate->quirks() & PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE) {
+ WebPluginDelegateImpl::ThrottleMessage(delegate->plugin_wnd_proc_, hwnd,
+ message, wparam, lparam);
+ return FALSE;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ delegate->last_message_ = message;
+ delegate->is_calling_wndproc = true;
+
+ if (!delegate->user_gesture_message_posted_ &&
+ IsUserGestureMessage(message)) {
+ delegate->user_gesture_message_posted_ = true;
+
+ delegate->instance()->PushPopupsEnabledState(true);
+
+ MessageLoop::current()->PostTask(FROM_HERE,
+ delegate->user_gesture_msg_factory_.NewRunnableMethod(
+ &WebPluginDelegateImpl::OnUserGestureEnd));
+ }
+
+ LRESULT result = CallWindowProc(delegate->plugin_wnd_proc_, hwnd, message,
+ wparam, lparam);
+ delegate->is_calling_wndproc = false;
+ return result;
+}
+
+void WebPluginDelegateImpl::WindowlessUpdateGeometry(
+ const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect) {
+ // Only resend to the instance if the geometry has changed.
+ if (window_rect == window_rect_ && clip_rect == clip_rect_)
+ return;
+
+ // Set this flag before entering the instance in case of side-effects.
+ windowless_needs_set_window_ = true;
+
+ // We will inform the instance of this change when we call NPP_SetWindow.
+ clip_rect_ = clip_rect;
+
+ if (window_rect_ != window_rect) {
+ window_rect_ = window_rect;
+
+ WindowlessSetWindow(true);
+
+ WINDOWPOS win_pos = {0};
+ win_pos.x = window_rect_.x();
+ win_pos.y = window_rect_.y();
+ win_pos.cx = window_rect_.width();
+ win_pos.cy = window_rect_.height();
+
+ NPEvent pos_changed_event;
+ pos_changed_event.event = WM_WINDOWPOSCHANGED;
+ pos_changed_event.wParam = 0;
+ pos_changed_event.lParam = PtrToUlong(&win_pos);
+
+ instance()->NPP_HandleEvent(&pos_changed_event);
+ }
+}
+
+void WebPluginDelegateImpl::WindowlessPaint(HDC hdc,
+ const gfx::Rect& damage_rect) {
+ DCHECK(hdc);
+
+ RECT damage_rect_win;
+ damage_rect_win.left = damage_rect.x(); // + window_rect_.x();
+ damage_rect_win.top = damage_rect.y(); // + window_rect_.y();
+ damage_rect_win.right = damage_rect_win.left + damage_rect.width();
+ damage_rect_win.bottom = damage_rect_win.top + damage_rect.height();
+
+ window_.window = (void*)hdc;
+
+ // TODO(darin): we should avoid calling NPP_SetWindow here since it may
+ // cause page layout to be invalidated.
+
+ // We really don't need to continually call SetWindow.
+ // m_needsSetWindow flags when the geometry has changed.
+ if (windowless_needs_set_window_)
+ WindowlessSetWindow(false);
+
+ NPEvent paint_event;
+ paint_event.event = WM_PAINT;
+ // NOTE: NPAPI is not 64bit safe. It puts pointers into 32bit values.
+ paint_event.wParam = PtrToUlong(hdc);
+ paint_event.lParam = PtrToUlong(&damage_rect_win);
+ static StatsRate plugin_paint(L"Plugin.Paint");
+ StatsScope<StatsRate> scope(plugin_paint);
+ instance()->NPP_HandleEvent(&paint_event);
+}
+
+void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
+ if (!instance())
+ return;
+
+ if (window_rect_.IsEmpty()) // wait for geometry to be set.
+ return;
+
+ DCHECK(instance()->windowless());
+
+ window_.clipRect.top = clip_rect_.y();
+ window_.clipRect.left = clip_rect_.x();
+ window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
+ window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
+ window_.height = window_rect_.height();
+ window_.width = window_rect_.width();
+ window_.x = window_rect_.x();
+ window_.y = window_rect_.y();
+ window_.type = NPWindowTypeDrawable;
+
+ if (!force_set_window)
+ // Reset this flag before entering the instance in case of side-effects.
+ windowless_needs_set_window_ = false;
+
+ NPError err = instance()->NPP_SetWindow(&window_);
+ DCHECK(err == NPERR_NO_ERROR);
+}
+
+void WebPluginDelegateImpl::SetFocus() {
+ DCHECK(instance()->windowless());
+
+ NPEvent focus_event;
+ focus_event.event = WM_SETFOCUS;
+ focus_event.wParam = 0;
+ focus_event.lParam = 0;
+
+ instance()->NPP_HandleEvent(&focus_event);
+}
+
+bool WebPluginDelegateImpl::HandleEvent(NPEvent* event,
+ WebCursor* cursor) {
+ DCHECK(windowless_) << "events should only be received in windowless mode";
+ DCHECK(cursor != NULL);
+
+ // To ensure that the plugin receives keyboard events we set focus to the
+ // dummy window.
+ // TODO(iyengar) We need a framework in the renderer to identify which
+ // windowless plugin is under the mouse and to handle this. This would
+ // also require some changes in RenderWidgetHost to detect this in the
+ // WM_MOUSEACTIVATE handler and inform the renderer accordingly.
+ HWND prev_focus_window = NULL;
+ if (event->event == WM_RBUTTONDOWN) {
+ prev_focus_window = ::SetFocus(dummy_window_for_activation_);
+ }
+
+ if (ShouldTrackEventForModalLoops(event)) {
+ // A windowless plugin can enter a modal loop in a NPP_HandleEvent call.
+ // For e.g. Flash puts up a context menu when we right click on the
+ // windowless plugin area. We detect this by setting up a message filter
+ // hook pror to calling NPP_HandleEvent on the plugin and unhook on
+ // return from NPP_HandleEvent. If the plugin does enter a modal loop
+ // in that context we unhook on receiving the first notification in
+ // the message filter hook.
+ handle_event_message_filter_hook_ =
+ SetWindowsHookEx(WH_MSGFILTER, HandleEventMessageFilterHook, NULL,
+ GetCurrentThreadId());
+ }
+
+ bool old_task_reentrancy_state =
+ MessageLoop::current()->NestableTasksAllowed();
+
+ current_plugin_instance_ = this;
+
+ handle_event_depth_++;
+
+ bool pop_user_gesture = false;
+
+ if (IsUserGestureMessage(event->event)) {
+ pop_user_gesture = true;
+ instance()->PushPopupsEnabledState(true);
+ }
+
+ bool ret = instance()->NPP_HandleEvent(event) != 0;
+
+ if (pop_user_gesture) {
+ instance()->PopPopupsEnabledState();
+ }
+
+ handle_event_depth_--;
+
+ current_plugin_instance_ = NULL;
+
+ MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state);
+
+ if (handle_event_message_filter_hook_) {
+ UnhookWindowsHookEx(handle_event_message_filter_hook_);
+ handle_event_message_filter_hook_ = NULL;
+ }
+
+ // We could have multiple NPP_HandleEvent calls nested together in case
+ // the plugin enters a modal loop. Reset the pump messages event when
+ // the outermost NPP_HandleEvent call unwinds.
+ if (handle_event_depth_ == 0) {
+ ResetEvent(handle_event_pump_messages_event_);
+ }
+
+ if (::IsWindow(prev_focus_window)) {
+ ::SetFocus(prev_focus_window);
+ }
+
+ if (WM_MOUSEMOVE == event->event) {
+ HCURSOR actual_cursor = ::GetCursor();
+ *cursor = GetCursorType(actual_cursor);
+ }
+
+ return ret;
+}
+
+WebCursor::Type WebPluginDelegateImpl::GetCursorType(
+ HCURSOR cursor) const {
+ static HCURSOR standard_cursors[] = {
+ LoadCursor(NULL, IDC_ARROW),
+ LoadCursor(NULL, IDC_IBEAM),
+ LoadCursor(NULL, IDC_WAIT),
+ LoadCursor(NULL, IDC_CROSS),
+ LoadCursor(NULL, IDC_UPARROW),
+ LoadCursor(NULL, IDC_SIZE),
+ LoadCursor(NULL, IDC_ICON),
+ LoadCursor(NULL, IDC_SIZENWSE),
+ LoadCursor(NULL, IDC_SIZENESW),
+ LoadCursor(NULL, IDC_SIZEWE),
+ LoadCursor(NULL, IDC_SIZENS),
+ LoadCursor(NULL, IDC_SIZEALL),
+ LoadCursor(NULL, IDC_NO),
+ LoadCursor(NULL, IDC_HAND),
+ LoadCursor(NULL, IDC_APPSTARTING),
+ LoadCursor(NULL, IDC_HELP),
+ };
+
+ for (int cursor_index = 0; cursor_index < arraysize(standard_cursors);
+ cursor_index++) {
+ if (cursor == standard_cursors[cursor_index])
+ return static_cast<WebCursor::Type>(cursor_index);
+ }
+
+ return WebCursor::ARROW;
+}
+
+WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
+ int resource_id, const std::string &url, bool notify_needed,
+ void *notify_data) {
+ if (notify_needed) {
+ instance()->SetURLLoadData(GURL(url.c_str()), notify_data);
+ }
+ std::string mime_type;
+ NPAPI::PluginStreamUrl *stream = instance()->CreateStream(resource_id,
+ url,
+ mime_type,
+ notify_needed,
+ notify_data);
+ return stream;
+}
+
+void WebPluginDelegateImpl::URLRequestRouted(const std::string&url,
+ bool notify_needed,
+ void* notify_data) {
+ if (notify_needed) {
+ instance()->SetURLLoadData(GURL(url.c_str()), notify_data);
+ }
+}
+
+void WebPluginDelegateImpl::OnModalLoopEntered() {
+ DCHECK(handle_event_pump_messages_event_ != NULL);
+ SetEvent(handle_event_pump_messages_event_);
+
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+
+ UnhookWindowsHookEx(handle_event_message_filter_hook_);
+ handle_event_message_filter_hook_ = NULL;
+}
+
+bool WebPluginDelegateImpl::ShouldTrackEventForModalLoops(NPEvent* event) {
+ if (event->event == WM_RBUTTONDOWN)
+ return true;
+ return false;
+}
+
+bool WebPluginDelegateImpl::IsUserGestureMessage(unsigned int message) {
+ switch (message) {
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_KEYUP:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void WebPluginDelegateImpl::OnUserGestureEnd() {
+ user_gesture_message_posted_ = false;
+ instance()->PopPopupsEnabledState();
+}
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h
new file mode 100644
index 0000000..3b774e8
--- /dev/null
+++ b/webkit/glue/plugins/webplugin_delegate_impl.h
@@ -0,0 +1,287 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WEBKIT_GLUE_PLUGIN_WEBPLUGIN_DELEGATE_IMPL_H__
+#define WEBKIT_GLUE_PLUGIN_WEBPLUGIN_DELEGATE_IMPL_H__
+
+#include <string>
+#include <list>
+
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "webkit/glue/webplugin_delegate.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "webkit/glue/webcursor.h"
+
+namespace NPAPI {
+ class PluginInstance;
+};
+
+// An implementation of WebPluginDelegate that proxies all calls to
+// the plugin process.
+class WebPluginDelegateImpl : public WebPluginDelegate {
+ public:
+ static WebPluginDelegateImpl* Create(const std::wstring& filename,
+ const std::string& mime_type,
+ HWND containing_window);
+ static bool IsPluginDelegateWindow(HWND window);
+ static bool GetPluginNameFromWindow(HWND window, std::wstring *plugin_name);
+
+ // Returns true if the window handle passed in is that of the dummy
+ // activation window for windowless plugins.
+ static bool IsDummyActivationWindow(HWND window);
+
+ // WebPluginDelegate implementation
+ virtual void PluginDestroyed();
+ virtual bool Initialize(const GURL& url,
+ char** argn,
+ char** argv,
+ int argc,
+ WebPlugin* plugin,
+ bool load_manually);
+ virtual void UpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect, bool visible);
+ virtual void Paint(HDC hdc, const gfx::Rect& rect);
+ virtual void Print(HDC hdc);
+ virtual void SetFocus(); // only called when windowless
+// only called when windowless
+ virtual bool HandleEvent(NPEvent* event,
+ WebCursor* cursor);
+ virtual NPObject* GetPluginScriptableObject();
+ virtual void DidFinishLoadWithReason(NPReason reason);
+ virtual int GetProcessId();
+ virtual HWND GetWindowHandle();
+
+ virtual void FlushGeometryUpdates() {
+ }
+ virtual void SendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success, bool notify_needed,
+ int notify_data);
+ virtual void DidReceiveManualResponse(const std::string& url,
+ const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified);
+ virtual void DidReceiveManualData(const char* buffer, int length);
+ virtual void DidFinishManualLoading();
+ virtual void DidManualLoadFail();
+ virtual std::wstring GetPluginPath();
+ virtual void InstallMissingPlugin();
+ virtual WebPluginResourceClient* CreateResourceClient(int resource_id,
+ const std::string &url,
+ bool notify_needed,
+ void *notify_data);
+
+ virtual void URLRequestRouted(const std::string&url, bool notify_needed,
+ void* notify_data);
+ bool windowless() const {
+ return windowless_;
+ }
+
+ enum PluginQuirks {
+ PLUGIN_QUIRK_SETWINDOW_TWICE = 1,
+ PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE = 2,
+ PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY = 4,
+ PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY = 8,
+ PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES = 16,
+ };
+
+ int quirks() { return quirks_; }
+
+ static void MoveWindow(HWND window,
+ const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible);
+
+ private:
+ WebPluginDelegateImpl(HWND containing_window,
+ NPAPI::PluginInstance *instance);
+ ~WebPluginDelegateImpl();
+
+ //--------------------------
+ // used for windowed plugins
+ void WindowedUpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect, bool visible);
+ // Create the native window.
+ // Returns true if the window is created (or already exists).
+ // Returns false if unable to create the window.
+ bool WindowedCreatePlugin();
+
+ // Destroy the native window.
+ void WindowedDestroyWindow();
+
+ // Reposition the native window to be in sync with the given geometry.
+ // Returns true if the native window has moved or been clipped differently.
+ bool WindowedReposition(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect, bool visible);
+
+ // Tells the plugin about the current state of the window.
+ // See NPAPI NPP_SetWindow for more information.
+ void WindowedSetWindow();
+
+ // Registers the window class for our window
+ ATOM RegisterNativeWindowClass();
+
+ // Our WndProc functions.
+ static LRESULT CALLBACK NativeWndProc(
+ HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+ static LRESULT CALLBACK FlashWindowlessWndProc(
+ HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+
+ // Used for throttling Flash messages.
+ static void ClearThrottleQueueForWindow(HWND window);
+ static void OnThrottleMessage();
+ static void ThrottleMessage(WNDPROC proc, HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam);
+
+ //----------------------------
+ // used for windowless plugins
+ void WindowlessUpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect);
+ void WindowlessPaint(HDC hdc, const gfx::Rect& rect);
+
+ // Tells the plugin about the current state of the window.
+ // See NPAPI NPP_SetWindow for more information.
+ void WindowlessSetWindow(bool force_set_window);
+
+
+ //-----------------------------------------
+ // used for windowed and windowless plugins
+
+ NPAPI::PluginInstance* instance() { return instance_.get(); }
+
+ // Closes down and destroys our plugin instance.
+ void DestroyInstance();
+
+ // Returns the cursor type.
+ // TODO(iyengar) Add support for custom cursors.
+ WebCursor::Type GetCursorType(HCURSOR cursor) const;
+
+ // used for windowed plugins
+ HWND windowed_handle_;
+ bool windowed_did_set_window_;
+ gfx::Rect windowed_last_pos_;
+
+ // this is an optimization to avoid calling SetWindow to the plugin
+ // when it is not necessary. Initially, we need to call SetWindow,
+ // and after that we only need to call it when the geometry changes.
+ // use this flag to indicate whether we really need it or not.
+ bool windowless_needs_set_window_;
+
+ // used by windowed and windowless plugins
+ bool windowless_;
+
+ WebPlugin* plugin_;
+ scoped_refptr<NPAPI::PluginInstance> instance_;
+
+ // Original wndproc before we subclassed.
+ WNDPROC plugin_wnd_proc_;
+
+ // Used to throttle WM_USER+1 messages in Flash.
+ uint32 last_message_;
+ bool is_calling_wndproc;
+
+ HWND parent_;
+ NPWindow window_;
+ gfx::Rect window_rect_;
+ gfx::Rect clip_rect_;
+ int quirks_;
+
+ // We only move/size the plugin window once after its creation. The
+ // rest of the moves are controlled by the browser. This flag controls
+ // this behaviour.
+ bool initial_plugin_resize_done_;
+
+ // Windowless plugins don't have keyboard focus causing issues with the
+ // plugin not receiving keyboard events if the plugin enters a modal
+ // loop like TrackPopupMenuEx or MessageBox, etc.
+ // This is a basic issue with windows activation and focus arising due to
+ // the fact that these windows are created by different threads. Activation
+ // and focus are thread specific states, and if the browser has focus,
+ // the plugin may not have focus.
+ // To fix a majority of these activation issues we create a dummy visible
+ // child window to which we set focus whenever the windowless plugin
+ // receives a WM_LBUTTONDOWN/WM_RBUTTONDOWN message via NPP_HandleEvent.
+ HWND dummy_window_for_activation_;
+ bool CreateDummyWindowForActivation();
+
+ static std::list<MSG> throttle_queue_;
+
+ // Returns true if the event passed in needs to be tracked for a potential
+ // modal loop.
+ static bool ShouldTrackEventForModalLoops(NPEvent* event);
+
+ // The message filter hook procedure, which tracks modal loops entered by
+ // a plugin in the course of a NPP_HandleEvent call.
+ static LRESULT CALLBACK HandleEventMessageFilterHook(int code, WPARAM wParam,
+ LPARAM lParam);
+
+ // Called by the message filter hook when the plugin enters a modal loop.
+ void OnModalLoopEntered();
+
+ // Returns true if the message passed in corresponds to a user gesture.
+ static bool IsUserGestureMessage(unsigned int message);
+
+ // Indicates the end of a user gesture period.
+ void OnUserGestureEnd();
+
+ // Handle to the message filter hook
+ HHOOK handle_event_message_filter_hook_;
+
+ // The current instance of the plugin which entered the modal loop.
+ static WebPluginDelegateImpl* current_plugin_instance_;
+
+ // Event which is set when the plugin enters a modal loop in the course
+ // of a NPP_HandleEvent call.
+ HANDLE handle_event_pump_messages_event_;
+
+ // Holds the depth of the HandleEvent callstack.
+ int handle_event_depth_;
+
+ // This flag indicates whether we started tracking a user gesture message.
+ bool user_gesture_message_posted_;
+
+ // Runnable Method Factory used to invoke the OnUserGestureEnd method
+ // asynchronously.
+ ScopedRunnableMethodFactory<WebPluginDelegateImpl> user_gesture_msg_factory_;
+
+ // The url with which the plugin was instantiated.
+ std::string plugin_url_;
+
+ // Indicates if the download would be initiated by the plugin or us.
+ bool load_manually_;
+
+ // Indicates whether a geometry update sequence is the first.
+ bool first_geometry_update_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebPluginDelegateImpl);
+};
+
+#endif // #ifndef WEBKIT_GLUE_PLUGIN_WEBPLUGIN_DELEGATE_IMPL_H__