- add sources.
[platform/framework/web/crosswalk.git] / src / content / child / npapi / npobject_util.cc
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_util.h"
6
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"
14 #include "webkit/glue/webkit_glue.h"
15
16 using WebKit::WebBindings;
17
18 namespace content {
19
20 // true if the current process is a plugin process, false otherwise.
21 static bool g_plugin_process;
22
23 namespace {
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);
34 }
35
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);
43 }
44
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);
52 }
53
54 static bool NPN_HasPropertyPatch(NPP npp,
55                                  NPObject *npobj,
56                                  NPIdentifier propertyName) {
57   return NPObjectProxy::NPHasProperty(npobj, propertyName);
58 }
59
60 static bool NPN_GetPropertyPatch(NPP npp,
61                                  NPObject *npobj,
62                                  NPIdentifier propertyName,
63                                  NPVariant *result) {
64   return NPObjectProxy::NPGetProperty(npobj, propertyName, result);
65 }
66
67 static bool NPN_SetPropertyPatch(NPP npp,
68                                  NPObject *npobj,
69                                  NPIdentifier propertyName,
70                                  const NPVariant *value) {
71   return NPObjectProxy::NPSetProperty(npobj, propertyName, value);
72 }
73
74 static bool NPN_RemovePropertyPatch(NPP npp,
75                                     NPObject *npobj,
76                                     NPIdentifier propertyName) {
77   return NPObjectProxy::NPRemoveProperty(npobj, propertyName);
78 }
79
80 static bool NPN_EvaluatePatch(NPP npp,
81                               NPObject *npobj,
82                               NPString *script,
83                               NPVariant *result) {
84   return NPObjectProxy::NPNEvaluate(npp, npobj, script, result);
85 }
86
87
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());
96   }
97 }
98
99 static bool NPN_EnumeratePatch(NPP npp, NPObject *obj,
100                                NPIdentifier **identifier, uint32_t *count) {
101   return NPObjectProxy::NPNEnumerate(obj, identifier, count);
102 }
103
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;
110
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;
122
123   init = true;
124   return &host_funcs;
125 }
126
127 }
128
129 void PatchNPNFunctions() {
130   g_plugin_process = true;
131   NPNetscapeFuncs* funcs = GetHostFunctions();
132   PluginHost::Singleton()->PatchNPNetscapeFuncs(funcs);
133 }
134
135 bool IsPluginProcess() {
136   return g_plugin_process;
137 }
138
139 void CreateNPIdentifierParam(NPIdentifier id, NPIdentifier_Param* param) {
140   param->identifier = id;
141 }
142
143 NPIdentifier CreateNPIdentifier(const NPIdentifier_Param& param) {
144   return param.identifier;
145 }
146
147 void CreateNPVariantParam(const NPVariant& variant,
148                           NPChannelBase* channel,
149                           NPVariant_Param* param,
150                           bool release,
151                           int render_view_id,
152                           const GURL& page_url) {
153   switch (variant.type) {
154     case NPVariantType_Void:
155       param->type = NPVARIANT_PARAM_VOID;
156       break;
157     case NPVariantType_Null:
158       param->type = NPVARIANT_PARAM_NULL;
159       break;
160     case NPVariantType_Bool:
161       param->type = NPVARIANT_PARAM_BOOL;
162       param->bool_value = variant.value.boolValue;
163       break;
164     case NPVariantType_Int32:
165       param->type = NPVARIANT_PARAM_INT;
166       param->int_value = variant.value.intValue;
167       break;
168     case NPVariantType_Double:
169       param->type = NPVARIANT_PARAM_DOUBLE;
170       param->double_value = variant.value.doubleValue;
171       break;
172     case NPVariantType_String:
173       param->type = NPVARIANT_PARAM_STRING;
174       if (variant.value.stringValue.UTF8Length) {
175         param->string_value.assign(variant.value.stringValue.UTF8Characters,
176                                    variant.value.stringValue.UTF8Length);
177       }
178       break;
179     case NPVariantType_Object: {
180       if (variant.value.objectValue->_class == NPObjectProxy::npclass()) {
181         param->type = NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID;
182         NPObjectProxy* proxy =
183             NPObjectProxy::GetProxy(variant.value.objectValue);
184         DCHECK(proxy);
185         param->npobject_routing_id = proxy->route_id();
186         // Don't release, because our original variant is the same as our proxy.
187         release = false;
188       } else {
189         // The channel could be NULL if there was a channel error. The caller's
190         // Send call will fail anyways.
191         if (channel) {
192           // NPObjectStub adds its own reference to the NPObject it owns, so if
193           // we were supposed to release the corresponding variant
194           // (release==true), we should still do that.
195           param->type = NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID;
196           int route_id = channel->GetExistingRouteForNPObjectStub(
197               variant.value.objectValue);
198           if (route_id != MSG_ROUTING_NONE) {
199             param->npobject_routing_id = route_id;
200           } else {
201             route_id = channel->GenerateRouteID();
202             new NPObjectStub(
203                 variant.value.objectValue, channel, route_id, render_view_id,
204                 page_url);
205             param->npobject_routing_id = route_id;
206           }
207
208           // Include the object's owner.
209           NPP owner = WebBindings::getObjectOwner(variant.value.objectValue);
210           param->npobject_owner_id =
211               channel->GetExistingRouteForNPObjectOwner(owner);
212         } else {
213           param->type = NPVARIANT_PARAM_VOID;
214         }
215       }
216       break;
217     }
218     default:
219       NOTREACHED();
220   }
221
222   if (release)
223     WebBindings::releaseVariantValue(const_cast<NPVariant*>(&variant));
224 }
225
226 bool CreateNPVariant(const NPVariant_Param& param,
227                      NPChannelBase* channel,
228                      NPVariant* result,
229                      int render_view_id,
230                      const GURL& page_url) {
231   switch (param.type) {
232     case NPVARIANT_PARAM_VOID:
233       result->type = NPVariantType_Void;
234       break;
235     case NPVARIANT_PARAM_NULL:
236       result->type = NPVariantType_Null;
237       break;
238     case NPVARIANT_PARAM_BOOL:
239       result->type = NPVariantType_Bool;
240       result->value.boolValue = param.bool_value;
241       break;
242     case NPVARIANT_PARAM_INT:
243       result->type = NPVariantType_Int32;
244       result->value.intValue = param.int_value;
245       break;
246     case NPVARIANT_PARAM_DOUBLE:
247       result->type = NPVariantType_Double;
248       result->value.doubleValue = param.double_value;
249       break;
250     case NPVARIANT_PARAM_STRING: {
251       result->type = NPVariantType_String;
252       void* buffer = malloc(param.string_value.size());
253       size_t size = param.string_value.size();
254       result->value.stringValue.UTF8Characters = static_cast<NPUTF8*>(buffer);
255       memcpy(buffer, param.string_value.c_str(), size);
256       result->value.stringValue.UTF8Length = static_cast<int>(size);
257       break;
258     }
259     case NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID: {
260       result->type = NPVariantType_Object;
261       NPObject* object =
262           channel->GetExistingNPObjectProxy(param.npobject_routing_id);
263       if (object) {
264         WebBindings::retainObject(object);
265         result->value.objectValue = object;
266       } else {
267         NPP owner =
268             channel->GetExistingNPObjectOwner(param.npobject_owner_id);
269         // TODO(wez): Once NPObject tracking lands in Blink, check |owner| and
270         // return NPVariantType_Void if it is NULL.
271         result->value.objectValue =
272             NPObjectProxy::Create(channel,
273                                   param.npobject_routing_id,
274                                   render_view_id,
275                                   page_url,
276                                   owner);
277       }
278       break;
279     }
280     case NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID: {
281       NPObjectBase* npobject_base =
282           channel->GetNPObjectListenerForRoute(param.npobject_routing_id);
283       if (!npobject_base) {
284         DLOG(WARNING) << "Invalid routing id passed in"
285                       << param.npobject_routing_id;
286         return false;
287       }
288
289       DCHECK(npobject_base->GetUnderlyingNPObject() != NULL);
290
291       result->type = NPVariantType_Object;
292       result->value.objectValue = npobject_base->GetUnderlyingNPObject();
293       WebBindings::retainObject(result->value.objectValue);
294       break;
295     }
296     default:
297       NOTREACHED();
298   }
299   return true;
300 }
301
302 }  // namespace content