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