OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/common/npobject_stub.h" | |
6 | |
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" | |
16 | |
17 #if defined(OS_WIN) | |
18 #include "base/command_line.h" | |
19 #include "webkit/plugins/npapi/plugin_constants_win.h" | |
20 #endif | |
21 | |
22 using WebKit::WebBindings; | |
23 | |
24 namespace content { | |
25 | |
26 NPObjectStub::NPObjectStub( | |
27 NPObject* npobject, | |
28 NPChannelBase* channel, | |
29 int route_id, | |
30 int render_view_id, | |
31 const GURL& page_url) | |
32 : npobject_(npobject), | |
33 channel_(channel), | |
34 route_id_(route_id), | |
35 render_view_id_(render_view_id), | |
36 page_url_(page_url) { | |
37 channel_->AddMappingForNPObjectStub(route_id, npobject); | |
38 channel_->AddRoute(route_id, this, this); | |
39 | |
40 // We retain the object just as PluginHost does if everything was in-process. | |
41 WebBindings::retainObject(npobject_); | |
42 } | |
43 | |
44 NPObjectStub::~NPObjectStub() { | |
45 channel_->RemoveRoute(route_id_); | |
46 DCHECK(!npobject_); | |
47 } | |
48 | |
49 void NPObjectStub::DeleteSoon() { | |
50 if (npobject_) { | |
51 channel_->RemoveMappingForNPObjectStub(route_id_, npobject_); | |
52 | |
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_; | |
57 npobject_ = NULL; | |
58 | |
59 WebBindings::releaseObject(npobject); | |
60 | |
61 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
62 } | |
63 } | |
64 | |
65 bool NPObjectStub::Send(IPC::Message* msg) { | |
66 return channel_->Send(msg); | |
67 } | |
68 | |
69 NPObject* NPObjectStub::GetUnderlyingNPObject() { | |
70 return npobject_; | |
71 } | |
72 | |
73 IPC::Listener* NPObjectStub::GetChannelListener() { | |
74 return static_cast<IPC::Listener*>(this); | |
75 } | |
76 | |
77 bool NPObjectStub::OnMessageReceived(const IPC::Message& msg) { | |
78 GetContentClient()->SetActiveURL(page_url_); | |
79 if (!npobject_) { | |
80 if (msg.is_sync()) { | |
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(); | |
85 Send(reply); | |
86 } | |
87 | |
88 return true; | |
89 } | |
90 | |
91 bool handled = true; | |
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() | |
106 DCHECK(handled); | |
107 return handled; | |
108 } | |
109 | |
110 void NPObjectStub::OnChannelError() { | |
111 DeleteSoon(); | |
112 } | |
113 | |
114 void NPObjectStub::OnRelease(IPC::Message* reply_msg) { | |
115 Send(reply_msg); | |
116 DeleteSoon(); | |
117 } | |
118 | |
119 void NPObjectStub::OnHasMethod(const NPIdentifier_Param& name, | |
120 bool* result) { | |
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); | |
129 } else { | |
130 *result = false; | |
131 } | |
132 } else { | |
133 *result = WebBindings::hasMethod(0, npobject_, id); | |
134 } | |
135 } | |
136 | |
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; | |
144 | |
145 VOID_TO_NPVARIANT(result_var); | |
146 result_param.type = NPVARIANT_PARAM_VOID; | |
147 | |
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, | |
154 return_value); | |
155 channel_->Send(reply_msg); | |
156 delete[] args_var; | |
157 return; | |
158 } | |
159 } | |
160 | |
161 if (is_default) { | |
162 if (IsPluginProcess()) { | |
163 if (npobject_->_class->invokeDefault) { | |
164 return_value = npobject_->_class->invokeDefault( | |
165 npobject_, args_var, arg_count, &result_var); | |
166 } else { | |
167 return_value = false; | |
168 } | |
169 } else { | |
170 return_value = WebBindings::invokeDefault( | |
171 0, npobject_, args_var, arg_count, &result_var); | |
172 } | |
173 } else { | |
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); | |
179 } else { | |
180 return_value = false; | |
181 } | |
182 } else { | |
183 return_value = WebBindings::invoke( | |
184 0, npobject_, id, args_var, arg_count, &result_var); | |
185 } | |
186 } | |
187 | |
188 for (int i = 0; i < arg_count; ++i) | |
189 WebBindings::releaseVariantValue(&(args_var[i])); | |
190 | |
191 delete[] args_var; | |
192 | |
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); | |
197 } | |
198 | |
199 void NPObjectStub::OnHasProperty(const NPIdentifier_Param& name, | |
200 bool* result) { | |
201 NPIdentifier id = CreateNPIdentifier(name); | |
202 if (IsPluginProcess()) { | |
203 if (npobject_->_class->hasProperty) { | |
204 *result = npobject_->_class->hasProperty(npobject_, id); | |
205 } else { | |
206 *result = false; | |
207 } | |
208 } else { | |
209 *result = WebBindings::hasProperty(0, npobject_, id); | |
210 } | |
211 } | |
212 | |
213 void NPObjectStub::OnGetProperty(const NPIdentifier_Param& name, | |
214 NPVariant_Param* property, | |
215 bool* result) { | |
216 NPVariant result_var; | |
217 VOID_TO_NPVARIANT(result_var); | |
218 NPIdentifier id = CreateNPIdentifier(name); | |
219 | |
220 if (IsPluginProcess()) { | |
221 if (npobject_->_class->getProperty) { | |
222 *result = npobject_->_class->getProperty(npobject_, id, &result_var); | |
223 } else { | |
224 *result = false; | |
225 } | |
226 } else { | |
227 *result = WebBindings::getProperty(0, npobject_, id, &result_var); | |
228 } | |
229 | |
230 CreateNPVariantParam( | |
231 result_var, channel_, property, true, render_view_id_, page_url_); | |
232 } | |
233 | |
234 void NPObjectStub::OnSetProperty(const NPIdentifier_Param& name, | |
235 const NPVariant_Param& property, | |
236 IPC::Message* reply_msg) { | |
237 bool result = false; | |
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); | |
244 return; | |
245 } | |
246 | |
247 if (IsPluginProcess()) { | |
248 if (npobject_->_class->setProperty) { | |
249 #if defined(OS_WIN) | |
250 static base::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); | |
261 Send(reply_msg); | |
262 reply_msg = NULL; | |
263 } | |
264 #endif | |
265 result = npobject_->_class->setProperty(npobject_, id, &property_var); | |
266 } else { | |
267 result = false; | |
268 } | |
269 } else { | |
270 result = WebBindings::setProperty(0, npobject_, id, &property_var); | |
271 } | |
272 | |
273 WebBindings::releaseVariantValue(&property_var); | |
274 | |
275 if (reply_msg) { | |
276 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result); | |
277 Send(reply_msg); | |
278 } | |
279 } | |
280 | |
281 void NPObjectStub::OnRemoveProperty(const NPIdentifier_Param& name, | |
282 bool* result) { | |
283 NPIdentifier id = CreateNPIdentifier(name); | |
284 if (IsPluginProcess()) { | |
285 if (npobject_->_class->removeProperty) { | |
286 *result = npobject_->_class->removeProperty(npobject_, id); | |
287 } else { | |
288 *result = false; | |
289 } | |
290 } else { | |
291 *result = WebBindings::removeProperty(0, npobject_, id); | |
292 } | |
293 } | |
294 | |
295 void NPObjectStub::OnInvalidate() { | |
296 if (!IsPluginProcess()) { | |
297 NOTREACHED() << "Should only be called on NPObjects in the plugin"; | |
298 return; | |
299 } | |
300 | |
301 if (!npobject_->_class->invalidate) | |
302 return; | |
303 | |
304 npobject_->_class->invalidate(npobject_); | |
305 } | |
306 | |
307 void NPObjectStub::OnEnumeration(std::vector<NPIdentifier_Param>* value, | |
308 bool* result) { | |
309 NPIdentifier* value_np = NULL; | |
310 unsigned int count = 0; | |
311 if (!IsPluginProcess()) { | |
312 *result = WebBindings::enumerate(0, npobject_, &value_np, &count); | |
313 } else { | |
314 if (npobject_->_class->structVersion < NP_CLASS_STRUCT_VERSION_ENUM || | |
315 !npobject_->_class->enumerate) { | |
316 *result = false; | |
317 return; | |
318 } | |
319 | |
320 *result = npobject_->_class->enumerate(npobject_, &value_np, &count); | |
321 } | |
322 | |
323 if (!*result) | |
324 return; | |
325 | |
326 for (unsigned int i = 0; i < count; ++i) { | |
327 NPIdentifier_Param param; | |
328 CreateNPIdentifierParam(value_np[i], ¶m); | |
329 value->push_back(param); | |
330 } | |
331 | |
332 webkit::npapi::PluginHost::Singleton()->host_functions()->memfree(value_np); | |
333 } | |
334 | |
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; | |
340 | |
341 VOID_TO_NPVARIANT(result_var); | |
342 | |
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, | |
349 return_value); | |
350 channel_->Send(reply_msg); | |
351 delete[] args_var; | |
352 return; | |
353 } | |
354 } | |
355 | |
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); | |
361 } else { | |
362 return_value = false; | |
363 } | |
364 } else { | |
365 return_value = WebBindings::construct( | |
366 0, npobject_, args_var, arg_count, &result_var); | |
367 } | |
368 | |
369 for (int i = 0; i < arg_count; ++i) | |
370 WebBindings::releaseVariantValue(&(args_var[i])); | |
371 | |
372 delete[] args_var; | |
373 | |
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); | |
378 } | |
379 | |
380 void NPObjectStub::OnEvaluate(const std::string& script, | |
381 bool popups_allowed, | |
382 IPC::Message* reply_msg) { | |
383 if (IsPluginProcess()) { | |
384 NOTREACHED() << "Should only be called on NPObjects in the renderer"; | |
385 return; | |
386 } | |
387 | |
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()); | |
392 | |
393 bool return_value = WebBindings::evaluateHelper(0, popups_allowed, npobject_, | |
394 &script_string, &result_var); | |
395 | |
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); | |
401 } | |
402 | |
403 } // namespace content | |
OLD | NEW |