992e7a9b0cbd0388ced361a136c52e9a8050b2b6
[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 static NPClass *javascriptClass = &_javascriptClass;
75 NPClass *NPScriptObjectClass = javascriptClass;
76
77 Identifier identiferFromNPIdentifier(const NPUTF8 *name)
78 {
79     NPUTF16 *methodName;
80     unsigned int UTF16Length;
81     
82     convertUTF8ToUTF16 (name, -1, &methodName, &UTF16Length); // requires free() of returned memory.
83     Identifier identifier ((const KJS::UChar*)methodName, UTF16Length);
84     free ((void *)methodName);
85     
86     return identifier;
87 }
88
89 NPObject *_NPN_CreateScriptObject (NPP npp, KJS::ObjectImp *imp, KJS::Bindings::RootObject *root)
90 {
91     JavaScriptObject *obj = (JavaScriptObject *)_NPN_CreateObject(npp, NPScriptObjectClass);
92
93     obj->imp = imp;
94     obj->root = root;    
95
96     addNativeReference (root, imp);
97     
98     return (NPObject *)obj;
99 }
100
101 bool _NPN_InvokeDefault (NPP npp, NPObject *o, const NPVariant *args, uint32_t argCount, NPVariant *result)
102 {
103     if (o->_class == NPScriptObjectClass) {
104         // No notion of a default function on JS objects.  Just return false, can't handle.
105         return false;
106     }
107     else {
108         if (o->_class->invokeDefault) {
109             return o->_class->invokeDefault (o, args, argCount, result);
110         }
111     }
112     
113     return true;
114 }
115
116 bool _NPN_Invoke (NPP npp, NPObject *o, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
117 {
118     if (o->_class == NPScriptObjectClass) {
119         JavaScriptObject *obj = (JavaScriptObject *)o; 
120         
121         PrivateIdentifier *i = (PrivateIdentifier *)methodName;
122         if (!i->isString)
123             return false;
124             
125         // Lookup the function object.
126         ExecState *exec = obj->root->interpreter()->globalExec();
127         Interpreter::lock();
128         Value func = obj->imp->get (exec, identiferFromNPIdentifier(i->value.string));
129         Interpreter::unlock();
130
131         if (func.isNull()) {
132             NPN_InitializeVariantAsNull(result);
133             return false;
134         }
135         else if ( func.type() == UndefinedType) {
136             NPN_InitializeVariantAsUndefined(result);
137             return false;
138         }
139         else {
140             // Call the function object.
141             ObjectImp *funcImp = static_cast<ObjectImp*>(func.imp());
142             Object thisObj = Object(const_cast<ObjectImp*>(obj->imp));
143             List argList = listFromVariantArgs(exec, args, argCount);
144             Interpreter::lock();
145             Value resultV = funcImp->call (exec, thisObj, argList);
146             Interpreter::unlock();
147
148             // Convert and return the result of the function call.
149             convertValueToNPVariant(exec, resultV, result);
150             return true;
151         }
152     }
153     else {
154         if (o->_class->invoke) {
155             return o->_class->invoke (o, methodName, args, argCount, result);
156         }
157     }
158     
159     return true;
160 }
161
162 bool _NPN_Evaluate (NPP npp, NPObject *o, NPString *s, NPVariant *variant)
163 {
164     if (o->_class == NPScriptObjectClass) {
165         JavaScriptObject *obj = (JavaScriptObject *)o; 
166
167         ExecState *exec = obj->root->interpreter()->globalExec();
168         Object thisObj = Object(const_cast<ObjectImp*>(obj->imp));
169         Value result;
170         
171         Interpreter::lock();
172         NPUTF16 *scriptString;
173         unsigned int UTF16Length;
174         convertNPStringToUTF16 (s, &scriptString, &UTF16Length);    // requires free() of returned memory.
175         Completion completion = obj->root->interpreter()->evaluate(UString(), 0, UString((const UChar *)scriptString,UTF16Length));
176         ComplType type = completion.complType();
177         
178         if (type == Normal) {
179             result = completion.value();
180             if (result.isNull()) {
181                 result = Undefined();
182             }
183         }
184         else
185             result = Undefined();
186             
187         Interpreter::unlock();
188         
189         free ((void *)scriptString);
190         
191         convertValueToNPVariant(exec, result, variant);
192     
193         return true;
194     }
195     return false;
196 }
197
198 bool _NPN_GetProperty (NPP npp, NPObject *o, NPIdentifier propertyName, NPVariant *variant)
199 {
200     if (o->_class == NPScriptObjectClass) {
201         JavaScriptObject *obj = (JavaScriptObject *)o; 
202         ExecState *exec = obj->root->interpreter()->globalExec();
203
204         PrivateIdentifier *i = (PrivateIdentifier *)propertyName;
205         if (i->isString) {
206             if (!obj->imp->hasProperty (exec, identiferFromNPIdentifier(i->value.string))) {
207                 NPN_InitializeVariantAsNull(variant);
208                 return false;
209             }
210         }
211         else {
212             if (!obj->imp->hasProperty (exec, i->value.number)) {
213                 NPN_InitializeVariantAsNull(variant);
214                 return false;
215             }
216         }
217         
218         Interpreter::lock();
219         Value result;
220         if (i->isString) {
221             result = obj->imp->get (exec, identiferFromNPIdentifier(i->value.string));
222         }
223         else {
224             result = obj->imp->get (exec, i->value.number);
225         }
226         Interpreter::unlock();
227
228         if (result.isNull()) {
229             NPN_InitializeVariantAsNull(variant);
230             return false;
231         }
232         else if (result.type() == UndefinedType) {
233             NPN_InitializeVariantAsUndefined(variant);
234             return false;
235         }
236         else {
237             convertValueToNPVariant(exec, result, variant);
238         }
239
240         return true;
241     }
242     else if (o->_class->hasProperty && o->_class->getProperty) {
243         if (o->_class->hasProperty (o, propertyName)) {
244             return o->_class->getProperty (o, propertyName, variant);
245         }
246         else {
247             return false;
248         }
249     }
250     return false;
251 }
252
253 bool _NPN_SetProperty (NPP npp, NPObject *o, NPIdentifier propertyName, const NPVariant *variant)
254 {
255     if (o->_class == NPScriptObjectClass) {
256         JavaScriptObject *obj = (JavaScriptObject *)o; 
257
258         ExecState *exec = obj->root->interpreter()->globalExec();
259         Interpreter::lock();
260         Value result;
261         PrivateIdentifier *i = (PrivateIdentifier *)propertyName;
262         if (i->isString) {
263             obj->imp->put (exec, identiferFromNPIdentifier(i->value.string), convertNPVariantToValue(exec, variant));
264         }
265         else {
266             obj->imp->put (exec, i->value.number, convertNPVariantToValue(exec, variant));
267         }
268         Interpreter::unlock();
269         
270         return true;
271     }
272     else if (o->_class->setProperty) {
273         return o->_class->setProperty (o, propertyName, variant);
274     }
275     return false;
276 }
277
278 bool _NPN_RemoveProperty (NPP npp, NPObject *o, NPIdentifier propertyName)
279 {
280     if (o->_class == NPScriptObjectClass) {
281         JavaScriptObject *obj = (JavaScriptObject *)o; 
282         ExecState *exec = obj->root->interpreter()->globalExec();
283
284         PrivateIdentifier *i = (PrivateIdentifier *)propertyName;
285         if (i->isString) {
286             if (!obj->imp->hasProperty (exec, identiferFromNPIdentifier(i->value.string))) {
287                 return false;
288             }
289         }
290         else {
291             if (!obj->imp->hasProperty (exec, i->value.number)) {
292                 return false;
293             }
294         }
295
296         Interpreter::lock();
297         if (i->isString) {
298             obj->imp->deleteProperty (exec, identiferFromNPIdentifier(i->value.string));
299         }
300         else {
301             obj->imp->deleteProperty (exec, i->value.number);
302         }
303         Interpreter::unlock();
304         
305         return true;
306     }
307     return false;
308 }
309
310 bool _NPN_HasProperty(NPP npp, NPObject *o, NPIdentifier propertyName)
311 {
312     if (o->_class == NPScriptObjectClass) {
313         JavaScriptObject *obj = (JavaScriptObject *)o; 
314         ExecState *exec = obj->root->interpreter()->globalExec();
315
316         PrivateIdentifier *i = (PrivateIdentifier *)propertyName;
317         // String identifier?
318         if (i->isString) {
319             ExecState *exec = obj->root->interpreter()->globalExec();
320             Interpreter::lock();
321             bool result = obj->imp->hasProperty (exec, identiferFromNPIdentifier(i->value.string));
322             Interpreter::unlock();
323             return result;
324         }
325         
326         // Numeric identifer
327         Interpreter::lock();
328         bool result = obj->imp->hasProperty (exec, i->value.number);
329         Interpreter::unlock();
330         return result;
331     }
332     else if (o->_class->hasProperty) {
333         return o->_class->hasProperty (o, propertyName);
334     }
335     
336     return false;
337 }
338
339 bool _NPN_HasMethod(NPP npp, NPObject *o, NPIdentifier methodName)
340 {
341     if (o->_class == NPScriptObjectClass) {
342         JavaScriptObject *obj = (JavaScriptObject *)o; 
343         
344         PrivateIdentifier *i = (PrivateIdentifier *)methodName;
345         if (!i->isString)
346             return false;
347             
348         // Lookup the function object.
349         ExecState *exec = obj->root->interpreter()->globalExec();
350         Interpreter::lock();
351         Value func = obj->imp->get (exec, identiferFromNPIdentifier(i->value.string));
352         Interpreter::unlock();
353
354         if (func.isNull() || func.type() == UndefinedType) {
355             return false;
356         }
357         
358         return true;
359     }
360     
361     else if (o->_class->hasMethod) {
362         return o->_class->hasMethod (o, methodName);
363     }
364     
365     return false;
366 }