Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / child / npapi / npobject_util.cc
blobe8f5b4ee2ce2b1eb02a502cd0c80dbbdfc6cd060
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.
5 #include "content/child/npapi/npobject_util.h"
7 #include "base/strings/string_util.h"
8 #include "content/child/npapi/np_channel_base.h"
9 #include "content/child/npapi/npobject_proxy.h"
10 #include "content/child/npapi/plugin_host.h"
11 #include "content/child/plugin_messages.h"
12 #include "third_party/WebKit/public/web/WebBindings.h"
13 #include "third_party/npapi/bindings/nphostapi.h"
15 using blink::WebBindings;
17 namespace content {
19 // true if the current process is a plugin process, false otherwise.
20 static bool g_plugin_process;
22 namespace {
23 #if defined(ENABLE_PLUGINS)
24 // The next 7 functions are called by the plugin code when it's using the
25 // NPObject. Plugins always ignore the functions in NPClass (except allocate
26 // and deallocate), and instead just use the function pointers that were
27 // passed in NPInitialize.
28 // When the renderer interacts with an NPObject from the plugin, it of course
29 // uses the function pointers in its NPClass structure.
30 static bool NPN_HasMethodPatch(NPP npp,
31 NPObject *npobj,
32 NPIdentifier methodName) {
33 return NPObjectProxy::NPHasMethod(npobj, methodName);
36 static bool NPN_InvokePatch(NPP npp, NPObject *npobj,
37 NPIdentifier methodName,
38 const NPVariant *args,
39 uint32_t argCount,
40 NPVariant *result) {
41 return NPObjectProxy::NPInvokePrivate(npp, npobj, false, methodName, args,
42 argCount, result);
45 static bool NPN_InvokeDefaultPatch(NPP npp,
46 NPObject *npobj,
47 const NPVariant *args,
48 uint32_t argCount,
49 NPVariant *result) {
50 return NPObjectProxy::NPInvokePrivate(npp, npobj, true, 0, args, argCount,
51 result);
54 static bool NPN_HasPropertyPatch(NPP npp,
55 NPObject *npobj,
56 NPIdentifier propertyName) {
57 return NPObjectProxy::NPHasProperty(npobj, propertyName);
60 static bool NPN_GetPropertyPatch(NPP npp,
61 NPObject *npobj,
62 NPIdentifier propertyName,
63 NPVariant *result) {
64 return NPObjectProxy::NPGetProperty(npobj, propertyName, result);
67 static bool NPN_SetPropertyPatch(NPP npp,
68 NPObject *npobj,
69 NPIdentifier propertyName,
70 const NPVariant *value) {
71 return NPObjectProxy::NPSetProperty(npobj, propertyName, value);
74 static bool NPN_RemovePropertyPatch(NPP npp,
75 NPObject *npobj,
76 NPIdentifier propertyName) {
77 return NPObjectProxy::NPRemoveProperty(npobj, propertyName);
80 static bool NPN_EvaluatePatch(NPP npp,
81 NPObject *npobj,
82 NPString *script,
83 NPVariant *result) {
84 return NPObjectProxy::NPNEvaluate(npp, npobj, script, result);
88 static void NPN_SetExceptionPatch(NPObject *obj, const NPUTF8 *message) {
89 std::string message_str(message);
90 if (IsPluginProcess()) {
91 NPChannelBase* renderer_channel = NPChannelBase::GetCurrentChannel();
92 if (renderer_channel)
93 renderer_channel->Send(new PluginHostMsg_SetException(message_str));
94 } else {
95 WebBindings::setException(obj, message_str.c_str());
99 static bool NPN_EnumeratePatch(NPP npp, NPObject *obj,
100 NPIdentifier **identifier, uint32_t *count) {
101 return NPObjectProxy::NPNEnumerate(obj, identifier, count);
104 // The overrided table of functions provided to the plugin.
105 NPNetscapeFuncs *GetHostFunctions() {
106 static bool init = false;
107 static NPNetscapeFuncs host_funcs;
108 if (init)
109 return &host_funcs;
111 memset(&host_funcs, 0, sizeof(host_funcs));
112 host_funcs.invoke = NPN_InvokePatch;
113 host_funcs.invokeDefault = NPN_InvokeDefaultPatch;
114 host_funcs.evaluate = NPN_EvaluatePatch;
115 host_funcs.getproperty = NPN_GetPropertyPatch;
116 host_funcs.setproperty = NPN_SetPropertyPatch;
117 host_funcs.removeproperty = NPN_RemovePropertyPatch;
118 host_funcs.hasproperty = NPN_HasPropertyPatch;
119 host_funcs.hasmethod = NPN_HasMethodPatch;
120 host_funcs.setexception = NPN_SetExceptionPatch;
121 host_funcs.enumerate = NPN_EnumeratePatch;
123 init = true;
124 return &host_funcs;
127 #endif // defined(ENABLE_PLUGINS)
130 #if defined(ENABLE_PLUGINS)
131 void PatchNPNFunctions() {
132 g_plugin_process = true;
133 NPNetscapeFuncs* funcs = GetHostFunctions();
134 PluginHost::Singleton()->PatchNPNetscapeFuncs(funcs);
136 #endif
138 bool IsPluginProcess() {
139 return g_plugin_process;
142 void CreateNPIdentifierParam(NPIdentifier id, NPIdentifier_Param* param) {
143 param->identifier = id;
146 NPIdentifier CreateNPIdentifier(const NPIdentifier_Param& param) {
147 return param.identifier;
150 void CreateNPVariantParam(const NPVariant& variant,
151 NPChannelBase* channel,
152 NPVariant_Param* param,
153 bool release,
154 int render_view_id,
155 const GURL& page_url) {
156 switch (variant.type) {
157 case NPVariantType_Void:
158 param->type = NPVARIANT_PARAM_VOID;
159 break;
160 case NPVariantType_Null:
161 param->type = NPVARIANT_PARAM_NULL;
162 break;
163 case NPVariantType_Bool:
164 param->type = NPVARIANT_PARAM_BOOL;
165 param->bool_value = variant.value.boolValue;
166 break;
167 case NPVariantType_Int32:
168 param->type = NPVARIANT_PARAM_INT;
169 param->int_value = variant.value.intValue;
170 break;
171 case NPVariantType_Double:
172 param->type = NPVARIANT_PARAM_DOUBLE;
173 param->double_value = variant.value.doubleValue;
174 break;
175 case NPVariantType_String:
176 param->type = NPVARIANT_PARAM_STRING;
177 if (variant.value.stringValue.UTF8Length) {
178 param->string_value.assign(variant.value.stringValue.UTF8Characters,
179 variant.value.stringValue.UTF8Length);
181 break;
182 case NPVariantType_Object: {
183 if (variant.value.objectValue->_class == NPObjectProxy::npclass()) {
184 param->type = NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID;
185 NPObjectProxy* proxy =
186 NPObjectProxy::GetProxy(variant.value.objectValue);
187 DCHECK(proxy);
188 param->npobject_routing_id = proxy->route_id();
189 // Don't release, because our original variant is the same as our proxy.
190 release = false;
191 } else {
192 // The channel could be NULL if there was a channel error. The caller's
193 // Send call will fail anyways.
194 if (channel) {
195 // NPObjectStub adds its own reference to the NPObject it owns, so if
196 // we were supposed to release the corresponding variant
197 // (release==true), we should still do that.
198 param->type = NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID;
199 int route_id = channel->GetExistingRouteForNPObjectStub(
200 variant.value.objectValue);
201 if (route_id != MSG_ROUTING_NONE) {
202 param->npobject_routing_id = route_id;
203 } else {
204 route_id = channel->GenerateRouteID();
205 new NPObjectStub(
206 variant.value.objectValue, channel, route_id, render_view_id,
207 page_url);
208 param->npobject_routing_id = route_id;
211 // Include the object's owner.
212 NPP owner = WebBindings::getObjectOwner(variant.value.objectValue);
213 param->npobject_owner_id =
214 channel->GetExistingRouteForNPObjectOwner(owner);
215 } else {
216 param->type = NPVARIANT_PARAM_VOID;
219 break;
221 default:
222 NOTREACHED();
225 if (release)
226 WebBindings::releaseVariantValue(const_cast<NPVariant*>(&variant));
229 bool CreateNPVariant(const NPVariant_Param& param,
230 NPChannelBase* channel,
231 NPVariant* result,
232 int render_view_id,
233 const GURL& page_url) {
234 switch (param.type) {
235 case NPVARIANT_PARAM_VOID:
236 result->type = NPVariantType_Void;
237 break;
238 case NPVARIANT_PARAM_NULL:
239 result->type = NPVariantType_Null;
240 break;
241 case NPVARIANT_PARAM_BOOL:
242 result->type = NPVariantType_Bool;
243 result->value.boolValue = param.bool_value;
244 break;
245 case NPVARIANT_PARAM_INT:
246 result->type = NPVariantType_Int32;
247 result->value.intValue = param.int_value;
248 break;
249 case NPVARIANT_PARAM_DOUBLE:
250 result->type = NPVariantType_Double;
251 result->value.doubleValue = param.double_value;
252 break;
253 case NPVARIANT_PARAM_STRING: {
254 result->type = NPVariantType_String;
255 void* buffer = malloc(param.string_value.size());
256 size_t size = param.string_value.size();
257 result->value.stringValue.UTF8Characters = static_cast<NPUTF8*>(buffer);
258 memcpy(buffer, param.string_value.c_str(), size);
259 result->value.stringValue.UTF8Length = static_cast<int>(size);
260 break;
262 case NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID: {
263 result->type = NPVariantType_Object;
264 NPObject* object =
265 channel->GetExistingNPObjectProxy(param.npobject_routing_id);
266 if (object) {
267 WebBindings::retainObject(object);
268 result->value.objectValue = object;
269 } else {
270 NPP owner =
271 channel->GetExistingNPObjectOwner(param.npobject_owner_id);
272 // TODO(wez): Once NPObject tracking lands in Blink, check |owner| and
273 // return NPVariantType_Void if it is NULL.
274 result->value.objectValue =
275 NPObjectProxy::Create(channel,
276 param.npobject_routing_id,
277 render_view_id,
278 page_url,
279 owner);
281 break;
283 case NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID: {
284 NPObjectBase* npobject_base =
285 channel->GetNPObjectListenerForRoute(param.npobject_routing_id);
286 if (!npobject_base) {
287 DLOG(WARNING) << "Invalid routing id passed in"
288 << param.npobject_routing_id;
289 return false;
292 DCHECK(npobject_base->GetUnderlyingNPObject() != NULL);
294 result->type = NPVariantType_Object;
295 result->value.objectValue = npobject_base->GetUnderlyingNPObject();
296 WebBindings::retainObject(result->value.objectValue);
297 break;
299 default:
300 NOTREACHED();
302 return true;
305 } // namespace content