summaryrefslogtreecommitdiffstats
path: root/content/plugin/npobject_proxy.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/plugin/npobject_proxy.cc')
-rw-r--r--content/plugin/npobject_proxy.cc500
1 files changed, 500 insertions, 0 deletions
diff --git a/content/plugin/npobject_proxy.cc b/content/plugin/npobject_proxy.cc
new file mode 100644
index 0000000..5c08724
--- /dev/null
+++ b/content/plugin/npobject_proxy.cc
@@ -0,0 +1,500 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/plugin/npobject_proxy.h"
+
+#include "content/common/plugin_messages.h"
+#include "content/plugin/npobject_util.h"
+#include "content/plugin/plugin_channel.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/plugins/npapi/plugin_instance.h"
+
+using WebKit::WebBindings;
+
+struct NPObjectWrapper {
+ NPObject object;
+ NPObjectProxy* proxy;
+};
+
+NPClass NPObjectProxy::npclass_proxy_ = {
+ NP_CLASS_STRUCT_VERSION,
+ NPObjectProxy::NPAllocate,
+ NPObjectProxy::NPDeallocate,
+ NPObjectProxy::NPPInvalidate,
+ NPObjectProxy::NPHasMethod,
+ NPObjectProxy::NPInvoke,
+ NPObjectProxy::NPInvokeDefault,
+ NPObjectProxy::NPHasProperty,
+ NPObjectProxy::NPGetProperty,
+ NPObjectProxy::NPSetProperty,
+ NPObjectProxy::NPRemoveProperty,
+ NPObjectProxy::NPNEnumerate,
+ NPObjectProxy::NPNConstruct
+};
+
+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;
+}
+
+NPObject* NPObjectProxy::GetUnderlyingNPObject() {
+ return NULL;
+}
+
+IPC::Channel::Listener* NPObjectProxy::GetChannelListener() {
+ return static_cast<IPC::Channel::Listener*>(this);
+}
+
+NPObjectProxy::NPObjectProxy(
+ PluginChannelBase* channel,
+ int route_id,
+ gfx::NativeViewId containing_window,
+ const GURL& page_url)
+ : channel_(channel),
+ route_id_(route_id),
+ containing_window_(containing_window),
+ page_url_(page_url) {
+ channel_->AddRoute(route_id, this, this);
+}
+
+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,
+ gfx::NativeViewId containing_window,
+ const GURL& page_url) {
+ NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(
+ WebBindings::createObject(0, &npclass_proxy_));
+ obj->proxy = new NPObjectProxy(
+ channel, route_id, containing_window, page_url);
+
+ 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;
+}
+
+bool NPObjectProxy::OnMessageReceived(const IPC::Message& msg) {
+ NOTREACHED();
+ return false;
+}
+
+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) {
+ if (obj == NULL)
+ return false;
+
+ 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) {
+ if (obj == NULL)
+ return false;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ if (is_default) {
+ return obj->_class->invokeDefault(obj, args, arg_count, np_result);
+ } else {
+ return obj->_class->invoke(obj, name, args, arg_count, np_result);
+ }
+ }
+
+ bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
+ 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.identifier = NULL;
+ } 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, containing_window,
+ proxy->page_url_);
+ 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).
+ if (IsPluginProcess()) {
+ PluginChannel* channel = static_cast<PluginChannel*>(proxy->channel_.get());
+ if (channel) {
+ msg->set_pump_messages_event(
+ channel->GetModalDialogEvent(containing_window));
+ }
+ }
+
+ GURL page_url = proxy->page_url_;
+ proxy->Send(msg);
+
+ // Send may delete proxy.
+ proxy = NULL;
+
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ param_result, channel_copy, np_result, containing_window, page_url);
+ return true;
+}
+
+bool NPObjectProxy::NPHasProperty(NPObject *obj,
+ NPIdentifier name) {
+ if (obj == NULL)
+ return false;
+
+ 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));
+
+ // Send may delete proxy.
+ proxy = NULL;
+
+ return result;
+}
+
+bool NPObjectProxy::NPGetProperty(NPObject *obj,
+ NPIdentifier name,
+ NPVariant *np_result) {
+ // Please refer to http://code.google.com/p/chromium/issues/detail?id=2556,
+ // which was a crash in the XStandard plugin during plugin shutdown. The
+ // crash occured because the plugin requests the plugin script object,
+ // which fails. The plugin does not check the result of the operation and
+ // invokes NPN_GetProperty on a NULL object which lead to the crash. If
+ // we observe similar crashes in other methods in the future, these null
+ // checks may have to be replicated in the other methods in this class.
+ if (obj == NULL)
+ return false;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->getProperty(obj, name, np_result);
+ }
+
+ bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param param;
+ scoped_refptr<PluginChannelBase> channel(proxy->channel_);
+
+ GURL page_url = proxy->page_url_;
+ proxy->Send(new NPObjectMsg_GetProperty(
+ proxy->route_id(), name_param, &param, &result));
+ // Send may delete proxy.
+ proxy = NULL;
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ param, channel.get(), np_result, containing_window, page_url);
+
+ return true;
+}
+
+bool NPObjectProxy::NPSetProperty(NPObject *obj,
+ NPIdentifier name,
+ const NPVariant *value) {
+ if (obj == NULL)
+ return false;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return obj->_class->setProperty(obj, name, value);
+ }
+
+ bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
+ NPIdentifier_Param name_param;
+ CreateNPIdentifierParam(name, &name_param);
+
+ NPVariant_Param value_param;
+ CreateNPVariantParam(
+ *value, proxy->channel(), &value_param, false,
+ containing_window, proxy->page_url_);
+
+ proxy->Send(new NPObjectMsg_SetProperty(
+ proxy->route_id(), name_param, value_param, &result));
+ // Send may delete proxy.
+ proxy = NULL;
+
+ return result;
+}
+
+bool NPObjectProxy::NPRemoveProperty(NPObject *obj,
+ NPIdentifier name) {
+ if (obj == NULL)
+ return false;
+
+ 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));
+ // Send may delete proxy.
+ proxy = NULL;
+
+ return result;
+}
+
+void NPObjectProxy::NPPInvalidate(NPObject *obj) {
+ if (obj == NULL)
+ return;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ obj->_class->invalidate(obj);
+ return;
+ }
+
+ proxy->Send(new NPObjectMsg_Invalidate(proxy->route_id()));
+ // Send may delete proxy.
+ proxy = NULL;
+}
+
+bool NPObjectProxy::NPNEnumerate(NPObject *obj,
+ NPIdentifier **value,
+ uint32_t *count) {
+ if (obj == NULL)
+ return false;
+
+ bool result = false;
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM) {
+ return obj->_class->enumerate(obj, value, count);
+ } else {
+ return false;
+ }
+ }
+
+ std::vector<NPIdentifier_Param> value_param;
+ proxy->Send(new NPObjectMsg_Enumeration(
+ proxy->route_id(), &value_param, &result));
+ // Send may delete proxy.
+ proxy = NULL;
+
+ 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::NPNConstruct(NPObject *obj,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *np_result) {
+ if (obj == NULL)
+ return false;
+
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR) {
+ return obj->_class->construct(obj, args, arg_count, np_result);
+ } else {
+ return false;
+ }
+ }
+
+ bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
+
+ // 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, containing_window,
+ proxy->page_url_);
+ args_param.push_back(param);
+ }
+
+ NPVariant_Param param_result;
+ NPObjectMsg_Construct* msg = new NPObjectMsg_Construct(
+ proxy->route_id_, args_param, &param_result, &result);
+
+ // See comment in NPObjectProxy::NPInvokePrivate.
+ if (IsPluginProcess()) {
+ PluginChannel* channel = static_cast<PluginChannel*>(proxy->channel_.get());
+ if (channel) {
+ msg->set_pump_messages_event(
+ channel->GetModalDialogEvent(proxy->containing_window_));
+ }
+ }
+
+ GURL page_url = proxy->page_url_;
+ proxy->Send(msg);
+
+ // Send may delete proxy.
+ proxy = NULL;
+
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ param_result, channel_copy, np_result, containing_window, page_url);
+ return true;
+}
+
+bool NPObjectProxy::NPNEvaluate(NPP npp,
+ NPObject *obj,
+ NPString *script,
+ NPVariant *result_var) {
+ NPObjectProxy* proxy = GetProxy(obj);
+ if (!proxy) {
+ return false;
+ }
+
+ bool result = false;
+ gfx::NativeViewId containing_window = proxy->containing_window_;
+ bool popups_allowed = false;
+
+ if (npp) {
+ webkit::npapi::PluginInstance* plugin_instance =
+ reinterpret_cast<webkit::npapi::PluginInstance*>(npp->ndata);
+ if (plugin_instance)
+ popups_allowed = plugin_instance->popups_allowed();
+ }
+
+ 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,
+ popups_allowed,
+ &result_param,
+ &result);
+
+ // See comment in NPObjectProxy::NPInvokePrivate.
+ if (IsPluginProcess()) {
+ PluginChannel* channel = static_cast<PluginChannel*>(proxy->channel_.get());
+ if (channel) {
+ msg->set_pump_messages_event(
+ channel->GetModalDialogEvent(proxy->containing_window_));
+ }
+ }
+ scoped_refptr<PluginChannelBase> channel(proxy->channel_);
+
+ GURL page_url = proxy->page_url_;
+ proxy->Send(msg);
+ // Send may delete proxy.
+ proxy = NULL;
+ if (!result)
+ return false;
+
+ CreateNPVariant(
+ result_param, channel.get(), result_var, containing_window, page_url);
+ return true;
+}