Reviewed by Anders Carlsson.
[WebKit-https.git] / WebCore / bridge / NP_jsobject.cpp
1 /*
2  * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(NETSCAPE_PLUGIN_API)
29
30 #include "NP_jsobject.h"
31
32 #include <kjs/JSGlobalObject.h>
33 #include <kjs/JSLock.h>
34 #include <kjs/PropertyNameArray.h>
35 #include "c_utility.h"
36 #include <kjs/completion.h>
37 #include <kjs/interpreter.h>
38 #include "PlatformString.h"
39 #include "npruntime_impl.h"
40 #include "npruntime_priv.h"
41 #include "runtime_root.h"
42
43 using WebCore::String;
44 using namespace KJS;
45 using namespace KJS::Bindings;
46
47 static void getListFromVariantArgs(ExecState* exec, const NPVariant* args, unsigned argCount, RootObject* rootObject, ArgList& aList)
48 {
49     for (unsigned i = 0; i < argCount; i++)
50         aList.append(convertNPVariantToValue(exec, &args[i], rootObject));
51 }
52
53 static NPObject* jsAllocate(NPP, NPClass*)
54 {
55     return (NPObject*)malloc(sizeof(JavaScriptObject));
56 }
57
58 static void jsDeallocate(NPObject* npObj)
59 {
60     JavaScriptObject* obj = (JavaScriptObject*)npObj;
61
62     if (obj->rootObject && obj->rootObject->isValid())
63         obj->rootObject->gcUnprotect(obj->imp);
64
65     if (obj->rootObject)
66         obj->rootObject->deref();
67
68     free(obj);
69 }
70
71 static NPClass javascriptClass = { 1, jsAllocate, jsDeallocate, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
72 static NPClass noScriptClass = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
73
74 NPClass* NPScriptObjectClass = &javascriptClass;
75 static NPClass* NPNoScriptObjectClass = &noScriptClass;
76
77 NPObject* _NPN_CreateScriptObject(NPP npp, JSObject* imp, PassRefPtr<RootObject> rootObject)
78 {
79     JavaScriptObject* obj = (JavaScriptObject*)_NPN_CreateObject(npp, NPScriptObjectClass);
80
81     obj->rootObject = rootObject.releaseRef();
82
83     if (obj->rootObject)
84         obj->rootObject->gcProtect(imp);
85     obj->imp = imp;
86
87     return (NPObject*)obj;
88 }
89
90 NPObject *_NPN_CreateNoScriptObject(void)
91 {
92     return _NPN_CreateObject(0, NPNoScriptObjectClass);
93 }
94
95 bool _NPN_InvokeDefault(NPP, NPObject* o, const NPVariant* args, uint32_t argCount, NPVariant* result)
96 {
97     if (o->_class == NPScriptObjectClass) {
98         JavaScriptObject* obj = (JavaScriptObject*)o; 
99         
100         VOID_TO_NPVARIANT(*result);
101         
102         // Lookup the function object.
103         RootObject* rootObject = obj->rootObject;
104         if (!rootObject || !rootObject->isValid())
105             return false;
106         
107         ExecState* exec = rootObject->globalObject()->globalExec();
108         JSLock lock(false);
109         
110         // Call the function object.
111         JSValue* function = obj->imp;
112         CallData callData;
113         CallType callType = function->getCallData(callData);
114         if (callType == CallTypeNone)
115             return false;
116         
117         ArgList argList;
118         getListFromVariantArgs(exec, args, argCount, rootObject, argList);
119         rootObject->globalObject()->startTimeoutCheck();
120         JSValue *resultV = call(exec, function, callType, callData, function, argList);
121         rootObject->globalObject()->stopTimeoutCheck();
122
123         // Convert and return the result of the function call.
124         convertValueToNPVariant(exec, resultV, result);
125         return true;        
126     }
127
128     if (o->_class->invokeDefault)
129         return o->_class->invokeDefault(o, args, argCount, result);    
130     VOID_TO_NPVARIANT(*result);
131     return true;
132 }
133
134 bool _NPN_Invoke(NPP npp, NPObject* o, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result)
135 {
136     if (o->_class == NPScriptObjectClass) {
137         JavaScriptObject* obj = (JavaScriptObject*)o; 
138
139         PrivateIdentifier* i = (PrivateIdentifier*)methodName;
140         if (!i->isString)
141             return false;
142
143         // Special case the "eval" method.
144         if (methodName == _NPN_GetStringIdentifier("eval")) {
145             if (argCount != 1)
146                 return false;
147             if (args[0].type != NPVariantType_String)
148                 return false;
149             return _NPN_Evaluate(npp, o, (NPString *)&args[0].value.stringValue, result);
150         }
151
152         // Look up the function object.
153         RootObject* rootObject = obj->rootObject;
154         if (!rootObject || !rootObject->isValid())
155             return false;
156         ExecState* exec = rootObject->globalObject()->globalExec();
157         JSLock lock(false);
158         JSValue* function = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
159         CallData callData;
160         CallType callType = function->getCallData(callData);
161         if (callType == CallTypeNone)
162             return false;
163
164         // Call the function object.
165         ArgList argList;
166         getListFromVariantArgs(exec, args, argCount, rootObject, argList);
167         rootObject->globalObject()->startTimeoutCheck();
168         JSValue* resultV = call(exec, function, callType, callData, obj->imp, argList);
169         rootObject->globalObject()->stopTimeoutCheck();
170
171         // Convert and return the result of the function call.
172         convertValueToNPVariant(exec, resultV, result);
173         return true;
174     }
175
176     if (o->_class->invoke)
177         return o->_class->invoke(o, methodName, args, argCount, result);
178     
179     VOID_TO_NPVARIANT(*result);
180     return true;
181 }
182
183 bool _NPN_Evaluate(NPP, NPObject* o, NPString* s, NPVariant* variant)
184 {
185     if (o->_class == NPScriptObjectClass) {
186         JavaScriptObject* obj = (JavaScriptObject*)o; 
187
188         RootObject* rootObject = obj->rootObject;
189         if (!rootObject || !rootObject->isValid())
190             return false;
191
192         ExecState* exec = rootObject->globalObject()->globalExec();
193         
194         JSLock lock(false);
195         String scriptString = convertNPStringToUTF16(s);
196         rootObject->globalObject()->startTimeoutCheck();
197         Completion completion = Interpreter::evaluate(rootObject->globalObject()->globalExec(), rootObject->globalObject()->globalScopeChain(), UString(), 1, scriptString);
198         rootObject->globalObject()->stopTimeoutCheck();
199         ComplType type = completion.complType();
200         
201         JSValue* result;
202         if (type == Normal) {
203             result = completion.value();
204             if (!result)
205                 result = jsUndefined();
206         } else
207             result = jsUndefined();
208
209         convertValueToNPVariant(exec, result, variant);
210     
211         return true;
212     }
213
214     VOID_TO_NPVARIANT(*variant);
215     return false;
216 }
217
218 bool _NPN_GetProperty(NPP, NPObject* o, NPIdentifier propertyName, NPVariant* variant)
219 {
220     if (o->_class == NPScriptObjectClass) {
221         JavaScriptObject* obj = (JavaScriptObject*)o; 
222
223         RootObject* rootObject = obj->rootObject;
224         if (!rootObject || !rootObject->isValid())
225             return false;
226
227         ExecState* exec = rootObject->globalObject()->globalExec();
228         PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
229         
230         JSLock lock(false);
231         JSValue *result;
232         if (i->isString)
233             result = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
234         else
235             result = obj->imp->get(exec, i->value.number);
236
237         convertValueToNPVariant(exec, result, variant);
238         return true;
239     }
240
241     if (o->_class->hasProperty && o->_class->getProperty) {
242         if (o->_class->hasProperty(o, propertyName))
243             return o->_class->getProperty(o, propertyName, variant);
244         return false;
245     }
246
247     VOID_TO_NPVARIANT(*variant);
248     return false;
249 }
250
251 bool _NPN_SetProperty(NPP, NPObject* o, NPIdentifier propertyName, const NPVariant* variant)
252 {
253     if (o->_class == NPScriptObjectClass) {
254         JavaScriptObject* obj = (JavaScriptObject*)o; 
255
256         RootObject* rootObject = obj->rootObject;
257         if (!rootObject || !rootObject->isValid())
258             return false;
259
260         ExecState* exec = rootObject->globalObject()->globalExec();
261         JSLock lock(false);
262         PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
263         if (i->isString)
264             obj->imp->put(exec, identifierFromNPIdentifier(i->value.string), convertNPVariantToValue(exec, variant, rootObject));
265         else
266             obj->imp->put(exec, i->value.number, convertNPVariantToValue(exec, variant, rootObject));
267         return true;
268     }
269
270     if (o->_class->setProperty)
271         return o->_class->setProperty(o, propertyName, variant);
272
273     return false;
274 }
275
276 bool _NPN_RemoveProperty(NPP, NPObject* o, NPIdentifier propertyName)
277 {
278     if (o->_class == NPScriptObjectClass) {
279         JavaScriptObject* obj = (JavaScriptObject*)o; 
280
281         RootObject* rootObject = obj->rootObject;
282         if (!rootObject || !rootObject->isValid())
283             return false;
284
285         ExecState* exec = rootObject->globalObject()->globalExec();
286         PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
287         if (i->isString) {
288             if (!obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->value.string)))
289                 return false;
290         } else {
291             if (!obj->imp->hasProperty(exec, i->value.number))
292                 return false;
293         }
294
295         JSLock lock(false);
296         if (i->isString)
297             obj->imp->deleteProperty(exec, identifierFromNPIdentifier(i->value.string));
298         else
299             obj->imp->deleteProperty(exec, i->value.number);
300         
301         return true;
302     }
303     return false;
304 }
305
306 bool _NPN_HasProperty(NPP, NPObject* o, NPIdentifier propertyName)
307 {
308     if (o->_class == NPScriptObjectClass) {
309         JavaScriptObject* obj = (JavaScriptObject*)o; 
310
311         RootObject* rootObject = obj->rootObject;
312         if (!rootObject || !rootObject->isValid())
313             return false;
314
315         ExecState* exec = rootObject->globalObject()->globalExec();
316         PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
317         JSLock lock(false);
318         if (i->isString)
319             return obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->value.string));
320         return obj->imp->hasProperty(exec, i->value.number);
321     }
322
323     if (o->_class->hasProperty)
324         return o->_class->hasProperty(o, propertyName);
325
326     return false;
327 }
328
329 bool _NPN_HasMethod(NPP, NPObject* o, NPIdentifier methodName)
330 {
331     if (o->_class == NPScriptObjectClass) {
332         JavaScriptObject* obj = (JavaScriptObject*)o; 
333
334         PrivateIdentifier* i = (PrivateIdentifier*)methodName;
335         if (!i->isString)
336             return false;
337
338         RootObject* rootObject = obj->rootObject;
339         if (!rootObject || !rootObject->isValid())
340             return false;
341
342         ExecState* exec = rootObject->globalObject()->globalExec();
343         JSLock lock(false);
344         JSValue* func = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
345         return !func->isUndefined();
346     }
347     
348     if (o->_class->hasMethod)
349         return o->_class->hasMethod(o, methodName);
350     
351     return false;
352 }
353
354 void _NPN_SetException(NPObject* o, const NPUTF8* message)
355 {
356     if (o->_class == NPScriptObjectClass) {
357         JavaScriptObject* obj = (JavaScriptObject*)o; 
358         RootObject* rootObject = obj->rootObject;
359         if (!rootObject || !rootObject->isValid())
360             return;
361
362         ExecState* exec = rootObject->globalObject()->globalExec();
363         JSLock lock(false);
364         throwError(exec, GeneralError, message);
365     }
366 }
367
368 bool _NPN_Enumerate(NPP, NPObject *o, NPIdentifier **identifier, uint32_t *count)
369 {
370     if (o->_class == NPScriptObjectClass) {
371         JavaScriptObject* obj = (JavaScriptObject*)o; 
372         
373         RootObject* rootObject = obj->rootObject;
374         if (!rootObject || !rootObject->isValid())
375             return false;
376         
377         ExecState* exec = rootObject->globalObject()->globalExec();
378         JSLock lock(false);
379         PropertyNameArray propertyNames(exec);
380
381         obj->imp->getPropertyNames(exec, propertyNames);
382         unsigned size = static_cast<unsigned>(propertyNames.size());
383         // FIXME: This should really call NPN_MemAlloc but that's in WebKit
384         NPIdentifier *identifiers = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier) * size));
385         
386         for (unsigned i = 0; i < size; i++)
387             identifiers[i] = _NPN_GetStringIdentifier(propertyNames[i].ustring().UTF8String().c_str());
388
389         *identifier = identifiers;
390         *count = size;
391         
392         return true;
393     }
394     
395     if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(o->_class) && o->_class->enumerate)
396         return o->_class->enumerate(o, identifier, count);
397     
398     return false;
399 }
400
401 #endif // ENABLE(NETSCAPE_PLUGIN_API)