blob: fa48d8778dfcea88bb1ca3da089fc2c1d6454011 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
initial.commit09911bf2008-07-26 23:55:294
5#include "chrome/plugin/npobject_proxy.h"
6
[email protected]1c4947f2009-01-15 22:25:117#include "base/waitable_event.h"
initial.commit09911bf2008-07-26 23:55:298#include "chrome/common/plugin_messages.h"
initial.commit09911bf2008-07-26 23:55:299#include "chrome/plugin/npobject_util.h"
10#include "chrome/plugin/plugin_channel_base.h"
11#include "webkit/glue/webkit_glue.h"
12#include "webkit/glue/plugins/plugin_instance.h"
13
14
15struct NPObjectWrapper {
16 NPObject object;
17 NPObjectProxy* proxy;
18};
19
20NPClass NPObjectProxy::npclass_proxy_ = {
21 2,
22 NPObjectProxy::NPAllocate,
23 NPObjectProxy::NPDeallocate,
24 NPObjectProxy::NPPInvalidate,
25 NPObjectProxy::NPHasMethod,
26 NPObjectProxy::NPInvoke,
27 NPObjectProxy::NPInvokeDefault,
28 NPObjectProxy::NPHasProperty,
29 NPObjectProxy::NPGetProperty,
30 NPObjectProxy::NPSetProperty,
31 NPObjectProxy::NPRemoveProperty,
32 NPObjectProxy::NPNEnumerate
33};
34
35NPObjectProxy* NPObjectProxy::GetProxy(NPObject* object) {
36 NPObjectProxy* proxy = NULL;
37
38 // Wrapper exists only for NPObjects that we had created.
39 if (&npclass_proxy_ == object->_class) {
40 NPObjectWrapper* wrapper = reinterpret_cast<NPObjectWrapper*>(object);
41 proxy = wrapper->proxy;
42 }
43
44 return proxy;
45}
46
47NPObjectProxy::NPObjectProxy(
48 PluginChannelBase* channel,
49 int route_id,
[email protected]829c2842009-04-01 01:48:5250 intptr_t npobject_ptr,
[email protected]1c4947f2009-01-15 22:25:1151 base::WaitableEvent* modal_dialog_event)
initial.commit09911bf2008-07-26 23:55:2952 : channel_(channel),
53 route_id_(route_id),
54 npobject_ptr_(npobject_ptr),
55 modal_dialog_event_(modal_dialog_event) {
56 channel_->AddRoute(route_id, this, true);
57}
58
59NPObjectProxy::~NPObjectProxy() {
60 if (channel_.get()) {
61 Send(new NPObjectMsg_Release(route_id_));
62 if (channel_.get())
63 channel_->RemoveRoute(route_id_);
64 }
65}
66
67NPObject* NPObjectProxy::Create(PluginChannelBase* channel,
68 int route_id,
[email protected]829c2842009-04-01 01:48:5269 intptr_t npobject_ptr,
[email protected]1c4947f2009-01-15 22:25:1170 base::WaitableEvent* modal_dialog_event) {
initial.commit09911bf2008-07-26 23:55:2971 NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(
72 NPN_CreateObject(0, &npclass_proxy_));
73 obj->proxy = new NPObjectProxy(
74 channel, route_id, npobject_ptr, modal_dialog_event);
75
76 return reinterpret_cast<NPObject*>(obj);
77}
78
79bool NPObjectProxy::Send(IPC::Message* msg) {
80 if (channel_.get())
81 return channel_->Send(msg);
82
83 delete msg;
84 return false;
85}
86
87NPObject* NPObjectProxy::NPAllocate(NPP, NPClass*) {
88 return reinterpret_cast<NPObject*>(new NPObjectWrapper);
89}
90
91void NPObjectProxy::NPDeallocate(NPObject* npObj) {
92 NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(npObj);
93 delete obj->proxy;
94 delete obj;
95}
96
97void NPObjectProxy::OnMessageReceived(const IPC::Message& msg) {
98 NOTREACHED();
99}
100
101void NPObjectProxy::OnChannelError() {
102 // Release our ref count of the plugin channel object, as it addrefs the
103 // process.
104 channel_ = NULL;
105}
106
107bool NPObjectProxy::NPHasMethod(NPObject *obj,
108 NPIdentifier name) {
109 bool result = false;
110 NPObjectProxy* proxy = GetProxy(obj);
111
112 if (!proxy) {
113 return obj->_class->hasMethod(obj, name);
114 }
115
116 NPIdentifier_Param name_param;
117 CreateNPIdentifierParam(name, &name_param);
118
[email protected]f09c7182009-03-10 12:54:04119 proxy->Send(new NPObjectMsg_HasMethod(proxy->route_id(), name_param,
120 &result));
initial.commit09911bf2008-07-26 23:55:29121 return result;
122}
123
124bool NPObjectProxy::NPInvoke(NPObject *obj,
125 NPIdentifier name,
126 const NPVariant *args,
127 uint32_t arg_count,
128 NPVariant *result) {
129 return NPInvokePrivate(0, obj, false, name, args, arg_count, result);
130}
131
132bool NPObjectProxy::NPInvokeDefault(NPObject *npobj,
133 const NPVariant *args,
134 uint32_t arg_count,
135 NPVariant *result) {
136 return NPInvokePrivate(0, npobj, true, 0, args, arg_count, result);
137}
138
139bool NPObjectProxy::NPInvokePrivate(NPP npp,
140 NPObject *obj,
141 bool is_default,
142 NPIdentifier name,
143 const NPVariant *args,
144 uint32_t arg_count,
145 NPVariant *np_result) {
146 NPObjectProxy* proxy = GetProxy(obj);
147 if (!proxy) {
148 return obj->_class->invoke(obj, name, args, arg_count, np_result);
149 }
150
151 bool result = false;
152 NPIdentifier_Param name_param;
153 if (is_default) {
[email protected]f09c7182009-03-10 12:54:04154 // The data won't actually get used, but set it so we don't send random
155 // data.
[email protected]6408eba2008-08-06 18:44:29156 name_param.identifier = NULL;
initial.commit09911bf2008-07-26 23:55:29157 } else {
158 CreateNPIdentifierParam(name, &name_param);
159 }
160
161 // Note: This instance can get destroyed in the context of
162 // Send so addref the channel in this scope.
163 scoped_refptr<PluginChannelBase> channel_copy = proxy->channel_;
164 std::vector<NPVariant_Param> args_param;
165 for (unsigned int i = 0; i < arg_count; ++i) {
166 NPVariant_Param param;
[email protected]b62de6b22009-02-21 08:10:29167 CreateNPVariantParam(
168 args[i], channel_copy, &param, false, proxy->modal_dialog_event_);
initial.commit09911bf2008-07-26 23:55:29169 args_param.push_back(param);
170 }
171
172 NPVariant_Param param_result;
173 NPObjectMsg_Invoke* msg = new NPObjectMsg_Invoke(
174 proxy->route_id_, is_default, name_param, args_param, &param_result,
175 &result);
176
177 // If we're in the plugin process and this invoke leads to a dialog box, the
178 // plugin will hang the window hierarchy unless we pump the window message
179 // queue while waiting for a reply. We need to do this to simulate what
180 // happens when everything runs in-process (while calling MessageBox window
181 // messages are pumped).
182 msg->set_pump_messages_event(proxy->modal_dialog_event_);
183
[email protected]1c4947f2009-01-15 22:25:11184 base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
[email protected]25e7d392008-12-23 22:55:06185
initial.commit09911bf2008-07-26 23:55:29186 proxy->Send(msg);
187
[email protected]25e7d392008-12-23 22:55:06188 // Send may delete proxy.
189 proxy = NULL;
190
initial.commit09911bf2008-07-26 23:55:29191 if (!result)
192 return false;
193
194 CreateNPVariant(
[email protected]25e7d392008-12-23 22:55:06195 param_result, channel_copy, np_result, modal_dialog_event_handle);
initial.commit09911bf2008-07-26 23:55:29196 return true;
197}
198
199bool NPObjectProxy::NPHasProperty(NPObject *obj,
200 NPIdentifier name) {
201 bool result = false;
202 NPObjectProxy* proxy = GetProxy(obj);
203 if (!proxy) {
204 return obj->_class->hasProperty(obj, name);
205 }
206
207 NPIdentifier_Param name_param;
208 CreateNPIdentifierParam(name, &name_param);
209
210 NPVariant_Param param;
211 proxy->Send(new NPObjectMsg_HasProperty(
212 proxy->route_id(), name_param, &result));
213
[email protected]25e7d392008-12-23 22:55:06214 // Send may delete proxy.
215 proxy = NULL;
216
initial.commit09911bf2008-07-26 23:55:29217 return result;
218}
219
220bool NPObjectProxy::NPGetProperty(NPObject *obj,
221 NPIdentifier name,
222 NPVariant *np_result) {
[email protected]c328da82008-09-20 00:09:09223 // Please refer to http://code.google.com/p/chromium/issues/detail?id=2556,
224 // which was a crash in the XStandard plugin during plugin shutdown. The
225 // crash occured because the plugin requests the plugin script object,
226 // which fails. The plugin does not check the result of the operation and
227 // invokes NPN_GetProperty on a NULL object which lead to the crash. If
228 // we observe similar crashes in other methods in the future, these null
229 // checks may have to be replicated in the other methods in this class.
230 if (obj == NULL)
231 return false;
232
initial.commit09911bf2008-07-26 23:55:29233 bool result = false;
234 NPObjectProxy* proxy = GetProxy(obj);
235 if (!proxy) {
236 return obj->_class->getProperty(obj, name, np_result);
237 }
238
239 NPIdentifier_Param name_param;
240 CreateNPIdentifierParam(name, &name_param);
241
242 NPVariant_Param param;
[email protected]1c4947f2009-01-15 22:25:11243 base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
[email protected]25e7d392008-12-23 22:55:06244 scoped_refptr<PluginChannelBase> channel(proxy->channel_);
initial.commit09911bf2008-07-26 23:55:29245 proxy->Send(new NPObjectMsg_GetProperty(
246 proxy->route_id(), name_param, &param, &result));
[email protected]25e7d392008-12-23 22:55:06247 // Send may delete proxy.
248 proxy = NULL;
initial.commit09911bf2008-07-26 23:55:29249 if (!result)
250 return false;
251
252 CreateNPVariant(
[email protected]25e7d392008-12-23 22:55:06253 param, channel.get(), np_result, modal_dialog_event_handle);
initial.commit09911bf2008-07-26 23:55:29254
255 return true;
256}
257
258bool NPObjectProxy::NPSetProperty(NPObject *obj,
259 NPIdentifier name,
260 const NPVariant *value) {
261 bool result = false;
262 NPObjectProxy* proxy = GetProxy(obj);
263 if (!proxy) {
264 return obj->_class->setProperty(obj, name, value);
265 }
266
267 NPIdentifier_Param name_param;
268 CreateNPIdentifierParam(name, &name_param);
269
270 NPVariant_Param value_param;
[email protected]b62de6b22009-02-21 08:10:29271 CreateNPVariantParam(
272 *value, proxy->channel(), &value_param, false,
273 proxy->modal_dialog_event_);
initial.commit09911bf2008-07-26 23:55:29274
275 proxy->Send(new NPObjectMsg_SetProperty(
276 proxy->route_id(), name_param, value_param, &result));
[email protected]25e7d392008-12-23 22:55:06277 // Send may delete proxy.
278 proxy = NULL;
initial.commit09911bf2008-07-26 23:55:29279
280 return result;
281}
282
283bool NPObjectProxy::NPRemoveProperty(NPObject *obj,
284 NPIdentifier name) {
285 bool result = false;
286 NPObjectProxy* proxy = GetProxy(obj);
287 if (!proxy) {
288 return obj->_class->removeProperty(obj, name);
289 }
290
291 NPIdentifier_Param name_param;
292 CreateNPIdentifierParam(name, &name_param);
293
294 NPVariant_Param param;
295 proxy->Send(new NPObjectMsg_RemoveProperty(
296 proxy->route_id(), name_param, &result));
[email protected]25e7d392008-12-23 22:55:06297 // Send may delete proxy.
298 proxy = NULL;
initial.commit09911bf2008-07-26 23:55:29299
300 return result;
301}
302
303void NPObjectProxy::NPPInvalidate(NPObject *obj) {
initial.commit09911bf2008-07-26 23:55:29304 NPObjectProxy* proxy = GetProxy(obj);
305 if (!proxy) {
[email protected]157e5d22009-04-23 18:43:35306 obj->_class->invalidate(obj);
307 return;
initial.commit09911bf2008-07-26 23:55:29308 }
309
310 proxy->Send(new NPObjectMsg_Invalidate(proxy->route_id()));
[email protected]25e7d392008-12-23 22:55:06311 // Send may delete proxy.
312 proxy = NULL;
initial.commit09911bf2008-07-26 23:55:29313}
314
315bool NPObjectProxy::NPNEnumerate(NPObject *obj,
316 NPIdentifier **value,
317 uint32_t *count) {
318 bool result = false;
319 NPObjectProxy* proxy = GetProxy(obj);
320 if (!proxy) {
321 return obj->_class->enumerate(obj, value, count);
322 }
323
324 std::vector<NPIdentifier_Param> value_param;
325 proxy->Send(new NPObjectMsg_Enumeration(
326 proxy->route_id(), &value_param, &result));
[email protected]25e7d392008-12-23 22:55:06327 // Send may delete proxy.
328 proxy = NULL;
initial.commit09911bf2008-07-26 23:55:29329
330 if (!result)
331 return false;
332
333 *count = static_cast<unsigned int>(value_param.size());
334 *value = static_cast<NPIdentifier *>(
335 NPN_MemAlloc(sizeof(NPIdentifier) * *count));
336 for (unsigned int i = 0; i < *count; ++i)
337 (*value)[i] = CreateNPIdentifier(value_param[i]);
338
339 return true;
340}
341
342bool NPObjectProxy::NPNEvaluate(NPP npp,
343 NPObject *obj,
344 NPString *script,
345 NPVariant *result_var) {
346 bool result = false;
347 NPObjectProxy* proxy = GetProxy(obj);
348 if (!proxy) {
349 return false;
350 }
351
[email protected]35bb1432008-10-09 19:58:15352 bool popups_allowed = false;
353
354 if (npp) {
355 NPAPI::PluginInstance* plugin_instance =
356 reinterpret_cast<NPAPI::PluginInstance*>(npp->ndata);
357 if (plugin_instance)
358 popups_allowed = plugin_instance->popups_allowed();
359 }
360
initial.commit09911bf2008-07-26 23:55:29361 NPVariant_Param result_param;
362 std::string script_str = std::string(
363 script->UTF8Characters, script->UTF8Length);
364
365 NPObjectMsg_Evaluate* msg = new NPObjectMsg_Evaluate(proxy->route_id(),
366 script_str,
[email protected]35bb1432008-10-09 19:58:15367 popups_allowed,
initial.commit09911bf2008-07-26 23:55:29368 &result_param,
369 &result);
370
371 // Please refer to the comments in NPObjectProxy::NPInvokePrivate for
372 // the reasoning behind setting the pump messages event in the sync message.
373 msg->set_pump_messages_event(proxy->modal_dialog_event_);
[email protected]25e7d392008-12-23 22:55:06374 scoped_refptr<PluginChannelBase> channel(proxy->channel_);
[email protected]1c4947f2009-01-15 22:25:11375 base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
initial.commit09911bf2008-07-26 23:55:29376 proxy->Send(msg);
[email protected]25e7d392008-12-23 22:55:06377 // Send may delete proxy.
378 proxy = NULL;
initial.commit09911bf2008-07-26 23:55:29379 if (!result)
380 return false;
381
382 CreateNPVariant(
[email protected]25e7d392008-12-23 22:55:06383 result_param, channel.get(), result_var, modal_dialog_event_handle);
initial.commit09911bf2008-07-26 23:55:29384 return true;
385}
386
387void NPObjectProxy::NPNSetException(NPObject *obj,
388 const NPUTF8 *message) {
389 NPObjectProxy* proxy = GetProxy(obj);
390 if (!proxy) {
391 return;
392 }
393
394 NPVariant_Param result_param;
395 std::string message_str(message);
396
397 proxy->Send(new NPObjectMsg_SetException(proxy->route_id(), message_str));
[email protected]25e7d392008-12-23 22:55:06398 // Send may delete proxy.
399 proxy = NULL;
initial.commit09911bf2008-07-26 23:55:29400}