1 // Copyright 2013 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/child/npapi/npobject_stub.h"
7 #include "content/child/npapi/np_channel_base.h"
8 #include "content/child/npapi/npobject_util.h"
9 #include "content/child/plugin_messages.h"
10 #include "content/public/common/content_client.h"
11 #include "content/public/common/content_switches.h"
12 #include "third_party/WebKit/public/web/WebBindings.h"
13 #include "third_party/npapi/bindings/npapi.h"
14 #include "third_party/npapi/bindings/npruntime.h"
17 #include "base/command_line.h"
18 #include "content/common/plugin_constants_win.h"
21 using blink::WebBindings
;
25 NPObjectStub::NPObjectStub(
27 NPChannelBase
* channel
,
31 : npobject_(npobject
),
34 render_view_id_(render_view_id
),
36 channel_
->AddMappingForNPObjectStub(route_id
, npobject
);
37 channel_
->AddRoute(route_id
, this, this);
39 // We retain the object just as PluginHost does if everything was in-process.
40 WebBindings::retainObject(npobject_
);
43 NPObjectStub::~NPObjectStub() {
44 channel_
->RemoveRoute(route_id_
);
48 void NPObjectStub::DeleteSoon() {
50 channel_
->RemoveMappingForNPObjectStub(route_id_
, npobject_
);
52 // We need to NULL npobject_ prior to calling releaseObject() to avoid
53 // problems with re-entrancy. See http://crbug.com/94179#c17 for more
54 // details on how this can happen.
55 NPObject
* npobject
= npobject_
;
58 WebBindings::releaseObject(npobject
);
60 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
64 bool NPObjectStub::Send(IPC::Message
* msg
) {
65 return channel_
->Send(msg
);
68 NPObject
* NPObjectStub::GetUnderlyingNPObject() {
72 IPC::Listener
* NPObjectStub::GetChannelListener() {
73 return static_cast<IPC::Listener
*>(this);
76 bool NPObjectStub::OnMessageReceived(const IPC::Message
& msg
) {
77 GetContentClient()->SetActiveURL(page_url_
);
80 // The object could be garbage because the frame has gone away, so
81 // just send an error reply to the caller.
82 IPC::Message
* reply
= IPC::SyncMessage::GenerateReply(&msg
);
83 reply
->set_reply_error();
91 IPC_BEGIN_MESSAGE_MAP(NPObjectStub
, msg
)
92 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Release
, OnRelease
);
93 IPC_MESSAGE_HANDLER(NPObjectMsg_HasMethod
, OnHasMethod
);
94 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Invoke
, OnInvoke
);
95 IPC_MESSAGE_HANDLER(NPObjectMsg_HasProperty
, OnHasProperty
);
96 IPC_MESSAGE_HANDLER(NPObjectMsg_GetProperty
, OnGetProperty
);
97 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_SetProperty
, OnSetProperty
);
98 IPC_MESSAGE_HANDLER(NPObjectMsg_RemoveProperty
, OnRemoveProperty
);
99 IPC_MESSAGE_HANDLER(NPObjectMsg_Invalidate
, OnInvalidate
);
100 IPC_MESSAGE_HANDLER(NPObjectMsg_Enumeration
, OnEnumeration
);
101 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Construct
, OnConstruct
);
102 IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Evaluate
, OnEvaluate
);
103 IPC_MESSAGE_UNHANDLED(handled
= false)
104 IPC_END_MESSAGE_MAP()
109 void NPObjectStub::OnChannelError() {
113 void NPObjectStub::OnRelease(IPC::Message
* reply_msg
) {
118 void NPObjectStub::OnHasMethod(const NPIdentifier_Param
& name
,
120 NPIdentifier id
= CreateNPIdentifier(name
);
121 // If we're in the plugin process, then the stub is holding onto an NPObject
122 // from the plugin, so all function calls on it need to go through the
123 // functions in NPClass. If we're in the renderer process, then we just call
124 // the NPN_ functions.
125 if (IsPluginProcess()) {
126 if (npobject_
->_class
->hasMethod
) {
127 *result
= npobject_
->_class
->hasMethod(npobject_
, id
);
132 *result
= WebBindings::hasMethod(0, npobject_
, id
);
136 void NPObjectStub::OnInvoke(bool is_default
,
137 const NPIdentifier_Param
& method
,
138 const std::vector
<NPVariant_Param
>& args
,
139 IPC::Message
* reply_msg
) {
140 bool return_value
= false;
141 NPVariant_Param result_param
;
142 NPVariant result_var
;
144 VOID_TO_NPVARIANT(result_var
);
145 result_param
.type
= NPVARIANT_PARAM_VOID
;
147 int arg_count
= static_cast<int>(args
.size());
148 NPVariant
* args_var
= new NPVariant
[arg_count
];
149 for (int i
= 0; i
< arg_count
; ++i
) {
150 if (!CreateNPVariant(args
[i
],
155 NPObjectMsg_Invoke::WriteReplyParams(
156 reply_msg
, result_param
, return_value
);
157 channel_
->Send(reply_msg
);
164 if (IsPluginProcess()) {
165 if (npobject_
->_class
->invokeDefault
) {
166 return_value
= npobject_
->_class
->invokeDefault(
167 npobject_
, args_var
, arg_count
, &result_var
);
169 return_value
= false;
172 return_value
= WebBindings::invokeDefault(
173 0, npobject_
, args_var
, arg_count
, &result_var
);
176 NPIdentifier id
= CreateNPIdentifier(method
);
177 if (IsPluginProcess()) {
178 if (npobject_
->_class
->invoke
) {
179 return_value
= npobject_
->_class
->invoke(
180 npobject_
, id
, args_var
, arg_count
, &result_var
);
182 return_value
= false;
185 return_value
= WebBindings::invoke(
186 0, npobject_
, id
, args_var
, arg_count
, &result_var
);
190 for (int i
= 0; i
< arg_count
; ++i
)
191 WebBindings::releaseVariantValue(&(args_var
[i
]));
195 CreateNPVariantParam(result_var
,
201 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
, return_value
);
202 channel_
->Send(reply_msg
);
205 void NPObjectStub::OnHasProperty(const NPIdentifier_Param
& name
,
207 NPIdentifier id
= CreateNPIdentifier(name
);
208 if (IsPluginProcess()) {
209 if (npobject_
->_class
->hasProperty
) {
210 *result
= npobject_
->_class
->hasProperty(npobject_
, id
);
215 *result
= WebBindings::hasProperty(0, npobject_
, id
);
219 void NPObjectStub::OnGetProperty(const NPIdentifier_Param
& name
,
220 NPVariant_Param
* property
,
222 NPVariant result_var
;
223 VOID_TO_NPVARIANT(result_var
);
224 NPIdentifier id
= CreateNPIdentifier(name
);
226 if (IsPluginProcess()) {
227 if (npobject_
->_class
->getProperty
) {
228 *result
= npobject_
->_class
->getProperty(npobject_
, id
, &result_var
);
233 *result
= WebBindings::getProperty(0, npobject_
, id
, &result_var
);
236 CreateNPVariantParam(
237 result_var
, channel_
.get(), property
, true, render_view_id_
, page_url_
);
240 void NPObjectStub::OnSetProperty(const NPIdentifier_Param
& name
,
241 const NPVariant_Param
& property
,
242 IPC::Message
* reply_msg
) {
244 NPIdentifier id
= CreateNPIdentifier(name
);
245 NPVariant property_var
;
246 if (!CreateNPVariant(property
,
251 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg
, result
);
252 channel_
->Send(reply_msg
);
256 if (IsPluginProcess()) {
257 if (npobject_
->_class
->setProperty
) {
259 static base::FilePath plugin_path
=
260 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
261 switches::kPluginPath
);
262 static std::wstring filename
= base::StringToLowerASCII(
263 plugin_path
.BaseName().value());
264 static NPIdentifier fullscreen
=
265 WebBindings::getStringIdentifier("fullScreen");
266 if (filename
== kNewWMPPlugin
&& id
== fullscreen
) {
267 // Workaround for bug 15985, which is if Flash causes WMP to go
268 // full screen a deadlock can occur when WMP calls SetFocus.
269 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg
, true);
274 result
= npobject_
->_class
->setProperty(npobject_
, id
, &property_var
);
279 result
= WebBindings::setProperty(0, npobject_
, id
, &property_var
);
282 WebBindings::releaseVariantValue(&property_var
);
285 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg
, result
);
290 void NPObjectStub::OnRemoveProperty(const NPIdentifier_Param
& name
,
292 NPIdentifier id
= CreateNPIdentifier(name
);
293 if (IsPluginProcess()) {
294 if (npobject_
->_class
->removeProperty
) {
295 *result
= npobject_
->_class
->removeProperty(npobject_
, id
);
300 *result
= WebBindings::removeProperty(0, npobject_
, id
);
304 void NPObjectStub::OnInvalidate() {
305 if (!IsPluginProcess()) {
306 NOTREACHED() << "Should only be called on NPObjects in the plugin";
310 if (!npobject_
->_class
->invalidate
)
313 npobject_
->_class
->invalidate(npobject_
);
316 void NPObjectStub::OnEnumeration(std::vector
<NPIdentifier_Param
>* value
,
318 NPIdentifier
* value_np
= NULL
;
319 unsigned int count
= 0;
320 if (!IsPluginProcess()) {
321 *result
= WebBindings::enumerate(0, npobject_
, &value_np
, &count
);
323 if (npobject_
->_class
->structVersion
< NP_CLASS_STRUCT_VERSION_ENUM
||
324 !npobject_
->_class
->enumerate
) {
329 *result
= npobject_
->_class
->enumerate(npobject_
, &value_np
, &count
);
335 for (unsigned int i
= 0; i
< count
; ++i
) {
336 NPIdentifier_Param param
;
337 CreateNPIdentifierParam(value_np
[i
], ¶m
);
338 value
->push_back(param
);
344 void NPObjectStub::OnConstruct(const std::vector
<NPVariant_Param
>& args
,
345 IPC::Message
* reply_msg
) {
346 bool return_value
= false;
347 NPVariant_Param result_param
;
348 NPVariant result_var
;
350 VOID_TO_NPVARIANT(result_var
);
352 int arg_count
= static_cast<int>(args
.size());
353 NPVariant
* args_var
= new NPVariant
[arg_count
];
354 for (int i
= 0; i
< arg_count
; ++i
) {
355 if (!CreateNPVariant(args
[i
],
360 NPObjectMsg_Invoke::WriteReplyParams(
361 reply_msg
, result_param
, return_value
);
362 channel_
->Send(reply_msg
);
368 if (IsPluginProcess()) {
369 if (npobject_
->_class
->structVersion
>= NP_CLASS_STRUCT_VERSION_CTOR
&&
370 npobject_
->_class
->construct
) {
371 return_value
= npobject_
->_class
->construct(
372 npobject_
, args_var
, arg_count
, &result_var
);
374 return_value
= false;
377 return_value
= WebBindings::construct(
378 0, npobject_
, args_var
, arg_count
, &result_var
);
381 for (int i
= 0; i
< arg_count
; ++i
)
382 WebBindings::releaseVariantValue(&(args_var
[i
]));
386 CreateNPVariantParam(result_var
,
392 NPObjectMsg_Invoke::WriteReplyParams(reply_msg
, result_param
, return_value
);
393 channel_
->Send(reply_msg
);
396 void NPObjectStub::OnEvaluate(const std::string
& script
,
398 IPC::Message
* reply_msg
) {
399 if (IsPluginProcess()) {
400 NOTREACHED() << "Should only be called on NPObjects in the renderer";
404 NPVariant result_var
;
405 NPString script_string
;
406 script_string
.UTF8Characters
= script
.c_str();
407 script_string
.UTF8Length
= static_cast<unsigned int>(script
.length());
409 bool return_value
= WebBindings::evaluateHelper(0, popups_allowed
, npobject_
,
410 &script_string
, &result_var
);
412 NPVariant_Param result_param
;
413 CreateNPVariantParam(result_var
,
419 NPObjectMsg_Evaluate::WriteReplyParams(reply_msg
, result_param
, return_value
);
420 channel_
->Send(reply_msg
);
423 } // namespace content