OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/child/npapi/npobject_stub.h" | |
6 | |
7 #include "build/build_config.h" | |
8 #include "content/child/npapi/np_channel_base.h" | |
9 #include "content/child/npapi/npobject_util.h" | |
10 #include "content/child/plugin_messages.h" | |
11 #include "content/public/common/content_client.h" | |
12 #include "content/public/common/content_switches.h" | |
13 #include "third_party/WebKit/public/web/WebBindings.h" | |
14 #include "third_party/npapi/bindings/npapi.h" | |
15 #include "third_party/npapi/bindings/npruntime.h" | |
16 | |
17 #if defined(OS_WIN) | |
18 #include "base/command_line.h" | |
19 #include "content/common/plugin_constants_win.h" | |
20 #endif | |
21 | |
22 using blink::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(args[i], | |
152 channel_.get(), | |
153 &(args_var[i]), | |
154 render_view_id_, | |
155 page_url_)) { | |
156 NPObjectMsg_Invoke::WriteReplyParams( | |
157 reply_msg, result_param, return_value); | |
158 channel_->Send(reply_msg); | |
159 delete[] args_var; | |
160 return; | |
161 } | |
162 } | |
163 | |
164 if (is_default) { | |
165 if (IsPluginProcess()) { | |
166 if (npobject_->_class->invokeDefault) { | |
167 return_value = npobject_->_class->invokeDefault( | |
168 npobject_, args_var, arg_count, &result_var); | |
169 } else { | |
170 return_value = false; | |
171 } | |
172 } else { | |
173 return_value = WebBindings::invokeDefault( | |
174 0, npobject_, args_var, arg_count, &result_var); | |
175 } | |
176 } else { | |
177 NPIdentifier id = CreateNPIdentifier(method); | |
178 if (IsPluginProcess()) { | |
179 if (npobject_->_class->invoke) { | |
180 return_value = npobject_->_class->invoke( | |
181 npobject_, id, args_var, arg_count, &result_var); | |
182 } else { | |
183 return_value = false; | |
184 } | |
185 } else { | |
186 return_value = WebBindings::invoke( | |
187 0, npobject_, id, args_var, arg_count, &result_var); | |
188 } | |
189 } | |
190 | |
191 for (int i = 0; i < arg_count; ++i) | |
192 WebBindings::releaseVariantValue(&(args_var[i])); | |
193 | |
194 delete[] args_var; | |
195 | |
196 CreateNPVariantParam(result_var, | |
197 channel_.get(), | |
198 &result_param, | |
199 true, | |
200 render_view_id_, | |
201 page_url_); | |
202 NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value); | |
203 channel_->Send(reply_msg); | |
204 } | |
205 | |
206 void NPObjectStub::OnHasProperty(const NPIdentifier_Param& name, | |
207 bool* result) { | |
208 NPIdentifier id = CreateNPIdentifier(name); | |
209 if (IsPluginProcess()) { | |
210 if (npobject_->_class->hasProperty) { | |
211 *result = npobject_->_class->hasProperty(npobject_, id); | |
212 } else { | |
213 *result = false; | |
214 } | |
215 } else { | |
216 *result = WebBindings::hasProperty(0, npobject_, id); | |
217 } | |
218 } | |
219 | |
220 void NPObjectStub::OnGetProperty(const NPIdentifier_Param& name, | |
221 NPVariant_Param* property, | |
222 bool* result) { | |
223 NPVariant result_var; | |
224 VOID_TO_NPVARIANT(result_var); | |
225 NPIdentifier id = CreateNPIdentifier(name); | |
226 | |
227 if (IsPluginProcess()) { | |
228 if (npobject_->_class->getProperty) { | |
229 *result = npobject_->_class->getProperty(npobject_, id, &result_var); | |
230 } else { | |
231 *result = false; | |
232 } | |
233 } else { | |
234 *result = WebBindings::getProperty(0, npobject_, id, &result_var); | |
235 } | |
236 | |
237 CreateNPVariantParam( | |
238 result_var, channel_.get(), property, true, render_view_id_, page_url_); | |
239 } | |
240 | |
241 void NPObjectStub::OnSetProperty(const NPIdentifier_Param& name, | |
242 const NPVariant_Param& property, | |
243 IPC::Message* reply_msg) { | |
244 bool result = false; | |
245 NPIdentifier id = CreateNPIdentifier(name); | |
246 NPVariant property_var; | |
247 if (!CreateNPVariant(property, | |
248 channel_.get(), | |
249 &property_var, | |
250 render_view_id_, | |
251 page_url_)) { | |
252 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result); | |
253 channel_->Send(reply_msg); | |
254 return; | |
255 } | |
256 | |
257 if (IsPluginProcess()) { | |
258 if (npobject_->_class->setProperty) { | |
259 #if defined(OS_WIN) | |
260 static base::FilePath plugin_path = | |
261 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( | |
262 switches::kPluginPath); | |
263 static std::wstring filename = base::ToLowerASCII( | |
264 plugin_path.BaseName().value()); | |
265 static NPIdentifier fullscreen = | |
266 WebBindings::getStringIdentifier("fullScreen"); | |
267 if (filename == kNewWMPPlugin && id == fullscreen) { | |
268 // Workaround for bug 15985, which is if Flash causes WMP to go | |
269 // full screen a deadlock can occur when WMP calls SetFocus. | |
270 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, true); | |
271 Send(reply_msg); | |
272 reply_msg = NULL; | |
273 } | |
274 #endif | |
275 result = npobject_->_class->setProperty(npobject_, id, &property_var); | |
276 } else { | |
277 result = false; | |
278 } | |
279 } else { | |
280 result = WebBindings::setProperty(0, npobject_, id, &property_var); | |
281 } | |
282 | |
283 WebBindings::releaseVariantValue(&property_var); | |
284 | |
285 if (reply_msg) { | |
286 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result); | |
287 Send(reply_msg); | |
288 } | |
289 } | |
290 | |
291 void NPObjectStub::OnRemoveProperty(const NPIdentifier_Param& name, | |
292 bool* result) { | |
293 NPIdentifier id = CreateNPIdentifier(name); | |
294 if (IsPluginProcess()) { | |
295 if (npobject_->_class->removeProperty) { | |
296 *result = npobject_->_class->removeProperty(npobject_, id); | |
297 } else { | |
298 *result = false; | |
299 } | |
300 } else { | |
301 *result = WebBindings::removeProperty(0, npobject_, id); | |
302 } | |
303 } | |
304 | |
305 void NPObjectStub::OnInvalidate() { | |
306 if (!IsPluginProcess()) { | |
307 NOTREACHED() << "Should only be called on NPObjects in the plugin"; | |
308 return; | |
309 } | |
310 | |
311 if (!npobject_->_class->invalidate) | |
312 return; | |
313 | |
314 npobject_->_class->invalidate(npobject_); | |
315 } | |
316 | |
317 void NPObjectStub::OnEnumeration(std::vector<NPIdentifier_Param>* value, | |
318 bool* result) { | |
319 NPIdentifier* value_np = NULL; | |
320 unsigned int count = 0; | |
321 if (!IsPluginProcess()) { | |
322 *result = WebBindings::enumerate(0, npobject_, &value_np, &count); | |
323 } else { | |
324 if (npobject_->_class->structVersion < NP_CLASS_STRUCT_VERSION_ENUM || | |
325 !npobject_->_class->enumerate) { | |
326 *result = false; | |
327 return; | |
328 } | |
329 | |
330 *result = npobject_->_class->enumerate(npobject_, &value_np, &count); | |
331 } | |
332 | |
333 if (!*result) | |
334 return; | |
335 | |
336 for (unsigned int i = 0; i < count; ++i) { | |
337 NPIdentifier_Param param; | |
338 CreateNPIdentifierParam(value_np[i], ¶m); | |
339 value->push_back(param); | |
340 } | |
341 | |
342 free(value_np); | |
343 } | |
344 | |
345 void NPObjectStub::OnConstruct(const std::vector<NPVariant_Param>& args, | |
346 IPC::Message* reply_msg) { | |
347 bool return_value = false; | |
348 NPVariant_Param result_param; | |
349 NPVariant result_var; | |
350 | |
351 VOID_TO_NPVARIANT(result_var); | |
352 | |
353 int arg_count = static_cast<int>(args.size()); | |
354 NPVariant* args_var = new NPVariant[arg_count]; | |
355 for (int i = 0; i < arg_count; ++i) { | |
356 if (!CreateNPVariant(args[i], | |
357 channel_.get(), | |
358 &(args_var[i]), | |
359 render_view_id_, | |
360 page_url_)) { | |
361 NPObjectMsg_Invoke::WriteReplyParams( | |
362 reply_msg, result_param, return_value); | |
363 channel_->Send(reply_msg); | |
364 delete[] args_var; | |
365 return; | |
366 } | |
367 } | |
368 | |
369 if (IsPluginProcess()) { | |
370 if (npobject_->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR && | |
371 npobject_->_class->construct) { | |
372 return_value = npobject_->_class->construct( | |
373 npobject_, args_var, arg_count, &result_var); | |
374 } else { | |
375 return_value = false; | |
376 } | |
377 } else { | |
378 return_value = WebBindings::construct( | |
379 0, npobject_, args_var, arg_count, &result_var); | |
380 } | |
381 | |
382 for (int i = 0; i < arg_count; ++i) | |
383 WebBindings::releaseVariantValue(&(args_var[i])); | |
384 | |
385 delete[] args_var; | |
386 | |
387 CreateNPVariantParam(result_var, | |
388 channel_.get(), | |
389 &result_param, | |
390 true, | |
391 render_view_id_, | |
392 page_url_); | |
393 NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value); | |
394 channel_->Send(reply_msg); | |
395 } | |
396 | |
397 void NPObjectStub::OnEvaluate(const std::string& script, | |
398 bool popups_allowed, | |
399 IPC::Message* reply_msg) { | |
400 if (IsPluginProcess()) { | |
401 NOTREACHED() << "Should only be called on NPObjects in the renderer"; | |
402 return; | |
403 } | |
404 | |
405 NPVariant result_var; | |
406 NPString script_string; | |
407 script_string.UTF8Characters = script.c_str(); | |
408 script_string.UTF8Length = static_cast<unsigned int>(script.length()); | |
409 | |
410 bool return_value = WebBindings::evaluateHelper(0, popups_allowed, npobject_, | |
411 &script_string, &result_var); | |
412 | |
413 NPVariant_Param result_param; | |
414 CreateNPVariantParam(result_var, | |
415 channel_.get(), | |
416 &result_param, | |
417 true, | |
418 render_view_id_, | |
419 page_url_); | |
420 NPObjectMsg_Evaluate::WriteReplyParams(reply_msg, result_param, return_value); | |
421 channel_->Send(reply_msg); | |
422 } | |
423 | |
424 } // namespace content | |
OLD | NEW |