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 "content/common/np_channel_base.h"
8 #include "content/common/npobject_util.h"
9 #include "content/common/plugin_messages.h"
10 #include "content/public/common/content_client.h"
11 #include "content/public/common/content_switches.h"
12 #include "third_party/npapi/bindings/npapi.h"
13 #include "third_party/npapi/bindings/npruntime.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
15 #include "webkit/plugins/npapi/plugin_host.h"
18 #include "base/command_line.h"
19 #include "webkit/plugins/npapi/plugin_constants_win.h"
22 using WebKit::WebBindings
;
26 NPObjectStub::NPObjectStub(
28 NPChannelBase
* channel
,
32 : npobject_(npobject
),
35 render_view_id_(render_view_id
),
37 channel_
->AddMappingForNPObjectStub(route_id
, npobject
);
38 channel_
->AddRoute(route_id
, this, this);
40 // We retain the object just as PluginHost does if everything was in-process.
41 WebBindings::retainObject(npobject_
);
44 NPObjectStub::~NPObjectStub() {
45 channel_
->RemoveRoute(route_id_
);
49 void NPObjectStub::DeleteSoon() {
51 channel_
->RemoveMappingForNPObjectStub(route_id_
, npobject_
);
53 // We need to NULL npobject_ prior to calling releaseObject() to avoid
54 // problems with re-entrancy. See http://crbug.com/94179#c17 for more
55 // details on how this can happen.
56 NPObject
* npobject
= npobject_
;
59 WebBindings::releaseObject(npobject
);
61 MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
65 bool NPObjectStub::Send(IPC::Message
* msg
) {
66 return channel_
->Send(msg
);
69 NPObject
* NPObjectStub::GetUnderlyingNPObject() {
73 IPC::Listener
* NPObjectStub::GetChannelListener() {
74 return static_cast<IPC::Listener
*>(this);
77 bool NPObjectStub::OnMessageReceived(const IPC::Message
& msg
) {
78 GetContentClient()->SetActiveURL(page_url_
);
81 // The object could be garbage because the frame has gone away, so
82 // just send an error reply to the caller.
83 IPC::Message
* reply
= IPC::SyncMessage::GenerateReply(&msg
);
84 reply
->set_reply_error();
92 IPC_BEGIN_MESSAGE_MAP(NPObjectStub
, msg
)
93 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Release
, OnRelease
);
94 IPC_MESSAGE_HANDLER(NPObjectMsg_HasMethod
, OnHasMethod
);
95 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Invoke
, OnInvoke
);
96 IPC_MESSAGE_HANDLER(NPObjectMsg_HasProperty
, OnHasProperty
);
97 IPC_MESSAGE_HANDLER(NPObjectMsg_GetProperty
, OnGetProperty
);
98 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_SetProperty
, OnSetProperty
);
99 IPC_MESSAGE_HANDLER(NPObjectMsg_RemoveProperty
, OnRemoveProperty
);
100 IPC_MESSAGE_HANDLER(NPObjectMsg_Invalidate
, OnInvalidate
);
101 IPC_MESSAGE_HANDLER(NPObjectMsg_Enumeration
, OnEnumeration
);
102 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Construct
, OnConstruct
);
103 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Evaluate
, OnEvaluate
);
104 IPC_MESSAGE_UNHANDLED(handled
= false)
105 IPC_END_MESSAGE_MAP()
110 void NPObjectStub::OnChannelError() {
114 void NPObjectStub::OnRelease(IPC::Message
* reply_msg
) {
119 void NPObjectStub::OnHasMethod(const NPIdentifier_Param
& name
,
121 NPIdentifier id
= CreateNPIdentifier(name
);
122 // If we're in the plugin process, then the stub is holding onto an NPObject
123 // from the plugin, so all function calls on it need to go through the
124 // functions in NPClass. If we're in the renderer process, then we just call
125 // the NPN_ functions.
126 if (IsPluginProcess()) {
127 if (npobject_
->_class
->hasMethod
) {
128 *result
= npobject_
->_class
->hasMethod(npobject_
, id
);
133 *result
= WebBindings::hasMethod(0, npobject_
, id
);
137 void NPObjectStub::OnInvoke(bool is_default
,
138 const NPIdentifier_Param
& method
,
139 const std::vector
<NPVariant_Param
>& args
,
140 IPC::Message
* reply_msg
) {
141 bool return_value
= false;
142 NPVariant_Param result_param
;
143 NPVariant result_var
;
145 VOID_TO_NPVARIANT(result_var
);
146 result_param
.type
= NPVARIANT_PARAM_VOID
;
148 int arg_count
= static_cast<int>(args
.size());
149 NPVariant
* args_var
= new NPVariant
[arg_count
];
150 for (int i
= 0; i
< arg_count
; ++i
) {
151 if (!CreateNPVariant(
152 args
[i
], channel_
, &(args_var
[i
]), render_view_id_
, page_url_
)) {
153 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
,
155 channel_
->Send(reply_msg
);
162 if (IsPluginProcess()) {
163 if (npobject_
->_class
->invokeDefault
) {
164 return_value
= npobject_
->_class
->invokeDefault(
165 npobject_
, args_var
, arg_count
, &result_var
);
167 return_value
= false;
170 return_value
= WebBindings::invokeDefault(
171 0, npobject_
, args_var
, arg_count
, &result_var
);
174 NPIdentifier id
= CreateNPIdentifier(method
);
175 if (IsPluginProcess()) {
176 if (npobject_
->_class
->invoke
) {
177 return_value
= npobject_
->_class
->invoke(
178 npobject_
, id
, args_var
, arg_count
, &result_var
);
180 return_value
= false;
183 return_value
= WebBindings::invoke(
184 0, npobject_
, id
, args_var
, arg_count
, &result_var
);
188 for (int i
= 0; i
< arg_count
; ++i
)
189 WebBindings::releaseVariantValue(&(args_var
[i
]));
193 CreateNPVariantParam(
194 result_var
, channel_
, &result_param
, true, render_view_id_
, page_url_
);
195 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
, return_value
);
196 channel_
->Send(reply_msg
);
199 void NPObjectStub::OnHasProperty(const NPIdentifier_Param
& name
,
201 NPIdentifier id
= CreateNPIdentifier(name
);
202 if (IsPluginProcess()) {
203 if (npobject_
->_class
->hasProperty
) {
204 *result
= npobject_
->_class
->hasProperty(npobject_
, id
);
209 *result
= WebBindings::hasProperty(0, npobject_
, id
);
213 void NPObjectStub::OnGetProperty(const NPIdentifier_Param
& name
,
214 NPVariant_Param
* property
,
216 NPVariant result_var
;
217 VOID_TO_NPVARIANT(result_var
);
218 NPIdentifier id
= CreateNPIdentifier(name
);
220 if (IsPluginProcess()) {
221 if (npobject_
->_class
->getProperty
) {
222 *result
= npobject_
->_class
->getProperty(npobject_
, id
, &result_var
);
227 *result
= WebBindings::getProperty(0, npobject_
, id
, &result_var
);
230 CreateNPVariantParam(
231 result_var
, channel_
, property
, true, render_view_id_
, page_url_
);
234 void NPObjectStub::OnSetProperty(const NPIdentifier_Param
& name
,
235 const NPVariant_Param
& property
,
236 IPC::Message
* reply_msg
) {
238 NPIdentifier id
= CreateNPIdentifier(name
);
239 NPVariant property_var
;
240 if (!CreateNPVariant(
241 property
, channel_
, &property_var
, render_view_id_
, page_url_
)) {
242 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg
, result
);
243 channel_
->Send(reply_msg
);
247 if (IsPluginProcess()) {
248 if (npobject_
->_class
->setProperty
) {
250 static FilePath plugin_path
=
251 CommandLine::ForCurrentProcess()->GetSwitchValuePath(
252 switches::kPluginPath
);
253 static std::wstring filename
= StringToLowerASCII(
254 plugin_path
.BaseName().value());
255 static NPIdentifier fullscreen
=
256 WebBindings::getStringIdentifier("fullScreen");
257 if (filename
== webkit::npapi::kNewWMPPlugin
&& id
== fullscreen
) {
258 // Workaround for bug 15985, which is if Flash causes WMP to go
259 // full screen a deadlock can occur when WMP calls SetFocus.
260 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg
, true);
265 result
= npobject_
->_class
->setProperty(npobject_
, id
, &property_var
);
270 result
= WebBindings::setProperty(0, npobject_
, id
, &property_var
);
273 WebBindings::releaseVariantValue(&property_var
);
276 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg
, result
);
281 void NPObjectStub::OnRemoveProperty(const NPIdentifier_Param
& name
,
283 NPIdentifier id
= CreateNPIdentifier(name
);
284 if (IsPluginProcess()) {
285 if (npobject_
->_class
->removeProperty
) {
286 *result
= npobject_
->_class
->removeProperty(npobject_
, id
);
291 *result
= WebBindings::removeProperty(0, npobject_
, id
);
295 void NPObjectStub::OnInvalidate() {
296 if (!IsPluginProcess()) {
297 NOTREACHED() << "Should only be called on NPObjects in the plugin";
301 if (!npobject_
->_class
->invalidate
)
304 npobject_
->_class
->invalidate(npobject_
);
307 void NPObjectStub::OnEnumeration(std::vector
<NPIdentifier_Param
>* value
,
309 NPIdentifier
* value_np
= NULL
;
310 unsigned int count
= 0;
311 if (!IsPluginProcess()) {
312 *result
= WebBindings::enumerate(0, npobject_
, &value_np
, &count
);
314 if (npobject_
->_class
->structVersion
< NP_CLASS_STRUCT_VERSION_ENUM
||
315 !npobject_
->_class
->enumerate
) {
320 *result
= npobject_
->_class
->enumerate(npobject_
, &value_np
, &count
);
326 for (unsigned int i
= 0; i
< count
; ++i
) {
327 NPIdentifier_Param param
;
328 CreateNPIdentifierParam(value_np
[i
], ¶m
);
329 value
->push_back(param
);
332 webkit::npapi::PluginHost::Singleton()->host_functions()->memfree(value_np
);
335 void NPObjectStub::OnConstruct(const std::vector
<NPVariant_Param
>& args
,
336 IPC::Message
* reply_msg
) {
337 bool return_value
= false;
338 NPVariant_Param result_param
;
339 NPVariant result_var
;
341 VOID_TO_NPVARIANT(result_var
);
343 int arg_count
= static_cast<int>(args
.size());
344 NPVariant
* args_var
= new NPVariant
[arg_count
];
345 for (int i
= 0; i
< arg_count
; ++i
) {
346 if (!CreateNPVariant(
347 args
[i
], channel_
, &(args_var
[i
]), render_view_id_
, page_url_
)) {
348 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
,
350 channel_
->Send(reply_msg
);
356 if (IsPluginProcess()) {
357 if (npobject_
->_class
->structVersion
>= NP_CLASS_STRUCT_VERSION_CTOR
&&
358 npobject_
->_class
->construct
) {
359 return_value
= npobject_
->_class
->construct(
360 npobject_
, args_var
, arg_count
, &result_var
);
362 return_value
= false;
365 return_value
= WebBindings::construct(
366 0, npobject_
, args_var
, arg_count
, &result_var
);
369 for (int i
= 0; i
< arg_count
; ++i
)
370 WebBindings::releaseVariantValue(&(args_var
[i
]));
374 CreateNPVariantParam(
375 result_var
, channel_
, &result_param
, true, render_view_id_
, page_url_
);
376 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
, return_value
);
377 channel_
->Send(reply_msg
);
380 void NPObjectStub::OnEvaluate(const std::string
& script
,
382 IPC::Message
* reply_msg
) {
383 if (IsPluginProcess()) {
384 NOTREACHED() << "Should only be called on NPObjects in the renderer";
388 NPVariant result_var
;
389 NPString script_string
;
390 script_string
.UTF8Characters
= script
.c_str();
391 script_string
.UTF8Length
= static_cast<unsigned int>(script
.length());
393 bool return_value
= WebBindings::evaluateHelper(0, popups_allowed
, npobject_
,
394 &script_string
, &result_var
);
396 NPVariant_Param result_param
;
397 CreateNPVariantParam(
398 result_var
, channel_
, &result_param
, true, render_view_id_
, page_url_
);
399 NPObjectMsg_Evaluate::WriteReplyParams(reply_msg
, result_param
, return_value
);
400 channel_
->Send(reply_msg
);
403 } // namespace content