c07d624bca3fc35f4fa7f625bfb2d4025dd37024
[WebKit-https.git] / JavaScriptCore / bindings / objc / WebScriptObject.mm
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
26 #import <JavaScriptCore/WebScriptObjectPrivate.h>
27
28 #include <JavaScriptCore/internal.h>
29 #include <JavaScriptCore/list.h>
30 #include <JavaScriptCore/value.h>
31
32 #include <objc_jsobject.h>
33 #include <objc_instance.h>
34 #include <objc_utility.h>
35
36 #include <runtime_object.h>
37 #include <runtime_root.h>
38
39 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3
40
41 @interface NSObject (WebExtras)
42 - (void)finalize;
43 @end
44
45 #endif
46
47 using namespace KJS;
48 using namespace KJS::Bindings;
49
50 #define LOG_EXCEPTION(exec) \
51     if (Interpreter::shouldPrintExceptions()) \
52         NSLog (@"%s:%d:  JavaScript exception:  %s\n", __FILE__, __LINE__, exec->exception().toObject(exec).get(exec, messagePropertyName).toString(exec).ascii());
53
54 @implementation WebScriptObjectPrivate
55
56 @end
57
58 @implementation WebScriptObject
59
60 static void _didExecute(WebScriptObject *obj)
61 {
62     ExecState *exec = obj->_private->root->interpreter()->globalExec();
63     KJSDidExecuteFunctionPtr func = Instance::didExecuteFunction();
64     if (func)
65         func (exec, static_cast<KJS::ObjectImp*>(obj->_private->root->rootObjectImp()));
66 }
67
68 - (void)_initializeWithObjectImp:(KJS::ObjectImp *)imp root:(const Bindings::RootObject *)root
69 {
70     _private->imp = imp;
71     _private->root = root;    
72
73     addNativeReference (root, imp);
74 }
75
76 - _initWithObjectImp:(KJS::ObjectImp *)imp root:(const Bindings::RootObject *)root
77 {
78     assert (imp != 0);
79     //assert (root != 0);
80
81     self = [super init];
82
83     _private = [[WebScriptObjectPrivate alloc] init];
84
85     [self _initializeWithObjectImp:imp root:root];
86     
87     return self;
88 }
89
90 - (KJS::ObjectImp *)_imp
91 {
92     if (!_private->imp && _private->isCreatedByDOMWrapper) {
93         // Associate the WebScriptObject with the JS wrapper for the ObjC DOM
94         // wrapper.  This is done on lazily, on demand.
95         [self _initializeScriptDOMNodeImp];
96     }
97     return _private->imp;
98 }
99
100 - (void)dealloc
101 {
102     removeNativeReference(_private->imp);
103     [_private release];
104         
105     [super dealloc];
106 }
107
108 - (void)finalize
109 {
110     removeNativeReference(_private->imp);
111         
112     [super finalize];
113 }
114
115 + (BOOL)throwException:(NSString *)exceptionMessage
116 {
117     InterpreterImp *first, *interp = InterpreterImp::firstInterpreter();
118
119     // This code assumes that we only ever have one running interpreter.  A
120     // good assumption for now, as we depend on that elsewhere.  However,
121     // in the future we may have the ability to run multiple interpreters,
122     // in which case this will have to change.
123     first = interp;
124     do {
125         ExecState *exec = interp->globalExec();
126         // If the interpreter has a context, we set the exception.
127         if (interp->context()) {
128             Object err = Error::create(exec, GeneralError, [exceptionMessage UTF8String]);
129             exec->setException (err);
130             return YES;
131         }
132         interp = interp->nextInterpreter();
133     } while (interp != first);
134     
135     return NO;
136 }
137
138 static KJS::List listFromNSArray(ExecState *exec, NSArray *array)
139 {
140     long i, numObjects = array ? [array count] : 0;
141     KJS::List aList;
142     
143     for (i = 0; i < numObjects; i++) {
144         id anObject = [array objectAtIndex:i];
145         aList.append (convertObjcValueToValue(exec, &anObject, ObjcObjectType));
146     }
147     return aList;
148 }
149
150 - (id)callWebScriptMethod:(NSString *)name withArguments:(NSArray *)args
151 {
152     // Lookup the function object.
153     ExecState *exec = _private->root->interpreter()->globalExec();
154     Interpreter::lock();
155     
156     Value v = convertObjcValueToValue(exec, &name, ObjcObjectType);
157     Identifier identifier(v.toString(exec));
158     Value func = [self _imp]->get (exec, identifier);
159     Interpreter::unlock();
160     if (func.isNull() || func.type() == UndefinedType) {
161         // Maybe throw an exception here?
162         return 0;
163     }
164
165     // Call the function object.    
166     Interpreter::lock();
167     ObjectImp *funcImp = static_cast<ObjectImp*>(func.imp());
168     Object thisObj = Object(const_cast<ObjectImp*>([self _imp]));
169     List argList = listFromNSArray(exec, args);
170     Value result = funcImp->call (exec, thisObj, argList);
171     Interpreter::unlock();
172
173     if (exec->hadException()) {
174         LOG_EXCEPTION (exec);
175         result = Undefined();
176     }
177
178     // Convert and return the result of the function call.
179     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
180
181     _didExecute(self);
182         
183     return resultObj;
184 }
185
186 - (id)evaluateWebScript:(NSString *)script
187 {
188     ExecState *exec = _private->root->interpreter()->globalExec();
189     Object thisObj = Object(const_cast<ObjectImp*>([self _imp]));
190     Value result;
191     
192     Interpreter::lock();
193     
194     Value v = convertObjcValueToValue(exec, &script, ObjcObjectType);
195     Completion completion = _private->root->interpreter()->evaluate(UString(), 0, v.toString(exec));
196     ComplType type = completion.complType();
197     
198     if (type == Normal) {
199         result = completion.value();
200         if (result.isNull()) {
201             result = Undefined();
202         }
203     }
204     else
205         result = Undefined();
206
207     Interpreter::unlock();
208     
209     if (exec->hadException()) {
210         LOG_EXCEPTION (exec);
211         result = Undefined();
212     }
213
214     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
215
216     _didExecute(self);
217     
218     return resultObj;
219 }
220
221 - (void)setValue:(id)value forKey:(NSString *)key
222 {
223     ExecState *exec = _private->root->interpreter()->globalExec();
224     Interpreter::lock();
225     Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
226     [self _imp]->put (exec, Identifier (v.toString(exec)), (convertObjcValueToValue(exec, &value, ObjcObjectType)));
227     Interpreter::unlock();
228
229     if (exec->hadException()) {
230         LOG_EXCEPTION (exec);
231     }
232
233     _didExecute(self);
234 }
235
236 - (id)valueForKey:(NSString *)key
237 {
238     ExecState *exec = _private->root->interpreter()->globalExec();
239     Interpreter::lock();
240     Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
241     Value result = [self _imp]->get (exec, Identifier (v.toString(exec)));
242     Interpreter::unlock();
243     
244     if (exec->hadException()) {
245         LOG_EXCEPTION (exec);
246         result = Undefined();
247     }
248
249     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
250
251     _didExecute(self);
252     
253     return resultObj;
254 }
255
256 - (void)removeWebScriptKey:(NSString *)key;
257 {
258     ExecState *exec = _private->root->interpreter()->globalExec();
259     Interpreter::lock();
260     Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
261     [self _imp]->deleteProperty (exec, Identifier (v.toString(exec)));
262     Interpreter::unlock();
263
264     if (exec->hadException()) {
265         LOG_EXCEPTION (exec);
266     }
267
268     _didExecute(self);
269 }
270
271 - (NSString *)stringRepresentation
272 {
273     Interpreter::lock();
274     Object thisObj = Object(const_cast<ObjectImp*>([self _imp]));
275     ExecState *exec = _private->root->interpreter()->globalExec();
276     
277     id result = convertValueToObjcValue(exec, thisObj, ObjcObjectType).objectValue;
278
279     Interpreter::unlock();
280     
281     id resultObj = [result description];
282
283     _didExecute(self);
284
285     return resultObj;
286 }
287
288 - (id)webScriptValueAtIndex:(unsigned int)index;
289 {
290     ExecState *exec = _private->root->interpreter()->globalExec();
291     Interpreter::lock();
292     Value result = [self _imp]->get (exec, (unsigned)index);
293     Interpreter::unlock();
294
295     if (exec->hadException()) {
296         LOG_EXCEPTION (exec);
297         result = Undefined();
298     }
299
300     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
301
302     _didExecute(self);
303
304     return resultObj;
305 }
306
307 - (void)setWebScriptValueAtIndex:(unsigned int)index value:(id)value;
308 {
309     ExecState *exec = _private->root->interpreter()->globalExec();
310     Interpreter::lock();
311     [self _imp]->put (exec, (unsigned)index, (convertObjcValueToValue(exec, &value, ObjcObjectType)));
312     Interpreter::unlock();
313
314     if (exec->hadException()) {
315         LOG_EXCEPTION (exec);
316     }
317
318     _didExecute(self);
319 }
320
321 - (void)setException: (NSString *)description;
322 {
323     ExecState *exec = _private->root->interpreter()->globalExec();
324     Object err = Error::create(exec, GeneralError, [description UTF8String]);
325     exec->setException (err);
326 }
327
328 + (id)_convertValueToObjcValue:(KJS::Value)value root:(const Bindings::RootObject *)root
329 {
330     id result = 0;
331
332     // First see if we have a ObjC instance.
333     if (value.type() == KJS::ObjectType){
334         ObjectImp *objectImp = static_cast<ObjectImp*>(value.imp());
335         if (strcmp(objectImp->classInfo()->className, "RuntimeObject") == 0) {
336             RuntimeObjectImp *imp = static_cast<RuntimeObjectImp *>(value.imp());
337             ObjcInstance *instance = static_cast<ObjcInstance*>(imp->getInternalInstance());
338             if (instance)
339                 result = instance->getObject();
340         }
341         // Convert to a WebScriptObject
342         else {
343             result = [[[WebScriptObject alloc] _initWithObjectImp:objectImp root:root] autorelease];
344         }
345     }
346     
347     // Convert JavaScript String value to NSString?
348     else if (value.type() == KJS::StringType) {
349         StringImp *s = static_cast<KJS::StringImp*>(value.imp());
350         UString u = s->value();
351         
352         NSString *string = [NSString stringWithCharacters:(const unichar*)u.data() length:u.size()];
353         result = string;
354     }
355     
356     // Convert JavaScript Number value to NSNumber?
357     else if (value.type() == KJS::NumberType) {
358         Number n = Number::dynamicCast(value);
359         result = [NSNumber numberWithDouble:n.value()];
360     }
361     
362     else if (value.type() == KJS::BooleanType) {
363         KJS::BooleanImp *b = static_cast<KJS::BooleanImp*>(value.imp());
364         result = [NSNumber numberWithBool:b->value()];
365     }
366     
367     return result;
368 }
369
370 @end
371
372
373 @implementation WebUndefined
374
375 static WebUndefined *sharedUndefined = 0;
376
377 + (WebUndefined *)undefined
378 {
379     if (!sharedUndefined)
380         sharedUndefined = [[WebUndefined alloc] init];
381     return sharedUndefined;
382 }
383
384 - (id)initWithCoder:(NSCoder *)coder
385 {
386     return [WebUndefined undefined];
387 }
388
389 - (void)encodeWithCoder:(NSCoder *)encoder
390 {
391 }
392
393 - (id)copyWithZone:(NSZone *)zone
394 {
395     return [WebUndefined undefined];
396 }
397
398 - (id)retain {
399     return [WebUndefined undefined];
400 }
401
402 - (void)release {
403 }
404
405 - (unsigned)retainCount {
406     return 0xFFFFFFFF;
407 }
408
409 - (id)autorelease {
410     return [WebUndefined undefined];
411 }
412
413 - (void)dealloc {
414 }
415
416 - (id)copy {
417     return [WebUndefined undefined];
418 }
419
420 - (id)replacementObjectForPortCoder:(NSPortCoder *)encoder {
421     return [WebUndefined undefined];
422 }
423
424 @end