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