Reviewed by Kevin.
[WebKit-https.git] / JavaScriptCore / bindings / NP_jsobject.cpp
1 /*
2  * Copyright (C) 2004 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 #include <NP_jsobject.h>
26
27 #include <JavaScriptCore/npruntime.h>
28 #include <JavaScriptCore/c_utility.h>
29 #include <JavaScriptCore/npruntime_impl.h>
30 #include <JavaScriptCore/npruntime_priv.h>
31
32 using namespace KJS;
33 using namespace KJS::Bindings;
34
35
36 static KJS::List listFromVariantArgs(KJS::ExecState *exec, const NPVariant *args, unsigned argCount)
37 {
38     KJS::List aList; 
39     unsigned i;
40     const NPVariant *v = args;
41     
42     for (i = 0; i < argCount; i++) {
43         aList.append (convertNPVariantToValue (exec, v));
44         v++;
45     }
46     
47     return aList;
48 }
49
50 static NPObject *jsAllocate(NPP npp, NPClass *aClass)
51 {
52     return (NPObject *)malloc(sizeof(JavaScriptObject));
53 }
54
55 static void jsDeallocate (JavaScriptObject *obj)
56 {
57     free (obj);
58 }
59
60 static NPClass _javascriptClass = { 
61     1,
62     jsAllocate, 
63     (NPDeallocateFunctionPtr)jsDeallocate, 
64     0,
65     0,
66     0,
67     0,
68     0,
69     0,
70     0,
71     0
72 };
73
74 NPClass *NPScriptObjectClass = &_javascriptClass;
75
76 Identifier identiferFromNPIdentifier(const NPUTF8 *name)
77 {
78     NPUTF16 *methodName;
79     unsigned int UTF16Length;
80     
81     convertUTF8ToUTF16 (name, -1, &methodName, &UTF16Length); // requires free() of returned memory.
82     Identifier identifier ((const KJS::UChar*)methodName, UTF16Length);
83     free ((void *)methodName);
84     
85     return identifier;
86 }
87
88 NPObject *_NPN_CreateScriptObject (NPP npp, KJS::ObjectImp *imp, KJS::Bindings::RootObject *root)
89 {
90     JavaScriptObject *obj = (JavaScriptObject *)_NPN_CreateObject(npp, NPScriptObjectClass);
91
92     obj->imp = imp;
93     obj->root = root;    
94
95     addNativeReference (root, imp);
96     
97     return (NPObject *)obj;
98 }
99
100 bool _NPN_InvokeDefault (NPP npp, NPObject *o, const NPVariant *args, uint32_t argCount, NPVariant *result)
101 {
102     if (o->_class == NPScriptObjectClass) {
103         // No notion of a default function on JS objects.  Just return false, can't handle.
104         return false;
105     }
106     else {
107         if (o->_class->invokeDefault) {
108             return o->_class->invokeDefault (o, args, argCount, result);
109         }
110     }
111     
112     return true;
113 }
114
115 bool _NPN_Invoke (NPP npp, NPObject *o, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
116 {
117     if (o->_class == NPScriptObjectClass) {
118         JavaScriptObject *obj = (JavaScriptObject *)o; 
119         
120         PrivateIdentifier *i = (PrivateIdentifier *)methodName;
121         if (!i->isString)
122             return false;
123             
124         // Lookup the function object.
125         ExecState *exec = obj->root->interpreter()->globalExec();
126         Interpreter::lock();
127         Value func = obj->imp->get (exec, identiferFromNPIdentifier(i->value.string));
128         Interpreter::unlock();
129
130         if (func.isNull()) {
131             NPN_InitializeVariantAsNull(result);
132             return false;
133         }
134         else if ( func.type() == UndefinedType) {
135             NPN_InitializeVariantAsUndefined(result);
136             return false;
137         }
138         else {
139             // Call the function object.
140             ObjectImp *funcImp = static_cast<ObjectImp*>(func.imp());
141             Object thisObj = Object(const_cast<ObjectImp*>(obj->imp));
142             List argList = listFromVariantArgs(exec, args, argCount);
143             Interpreter::lock();
144             Value resultV = funcImp->call (exec, thisObj, argList);
145             Interpreter::unlock();
146
147             // Convert and return the result of the function call.
148             convertValueToNPVariant(exec, resultV, result);
149             return true;
150         }
151     }
152     else {
153         if (o->_class->invoke) {
154             return o->_class->invoke (o, methodName, args, argCount, result);
155         }
156     }
157     
158     return true;
159 }
160
161 bool _NPN_Evaluate (NPP npp, NPObject *o, NPString *s, NPVariant *variant)
162 {
163     if (o->_class == NPScriptObjectClass) {
164         JavaScriptObject *obj = (JavaScriptObject *)o; 
165
166         ExecState *exec = obj->root->interpreter()->globalExec();
167         Object thisObj = Object(const_cast<ObjectImp*>(obj->imp));
168         Value result;
169         
170         Interpreter::lock();
171         NPUTF16 *scriptString;
172         unsigned int UTF16Length;
173         convertNPStringToUTF16 (s, &scriptString, &UTF16Length);    // requires free() of returned memory.
174         Completion completion = obj->root->interpreter()->evaluate(UString(), 0, UString((const UChar *)scriptString,UTF16Length));
175         ComplType type = completion.complType();
176         
177         if (type == Normal) {
178             result = completion.value();
179             if (result.isNull()) {
180                 result = Undefined();
181             }
182         }
183         else
184             result = Undefined();
185             
186         Interpreter::unlock();
187         
188         free ((void *)scriptString);
189         
190         convertValueToNPVariant(exec, result, variant);
191     
192         return true;
193     }
194     return false;
195 }
196
197 bool _NPN_GetProperty (NPP npp, NPObject *o, NPIdentifier propertyName, NPVariant *variant)
198 {
199     if (o->_class == NPScriptObjectClass) {
200         JavaScriptObject *obj = (JavaScriptObject *)o; 
201         ExecState *exec = obj->root->interpreter()->globalExec();
202
203         PrivateIdentifier *i = (PrivateIdentifier *)propertyName;
204         if (i->isString) {
205             if (!obj->imp->hasProperty (exec, identiferFromNPIdentifier(i->value.string))) {
206                 NPN_InitializeVariantAsNull(variant);
207                 return false;
208             }
209         }
210         else {
211             if (!obj->imp->hasProperty (exec, i->value.number)) {
212                 NPN_InitializeVariantAsNull(variant);
213                 return false;
214             }
215         }
216         
217         Interpreter::lock();
218         Value result;
219         if (i->isString) {
220             result = obj->imp->get (exec, identiferFromNPIdentifier(i->value.string));
221         }
222         else {
223             result = obj->imp->get (exec, i->value.number);
224         }
225         Interpreter::unlock();
226
227         if (result.isNull()) {
228             NPN_InitializeVariantAsNull(variant);
229             return false;
230         }
231         else if (result.type() == UndefinedType) {
232             NPN_InitializeVariantAsUndefined(variant);
233             return false;
234         }
235         else {
236             convertValueToNPVariant(exec, result, variant);
237         }
238
239         return true;
240     }
241     else if (o->_class->hasProperty && o->_class->getProperty) {
242         if (o->_class->hasProperty (o, propertyName)) {
243             return o->_class->getProperty (o, propertyName, variant);
244         }
245         else {
246             return false;
247         }
248     }
249     return false;
250 }
251
252 bool _NPN_SetProperty (NPP npp, NPObject *o, NPIdentifier propertyName, const NPVariant *variant)
253 {
254     if (o->_class == NPScriptObjectClass) {
255         JavaScriptObject *obj = (JavaScriptObject *)o; 
256
257         ExecState *exec = obj->root->interpreter()->globalExec();
258         Interpreter::lock();
259         Value result;
260         PrivateIdentifier *i = (PrivateIdentifier *)propertyName;
261         if (i->isString) {
262             obj->imp->put (exec, identiferFromNPIdentifier(i->value.string), convertNPVariantToValue(exec, variant));
263         }
264         else {
265             obj->imp->put (exec, i->value.number, convertNPVariantToValue(exec, variant));
266         }
267         Interpreter::unlock();
268         
269         return true;
270     }
271     else if (o->_class->setProperty) {
272         return o->_class->setProperty (o, propertyName, variant);
273     }
274     return false;
275 }
276
277 bool _NPN_RemoveProperty (NPP npp, NPObject *o, NPIdentifier propertyName)
278 {
279     if (o->_class == NPScriptObjectClass) {
280         JavaScriptObject *obj = (JavaScriptObject *)o; 
281         ExecState *exec = obj->root->interpreter()->globalExec();
282
283         PrivateIdentifier *i = (PrivateIdentifier *)propertyName;
284         if (i->isString) {
285             if (!obj->imp->hasProperty (exec, identiferFromNPIdentifier(i->value.string))) {
286                 return false;
287             }
288         }
289         else {
290             if (!obj->imp->hasProperty (exec, i->value.number)) {
291                 return false;
292             }
293         }
294
295         Interpreter::lock();
296         if (i->isString) {
297             obj->imp->deleteProperty (exec, identiferFromNPIdentifier(i->value.string));
298         }
299         else {
300             obj->imp->deleteProperty (exec, i->value.number);
301         }
302         Interpreter::unlock();
303         
304         return true;
305     }
306     return false;
307 }
308
309 bool _NPN_HasProperty(NPP npp, NPObject *o, NPIdentifier propertyName)
310 {
311     if (o->_class == NPScriptObjectClass) {
312         JavaScriptObject *obj = (JavaScriptObject *)o; 
313         ExecState *exec = obj->root->interpreter()->globalExec();
314
315         PrivateIdentifier *i = (PrivateIdentifier *)propertyName;
316         // String identifier?
317         if (i->isString) {
318             ExecState *exec = obj->root->interpreter()->globalExec();
319             Interpreter::lock();
320             bool result = obj->imp->hasProperty (exec, identiferFromNPIdentifier(i->value.string));
321             Interpreter::unlock();
322             return result;
323         }
324         
325         // Numeric identifer
326         Interpreter::lock();
327         bool result = obj->imp->hasProperty (exec, i->value.number);
328         Interpreter::unlock();
329         return result;
330     }
331     else if (o->_class->hasProperty) {
332         return o->_class->hasProperty (o, propertyName);
333     }
334     
335     return false;
336 }
337
338 bool _NPN_HasMethod(NPP npp, NPObject *o, NPIdentifier methodName)
339 {
340     if (o->_class == NPScriptObjectClass) {
341         JavaScriptObject *obj = (JavaScriptObject *)o; 
342         
343         PrivateIdentifier *i = (PrivateIdentifier *)methodName;
344         if (!i->isString)
345             return false;
346             
347         // Lookup the function object.
348         ExecState *exec = obj->root->interpreter()->globalExec();
349         Interpreter::lock();
350         Value func = obj->imp->get (exec, identiferFromNPIdentifier(i->value.string));
351         Interpreter::unlock();
352
353         if (func.isNull() || func.type() == UndefinedType) {
354             return false;
355         }
356         
357         return true;
358     }
359     
360     else if (o->_class->hasMethod) {
361         return o->_class->hasMethod (o, methodName);
362     }
363     
364     return false;
365 }
366
367 void _NPN_SetException (NPObject *o, NPString *message)
368 {
369     if (o->_class == NPScriptObjectClass) {
370         JavaScriptObject *obj = (JavaScriptObject *)o; 
371         ExecState *exec = obj->root->interpreter()->globalExec();
372         Interpreter::lock();
373         char *msg = (char *)malloc (message->UTF8Length + 1);
374         strncpy (msg, message->UTF8Characters, message->UTF8Length);
375         msg[message->UTF8Length] = 0;
376         Object err = Error::create(exec, GeneralError, msg);
377         free (msg);
378         exec->setException (err);
379         Interpreter::unlock();
380     }
381 }