[content shell] hook up testRunner.dumpEditingCallbacks
[chromium-blink-merge.git] / content / common / npobject_stub.cc
blobb71522452b17a059bb1dfc95df61ae4ba4b4bd85
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_stub.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 "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"
17 #if defined(OS_WIN)
18 #include "base/command_line.h"
19 #include "webkit/plugins/npapi/plugin_constants_win.h"
20 #endif
22 using WebKit::WebBindings;
24 namespace content {
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);
40 // We retain the object just as PluginHost does if everything was in-process.
41 WebBindings::retainObject(npobject_);
44 NPObjectStub::~NPObjectStub() {
45 channel_->RemoveRoute(route_id_);
46 DCHECK(!npobject_);
49 void NPObjectStub::DeleteSoon() {
50 if (npobject_) {
51 channel_->RemoveMappingForNPObjectStub(route_id_, npobject_);
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;
59 WebBindings::releaseObject(npobject);
61 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
65 bool NPObjectStub::Send(IPC::Message* msg) {
66 return channel_->Send(msg);
69 NPObject* NPObjectStub::GetUnderlyingNPObject() {
70 return npobject_;
73 IPC::Listener* NPObjectStub::GetChannelListener() {
74 return static_cast<IPC::Listener*>(this);
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);
88 return true;
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;
110 void NPObjectStub::OnChannelError() {
111 DeleteSoon();
114 void NPObjectStub::OnRelease(IPC::Message* reply_msg) {
115 Send(reply_msg);
116 DeleteSoon();
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;
132 } else {
133 *result = WebBindings::hasMethod(0, npobject_, id);
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;
145 VOID_TO_NPVARIANT(result_var);
146 result_param.type = NPVARIANT_PARAM_VOID;
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;
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;
169 } else {
170 return_value = WebBindings::invokeDefault(
171 0, npobject_, args_var, arg_count, &result_var);
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;
182 } else {
183 return_value = WebBindings::invoke(
184 0, npobject_, id, args_var, arg_count, &result_var);
188 for (int i = 0; i < arg_count; ++i)
189 WebBindings::releaseVariantValue(&(args_var[i]));
191 delete[] args_var;
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);
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;
208 } else {
209 *result = WebBindings::hasProperty(0, npobject_, id);
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);
220 if (IsPluginProcess()) {
221 if (npobject_->_class->getProperty) {
222 *result = npobject_->_class->getProperty(npobject_, id, &result_var);
223 } else {
224 *result = false;
226 } else {
227 *result = WebBindings::getProperty(0, npobject_, id, &result_var);
230 CreateNPVariantParam(
231 result_var, channel_, property, true, render_view_id_, page_url_);
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;
247 if (IsPluginProcess()) {
248 if (npobject_->_class->setProperty) {
249 #if defined(OS_WIN)
250 static 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;
264 #endif
265 result = npobject_->_class->setProperty(npobject_, id, &property_var);
266 } else {
267 result = false;
269 } else {
270 result = WebBindings::setProperty(0, npobject_, id, &property_var);
273 WebBindings::releaseVariantValue(&property_var);
275 if (reply_msg) {
276 NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result);
277 Send(reply_msg);
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;
290 } else {
291 *result = WebBindings::removeProperty(0, npobject_, id);
295 void NPObjectStub::OnInvalidate() {
296 if (!IsPluginProcess()) {
297 NOTREACHED() << "Should only be called on NPObjects in the plugin";
298 return;
301 if (!npobject_->_class->invalidate)
302 return;
304 npobject_->_class->invalidate(npobject_);
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;
320 *result = npobject_->_class->enumerate(npobject_, &value_np, &count);
323 if (!*result)
324 return;
326 for (unsigned int i = 0; i < count; ++i) {
327 NPIdentifier_Param param;
328 CreateNPIdentifierParam(value_np[i], &param);
329 value->push_back(param);
332 webkit::npapi::PluginHost::Singleton()->host_functions()->memfree(value_np);
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;
341 VOID_TO_NPVARIANT(result_var);
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;
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;
364 } else {
365 return_value = WebBindings::construct(
366 0, npobject_, args_var, arg_count, &result_var);
369 for (int i = 0; i < arg_count; ++i)
370 WebBindings::releaseVariantValue(&(args_var[i]));
372 delete[] args_var;
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);
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;
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());
393 bool return_value = WebBindings::evaluateHelper(0, popups_allowed, npobject_,
394 &script_string, &result_var);
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);
403 } // namespace content