[Android WebView] Fix webview perf bot switchover to use org.chromium.webview_shell...
[chromium-blink-merge.git] / content / child / npapi / npobject_proxy.cc
blob45dc68d665e1d793f59e601412e08d8cd057dbe8
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_proxy.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 "third_party/WebKit/public/web/WebBindings.h"
12 #if defined(ENABLE_PLUGINS)
13 #include "content/child/npapi/plugin_instance.h"
14 #endif
16 using blink::WebBindings;
18 namespace content {
20 struct NPObjectWrapper {
21 NPObject object;
22 NPObjectProxy* proxy;
25 NPClass NPObjectProxy::npclass_proxy_ = {
26 NP_CLASS_STRUCT_VERSION,
27 NPObjectProxy::NPAllocate,
28 NPObjectProxy::NPDeallocate,
29 NPObjectProxy::NPPInvalidate,
30 NPObjectProxy::NPHasMethod,
31 NPObjectProxy::NPInvoke,
32 NPObjectProxy::NPInvokeDefault,
33 NPObjectProxy::NPHasProperty,
34 NPObjectProxy::NPGetProperty,
35 NPObjectProxy::NPSetProperty,
36 NPObjectProxy::NPRemoveProperty,
37 NPObjectProxy::NPNEnumerate,
38 NPObjectProxy::NPNConstruct
41 NPObjectProxy* NPObjectProxy::GetProxy(NPObject* object) {
42 NPObjectProxy* proxy = NULL;
44 // Wrapper exists only for NPObjects that we had created.
45 if (&npclass_proxy_ == object->_class) {
46 NPObjectWrapper* wrapper = reinterpret_cast<NPObjectWrapper*>(object);
47 proxy = wrapper->proxy;
50 return proxy;
53 NPObject* NPObjectProxy::GetUnderlyingNPObject() {
54 return NULL;
57 IPC::Listener* NPObjectProxy::GetChannelListener() {
58 return static_cast<IPC::Listener*>(this);
61 NPObjectProxy::NPObjectProxy(
62 NPChannelBase* channel,
63 int route_id,
64 int render_view_id,
65 const GURL& page_url)
66 : channel_(channel),
67 route_id_(route_id),
68 render_view_id_(render_view_id),
69 page_url_(page_url) {
70 channel_->AddRoute(route_id, this, this);
73 NPObjectProxy::~NPObjectProxy() {
74 if (channel_.get()) {
75 // This NPObjectProxy instance is now invalid and should not be reused for
76 // requests initiated by plugins. We may receive requests for the
77 // same NPObject in the context of the outgoing NPObjectMsg_Release call.
78 // We should be creating new NPObjectProxy instances to wrap these
79 // NPObjects.
80 channel_->RemoveMappingForNPObjectProxy(route_id_);
81 channel_->RemoveRoute(route_id_);
82 Send(new NPObjectMsg_Release(route_id_));
86 NPObject* NPObjectProxy::Create(NPChannelBase* channel,
87 int route_id,
88 int render_view_id,
89 const GURL& page_url,
90 NPP owner) {
91 NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(
92 WebBindings::createObject(owner, &npclass_proxy_));
93 obj->proxy = new NPObjectProxy(channel, route_id, render_view_id, page_url);
94 channel->AddMappingForNPObjectProxy(route_id, &obj->object);
95 return reinterpret_cast<NPObject*>(obj);
98 bool NPObjectProxy::Send(IPC::Message* msg) {
99 if (channel_.get())
100 return channel_->Send(msg);
102 delete msg;
103 return false;
106 NPObject* NPObjectProxy::NPAllocate(NPP, NPClass*) {
107 return reinterpret_cast<NPObject*>(new NPObjectWrapper);
110 void NPObjectProxy::NPDeallocate(NPObject* npObj) {
111 NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(npObj);
112 delete obj->proxy;
113 delete obj;
116 bool NPObjectProxy::OnMessageReceived(const IPC::Message& msg) {
117 NOTREACHED();
118 return false;
121 void NPObjectProxy::OnChannelError() {
122 // Release our ref count of the plugin channel object, as it addrefs the
123 // process.
124 channel_ = NULL;
127 bool NPObjectProxy::NPHasMethod(NPObject *obj,
128 NPIdentifier name) {
129 if (obj == NULL)
130 return false;
132 bool result = false;
133 NPObjectProxy* proxy = GetProxy(obj);
135 if (!proxy) {
136 return obj->_class->hasMethod(obj, name);
139 NPIdentifier_Param name_param;
140 CreateNPIdentifierParam(name, &name_param);
142 proxy->Send(new NPObjectMsg_HasMethod(proxy->route_id(), name_param,
143 &result));
144 return result;
147 bool NPObjectProxy::NPInvoke(NPObject *obj,
148 NPIdentifier name,
149 const NPVariant *args,
150 uint32_t arg_count,
151 NPVariant *result) {
152 return NPInvokePrivate(0, obj, false, name, args, arg_count, result);
155 bool NPObjectProxy::NPInvokeDefault(NPObject *npobj,
156 const NPVariant *args,
157 uint32_t arg_count,
158 NPVariant *result) {
159 return NPInvokePrivate(0, npobj, true, 0, args, arg_count, result);
162 bool NPObjectProxy::NPInvokePrivate(NPP npp,
163 NPObject *obj,
164 bool is_default,
165 NPIdentifier name,
166 const NPVariant *args,
167 uint32_t arg_count,
168 NPVariant *np_result) {
169 if (obj == NULL)
170 return false;
172 NPObjectProxy* proxy = GetProxy(obj);
173 if (!proxy) {
174 if (is_default) {
175 return obj->_class->invokeDefault(obj, args, arg_count, np_result);
176 } else {
177 return obj->_class->invoke(obj, name, args, arg_count, np_result);
181 bool result = false;
182 int render_view_id = proxy->render_view_id_;
183 NPIdentifier_Param name_param;
184 if (is_default) {
185 // The data won't actually get used, but set it so we don't send random
186 // data.
187 name_param.identifier = NULL;
188 } else {
189 CreateNPIdentifierParam(name, &name_param);
192 // Note: This instance can get destroyed in the context of
193 // Send so addref the channel in this scope.
194 scoped_refptr<NPChannelBase> channel_copy = proxy->channel_;
195 std::vector<NPVariant_Param> args_param;
196 for (unsigned int i = 0; i < arg_count; ++i) {
197 NPVariant_Param param;
198 CreateNPVariantParam(args[i],
199 channel_copy.get(),
200 &param,
201 false,
202 render_view_id,
203 proxy->page_url_);
204 args_param.push_back(param);
207 NPVariant_Param param_result;
208 NPObjectMsg_Invoke* msg = new NPObjectMsg_Invoke(
209 proxy->route_id_, is_default, name_param, args_param, &param_result,
210 &result);
212 // If we're in the plugin process and this invoke leads to a dialog box, the
213 // plugin will hang the window hierarchy unless we pump the window message
214 // queue while waiting for a reply. We need to do this to simulate what
215 // happens when everything runs in-process (while calling MessageBox window
216 // messages are pumped).
217 if (IsPluginProcess() && proxy->channel()) {
218 msg->set_pump_messages_event(
219 proxy->channel()->GetModalDialogEvent(render_view_id));
222 GURL page_url = proxy->page_url_;
223 proxy->Send(msg);
225 // Send may delete proxy.
226 proxy = NULL;
228 if (!result)
229 return false;
231 CreateNPVariant(
232 param_result, channel_copy.get(), np_result, render_view_id, page_url);
233 return true;
236 bool NPObjectProxy::NPHasProperty(NPObject *obj,
237 NPIdentifier name) {
238 if (obj == NULL)
239 return false;
241 bool result = false;
242 NPObjectProxy* proxy = GetProxy(obj);
243 if (!proxy) {
244 return obj->_class->hasProperty(obj, name);
247 NPIdentifier_Param name_param;
248 CreateNPIdentifierParam(name, &name_param);
250 NPVariant_Param param;
251 proxy->Send(new NPObjectMsg_HasProperty(
252 proxy->route_id(), name_param, &result));
254 // Send may delete proxy.
255 proxy = NULL;
257 return result;
260 bool NPObjectProxy::NPGetProperty(NPObject *obj,
261 NPIdentifier name,
262 NPVariant *np_result) {
263 // Please refer to http://code.google.com/p/chromium/issues/detail?id=2556,
264 // which was a crash in the XStandard plugin during plugin shutdown. The
265 // crash occured because the plugin requests the plugin script object,
266 // which fails. The plugin does not check the result of the operation and
267 // invokes NPN_GetProperty on a NULL object which lead to the crash. If
268 // we observe similar crashes in other methods in the future, these null
269 // checks may have to be replicated in the other methods in this class.
270 if (obj == NULL)
271 return false;
273 NPObjectProxy* proxy = GetProxy(obj);
274 if (!proxy) {
275 return obj->_class->getProperty(obj, name, np_result);
278 bool result = false;
279 int render_view_id = proxy->render_view_id_;
280 NPIdentifier_Param name_param;
281 CreateNPIdentifierParam(name, &name_param);
283 NPVariant_Param param;
284 scoped_refptr<NPChannelBase> channel(proxy->channel_);
286 GURL page_url = proxy->page_url_;
287 proxy->Send(new NPObjectMsg_GetProperty(
288 proxy->route_id(), name_param, &param, &result));
289 // Send may delete proxy.
290 proxy = NULL;
291 if (!result)
292 return false;
294 CreateNPVariant(
295 param, channel.get(), np_result, render_view_id, page_url);
297 return true;
300 bool NPObjectProxy::NPSetProperty(NPObject *obj,
301 NPIdentifier name,
302 const NPVariant *value) {
303 if (obj == NULL)
304 return false;
306 NPObjectProxy* proxy = GetProxy(obj);
307 if (!proxy) {
308 return obj->_class->setProperty(obj, name, value);
311 bool result = false;
312 int render_view_id = proxy->render_view_id_;
313 NPIdentifier_Param name_param;
314 CreateNPIdentifierParam(name, &name_param);
316 NPVariant_Param value_param;
317 CreateNPVariantParam(
318 *value, proxy->channel(), &value_param, false, render_view_id,
319 proxy->page_url_);
321 proxy->Send(new NPObjectMsg_SetProperty(
322 proxy->route_id(), name_param, value_param, &result));
323 // Send may delete proxy.
324 proxy = NULL;
326 return result;
329 bool NPObjectProxy::NPRemoveProperty(NPObject *obj,
330 NPIdentifier name) {
331 if (obj == NULL)
332 return false;
334 bool result = false;
335 NPObjectProxy* proxy = GetProxy(obj);
336 if (!proxy) {
337 return obj->_class->removeProperty(obj, name);
340 NPIdentifier_Param name_param;
341 CreateNPIdentifierParam(name, &name_param);
343 NPVariant_Param param;
344 proxy->Send(new NPObjectMsg_RemoveProperty(
345 proxy->route_id(), name_param, &result));
346 // Send may delete proxy.
347 proxy = NULL;
349 return result;
352 void NPObjectProxy::NPPInvalidate(NPObject *obj) {
353 if (obj == NULL)
354 return;
356 NPObjectProxy* proxy = GetProxy(obj);
357 if (!proxy) {
358 obj->_class->invalidate(obj);
359 return;
362 proxy->Send(new NPObjectMsg_Invalidate(proxy->route_id()));
363 // Send may delete proxy.
364 proxy = NULL;
367 bool NPObjectProxy::NPNEnumerate(NPObject *obj,
368 NPIdentifier **value,
369 uint32_t *count) {
370 if (obj == NULL)
371 return false;
373 bool result = false;
374 NPObjectProxy* proxy = GetProxy(obj);
375 if (!proxy) {
376 if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM) {
377 return obj->_class->enumerate(obj, value, count);
378 } else {
379 return false;
383 std::vector<NPIdentifier_Param> value_param;
384 proxy->Send(new NPObjectMsg_Enumeration(
385 proxy->route_id(), &value_param, &result));
386 // Send may delete proxy.
387 proxy = NULL;
389 if (!result)
390 return false;
392 *count = static_cast<unsigned int>(value_param.size());
393 *value = static_cast<NPIdentifier *>(malloc(sizeof(NPIdentifier) * *count));
394 for (unsigned int i = 0; i < *count; ++i)
395 (*value)[i] = CreateNPIdentifier(value_param[i]);
397 return true;
400 bool NPObjectProxy::NPNConstruct(NPObject *obj,
401 const NPVariant *args,
402 uint32_t arg_count,
403 NPVariant *np_result) {
404 if (obj == NULL)
405 return false;
407 NPObjectProxy* proxy = GetProxy(obj);
408 if (!proxy) {
409 if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR) {
410 return obj->_class->construct(obj, args, arg_count, np_result);
411 } else {
412 return false;
416 bool result = false;
417 int render_view_id = proxy->render_view_id_;
419 // Note: This instance can get destroyed in the context of
420 // Send so addref the channel in this scope.
421 scoped_refptr<NPChannelBase> channel_copy = proxy->channel_;
422 std::vector<NPVariant_Param> args_param;
423 for (unsigned int i = 0; i < arg_count; ++i) {
424 NPVariant_Param param;
425 CreateNPVariantParam(args[i],
426 channel_copy.get(),
427 &param,
428 false,
429 render_view_id,
430 proxy->page_url_);
431 args_param.push_back(param);
434 NPVariant_Param param_result;
435 NPObjectMsg_Construct* msg = new NPObjectMsg_Construct(
436 proxy->route_id_, args_param, &param_result, &result);
438 // See comment in NPObjectProxy::NPInvokePrivate.
439 if (IsPluginProcess() && proxy->channel()) {
440 msg->set_pump_messages_event(
441 proxy->channel()->GetModalDialogEvent(proxy->render_view_id_));
444 GURL page_url = proxy->page_url_;
445 proxy->Send(msg);
447 // Send may delete proxy.
448 proxy = NULL;
450 if (!result)
451 return false;
453 CreateNPVariant(
454 param_result, channel_copy.get(), np_result, render_view_id, page_url);
455 return true;
458 bool NPObjectProxy::NPNEvaluate(NPP npp,
459 NPObject *obj,
460 NPString *script,
461 NPVariant *result_var) {
462 NPObjectProxy* proxy = GetProxy(obj);
463 if (!proxy) {
464 return false;
467 bool result = false;
468 int render_view_id = proxy->render_view_id_;
469 bool popups_allowed = false;
471 #if defined(ENABLE_PLUGINS)
472 if (npp) {
473 PluginInstance* plugin_instance =
474 reinterpret_cast<PluginInstance*>(npp->ndata);
475 if (plugin_instance)
476 popups_allowed = plugin_instance->popups_allowed();
478 #endif
480 NPVariant_Param result_param;
481 std::string script_str = std::string(
482 script->UTF8Characters, script->UTF8Length);
484 NPObjectMsg_Evaluate* msg = new NPObjectMsg_Evaluate(proxy->route_id(),
485 script_str,
486 popups_allowed,
487 &result_param,
488 &result);
490 // See comment in NPObjectProxy::NPInvokePrivate.
491 if (IsPluginProcess() && proxy->channel()) {
492 msg->set_pump_messages_event(
493 proxy->channel()->GetModalDialogEvent(render_view_id));
495 scoped_refptr<NPChannelBase> channel(proxy->channel_);
497 GURL page_url = proxy->page_url_;
498 proxy->Send(msg);
499 // Send may delete proxy.
500 proxy = NULL;
501 if (!result)
502 return false;
504 CreateNPVariant(
505 result_param, channel.get(), result_var, render_view_id, page_url);
506 return true;
509 } // namespace content