403a59f122b11190504ee492c03dbf71de5700da
[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     NSLog (@"%s:%d:  not yet implemented", __PRETTY_FUNCTION__, __LINE__);
118     return NO;
119 }
120
121 static KJS::List listFromNSArray(ExecState *exec, NSArray *array)
122 {
123     long i, numObjects = array ? [array count] : 0;
124     KJS::List aList;
125     
126     for (i = 0; i < numObjects; i++) {
127         id anObject = [array objectAtIndex:i];
128         aList.append (convertObjcValueToValue(exec, &anObject, ObjcObjectType));
129     }
130     return aList;
131 }
132
133 - (id)callWebScriptMethod:(NSString *)name withArguments:(NSArray *)args
134 {
135     // Lookup the function object.
136     ExecState *exec = _private->root->interpreter()->globalExec();
137     Interpreter::lock();
138     
139     Value v = convertObjcValueToValue(exec, &name, ObjcObjectType);
140     Identifier identifier(v.toString(exec));
141     Value func = [self _imp]->get (exec, identifier);
142     Interpreter::unlock();
143     if (func.isNull() || func.type() == UndefinedType) {
144         // Maybe throw an exception here?
145         return 0;
146     }
147
148     // Call the function object.    
149     Interpreter::lock();
150     ObjectImp *funcImp = static_cast<ObjectImp*>(func.imp());
151     Object thisObj = Object(const_cast<ObjectImp*>([self _imp]));
152     List argList = listFromNSArray(exec, args);
153     Value result = funcImp->call (exec, thisObj, argList);
154     Interpreter::unlock();
155
156     if (exec->hadException()) {
157         LOG_EXCEPTION (exec);
158         result = Undefined();
159     }
160
161     // Convert and return the result of the function call.
162     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
163
164     _didExecute(self);
165         
166     return resultObj;
167 }
168
169 - (id)evaluateWebScript:(NSString *)script
170 {
171     ExecState *exec = _private->root->interpreter()->globalExec();
172     Object thisObj = Object(const_cast<ObjectImp*>([self _imp]));
173     Value result;
174     
175     Interpreter::lock();
176     
177     Value v = convertObjcValueToValue(exec, &script, ObjcObjectType);
178     Completion completion = _private->root->interpreter()->evaluate(UString(), 0, v.toString(exec));
179     ComplType type = completion.complType();
180     
181     if (type == Normal) {
182         result = completion.value();
183         if (result.isNull()) {
184             result = Undefined();
185         }
186     }
187     else
188         result = Undefined();
189
190     Interpreter::unlock();
191     
192     if (exec->hadException()) {
193         LOG_EXCEPTION (exec);
194         result = Undefined();
195     }
196
197     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
198
199     _didExecute(self);
200     
201     return resultObj;
202 }
203
204 - (void)setValue:(id)value forKey:(NSString *)key
205 {
206     ExecState *exec = _private->root->interpreter()->globalExec();
207     Interpreter::lock();
208     Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
209     [self _imp]->put (exec, Identifier (v.toString(exec)), (convertObjcValueToValue(exec, &value, ObjcObjectType)));
210     Interpreter::unlock();
211
212     if (exec->hadException()) {
213         LOG_EXCEPTION (exec);
214     }
215
216     _didExecute(self);
217 }
218
219 - (id)valueForKey:(NSString *)key
220 {
221     ExecState *exec = _private->root->interpreter()->globalExec();
222     Interpreter::lock();
223     Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
224     Value result = [self _imp]->get (exec, Identifier (v.toString(exec)));
225     Interpreter::unlock();
226     
227     if (exec->hadException()) {
228         LOG_EXCEPTION (exec);
229         result = Undefined();
230     }
231
232     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
233
234     _didExecute(self);
235     
236     return resultObj;
237 }
238
239 - (void)removeWebScriptKey:(NSString *)key;
240 {
241     ExecState *exec = _private->root->interpreter()->globalExec();
242     Interpreter::lock();
243     Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
244     [self _imp]->deleteProperty (exec, Identifier (v.toString(exec)));
245     Interpreter::unlock();
246
247     if (exec->hadException()) {
248         LOG_EXCEPTION (exec);
249     }
250
251     _didExecute(self);
252 }
253
254 - (NSString *)stringRepresentation
255 {
256     Interpreter::lock();
257     Object thisObj = Object(const_cast<ObjectImp*>([self _imp]));
258     ExecState *exec = _private->root->interpreter()->globalExec();
259     
260     id result = convertValueToObjcValue(exec, thisObj, ObjcObjectType).objectValue;
261
262     Interpreter::unlock();
263     
264     id resultObj = [result description];
265
266     _didExecute(self);
267
268     return resultObj;
269 }
270
271 - (id)webScriptValueAtIndex:(unsigned int)index;
272 {
273     ExecState *exec = _private->root->interpreter()->globalExec();
274     Interpreter::lock();
275     Value result = [self _imp]->get (exec, (unsigned)index);
276     Interpreter::unlock();
277
278     if (exec->hadException()) {
279         LOG_EXCEPTION (exec);
280         result = Undefined();
281     }
282
283     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
284
285     _didExecute(self);
286
287     return resultObj;
288 }
289
290 - (void)setWebScriptValueAtIndex:(unsigned int)index value:(id)value;
291 {
292     ExecState *exec = _private->root->interpreter()->globalExec();
293     Interpreter::lock();
294     [self _imp]->put (exec, (unsigned)index, (convertObjcValueToValue(exec, &value, ObjcObjectType)));
295     Interpreter::unlock();
296
297     if (exec->hadException()) {
298         LOG_EXCEPTION (exec);
299     }
300
301     _didExecute(self);
302 }
303
304 - (void)setException: (NSString *)description;
305 {
306     ExecState *exec = _private->root->interpreter()->globalExec();
307     Object err = Error::create(exec, GeneralError, [description UTF8String]);
308     exec->setException (err);
309 }
310
311 + (id)_convertValueToObjcValue:(KJS::Value)value root:(const Bindings::RootObject *)root
312 {
313     id result = 0;
314
315     // First see if we have a ObjC instance.
316     if (value.type() == KJS::ObjectType){
317         ObjectImp *objectImp = static_cast<ObjectImp*>(value.imp());
318         if (strcmp(objectImp->classInfo()->className, "RuntimeObject") == 0) {
319             RuntimeObjectImp *imp = static_cast<RuntimeObjectImp *>(value.imp());
320             ObjcInstance *instance = static_cast<ObjcInstance*>(imp->getInternalInstance());
321             if (instance)
322                 result = instance->getObject();
323         }
324         // Convert to a WebScriptObject
325         else {
326             result = [[[WebScriptObject alloc] _initWithObjectImp:objectImp root:root] autorelease];
327         }
328     }
329     
330     // Convert JavaScript String value to NSString?
331     else if (value.type() == KJS::StringType) {
332         StringImp *s = static_cast<KJS::StringImp*>(value.imp());
333         UString u = s->value();
334         
335         NSString *string = [NSString stringWithCharacters:(const unichar*)u.data() length:u.size()];
336         result = string;
337     }
338     
339     // Convert JavaScript Number value to NSNumber?
340     else if (value.type() == KJS::NumberType) {
341         Number n = Number::dynamicCast(value);
342         result = [NSNumber numberWithDouble:n.value()];
343     }
344     
345     else if (value.type() == KJS::BooleanType) {
346         KJS::BooleanImp *b = static_cast<KJS::BooleanImp*>(value.imp());
347         result = [NSNumber numberWithBool:b->value()];
348     }
349     
350     return result;
351 }
352
353 @end
354
355
356 @implementation WebUndefined
357
358 static WebUndefined *sharedUndefined = 0;
359
360 + (WebUndefined *)undefined
361 {
362     if (!sharedUndefined)
363         sharedUndefined = [[WebUndefined alloc] init];
364     return sharedUndefined;
365 }
366
367 - (id)initWithCoder:(NSCoder *)coder
368 {
369     return [WebUndefined undefined];
370 }
371
372 - (void)encodeWithCoder:(NSCoder *)encoder
373 {
374 }
375
376 - (id)copyWithZone:(NSZone *)zone
377 {
378     return [WebUndefined undefined];
379 }
380
381 - (id)retain {
382     return [WebUndefined undefined];
383 }
384
385 - (void)release {
386 }
387
388 - (unsigned)retainCount {
389     return 0xFFFFFFFF;
390 }
391
392 - (id)autorelease {
393     return [WebUndefined undefined];
394 }
395
396 - (void)dealloc {
397 }
398
399 - (id)copy {
400     return [WebUndefined undefined];
401 }
402
403 - (id)replacementObjectForPortCoder:(NSPortCoder *)encoder {
404     return [WebUndefined undefined];
405 }
406
407 @end