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.
27 #include "objc_runtime.h"
29 #include "objc_instance.h"
30 #include "runtime_array.h"
31 #include "runtime_object.h"
32 #include "WebScriptObject.h"
35 using namespace KJS::Bindings;
37 extern ClassStructPtr KJS::Bindings::webScriptObjectClass()
39 static ClassStructPtr<WebScriptObject> webScriptObjectClass = NSClassFromString(@"WebScriptObject");
40 return webScriptObjectClass;
43 extern ClassStructPtr KJS::Bindings::webUndefinedClass()
45 static ClassStructPtr<WebUndefined> webUndefinedClass = NSClassFromString(@"WebUndefined");
46 return webUndefinedClass;
49 // ---------------------- ObjcMethod ----------------------
51 ObjcMethod::ObjcMethod(ClassStructPtr aClass, const char* name)
54 _selector = name; // Assume ObjC runtime keeps these around forever.
58 const char* ObjcMethod::name() const
63 int ObjcMethod::numParameters() const
65 return [getMethodSignature() numberOfArguments] - 2;
68 NSMethodSignature* ObjcMethod::getMethodSignature() const
70 #if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
71 return [_objcClass instanceMethodSignatureForSelector:sel_registerName(_selector)];
73 return [_objcClass instanceMethodSignatureForSelector:(SEL)_selector];
77 // ---------------------- ObjcField ----------------------
79 ObjcField::ObjcField(Ivar ivar)
81 _ivar = ivar; // Assume ObjectiveC runtime will keep this alive forever
85 ObjcField::ObjcField(CFStringRef name)
88 _name = (CFStringRef)CFRetain(name);
91 const char* ObjcField::name() const
93 #if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
95 return ivar_getName(_ivar);
98 return _ivar->ivar_name;
100 return [(NSString*)_name.get() UTF8String];
103 JSValue* ObjcField::valueFromInstance(ExecState* exec, const Instance* instance) const
105 JSValue* result = jsUndefined();
107 id targetObject = (static_cast<const ObjcInstance*>(instance))->getObject();
109 JSLock::DropAllLocks dropAllLocks; // Can't put this inside the @try scope because it unwinds incorrectly.
112 NSString* key = [NSString stringWithCString:name() encoding:NSASCIIStringEncoding];
113 if (id objcValue = [targetObject valueForKey:key])
114 result = convertObjcValueToValue(exec, &objcValue, ObjcObjectType, instance->rootObject());
115 } @catch(NSException* localException) {
117 throwError(exec, GeneralError, [localException reason]);
124 static id convertValueToObjcObject(ExecState* exec, JSValue* value)
126 RefPtr<RootObject> rootObject = findRootObject(exec->dynamicGlobalObject());
129 return [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:rootObject.get() rootObject:rootObject.get()];
132 void ObjcField::setValueToInstance(ExecState* exec, const Instance* instance, JSValue* aValue) const
134 id targetObject = (static_cast<const ObjcInstance*>(instance))->getObject();
135 id value = convertValueToObjcObject(exec, aValue);
137 JSLock::DropAllLocks dropAllLocks; // Can't put this inside the @try scope because it unwinds incorrectly.
140 NSString* key = [NSString stringWithCString:name() encoding:NSASCIIStringEncoding];
141 [targetObject setValue:value forKey:key];
142 } @catch(NSException* localException) {
144 throwError(exec, GeneralError, [localException reason]);
149 // ---------------------- ObjcArray ----------------------
151 ObjcArray::ObjcArray(ObjectStructPtr a, PassRefPtr<RootObject> rootObject)
157 void ObjcArray::setValueAt(ExecState* exec, unsigned int index, JSValue* aValue) const
159 if (![_array.get() respondsToSelector:@selector(insertObject:atIndex:)]) {
160 throwError(exec, TypeError, "Array is not mutable.");
164 if (index > [_array.get() count]) {
165 throwError(exec, RangeError, "Index exceeds array size.");
169 // Always try to convert the value to an ObjC object, so it can be placed in the
171 ObjcValue oValue = convertValueToObjcValue (exec, aValue, ObjcObjectType);
174 [_array.get() insertObject:oValue.objectValue atIndex:index];
175 } @catch(NSException* localException) {
176 throwError(exec, GeneralError, "Objective-C exception.");
180 JSValue* ObjcArray::valueAt(ExecState* exec, unsigned int index) const
182 if (index > [_array.get() count])
183 return throwError(exec, RangeError, "Index exceeds array size.");
185 id obj = [_array.get() objectAtIndex:index];
187 return convertObjcValueToValue (exec, &obj, ObjcObjectType, _rootObject.get());
188 } @catch(NSException* localException) {
189 return throwError(exec, GeneralError, "Objective-C exception.");
191 return jsUndefined();
194 unsigned int ObjcArray::getLength() const
196 return [_array.get() count];
199 const ClassInfo ObjcFallbackObjectImp::info = { "ObjcFallbackObject", 0, 0 };
201 ObjcFallbackObjectImp::ObjcFallbackObjectImp(ObjcInstance* i, const KJS::Identifier propertyName)
203 , _item(propertyName)
207 bool ObjcFallbackObjectImp::getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot& slot)
209 // keep the prototype from getting called instead of just returning false
210 slot.setUndefined(this);
214 void ObjcFallbackObjectImp::put(ExecState*, const Identifier&, JSValue*, int)
218 bool ObjcFallbackObjectImp::canPut(ExecState*, const Identifier&) const
224 JSType ObjcFallbackObjectImp::type() const
226 id targetObject = _instance->getObject();
228 if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)])
231 return UndefinedType;
234 bool ObjcFallbackObjectImp::implementsCall() const
236 id targetObject = _instance->getObject();
238 if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)])
244 JSValue* ObjcFallbackObjectImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
246 if (thisObj->classInfo() != &KJS::RuntimeObjectImp::info)
247 return throwError(exec, TypeError);
249 JSValue* result = jsUndefined();
251 RuntimeObjectImp* imp = static_cast<RuntimeObjectImp*>(thisObj);
252 Instance* instance = imp->getInternalInstance();
255 return RuntimeObjectImp::throwInvalidAccessError(exec);
259 ObjcInstance* objcInstance = static_cast<ObjcInstance*>(instance);
260 id targetObject = objcInstance->getObject();
262 if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)]){
263 MethodList methodList;
264 ObjcClass* objcClass = static_cast<ObjcClass*>(instance->getClass());
265 ObjcMethod* fallbackMethod = new ObjcMethod (objcClass->isa(), sel_getName(@selector(invokeUndefinedMethodFromWebScript:withArguments:)));
266 fallbackMethod->setJavaScriptName((CFStringRef)[NSString stringWithCString:_item.ascii() encoding:NSASCIIStringEncoding]);
267 methodList.append(fallbackMethod);
268 result = instance->invokeMethod(exec, methodList, args);
269 delete fallbackMethod;
277 bool ObjcFallbackObjectImp::deleteProperty(ExecState*, const Identifier&)
282 JSValue* ObjcFallbackObjectImp::defaultValue(ExecState* exec, JSType hint) const
284 return _instance->getValueOfUndefinedField(exec, _item, hint);
287 bool ObjcFallbackObjectImp::toBoolean(ExecState *) const
289 id targetObject = _instance->getObject();
291 if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)])