[content shell] hook up testRunner.dumpEditingCallbacks
[chromium-blink-merge.git] / content / common / npobject_proxy.cc
blob4203b132aa46ad3c576c45f11344b5111bddfe0f
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;
17 namespace content {
19 struct NPObjectWrapper {
20 NPObject object;
21 NPObjectProxy* proxy;
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;
49 return proxy;
52 NPObject* NPObjectProxy::GetUnderlyingNPObject() {
53 return NULL;
56 IPC::Listener* NPObjectProxy::GetChannelListener() {
57 return static_cast<IPC::Listener*>(this);
60 NPObjectProxy::NPObjectProxy(
61 NPChannelBase* channel,
62 int route_id,
63 int render_view_id,
64 const GURL& page_url)
65 : channel_(channel),
66 route_id_(route_id),
67 render_view_id_(render_view_id),
68 page_url_(page_url) {
69 channel_->AddRoute(route_id, this, this);
72 NPObjectProxy::~NPObjectProxy() {
73 if (channel_.get()) {
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
78 // NPObjects.
79 channel_->RemoveMappingForNPObjectProxy(route_id_);
80 channel_->RemoveRoute(route_id_);
81 Send(new NPObjectMsg_Release(route_id_));
85 NPObject* NPObjectProxy::Create(NPChannelBase* channel,
86 int route_id,
87 int render_view_id,
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) {
97 if (channel_.get())
98 return channel_->Send(msg);
100 delete msg;
101 return false;
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);
110 delete obj->proxy;
111 delete obj;
114 bool NPObjectProxy::OnMessageReceived(const IPC::Message& msg) {
115 NOTREACHED();
116 return false;
119 void NPObjectProxy::OnChannelError() {
120 // Release our ref count of the plugin channel object, as it addrefs the
121 // process.
122 channel_ = NULL;
125 bool NPObjectProxy::NPHasMethod(NPObject *obj,
126 NPIdentifier name) {
127 if (obj == NULL)
128 return false;
130 bool result = false;
131 NPObjectProxy* proxy = GetProxy(obj);
133 if (!proxy) {
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,
141 &result));
142 return result;
145 bool NPObjectProxy::NPInvoke(NPObject *obj,
146 NPIdentifier name,
147 const NPVariant *args,
148 uint32_t arg_count,
149 NPVariant *result) {
150 return NPInvokePrivate(0, obj, false, name, args, arg_count, result);
153 bool NPObjectProxy::NPInvokeDefault(NPObject *npobj,
154 const NPVariant *args,
155 uint32_t arg_count,
156 NPVariant *result) {
157 return NPInvokePrivate(0, npobj, true, 0, args, arg_count, result);
160 bool NPObjectProxy::NPInvokePrivate(NPP npp,
161 NPObject *obj,
162 bool is_default,
163 NPIdentifier name,
164 const NPVariant *args,
165 uint32_t arg_count,
166 NPVariant *np_result) {
167 if (obj == NULL)
168 return false;
170 NPObjectProxy* proxy = GetProxy(obj);
171 if (!proxy) {
172 if (is_default) {
173 return obj->_class->invokeDefault(obj, args, arg_count, np_result);
174 } else {
175 return obj->_class->invoke(obj, name, args, arg_count, np_result);
179 bool result = false;
180 int render_view_id = proxy->render_view_id_;
181 NPIdentifier_Param name_param;
182 if (is_default) {
183 // The data won't actually get used, but set it so we don't send random
184 // data.
185 name_param.identifier = NULL;
186 } else {
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, &param, false, render_view_id,
198 proxy->page_url_);
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, &param_result,
205 &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_;
218 proxy->Send(msg);
220 // Send may delete proxy.
221 proxy = NULL;
223 if (!result)
224 return false;
226 CreateNPVariant(
227 param_result, channel_copy, np_result, render_view_id, page_url);
228 return true;
231 bool NPObjectProxy::NPHasProperty(NPObject *obj,
232 NPIdentifier name) {
233 if (obj == NULL)
234 return false;
236 bool result = false;
237 NPObjectProxy* proxy = GetProxy(obj);
238 if (!proxy) {
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.
250 proxy = NULL;
252 return result;
255 bool NPObjectProxy::NPGetProperty(NPObject *obj,
256 NPIdentifier name,
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.
265 if (obj == NULL)
266 return false;
268 NPObjectProxy* proxy = GetProxy(obj);
269 if (!proxy) {
270 return obj->_class->getProperty(obj, name, np_result);
273 bool result = false;
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, &param, &result));
284 // Send may delete proxy.
285 proxy = NULL;
286 if (!result)
287 return false;
289 CreateNPVariant(
290 param, channel.get(), np_result, render_view_id, page_url);
292 return true;
295 bool NPObjectProxy::NPSetProperty(NPObject *obj,
296 NPIdentifier name,
297 const NPVariant *value) {
298 if (obj == NULL)
299 return false;
301 NPObjectProxy* proxy = GetProxy(obj);
302 if (!proxy) {
303 return obj->_class->setProperty(obj, name, value);
306 bool result = false;
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,
314 proxy->page_url_);
316 proxy->Send(new NPObjectMsg_SetProperty(
317 proxy->route_id(), name_param, value_param, &result));
318 // Send may delete proxy.
319 proxy = NULL;
321 return result;
324 bool NPObjectProxy::NPRemoveProperty(NPObject *obj,
325 NPIdentifier name) {
326 if (obj == NULL)
327 return false;
329 bool result = false;
330 NPObjectProxy* proxy = GetProxy(obj);
331 if (!proxy) {
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.
342 proxy = NULL;
344 return result;
347 void NPObjectProxy::NPPInvalidate(NPObject *obj) {
348 if (obj == NULL)
349 return;
351 NPObjectProxy* proxy = GetProxy(obj);
352 if (!proxy) {
353 obj->_class->invalidate(obj);
354 return;
357 proxy->Send(new NPObjectMsg_Invalidate(proxy->route_id()));
358 // Send may delete proxy.
359 proxy = NULL;
362 bool NPObjectProxy::NPNEnumerate(NPObject *obj,
363 NPIdentifier **value,
364 uint32_t *count) {
365 if (obj == NULL)
366 return false;
368 bool result = false;
369 NPObjectProxy* proxy = GetProxy(obj);
370 if (!proxy) {
371 if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM) {
372 return obj->_class->enumerate(obj, value, count);
373 } else {
374 return false;
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.
382 proxy = NULL;
384 if (!result)
385 return false;
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]);
394 return true;
397 bool NPObjectProxy::NPNConstruct(NPObject *obj,
398 const NPVariant *args,
399 uint32_t arg_count,
400 NPVariant *np_result) {
401 if (obj == NULL)
402 return false;
404 NPObjectProxy* proxy = GetProxy(obj);
405 if (!proxy) {
406 if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR) {
407 return obj->_class->construct(obj, args, arg_count, np_result);
408 } else {
409 return false;
413 bool result = false;
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, &param, false, render_view_id,
424 proxy->page_url_);
425 args_param.push_back(param);
428 NPVariant_Param param_result;
429 NPObjectMsg_Construct* msg = new NPObjectMsg_Construct(
430 proxy->route_id_, args_param, &param_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_;
439 proxy->Send(msg);
441 // Send may delete proxy.
442 proxy = NULL;
444 if (!result)
445 return false;
447 CreateNPVariant(
448 param_result, channel_copy, np_result, render_view_id, page_url);
449 return true;
452 bool NPObjectProxy::NPNEvaluate(NPP npp,
453 NPObject *obj,
454 NPString *script,
455 NPVariant *result_var) {
456 NPObjectProxy* proxy = GetProxy(obj);
457 if (!proxy) {
458 return false;
461 bool result = false;
462 int render_view_id = proxy->render_view_id_;
463 bool popups_allowed = false;
465 if (npp) {
466 webkit::npapi::PluginInstance* plugin_instance =
467 reinterpret_cast<webkit::npapi::PluginInstance*>(npp->ndata);
468 if (plugin_instance)
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(),
477 script_str,
478 popups_allowed,
479 &result_param,
480 &result);
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_;
490 proxy->Send(msg);
491 // Send may delete proxy.
492 proxy = NULL;
493 if (!result)
494 return false;
496 CreateNPVariant(
497 result_param, channel.get(), result_var, render_view_id, page_url);
498 return true;
501 } // namespace content