c7c2791027
Review URL: http://codereview.chromium.org/155238 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20191 0039d316-1c4b-4281-b951-d872f2087c98
460 linhas
14 KiB
C++
460 linhas
14 KiB
C++
// 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 "chrome/plugin/npobject_proxy.h"
|
|
|
|
#include "base/waitable_event.h"
|
|
#include "chrome/common/plugin_messages.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_ = {
|
|
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;
|
|
}
|
|
|
|
NPObjectProxy::NPObjectProxy(
|
|
PluginChannelBase* channel,
|
|
int route_id,
|
|
intptr_t npobject_ptr,
|
|
base::WaitableEvent* modal_dialog_event,
|
|
const GURL& page_url)
|
|
: channel_(channel),
|
|
route_id_(route_id),
|
|
npobject_ptr_(npobject_ptr),
|
|
modal_dialog_event_(modal_dialog_event),
|
|
page_url_(page_url) {
|
|
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,
|
|
intptr_t npobject_ptr,
|
|
base::WaitableEvent* modal_dialog_event,
|
|
const GURL& page_url) {
|
|
NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(
|
|
NPN_CreateObject(0, &npclass_proxy_));
|
|
obj->proxy = new NPObjectProxy(
|
|
channel, route_id, npobject_ptr, modal_dialog_event, 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;
|
|
}
|
|
|
|
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.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, ¶m, false, proxy->modal_dialog_event_,
|
|
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, ¶m_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_);
|
|
|
|
base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
|
|
|
|
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, modal_dialog_event_handle,
|
|
page_url);
|
|
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));
|
|
|
|
// 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;
|
|
|
|
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;
|
|
base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
|
|
scoped_refptr<PluginChannelBase> channel(proxy->channel_);
|
|
|
|
GURL page_url = proxy->page_url_;
|
|
proxy->Send(new NPObjectMsg_GetProperty(
|
|
proxy->route_id(), name_param, ¶m, &result));
|
|
// Send may delete proxy.
|
|
proxy = NULL;
|
|
if (!result)
|
|
return false;
|
|
|
|
CreateNPVariant(
|
|
param, channel.get(), np_result, modal_dialog_event_handle, page_url);
|
|
|
|
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->modal_dialog_event_, 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) {
|
|
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) {
|
|
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) {
|
|
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));
|
|
// 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) {
|
|
NPObjectProxy* proxy = GetProxy(obj);
|
|
if (!proxy) {
|
|
return obj->_class->construct(obj, args, arg_count, np_result);
|
|
}
|
|
|
|
bool result = false;
|
|
|
|
// 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, ¶m, false, proxy->modal_dialog_event_,
|
|
proxy->page_url_);
|
|
args_param.push_back(param);
|
|
}
|
|
|
|
NPVariant_Param param_result;
|
|
NPObjectMsg_Construct* msg = new NPObjectMsg_Construct(
|
|
proxy->route_id_, args_param, ¶m_result, &result);
|
|
|
|
// See comment in NPObjectProxy::NPInvokePrivate.
|
|
msg->set_pump_messages_event(proxy->modal_dialog_event_);
|
|
|
|
base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
|
|
|
|
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, modal_dialog_event_handle,
|
|
page_url);
|
|
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;
|
|
}
|
|
|
|
bool popups_allowed = false;
|
|
|
|
if (npp) {
|
|
NPAPI::PluginInstance* plugin_instance =
|
|
reinterpret_cast<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);
|
|
|
|
// 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_);
|
|
scoped_refptr<PluginChannelBase> channel(proxy->channel_);
|
|
base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
|
|
|
|
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, modal_dialog_event_handle,
|
|
page_url);
|
|
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));
|
|
// Send may delete proxy.
|
|
proxy = NULL;
|
|
}
|