2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #import <JavaScriptCore/WebScriptObjectPrivate.h>
28 #include <JavaScriptCore/internal.h>
29 #include <JavaScriptCore/list.h>
30 #include <JavaScriptCore/value.h>
32 #include <objc_jsobject.h>
33 #include <objc_instance.h>
34 #include <objc_utility.h>
36 #include <runtime_object.h>
37 #include <runtime_root.h>
39 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3
41 @interface NSObject (WebExtras)
48 using namespace KJS::Bindings;
50 #define LOG_EXCEPTION(exec) \
51 if (Interpreter::shouldPrintExceptions()) \
52 NSLog (@"%s:%d:[%d] JavaScript exception: %s\n", __FILE__, __LINE__, getpid(), exec->exception().toObject(exec).get(exec, messagePropertyName).toString(exec).ascii());
54 @implementation WebScriptObjectPrivate
58 @implementation WebScriptObject
60 static void _didExecute(WebScriptObject *obj)
62 ExecState *exec = [obj _executionContext]->interpreter()->globalExec();
63 KJSDidExecuteFunctionPtr func = Instance::didExecuteFunction();
65 func (exec, static_cast<KJS::ObjectImp*>([obj _executionContext]->rootObjectImp()));
68 - (void)_initializeWithObjectImp:(KJS::ObjectImp *)imp root:(const Bindings::RootObject *)root
71 _private->root = root;
73 addNativeReference (root, imp);
76 - _initWithObjectImp:(KJS::ObjectImp *)imp root:(const Bindings::RootObject *)root
83 _private = [[WebScriptObjectPrivate alloc] init];
85 [self _initializeWithObjectImp:imp root:root];
90 - (KJS::ObjectImp *)_imp
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];
100 - (const KJS::Bindings::RootObject *)_executionContext
102 return _private->root;
107 removeNativeReference(_private->imp);
115 removeNativeReference(_private->imp);
120 + (BOOL)throwException:(NSString *)exceptionMessage
122 InterpreterImp *first, *interp = InterpreterImp::firstInterpreter();
124 // This code assumes that we only ever have one running interpreter. A
125 // good assumption for now, as we depend on that elsewhere. However,
126 // in the future we may have the ability to run multiple interpreters,
127 // in which case this will have to change.
130 ExecState *exec = interp->globalExec();
131 // If the interpreter has a context, we set the exception.
132 if (interp->context()) {
133 Object err = Error::create(exec, GeneralError, [exceptionMessage UTF8String]);
134 exec->setException (err);
137 interp = interp->nextInterpreter();
138 } while (interp != first);
143 static KJS::List listFromNSArray(ExecState *exec, NSArray *array)
145 long i, numObjects = array ? [array count] : 0;
148 for (i = 0; i < numObjects; i++) {
149 id anObject = [array objectAtIndex:i];
150 aList.append (convertObjcValueToValue(exec, &anObject, ObjcObjectType));
155 - (id)callWebScriptMethod:(NSString *)name withArguments:(NSArray *)args
157 if (![self _executionContext])
160 // Lookup the function object.
161 ExecState *exec = [self _executionContext]->interpreter()->globalExec();
164 Value v = convertObjcValueToValue(exec, &name, ObjcObjectType);
165 Identifier identifier(v.toString(exec));
166 Value func = [self _imp]->get (exec, identifier);
167 Interpreter::unlock();
168 if (func.isNull() || func.type() == UndefinedType) {
169 // Maybe throw an exception here?
173 // Call the function object.
175 ObjectImp *funcImp = static_cast<ObjectImp*>(func.imp());
176 Object thisObj = Object(const_cast<ObjectImp*>([self _imp]));
177 List argList = listFromNSArray(exec, args);
178 Value result = funcImp->call (exec, thisObj, argList);
179 Interpreter::unlock();
181 if (exec->hadException()) {
182 LOG_EXCEPTION (exec);
183 result = Undefined();
186 // Convert and return the result of the function call.
187 id resultObj = [WebScriptObject _convertValueToObjcValue:result root:[self _executionContext]];
194 - (id)evaluateWebScript:(NSString *)script
196 if (![self _executionContext])
199 ExecState *exec = [self _executionContext]->interpreter()->globalExec();
200 Object thisObj = Object(const_cast<ObjectImp*>([self _imp]));
205 Value v = convertObjcValueToValue(exec, &script, ObjcObjectType);
206 Completion completion = [self _executionContext]->interpreter()->evaluate(UString(), 0, v.toString(exec));
207 ComplType type = completion.complType();
209 if (type == Normal) {
210 result = completion.value();
211 if (result.isNull()) {
212 result = Undefined();
216 result = Undefined();
218 Interpreter::unlock();
220 if (exec->hadException()) {
221 LOG_EXCEPTION (exec);
222 result = Undefined();
225 id resultObj = [WebScriptObject _convertValueToObjcValue:result root:[self _executionContext]];
232 - (void)setValue:(id)value forKey:(NSString *)key
234 if (![self _executionContext])
237 ExecState *exec = [self _executionContext]->interpreter()->globalExec();
239 Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
240 [self _imp]->put (exec, Identifier (v.toString(exec)), (convertObjcValueToValue(exec, &value, ObjcObjectType)));
241 Interpreter::unlock();
243 if (exec->hadException()) {
244 LOG_EXCEPTION (exec);
250 - (id)valueForKey:(NSString *)key
252 if (![self _executionContext])
255 ExecState *exec = [self _executionContext]->interpreter()->globalExec();
257 Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
258 Value result = [self _imp]->get (exec, Identifier (v.toString(exec)));
259 Interpreter::unlock();
261 if (exec->hadException()) {
262 LOG_EXCEPTION (exec);
263 result = Undefined();
266 id resultObj = [WebScriptObject _convertValueToObjcValue:result root:[self _executionContext]];
273 - (void)removeWebScriptKey:(NSString *)key;
275 if (![self _executionContext])
278 ExecState *exec = [self _executionContext]->interpreter()->globalExec();
280 Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
281 [self _imp]->deleteProperty (exec, Identifier (v.toString(exec)));
282 Interpreter::unlock();
284 if (exec->hadException()) {
285 LOG_EXCEPTION (exec);
291 - (NSString *)stringRepresentation
294 Object thisObj = Object(const_cast<ObjectImp*>([self _imp]));
295 ExecState *exec = [self _executionContext]->interpreter()->globalExec();
297 id result = convertValueToObjcValue(exec, thisObj, ObjcObjectType).objectValue;
299 Interpreter::unlock();
301 id resultObj = [result description];
308 - (id)webScriptValueAtIndex:(unsigned int)index;
310 if (![self _executionContext])
313 ExecState *exec = [self _executionContext]->interpreter()->globalExec();
315 Value result = [self _imp]->get (exec, (unsigned)index);
316 Interpreter::unlock();
318 if (exec->hadException()) {
319 LOG_EXCEPTION (exec);
320 result = Undefined();
323 id resultObj = [WebScriptObject _convertValueToObjcValue:result root:[self _executionContext]];
330 - (void)setWebScriptValueAtIndex:(unsigned int)index value:(id)value;
332 if (![self _executionContext])
335 ExecState *exec = [self _executionContext]->interpreter()->globalExec();
337 [self _imp]->put (exec, (unsigned)index, (convertObjcValueToValue(exec, &value, ObjcObjectType)));
338 Interpreter::unlock();
340 if (exec->hadException()) {
341 LOG_EXCEPTION (exec);
347 - (void)setException: (NSString *)description;
349 if (![self _executionContext])
352 ExecState *exec = [self _executionContext]->interpreter()->globalExec();
353 Object err = Error::create(exec, GeneralError, [description UTF8String]);
354 exec->setException (err);
357 + (id)_convertValueToObjcValue:(KJS::Value)value root:(const Bindings::RootObject *)root
361 // First see if we have a ObjC instance.
362 if (value.type() == KJS::ObjectType){
363 ObjectImp *objectImp = static_cast<ObjectImp*>(value.imp());
364 if (strcmp(objectImp->classInfo()->className, "RuntimeObject") == 0) {
365 RuntimeObjectImp *imp = static_cast<RuntimeObjectImp *>(value.imp());
366 ObjcInstance *instance = static_cast<ObjcInstance*>(imp->getInternalInstance());
368 result = instance->getObject();
370 // Convert to a WebScriptObject
372 result = [[[WebScriptObject alloc] _initWithObjectImp:objectImp root:root] autorelease];
376 // Convert JavaScript String value to NSString?
377 else if (value.type() == KJS::StringType) {
378 StringImp *s = static_cast<KJS::StringImp*>(value.imp());
379 UString u = s->value();
381 NSString *string = [NSString stringWithCharacters:(const unichar*)u.data() length:u.size()];
385 // Convert JavaScript Number value to NSNumber?
386 else if (value.type() == KJS::NumberType) {
387 Number n = Number::dynamicCast(value);
388 result = [NSNumber numberWithDouble:n.value()];
391 else if (value.type() == KJS::BooleanType) {
392 KJS::BooleanImp *b = static_cast<KJS::BooleanImp*>(value.imp());
393 result = [NSNumber numberWithBool:b->value()];
402 @implementation WebUndefined
404 static WebUndefined *sharedUndefined = 0;
406 + (WebUndefined *)undefined
408 if (!sharedUndefined)
409 sharedUndefined = [[WebUndefined alloc] init];
410 return sharedUndefined;
413 - (id)initWithCoder:(NSCoder *)coder
415 return [WebUndefined undefined];
418 - (void)encodeWithCoder:(NSCoder *)encoder
422 - (id)copyWithZone:(NSZone *)zone
424 return [WebUndefined undefined];
428 return [WebUndefined undefined];
434 - (unsigned)retainCount {
439 return [WebUndefined undefined];
446 return [WebUndefined undefined];
449 - (id)replacementObjectForPortCoder:(NSPortCoder *)encoder {
450 return [WebUndefined undefined];