1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/common/npobject_proxy.h"
7 #include "content/common/np_channel_base.h"
8 #include "content/common/npobject_util.h"
9 #include "content/common/plugin_messages.h"
10 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
11 #include "webkit/glue/webkit_glue.h"
12 #include "webkit/plugins/npapi/plugin_instance.h"
13 #include "webkit/plugins/npapi/plugin_host.h"
15 using WebKit::WebBindings
;
19 struct NPObjectWrapper
{
24 NPClass
NPObjectProxy::npclass_proxy_
= {
25 NP_CLASS_STRUCT_VERSION
,
26 NPObjectProxy::NPAllocate
,
27 NPObjectProxy::NPDeallocate
,
28 NPObjectProxy::NPPInvalidate
,
29 NPObjectProxy::NPHasMethod
,
30 NPObjectProxy::NPInvoke
,
31 NPObjectProxy::NPInvokeDefault
,
32 NPObjectProxy::NPHasProperty
,
33 NPObjectProxy::NPGetProperty
,
34 NPObjectProxy::NPSetProperty
,
35 NPObjectProxy::NPRemoveProperty
,
36 NPObjectProxy::NPNEnumerate
,
37 NPObjectProxy::NPNConstruct
40 NPObjectProxy
* NPObjectProxy::GetProxy(NPObject
* object
) {
41 NPObjectProxy
* proxy
= NULL
;
43 // Wrapper exists only for NPObjects that we had created.
44 if (&npclass_proxy_
== object
->_class
) {
45 NPObjectWrapper
* wrapper
= reinterpret_cast<NPObjectWrapper
*>(object
);
46 proxy
= wrapper
->proxy
;
52 NPObject
* NPObjectProxy::GetUnderlyingNPObject() {
56 IPC::Listener
* NPObjectProxy::GetChannelListener() {
57 return static_cast<IPC::Listener
*>(this);
60 NPObjectProxy::NPObjectProxy(
61 NPChannelBase
* channel
,
67 render_view_id_(render_view_id
),
69 channel_
->AddRoute(route_id
, this, this);
72 NPObjectProxy::~NPObjectProxy() {
74 // This NPObjectProxy instance is now invalid and should not be reused for
75 // requests initiated by plugins. We may receive requests for the
76 // same NPObject in the context of the outgoing NPObjectMsg_Release call.
77 // We should be creating new NPObjectProxy instances to wrap these
79 channel_
->RemoveMappingForNPObjectProxy(route_id_
);
80 channel_
->RemoveRoute(route_id_
);
81 Send(new NPObjectMsg_Release(route_id_
));
85 NPObject
* NPObjectProxy::Create(NPChannelBase
* channel
,
88 const GURL
& page_url
) {
89 NPObjectWrapper
* obj
= reinterpret_cast<NPObjectWrapper
*>(
90 WebBindings::createObject(0, &npclass_proxy_
));
91 obj
->proxy
= new NPObjectProxy(channel
, route_id
, render_view_id
, page_url
);
92 channel
->AddMappingForNPObjectProxy(route_id
, &obj
->object
);
93 return reinterpret_cast<NPObject
*>(obj
);
96 bool NPObjectProxy::Send(IPC::Message
* msg
) {
98 return channel_
->Send(msg
);
104 NPObject
* NPObjectProxy::NPAllocate(NPP
, NPClass
*) {
105 return reinterpret_cast<NPObject
*>(new NPObjectWrapper
);
108 void NPObjectProxy::NPDeallocate(NPObject
* npObj
) {
109 NPObjectWrapper
* obj
= reinterpret_cast<NPObjectWrapper
*>(npObj
);
114 bool NPObjectProxy::OnMessageReceived(const IPC::Message
& msg
) {
119 void NPObjectProxy::OnChannelError() {
120 // Release our ref count of the plugin channel object, as it addrefs the
125 bool NPObjectProxy::NPHasMethod(NPObject
*obj
,
131 NPObjectProxy
* proxy
= GetProxy(obj
);
134 return obj
->_class
->hasMethod(obj
, name
);
137 NPIdentifier_Param name_param
;
138 CreateNPIdentifierParam(name
, &name_param
);
140 proxy
->Send(new NPObjectMsg_HasMethod(proxy
->route_id(), name_param
,
145 bool NPObjectProxy::NPInvoke(NPObject
*obj
,
147 const NPVariant
*args
,
150 return NPInvokePrivate(0, obj
, false, name
, args
, arg_count
, result
);
153 bool NPObjectProxy::NPInvokeDefault(NPObject
*npobj
,
154 const NPVariant
*args
,
157 return NPInvokePrivate(0, npobj
, true, 0, args
, arg_count
, result
);
160 bool NPObjectProxy::NPInvokePrivate(NPP npp
,
164 const NPVariant
*args
,
166 NPVariant
*np_result
) {
170 NPObjectProxy
* proxy
= GetProxy(obj
);
173 return obj
->_class
->invokeDefault(obj
, args
, arg_count
, np_result
);
175 return obj
->_class
->invoke(obj
, name
, args
, arg_count
, np_result
);
180 int render_view_id
= proxy
->render_view_id_
;
181 NPIdentifier_Param name_param
;
183 // The data won't actually get used, but set it so we don't send random
185 name_param
.identifier
= NULL
;
187 CreateNPIdentifierParam(name
, &name_param
);
190 // Note: This instance can get destroyed in the context of
191 // Send so addref the channel in this scope.
192 scoped_refptr
<NPChannelBase
> channel_copy
= proxy
->channel_
;
193 std::vector
<NPVariant_Param
> args_param
;
194 for (unsigned int i
= 0; i
< arg_count
; ++i
) {
195 NPVariant_Param param
;
196 CreateNPVariantParam(
197 args
[i
], channel_copy
, ¶m
, false, render_view_id
,
199 args_param
.push_back(param
);
202 NPVariant_Param param_result
;
203 NPObjectMsg_Invoke
* msg
= new NPObjectMsg_Invoke(
204 proxy
->route_id_
, is_default
, name_param
, args_param
, ¶m_result
,
207 // If we're in the plugin process and this invoke leads to a dialog box, the
208 // plugin will hang the window hierarchy unless we pump the window message
209 // queue while waiting for a reply. We need to do this to simulate what
210 // happens when everything runs in-process (while calling MessageBox window
211 // messages are pumped).
212 if (IsPluginProcess() && proxy
->channel()) {
213 msg
->set_pump_messages_event(
214 proxy
->channel()->GetModalDialogEvent(render_view_id
));
217 GURL page_url
= proxy
->page_url_
;
220 // Send may delete proxy.
227 param_result
, channel_copy
, np_result
, render_view_id
, page_url
);
231 bool NPObjectProxy::NPHasProperty(NPObject
*obj
,
237 NPObjectProxy
* proxy
= GetProxy(obj
);
239 return obj
->_class
->hasProperty(obj
, name
);
242 NPIdentifier_Param name_param
;
243 CreateNPIdentifierParam(name
, &name_param
);
245 NPVariant_Param param
;
246 proxy
->Send(new NPObjectMsg_HasProperty(
247 proxy
->route_id(), name_param
, &result
));
249 // Send may delete proxy.
255 bool NPObjectProxy::NPGetProperty(NPObject
*obj
,
257 NPVariant
*np_result
) {
258 // Please refer to http://code.google.com/p/chromium/issues/detail?id=2556,
259 // which was a crash in the XStandard plugin during plugin shutdown. The
260 // crash occured because the plugin requests the plugin script object,
261 // which fails. The plugin does not check the result of the operation and
262 // invokes NPN_GetProperty on a NULL object which lead to the crash. If
263 // we observe similar crashes in other methods in the future, these null
264 // checks may have to be replicated in the other methods in this class.
268 NPObjectProxy
* proxy
= GetProxy(obj
);
270 return obj
->_class
->getProperty(obj
, name
, np_result
);
274 int render_view_id
= proxy
->render_view_id_
;
275 NPIdentifier_Param name_param
;
276 CreateNPIdentifierParam(name
, &name_param
);
278 NPVariant_Param param
;
279 scoped_refptr
<NPChannelBase
> channel(proxy
->channel_
);
281 GURL page_url
= proxy
->page_url_
;
282 proxy
->Send(new NPObjectMsg_GetProperty(
283 proxy
->route_id(), name_param
, ¶m
, &result
));
284 // Send may delete proxy.
290 param
, channel
.get(), np_result
, render_view_id
, page_url
);
295 bool NPObjectProxy::NPSetProperty(NPObject
*obj
,
297 const NPVariant
*value
) {
301 NPObjectProxy
* proxy
= GetProxy(obj
);
303 return obj
->_class
->setProperty(obj
, name
, value
);
307 int render_view_id
= proxy
->render_view_id_
;
308 NPIdentifier_Param name_param
;
309 CreateNPIdentifierParam(name
, &name_param
);
311 NPVariant_Param value_param
;
312 CreateNPVariantParam(
313 *value
, proxy
->channel(), &value_param
, false, render_view_id
,
316 proxy
->Send(new NPObjectMsg_SetProperty(
317 proxy
->route_id(), name_param
, value_param
, &result
));
318 // Send may delete proxy.
324 bool NPObjectProxy::NPRemoveProperty(NPObject
*obj
,
330 NPObjectProxy
* proxy
= GetProxy(obj
);
332 return obj
->_class
->removeProperty(obj
, name
);
335 NPIdentifier_Param name_param
;
336 CreateNPIdentifierParam(name
, &name_param
);
338 NPVariant_Param param
;
339 proxy
->Send(new NPObjectMsg_RemoveProperty(
340 proxy
->route_id(), name_param
, &result
));
341 // Send may delete proxy.
347 void NPObjectProxy::NPPInvalidate(NPObject
*obj
) {
351 NPObjectProxy
* proxy
= GetProxy(obj
);
353 obj
->_class
->invalidate(obj
);
357 proxy
->Send(new NPObjectMsg_Invalidate(proxy
->route_id()));
358 // Send may delete proxy.
362 bool NPObjectProxy::NPNEnumerate(NPObject
*obj
,
363 NPIdentifier
**value
,
369 NPObjectProxy
* proxy
= GetProxy(obj
);
371 if (obj
->_class
->structVersion
>= NP_CLASS_STRUCT_VERSION_ENUM
) {
372 return obj
->_class
->enumerate(obj
, value
, count
);
378 std::vector
<NPIdentifier_Param
> value_param
;
379 proxy
->Send(new NPObjectMsg_Enumeration(
380 proxy
->route_id(), &value_param
, &result
));
381 // Send may delete proxy.
387 *count
= static_cast<unsigned int>(value_param
.size());
388 *value
= static_cast<NPIdentifier
*>(
389 webkit::npapi::PluginHost::Singleton()->host_functions()->memalloc(
390 sizeof(NPIdentifier
) * *count
));
391 for (unsigned int i
= 0; i
< *count
; ++i
)
392 (*value
)[i
] = CreateNPIdentifier(value_param
[i
]);
397 bool NPObjectProxy::NPNConstruct(NPObject
*obj
,
398 const NPVariant
*args
,
400 NPVariant
*np_result
) {
404 NPObjectProxy
* proxy
= GetProxy(obj
);
406 if (obj
->_class
->structVersion
>= NP_CLASS_STRUCT_VERSION_CTOR
) {
407 return obj
->_class
->construct(obj
, args
, arg_count
, np_result
);
414 int render_view_id
= proxy
->render_view_id_
;
416 // Note: This instance can get destroyed in the context of
417 // Send so addref the channel in this scope.
418 scoped_refptr
<NPChannelBase
> channel_copy
= proxy
->channel_
;
419 std::vector
<NPVariant_Param
> args_param
;
420 for (unsigned int i
= 0; i
< arg_count
; ++i
) {
421 NPVariant_Param param
;
422 CreateNPVariantParam(
423 args
[i
], channel_copy
, ¶m
, false, render_view_id
,
425 args_param
.push_back(param
);
428 NPVariant_Param param_result
;
429 NPObjectMsg_Construct
* msg
= new NPObjectMsg_Construct(
430 proxy
->route_id_
, args_param
, ¶m_result
, &result
);
432 // See comment in NPObjectProxy::NPInvokePrivate.
433 if (IsPluginProcess() && proxy
->channel()) {
434 msg
->set_pump_messages_event(
435 proxy
->channel()->GetModalDialogEvent(proxy
->render_view_id_
));
438 GURL page_url
= proxy
->page_url_
;
441 // Send may delete proxy.
448 param_result
, channel_copy
, np_result
, render_view_id
, page_url
);
452 bool NPObjectProxy::NPNEvaluate(NPP npp
,
455 NPVariant
*result_var
) {
456 NPObjectProxy
* proxy
= GetProxy(obj
);
462 int render_view_id
= proxy
->render_view_id_
;
463 bool popups_allowed
= false;
466 webkit::npapi::PluginInstance
* plugin_instance
=
467 reinterpret_cast<webkit::npapi::PluginInstance
*>(npp
->ndata
);
469 popups_allowed
= plugin_instance
->popups_allowed();
472 NPVariant_Param result_param
;
473 std::string script_str
= std::string(
474 script
->UTF8Characters
, script
->UTF8Length
);
476 NPObjectMsg_Evaluate
* msg
= new NPObjectMsg_Evaluate(proxy
->route_id(),
482 // See comment in NPObjectProxy::NPInvokePrivate.
483 if (IsPluginProcess() && proxy
->channel()) {
484 msg
->set_pump_messages_event(
485 proxy
->channel()->GetModalDialogEvent(render_view_id
));
487 scoped_refptr
<NPChannelBase
> channel(proxy
->channel_
);
489 GURL page_url
= proxy
->page_url_
;
491 // Send may delete proxy.
497 result_param
, channel
.get(), result_var
, render_view_id
, page_url
);
501 } // namespace content