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_stub.h"
7 #include "base/command_line.h"
8 #include "content/common/np_channel_base.h"
9 #include "content/common/npobject_util.h"
10 #include "content/common/plugin_messages.h"
11 #include "content/public/common/content_client.h"
12 #include "content/public/common/content_switches.h"
13 #include "third_party/npapi/bindings/npapi.h"
14 #include "third_party/npapi/bindings/npruntime.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
16 #include "webkit/plugins/npapi/plugin_constants_win.h"
17 #include "webkit/plugins/npapi/plugin_host.h"
19 using WebKit::WebBindings
;
21 NPObjectStub::NPObjectStub(
23 NPChannelBase
* channel
,
25 gfx::NativeViewId containing_window
,
27 : npobject_(npobject
),
30 containing_window_(containing_window
),
32 channel_
->AddMappingForNPObjectStub(route_id
, npobject
);
33 channel_
->AddRoute(route_id
, this, this);
35 // We retain the object just as PluginHost does if everything was in-process.
36 WebBindings::retainObject(npobject_
);
39 NPObjectStub::~NPObjectStub() {
40 channel_
->RemoveRoute(route_id_
);
44 void NPObjectStub::DeleteSoon() {
46 channel_
->RemoveMappingForNPObjectStub(route_id_
, npobject_
);
48 // We need to NULL npobject_ prior to calling releaseObject() to avoid
49 // problems with re-entrancy. See http://crbug.com/94179#c17 for more
50 // details on how this can happen.
51 NPObject
* npobject
= npobject_
;
54 WebBindings::releaseObject(npobject
);
56 MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
60 bool NPObjectStub::Send(IPC::Message
* msg
) {
61 return channel_
->Send(msg
);
64 NPObject
* NPObjectStub::GetUnderlyingNPObject() {
68 IPC::Channel::Listener
* NPObjectStub::GetChannelListener() {
69 return static_cast<IPC::Channel::Listener
*>(this);
72 bool NPObjectStub::OnMessageReceived(const IPC::Message
& msg
) {
73 content::GetContentClient()->SetActiveURL(page_url_
);
76 // The object could be garbage because the frame has gone away, so
77 // just send an error reply to the caller.
78 IPC::Message
* reply
= IPC::SyncMessage::GenerateReply(&msg
);
79 reply
->set_reply_error();
87 IPC_BEGIN_MESSAGE_MAP(NPObjectStub
, msg
)
88 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Release
, OnRelease
);
89 IPC_MESSAGE_HANDLER(NPObjectMsg_HasMethod
, OnHasMethod
);
90 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Invoke
, OnInvoke
);
91 IPC_MESSAGE_HANDLER(NPObjectMsg_HasProperty
, OnHasProperty
);
92 IPC_MESSAGE_HANDLER(NPObjectMsg_GetProperty
, OnGetProperty
);
93 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_SetProperty
, OnSetProperty
);
94 IPC_MESSAGE_HANDLER(NPObjectMsg_RemoveProperty
, OnRemoveProperty
);
95 IPC_MESSAGE_HANDLER(NPObjectMsg_Invalidate
, OnInvalidate
);
96 IPC_MESSAGE_HANDLER(NPObjectMsg_Enumeration
, OnEnumeration
);
97 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Construct
, OnConstruct
);
98 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Evaluate
, OnEvaluate
);
99 IPC_MESSAGE_UNHANDLED(handled
= false)
100 IPC_END_MESSAGE_MAP()
105 void NPObjectStub::OnChannelError() {
109 void NPObjectStub::OnRelease(IPC::Message
* reply_msg
) {
114 void NPObjectStub::OnHasMethod(const NPIdentifier_Param
& name
,
116 NPIdentifier id
= CreateNPIdentifier(name
);
117 // If we're in the plugin process, then the stub is holding onto an NPObject
118 // from the plugin, so all function calls on it need to go through the
119 // functions in NPClass. If we're in the renderer process, then we just call
120 // the NPN_ functions.
121 if (IsPluginProcess()) {
122 if (npobject_
->_class
->hasMethod
) {
123 *result
= npobject_
->_class
->hasMethod(npobject_
, id
);
128 *result
= WebBindings::hasMethod(0, npobject_
, id
);
132 void NPObjectStub::OnInvoke(bool is_default
,
133 const NPIdentifier_Param
& method
,
134 const std::vector
<NPVariant_Param
>& args
,
135 IPC::Message
* reply_msg
) {
136 bool return_value
= false;
137 NPVariant_Param result_param
;
138 NPVariant result_var
;
140 VOID_TO_NPVARIANT(result_var
);
141 result_param
.type
= NPVARIANT_PARAM_VOID
;
143 int arg_count
= static_cast<int>(args
.size());
144 NPVariant
* args_var
= new NPVariant
[arg_count
];
145 for (int i
= 0; i
< arg_count
; ++i
) {
146 if (!CreateNPVariant(
147 args
[i
], channel_
, &(args_var
[i
]), containing_window_
,
149 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
,
151 channel_
->Send(reply_msg
);
158 if (IsPluginProcess()) {
159 if (npobject_
->_class
->invokeDefault
) {
160 return_value
= npobject_
->_class
->invokeDefault(
161 npobject_
, args_var
, arg_count
, &result_var
);
163 return_value
= false;
166 return_value
= WebBindings::invokeDefault(
167 0, npobject_
, args_var
, arg_count
, &result_var
);
170 NPIdentifier id
= CreateNPIdentifier(method
);
171 if (IsPluginProcess()) {
172 if (npobject_
->_class
->invoke
) {
173 return_value
= npobject_
->_class
->invoke(
174 npobject_
, id
, args_var
, arg_count
, &result_var
);
176 return_value
= false;
179 return_value
= WebBindings::invoke(
180 0, npobject_
, id
, args_var
, arg_count
, &result_var
);
184 for (int i
= 0; i
< arg_count
; ++i
)
185 WebBindings::releaseVariantValue(&(args_var
[i
]));
189 CreateNPVariantParam(
190 result_var
, channel_
, &result_param
, true, containing_window_
,
192 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
, return_value
);
193 channel_
->Send(reply_msg
);
196 void NPObjectStub::OnHasProperty(const NPIdentifier_Param
& name
,
198 NPIdentifier id
= CreateNPIdentifier(name
);
199 if (IsPluginProcess()) {
200 if (npobject_
->_class
->hasProperty
) {
201 *result
= npobject_
->_class
->hasProperty(npobject_
, id
);
206 *result
= WebBindings::hasProperty(0, npobject_
, id
);
210 void NPObjectStub::OnGetProperty(const NPIdentifier_Param
& name
,
211 NPVariant_Param
* property
,
213 NPVariant result_var
;
214 VOID_TO_NPVARIANT(result_var
);
215 NPIdentifier id
= CreateNPIdentifier(name
);
217 if (IsPluginProcess()) {
218 if (npobject_
->_class
->getProperty
) {
219 *result
= npobject_
->_class
->getProperty(npobject_
, id
, &result_var
);
224 *result
= WebBindings::getProperty(0, npobject_
, id
, &result_var
);
227 CreateNPVariantParam(
228 result_var
, channel_
, property
, true, containing_window_
, page_url_
);
231 void NPObjectStub::OnSetProperty(const NPIdentifier_Param
& name
,
232 const NPVariant_Param
& property
,
233 IPC::Message
* reply_msg
) {
235 NPIdentifier id
= CreateNPIdentifier(name
);
236 NPVariant property_var
;
237 if (!CreateNPVariant(
238 property
, channel_
, &property_var
, containing_window_
, page_url_
)) {
239 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg
, result
);
240 channel_
->Send(reply_msg
);
244 if (IsPluginProcess()) {
245 if (npobject_
->_class
->setProperty
) {
247 static FilePath plugin_path
=
248 CommandLine::ForCurrentProcess()->GetSwitchValuePath(
249 switches::kPluginPath
);
250 static std::wstring filename
= StringToLowerASCII(
251 plugin_path
.BaseName().value());
252 static NPIdentifier fullscreen
=
253 WebBindings::getStringIdentifier("fullScreen");
254 if (filename
== webkit::npapi::kNewWMPPlugin
&& id
== fullscreen
) {
255 // Workaround for bug 15985, which is if Flash causes WMP to go
256 // full screen a deadlock can occur when WMP calls SetFocus.
257 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg
, true);
262 result
= npobject_
->_class
->setProperty(npobject_
, id
, &property_var
);
267 result
= WebBindings::setProperty(0, npobject_
, id
, &property_var
);
270 WebBindings::releaseVariantValue(&property_var
);
273 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg
, result
);
278 void NPObjectStub::OnRemoveProperty(const NPIdentifier_Param
& name
,
280 NPIdentifier id
= CreateNPIdentifier(name
);
281 if (IsPluginProcess()) {
282 if (npobject_
->_class
->removeProperty
) {
283 *result
= npobject_
->_class
->removeProperty(npobject_
, id
);
288 *result
= WebBindings::removeProperty(0, npobject_
, id
);
292 void NPObjectStub::OnInvalidate() {
293 if (!IsPluginProcess()) {
294 NOTREACHED() << "Should only be called on NPObjects in the plugin";
298 if (!npobject_
->_class
->invalidate
)
301 npobject_
->_class
->invalidate(npobject_
);
304 void NPObjectStub::OnEnumeration(std::vector
<NPIdentifier_Param
>* value
,
306 NPIdentifier
* value_np
= NULL
;
307 unsigned int count
= 0;
308 if (!IsPluginProcess()) {
309 *result
= WebBindings::enumerate(0, npobject_
, &value_np
, &count
);
311 if (npobject_
->_class
->structVersion
< NP_CLASS_STRUCT_VERSION_ENUM
||
312 !npobject_
->_class
->enumerate
) {
317 *result
= npobject_
->_class
->enumerate(npobject_
, &value_np
, &count
);
323 for (unsigned int i
= 0; i
< count
; ++i
) {
324 NPIdentifier_Param param
;
325 CreateNPIdentifierParam(value_np
[i
], ¶m
);
326 value
->push_back(param
);
329 webkit::npapi::PluginHost::Singleton()->host_functions()->memfree(value_np
);
332 void NPObjectStub::OnConstruct(const std::vector
<NPVariant_Param
>& args
,
333 IPC::Message
* reply_msg
) {
334 bool return_value
= false;
335 NPVariant_Param result_param
;
336 NPVariant result_var
;
338 VOID_TO_NPVARIANT(result_var
);
340 int arg_count
= static_cast<int>(args
.size());
341 NPVariant
* args_var
= new NPVariant
[arg_count
];
342 for (int i
= 0; i
< arg_count
; ++i
) {
343 if (!CreateNPVariant(
344 args
[i
], channel_
, &(args_var
[i
]), containing_window_
,
346 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
,
348 channel_
->Send(reply_msg
);
354 if (IsPluginProcess()) {
355 if (npobject_
->_class
->structVersion
>= NP_CLASS_STRUCT_VERSION_CTOR
&&
356 npobject_
->_class
->construct
) {
357 return_value
= npobject_
->_class
->construct(
358 npobject_
, args_var
, arg_count
, &result_var
);
360 return_value
= false;
363 return_value
= WebBindings::construct(
364 0, npobject_
, args_var
, arg_count
, &result_var
);
367 for (int i
= 0; i
< arg_count
; ++i
)
368 WebBindings::releaseVariantValue(&(args_var
[i
]));
372 CreateNPVariantParam(
373 result_var
, channel_
, &result_param
, true, containing_window_
,
375 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
, return_value
);
376 channel_
->Send(reply_msg
);
379 void NPObjectStub::OnEvaluate(const std::string
& script
,
381 IPC::Message
* reply_msg
) {
382 if (IsPluginProcess()) {
383 NOTREACHED() << "Should only be called on NPObjects in the renderer";
387 NPVariant result_var
;
388 NPString script_string
;
389 script_string
.UTF8Characters
= script
.c_str();
390 script_string
.UTF8Length
= static_cast<unsigned int>(script
.length());
392 bool return_value
= WebBindings::evaluateHelper(0, popups_allowed
, npobject_
,
393 &script_string
, &result_var
);
395 NPVariant_Param result_param
;
396 CreateNPVariantParam(
397 result_var
, channel_
, &result_param
, true, containing_window_
, page_url_
);
398 NPObjectMsg_Evaluate::WriteReplyParams(reply_msg
, result_param
, return_value
);
399 channel_
->Send(reply_msg
);