3afdfa11f8c9871c96e37b25c2427cfab42ba6b4
[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         return true;        
127     }
128
129     if (o->_class->invokeDefault)
130         return o->_class->invokeDefault(o, args, argCount, result);    
131     VOID_TO_NPVARIANT(*result);
132     return true;
133 }
134
135 bool _NPN_Invoke(NPP npp, NPObject* o, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result)
136 {
137     if (o->_class == NPScriptObjectClass) {
138         JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o); 
139
140         PrivateIdentifier* i = static_cast<PrivateIdentifier*>(methodName);
141         if (!i->isString)
142             return false;
143
144         // Special case the "eval" method.
145         if (methodName == _NPN_GetStringIdentifier("eval")) {
146             if (argCount != 1)
147                 return false;
148             if (args[0].type != NPVariantType_String)
149                 return false;
150             return _NPN_Evaluate(npp, o, const_cast<NPString*>(&args[0].value.stringValue), result);
151         }
152
153         // Look up the function object.
154         RootObject* rootObject = obj->rootObject;
155         if (!rootObject || !rootObject->isValid())
156             return false;
157         ExecState* exec = rootObject->globalObject()->globalExec();
158         JSLock lock(false);
159         JSValue* function = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
160         CallData callData;
161         CallType callType = function->getCallData(callData);
162         if (callType == CallTypeNone)
163             return false;
164
165         // Call the function object.
166         ArgList argList;
167         getListFromVariantArgs(exec, args, argCount, rootObject, argList);
168         rootObject->globalObject()->startTimeoutCheck();
169         JSValue* resultV = call(exec, function, callType, callData, obj->imp, 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 = reinterpret_cast<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(false);
196         String scriptString = convertNPStringToUTF16(s);
197         rootObject->globalObject()->startTimeoutCheck();
198         Completion completion = Interpreter::evaluate(rootObject->globalObject()->globalExec(), rootObject->globalObject()->globalScopeChain(), UString(), 1, scriptString);
199         rootObject->globalObject()->stopTimeoutCheck();
200         ComplType type = completion.complType();
201         
202         JSValue* result;
203         if (type == Normal) {
204             result = completion.value();
205             if (!result)
206                 result = jsUndefined();
207         } else
208             result = jsUndefined();
209
210         convertValueToNPVariant(exec, result, variant);
211     
212         return true;
213     }
214
215     VOID_TO_NPVARIANT(*variant);
216     return false;
217 }
218
219 bool _NPN_GetProperty(NPP, NPObject* o, NPIdentifier propertyName, NPVariant* variant)
220 {
221     if (o->_class == NPScriptObjectClass) {
222         JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o); 
223
224         RootObject* rootObject = obj->rootObject;
225         if (!rootObject || !rootObject->isValid())
226             return false;
227
228         ExecState* exec = rootObject->globalObject()->globalExec();
229         PrivateIdentifier* i = static_cast<PrivateIdentifier*>(propertyName);
230         
231         JSLock lock(false);
232         JSValue* result;
233         if (i->isString)
234             result = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
235         else
236             result = obj->imp->get(exec, i->value.number);
237
238         convertValueToNPVariant(exec, result, variant);
239         return true;
240     }
241
242     if (o->_class->hasProperty && o->_class->getProperty) {
243         if (o->_class->hasProperty(o, propertyName))
244             return o->_class->getProperty(o, propertyName, variant);
245         return false;
246     }
247
248     VOID_TO_NPVARIANT(*variant);
249     return false;
250 }
251
252 bool _NPN_SetProperty(NPP, NPObject* o, NPIdentifier propertyName, const NPVariant* variant)
253 {
254     if (o->_class == NPScriptObjectClass) {
255         JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o); 
256
257         RootObject* rootObject = obj->rootObject;
258         if (!rootObject || !rootObject->isValid())
259             return false;
260
261         ExecState* exec = rootObject->globalObject()->globalExec();
262         JSLock lock(false);
263         PrivateIdentifier* i = static_cast<PrivateIdentifier*>(propertyName);
264         if (i->isString)
265             obj->imp->put(exec, identifierFromNPIdentifier(i->value.string), convertNPVariantToValue(exec, variant, rootObject));
266         else
267             obj->imp->put(exec, i->value.number, convertNPVariantToValue(exec, variant, rootObject));
268         return true;
269     }
270
271     if (o->_class->setProperty)
272         return o->_class->setProperty(o, propertyName, variant);
273
274     return false;
275 }
276
277 bool _NPN_RemoveProperty(NPP, NPObject* o, NPIdentifier propertyName)
278 {
279     if (o->_class == NPScriptObjectClass) {
280         JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o); 
281
282         RootObject* rootObject = obj->rootObject;
283         if (!rootObject || !rootObject->isValid())
284             return false;
285
286         ExecState* exec = rootObject->globalObject()->globalExec();
287         PrivateIdentifier* i = static_cast<PrivateIdentifier*>(propertyName);
288         if (i->isString) {
289             if (!obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->value.string)))
290                 return false;
291         } else {
292             if (!obj->imp->hasProperty(exec, i->value.number))
293                 return false;
294         }
295
296         JSLock lock(false);
297         if (i->isString)
298             obj->imp->deleteProperty(exec, identifierFromNPIdentifier(i->value.string));
299         else
300             obj->imp->deleteProperty(exec, i->value.number);
301         
302         return true;
303     }
304     return false;
305 }
306
307 bool _NPN_HasProperty(NPP, NPObject* o, NPIdentifier propertyName)
308 {
309     if (o->_class == NPScriptObjectClass) {
310         JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o); 
311
312         RootObject* rootObject = obj->rootObject;
313         if (!rootObject || !rootObject->isValid())
314             return false;
315
316         ExecState* exec = rootObject->globalObject()->globalExec();
317         PrivateIdentifier* i = static_cast<PrivateIdentifier*>(propertyName);
318         JSLock lock(false);
319         if (i->isString)
320             return obj->imp->hasProperty(exec, identifierFromNPIdentifier(i->value.string));
321         return obj->imp->hasProperty(exec, i->value.number);
322     }
323
324     if (o->_class->hasProperty)
325         return o->_class->hasProperty(o, propertyName);
326
327     return false;
328 }
329
330 bool _NPN_HasMethod(NPP, NPObject* o, NPIdentifier methodName)
331 {
332     if (o->_class == NPScriptObjectClass) {
333         JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o); 
334
335         PrivateIdentifier* i = static_cast<PrivateIdentifier*>(methodName);
336         if (!i->isString)
337             return false;
338
339         RootObject* rootObject = obj->rootObject;
340         if (!rootObject || !rootObject->isValid())
341             return false;
342
343         ExecState* exec = rootObject->globalObject()->globalExec();
344         JSLock lock(false);
345         JSValue* func = obj->imp->get(exec, identifierFromNPIdentifier(i->value.string));
346         return !func->isUndefined();
347     }
348     
349     if (o->_class->hasMethod)
350         return o->_class->hasMethod(o, methodName);
351     
352     return false;
353 }
354
355 void _NPN_SetException(NPObject*, const NPUTF8*)
356 {
357     // FIXME:
358     // Bug 19888: Implement _NPN_SetException() correctly
359     // <https://bugs.webkit.org/show_bug.cgi?id=19888>
360 }
361
362 bool _NPN_Enumerate(NPP, NPObject* o, NPIdentifier** identifier, uint32_t* count)
363 {
364     if (o->_class == NPScriptObjectClass) {
365         JavaScriptObject* obj = reinterpret_cast<JavaScriptObject*>(o); 
366         
367         RootObject* rootObject = obj->rootObject;
368         if (!rootObject || !rootObject->isValid())
369             return false;
370         
371         ExecState* exec = rootObject->globalObject()->globalExec();
372         JSLock lock(false);
373         PropertyNameArray propertyNames(exec);
374
375         obj->imp->getPropertyNames(exec, propertyNames);
376         unsigned size = static_cast<unsigned>(propertyNames.size());
377         // FIXME: This should really call NPN_MemAlloc but that's in WebKit
378         NPIdentifier* identifiers = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier) * size));
379         
380         for (unsigned i = 0; i < size; ++i)
381             identifiers[i] = _NPN_GetStringIdentifier(propertyNames[i].ustring().UTF8String().c_str());
382
383         *identifier = identifiers;
384         *count = size;
385         
386         return true;
387     }
388     
389     if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(o->_class) && o->_class->enumerate)
390         return o->_class->enumerate(o, identifier, count);
391     
392     return false;
393 }
394
395 #endif // ENABLE(NETSCAPE_PLUGIN_API)