JavaScriptCore:
[WebKit-https.git] / JavaScriptCore / bindings / 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 !PLATFORM(DARWIN) || !defined(__LP64__)
29
30 #include "NP_jsobject.h"
31
32 #include "JSGlobalObject.h"
33 #include "PropertyNameArray.h"
34 #include "c_utility.h"
35 #include "interpreter.h"
36 #include "npruntime_impl.h"
37 #include "npruntime_priv.h"
38 #include "object.h"
39 #include "runtime_root.h"
40
41 using namespace KJS;
42 using namespace KJS::Bindings;
43
44 static void getListFromVariantArgs(ExecState* exec, const NPVariant* args, unsigned argCount, RootObject* rootObject, List& aList)
45 {
46     for (unsigned i = 0; i < argCount; i++)
47         aList.append(convertNPVariantToValue(exec, &args[i], rootObject));
48 }
49
50 static NPObject* jsAllocate(NPP, NPClass*)
51 {
52     return (NPObject*)malloc(sizeof(JavaScriptObject));
53 }
54
55 static void jsDeallocate(NPObject* npObj)
56 {
57     JavaScriptObject* obj = (JavaScriptObject*)npObj;
58
59     if (obj->rootObject && obj->rootObject->isValid())
60         obj->rootObject->gcUnprotect(obj->imp);
61
62     if (obj->rootObject)
63         obj->rootObject->deref();
64
65     free(obj);
66 }
67
68 static NPClass javascriptClass = { 1, jsAllocate, jsDeallocate, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
69 static NPClass noScriptClass = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
70
71 NPClass* NPScriptObjectClass = &javascriptClass;
72 static NPClass* NPNoScriptObjectClass = &noScriptClass;
73
74 NPObject* _NPN_CreateScriptObject(NPP npp, JSObject* imp, PassRefPtr<RootObject> rootObject)
75 {
76     JavaScriptObject* obj = (JavaScriptObject*)_NPN_CreateObject(npp, NPScriptObjectClass);
77
78     obj->rootObject = rootObject.releaseRef();
79
80     if (obj->rootObject)
81         obj->rootObject->gcProtect(imp);
82     obj->imp = imp;
83
84     return (NPObject*)obj;
85 }
86
87 NPObject *_NPN_CreateNoScriptObject(void)
88 {
89     return _NPN_CreateObject(0, NPNoScriptObjectClass);
90 }
91
92 bool _NPN_InvokeDefault(NPP, NPObject* o, const NPVariant* args, uint32_t argCount, NPVariant* result)
93 {
94     if (o->_class == NPScriptObjectClass) {
95         JavaScriptObject* obj = (JavaScriptObject*)o; 
96         
97         VOID_TO_NPVARIANT(*result);
98         
99         // Lookup the function object.
100         RootObject* rootObject = obj->rootObject;
101         if (!rootObject || !rootObject->isValid())
102             return false;
103         
104         ExecState* exec = rootObject->globalObject()->globalExec();
105         JSLock lock;
106         
107         // Call the function object.
108         JSObject *funcImp = static_cast<JSObject*>(obj->imp);
109         if (!funcImp->implementsCall())
110             return false;
111         
112         List argList;
113         getListFromVariantArgs(exec, args, argCount, rootObject, argList);
114         rootObject->globalObject()->startTimeoutCheck();
115         JSValue *resultV = funcImp->call (exec, funcImp, argList);
116         rootObject->globalObject()->stopTimeoutCheck();
117
118         // Convert and return the result of the function call.
119         convertValueToNPVariant(exec, resultV, result);
120         return true;        
121     }
122
123     if (o->_class->invokeDefault)
124         return o->_class->invokeDefault(o, args, argCount, result);    
125     VOID_TO_NPVARIANT(*result);
126     return true;
127 }
128
129 bool _NPN_Invoke(NPP npp, NPObject* o, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result)
130 {
131     if (o->_class == NPScriptObjectClass) {
132         JavaScriptObject* obj = (JavaScriptObject*)o; 
133
134         PrivateIdentifier* i = (PrivateIdentifier*)methodName;
135         if (!i->isString)
136             return false;
137
138         // Special case the "eval" method.
139         if (methodName == _NPN_GetStringIdentifier("eval")) {
140             if (argCount != 1)
141                 return false;
142             if (args[0].type != NPVariantType_String)
143                 return false;
144             return _NPN_Evaluate(npp, o, (NPString *)&args[0].value.stringValue, result);
145         }
146
147         // Lookup the function object.
148         RootObject* rootObject = obj->rootObject;
149         if (!rootObject || !rootObject->isValid())
150             return false;
151
152         ExecState* exec = rootObject->globalObject()->globalExec();
153         JSLock lock;
154         JSValue* func = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
155         if (func->isNull()) {
156             NULL_TO_NPVARIANT(*result);
157             return false;
158         } 
159         if (func->isUndefined()) {
160             VOID_TO_NPVARIANT(*result);
161             return false;
162         }
163         // Call the function object.
164         JSObject *funcImp = static_cast<JSObject*>(func);
165         JSObject *thisObj = const_cast<JSObject*>(obj->imp);
166         List argList;
167         getListFromVariantArgs(exec, args, argCount, rootObject, argList);
168         rootObject->globalObject()->startTimeoutCheck();
169         JSValue *resultV = funcImp->call (exec, thisObj, argList);
170         rootObject->globalObject()->stopTimeoutCheck();
171
172         // Convert and return the result of the function call.
173         convertValueToNPVariant(exec, resultV, result);
174         return true;
175     }
176
177     if (o->_class->invoke)
178         return o->_class->invoke(o, methodName, args, argCount, result);
179     
180     VOID_TO_NPVARIANT(*result);
181     return true;
182 }
183
184 bool _NPN_Evaluate(NPP, NPObject* o, NPString* s, NPVariant* variant)
185 {
186     if (o->_class == NPScriptObjectClass) {
187         JavaScriptObject* obj = (JavaScriptObject*)o; 
188
189         RootObject* rootObject = obj->rootObject;
190         if (!rootObject || !rootObject->isValid())
191             return false;
192
193         ExecState* exec = rootObject->globalObject()->globalExec();
194         
195         JSLock lock;
196         NPUTF16* scriptString;
197         unsigned int UTF16Length;
198         convertNPStringToUTF16(s, &scriptString, &UTF16Length); // requires free() of returned memory
199         rootObject->globalObject()->startTimeoutCheck();
200         Completion completion = Interpreter::evaluate(rootObject->globalObject()->globalExec(), UString(), 0, UString(reinterpret_cast<const UChar*>(scriptString), UTF16Length));
201         rootObject->globalObject()->stopTimeoutCheck();
202         ComplType type = completion.complType();
203         
204         JSValue* result;
205         if (type == Normal) {
206             result = completion.value();
207             if (!result)
208                 result = jsUndefined();
209         } else
210             result = jsUndefined();
211
212         free(scriptString);
213
214         convertValueToNPVariant(exec, result, variant);
215     
216         return true;
217     }
218
219     VOID_TO_NPVARIANT(*variant);
220     return false;
221 }
222
223 bool _NPN_GetProperty(NPP, NPObject* o, NPIdentifier propertyName, NPVariant* variant)
224 {
225     if (o->_class == NPScriptObjectClass) {
226         JavaScriptObject* obj = (JavaScriptObject*)o; 
227
228         RootObject* rootObject = obj->rootObject;
229         if (!rootObject || !rootObject->isValid())
230             return false;
231
232         ExecState* exec = rootObject->globalObject()->globalExec();
233         PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
234         
235         JSLock lock;
236         JSValue *result;
237         if (i->isString)
238             result = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
239         else
240             result = obj->imp->get(exec, i->value.number);
241
242         if (result->isNull()) {
243             NULL_TO_NPVARIANT(*variant);
244             return false;
245         }
246         if (result->isUndefined()) {
247             VOID_TO_NPVARIANT(*variant);
248             return false;
249         }
250         convertValueToNPVariant(exec, result, variant);
251         return true;
252     }
253
254     if (o->_class->hasProperty && o->_class->getProperty) {
255         if (o->_class->hasProperty(o, propertyName))
256             return o->_class->getProperty(o, propertyName, variant);
257         return false;
258     }
259
260     VOID_TO_NPVARIANT(*variant);
261     return false;
262 }
263
264 bool _NPN_SetProperty(NPP, NPObject* o, NPIdentifier propertyName, const NPVariant* variant)
265 {
266     if (o->_class == NPScriptObjectClass) {
267         JavaScriptObject* obj = (JavaScriptObject*)o; 
268
269         RootObject* rootObject = obj->rootObject;
270         if (!rootObject || !rootObject->isValid())
271             return false;
272
273         ExecState* exec = rootObject->globalObject()->globalExec();
274         JSLock lock;
275         PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
276         if (i->isString)
277             obj->imp->put(exec, identifierFromNPIdentifier(i->value.string), convertNPVariantToValue(exec, variant, rootObject));
278         else
279             obj->imp->put(exec, i->value.number, convertNPVariantToValue(exec, variant, rootObject));
280         return true;
281     }
282
283     if (o->_class->setProperty)
284         return o->_class->setProperty(o, propertyName, variant);
285
286     return false;
287 }
288
289 bool _NPN_RemoveProperty(NPP, NPObject* o, NPIdentifier propertyName)
290 {
291     if (o->_class == NPScriptObjectClass) {
292         JavaScriptObject* obj = (JavaScriptObject*)o; 
293
294         RootObject* rootObject = obj->rootObject;
295         if (!rootObject || !rootObject->isValid())
296             return false;
297
298         ExecState* exec = rootObject->globalObject()->globalExec();
299         PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
300         if (i->isString) {
301             if (!obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->value.string)))
302                 return false;
303         } else {
304             if (!obj->imp->hasProperty(exec, i->value.number))
305                 return false;
306         }
307
308         JSLock lock;
309         if (i->isString)
310             obj->imp->deleteProperty(exec, identifierFromNPIdentifier(i->value.string));
311         else
312             obj->imp->deleteProperty(exec, i->value.number);
313         
314         return true;
315     }
316     return false;
317 }
318
319 bool _NPN_HasProperty(NPP, NPObject* o, NPIdentifier propertyName)
320 {
321     if (o->_class == NPScriptObjectClass) {
322         JavaScriptObject* obj = (JavaScriptObject*)o; 
323
324         RootObject* rootObject = obj->rootObject;
325         if (!rootObject || !rootObject->isValid())
326             return false;
327
328         ExecState* exec = rootObject->globalObject()->globalExec();
329         PrivateIdentifier* i = (PrivateIdentifier*)propertyName;
330         JSLock lock;
331         if (i->isString)
332             return obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->value.string));
333         return obj->imp->hasProperty(exec, i->value.number);
334     }
335
336     if (o->_class->hasProperty)
337         return o->_class->hasProperty(o, propertyName);
338
339     return false;
340 }
341
342 bool _NPN_HasMethod(NPP, NPObject* o, NPIdentifier methodName)
343 {
344     if (o->_class == NPScriptObjectClass) {
345         JavaScriptObject* obj = (JavaScriptObject*)o; 
346
347         PrivateIdentifier* i = (PrivateIdentifier*)methodName;
348         if (!i->isString)
349             return false;
350
351         RootObject* rootObject = obj->rootObject;
352         if (!rootObject || !rootObject->isValid())
353             return false;
354
355         ExecState* exec = rootObject->globalObject()->globalExec();
356         JSLock lock;
357         JSValue* func = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
358         return !func->isUndefined();
359     }
360     
361     if (o->_class->hasMethod)
362         return o->_class->hasMethod(o, methodName);
363     
364     return false;
365 }
366
367 void _NPN_SetException(NPObject* o, const NPUTF8* message)
368 {
369     if (o->_class == NPScriptObjectClass) {
370         JavaScriptObject* obj = (JavaScriptObject*)o; 
371         RootObject* rootObject = obj->rootObject;
372         if (!rootObject || !rootObject->isValid())
373             return;
374
375         ExecState* exec = rootObject->globalObject()->globalExec();
376         JSLock lock;
377         throwError(exec, GeneralError, message);
378     }
379 }
380
381 bool _NPN_Enumerate(NPP, NPObject *o, NPIdentifier **identifier, uint32_t *count)
382 {
383     if (o->_class == NPScriptObjectClass) {
384         JavaScriptObject* obj = (JavaScriptObject*)o; 
385         
386         RootObject* rootObject = obj->rootObject;
387         if (!rootObject || !rootObject->isValid())
388             return false;
389         
390         ExecState* exec = rootObject->globalObject()->globalExec();
391         JSLock lock;
392         PropertyNameArray propertyNames;
393
394         obj->imp->getPropertyNames(exec, propertyNames);
395         unsigned size = static_cast<unsigned>(propertyNames.size());
396         // FIXME: This should really call NPN_MemAlloc but that's in WebKit
397         NPIdentifier *identifiers = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier) * size));
398         
399         for (unsigned i = 0; i < size; i++)
400             identifiers[i] = _NPN_GetStringIdentifier(propertyNames[i].ustring().UTF8String().c_str());
401
402         *identifier = identifiers;
403         *count = size;
404         
405         return true;
406     }
407     
408     if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(o->_class) && o->_class->enumerate)
409         return o->_class->enumerate(o, identifier, count);
410     
411     return false;
412 }
413
414 #endif