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