summaryrefslogtreecommitdiffstats
path: root/chrome/plugin
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/plugin
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/plugin')
-rw-r--r--chrome/plugin/SConscript73
-rw-r--r--chrome/plugin/chrome_plugin_host.cc570
-rw-r--r--chrome/plugin/chrome_plugin_host.h38
-rw-r--r--chrome/plugin/npobject_proxy.cc374
-rw-r--r--chrome/plugin/npobject_proxy.h140
-rw-r--r--chrome/plugin/npobject_stub.cc320
-rw-r--r--chrome/plugin/npobject_stub.h106
-rw-r--r--chrome/plugin/npobject_util.cc275
-rw-r--r--chrome/plugin/npobject_util.h84
-rw-r--r--chrome/plugin/plugin.vcproj231
-rw-r--r--chrome/plugin/plugin_channel.cc136
-rw-r--r--chrome/plugin/plugin_channel.h84
-rw-r--r--chrome/plugin/plugin_channel_base.cc216
-rw-r--r--chrome/plugin/plugin_channel_base.h144
-rw-r--r--chrome/plugin/plugin_main.cc100
-rw-r--r--chrome/plugin/plugin_process.cc122
-rw-r--r--chrome/plugin/plugin_process.h76
-rw-r--r--chrome/plugin/plugin_thread.cc206
-rw-r--r--chrome/plugin/plugin_thread.h99
-rw-r--r--chrome/plugin/webplugin_delegate_stub.cc462
-rw-r--r--chrome/plugin/webplugin_delegate_stub.h137
-rw-r--r--chrome/plugin/webplugin_proxy.cc269
-rw-r--r--chrome/plugin/webplugin_proxy.h116
23 files changed, 4378 insertions, 0 deletions
diff --git a/chrome/plugin/SConscript b/chrome/plugin/SConscript
new file mode 100644
index 0000000..8dbb9ef
--- /dev/null
+++ b/chrome/plugin/SConscript
@@ -0,0 +1,73 @@
+# 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 = env.Clone()
+
+
+
+env.Prepend(
+ CPPPATH = [
+ Dir("#/../third_party/npapi"),
+ Dir("#/../chrome/tools/build/win"),
+ Dir("#/../skia/include"),
+ Dir("#/../skia/include/corecg"),
+ Dir("#/../skia/platform"),
+ Dir("#/.."),
+ ],
+ CPPDEFINES = [
+ "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
+ "WIN32_LEAN_AND_MEAN",
+ ],
+ CCFLAGS = [
+ '/TP',
+
+ #'/Wp64',
+
+ '/wd4503',
+ '/wd4819',
+ ],
+)
+
+input_files = [
+ "npobject_proxy.cc",
+ "webplugin_proxy.cc",
+ "webplugin_delegate_stub.cc",
+ "plugin_thread.cc",
+ "plugin_process.cc",
+ "plugin_main.cc",
+ "plugin_channel_base.cc",
+ "plugin_channel.cc",
+ "chrome_plugin_host.cc",
+ "npobject_util.cc",
+ "npobject_stub.cc",
+]
+
+env.StaticLibrary('plugin', input_files)
diff --git a/chrome/plugin/chrome_plugin_host.cc b/chrome/plugin/chrome_plugin_host.cc
new file mode 100644
index 0000000..5a3af53
--- /dev/null
+++ b/chrome/plugin/chrome_plugin_host.cc
@@ -0,0 +1,570 @@
+// 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 "chrome/plugin/chrome_plugin_host.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_plugin_lib.h"
+#include "chrome/common/chrome_plugin_util.h"
+#include "chrome/plugin/plugin_process.h"
+#include "chrome/plugin/plugin_thread.h"
+#include "chrome/plugin/webplugin_proxy.h"
+#include "net/base/data_url.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/resource_loader_bridge.h"
+#include "webkit/glue/resource_type.h"
+#include "webkit/glue/webkit_glue.h"
+
+namespace {
+
+using webkit_glue::ResourceLoaderBridge;
+
+// This class manages a network request made by the plugin, handling the
+// data as it comes in from the ResourceLoaderBridge and is requested by the
+// plugin.
+// NOTE: All methods must be called on the Plugin thread.
+class PluginRequestHandlerProxy
+ : public PluginHelper, public ResourceLoaderBridge::Peer {
+ public:
+ static PluginRequestHandlerProxy* FromCPRequest(CPRequest* request) {
+ return ScopableCPRequest::GetData<PluginRequestHandlerProxy*>(request);
+ }
+
+ PluginRequestHandlerProxy(ChromePluginLib* plugin,
+ ScopableCPRequest* cprequest)
+ : PluginHelper(plugin), cprequest_(cprequest), response_data_offset_(0),
+ completed_(false), sync_(false), read_buffer_(NULL) {
+ load_flags_ = PluginResponseUtils::CPLoadFlagsToNetFlags(0);
+ cprequest_->data = this; // see FromCPRequest().
+ }
+
+ ~PluginRequestHandlerProxy() {
+ if (bridge_.get() && !completed_) {
+ bridge_->Cancel();
+ }
+ }
+
+ // ResourceLoaderBridge::Peer
+ virtual void OnUploadProgress(uint64 position, uint64 size) {
+ CPRR_UploadProgressFunc upload_progress =
+ plugin_->functions().response_funcs->upload_progress;
+ if (upload_progress)
+ upload_progress(cprequest_.get(), position, size);
+ }
+
+ virtual void OnReceivedRedirect(const GURL& new_url) {
+ plugin_->functions().response_funcs->received_redirect(
+ cprequest_.get(), new_url.spec().c_str());
+ }
+
+ virtual void OnReceivedResponse(
+ const ResourceLoaderBridge::ResponseInfo& info) {
+ response_headers_ = info.headers;
+ plugin_->functions().response_funcs->start_completed(
+ cprequest_.get(), CPERR_SUCCESS);
+ }
+
+ virtual void OnReceivedData(const char* data, int len) {
+ response_data_.append(data, len);
+ if (read_buffer_) {
+ // If we had an asynchronous operation pending, read into that buffer
+ // and inform the plugin.
+ int rv = Read(read_buffer_, read_buffer_size_);
+ DCHECK(rv != CPERR_IO_PENDING);
+ read_buffer_ = NULL;
+ plugin_->functions().response_funcs->read_completed(
+ cprequest_.get(), rv);
+ }
+ }
+
+ virtual void OnCompletedRequest(const URLRequestStatus& status) {
+ completed_ = true;
+
+ if (!status.is_success()) {
+ // TODO(mpcomplete): better error codes
+ // Inform the plugin, calling the right function depending on whether
+ // we got the start_completed event or not.
+ if (response_headers_) {
+ plugin_->functions().response_funcs->start_completed(
+ cprequest_.get(), CPERR_FAILURE);
+ } else {
+ plugin_->functions().response_funcs->read_completed(
+ cprequest_.get(), CPERR_FAILURE);
+ }
+ } else if (read_buffer_) {
+ // The plugin was waiting for more data. Inform him we're done.
+ read_buffer_ = NULL;
+ plugin_->functions().response_funcs->read_completed(
+ cprequest_.get(), CPERR_SUCCESS);
+ }
+ }
+
+ virtual std::string GetURLForDebugging() {
+ return cprequest_->url;
+ }
+
+ void set_extra_headers(const std::string& headers) {
+ extra_headers_ = headers;
+ }
+ void set_load_flags(uint32 flags) {
+ load_flags_ = flags;
+ }
+ void set_sync(bool sync) {
+ sync_ = sync;
+ }
+ void AppendDataToUpload(const char* bytes, int bytes_len) {
+ upload_content_.push_back(net::UploadData::Element());
+ upload_content_.back().SetToBytes(bytes, bytes_len);
+ }
+
+ void AppendFileToUpload(const std::wstring &filepath) {
+ AppendFileRangeToUpload(filepath, 0, kuint64max);
+ }
+
+ void AppendFileRangeToUpload(const std::wstring &filepath,
+ uint64 offset, uint64 length) {
+ upload_content_.push_back(net::UploadData::Element());
+ upload_content_.back().SetToFilePathRange(filepath, offset, length);
+ }
+
+ CPError Start() {
+ bridge_.reset(
+ PluginThread::GetPluginThread()->resource_dispatcher()->CreateBridge(
+ cprequest_->method,
+ GURL(cprequest_->url),
+ GURL(cprequest_->url), // TODO(jackson): policy url?
+ GURL(), // TODO(mpcomplete): referrer?
+ extra_headers_,
+ load_flags_,
+ GetCurrentProcessId(),
+ ResourceType::OBJECT,
+ false, // TODO (jcampan): mixed-content?
+ cprequest_->context));
+ if (!bridge_.get())
+ return CPERR_FAILURE;
+
+ for (size_t i = 0; i < upload_content_.size(); ++i) {
+ switch (upload_content_[i].type()) {
+ case net::UploadData::TYPE_BYTES: {
+ const std::vector<char>& bytes = upload_content_[i].bytes();
+ bridge_->AppendDataToUpload(&bytes[0],
+ static_cast<int>(bytes.size()));
+ break;
+ }
+ case net::UploadData::TYPE_FILE: {
+ bridge_->AppendFileRangeToUpload(
+ upload_content_[i].file_path(),
+ upload_content_[i].file_range_offset(),
+ upload_content_[i].file_range_length());
+ break;
+ }
+ default: {
+ NOTREACHED() << "Unknown UploadData::Element type";
+ }
+ }
+ }
+
+ if (sync_) {
+ ResourceLoaderBridge::SyncLoadResponse response;
+ bridge_->SyncLoad(&response);
+ response_headers_ = response.headers;
+ response_data_ = response.data;
+ completed_ = true;
+ return response.status.is_success() ? CPERR_SUCCESS : CPERR_FAILURE;
+ } else {
+ if (!bridge_->Start(this)) {
+ bridge_.reset();
+ return CPERR_FAILURE;
+ }
+ return CPERR_IO_PENDING;
+ }
+ }
+
+ int GetResponseInfo(CPResponseInfoType type, void* buf, uint32 buf_size) {
+ return PluginResponseUtils::GetResponseInfo(
+ response_headers_, type, buf, buf_size);
+ }
+
+ int Read(void* buf, uint32 buf_size) {
+ uint32 avail =
+ static_cast<uint32>(response_data_.size()) - response_data_offset_;
+ uint32 count = buf_size;
+ if (count > avail)
+ count = avail;
+
+ int rv = CPERR_FAILURE;
+ if (count) {
+ // Data is ready now.
+ memcpy(buf, &response_data_[0] + response_data_offset_, count);
+ response_data_offset_ += count;
+ } else if (!completed_) {
+ read_buffer_ = buf;
+ read_buffer_size_ = buf_size;
+ DCHECK(!sync_);
+ return CPERR_IO_PENDING;
+ }
+
+ if (response_data_.size() == response_data_offset_) {
+ // Simple optimization for large requests. Generally the consumer will
+ // read the data faster than it comes in, so we can clear our buffer
+ // any time it has all been read.
+ response_data_.clear();
+ response_data_offset_ = 0;
+ }
+
+ read_buffer_ = NULL;
+ return count;
+ }
+
+ private:
+ scoped_ptr<ScopableCPRequest> cprequest_;
+ scoped_ptr<ResourceLoaderBridge> bridge_;
+ std::vector<net::UploadData::Element> upload_content_;
+ std::string extra_headers_;
+ uint32 load_flags_;
+ bool sync_;
+
+ scoped_refptr<net::HttpResponseHeaders> response_headers_;
+ std::string response_data_;
+ int response_data_offset_;
+ bool completed_;
+ void* read_buffer_;
+ uint32 read_buffer_size_;
+};
+
+//
+// Generic functions
+//
+
+void STDCALL CPB_SetKeepProcessAlive(CPID id, CPBool keep_alive) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ static bool g_keep_process_alive = false;
+ bool desired_value = keep_alive ? true : false; // smash to bool
+ if (desired_value != g_keep_process_alive) {
+ g_keep_process_alive = desired_value;
+ if (g_keep_process_alive)
+ PluginProcess::AddRefProcess();
+ else
+ PluginProcess::ReleaseProcess();
+ }
+}
+
+CPError STDCALL CPB_GetCookies(CPID id, CPBrowsingContext context,
+ const char* url, char** cookies) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ std::string cookies_str;
+ PluginThread::GetPluginThread()->Send(
+ new PluginProcessHostMsg_GetCookies(context, GURL(url), &cookies_str));
+ *cookies = CPB_StringDup(CPB_Alloc, cookies_str);
+ return CPERR_SUCCESS;
+}
+
+CPError STDCALL CPB_ShowHtmlDialogModal(
+ CPID id, CPBrowsingContext context, const char* url, int width, int height,
+ const char* json_arguments, char** json_retval) {
+ CHECK(ChromePluginLib::IsPluginThread());
+
+ WebPluginProxy* webplugin = WebPluginProxy::FromCPBrowsingContext(context);
+ if (!webplugin)
+ return CPERR_INVALID_PARAMETER;
+
+ std::string retval_str;
+ webplugin->ShowModalHTMLDialog(
+ GURL(url), width, height, json_arguments, &retval_str);
+ *json_retval = CPB_StringDup(CPB_Alloc, retval_str);
+ return CPERR_SUCCESS;
+}
+
+CPError STDCALL CPB_ShowHtmlDialog(
+ CPID id, CPBrowsingContext context, const char* url, int width, int height,
+ const char* json_arguments, void* plugin_context) {
+ // TODO(mpcomplete): support non-modal dialogs.
+ return CPERR_FAILURE;
+}
+
+CPError STDCALL CPB_GetCommandLineArguments(
+ CPID id, CPBrowsingContext context, const char* url, char** arguments) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ std::string arguments_str;
+ CPError rv = CPB_GetCommandLineArgumentsCommon(url, &arguments_str);
+ if (rv == CPERR_SUCCESS)
+ *arguments = CPB_StringDup(CPB_Alloc, arguments_str);
+ return rv;
+}
+
+CPBrowsingContext STDCALL CPB_GetBrowsingContextFromNPP(NPP npp) {
+ if (!npp)
+ return CPERR_INVALID_PARAMETER;
+
+ NPAPI::PluginInstance* instance =
+ static_cast<NPAPI::PluginInstance *>(npp->ndata);
+ WebPluginProxy* webplugin =
+ static_cast<WebPluginProxy*>(instance->webplugin());
+
+ return webplugin->GetCPBrowsingContext();
+}
+
+int STDCALL CPB_GetBrowsingContextInfo(
+ CPID id, CPBrowsingContext context, CPBrowsingContextInfoType type,
+ void* buf, uint32 buf_size) {
+ CHECK(ChromePluginLib::IsPluginThread());
+
+ switch (type) {
+ case CPBROWSINGCONTEXT_DATA_DIR_PTR: {
+ if (buf_size < sizeof(char*))
+ return sizeof(char*);
+
+ std::wstring wretval;
+ PluginThread::GetPluginThread()->Send(
+ new PluginProcessHostMsg_GetPluginDataDir(&wretval));
+ file_util::AppendToPath(&wretval, chrome::kChromePluginDataDirname);
+ *static_cast<char**>(buf) = CPB_StringDup(CPB_Alloc, WideToUTF8(wretval));
+ return CPERR_SUCCESS;
+ }
+ case CPBROWSINGCONTEXT_UI_LOCALE_PTR: {
+ if (buf_size < sizeof(char*))
+ return sizeof(char*);
+
+ std::wstring wretval = webkit_glue::GetWebKitLocale();
+ *static_cast<char**>(buf) = CPB_StringDup(CPB_Alloc, WideToUTF8(wretval));
+ return CPERR_SUCCESS;
+ }
+ }
+
+ return CPERR_FAILURE;
+}
+
+CPError STDCALL CPB_AddUICommand(CPID id, int command) {
+ // Not implemented in the plugin process
+ return CPERR_FAILURE;
+}
+
+CPError STDCALL CPB_HandleCommand(
+ CPID id, CPBrowsingContext context, int command, void *data) {
+ // Not implemented in the plugin process
+ return CPERR_FAILURE;
+}
+
+//
+// Functions related to network interception
+//
+
+void STDCALL CPB_EnableRequestIntercept(
+ CPID id, const char** schemes, uint32 num_schemes) {
+ // We ignore requests by the plugin to intercept from this process. That's
+ // handled in the browser process.
+}
+
+void STDCALL CPRR_ReceivedRedirect(CPRequest* request, const char* new_url) {
+ NOTREACHED() << "Network interception should not happen in plugin process.";
+}
+
+void STDCALL CPRR_StartCompleted(CPRequest* request, CPError result) {
+ NOTREACHED() << "Network interception should not happen in plugin process.";
+}
+
+void STDCALL CPRR_ReadCompleted(CPRequest* request, int bytes_read) {
+ NOTREACHED() << "Network interception should not happen in plugin process.";
+}
+
+void STDCALL CPRR_UploadProgress(CPRequest* request, uint64 pos, uint64 size) {
+ NOTREACHED() << "Network interception should not happen in plugin process.";
+}
+
+//
+// Functions related to serving network requests to the plugin
+//
+
+CPError STDCALL CPB_CreateRequest(CPID id, CPBrowsingContext context,
+ const char* method, const char* url,
+ CPRequest** request) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ ChromePluginLib* plugin = ChromePluginLib::FromCPID(id);
+ CHECK(plugin);
+
+ ScopableCPRequest* cprequest = new ScopableCPRequest(url, method, context);
+ PluginRequestHandlerProxy* handler =
+ new PluginRequestHandlerProxy(plugin, cprequest);
+
+ *request = cprequest;
+ return CPERR_SUCCESS;
+}
+
+CPError STDCALL CPR_StartRequest(CPRequest* request) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ PluginRequestHandlerProxy* handler =
+ PluginRequestHandlerProxy::FromCPRequest(request);
+ CHECK(handler);
+ return handler->Start();
+}
+
+void STDCALL CPR_EndRequest(CPRequest* request, CPError reason) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ PluginRequestHandlerProxy* handler =
+ PluginRequestHandlerProxy::FromCPRequest(request);
+ delete handler;
+}
+
+void STDCALL CPR_SetExtraRequestHeaders(CPRequest* request,
+ const char* headers) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ PluginRequestHandlerProxy* handler =
+ PluginRequestHandlerProxy::FromCPRequest(request);
+ CHECK(handler);
+ handler->set_extra_headers(headers);
+}
+
+void STDCALL CPR_SetRequestLoadFlags(CPRequest* request, uint32 flags) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ PluginRequestHandlerProxy* handler =
+ PluginRequestHandlerProxy::FromCPRequest(request);
+ CHECK(handler);
+
+ if (flags & CPREQUESTLOAD_SYNCHRONOUS) {
+ handler->set_sync(true);
+ }
+
+ uint32 net_flags = PluginResponseUtils::CPLoadFlagsToNetFlags(flags);
+ handler->set_load_flags(net_flags);
+}
+
+void STDCALL CPR_AppendDataToUpload(CPRequest* request, const char* bytes,
+ int bytes_len) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ PluginRequestHandlerProxy* handler =
+ PluginRequestHandlerProxy::FromCPRequest(request);
+ CHECK(handler);
+ handler->AppendDataToUpload(bytes, bytes_len);
+}
+
+CPError STDCALL CPR_AppendFileToUpload(CPRequest* request, const char* filepath,
+ uint64 offset, uint64 length) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ PluginRequestHandlerProxy* handler =
+ PluginRequestHandlerProxy::FromCPRequest(request);
+ CHECK(handler);
+
+ if (!length) length = kuint64max;
+ std::wstring wfilepath(UTF8ToWide(filepath));
+ handler->AppendFileRangeToUpload(wfilepath, offset, length);
+ return CPERR_SUCCESS;
+}
+
+int STDCALL CPR_GetResponseInfo(CPRequest* request, CPResponseInfoType type,
+ void* buf, uint32 buf_size) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ PluginRequestHandlerProxy* handler =
+ PluginRequestHandlerProxy::FromCPRequest(request);
+ CHECK(handler);
+ return handler->GetResponseInfo(type, buf, buf_size);
+}
+
+int STDCALL CPR_Read(CPRequest* request, void* buf, uint32 buf_size) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ PluginRequestHandlerProxy* handler =
+ PluginRequestHandlerProxy::FromCPRequest(request);
+ CHECK(handler);
+ return handler->Read(buf, buf_size);
+}
+
+
+CPBool STDCALL CPB_IsPluginProcessRunning(CPID id) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ return true;
+}
+
+CPProcessType STDCALL CPB_GetProcessType(CPID id) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ return CP_PROCESS_PLUGIN;
+}
+
+CPError STDCALL CPB_SendMessage(CPID id, const void *data, uint32 data_len) {
+ CHECK(ChromePluginLib::IsPluginThread());
+ const uint8* data_ptr = static_cast<const uint8*>(data);
+ std::vector<uint8> v(data_ptr, data_ptr + data_len);
+ if (!PluginThread::GetPluginThread()->Send(
+ new PluginProcessHostMsg_PluginMessage(v))) {
+ return CPERR_FAILURE;
+ }
+ return CPERR_SUCCESS;
+}
+
+} // namespace
+
+CPBrowserFuncs* GetCPBrowserFuncsForPlugin() {
+ static CPBrowserFuncs browser_funcs;
+ static CPRequestFuncs request_funcs;
+ static CPResponseFuncs response_funcs;
+ static bool initialized = false;
+ if (!initialized) {
+ initialized = true;
+
+ browser_funcs.size = sizeof(browser_funcs);
+ browser_funcs.version = CP_VERSION;
+ browser_funcs.enable_request_intercept = CPB_EnableRequestIntercept;
+ browser_funcs.create_request = CPB_CreateRequest;
+ browser_funcs.get_cookies = CPB_GetCookies;
+ browser_funcs.alloc = CPB_Alloc;
+ browser_funcs.free = CPB_Free;
+ browser_funcs.set_keep_process_alive = CPB_SetKeepProcessAlive;
+ browser_funcs.show_html_dialog = CPB_ShowHtmlDialog;
+ browser_funcs.show_html_dialog_modal = CPB_ShowHtmlDialogModal;
+ browser_funcs.is_plugin_process_running = CPB_IsPluginProcessRunning;
+ browser_funcs.get_process_type = CPB_GetProcessType;
+ browser_funcs.send_message = CPB_SendMessage;
+ browser_funcs.get_browsing_context_from_npp = CPB_GetBrowsingContextFromNPP;
+ browser_funcs.get_browsing_context_info = CPB_GetBrowsingContextInfo;
+ browser_funcs.get_command_line_arguments = CPB_GetCommandLineArguments;
+ browser_funcs.add_ui_command = CPB_AddUICommand;
+ browser_funcs.handle_command = CPB_HandleCommand;
+
+ browser_funcs.request_funcs = &request_funcs;
+ browser_funcs.response_funcs = &response_funcs;
+
+ request_funcs.size = sizeof(request_funcs);
+ request_funcs.start_request = CPR_StartRequest;
+ request_funcs.end_request = CPR_EndRequest;
+ request_funcs.set_extra_request_headers = CPR_SetExtraRequestHeaders;
+ request_funcs.set_request_load_flags = CPR_SetRequestLoadFlags;
+ request_funcs.append_data_to_upload = CPR_AppendDataToUpload;
+ request_funcs.get_response_info = CPR_GetResponseInfo;
+ request_funcs.read = CPR_Read;
+ request_funcs.append_file_to_upload = CPR_AppendFileToUpload;
+
+ response_funcs.size = sizeof(response_funcs);
+ response_funcs.received_redirect = CPRR_ReceivedRedirect;
+ response_funcs.start_completed = CPRR_StartCompleted;
+ response_funcs.read_completed = CPRR_ReadCompleted;
+ response_funcs.upload_progress = CPRR_UploadProgress;
+ }
+
+ return &browser_funcs;
+}
diff --git a/chrome/plugin/chrome_plugin_host.h b/chrome/plugin/chrome_plugin_host.h
new file mode 100644
index 0000000..365f96b
--- /dev/null
+++ b/chrome/plugin/chrome_plugin_host.h
@@ -0,0 +1,38 @@
+// 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 CHROME_PLUGIN_CHROME_PLUGIN_HOST_H__
+#define CHROME_PLUGIN_CHROME_PLUGIN_HOST_H__
+
+#include "chrome/common/chrome_plugin_api.h"
+
+// Returns the table of browser functions for use from the plugin process.
+CPBrowserFuncs* GetCPBrowserFuncsForPlugin();
+
+#endif // CHROME_PLUGIN_CHROME_PLUGIN_HOST_H__
diff --git a/chrome/plugin/npobject_proxy.cc b/chrome/plugin/npobject_proxy.cc
new file mode 100644
index 0000000..2dc8819
--- /dev/null
+++ b/chrome/plugin/npobject_proxy.cc
@@ -0,0 +1,374 @@
+// 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 "chrome/plugin/npobject_proxy.h"
+
+#include "chrome/common/plugin_messages.h"
+#include "chrome/common/win_util.h"
+#include "chrome/plugin/npobject_util.h"
+#include "chrome/plugin/plugin_channel_base.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+
+
+struct NPObjectWrapper {
+ NPObject object;
+ NPObjectProxy* proxy;
+};
+
+NPClass NPObjectProxy::npclass_proxy_ = {
+ 2,
+ NPObjectProxy::NPAllocate,
+ NPObjectProxy::NPDeallocate,
+ NPObjectProxy::NPPInvalidate,
+ NPObjectProxy::NPHasMethod,
+ NPObjectProxy::NPInvoke,
+ NPObjectProxy::NPInvokeDefault,
+ NPObjectProxy::NPHasProperty,
+ NPObjectProxy::NPGetProperty,
+ NPObjectProxy::NPSetProperty,
+ NPObjectProxy::NPRemoveProperty,
+ NPObjectProxy::NPNEnumerate
+};
+
+NPObjectProxy* NPObjectProxy::GetProxy(NPObject* object) {
+ NPObjectProxy* proxy = NULL;
+
+ // Wrapper exists only for NPObjects that we had created.
+ if (&npclass_proxy_ == object->_class) {
+ NPObjectWrapper* wrapper = reinterpret_cast<NPObjectWrapper*>(object);
+ proxy = wrapper->proxy;
+ }
+
+ return proxy;
+}
+
+NPObjectProxy::NPObjectProxy(
+ PluginChannelBase* channel,
+ int route_id,
+ void* npobject_ptr,
+ HANDLE modal_dialog_event)
+ : channel_(channel),
+ route_id_(route_id),
+ npobject_ptr_(npobject_ptr),
+ modal_dialog_event_(modal_dialog_event) {
+ channel_->AddRoute(route_id, this, true);
+}
+
+NPObjectProxy::~NPObjectProxy() {
+ if (channel_.get()) {
+ Send(new NPObjectMsg_Release(route_id_));
+ if (channel_.get())
+ channel_->RemoveRoute(route_id_);
+ }
+}
+
+NPObject* NPObjectProxy::Create(PluginChannelBase* channel,
+ int route_id,
+ void* npobject_ptr,
+ HANDLE modal_dialog_event) {
+ NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(
+ NPN_CreateObject(0, &npclass_proxy_));
+ obj->proxy = new NPObjectProxy(
+ channel, route_id, npobject_ptr, modal_dialog_event);
+
+ return reinterpret_cast<NPObject*>(obj);
+}
+
+bool NPObjectProxy::Send(IPC::Message* msg) {
+ if (channel_.get())
+ return channel_->Send(msg);
+
+ delete msg;
+ return false;
+}
+
+NPObject* NPObjectProxy::NPAllocate(NPP, NPClass*) {
+ return reinterpret_cast<NPObject*>(new NPObjectWrapper);
+}
+
+void NPObjectProxy::NPDeallocate(NPObject* npObj) {
+ NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(npObj);
+ delete obj->proxy;
+ delete obj;
+}
+
+void NPObjectProxy::OnMessageReceived(const IPC::Message& msg) {
+ NOTREACHED();
+}
+
+void NPObjectProxy::OnChannelError() {
+ // Release our ref count of the plugin channel object, as it addrefs the
+ // process.
+ channel_ = NULL;
+}
+
+bool NPObjectProxy::NPHasMethod(NPObject *obj,
+ NPIdentifier name) {
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+
+ if (!proxy) {
+ return obj->_class->hasMethod(obj, name);
+ }
+
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ proxy->Send(new NPObjectMsg_HasMethod(proxy->route_id(), name_param, &result));
+ return result;
+}
+
+bool NPObjectProxy::NPInvoke(NPObject *obj,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result) {
+ return NPInvokePrivate(0, obj, false, name, args, arg_count, result);
+}
+
+bool NPObjectProxy::NPInvokeDefault(NPObject *npobj,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result) {
+ return NPInvokePrivate(0, npobj, true, 0, args, arg_count, result);
+}
+
+bool NPObjectProxy::NPInvokePrivate(NPP npp,
+ NPObject *obj,
+ bool is_default,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *np_result) {
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->invoke(obj, name, args, arg_count, np_result);
+ }
+
+ bool result = false;
+ NPIdentifier_Param name_param;
+ if (is_default) {
+ // The data won't actually get used, but set it so we don't send random data.
+ name_param.is_string = true;
+ } else {
+ CreateNPIdentifierParam(name, &name_param);
+ }
+
+ // Note: This instance can get destroyed in the context of
+ // Send so addref the channel in this scope.
+ scoped_refptr<PluginChannelBase> channel_copy = proxy->channel_;
+ std::vector<NPVariant_Param> args_param;
+ for (unsigned int i = 0; i < arg_count; ++i) {
+ NPVariant_Param param;
+ CreateNPVariantParam(args[i], channel_copy, &param, false);
+ args_param.push_back(param);
+ }
+
+ NPVariant_Param param_result;
+ NPObjectMsg_Invoke* msg = new NPObjectMsg_Invoke(
+ proxy->route_id_, is_default, name_param, args_param, &param_result,
+ &result);
+
+ // If we're in the plugin process and this invoke leads to a dialog box, the
+ // plugin will hang the window hierarchy unless we pump the window message
+ // queue while waiting for a reply. We need to do this to simulate what
+ // happens when everything runs in-process (while calling MessageBox window
+ // messages are pumped).
+ msg->set_pump_messages_event(proxy->modal_dialog_event_);
+
+ proxy->Send(msg);
+
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ param_result, channel_copy, np_result, proxy->modal_dialog_event_);
+ return true;
+}
+
+bool NPObjectProxy::NPHasProperty(NPObject *obj,
+ NPIdentifier name) {
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->hasProperty(obj, name);
+ }
+
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param param;
+ proxy->Send(new NPObjectMsg_HasProperty(
+ proxy->route_id(), name_param, &result));
+
+ return result;
+}
+
+bool NPObjectProxy::NPGetProperty(NPObject *obj,
+ NPIdentifier name,
+ NPVariant *np_result) {
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->getProperty(obj, name, np_result);
+ }
+
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param param;
+ proxy->Send(new NPObjectMsg_GetProperty(
+ proxy->route_id(), name_param, &param, &result));
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ param, proxy->channel(), np_result, proxy->modal_dialog_event_);
+
+ return true;
+}
+
+bool NPObjectProxy::NPSetProperty(NPObject *obj,
+ NPIdentifier name,
+ const NPVariant *value) {
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->setProperty(obj, name, value);
+ }
+
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param value_param;
+ CreateNPVariantParam(*value, proxy->channel(), &value_param, false);
+
+ proxy->Send(new NPObjectMsg_SetProperty(
+ proxy->route_id(), name_param, value_param, &result));
+
+ return result;
+}
+
+bool NPObjectProxy::NPRemoveProperty(NPObject *obj,
+ NPIdentifier name) {
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->removeProperty(obj, name);
+ }
+
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param param;
+ proxy->Send(new NPObjectMsg_RemoveProperty(
+ proxy->route_id(), name_param, &result));
+
+ return result;
+}
+
+void NPObjectProxy::NPPInvalidate(NPObject *obj) {
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->invalidate(obj);
+ }
+
+ proxy->Send(new NPObjectMsg_Invalidate(proxy->route_id()));
+}
+
+bool NPObjectProxy::NPNEnumerate(NPObject *obj,
+ NPIdentifier **value,
+ uint32_t *count) {
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->enumerate(obj, value, count);
+ }
+
+ std::vector<NPIdentifier_Param> value_param;
+ proxy->Send(new NPObjectMsg_Enumeration(
+ proxy->route_id(), &value_param, &result));
+
+ if (!result)
+ return false;
+
+ *count = static_cast<unsigned int>(value_param.size());
+ *value = static_cast<NPIdentifier *>(
+ NPN_MemAlloc(sizeof(NPIdentifier) * *count));
+ for (unsigned int i = 0; i < *count; ++i)
+ (*value)[i] = CreateNPIdentifier(value_param[i]);
+
+ return true;
+}
+
+bool NPObjectProxy::NPNEvaluate(NPP npp,
+ NPObject *obj,
+ NPString *script,
+ NPVariant *result_var) {
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return false;
+ }
+
+ NPVariant_Param result_param;
+ std::string script_str = std::string(
+ script->UTF8Characters, script->UTF8Length);
+
+ NPObjectMsg_Evaluate* msg = new NPObjectMsg_Evaluate(proxy->route_id(),
+ script_str,
+ &result_param,
+ &result);
+
+ // Please refer to the comments in NPObjectProxy::NPInvokePrivate for
+ // the reasoning behind setting the pump messages event in the sync message.
+ msg->set_pump_messages_event(proxy->modal_dialog_event_);
+ proxy->Send(msg);
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ result_param, proxy->channel(), result_var, proxy->modal_dialog_event_);
+ return true;
+}
+
+void NPObjectProxy::NPNSetException(NPObject *obj,
+ const NPUTF8 *message) {
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return;
+ }
+
+ NPVariant_Param result_param;
+ std::string message_str(message);
+
+ proxy->Send(new NPObjectMsg_SetException(proxy->route_id(), message_str));
+}
diff --git a/chrome/plugin/npobject_proxy.h b/chrome/plugin/npobject_proxy.h
new file mode 100644
index 0000000..b75aa1c
--- /dev/null
+++ b/chrome/plugin/npobject_proxy.h
@@ -0,0 +1,140 @@
+// 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.
+//
+// A proxy for NPObject that sends all calls to the object to an NPObjectStub
+// running in a different process.
+
+#ifndef CHROME_PLUGIN_NPOBJECT_PROXY_H__
+#define CHROME_PLUGIN_NPOBJECT_PROXY_H__
+
+#include "base/ref_counted.h"
+#include "bindings/npruntime.h"
+#include "chrome/common/ipc_channel.h"
+
+class PluginChannelBase;
+struct NPObject;
+struct NPVariant_Param;
+
+// When running a plugin in a different process from the renderer, we need to
+// proxy calls to NPObjects across process boundaries. This happens both ways,
+// as a plugin can get an NPObject for the window, and a page can get an
+// NPObject for the plugin. In the process that interacts with the NPobject we
+// give it an NPObjectProxy instead. All calls to it are sent across an IPC
+// channel (specifically, a PluginChannelBase). The NPObjectStub on the other
+// side translates the IPC messages into calls to the actual NPObject, and
+// returns the marshalled result.
+class NPObjectProxy : public IPC::Channel::Listener,
+ public IPC::Message::Sender {
+ public:
+ ~NPObjectProxy();
+
+ static NPObject* Create(PluginChannelBase* channel,
+ int route_id,
+ void* npobject_ptr,
+ HANDLE modal_dialog_event);
+
+ // IPC::Message::Sender implementation:
+ bool Send(IPC::Message* msg);
+ int route_id() { return route_id_; }
+ PluginChannelBase* channel() { return channel_; }
+
+ // Returns the real NPObject's pointer (obviously only valid in the other
+ // process).
+ void* npobject_ptr() { return npobject_ptr_; }
+
+ // The next 8 functions are called on NPObjects from the plugin and browser.
+ static bool NPHasMethod(NPObject *obj,
+ NPIdentifier name);
+ static bool NPInvoke(NPObject *obj,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result);
+ static bool NPInvokeDefault(NPObject *npobj,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result);
+ static bool NPHasProperty(NPObject *obj,
+ NPIdentifier name);
+ static bool NPGetProperty(NPObject *obj,
+ NPIdentifier name,
+ NPVariant *result);
+ static bool NPSetProperty(NPObject *obj,
+ NPIdentifier name,
+ const NPVariant *value);
+ static bool NPRemoveProperty(NPObject *obj,
+ NPIdentifier name);
+ static bool NPNEnumerate(NPObject *obj,
+ NPIdentifier **value,
+ uint32_t *count);
+
+ // The next two functions are only called on NPObjects from the browser.
+ static bool NPNEvaluate(NPP npp,
+ NPObject *obj,
+ NPString *script,
+ NPVariant *result);
+
+ static void NPNSetException(NPObject *obj,
+ const NPUTF8 *message);
+
+ static bool NPInvokePrivate(NPP npp,
+ NPObject *obj,
+ bool is_default,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result);
+
+ static NPObjectProxy* GetProxy(NPObject* object);
+ static const NPClass* npclass() { return &npclass_proxy_; }
+
+ private:
+ NPObjectProxy(PluginChannelBase* channel,
+ int route_id,
+ void* npobject_ptr,
+ HANDLE modal_dialog_event);
+
+ // IPC::Channel::Listener implementation:
+ void OnMessageReceived(const IPC::Message& msg);
+ void OnChannelError();
+
+ static NPObject* NPAllocate(NPP, NPClass*);
+ static void NPDeallocate(NPObject* npObj);
+
+ // This function is only caled on NPObjects from the plugin.
+ static void NPPInvalidate(NPObject *obj);
+ static NPClass npclass_proxy_;
+
+ int route_id_;
+ void* npobject_ptr_;
+ scoped_refptr<PluginChannelBase> channel_;
+ HANDLE modal_dialog_event_;
+};
+
+#endif // CHROME_PLUGIN_NPOBJECT_PROXY_H__
diff --git a/chrome/plugin/npobject_stub.cc b/chrome/plugin/npobject_stub.cc
new file mode 100644
index 0000000..3ec6ca5
--- /dev/null
+++ b/chrome/plugin/npobject_stub.cc
@@ -0,0 +1,320 @@
+// 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 "chrome/plugin/npobject_stub.h"
+
+#include "bindings/npapi.h"
+#include "bindings/npruntime.h"
+#include "chrome/common/plugin_messages.h"
+#include "chrome/plugin/npobject_util.h"
+#include "chrome/plugin/plugin_channel_base.h"
+#include "chrome/renderer/webplugin_delegate_proxy.h"
+
+NPObjectStub::NPObjectStub(
+ NPObject* npobject, PluginChannelBase* channel, int route_id)
+ : channel_(channel),
+ npobject_(npobject),
+ route_id_(route_id),
+ valid_(true),
+ web_plugin_delegate_proxy_(NULL) {
+ channel_->AddRoute(route_id, this, true);
+
+ // We retain the object just as PluginHost does if everything was in-process.
+ NPN_RetainObject(npobject_);
+}
+
+NPObjectStub::~NPObjectStub() {
+ if (web_plugin_delegate_proxy_)
+ web_plugin_delegate_proxy_->DropWindowScriptObject();
+
+ channel_->RemoveRoute(route_id_);
+ if (npobject_ && valid_)
+ NPN_ReleaseObject(npobject_);
+}
+
+bool NPObjectStub::Send(IPC::Message* msg) {
+ return channel_->Send(msg);
+}
+
+void NPObjectStub::OnMessageReceived(const IPC::Message& msg) {
+ if (!valid_) {
+ if (msg.is_sync()) {
+ // The object could be garbage because the frame has gone away, so
+ // just send an error reply to the caller.
+ IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
+ reply->set_reply_error();
+ Send(reply);
+ }
+
+ return;
+ }
+
+ IPC_BEGIN_MESSAGE_MAP(NPObjectStub, msg)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Release, OnRelease);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_HasMethod, OnHasMethod);
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Invoke, OnInvoke);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_HasProperty, OnHasProperty);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_GetProperty, OnGetProperty);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_SetProperty, OnSetProperty);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_RemoveProperty, OnRemoveProperty);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_Invalidate, OnInvalidate);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_Enumeration, OnEnumeration);
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Evaluate, OnEvaluate);
+ IPC_MESSAGE_HANDLER(NPObjectMsg_SetException, OnSetException);
+ IPC_MESSAGE_UNHANDLED_ERROR()
+ IPC_END_MESSAGE_MAP()
+}
+
+void NPObjectStub::OnChannelError() {
+ // When the plugin process is shutting down, all the NPObjectStubs
+ // destructors are called. However the plugin dll might have already
+ // been released, in which case the NPN_ReleaseObject will cause a crash.
+ npobject_ = NULL;
+ delete this;
+}
+
+void NPObjectStub::OnRelease(IPC::Message* reply_msg) {
+ Send(reply_msg);
+ delete this;
+}
+
+void NPObjectStub::OnHasMethod(const NPIdentifier_Param& name,
+ bool* result) {
+ NPIdentifier id = CreateNPIdentifier(name);
+ // If we're in the plugin process, then the stub is holding onto an NPObject
+ // from the plugin, so all function calls on it need to go through the
+ // functions in NPClass. If we're in the renderer process, then we just call
+ // the NPN_ functions.
+ if (IsPluginProcess()) {
+ if (npobject_->_class->hasMethod) {
+ *result = npobject_->_class->hasMethod(npobject_, id);
+ } else {
+ *result = false;
+ }
+ } else {
+ *result = NPN_HasMethod(0, npobject_, id);
+ }
+}
+
+void NPObjectStub::OnInvoke(bool is_default,
+ const NPIdentifier_Param& method,
+ const std::vector<NPVariant_Param>& args,
+ IPC::Message* reply_msg) {
+ scoped_refptr<PluginChannelBase> local_channel = channel_;
+ bool return_value = false;
+ NPVariant_Param result_param;
+ NPVariant result_var;
+
+ VOID_TO_NPVARIANT(result_var);
+
+ int arg_count = static_cast<int>(args.size());
+ NPVariant* args_var = new NPVariant[arg_count];
+ for (int i = 0; i < arg_count; ++i)
+ CreateNPVariant(args[i], local_channel, &(args_var[i]), NULL);
+
+ if (is_default) {
+ if (IsPluginProcess()) {
+ if (npobject_->_class->invokeDefault) {
+ return_value = npobject_->_class->invokeDefault(
+ npobject_, args_var, arg_count, &result_var);
+ } else {
+ return_value = false;
+ }
+ } else {
+ return_value = NPN_InvokeDefault(
+ 0, npobject_, args_var, arg_count, &result_var);
+ }
+ } else {
+ NPIdentifier id = CreateNPIdentifier(method);
+ if (IsPluginProcess()) {
+ if (npobject_->_class->invoke) {
+ return_value = npobject_->_class->invoke(
+ npobject_, id, args_var, arg_count, &result_var);
+ } else {
+ return_value = false;
+ }
+ } else {
+ return_value = NPN_Invoke(
+ 0, npobject_, id, args_var, arg_count, &result_var);
+ }
+ }
+
+ for (int i = 0; i < arg_count; ++i)
+ NPN_ReleaseVariantValue(&(args_var[i]));
+
+ delete[] args_var;
+
+ CreateNPVariantParam(result_var, local_channel, &result_param, true);
+ NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value);
+ local_channel->Send(reply_msg);
+}
+
+void NPObjectStub::OnHasProperty(const NPIdentifier_Param& name,
+ bool* result) {
+ NPIdentifier id = CreateNPIdentifier(name);
+ if (IsPluginProcess()) {
+ if (npobject_->_class->hasProperty) {
+ *result = npobject_->_class->hasProperty(npobject_, id);
+ } else {
+ *result = false;
+ }
+ } else {
+ *result = NPN_HasProperty(0, npobject_, id);
+ }
+}
+
+void NPObjectStub::OnGetProperty(const NPIdentifier_Param& name,
+ NPVariant_Param* property,
+ bool* result) {
+ NPVariant result_var;
+ VOID_TO_NPVARIANT(result_var);
+ NPIdentifier id = CreateNPIdentifier(name);
+
+ if (IsPluginProcess()) {
+ if (npobject_->_class->getProperty) {
+ *result = npobject_->_class->getProperty(npobject_, id, &result_var);
+ } else {
+ *result = false;
+ }
+ } else {
+ *result = NPN_GetProperty(0, npobject_, id, &result_var);
+ }
+
+ CreateNPVariantParam(result_var, channel_, property, true);
+}
+
+void NPObjectStub::OnSetProperty(const NPIdentifier_Param& name,
+ const NPVariant_Param& property,
+ bool* result) {
+ NPVariant result_var;
+ VOID_TO_NPVARIANT(result_var);
+ NPIdentifier id = CreateNPIdentifier(name);
+ NPVariant property_var;
+ CreateNPVariant(property, channel_, &property_var, NULL);
+
+ if (IsPluginProcess()) {
+ if (npobject_->_class->setProperty) {
+ *result = npobject_->_class->setProperty(npobject_, id, &property_var);
+ } else {
+ *result = false;
+ }
+ } else {
+ *result = NPN_SetProperty(0, npobject_, id, &property_var);
+ }
+
+ NPN_ReleaseVariantValue(&property_var);
+}
+
+void NPObjectStub::OnRemoveProperty(const NPIdentifier_Param& name,
+ bool* result) {
+ NPIdentifier id = CreateNPIdentifier(name);
+ if (IsPluginProcess()) {
+ if (npobject_->_class->removeProperty) {
+ *result = npobject_->_class->removeProperty(npobject_, id);
+ } else {
+ *result = false;
+ }
+ } else {
+ *result = NPN_RemoveProperty(0, npobject_, id);
+ }
+}
+
+void NPObjectStub::OnInvalidate() {
+ if (!IsPluginProcess()) {
+ NOTREACHED() << "Should only be called on NPObjects in the plugin";
+ return;
+ }
+
+ if (!npobject_->_class->invalidate)
+ return;
+
+ npobject_->_class->invalidate(npobject_);
+}
+
+void NPObjectStub::OnEnumeration(std::vector<NPIdentifier_Param>* value,
+ bool* result) {
+ NPIdentifier* value_np = NULL;
+ unsigned int count = 0;
+ if (!IsPluginProcess()) {
+ *result = NPN_Enumerate(0, npobject_, &value_np, &count);
+ } else {
+ if (!npobject_->_class->enumerate) {
+ *result = false;
+ return;
+ }
+
+ *result = npobject_->_class->enumerate(npobject_, &value_np, &count);
+ }
+
+ if (!*result)
+ return;
+
+ for (unsigned int i = 0; i < count; ++i) {
+ NPIdentifier_Param param;
+ CreateNPIdentifierParam(value_np[i], &param);
+ value->push_back(param);
+ }
+
+ NPN_MemFree(value_np);
+}
+
+void NPObjectStub::OnEvaluate(const std::string& script,
+ IPC::Message* reply_msg) {
+ if (IsPluginProcess()) {
+ NOTREACHED() << "Should only be called on NPObjects in the renderer";
+ return;
+ }
+
+ // Grab a reference to the underlying channel, as the NPObjectStub
+ // instance can be destroyed in the context of NPN_Evaluate. This
+ // can happen if the containing plugin instance is destroyed in
+ // NPN_Evaluate.
+ scoped_refptr<PluginChannelBase> local_channel = channel_;
+
+ NPVariant result_var;
+ NPString script_string;
+ script_string.UTF8Characters = script.c_str();
+ script_string.UTF8Length = static_cast<unsigned int>(script.length());
+
+ bool return_value = NPN_Evaluate(0, npobject_, &script_string, &result_var);
+
+ NPVariant_Param result_param;
+ CreateNPVariantParam(result_var, local_channel, &result_param, true);
+ NPObjectMsg_Evaluate::WriteReplyParams(reply_msg, result_param, return_value);
+ local_channel->Send(reply_msg);
+}
+
+void NPObjectStub::OnSetException(const std::string& message) {
+ if (IsPluginProcess()) {
+ NOTREACHED() << "Should only be called on NPObjects in the renderer";
+ return;
+ }
+
+ NPN_SetException(npobject_, message.c_str());
+}
diff --git a/chrome/plugin/npobject_stub.h b/chrome/plugin/npobject_stub.h
new file mode 100644
index 0000000..4d0bf2c
--- /dev/null
+++ b/chrome/plugin/npobject_stub.h
@@ -0,0 +1,106 @@
+// 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.
+//
+// A class that receives IPC messages from an NPObjectProxy and calls the real
+// NPObject.
+
+#ifndef CHROME_PLUGIN_NPOBJECT_STUB_H__
+#define CHROME_PLUGIN_NPOBJECT_STUB_H__
+
+#include "base/ref_counted.h"
+#include "chrome/common/ipc_channel.h"
+
+class PluginChannelBase;
+class WebPluginDelegateProxy;
+struct NPIdentifier_Param;
+struct NPObject;
+struct NPVariant_Param;
+
+// This wraps an NPObject and converts IPC messages from NPObjectProxy to calls
+// to the object. The results are marshalled back. See npobject_proxy.h for
+// more information.
+class NPObjectStub : public IPC::Channel::Listener,
+ public IPC::Message::Sender {
+ public:
+ NPObjectStub(NPObject* npobject, PluginChannelBase* channel, int route_id);
+ ~NPObjectStub();
+
+ // IPC::Message::Sender implementation:
+ bool Send(IPC::Message* msg);
+
+ // Called when the plugin widget that this NPObject came from is destroyed.
+ // This is needed because the renderer calls NPN_DeallocateObject on the
+ // window script object on destruction to avoid leaks.
+ void set_invalid() { valid_ = false; }
+ void set_proxy(WebPluginDelegateProxy* proxy) {
+ web_plugin_delegate_proxy_ = proxy;
+ }
+
+ private:
+ // IPC::Channel::Listener implementation:
+ void OnMessageReceived(const IPC::Message& message);
+ void OnChannelError();
+
+ // message handlers
+ void OnRelease(IPC::Message* reply_msg);
+ void OnHasMethod(const NPIdentifier_Param& name,
+ bool* result);
+ void OnInvoke(bool is_default,
+ const NPIdentifier_Param& method,
+ const std::vector<NPVariant_Param>& args,
+ IPC::Message* reply_msg);
+ void OnHasProperty(const NPIdentifier_Param& name,
+ bool* result);
+ void OnGetProperty(const NPIdentifier_Param& name,
+ NPVariant_Param* property,
+ bool* result);
+ void OnSetProperty(const NPIdentifier_Param& name,
+ const NPVariant_Param& property,
+ bool* result);
+ void OnRemoveProperty(const NPIdentifier_Param& name,
+ bool* result);
+ void OnInvalidate();
+ void OnEnumeration(std::vector<NPIdentifier_Param>* value,
+ bool* result);
+ void OnEvaluate(const std::string& script, IPC::Message* reply_msg);
+ void OnSetException(const std::string& message);
+
+ private:
+ NPObject* npobject_;
+ int route_id_;
+ scoped_refptr<PluginChannelBase> channel_;
+
+ // These variables are used to ensure that the window script object is not
+ // called after the plugin widget has gone away, as the frame manually
+ // deallocates it and ignores the refcount to avoid leaks.
+ bool valid_;
+ WebPluginDelegateProxy* web_plugin_delegate_proxy_;
+};
+
+#endif // CHROME_PLUGIN_NPOBJECT_STUB_H__
diff --git a/chrome/plugin/npobject_util.cc b/chrome/plugin/npobject_util.cc
new file mode 100644
index 0000000..fa6f68e
--- /dev/null
+++ b/chrome/plugin/npobject_util.cc
@@ -0,0 +1,275 @@
+// 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 "chrome/plugin/npobject_util.h"
+
+#include "chrome/common/plugin_messages.h"
+#include "chrome/common/win_util.h"
+#include "chrome/plugin/npobject_proxy.h"
+#include "chrome/plugin/plugin_channel_base.h"
+#include "webkit/glue/plugins/nphostapi.h"
+#include "webkit/glue/plugins/plugin_host.h"
+#include "webkit/glue/webkit_glue.h"
+
+// true if the current process is a plugin process, false if it's a renderer
+// process.
+static bool g_plugin_process;
+
+namespace {
+// The next 7 functions are called by the plugin code when it's using the
+// NPObject. Plugins always ignore the functions in NPClass (except allocate
+// and deallocate), and instead just use the function pointers that were
+// passed in NPInitialize.
+// When the renderer interacts with an NPObject from the plugin, it of course
+// uses the function pointers in its NPClass structure.
+static bool NPN_HasMethodPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier methodName) {
+ return NPObjectProxy::NPHasMethod(npobj, methodName);
+}
+
+static bool NPN_InvokePatch(NPP npp, NPObject *npobj,
+ NPIdentifier methodName,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result) {
+ return NPObjectProxy::NPInvokePrivate(npp, npobj, false, methodName, args, argCount, result);
+}
+
+static bool NPN_InvokeDefaultPatch(NPP npp,
+ NPObject *npobj,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result) {
+ return NPObjectProxy::NPInvokePrivate(npp, npobj, true, 0, args, argCount, result);
+}
+
+static bool NPN_HasPropertyPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName) {
+ return NPObjectProxy::NPHasProperty(npobj, propertyName);
+}
+
+static bool NPN_GetPropertyPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName,
+ NPVariant *result) {
+ return NPObjectProxy::NPGetProperty(npobj, propertyName, result);
+}
+
+static bool NPN_SetPropertyPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName,
+ const NPVariant *value) {
+ return NPObjectProxy::NPSetProperty(npobj, propertyName, value);
+}
+
+static bool NPN_RemovePropertyPatch(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName) {
+ return NPObjectProxy::NPRemoveProperty(npobj, propertyName);
+}
+
+static bool NPN_EvaluatePatch(NPP npp,
+ NPObject *npobj,
+ NPString *script,
+ NPVariant *result) {
+ return NPObjectProxy::NPNEvaluate(npp, npobj, script, result);
+}
+
+
+static void NPN_SetExceptionPatch(NPObject *obj,
+ const NPUTF8 *message) {
+ return NPObjectProxy::NPNSetException(obj, message);
+}
+
+static bool NPN_EnumeratePatch(NPP npp, NPObject *obj,
+ NPIdentifier **identifier, uint32_t *count) {
+ return NPObjectProxy::NPNEnumerate(obj, identifier, count);
+}
+
+// The overrided table of functions provided to the plugin.
+NPNetscapeFuncs *GetHostFunctions() {
+ static bool init = false;
+ static NPNetscapeFuncs host_funcs;
+ if (init)
+ return &host_funcs;
+
+ memset(&host_funcs, 0, sizeof(host_funcs));
+ host_funcs.invoke = NPN_InvokePatch;
+ host_funcs.invokeDefault = NPN_InvokeDefaultPatch;
+ host_funcs.evaluate = NPN_EvaluatePatch;
+ host_funcs.getproperty = NPN_GetPropertyPatch;
+ host_funcs.setproperty = NPN_SetPropertyPatch;
+ host_funcs.removeproperty = NPN_RemovePropertyPatch;
+ host_funcs.hasproperty = NPN_HasPropertyPatch;
+ host_funcs.hasmethod = NPN_HasMethodPatch;
+ host_funcs.setexception = NPN_SetExceptionPatch;
+ host_funcs.enumerate = NPN_EnumeratePatch;
+
+ init = true;
+ return &host_funcs;
+}
+
+}
+
+void PatchNPNFunctions() {
+ g_plugin_process = true;
+ NPNetscapeFuncs* funcs = GetHostFunctions();
+ NPAPI::PluginHost::Singleton()->PatchNPNetscapeFuncs(funcs);
+}
+
+bool IsPluginProcess() {
+ return g_plugin_process;
+}
+
+void CreateNPIdentifierParam(NPIdentifier id, NPIdentifier_Param* param) {
+ param->is_string = NPN_IdentifierIsString(id);
+ if (param->is_string) {
+ NPUTF8* utf8 = NPN_UTF8FromIdentifier(id);
+ param->string = utf8;
+ NPN_MemFree(utf8);
+ } else {
+ param->number = NPN_IntFromIdentifier(id);
+ }
+}
+
+NPIdentifier CreateNPIdentifier(const NPIdentifier_Param& param) {
+ if (param.is_string) {
+ return NPN_GetStringIdentifier(param.string.c_str());
+ } else {
+ return NPN_GetIntIdentifier(param.number);
+ }
+}
+
+void CreateNPVariantParam(const NPVariant& variant,
+ PluginChannelBase* channel,
+ NPVariant_Param* param,
+ bool release) {
+ switch (variant.type) {
+ case NPVariantType_Void:
+ param->type = NPVARIANT_PARAM_VOID;
+ break;
+ case NPVariantType_Null:
+ param->type = NPVARIANT_PARAM_NULL;
+ break;
+ case NPVariantType_Bool:
+ param->type = NPVARIANT_PARAM_BOOL;
+ param->bool_value = variant.value.boolValue;
+ break;
+ case NPVariantType_Int32:
+ param->type = NPVARIANT_PARAM_INT;
+ param->int_value = variant.value.intValue;
+ break;
+ case NPVariantType_Double:
+ param->type = NPVARIANT_PARAM_DOUBLE;
+ param->double_value = variant.value.doubleValue;
+ break;
+ case NPVariantType_String:
+ param->type = NPVARIANT_PARAM_STRING;
+ if (variant.value.stringValue.UTF8Length) {
+ param->string_value = std::string(variant.value.stringValue.UTF8Characters,
+ variant.value.stringValue.UTF8Length);
+ }
+ break;
+ case NPVariantType_Object:
+ {
+ if (variant.value.objectValue->_class == NPObjectProxy::npclass()) {
+ param->type = NPVARIANT_PARAM_OBJECT_POINTER;
+ param->npobject_pointer =
+ NPObjectProxy::GetProxy(variant.value.objectValue)->npobject_ptr();
+ // Don't release, because our original variant is the same as our proxy.
+ release = false;
+ } else {
+ // NPObjectStub adds its own reference to the NPObject it owns, so if we
+ // were supposed to release the corresponding variant (release==true),
+ // we should still do that.
+ param->type = NPVARIANT_PARAM_OBJECT_ROUTING_ID;
+ int route_id = channel->GenerateRouteID();
+ NPObjectStub* object_stub = new NPObjectStub(
+ variant.value.objectValue, channel, route_id);
+ param->npobject_routing_id = route_id;
+ param->npobject_pointer = variant.value.objectValue;
+ }
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+
+ if (release)
+ NPN_ReleaseVariantValue(const_cast<NPVariant*>(&variant));
+}
+
+void CreateNPVariant(const NPVariant_Param& param,
+ PluginChannelBase* channel,
+ NPVariant* result,
+ HANDLE modal_dialog_event) {
+ switch (param.type) {
+ case NPVARIANT_PARAM_VOID:
+ result->type = NPVariantType_Void;
+ break;
+ case NPVARIANT_PARAM_NULL:
+ result->type = NPVariantType_Null;
+ break;
+ case NPVARIANT_PARAM_BOOL:
+ result->type = NPVariantType_Bool;
+ result->value.boolValue = param.bool_value;
+ break;
+ case NPVARIANT_PARAM_INT:
+ result->type = NPVariantType_Int32;
+ result->value.intValue = param.int_value;
+ break;
+ case NPVARIANT_PARAM_DOUBLE:
+ result->type = NPVariantType_Double;
+ result->value.doubleValue = param.double_value;
+ break;
+ case NPVARIANT_PARAM_STRING:
+ result->type = NPVariantType_String;
+ result->value.stringValue.UTF8Characters =
+ static_cast<NPUTF8 *>(_strdup(param.string_value.c_str()));
+ result->value.stringValue.UTF8Length =
+ static_cast<int>(param.string_value.size());
+ break;
+ case NPVARIANT_PARAM_OBJECT_ROUTING_ID:
+ result->type = NPVariantType_Object;
+ result->value.objectValue = NPObjectProxy::Create(channel,
+ param.npobject_routing_id,
+ param.npobject_pointer,
+ modal_dialog_event);
+ break;
+ case NPVARIANT_PARAM_OBJECT_POINTER:
+ result->type = NPVariantType_Object;
+ result->value.objectValue = static_cast<NPObject*>(param.npobject_pointer);
+ NPN_RetainObject(result->value.objectValue);
+ break;
+ default:
+ NOTREACHED();
+ }
+}
diff --git a/chrome/plugin/npobject_util.h b/chrome/plugin/npobject_util.h
new file mode 100644
index 0000000..4a0694d
--- /dev/null
+++ b/chrome/plugin/npobject_util.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.
+//
+// Helper functions that are used by the NPObject proxy and stub.
+
+#ifndef CHROME_PLUGIN_NPOBJECT_UTIL_H__
+#define CHROME_PLUGIN_NPOBJECT_UTIL_H__
+
+#include <windows.h>
+#include "chrome/plugin/npobject_stub.h"
+
+struct _NPVariant;
+typedef _NPVariant NPVariant;
+class NPObjectProxy;
+class PluginChannelBase;
+struct NPIdentifier_Param;
+struct NPVariant_Param;
+typedef void *NPIdentifier;
+
+
+// Needs to be called early in the plugin process lifetime, before any
+// plugin instances are initialized.
+void PatchNPNFunctions();
+
+// Returns true if the current process is a plugin process, or false if it's a
+// renderer process.
+bool IsPluginProcess();
+
+// Creates an object similar to NPIdentifier that can be marshalled.
+void CreateNPIdentifierParam(NPIdentifier id, NPIdentifier_Param* param);
+
+// Creates an NPIdentifier from the marshalled object.
+NPIdentifier CreateNPIdentifier(const NPIdentifier_Param& param);
+
+// Creates an object similar to NPVariant that can be marshalled.
+// If the containing NPObject happens to be an NPObject, then a stub
+// is created around it and param holds the routing id for it.
+// If release is true, the NPVariant object is released (except if
+// it contains an NPObject, since the stub will manage its lifetime).
+void CreateNPVariantParam(const NPVariant& variant,
+ PluginChannelBase* channel,
+ NPVariant_Param* param,
+ bool release);
+
+// Creates an NPVariant from the marshalled object.
+void CreateNPVariant(const NPVariant_Param& param,
+ PluginChannelBase* channel,
+ NPVariant* result,
+ HANDLE modal_dialog_event);
+
+// Given a plugin's HWND, returns an event associated with the WebContents
+// that's set when inside a messagebox. This tells the plugin process that
+// the message queue should be pumped (as what would happen if everything was
+// in-process). This avoids deadlocks when a plugin invokes javascript that
+// causes a message box to come up.
+HANDLE GetMessageBoxEvent(HWND hwnd);
+
+#endif // CHROME_PLUGIN_NPOBJECT_UTIL_H__
diff --git a/chrome/plugin/plugin.vcproj b/chrome/plugin/plugin.vcproj
new file mode 100644
index 0000000..008a702
--- /dev/null
+++ b/chrome/plugin/plugin.vcproj
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="plugin"
+ ProjectGUID="{20A560A0-2CD0-4D9E-A58B-1F24B99C087A}"
+ RootNamespace="plugin"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\skia\using_skia.vsprops;..\tools\build\win\precompiled.vsprops;$(SolutionDir)..\third_party\npapi\using_npapi.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="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\third_party\npapi\using_npapi.vsprops;$(SolutionDir)..\skia\using_skia.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="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="NPObject"
+ >
+ <File
+ RelativePath=".\npobject_proxy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\npobject_proxy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\npobject_stub.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\npobject_stub.h"
+ >
+ </File>
+ <File
+ RelativePath=".\npobject_util.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\npobject_util.h"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\chrome_plugin_host.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\chrome_plugin_host.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_channel.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_channel.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_channel_base.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_channel_base.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_main.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_process.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_process.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_thread.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_thread.h"
+ >
+ </File>
+ <File
+ RelativePath="..\tools\build\win\precompiled.cc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\tools\build\win\precompiled.h"
+ >
+ </File>
+ <File
+ RelativePath=".\webplugin_delegate_stub.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\webplugin_delegate_stub.h"
+ >
+ </File>
+ <File
+ RelativePath=".\webplugin_proxy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\webplugin_proxy.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/chrome/plugin/plugin_channel.cc b/chrome/plugin/plugin_channel.cc
new file mode 100644
index 0000000..e21f5a9
--- /dev/null
+++ b/chrome/plugin/plugin_channel.cc
@@ -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.
+
+#include <windows.h>
+
+#include "chrome/plugin/plugin_channel.h"
+
+#include "chrome/common/plugin_messages.h"
+#include "base/string_util.h"
+#include "chrome/plugin/plugin_thread.h"
+#include "chrome/plugin/plugin_process.h"
+
+PluginChannel* PluginChannel::GetPluginChannel(
+ int process_id, HANDLE renderer_handle, MessageLoop* ipc_message_loop) {
+ // map renderer's process id to a (single) channel to that process
+ std::wstring channel_name = StringPrintf(
+ L"%d.r%d", GetCurrentProcessId(), process_id);
+
+ PluginChannelBase* result = PluginChannelBase::GetChannel(
+ channel_name,
+ IPC::Channel::MODE_SERVER,
+ ClassFactory,
+ ipc_message_loop,
+ false);
+
+ PluginChannel* channel = static_cast<PluginChannel*>(result);
+ if (channel && !channel->renderer_handle())
+ channel->renderer_handle_.Set(renderer_handle);
+
+ return channel;
+}
+
+PluginChannel::PluginChannel() : in_send_(0) {
+ SendUnblockingOnlyDuringDispatch();
+ PluginProcess::AddRefProcess();
+}
+
+PluginChannel::~PluginChannel() {
+ PluginProcess::ReleaseProcess();
+}
+
+bool PluginChannel::Send(IPC::Message* msg) {
+ in_send_++;
+ bool result = PluginChannelBase::Send(msg);
+ in_send_--;
+ return result;
+}
+
+void PluginChannel::OnControlMessageReceived(const IPC::Message& msg) {
+ IPC_BEGIN_MESSAGE_MAP(PluginChannel, msg)
+ IPC_MESSAGE_HANDLER(PluginMsg_CreateInstance, OnCreateInstance)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_DestroyInstance, OnDestroyInstance)
+ IPC_MESSAGE_HANDLER(PluginMsg_GenerateRouteID, OnGenerateRouteID)
+ IPC_MESSAGE_UNHANDLED_ERROR()
+ IPC_END_MESSAGE_MAP()
+}
+
+void PluginChannel::OnCreateInstance(const std::string& mime_type,
+ int* instance_id) {
+ *instance_id = GenerateRouteID();
+ scoped_refptr<WebPluginDelegateStub> stub = new WebPluginDelegateStub(
+ mime_type, *instance_id, this);
+ AddRoute(*instance_id, stub, false);
+ plugin_stubs_.push_back(stub);
+}
+
+void PluginChannel::OnDestroyInstance(int instance_id,
+ IPC::Message* reply_msg) {
+ for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
+ if (plugin_stubs_[i]->instance_id() == instance_id) {
+ plugin_stubs_.erase(plugin_stubs_.begin() + i);
+ RemoveRoute(instance_id);
+ Send(reply_msg);
+ return;
+ }
+ }
+
+ NOTREACHED() << "Couldn't find WebPluginDelegateStub to destroy";
+}
+
+void PluginChannel::OnGenerateRouteID(int* route_id) {
+ *route_id = GenerateRouteID();
+}
+
+int PluginChannel::GenerateRouteID() {
+ static LONG last_id = 0;
+ return InterlockedIncrement(&last_id);
+}
+
+void PluginChannel::OnChannelError() {
+ renderer_handle_.Set(NULL);
+ PluginChannelBase::OnChannelError();
+ CleanUp();
+}
+
+void PluginChannel::CleanUp() {
+ // We need to clean up the stubs so that they call NPPDestroy. This will
+ // also lead to them releasing their reference on this object so that it can
+ // be deleted.
+ for (size_t i = 0; i < plugin_stubs_.size(); ++i)
+ RemoveRoute(plugin_stubs_[i]->instance_id());
+
+ // Need to addref this object temporarily because otherwise removing the last
+ // stub will cause the destructor of this object to be called, however at
+ // that point plugin_stubs_ will have one element and its destructor will be
+ // called twice.
+ scoped_refptr<PluginChannel> me(this);
+
+ plugin_stubs_.clear();
+} \ No newline at end of file
diff --git a/chrome/plugin/plugin_channel.h b/chrome/plugin/plugin_channel.h
new file mode 100644
index 0000000..0324bbb
--- /dev/null
+++ b/chrome/plugin/plugin_channel.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 CHROME_PLUGIN_PLUGIN_CHANNEL_H__
+#define CHROME_PLUGIN_PLUGIN_CHANNEL_H__
+
+#include <vector>
+#include "base/scoped_handle.h"
+#include "chrome/plugin/plugin_channel_base.h"
+#include "chrome/plugin/webplugin_delegate_stub.h"
+
+// Encapsulates an IPC channel between the plugin process and one renderer
+// process. On the renderer side there's a corresponding PluginChannelHost.
+class PluginChannel : public PluginChannelBase {
+ public:
+ // renderer_handle is the the handle to the renderer process requesting the
+ // channel. The handle has to be valid in the context of the plugin process.
+ static PluginChannel* GetPluginChannel(
+ int process_id, HANDLE renderer_handle, MessageLoop* ipc_message_loop);
+
+ ~PluginChannel();
+
+ virtual bool Send(IPC::Message* msg);
+
+ HANDLE renderer_handle() { return renderer_handle_.Get(); }
+ int GenerateRouteID();
+
+ bool in_send() { return in_send_ != 0; }
+
+ protected:
+ // IPC::Channel::Listener implementation:
+ virtual void OnChannelError();
+
+ virtual void CleanUp();
+
+ private:
+ // Called on the plugin thread
+ PluginChannel();
+
+ void OnControlMessageReceived(const IPC::Message& msg);
+
+ static PluginChannelBase* ClassFactory() { return new PluginChannel(); }
+
+ void OnCreateInstance(const std::string& mime_type, int* instance_id);
+ void OnDestroyInstance(int instance_id, IPC::Message* reply_msg);
+ void OnGenerateRouteID(int* route_id);
+
+ std::vector<scoped_refptr<WebPluginDelegateStub>> plugin_stubs_;
+
+ // Handle to the renderer process who is on the other side of the channel.
+ ScopedHandle renderer_handle_;
+
+ int in_send_; // Tracks if we're in a Send call.
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginChannel);
+};
+
+#endif // CHROME_PLUGIN_PLUGIN_CHANNEL_H__
diff --git a/chrome/plugin/plugin_channel_base.cc b/chrome/plugin/plugin_channel_base.cc
new file mode 100644
index 0000000..1cb3111
--- /dev/null
+++ b/chrome/plugin/plugin_channel_base.cc
@@ -0,0 +1,216 @@
+// 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 <hash_map>
+#include <windows.h>
+
+#include "chrome/plugin/plugin_channel_base.h"
+
+#include "chrome/common/ipc_sync_message.h"
+
+typedef stdext::hash_map<std::wstring, scoped_refptr<PluginChannelBase> >
+ PluginChannelMap;
+
+static PluginChannelMap g_plugin_channels_;
+
+
+PluginChannelBase* PluginChannelBase::GetChannel(
+ const std::wstring& channel_name, IPC::Channel::Mode mode,
+ PluginChannelFactory factory, MessageLoop* ipc_message_loop,
+ bool create_pipe_now) {
+ scoped_refptr<PluginChannelBase> channel;
+
+ PluginChannelMap::const_iterator iter = g_plugin_channels_.find(channel_name);
+ if (iter == g_plugin_channels_.end()) {
+ channel = factory();
+ } else {
+ channel = iter->second;
+ }
+
+ DCHECK(channel != NULL);
+
+ if (!channel->channel_valid()) {
+ channel->channel_name_ = channel_name;
+ channel->mode_ = mode;
+ if (channel->Init(ipc_message_loop, create_pipe_now)) {
+ g_plugin_channels_[channel_name] = channel;
+ } else {
+ channel = NULL;
+ }
+ }
+
+ return channel;
+}
+
+PluginChannelBase::PluginChannelBase()
+ : plugin_count_(0),
+ peer_pid_(0),
+ in_remove_route_(false),
+ channel_valid_(false),
+ in_dispatch_(0),
+ send_unblocking_only_during_dispatch_(false) {
+}
+
+PluginChannelBase::~PluginChannelBase() {
+}
+
+void PluginChannelBase::CleanupChannels() {
+ // Make a copy of the references as we can't iterate the map since items will
+ // be removed from it as we clean them up.
+ std::vector<scoped_refptr<PluginChannelBase>> channels;
+ for (PluginChannelMap::const_iterator iter = g_plugin_channels_.begin();
+ iter != g_plugin_channels_.end();
+ ++iter) {
+ channels.push_back(iter->second);
+ }
+
+ for (size_t i = 0; i < channels.size(); ++i)
+ channels[i]->CleanUp();
+
+ // This will clean up channels added to the map for which subsequent
+ // AddRoute wasn't called
+ g_plugin_channels_.clear();
+}
+
+bool PluginChannelBase::Init(MessageLoop* ipc_message_loop,
+ bool create_pipe_now) {
+ channel_.reset(new IPC::SyncChannel(channel_name_, mode_, this,
+ ipc_message_loop, create_pipe_now));
+ channel_valid_ = true;
+ return true;
+}
+
+bool PluginChannelBase::Send(IPC::Message* message) {
+ if (!channel_.get()) {
+ delete message;
+ return false;
+ }
+
+ if (send_unblocking_only_during_dispatch_ && in_dispatch_ == 0 &&
+ message->is_sync()) {
+ message->set_unblock(false);
+ }
+
+ return channel_->Send(message);
+}
+
+int PluginChannelBase::Count() {
+ return static_cast<int>(g_plugin_channels_.size());
+}
+
+void PluginChannelBase::OnMessageReceived(const IPC::Message& message) {
+ // This call might cause us to be deleted, so keep an extra reference to
+ // ourself so that we can send the reply and decrement back in_dispatch_.
+ scoped_refptr<PluginChannelBase> me(this);
+
+ in_dispatch_++;
+ if (message.routing_id() == MSG_ROUTING_CONTROL) {
+ OnControlMessageReceived(message);
+ } else {
+ bool routed = router_.RouteMessage(message);
+ if (!routed && message.is_sync()) {
+ // The listener has gone away, so we must respond or else the caller will
+ // hang waiting for a reply.
+ IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
+ reply->set_reply_error();
+ Send(reply);
+ }
+ }
+ in_dispatch_--;
+}
+
+void PluginChannelBase::OnChannelConnected(int32 peer_pid) {
+ peer_pid_ = peer_pid;
+}
+
+void PluginChannelBase::AddRoute(int route_id,
+ IPC::Channel::Listener* listener,
+ bool npobject) {
+ if (npobject) {
+ npobject_listeners_[route_id] = listener;
+ } else {
+ plugin_count_++;
+ }
+
+ router_.AddRoute(route_id, listener);
+}
+
+void PluginChannelBase::RemoveRoute(int route_id) {
+ router_.RemoveRoute(route_id);
+
+ ListenerMap::iterator iter = npobject_listeners_.find(route_id);
+ if (iter != npobject_listeners_.end()) {
+ // This was an NPObject proxy or stub, it's not involved in the refcounting.
+
+ // If this RemoveRoute call from the NPObject is a result of us calling
+ // OnChannelError below, don't call erase() here because that'll corrupt
+ // the iterator below.
+ if (!in_remove_route_)
+ npobject_listeners_.erase(iter);
+
+ return;
+ }
+
+ plugin_count_--;
+ DCHECK(plugin_count_ >= 0);
+
+ if (!plugin_count_) {
+ ListenerMap::iterator npobj_iter = npobject_listeners_.begin();
+ in_remove_route_ = true;
+ while (npobj_iter != npobject_listeners_.end()) {
+ npobj_iter->second->OnChannelError();
+ npobj_iter++;
+ }
+ in_remove_route_ = false;
+
+ PluginChannelMap::iterator iter = g_plugin_channels_.begin();
+ while (iter != g_plugin_channels_.end()) {
+ if (iter->second == this) {
+ g_plugin_channels_.erase(iter);
+ return;
+ }
+
+ iter++;
+ }
+
+ NOTREACHED();
+ }
+}
+
+void PluginChannelBase::OnControlMessageReceived(const IPC::Message& msg) {
+ NOTREACHED() << "should override in subclass if you care about control messages";
+}
+
+void PluginChannelBase::OnChannelError() {
+ channel_valid_ = false;
+}
+
+void PluginChannelBase::SendUnblockingOnlyDuringDispatch() {
+ send_unblocking_only_during_dispatch_ = true;
+}
diff --git a/chrome/plugin/plugin_channel_base.h b/chrome/plugin/plugin_channel_base.h
new file mode 100644
index 0000000..12565e1
--- /dev/null
+++ b/chrome/plugin/plugin_channel_base.h
@@ -0,0 +1,144 @@
+// 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 CHROME_WEBKIT_GLUE_PLUGIN_CHANNEL_BASE_H__
+#define CHROME_WEBKIT_GLUE_PLUGIN_CHANNEL_BASE_H__
+
+#include <hash_map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "chrome/common/ipc_sync_channel.h"
+#include "chrome/common/message_router.h"
+
+// Encapsulates an IPC channel between a renderer and a plugin process.
+class PluginChannelBase : public IPC::Channel::Listener,
+ public IPC::Message::Sender,
+ public base::RefCountedThreadSafe<PluginChannelBase> {
+ public:
+ virtual ~PluginChannelBase();
+
+ // WebPlugin[Delegate] call these on construction and destruction to setup
+ // the routing and manage lifetime of this object. This is also called by
+ // NPObjectProxy and NPObjectStub. However the latter don't control the
+ // lifetime of this object (by passing true for npobject) because we don't
+ // want a leak of an NPObject in a plugin to keep the channel around longer
+ // than necessary.
+ void AddRoute(int route_id, IPC::Channel::Listener* listener, bool npobject);
+ void RemoveRoute(int route_id);
+
+ // IPC::Message::Sender implementation:
+ virtual bool Send(IPC::Message* msg);
+
+ int peer_pid() { return peer_pid_; }
+ std::wstring channel_name() const { return channel_name_; }
+
+ // Returns the number of open plugin channels in this process.
+ static int Count();
+
+ // Returns a new route id.
+ virtual int GenerateRouteID() = 0;
+
+ // Returns whether the channel is valid or not. A channel is invalid
+ // if it is disconnected due to a channel error.
+ bool channel_valid() {
+ return channel_valid_;
+ }
+
+ static void CleanupChannels();
+
+ protected:
+ typedef PluginChannelBase* (*PluginChannelFactory)();
+
+ // Returns a PluginChannelBase derived object for the given channel name.
+ // If an existing channel exists returns that object, otherwise creates a
+ // new one. Even though on creation the object is refcounted, each caller
+ // must still ref count the returned value. When there are no more routes
+ // on the channel and its ref count is 0, the object deletes itself.
+ static PluginChannelBase* GetChannel(
+ const std::wstring& channel_name, IPC::Channel::Mode mode,
+ PluginChannelFactory factory, MessageLoop* ipc_message_loop,
+ bool create_pipe_now);
+
+ // Called on the worker thread
+ PluginChannelBase();
+
+ virtual void CleanUp() { }
+
+ // Implemented by derived classes to handle control messages
+ virtual void OnControlMessageReceived(const IPC::Message& msg);
+
+ // IPC::Channel::Listener implementation:
+ virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual void OnChannelConnected(int32 peer_pid);
+ virtual void OnChannelError();
+
+ // If this is set, sync messages that are sent will only unblock the receiver
+ // if this channel is in the middle of a dispatch.
+ void SendUnblockingOnlyDuringDispatch();
+
+ virtual bool Init(MessageLoop* ipc_message_loop, bool create_pipe_now);
+
+ scoped_ptr<IPC::SyncChannel> channel_;
+
+ private:
+
+ IPC::Channel::Mode mode_;
+ std::wstring channel_name_;
+ int plugin_count_;
+ int peer_pid_;
+
+ // true when in the middle of a RemoveRoute call
+ bool in_remove_route_;
+
+ // Keep track of all the registered NPObjects proxies/stubs so that when the
+ // channel is closed we can inform them.
+ typedef stdext::hash_map<int, IPC::Channel::Listener*> ListenerMap;
+ ListenerMap npobject_listeners_;
+
+ // Used to implement message routing functionality to WebPlugin[Delegate]
+ // objects
+ MessageRouter router_;
+
+ // A channel is invalid if it is disconnected as a result of a channel
+ // error. This flag is used to indicate the same.
+ bool channel_valid_;
+
+ // If true, sync messages will only be marked as unblocking if the channel is
+ // in the middle of dispatching a message.
+ bool send_unblocking_only_during_dispatch_;
+ int in_dispatch_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginChannelBase);
+};
+
+#endif // CHROME_WEBKIT_GLUE_PLUGIN_CHANNEL_BASE_H__
diff --git a/chrome/plugin/plugin_main.cc b/chrome/plugin/plugin_main.cc
new file mode 100644
index 0000000..7f9c282
--- /dev/null
+++ b/chrome/plugin/plugin_main.cc
@@ -0,0 +1,100 @@
+// 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 "base/command_line.h"
+#include "base/message_loop.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/logging_chrome.h"
+#include "chrome/common/win_util.h"
+#include "chrome/plugin/plugin_process.h"
+#include "chrome/test/injection_test_dll.h"
+#include "sandbox/src/sandbox.h"
+
+// mainline routine for running as the plugin process
+int PluginMain(CommandLine &parsed_command_line, int show_command,
+ sandbox::TargetServices* target_services) {
+ CoInitialize(NULL);
+ DLOG(INFO) << "Started plugin with " <<
+ parsed_command_line.command_line_string();
+
+ HMODULE sandbox_test_module = NULL;
+ bool no_sandbox = parsed_command_line.HasSwitch(switches::kNoSandbox) ||
+ !parsed_command_line.HasSwitch(switches::kSafePlugins);
+ if (target_services && !no_sandbox) {
+ // The command line might specify a test dll to load.
+ if (parsed_command_line.HasSwitch(switches::kTestSandbox)) {
+ std::wstring test_dll_name =
+ parsed_command_line.GetSwitchValue(switches::kTestSandbox);
+ sandbox_test_module = LoadLibrary(test_dll_name.c_str());
+ DCHECK(sandbox_test_module);
+ }
+ }
+
+ if (parsed_command_line.HasSwitch(switches::kPluginStartupDialog)) {
+ std::wstring title = chrome::kBrowserAppName;
+ title += L" plugin"; // makes attaching to process easier
+ win_util::MessageBox(NULL, L"plugin starting...", title,
+ MB_OK | MB_SETFOREGROUND);
+ }
+
+ std::wstring channel_name =
+ parsed_command_line.GetSwitchValue(switches::kProcessChannelID);
+ std::wstring plugin_path =
+ parsed_command_line.GetSwitchValue(switches::kPluginPath);
+ if (PluginProcess::GlobalInit(channel_name, plugin_path)) {
+ if (!no_sandbox && target_services) {
+ target_services->LowerToken();
+ }
+
+ if (sandbox_test_module) {
+ RunRendererTests run_security_tests =
+ reinterpret_cast<RunPluginTests>(GetProcAddress(sandbox_test_module,
+ kPluginTestCall));
+ DCHECK(run_security_tests);
+ if (run_security_tests) {
+ int test_count = 0;
+ DLOG(INFO) << "Running plugin security tests";
+ BOOL result = run_security_tests(&test_count);
+ DCHECK(result) << "Test number " << test_count << " has failed.";
+ // If we are in release mode, crash or debug the process.
+ if (!result)
+ __debugbreak();
+ }
+ }
+
+ // Load the accelerator table from the browser executable and tell the
+ // message loop to use it when translating messages.
+ MessageLoop::current()->Run();
+ }
+ PluginProcess::GlobalCleanup();
+
+ CoUninitialize();
+ return 0;
+}
diff --git a/chrome/plugin/plugin_process.cc b/chrome/plugin/plugin_process.cc
new file mode 100644
index 0000000..53c0a3a
--- /dev/null
+++ b/chrome/plugin/plugin_process.cc
@@ -0,0 +1,122 @@
+// 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 "chrome/plugin/plugin_process.h"
+
+#include "base/basictypes.h"
+#include "base/scoped_handle.h"
+#include "chrome/common/ipc_channel.h"
+#include "chrome/common/ipc_message_utils.h"
+#include "chrome/common/plugin_messages.h"
+#include "chrome/common/render_messages.h"
+#include "webkit/glue/webkit_glue.h"
+
+// Custom factory to allow us to pass additional ctor arguments.
+class PluginProcessFactory : public ChildProcessFactoryInterface {
+ public:
+ explicit PluginProcessFactory(const std::wstring& plugin_path)
+ : plugin_path_(plugin_path) {
+ }
+
+ virtual ChildProcess* Create(const std::wstring& channel_name) {
+ return new PluginProcess(channel_name, plugin_path_);
+ }
+
+ const std::wstring& plugin_path_;
+};
+
+// How long to wait after there are no more plugin instances before killing the
+// process.
+static const int kProcessShutdownDelayMs = 10 * 1000;
+
+// No AddRef required when using PluginProcess with RunnableMethod. This is
+// okay since the lifetime of the PluginProcess is always greater than the
+// lifetime of PluginThread because it's a member variable.
+template <> struct RunnableMethodTraits<PluginProcess> {
+ static void RetainCallee(PluginProcess*) {}
+ static void ReleaseCallee(PluginProcess*) {}
+};
+
+PluginProcess::PluginProcess(const std::wstring& channel_name,
+ const std::wstring& plugin_path) :
+ plugin_path_(plugin_path),
+#pragma warning(suppress: 4355) // Okay to pass "this" here.
+ plugin_thread_(this, channel_name) {
+}
+
+PluginProcess::~PluginProcess() {
+}
+
+bool PluginProcess::GlobalInit(const std::wstring &channel_name,
+ const std::wstring &plugin_path) {
+ PluginProcessFactory factory(plugin_path);
+ return ChildProcess::GlobalInit(channel_name, &factory);
+}
+
+
+// Note: may be called on any thread
+void PluginProcess::OnFinalRelease() {
+ // We override this to have the process linger for a few seconds to
+ // better accomdate back/forth navigation. This avoids shutting down and
+ // immediately starting a new plugin process. If a new channel is
+ // opened in the interim, the current process will not be shutdown.
+ main_thread_loop_->PostDelayedTask(FROM_HERE, NewRunnableMethod(
+ this, &PluginProcess::OnProcessShutdownTimeout),
+ kProcessShutdownDelayMs);
+}
+
+void PluginProcess::OnProcessShutdownTimeout() {
+ if (GetProcessRefcount() == 0) {
+ // The plugin process shutdown sequence is a request response based
+ // mechanism, where we send out an initial feeler request to the plugin
+ // process host instance in the browser to verify if it is ok to shutdown
+ // the plugin process. The browser then sends back a response indicating
+ // whether it is ok to shutdown.
+ plugin_thread_.Send(new PluginProcessHostMsg_ShutdownRequest);
+ }
+}
+
+// static
+void PluginProcess::ShutdownProcessResponse(bool ok_to_shutdown) {
+ if (ok_to_shutdown) {
+ PluginProcess* plugin_process =
+ static_cast<PluginProcess*>(child_process_);
+ DCHECK(plugin_process);
+ plugin_process->Shutdown();
+ }
+}
+
+void PluginProcess::BrowserShutdown() {
+ ShutdownProcessResponse(true);
+}
+
+void PluginProcess::Shutdown() {
+ ChildProcess::OnFinalRelease();
+}
diff --git a/chrome/plugin/plugin_process.h b/chrome/plugin/plugin_process.h
new file mode 100644
index 0000000..e43a1ec
--- /dev/null
+++ b/chrome/plugin/plugin_process.h
@@ -0,0 +1,76 @@
+// 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 CHROME_PLUGIN_PLUGIN_PROCESS_H__
+#define CHROME_PLUGIN_PLUGIN_PROCESS_H__
+
+#include "chrome/common/child_process.h"
+#include "chrome/plugin/plugin_thread.h"
+
+// Represents the plugin end of the renderer<->plugin connection. The
+// opposite end is the PluginProcessHost. This is a singleton object for
+// each plugin.
+class PluginProcess : public ChildProcess {
+ public:
+ static bool GlobalInit(const std::wstring& channel_name,
+ const std::wstring& plugin_path);
+
+ // Invoked with the response from the browser indicating whether it is
+ // ok to shutdown the plugin process.
+ static void ShutdownProcessResponse(bool ok_to_shutdown);
+
+ // Invoked when the browser is shutdown. This ensures that the plugin
+ // process does not hang around waiting for future invocations
+ // from the browser.
+ static void BrowserShutdown();
+
+ // File path of the plugin dll this process hosts.
+ const std::wstring& plugin_path() { return plugin_path_; }
+
+ private:
+ friend class PluginProcessFactory;
+ PluginProcess(const std::wstring& channel_name,
+ const std::wstring& plugin_path);
+ virtual ~PluginProcess();
+
+ virtual void OnFinalRelease();
+ void Shutdown();
+ void OnProcessShutdownTimeout();
+
+ const std::wstring plugin_path_;
+
+ // The thread where plugin instances live. Since NPAPI plugins weren't
+ // created with multi-threading in mind, running multiple instances on
+ // different threads would be asking for trouble.
+ PluginThread plugin_thread_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginProcess);
+};
+
+#endif // CHROME_PLUGIN_PLUGIN_PROCESS_H__
diff --git a/chrome/plugin/plugin_thread.cc b/chrome/plugin/plugin_thread.cc
new file mode 100644
index 0000000..3c117df
--- /dev/null
+++ b/chrome/plugin/plugin_thread.cc
@@ -0,0 +1,206 @@
+// 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 <objbase.h>
+
+#include "chrome/plugin/plugin_thread.h"
+
+#include "chrome/common/chrome_plugin_lib.h"
+#include "chrome/common/ipc_logging.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/plugin_messages.h"
+#include "chrome/plugin/chrome_plugin_host.h"
+#include "chrome/plugin/npobject_util.h"
+#include "chrome/plugin/plugin_process.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "webkit/glue/webkit_glue.h"
+
+PluginThread* PluginThread::plugin_thread_;
+
+PluginThread::PluginThread(PluginProcess* process,
+ const std::wstring& channel_name)
+ : plugin_process_(process),
+ channel_name_(channel_name),
+ owner_loop_(MessageLoop::current()),
+ preloaded_plugin_module_(NULL),
+ Thread("Chrome_PluginThread") {
+ DCHECK(plugin_process_);
+ DCHECK(owner_loop_);
+ DCHECK(!plugin_thread_);
+ plugin_thread_ = this;
+
+ Start();
+}
+
+PluginThread::~PluginThread() {
+ Stop();
+ plugin_thread_ = NULL;
+}
+
+void PluginThread::OnChannelError() {
+ owner_loop_->Quit();
+}
+
+bool PluginThread::Send(IPC::Message* msg) {
+ return channel_->Send(msg);
+}
+
+void PluginThread::OnMessageReceived(const IPC::Message& msg) {
+ if (msg.routing_id() == MSG_ROUTING_CONTROL) {
+ // Resource responses are sent to the resource dispatcher.
+ if (resource_dispatcher_->OnMessageReceived(msg))
+ return;
+ IPC_BEGIN_MESSAGE_MAP(PluginThread, msg)
+ IPC_MESSAGE_HANDLER(PluginProcessMsg_CreateChannel, OnCreateChannel)
+ IPC_MESSAGE_HANDLER(PluginProcessMsg_ShutdownResponse, OnShutdownResponse)
+ IPC_MESSAGE_HANDLER(PluginProcessMsg_PluginMessage, OnPluginMessage)
+ IPC_MESSAGE_HANDLER(PluginProcessMsg_BrowserShutdown, OnBrowserShutdown)
+ IPC_END_MESSAGE_MAP()
+ } else {
+ NOTREACHED() << "Only control messages should reach PluginThread.";
+ }
+}
+
+void PluginThread::Init() {
+ PatchNPNFunctions();
+ CoInitialize(NULL);
+ channel_.reset(new IPC::SyncChannel(channel_name_,
+ IPC::Channel::MODE_CLIENT, this, owner_loop_, true));
+ notification_service_.reset(new NotificationService);
+ resource_dispatcher_ = new ResourceDispatcher(this);
+
+ // Preload the dll to avoid loading, unloading then reloading
+ preloaded_plugin_module_ = NPAPI::PluginLib::LoadPluginHelper(
+ plugin_process_->plugin_path().c_str());
+
+ ChromePluginLib::Create(plugin_process_->plugin_path(),
+ GetCPBrowserFuncsForPlugin());
+
+ scoped_refptr<NPAPI::PluginLib> plugin =
+ NPAPI::PluginLib::CreatePluginLib(plugin_process_->plugin_path());
+ if (plugin.get()) {
+ plugin->NP_Initialize();
+ }
+
+ // Certain plugins, such as flash, steal the unhandled exception filter
+ // thus we never get crash reports when they fault. This call fixes it.
+ message_loop()->set_exception_restoration(true);
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ IPC::Logging::current()->SetIPCSender(this);
+#endif
+}
+
+void PluginThread::CleanUp() {
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ IPC::Logging::current()->SetIPCSender(NULL);
+#endif
+ if (preloaded_plugin_module_) {
+ FreeLibrary(preloaded_plugin_module_);
+ preloaded_plugin_module_ = NULL;
+ }
+ PluginChannelBase::CleanupChannels();
+ NPAPI::PluginLib::UnloadAllPlugins();
+ ChromePluginLib::UnloadAllPlugins();
+ notification_service_.reset();
+ resource_dispatcher_ = NULL;
+ CoUninitialize();
+}
+
+void PluginThread::OnCreateChannel(int process_id, HANDLE renderer_handle) {
+ std::wstring channel_name;
+ scoped_refptr<PluginChannel> channel =
+ PluginChannel::GetPluginChannel(process_id, renderer_handle, owner_loop_);
+ if (channel.get())
+ channel_name = channel->channel_name();
+
+ Send(new PluginProcessHostMsg_ChannelCreated(process_id, channel_name));
+}
+
+void PluginThread::OnShutdownResponse(bool ok_to_shutdown) {
+ PluginProcess::ShutdownProcessResponse(ok_to_shutdown);
+}
+
+void PluginThread::OnBrowserShutdown() {
+ PluginProcess::BrowserShutdown();
+}
+
+void PluginThread::OnPluginMessage(const std::vector<unsigned char> &data) {
+ // We Add/Release ref here to ensure that something will trigger the
+ // shutdown mechanism for processes started in the absence of renderer's
+ // opening a plugin channel.
+ PluginProcess::AddRefProcess();
+ ChromePluginLib *chrome_plugin =
+ ChromePluginLib::Find(plugin_process_->plugin_path());
+ if (chrome_plugin) {
+ void *data_ptr = const_cast<void*>(reinterpret_cast<const void*>(&data[0]));
+ uint32 data_len = static_cast<uint32>(data.size());
+ chrome_plugin->functions().on_message(data_ptr, data_len);
+ }
+ PluginProcess::ReleaseProcess();
+}
+
+namespace webkit_glue {
+
+bool DownloadUrl(const std::string& url, HWND caller_window) {
+ PluginThread* plugin_thread = PluginThread::GetPluginThread();
+ if (!plugin_thread) {
+ return false;
+ }
+
+ IPC::Message* message =
+ new PluginProcessHostMsg_DownloadUrl(MSG_ROUTING_NONE, url,
+ ::GetCurrentProcessId(),
+ caller_window);
+ return plugin_thread->Send(message);
+}
+
+bool GetPluginFinderURL(std::string* plugin_finder_url) {
+ if (!plugin_finder_url) {
+ NOTREACHED();
+ return false;
+ }
+
+ PluginThread* plugin_thread = PluginThread::GetPluginThread();
+ if (!plugin_thread) {
+ return false;
+ }
+
+ plugin_thread->Send(
+ new PluginProcessHostMsg_GetPluginFinderUrl(plugin_finder_url));
+ DCHECK(!plugin_finder_url->empty());
+ return true;
+}
+
+bool IsDefaultPluginEnabled() {
+ return true;
+}
+
+} // namespace webkit_glue
diff --git a/chrome/plugin/plugin_thread.h b/chrome/plugin/plugin_thread.h
new file mode 100644
index 0000000..5a9fd37
--- /dev/null
+++ b/chrome/plugin/plugin_thread.h
@@ -0,0 +1,99 @@
+// 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 CHROME_PLUGIN_PLUGIN_THREAD_H__
+#define CHROME_PLUGIN_PLUGIN_THREAD_H__
+
+#include "base/thread.h"
+#include "chrome/common/ipc_sync_channel.h"
+#include "chrome/common/message_router.h"
+#include "chrome/common/resource_dispatcher.h"
+#include "chrome/plugin/plugin_channel.h"
+
+class PluginProcess;
+class NotificationService;
+
+// The PluginThread class represents a background thread where plugin instances
+// live. Communication occurs between WebPluginDelegateProxy in the renderer
+// process and WebPluginDelegateStub in this thread through IPC messages.
+class PluginThread : public IPC::Channel::Listener,
+ public IPC::Message::Sender,
+ public Thread {
+ public:
+ PluginThread(PluginProcess *process, const std::wstring& channel_name);
+ ~PluginThread();
+
+ // IPC::Channel::Listener implementation:
+ virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual void OnChannelError();
+
+ // IPC::Message::Sender implementation:
+ virtual bool Send(IPC::Message* msg);
+
+ // Returns the one plugin thread.
+ static PluginThread* GetPluginThread() { return plugin_thread_; }
+
+ // Returns the one true dispatcher.
+ ResourceDispatcher* resource_dispatcher() { return resource_dispatcher_.get(); }
+
+ private:
+ // Thread implementation:
+ void Init();
+ void CleanUp();
+
+ void OnCreateChannel(int process_id, HANDLE renderer_handle);
+ void OnShutdownResponse(bool ok_to_shutdown);
+ void OnPluginMessage(const std::vector<uint8> &data);
+ void OnBrowserShutdown();
+
+ // The process that has created this thread
+ PluginProcess *plugin_process_;
+
+ // The message loop used to run tasks on the thread that started this thread.
+ MessageLoop* owner_loop_;
+
+ std::wstring channel_name_;
+ scoped_ptr<IPC::SyncChannel> channel_;
+
+ scoped_ptr<NotificationService> notification_service_;
+
+ // Handles resource loads for this view.
+ // NOTE: this object lives on the owner thread.
+ scoped_refptr<ResourceDispatcher> resource_dispatcher_;
+
+ // The plugin module which is preloaded in Init
+ HMODULE preloaded_plugin_module_;
+
+ // Points to the one PluginThread object in the process.
+ static PluginThread* plugin_thread_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginThread);
+};
+
+#endif // CHROME_PLUGIN_PLUGIN_THREAD_H__
diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc
new file mode 100644
index 0000000..0678b14
--- /dev/null
+++ b/chrome/plugin/webplugin_delegate_stub.cc
@@ -0,0 +1,462 @@
+// 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 "chrome/plugin/webplugin_delegate_stub.h"
+
+#include "base/command_line.h"
+#include "base/time.h"
+#include "base/gfx/bitmap_header.h"
+#include "base/gfx/platform_device.h"
+#include "bindings/npapi.h"
+#include "bindings/npruntime.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/gfx/emf.h"
+#include "chrome/common/plugin_messages.h"
+#include "chrome/common/win_util.h"
+#include "chrome/plugin/npobject_stub.h"
+#include "chrome/plugin/plugin_channel.h"
+#include "chrome/plugin/plugin_thread.h"
+#include "chrome/plugin/webplugin_proxy.h"
+#include "webkit/glue/plugins/webplugin_delegate_impl.h"
+#include "webkit/glue/webcursor.h"
+
+class FinishDestructionTask : public Task {
+ public:
+ FinishDestructionTask(WebPluginDelegate* delegate, WebPlugin* webplugin)
+ : delegate_(delegate), webplugin_(webplugin) { }
+
+ void Run() {
+ // WebPlugin must outlive WebPluginDelegate.
+ if (delegate_)
+ delegate_->PluginDestroyed();
+
+ delete webplugin_;
+ }
+
+ private:
+ WebPluginDelegate* delegate_;
+ WebPlugin* webplugin_;
+};
+
+WebPluginDelegateStub::WebPluginDelegateStub(
+ const std::string& mime_type, int instance_id, PluginChannel* channel) :
+ mime_type_(mime_type),
+ instance_id_(instance_id),
+ channel_(channel),
+ delegate_(NULL),
+ webplugin_(NULL) {
+ DCHECK(channel);
+}
+
+WebPluginDelegateStub::~WebPluginDelegateStub() {
+ if (channel_->in_send()) {
+ // The delegate or an npobject is in the callstack, so don't delete it
+ // right away.
+ MessageLoop::current()->PostTask(FROM_HERE,
+ new FinishDestructionTask(delegate_, webplugin_));
+ } else {
+ // Safe to delete right away.
+ if (delegate_)
+ delegate_->PluginDestroyed();
+
+ delete webplugin_;
+ }
+}
+
+void WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) {
+ // A plugin can execute a script to delete itself in any of its NPP methods.
+ // Hold an extra reference to ourself so that if this does occur and we're
+ // handling a sync message, we don't crash when attempting to send a reply.
+ AddRef();
+
+ IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateStub, msg)
+ IPC_MESSAGE_HANDLER(PluginMsg_Init, OnInit)
+ IPC_MESSAGE_HANDLER(PluginMsg_WillSendRequest, OnWillSendRequest)
+ IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveResponse, OnDidReceiveResponse)
+ IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveData, OnDidReceiveData)
+ IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoading, OnDidFinishLoading)
+ IPC_MESSAGE_HANDLER(PluginMsg_DidFail, OnDidFail)
+ IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoadWithReason,
+ OnDidFinishLoadWithReason)
+ IPC_MESSAGE_HANDLER(PluginMsg_SetFocus, OnSetFocus)
+ IPC_MESSAGE_HANDLER(PluginMsg_HandleEvent, OnHandleEvent)
+ IPC_MESSAGE_HANDLER(PluginMsg_Paint, OnPaint)
+ IPC_MESSAGE_HANDLER(PluginMsg_Print, OnPrint)
+ IPC_MESSAGE_HANDLER(PluginMsg_PaintIntoSharedMemory,
+ OnPaintIntoSharedMemory)
+ IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject,
+ OnGetPluginScriptableObject)
+ IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry)
+ IPC_MESSAGE_HANDLER(PluginMsg_SendJavaScriptStream,
+ OnSendJavaScriptStream)
+ IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse,
+ OnDidReceiveManualResponse)
+ IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualData, OnDidReceiveManualData)
+ IPC_MESSAGE_HANDLER(PluginMsg_DidFinishManualLoading,
+ OnDidFinishManualLoading)
+ IPC_MESSAGE_HANDLER(PluginMsg_DidManualLoadFail, OnDidManualLoadFail)
+ IPC_MESSAGE_HANDLER(PluginMsg_InstallMissingPlugin, OnInstallMissingPlugin)
+ IPC_MESSAGE_HANDLER(PluginMsg_HandleURLRequestReply, OnHandleURLRequestReply)
+ IPC_MESSAGE_HANDLER(PluginMsg_URLRequestRouted, OnURLRequestRouted)
+ IPC_MESSAGE_UNHANDLED_ERROR()
+ IPC_END_MESSAGE_MAP()
+
+ Release();
+}
+
+bool WebPluginDelegateStub::Send(IPC::Message* msg) {
+ return channel_->Send(msg);
+}
+
+void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params,
+ bool* result) {
+ *result = false;
+ int argc = static_cast<int>(params.arg_names.size());
+ if (argc != static_cast<int>(params.arg_values.size())) {
+ NOTREACHED();
+ return;
+ }
+
+ char **argn = new char*[argc];
+ char **argv = new char*[argc];
+ for (int i = 0; i < argc; ++i) {
+ argn[i] = const_cast<char*>(params.arg_names[i].c_str());
+ argv[i] = const_cast<char*>(params.arg_values[i].c_str());
+ }
+
+ CommandLine command_line;
+ std::wstring path = command_line.GetSwitchValue(switches::kPluginPath);
+ delegate_ = WebPluginDelegateImpl::Create(
+ path, mime_type_, params.containing_window);
+ if (delegate_) {
+ webplugin_ = new WebPluginProxy(
+ channel_, instance_id_, delegate_, params.modal_dialog_event);
+ *result = delegate_->Initialize(
+ params.url, argn, argv, argc, webplugin_, params.load_manually);
+ }
+
+ delete[] argn;
+ delete[] argv;
+}
+
+void WebPluginDelegateStub::OnWillSendRequest(int id, const GURL& url) {
+ WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
+ if (!client)
+ return;
+
+ client->WillSendRequest(url);
+}
+
+void WebPluginDelegateStub::OnDidReceiveResponse(
+ const PluginMsg_DidReceiveResponseParams& params, bool* cancel) {
+ *cancel = false;
+ WebPluginResourceClient* client = webplugin_->GetResourceClient(params.id);
+ if (!client)
+ return;
+
+ client->DidReceiveResponse(params.mime_type,
+ params.headers,
+ params.expected_length,
+ params.last_modified,
+ cancel);
+}
+
+void WebPluginDelegateStub::OnDidReceiveData(int id,
+ const std::vector<char>& buffer) {
+ WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
+ if (!client)
+ return;
+
+ client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size()));
+}
+
+void WebPluginDelegateStub::OnDidFinishLoading(int id) {
+ WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
+ if (!client)
+ return;
+
+ client->DidFinishLoading();
+}
+
+void WebPluginDelegateStub::OnDidFail(int id) {
+ WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
+ if (!client)
+ return;
+
+ client->DidFail();
+}
+
+void WebPluginDelegateStub::OnDidFinishLoadWithReason(int reason) {
+ delegate_->DidFinishLoadWithReason(reason);
+}
+
+void WebPluginDelegateStub::OnSetFocus() {
+ delegate_->SetFocus();
+}
+
+void WebPluginDelegateStub::OnHandleEvent(const NPEvent& event,
+ bool* handled,
+ WebCursor* cursor) {
+ *handled = delegate_->HandleEvent(const_cast<NPEvent*>(&event), cursor);
+}
+
+void WebPluginDelegateStub::OnPaint(const PluginMsg_Paint_Params& params) {
+ // Convert the shared memory handle to a handle that works in our process,
+ // and then use that to create an HDC.
+ win_util::ScopedHandle shared_section(win_util::GetSectionFromProcess(
+ params.shared_memory, channel_->renderer_handle(), false));
+
+ if (shared_section == NULL) {
+ NOTREACHED();
+ return;
+ }
+
+ void* data = NULL;
+ HDC screen_dc = GetDC(NULL);
+ BITMAPINFOHEADER bitmap_header;
+ gfx::CreateBitmapHeader(params.size.width(), params.size.height(),
+ &bitmap_header);
+ win_util::ScopedBitmap hbitmap(CreateDIBSection(
+ screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header),
+ DIB_RGB_COLORS, &data,
+ shared_section, 0));
+ ReleaseDC(NULL, screen_dc);
+ if (hbitmap == NULL) {
+ NOTREACHED();
+ return;
+ }
+
+ win_util::ScopedHDC hdc(CreateCompatibleDC(NULL));
+ if (hdc == NULL) {
+ NOTREACHED();
+ return;
+ }
+ gfx::PlatformDevice::InitializeDC(hdc);
+ SelectObject(hdc, hbitmap);
+ SetWorldTransform(hdc, &params.xf);
+
+ win_util::ScopedHRGN hrgn(CreateRectRgnIndirect(&params.clip_rect.ToRECT()));
+ SelectClipRgn(hdc, hrgn);
+ webplugin_->WillPaint();
+ delegate_->Paint(hdc, params.damaged_rect);
+}
+
+void WebPluginDelegateStub::OnPrint(PluginMsg_PrintResponse_Params* params) {
+ gfx::Emf emf;
+ if (!emf.CreateDc(NULL, NULL)) {
+ NOTREACHED();
+ return;
+ }
+ HDC hdc = emf.hdc();
+ gfx::PlatformDevice::InitializeDC(hdc);
+ delegate_->Print(hdc);
+ if (!emf.CloseDc()) {
+ NOTREACHED();
+ return;
+ }
+
+ size_t size = emf.GetDataSize();
+ DCHECK(size);
+ params->size = size;
+ SharedMemory shared_buf;
+ CreateSharedBuffer(size, &shared_buf, &params->shared_memory);
+
+ // Retrieve a copy of the data.
+ bool success = emf.GetData(shared_buf.memory(), size);
+ DCHECK(success);
+}
+
+void WebPluginDelegateStub::OnPaintIntoSharedMemory(
+ const PluginMsg_Paint_Params& params,
+ SharedMemoryHandle* emf_buffer,
+ size_t* bytes) {
+ *emf_buffer = NULL;
+ *bytes = 0;
+
+ gfx::Emf emf;
+ if (!emf.CreateDc(NULL, NULL)) {
+ NOTREACHED();
+ return;
+ }
+ HDC hdc = emf.hdc();
+ gfx::PlatformDevice::InitializeDC(hdc);
+
+ if (delegate_->windowless()) {
+ WindowlessPaint(hdc, params);
+ } else {
+ WindowedPaint(hdc, params.damaged_rect);
+ }
+
+ // Need to send back the data as shared memory.
+ if (!emf.CloseDc()) {
+ NOTREACHED();
+ return;
+ }
+
+ size_t size = emf.GetDataSize();
+ DCHECK(size);
+ *bytes = size;
+ SharedMemory shared_buf;
+ CreateSharedBuffer(size, &shared_buf, emf_buffer);
+
+ // Retrieve a copy of the data.
+ bool success = emf.GetData(shared_buf.memory(), size);
+ DCHECK(success);
+}
+
+void WebPluginDelegateStub::WindowedPaint(HDC hdc,
+ const gfx::Rect& window_rect) {
+ // Use the NPAPI print() function to render the plugin.
+ delegate_->Print(hdc);
+}
+
+void WebPluginDelegateStub::WindowlessPaint(
+ HDC hdc,
+ const PluginMsg_Paint_Params& params) {
+ void* data = NULL;
+ HDC screen_dc = GetDC(NULL);
+ BITMAPINFOHEADER bitmap_header;
+ gfx::CreateBitmapHeader(params.size.width(), params.size.height(),
+ &bitmap_header);
+ win_util::ScopedBitmap hbitmap(CreateDIBSection(
+ screen_dc, reinterpret_cast<const BITMAPINFO*>(&bitmap_header),
+ DIB_RGB_COLORS, &data, NULL, 0));
+ ReleaseDC(NULL, screen_dc);
+ if (hbitmap == NULL) {
+ NOTREACHED();
+ return;
+ }
+ SelectObject(hdc, hbitmap);
+
+ // Apply transform and clipping.
+ SetWorldTransform(hdc, &params.xf);
+ win_util::ScopedHRGN hrgn(CreateRectRgnIndirect(&params.clip_rect.ToRECT()));
+ SelectClipRgn(hdc, hrgn);
+ webplugin_->WillPaint();
+ delegate_->Paint(hdc, params.damaged_rect);
+}
+
+void WebPluginDelegateStub::OnUpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ delegate_->UpdateGeometry(window_rect, clip_rect, visible);
+}
+
+void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id,
+ void** npobject_ptr) {
+ NPObject* object = delegate_->GetPluginScriptableObject();
+ if (!object) {
+ *route_id = MSG_ROUTING_NONE;
+ return;
+ }
+
+ *route_id = channel_->GenerateRouteID();
+ *npobject_ptr = object;
+ // The stub will delete itself when the proxy tells it that it's released, or
+ // otherwise when the channel is closed.
+ NPObjectStub* stub = new NPObjectStub(object, channel_.get(), *route_id);
+
+ // Release ref added by GetPluginScriptableObject (our stub holds its own).
+ NPN_ReleaseObject(object);
+}
+
+void WebPluginDelegateStub::OnSendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success,
+ bool notify_needed,
+ int notify_data) {
+ delegate_->SendJavaScriptStream(url, result, success, notify_needed,
+ notify_data);
+}
+
+void WebPluginDelegateStub::OnDidReceiveManualResponse(
+ const std::string& url,
+ const PluginMsg_DidReceiveResponseParams& params) {
+ delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers,
+ params.expected_length,
+ params.last_modified);
+}
+
+void WebPluginDelegateStub::OnDidReceiveManualData(
+ const std::vector<char>& buffer) {
+ delegate_->DidReceiveManualData(&buffer.front(),
+ static_cast<int>(buffer.size()));
+}
+
+void WebPluginDelegateStub::OnDidFinishManualLoading() {
+ delegate_->DidFinishManualLoading();
+}
+
+void WebPluginDelegateStub::OnDidManualLoadFail() {
+ delegate_->DidManualLoadFail();
+}
+
+void WebPluginDelegateStub::OnInstallMissingPlugin() {
+ delegate_->InstallMissingPlugin();
+}
+
+void WebPluginDelegateStub::CreateSharedBuffer(
+ size_t size,
+ SharedMemory* shared_buf,
+ SharedMemoryHandle* remote_handle) {
+ if (!shared_buf->Create(std::wstring(), false, false, size)) {
+ NOTREACHED();
+ return;
+ }
+ if (!shared_buf->Map(size)) {
+ NOTREACHED();
+ shared_buf->Close();
+ return;
+ }
+
+ BOOL result = DuplicateHandle(GetCurrentProcess(),
+ shared_buf->handle(),
+ channel_->renderer_handle(),
+ remote_handle, 0, FALSE,
+ DUPLICATE_SAME_ACCESS);
+ DCHECK_NE(result, 0);
+ // If the calling function's shared_buf is on the stack, its destructor will
+ // close the shared memory buffer handle. This is fine since we already
+ // duplicated the handle to the renderer process so it will stay "alive".
+}
+
+void WebPluginDelegateStub::OnHandleURLRequestReply(
+ const PluginMsg_URLRequestReply_Params& params) {
+ WebPluginResourceClient* resource_client =
+ delegate_->CreateResourceClient(params.resource_id, params.url,
+ params.notify_needed,
+ params.notify_data);
+ webplugin_->OnResourceCreated(params.resource_id, resource_client);
+}
+
+void WebPluginDelegateStub::OnURLRequestRouted(const std::string& url,
+ bool notify_needed,
+ HANDLE notify_data) {
+ delegate_->URLRequestRouted(url, notify_needed, notify_data);
+}
diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h
new file mode 100644
index 0000000..27ecac6
--- /dev/null
+++ b/chrome/plugin/webplugin_delegate_stub.h
@@ -0,0 +1,137 @@
+// 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 CHROME_PLUGIN_WEBPLUGIN_DELEGATE_STUB_H__
+#define CHROME_PLUGIN_WEBPLUGIN_DELEGATE_STUB_H__
+
+#include <queue>
+
+#include "base/gfx/rect.h"
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "bindings/npapi.h"
+#include "chrome/common/ipc_channel.h"
+#include "chrome/common/plugin_messages.h"
+
+class GURL;
+class PluginChannel;
+class WebPluginProxy;
+class WebPluginDelegateImpl;
+struct PluginMsg_Init_Params;
+struct PluginMsg_Paint_Params;
+struct PluginMsg_DidReceiveResponseParams;
+class WebCursor;
+
+// Converts the IPC messages from WebPluginDelegateProxy into calls to the
+// actual WebPluginDelegate object.
+class WebPluginDelegateStub : public IPC::Channel::Listener,
+ public IPC::Message::Sender,
+ public base::RefCounted<WebPluginDelegateStub> {
+ public:
+ WebPluginDelegateStub(const std::string& mime_type, int instance_id,
+ PluginChannel* channel);
+ ~WebPluginDelegateStub();
+
+ // IPC::Channel::Listener implementation:
+ virtual void OnMessageReceived(const IPC::Message& msg);
+
+ // IPC::Message::Sender implementation:
+ virtual bool Send(IPC::Message* msg);
+
+ int instance_id() { return instance_id_; }
+
+ private:
+ // Message handlers for the WebPluginDelegate calls that are proxied from the
+ // renderer over the IPC channel.
+ void OnInit(const PluginMsg_Init_Params& params, bool* result);
+
+ void OnWillSendRequest(int id, const GURL& url);
+ void OnDidReceiveResponse(const PluginMsg_DidReceiveResponseParams& params,
+ bool* cancel);
+ void OnDidReceiveData(int id, const std::vector<char>& buffer);
+ void OnDidFinishLoading(int id);
+ void OnDidFail(int id);
+
+ void OnDidFinishLoadWithReason(int reason);
+ void OnSetFocus();
+ void OnHandleEvent(const NPEvent& event, bool* handled,
+ WebCursor* cursor);
+
+ void OnPaint(const PluginMsg_Paint_Params& params);
+
+ void OnPrint(PluginMsg_PrintResponse_Params* params);
+
+ // Paints the plugin into a buffer. It roughly does the same as OnPaint (i.e.
+ // painting a plugin) except that the plugin window is always renderered into
+ // an EMF buffer and that it is effective for windowed plugins too.
+ void OnPaintIntoSharedMemory(const PluginMsg_Paint_Params& params,
+ SharedMemoryHandle* emf_buffer, size_t* bytes);
+ // Paints a windowed plugin into a device context.
+ void WindowedPaint(HDC hdc, const gfx::Rect& window_rect);
+ // Paints a windowless plugin into a device context.
+ void WindowlessPaint(HDC hdc,
+ const PluginMsg_Paint_Params& params);
+ void OnUpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect, bool visible);
+ void OnGetPluginScriptableObject(int* route_id, void** npobject_ptr);
+ void OnSendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success, bool notify_needed,
+ int notify_data);
+
+ void OnDidReceiveManualResponse(
+ const std::string& url,
+ const PluginMsg_DidReceiveResponseParams& params);
+ void OnDidReceiveManualData(const std::vector<char>& buffer);
+ void OnDidFinishManualLoading();
+ void OnDidManualLoadFail();
+ void OnInstallMissingPlugin();
+
+ void OnHandleURLRequestReply(
+ const PluginMsg_URLRequestReply_Params& params);
+
+ void OnURLRequestRouted(const std::string& url, bool notify_needed,
+ HANDLE notify_data);
+
+ void CreateSharedBuffer(size_t size,
+ SharedMemory* shared_buf,
+ SharedMemoryHandle* remote_handle);
+
+ int instance_id_;
+ std::string mime_type_;
+
+ scoped_refptr<PluginChannel> channel_;
+
+ WebPluginDelegateImpl* delegate_;
+ WebPluginProxy* webplugin_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebPluginDelegateStub);
+};
+
+#endif // CHROME_PLUGIN_WEBPLUGIN_DELEGATE_STUB_H__
diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc
new file mode 100644
index 0000000..b969e58
--- /dev/null
+++ b/chrome/plugin/webplugin_proxy.cc
@@ -0,0 +1,269 @@
+// 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 "chrome/plugin/webplugin_proxy.h"
+
+#include "base/scoped_handle.h"
+#include "base/singleton.h"
+#include "chrome/common/plugin_messages.h"
+#include "chrome/plugin/plugin_channel.h"
+#include "chrome/plugin/webplugin_delegate_stub.h"
+#include "chrome/plugin/npobject_proxy.h"
+#include "chrome/plugin/npobject_util.h"
+#include "webkit/glue/webplugin_delegate.h"
+
+typedef std::map<CPBrowsingContext, WebPluginProxy*> ContextMap;
+static ContextMap& GetContextMap() {
+ return *Singleton<ContextMap>::get();
+}
+
+WebPluginProxy::WebPluginProxy(
+ PluginChannel* channel,
+ int route_id,
+ WebPluginDelegate* delegate,
+ HANDLE modal_dialog_event)
+ : channel_(channel),
+ route_id_(route_id),
+ cp_browsing_context_(0),
+ window_npobject_(NULL),
+ plugin_element_(NULL),
+ delegate_(delegate),
+ waiting_for_paint_(false) {
+
+ HANDLE event;
+ BOOL result = DuplicateHandle(channel->renderer_handle(),
+ modal_dialog_event,
+ GetCurrentProcess(),
+ &event,
+ SYNCHRONIZE,
+ FALSE,
+ 0);
+ DCHECK(result) << "Couldn't duplicate the modal dialog handle for the plugin.";
+ modal_dialog_event_.Set(event);
+}
+
+WebPluginProxy::~WebPluginProxy() {
+ if (cp_browsing_context_)
+ GetContextMap().erase(cp_browsing_context_);
+}
+
+bool WebPluginProxy::Send(IPC::Message* msg) {
+ return channel_->Send(msg);
+}
+
+void WebPluginProxy::SetWindow(HWND window, HANDLE pump_messages_event) {
+ HANDLE pump_messages_event_for_renderer = NULL;
+
+ if (pump_messages_event) {
+ DCHECK(window == NULL);
+ DuplicateHandle(GetCurrentProcess(), pump_messages_event,
+ channel_->renderer_handle(),
+ &pump_messages_event_for_renderer,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+ DCHECK(pump_messages_event_for_renderer != NULL);
+ }
+
+ Send(new PluginHostMsg_SetWindow(route_id_, window,
+ pump_messages_event_for_renderer));
+}
+
+void WebPluginProxy::CancelResource(int id) {
+ Send(new PluginHostMsg_CancelResource(route_id_, id));
+ resource_clients_.erase(id);
+}
+
+void WebPluginProxy::Invalidate() {
+ Send(new PluginHostMsg_Invalidate(route_id_));
+}
+
+void WebPluginProxy::InvalidateRect(const gfx::Rect& rect) {
+ // Ignore NPN_InvalidateRect calls with empty rects.
+ if (rect.IsEmpty()) {
+ return;
+ }
+ // Only send a single InvalidateRect message at a time. From WillPaint we
+ // will dispatch an additional InvalidateRect message if necessary.
+ if (waiting_for_paint_) {
+ damaged_rect_ = damaged_rect_.Union(rect);
+ } else {
+ waiting_for_paint_ = true;
+ Send(new PluginHostMsg_InvalidateRect(route_id_, rect));
+ }
+}
+
+NPObject* WebPluginProxy::GetWindowScriptNPObject() {
+ if (window_npobject_)
+ return NPN_RetainObject(window_npobject_);
+
+ int npobject_route_id = channel_->GenerateRouteID();
+ bool success = false;
+ void* npobject_ptr;
+ Send(new PluginHostMsg_GetWindowScriptNPObject(
+ route_id_, npobject_route_id, &success, &npobject_ptr));
+ if (!success)
+ return NULL;
+
+ window_npobject_ = NPObjectProxy::Create(channel_,
+ npobject_route_id,
+ npobject_ptr,
+ modal_dialog_event_.Get());
+
+ return window_npobject_;
+}
+
+NPObject* WebPluginProxy::GetPluginElement() {
+ if (plugin_element_)
+ return NPN_RetainObject(plugin_element_);
+
+ int npobject_route_id = channel_->GenerateRouteID();
+ bool success = false;
+ void* npobject_ptr;
+ Send(new PluginHostMsg_GetPluginElement(
+ route_id_, npobject_route_id, &success, &npobject_ptr));
+ if (!success)
+ return NULL;
+
+ plugin_element_ = NPObjectProxy::Create(channel_,
+ npobject_route_id,
+ npobject_ptr,
+ modal_dialog_event_.Get());
+
+ return plugin_element_;
+}
+
+void WebPluginProxy::SetCookie(const GURL& url,
+ const GURL& policy_url,
+ const std::string& cookie) {
+ Send(new PluginHostMsg_SetCookie(route_id_, url, policy_url, cookie));
+}
+
+std::string WebPluginProxy::GetCookies(const GURL& url,
+ const GURL& policy_url) {
+ std::string cookies;
+ Send(new PluginHostMsg_GetCookies(route_id_, url, policy_url, &cookies));
+
+ return cookies;
+}
+
+void WebPluginProxy::ShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ std::string* json_retval) {
+ PluginHostMsg_ShowModalHTMLDialog* msg =
+ new PluginHostMsg_ShowModalHTMLDialog(
+ route_id_, url, width, height, json_arguments, json_retval);
+
+ // Create a new event and set it. This forces us to pump messages while
+ // waiting for a response (which won't come until the dialog is closed). This
+ // avoids a deadlock.
+ ScopedHandle event(CreateEvent(NULL, FALSE, TRUE, NULL));
+ msg->set_pump_messages_event(event);
+
+ Send(msg);
+}
+
+void WebPluginProxy::OnMissingPluginStatus(int status) {
+ Send(new PluginHostMsg_MissingPluginStatus(route_id_, status));
+}
+
+CPBrowsingContext WebPluginProxy::GetCPBrowsingContext() {
+ if (cp_browsing_context_ == 0) {
+ Send(new PluginHostMsg_GetCPBrowsingContext(route_id_,
+ &cp_browsing_context_));
+ GetContextMap()[cp_browsing_context_] = this;
+ }
+ return cp_browsing_context_;
+}
+
+WebPluginProxy* WebPluginProxy::FromCPBrowsingContext(
+ CPBrowsingContext context) {
+ return GetContextMap()[context];
+}
+
+WebPluginResourceClient* WebPluginProxy::GetResourceClient(int id) {
+ ResourceClientMap::iterator iterator = resource_clients_.find(id);
+ if (iterator == resource_clients_.end()) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return iterator->second;
+}
+
+void WebPluginProxy::WillPaint() {
+ // If we have an accumulated damaged rect, then check to see if we need to
+ // send out another InvalidateRect message.
+ waiting_for_paint_ = false;
+ if (!damaged_rect_.IsEmpty()) {
+ InvalidateRect(damaged_rect_);
+ damaged_rect_ = gfx::Rect();
+ }
+}
+
+void WebPluginProxy::OnResourceCreated(int resource_id, HANDLE cookie) {
+ WebPluginResourceClient* resource_client =
+ reinterpret_cast<WebPluginResourceClient*>(cookie);
+ if (!resource_client) {
+ NOTREACHED();
+ return;
+ }
+
+ DCHECK(resource_clients_.find(resource_id) == resource_clients_.end());
+ resource_clients_[resource_id] = resource_client;
+}
+
+void WebPluginProxy::HandleURLRequest(const char *method,
+ bool is_javascript_url,
+ const char* target, unsigned int len,
+ const char* buf, bool is_file_data,
+ bool notify, const char* url,
+ void* notify_data, bool popups_allowed) {
+ if (!url) {
+ NOTREACHED();
+ return;
+ }
+
+ PluginHostMsg_URLRequest_Params params;
+ params.method = method;
+ params.is_javascript_url = is_javascript_url;
+ if (target)
+ params.target = std::string(target);
+
+ if (len) {
+ params.buffer.resize(len);
+ memcpy(&params.buffer.front(), buf, len);
+ }
+
+ params.is_file_data = is_file_data;
+ params.notify = notify;
+ params.url = url;
+ params.notify_data = notify_data;
+ params.popups_allowed = popups_allowed;
+
+ Send(new PluginHostMsg_URLRequest(route_id_, params));
+}
diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h
new file mode 100644
index 0000000..6c862e1
--- /dev/null
+++ b/chrome/plugin/webplugin_proxy.h
@@ -0,0 +1,116 @@
+// 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 CHROME_PLUGIN_PLUGIN_WEBPLUGIN_PROXY_H__
+#define CHROME_PLUGIN_PLUGIN_WEBPLUGIN_PROXY_H__
+
+#include <hash_map>
+
+#include "base/ref_counted.h"
+#include "base/scoped_handle.h"
+#include "chrome/common/ipc_message.h"
+#include "chrome/common/chrome_plugin_api.h"
+#include "webkit/glue/webplugin.h"
+
+class PluginChannel;
+class WebPluginDelegate;
+
+// This is an implementation of WebPlugin that proxies all calls to the
+// renderer.
+class WebPluginProxy : public WebPlugin {
+ public:
+ // Creates a new proxy for WebPlugin, using the given sender to send the
+ // marshalled WebPlugin calls.
+ WebPluginProxy(PluginChannel* channel,
+ int route_id,
+ WebPluginDelegate* delegate,
+ HANDLE modal_dialog_event);
+ ~WebPluginProxy();
+
+ // WebPlugin overrides
+ void SetWindow(HWND window, HANDLE pump_messages_event);
+ void CancelResource(int id);
+ void Invalidate();
+ void InvalidateRect(const gfx::Rect& rect);
+ NPObject* GetWindowScriptNPObject();
+ NPObject* GetPluginElement();
+ void SetCookie(const GURL& url,
+ const GURL& policy_url,
+ const std::string& cookie);
+ std::string GetCookies(const GURL& url, const GURL& policy_url);
+
+ void ShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ std::string* json_retval);
+ void OnMissingPluginStatus(int status);
+ // class-specific methods
+
+ // Retrieves the browsing context associated with the renderer this plugin
+ // is in. Calling multiple times will return the same value.
+ CPBrowsingContext GetCPBrowsingContext();
+
+ // Retrieves the WebPluginProxy for the given context that was returned by
+ // GetCPBrowsingContext, or NULL if not found.
+ static WebPluginProxy* FromCPBrowsingContext(CPBrowsingContext context);
+
+ // Returns a WebPluginResourceClient object given its id, or NULL if no
+ // object with that id exists.
+ WebPluginResourceClient* GetResourceClient(int id);
+
+ void WillPaint();
+
+ // Notification received on a plugin issued resource request
+ // creation.
+ void OnResourceCreated(int resource_id, HANDLE cookie);
+
+ void HandleURLRequest(const char *method,
+ bool is_javascript_url,
+ const char* target, unsigned int len,
+ const char* buf, bool is_file_data,
+ bool notify, const char* url,
+ void* notify_data, bool popups_allowed);
+
+ private:
+ bool Send(IPC::Message* msg);
+
+ typedef stdext::hash_map<int, WebPluginResourceClient*> ResourceClientMap;
+ ResourceClientMap resource_clients_;
+
+ scoped_refptr<PluginChannel> channel_;
+ int route_id_;
+ NPObject* window_npobject_;
+ NPObject* plugin_element_;
+ WebPluginDelegate* delegate_;
+ gfx::Rect damaged_rect_;
+ bool waiting_for_paint_;
+ uint32 cp_browsing_context_;
+ ScopedHandle modal_dialog_event_;
+};
+
+#endif // CHROME_PLUGIN_PLUGIN_WEBPLUGIN_PROXY_H__