diff options
| author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
|---|---|---|
| committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
| commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
| tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/bridge/objc | |
| parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
| download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 | |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/bridge/objc')
| -rw-r--r-- | Source/WebCore/bridge/objc/ObjCRuntimeObject.h | 52 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/ObjCRuntimeObject.mm | 52 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/WebScriptObject.h | 44 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/objc_class.h | 59 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/objc_class.mm | 253 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/objc_header.h | 53 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/objc_instance.h | 86 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/objc_instance.mm | 465 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/objc_runtime.h | 131 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/objc_runtime.mm | 280 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/objc_utility.h | 88 | ||||
| -rw-r--r-- | Source/WebCore/bridge/objc/objc_utility.mm | 373 |
12 files changed, 1936 insertions, 0 deletions
diff --git a/Source/WebCore/bridge/objc/ObjCRuntimeObject.h b/Source/WebCore/bridge/objc/ObjCRuntimeObject.h new file mode 100644 index 0000000..78550b9 --- /dev/null +++ b/Source/WebCore/bridge/objc/ObjCRuntimeObject.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ObjCRuntimeObject_h +#define ObjCRuntimeObject_h + +#include "runtime_object.h" + +namespace JSC { +namespace Bindings { + +class ObjcInstance; + +class ObjCRuntimeObject : public RuntimeObject { +public: + ObjCRuntimeObject(ExecState*, JSGlobalObject*, PassRefPtr<ObjcInstance>); + virtual ~ObjCRuntimeObject(); + + ObjcInstance* getInternalObjCInstance() const; + + static const ClassInfo s_info; + +private: + virtual const ClassInfo* classInfo() const { return &s_info; } +}; + +} +} + +#endif diff --git a/Source/WebCore/bridge/objc/ObjCRuntimeObject.mm b/Source/WebCore/bridge/objc/ObjCRuntimeObject.mm new file mode 100644 index 0000000..d9afdf2 --- /dev/null +++ b/Source/WebCore/bridge/objc/ObjCRuntimeObject.mm @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" + +#import "ObjCRuntimeObject.h" +#import "objc_instance.h" + +namespace JSC { +namespace Bindings { + +const ClassInfo ObjCRuntimeObject::s_info = { "ObjCRuntimeObject", &RuntimeObject::s_info, 0, 0 }; + +ObjCRuntimeObject::ObjCRuntimeObject(ExecState* exec, JSGlobalObject* globalObject, PassRefPtr<ObjcInstance> instance) + : RuntimeObject(exec, globalObject, instance) +{ +} + +ObjCRuntimeObject::~ObjCRuntimeObject() +{ +} + +ObjcInstance* ObjCRuntimeObject::getInternalObjCInstance() const +{ + return static_cast<ObjcInstance*>(getInternalInstance()); +} + + +} +} diff --git a/Source/WebCore/bridge/objc/WebScriptObject.h b/Source/WebCore/bridge/objc/WebScriptObject.h new file mode 100644 index 0000000..6d9ff2c --- /dev/null +++ b/Source/WebCore/bridge/objc/WebScriptObject.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2006 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Foundation/Foundation.h> +#import "runtime_root.h" + +@class WebUndefined; + +@protocol WebScriptObject ++ (NSString *)webScriptNameForSelector:(SEL)aSelector; ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector; ++ (NSString *)webScriptNameForKey:(const char *)name; ++ (BOOL)isKeyExcludedFromWebScript:(const char *)name; + ++ (id)_convertValueToObjcValue:(JSC::JSValue)value originRootObject:(JSC::Bindings::RootObject*)originRootObject rootObject:(JSC::Bindings::RootObject*)rootObject; +- _initWithJSObject:(JSC::JSObject*)imp originRootObject:(PassRefPtr<JSC::Bindings::RootObject>)originRootObject rootObject:(PassRefPtr<JSC::Bindings::RootObject>)rootObject; +- (JSC::JSObject *)_imp; +@end + +@protocol WebUndefined ++ (WebUndefined *)undefined; +@end diff --git a/Source/WebCore/bridge/objc/objc_class.h b/Source/WebCore/bridge/objc/objc_class.h new file mode 100644 index 0000000..eebfd2a --- /dev/null +++ b/Source/WebCore/bridge/objc/objc_class.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef KJS_BINDINGS_OBJC_CLASS_H +#define KJS_BINDINGS_OBJC_CLASS_H + +#include "objc_runtime.h" + +namespace JSC { +namespace Bindings { + +class ObjcClass : public Class +{ +protected: + ObjcClass (ClassStructPtr aClass); // Use classForIsA to create an ObjcClass. + +public: + // Return the cached ObjC of the specified name. + static ObjcClass *classForIsA(ClassStructPtr); + + virtual MethodList methodsNamed(const Identifier&, Instance *instance) const; + virtual Field *fieldNamed(const Identifier&, Instance *instance) const; + + virtual JSValue fallbackObject(ExecState *exec, Instance *instance, const Identifier &propertyName); + + ClassStructPtr isa() { return _isa; } + +private: + ClassStructPtr _isa; + RetainPtr<CFMutableDictionaryRef> _methods; + RetainPtr<CFMutableDictionaryRef> _fields; +}; + +} // namespace Bindings +} // namespace JSC + +#endif diff --git a/Source/WebCore/bridge/objc/objc_class.mm b/Source/WebCore/bridge/objc/objc_class.mm new file mode 100644 index 0000000..2d29499 --- /dev/null +++ b/Source/WebCore/bridge/objc/objc_class.mm @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2004 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "objc_class.h" + +#include "objc_instance.h" +#include "WebScriptObject.h" + +namespace JSC { +namespace Bindings { + +static void deleteMethod(CFAllocatorRef, const void* value) +{ + delete static_cast<const Method*>(value); +} + +static void deleteField(CFAllocatorRef, const void* value) +{ + delete static_cast<const Field*>(value); +} + +const CFDictionaryValueCallBacks MethodDictionaryValueCallBacks = { 0, 0, &deleteMethod, 0 , 0 }; +const CFDictionaryValueCallBacks FieldDictionaryValueCallBacks = { 0, 0, &deleteField, 0 , 0 }; + +ObjcClass::ObjcClass(ClassStructPtr aClass) + : _isa(aClass) + , _methods(AdoptCF, CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &MethodDictionaryValueCallBacks)) + , _fields(AdoptCF, CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &FieldDictionaryValueCallBacks)) +{ +} + +static CFMutableDictionaryRef classesByIsA = 0; + +static void _createClassesByIsAIfNecessary() +{ + if (!classesByIsA) + classesByIsA = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); +} + +ObjcClass* ObjcClass::classForIsA(ClassStructPtr isa) +{ + _createClassesByIsAIfNecessary(); + + ObjcClass* aClass = (ObjcClass*)CFDictionaryGetValue(classesByIsA, isa); + if (!aClass) { + aClass = new ObjcClass(isa); + CFDictionaryAddValue(classesByIsA, isa, aClass); + } + + return aClass; +} + +MethodList ObjcClass::methodsNamed(const Identifier& identifier, Instance*) const +{ + MethodList methodList; + char fixedSizeBuffer[1024]; + char* buffer = fixedSizeBuffer; + CString jsName = identifier.ascii(); + if (!convertJSMethodNameToObjc(jsName.data(), buffer, sizeof(fixedSizeBuffer))) { + int length = jsName.length() + 1; + buffer = new char[length]; + if (!buffer || !convertJSMethodNameToObjc(jsName.data(), buffer, length)) + return methodList; + } + + + RetainPtr<CFStringRef> methodName(AdoptCF, CFStringCreateWithCString(NULL, buffer, kCFStringEncodingASCII)); + Method* method = (Method*)CFDictionaryGetValue(_methods.get(), methodName.get()); + if (method) { + methodList.append(method); + return methodList; + } + + ClassStructPtr thisClass = _isa; + while (thisClass && methodList.isEmpty()) { +#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2 + unsigned numMethodsInClass = 0; + MethodStructPtr* objcMethodList = class_copyMethodList(thisClass, &numMethodsInClass); +#else + void* iterator = 0; + struct objc_method_list* objcMethodList; + while ((objcMethodList = class_nextMethodList(thisClass, &iterator))) { + unsigned numMethodsInClass = objcMethodList->method_count; +#endif + for (unsigned i = 0; i < numMethodsInClass; i++) { +#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2 + MethodStructPtr objcMethod = objcMethodList[i]; + SEL objcMethodSelector = method_getName(objcMethod); +#else + struct objc_method* objcMethod = &objcMethodList->method_list[i]; + SEL objcMethodSelector = objcMethod->method_name; +#endif + const char* objcMethodSelectorName = sel_getName(objcMethodSelector); + NSString* mappedName = nil; + + // See if the class wants to exclude the selector from visibility in JavaScript. + if ([thisClass respondsToSelector:@selector(isSelectorExcludedFromWebScript:)]) + if ([thisClass isSelectorExcludedFromWebScript:objcMethodSelector]) + continue; + + // See if the class want to provide a different name for the selector in JavaScript. + // Note that we do not do any checks to guarantee uniqueness. That's the responsiblity + // of the class. + if ([thisClass respondsToSelector:@selector(webScriptNameForSelector:)]) + mappedName = [thisClass webScriptNameForSelector:objcMethodSelector]; + + if ((mappedName && [mappedName isEqual:(NSString*)methodName.get()]) || strcmp(objcMethodSelectorName, buffer) == 0) { + Method* aMethod = new ObjcMethod(thisClass, objcMethodSelector); // deleted when the dictionary is destroyed + CFDictionaryAddValue(_methods.get(), methodName.get(), aMethod); + methodList.append(aMethod); + break; + } + } +#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2 + thisClass = class_getSuperclass(thisClass); + free(objcMethodList); +#else + } + thisClass = thisClass->super_class; +#endif + } + + if (buffer != fixedSizeBuffer) + delete [] buffer; + + return methodList; +} + +Field* ObjcClass::fieldNamed(const Identifier& identifier, Instance* instance) const +{ + ClassStructPtr thisClass = _isa; + + CString jsName = identifier.ascii(); + RetainPtr<CFStringRef> fieldName(AdoptCF, CFStringCreateWithCString(NULL, jsName.data(), kCFStringEncodingASCII)); + Field* aField = (Field*)CFDictionaryGetValue(_fields.get(), fieldName.get()); + if (aField) + return aField; + + id targetObject = (static_cast<ObjcInstance*>(instance))->getObject(); + id attributes = [targetObject attributeKeys]; + if (attributes) { + // Class overrides attributeKeys, use that array of key names. + unsigned count = [attributes count]; + for (unsigned i = 0; i < count; i++) { + NSString* keyName = [attributes objectAtIndex:i]; + const char* UTF8KeyName = [keyName UTF8String]; // ObjC actually only supports ASCII names. + + // See if the class wants to exclude the selector from visibility in JavaScript. + if ([thisClass respondsToSelector:@selector(isKeyExcludedFromWebScript:)]) + if ([thisClass isKeyExcludedFromWebScript:UTF8KeyName]) + continue; + + // See if the class want to provide a different name for the selector in JavaScript. + // Note that we do not do any checks to guarantee uniqueness. That's the responsiblity + // of the class. + NSString* mappedName = nil; + if ([thisClass respondsToSelector:@selector(webScriptNameForKey:)]) + mappedName = [thisClass webScriptNameForKey:UTF8KeyName]; + + if ((mappedName && [mappedName isEqual:(NSString*)fieldName.get()]) || [keyName isEqual:(NSString*)fieldName.get()]) { + aField = new ObjcField((CFStringRef)keyName); // deleted when the dictionary is destroyed + CFDictionaryAddValue(_fields.get(), fieldName.get(), aField); + break; + } + } + } else { + // Class doesn't override attributeKeys, so fall back on class runtime + // introspection. + + while (thisClass) { +#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2 + unsigned numFieldsInClass = 0; + IvarStructPtr* ivarsInClass = class_copyIvarList(thisClass, &numFieldsInClass); +#else + struct objc_ivar_list* fieldsInClass = thisClass->ivars; + if (fieldsInClass) { + unsigned numFieldsInClass = fieldsInClass->ivar_count; +#endif + for (unsigned i = 0; i < numFieldsInClass; i++) { +#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2 + IvarStructPtr objcIVar = ivarsInClass[i]; + const char* objcIvarName = ivar_getName(objcIVar); +#else + IvarStructPtr objcIVar = &fieldsInClass->ivar_list[i]; + const char* objcIvarName = objcIVar->ivar_name; +#endif + NSString* mappedName = 0; + + // See if the class wants to exclude the selector from visibility in JavaScript. + if ([thisClass respondsToSelector:@selector(isKeyExcludedFromWebScript:)]) + if ([thisClass isKeyExcludedFromWebScript:objcIvarName]) + continue; + + // See if the class want to provide a different name for the selector in JavaScript. + // Note that we do not do any checks to guarantee uniqueness. That's the responsiblity + // of the class. + if ([thisClass respondsToSelector:@selector(webScriptNameForKey:)]) + mappedName = [thisClass webScriptNameForKey:objcIvarName]; + + if ((mappedName && [mappedName isEqual:(NSString*)fieldName.get()]) || strcmp(objcIvarName, jsName.data()) == 0) { + aField = new ObjcField(objcIVar); // deleted when the dictionary is destroyed + CFDictionaryAddValue(_fields.get(), fieldName.get(), aField); + break; + } + } +#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2 + thisClass = class_getSuperclass(thisClass); + free(ivarsInClass); +#else + } + thisClass = thisClass->super_class; +#endif + } + } + + return aField; +} + +JSValue ObjcClass::fallbackObject(ExecState* exec, Instance* instance, const Identifier &propertyName) +{ + ObjcInstance* objcInstance = static_cast<ObjcInstance*>(instance); + id targetObject = objcInstance->getObject(); + + if (![targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)]) + return jsUndefined(); + return new (exec) ObjcFallbackObjectImp(exec, exec->lexicalGlobalObject(), objcInstance, propertyName); +} + +} +} diff --git a/Source/WebCore/bridge/objc/objc_header.h b/Source/WebCore/bridge/objc/objc_header.h new file mode 100644 index 0000000..07954a1 --- /dev/null +++ b/Source/WebCore/bridge/objc/objc_header.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef KJS_BINDINGS_OBJC_HEADER_H +#define KJS_BINDINGS_OBJC_HEADER_H + +#ifdef __OBJC__ + +#include <objc/objc.h> +#include <objc/objc-class.h> +#include <objc/objc-runtime.h> + +typedef Class ClassStructPtr; +typedef id ObjectStructPtr; +typedef Method MethodStructPtr; +typedef Ivar IvarStructPtr; + +@class NSMethodSignature; + +#else + +typedef struct objc_class* ClassStructPtr; +typedef struct objc_object* ObjectStructPtr; +typedef struct objc_method* MethodStructPtr; +typedef struct objc_ivar* IvarStructPtr; + +class NSMethodSignature; + +#endif + +#endif diff --git a/Source/WebCore/bridge/objc/objc_instance.h b/Source/WebCore/bridge/objc/objc_instance.h new file mode 100644 index 0000000..ae6972a --- /dev/null +++ b/Source/WebCore/bridge/objc/objc_instance.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2003, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BINDINGS_OBJC_INSTANCE_H_ +#define BINDINGS_OBJC_INSTANCE_H_ + +#include "objc_class.h" +#include "objc_utility.h" + +namespace JSC { + +namespace Bindings { + +class ObjcClass; + +class ObjcInstance : public Instance { +public: + static PassRefPtr<ObjcInstance> create(ObjectStructPtr, PassRefPtr<RootObject>); + virtual ~ObjcInstance(); + + static void setGlobalException(NSString*, JSGlobalObject* exceptionEnvironment = 0); // A null exceptionEnvironment means the exception should propogate to any execution environment. + + virtual Class* getClass() const; + + virtual JSValue valueOf(ExecState*) const; + virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const; + + virtual JSValue getMethod(ExecState* exec, const Identifier& propertyName); + JSValue invokeObjcMethod(ExecState*, ObjcMethod* method); + virtual JSValue invokeMethod(ExecState*, RuntimeMethod* method); + virtual bool supportsInvokeDefaultMethod() const; + virtual JSValue invokeDefaultMethod(ExecState*); + + JSValue getValueOfUndefinedField(ExecState*, const Identifier&) const; + virtual bool setValueOfUndefinedField(ExecState*, const Identifier&, JSValue); + + ObjectStructPtr getObject() const { return _instance.get(); } + + JSValue stringValue(ExecState*) const; + JSValue numberValue(ExecState*) const; + JSValue booleanValue() const; + +protected: + virtual void virtualBegin(); + virtual void virtualEnd(); + +private: + static void moveGlobalExceptionToExecState(ExecState*); + + ObjcInstance(ObjectStructPtr, PassRefPtr<RootObject>); + + virtual RuntimeObject* newRuntimeObject(ExecState*); + + RetainPtr<ObjectStructPtr> _instance; + mutable ObjcClass *_class; + ObjectStructPtr _pool; + int _beginCount; +}; + +} // namespace Bindings + +} // namespace JSC + +#endif // BINDINGS_OBJC_INSTANCE_H_ diff --git a/Source/WebCore/bridge/objc/objc_instance.mm b/Source/WebCore/bridge/objc/objc_instance.mm new file mode 100644 index 0000000..ae9d95d --- /dev/null +++ b/Source/WebCore/bridge/objc/objc_instance.mm @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2004, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "objc_instance.h" + +#import "runtime_method.h" +#import "ObjCRuntimeObject.h" +#import "WebScriptObject.h" +#import <objc/objc-auto.h> +#import <runtime/Error.h> +#import <runtime/JSLock.h> +#import <wtf/Assertions.h> + +#ifdef NDEBUG +#define OBJC_LOG(formatAndArgs...) ((void)0) +#else +#define OBJC_LOG(formatAndArgs...) { \ + fprintf (stderr, "%s:%d -- %s: ", __FILE__, __LINE__, __FUNCTION__); \ + fprintf(stderr, formatAndArgs); \ +} +#endif + +using namespace JSC::Bindings; +using namespace JSC; + +static NSString *s_exception; +static JSGlobalObject* s_exceptionEnvironment; // No need to protect this value, since we just use it for a pointer comparison. +static NSMapTable *s_instanceWrapperCache; + +static NSMapTable *createInstanceWrapperCache() +{ +#ifdef BUILDING_ON_TIGER + return NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSNonOwnedPointerMapValueCallBacks, 0); +#else + // NSMapTable with zeroing weak pointers is the recommended way to build caches like this under garbage collection. + NSPointerFunctionsOptions keyOptions = NSPointerFunctionsZeroingWeakMemory | NSPointerFunctionsOpaquePersonality; + NSPointerFunctionsOptions valueOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality; + return [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; +#endif +} + +RuntimeObject* ObjcInstance::newRuntimeObject(ExecState* exec) +{ + return new (exec) ObjCRuntimeObject(exec, exec->lexicalGlobalObject(), this); +} + +void ObjcInstance::setGlobalException(NSString* exception, JSGlobalObject* exceptionEnvironment) +{ + NSString *oldException = s_exception; + s_exception = [exception copy]; + [oldException release]; + + s_exceptionEnvironment = exceptionEnvironment; +} + +void ObjcInstance::moveGlobalExceptionToExecState(ExecState* exec) +{ + if (!s_exception) { + ASSERT(!s_exceptionEnvironment); + return; + } + + if (!s_exceptionEnvironment || s_exceptionEnvironment == exec->dynamicGlobalObject()) { + JSLock lock(SilenceAssertionsOnly); + throwError(exec, s_exception); + } + + [s_exception release]; + s_exception = nil; + s_exceptionEnvironment = 0; +} + +ObjcInstance::ObjcInstance(id instance, PassRefPtr<RootObject> rootObject) + : Instance(rootObject) + , _instance(instance) + , _class(0) + , _pool(0) + , _beginCount(0) +{ +} + +PassRefPtr<ObjcInstance> ObjcInstance::create(id instance, PassRefPtr<RootObject> rootObject) +{ + if (!s_instanceWrapperCache) + s_instanceWrapperCache = createInstanceWrapperCache(); + if (void* existingWrapper = NSMapGet(s_instanceWrapperCache, instance)) + return static_cast<ObjcInstance*>(existingWrapper); + RefPtr<ObjcInstance> wrapper = adoptRef(new ObjcInstance(instance, rootObject)); + NSMapInsert(s_instanceWrapperCache, instance, wrapper.get()); + return wrapper.release(); +} + +ObjcInstance::~ObjcInstance() +{ + // Both -finalizeForWebScript and -dealloc/-finalize of _instance may require autorelease pools. + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + ASSERT(s_instanceWrapperCache); + ASSERT(_instance); + NSMapRemove(s_instanceWrapperCache, _instance.get()); + + if ([_instance.get() respondsToSelector:@selector(finalizeForWebScript)]) + [_instance.get() performSelector:@selector(finalizeForWebScript)]; + _instance = 0; + + [pool drain]; +} + +static NSAutoreleasePool* allocateAutoReleasePool() +{ +#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2 + // If GC is enabled an autorelease pool is unnecessary, and the + // pool cannot be protected from GC so may be collected leading + // to a crash when we try to drain the release pool. + if (objc_collectingEnabled()) + return nil; +#endif + return [[NSAutoreleasePool alloc] init]; +} + +void ObjcInstance::virtualBegin() +{ + if (!_pool) + _pool = allocateAutoReleasePool(); + _beginCount++; +} + +void ObjcInstance::virtualEnd() +{ + _beginCount--; + ASSERT(_beginCount >= 0); + if (!_beginCount) { + [_pool drain]; + _pool = 0; + } +} + +Bindings::Class* ObjcInstance::getClass() const +{ + if (!_instance) + return 0; + if (!_class) + _class = ObjcClass::classForIsA(_instance->isa); + return static_cast<Bindings::Class*>(_class); +} + +bool ObjcInstance::supportsInvokeDefaultMethod() const +{ + return [_instance.get() respondsToSelector:@selector(invokeDefaultMethodWithArguments:)]; +} + +class ObjCRuntimeMethod : public RuntimeMethod { +public: + ObjCRuntimeMethod(ExecState* exec, JSGlobalObject* globalObject, const Identifier& name, Bindings::MethodList& list) + : RuntimeMethod(exec, globalObject, name, list) + { + } + + virtual const ClassInfo* classInfo() const { return &s_info; } + + static const ClassInfo s_info; +}; + +const ClassInfo ObjCRuntimeMethod::s_info = { "ObjCRuntimeMethod", &RuntimeMethod::s_info, 0, 0 }; + +JSValue ObjcInstance::getMethod(ExecState* exec, const Identifier& propertyName) +{ + MethodList methodList = getClass()->methodsNamed(propertyName, this); + return new (exec) ObjCRuntimeMethod(exec, exec->lexicalGlobalObject(), propertyName, methodList); +} + +JSValue ObjcInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod) +{ + if (!asObject(runtimeMethod)->inherits(&ObjCRuntimeMethod::s_info)) + return throwError(exec, createTypeError(exec, "Attempt to invoke non-plug-in method on plug-in object.")); + + const MethodList& methodList = *runtimeMethod->methods(); + + // Overloading methods is not allowed in ObjectiveC. Should only be one + // name match for a particular method. + ASSERT(methodList.size() == 1); + + return invokeObjcMethod(exec, static_cast<ObjcMethod*>(methodList[0])); +} + +JSValue ObjcInstance::invokeObjcMethod(ExecState* exec, ObjcMethod* method) +{ + JSValue result = jsUndefined(); + + JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly. + + setGlobalException(nil); + +@try { + NSMethodSignature* signature = method->getMethodSignature(); + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setSelector:method->selector()]; + [invocation setTarget:_instance.get()]; + + if (method->isFallbackMethod()) { + if (objcValueTypeForType([signature methodReturnType]) != ObjcObjectType) { + NSLog(@"Incorrect signature for invokeUndefinedMethodFromWebScript:withArguments: -- return type must be object."); + return result; + } + + // Invoke invokeUndefinedMethodFromWebScript:withArguments:, pass JavaScript function + // name as first (actually at 2) argument and array of args as second. + NSString* jsName = (NSString* )method->javaScriptName(); + [invocation setArgument:&jsName atIndex:2]; + + NSMutableArray* objcArgs = [NSMutableArray array]; + int count = exec->argumentCount(); + for (int i = 0; i < count; i++) { + ObjcValue value = convertValueToObjcValue(exec, exec->argument(i), ObjcObjectType); + [objcArgs addObject:value.objectValue]; + } + [invocation setArgument:&objcArgs atIndex:3]; + } else { + unsigned count = [signature numberOfArguments]; + for (unsigned i = 2; i < count ; i++) { + const char* type = [signature getArgumentTypeAtIndex:i]; + ObjcValueType objcValueType = objcValueTypeForType(type); + + // Must have a valid argument type. This method signature should have + // been filtered already to ensure that it has acceptable argument + // types. + ASSERT(objcValueType != ObjcInvalidType && objcValueType != ObjcVoidType); + + ObjcValue value = convertValueToObjcValue(exec, exec->argument(i-2), objcValueType); + + switch (objcValueType) { + case ObjcObjectType: + [invocation setArgument:&value.objectValue atIndex:i]; + break; + case ObjcCharType: + case ObjcUnsignedCharType: + [invocation setArgument:&value.charValue atIndex:i]; + break; + case ObjcShortType: + case ObjcUnsignedShortType: + [invocation setArgument:&value.shortValue atIndex:i]; + break; + case ObjcIntType: + case ObjcUnsignedIntType: + [invocation setArgument:&value.intValue atIndex:i]; + break; + case ObjcLongType: + case ObjcUnsignedLongType: + [invocation setArgument:&value.longValue atIndex:i]; + break; + case ObjcLongLongType: + case ObjcUnsignedLongLongType: + [invocation setArgument:&value.longLongValue atIndex:i]; + break; + case ObjcFloatType: + [invocation setArgument:&value.floatValue atIndex:i]; + break; + case ObjcDoubleType: + [invocation setArgument:&value.doubleValue atIndex:i]; + break; + default: + // Should never get here. Argument types are filtered (and + // the assert above should have fired in the impossible case + // of an invalid type anyway). + fprintf(stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)objcValueType); + ASSERT(false); + } + } + } + + [invocation invoke]; + + // Get the return value type. + const char* type = [signature methodReturnType]; + ObjcValueType objcValueType = objcValueTypeForType(type); + + // Must have a valid return type. This method signature should have + // been filtered already to ensure that it have an acceptable return + // type. + ASSERT(objcValueType != ObjcInvalidType); + + // Get the return value and convert it to a JavaScript value. Length + // of return value will never exceed the size of largest scalar + // or a pointer. + char buffer[1024]; + ASSERT([signature methodReturnLength] < 1024); + + if (*type != 'v') { + [invocation getReturnValue:buffer]; + result = convertObjcValueToValue(exec, buffer, objcValueType, m_rootObject.get()); + } +} @catch(NSException* localException) { +} + moveGlobalExceptionToExecState(exec); + + // Work around problem in some versions of GCC where result gets marked volatile and + // it can't handle copying from a volatile to non-volatile. + return const_cast<JSValue&>(result); +} + +JSValue ObjcInstance::invokeDefaultMethod(ExecState* exec) +{ + JSValue result = jsUndefined(); + + JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly. + setGlobalException(nil); + +@try { + if (![_instance.get() respondsToSelector:@selector(invokeDefaultMethodWithArguments:)]) + return result; + + NSMethodSignature* signature = [_instance.get() methodSignatureForSelector:@selector(invokeDefaultMethodWithArguments:)]; + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setSelector:@selector(invokeDefaultMethodWithArguments:)]; + [invocation setTarget:_instance.get()]; + + if (objcValueTypeForType([signature methodReturnType]) != ObjcObjectType) { + NSLog(@"Incorrect signature for invokeDefaultMethodWithArguments: -- return type must be object."); + return result; + } + + NSMutableArray* objcArgs = [NSMutableArray array]; + unsigned count = exec->argumentCount(); + for (unsigned i = 0; i < count; i++) { + ObjcValue value = convertValueToObjcValue(exec, exec->argument(i), ObjcObjectType); + [objcArgs addObject:value.objectValue]; + } + [invocation setArgument:&objcArgs atIndex:2]; + + [invocation invoke]; + + // Get the return value type, should always be "@" because of + // check above. + const char* type = [signature methodReturnType]; + ObjcValueType objcValueType = objcValueTypeForType(type); + + // Get the return value and convert it to a JavaScript value. Length + // of return value will never exceed the size of a pointer, so we're + // OK with 32 here. + char buffer[32]; + [invocation getReturnValue:buffer]; + result = convertObjcValueToValue(exec, buffer, objcValueType, m_rootObject.get()); +} @catch(NSException* localException) { +} + moveGlobalExceptionToExecState(exec); + + // Work around problem in some versions of GCC where result gets marked volatile and + // it can't handle copying from a volatile to non-volatile. + return const_cast<JSValue&>(result); +} + +bool ObjcInstance::setValueOfUndefinedField(ExecState* exec, const Identifier& property, JSValue aValue) +{ + id targetObject = getObject(); + if (![targetObject respondsToSelector:@selector(setValue:forUndefinedKey:)]) + return false; + + JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly. + + // This check is not really necessary because NSObject implements + // setValue:forUndefinedKey:, and unfortunately the default implementation + // throws an exception. + if ([targetObject respondsToSelector:@selector(setValue:forUndefinedKey:)]){ + setGlobalException(nil); + + ObjcValue objcValue = convertValueToObjcValue(exec, aValue, ObjcObjectType); + + @try { + [targetObject setValue:objcValue.objectValue forUndefinedKey:[NSString stringWithCString:property.ascii().data() encoding:NSASCIIStringEncoding]]; + } @catch(NSException* localException) { + // Do nothing. Class did not override valueForUndefinedKey:. + } + + moveGlobalExceptionToExecState(exec); + } + + return true; +} + +JSValue ObjcInstance::getValueOfUndefinedField(ExecState* exec, const Identifier& property) const +{ + JSValue result = jsUndefined(); + + id targetObject = getObject(); + + JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly. + + // This check is not really necessary because NSObject implements + // valueForUndefinedKey:, and unfortunately the default implementation + // throws an exception. + if ([targetObject respondsToSelector:@selector(valueForUndefinedKey:)]){ + setGlobalException(nil); + + @try { + id objcValue = [targetObject valueForUndefinedKey:[NSString stringWithCString:property.ascii().data() encoding:NSASCIIStringEncoding]]; + result = convertObjcValueToValue(exec, &objcValue, ObjcObjectType, m_rootObject.get()); + } @catch(NSException* localException) { + // Do nothing. Class did not override valueForUndefinedKey:. + } + + moveGlobalExceptionToExecState(exec); + } + + // Work around problem in some versions of GCC where result gets marked volatile and + // it can't handle copying from a volatile to non-volatile. + return const_cast<JSValue&>(result); +} + +JSValue ObjcInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const +{ + if (hint == PreferString) + return stringValue(exec); + if (hint == PreferNumber) + return numberValue(exec); + if ([_instance.get() isKindOfClass:[NSString class]]) + return stringValue(exec); + if ([_instance.get() isKindOfClass:[NSNumber class]]) + return numberValue(exec); + return valueOf(exec); +} + +JSValue ObjcInstance::stringValue(ExecState* exec) const +{ + return convertNSStringToString(exec, [getObject() description]); +} + +JSValue ObjcInstance::numberValue(ExecState*) const +{ + // FIXME: Implement something sensible + return jsNumber(0); +} + +JSValue ObjcInstance::booleanValue() const +{ + // FIXME: Implement something sensible + return jsBoolean(false); +} + +JSValue ObjcInstance::valueOf(ExecState* exec) const +{ + return stringValue(exec); +} diff --git a/Source/WebCore/bridge/objc/objc_runtime.h b/Source/WebCore/bridge/objc/objc_runtime.h new file mode 100644 index 0000000..60fbdac --- /dev/null +++ b/Source/WebCore/bridge/objc/objc_runtime.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef KJS_BINDINGS_OBJC_RUNTIME_H +#define KJS_BINDINGS_OBJC_RUNTIME_H + +#include "Bridge.h" +#include "objc_header.h" +#include <runtime/JSGlobalObject.h> +#include <runtime/JSObjectWithGlobalObject.h> +#include <wtf/RetainPtr.h> + +namespace JSC { +namespace Bindings { + +ClassStructPtr webScriptObjectClass(); +ClassStructPtr webUndefinedClass(); + +class ObjcInstance; + +class ObjcField : public Field { +public: + ObjcField(IvarStructPtr); + ObjcField(CFStringRef name); + + virtual JSValue valueFromInstance(ExecState*, const Instance*) const; + virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const; + +private: + IvarStructPtr _ivar; + RetainPtr<CFStringRef> _name; +}; + +class ObjcMethod : public Method { +public: + ObjcMethod() : _objcClass(0), _selector(0), _javaScriptName(0) {} + ObjcMethod(ClassStructPtr aClass, SEL _selector); + + virtual int numParameters() const; + + NSMethodSignature *getMethodSignature() const; + + bool isFallbackMethod() const { return _selector == @selector(invokeUndefinedMethodFromWebScript:withArguments:); } + void setJavaScriptName(CFStringRef n) { _javaScriptName = n; } + CFStringRef javaScriptName() const { return _javaScriptName.get(); } + + SEL selector() const { return _selector; } + +private: + ClassStructPtr _objcClass; + SEL _selector; + RetainPtr<CFStringRef> _javaScriptName; +}; + +class ObjcArray : public Array { +public: + ObjcArray(ObjectStructPtr, PassRefPtr<RootObject>); + + virtual void setValueAt(ExecState *exec, unsigned int index, JSValue aValue) const; + virtual JSValue valueAt(ExecState *exec, unsigned int index) const; + virtual unsigned int getLength() const; + + ObjectStructPtr getObjcArray() const { return _array.get(); } + + static JSValue convertObjcArrayToArray(ExecState *exec, ObjectStructPtr anObject); + +private: + RetainPtr<ObjectStructPtr> _array; +}; + +class ObjcFallbackObjectImp : public JSObjectWithGlobalObject { +public: + ObjcFallbackObjectImp(ExecState*, JSGlobalObject*, ObjcInstance*, const Identifier& propertyName); + + static const ClassInfo s_info; + + const Identifier& propertyName() const { return _item; } + + static ObjectPrototype* createPrototype(ExecState*, JSGlobalObject* globalObject) + { + return globalObject->objectPrototype(); + } + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + } + +private: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); + virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + virtual CallType getCallData(CallData&); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const; + + virtual bool toBoolean(ExecState*) const; + + virtual const ClassInfo* classInfo() const { return &s_info; } + + RefPtr<ObjcInstance> _instance; + Identifier _item; +}; + +} // namespace Bindings +} // namespace JSC + +#endif diff --git a/Source/WebCore/bridge/objc/objc_runtime.mm b/Source/WebCore/bridge/objc/objc_runtime.mm new file mode 100644 index 0000000..3c4ba23 --- /dev/null +++ b/Source/WebCore/bridge/objc/objc_runtime.mm @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "objc_runtime.h" + +#include "JSDOMBinding.h" +#include "ObjCRuntimeObject.h" +#include "WebScriptObject.h" +#include "objc_instance.h" +#include "runtime_array.h" +#include "runtime_object.h" +#include <runtime/Error.h> +#include <runtime/JSGlobalObject.h> +#include <runtime/JSLock.h> +#include <runtime/ObjectPrototype.h> +#include <wtf/RetainPtr.h> + +using namespace WebCore; + +namespace JSC { +namespace Bindings { + +ClassStructPtr webScriptObjectClass() +{ + static ClassStructPtr<WebScriptObject> webScriptObjectClass = NSClassFromString(@"WebScriptObject"); + return webScriptObjectClass; +} + +ClassStructPtr webUndefinedClass() +{ + static ClassStructPtr<WebUndefined> webUndefinedClass = NSClassFromString(@"WebUndefined"); + return webUndefinedClass; +} + +// ---------------------- ObjcMethod ---------------------- + +ObjcMethod::ObjcMethod(ClassStructPtr aClass, SEL selector) + : _objcClass(aClass) + , _selector(selector) +{ +} + +int ObjcMethod::numParameters() const +{ + return [getMethodSignature() numberOfArguments] - 2; +} + +NSMethodSignature* ObjcMethod::getMethodSignature() const +{ + return [_objcClass instanceMethodSignatureForSelector:_selector]; +} + +// ---------------------- ObjcField ---------------------- + +ObjcField::ObjcField(Ivar ivar) + : _ivar(ivar) +#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2 + , _name(AdoptCF, CFStringCreateWithCString(0, ivar_getName(_ivar), kCFStringEncodingASCII)) +#else + , _name(AdoptCF, CFStringCreateWithCString(0, _ivar->ivar_name, kCFStringEncodingASCII)) +#endif +{ +} + +ObjcField::ObjcField(CFStringRef name) + : _ivar(0) + , _name(name) +{ +} + +JSValue ObjcField::valueFromInstance(ExecState* exec, const Instance* instance) const +{ + JSValue result = jsUndefined(); + + id targetObject = (static_cast<const ObjcInstance*>(instance))->getObject(); + + JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly. + + @try { + if (id objcValue = [targetObject valueForKey:(NSString *)_name.get()]) + result = convertObjcValueToValue(exec, &objcValue, ObjcObjectType, instance->rootObject()); + } @catch(NSException* localException) { + JSLock::lock(SilenceAssertionsOnly); + throwError(exec, [localException reason]); + JSLock::unlock(SilenceAssertionsOnly); + } + + // Work around problem in some versions of GCC where result gets marked volatile and + // it can't handle copying from a volatile to non-volatile. + return const_cast<JSValue&>(result); +} + +static id convertValueToObjcObject(ExecState* exec, JSValue value) +{ + RefPtr<RootObject> rootObject = findRootObject(exec->dynamicGlobalObject()); + if (!rootObject) + return nil; + return [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:rootObject.get() rootObject:rootObject.get()]; +} + +void ObjcField::setValueToInstance(ExecState* exec, const Instance* instance, JSValue aValue) const +{ + id targetObject = (static_cast<const ObjcInstance*>(instance))->getObject(); + id value = convertValueToObjcObject(exec, aValue); + + JSLock::DropAllLocks dropAllLocks(SilenceAssertionsOnly); // Can't put this inside the @try scope because it unwinds incorrectly. + + @try { + [targetObject setValue:value forKey:(NSString *)_name.get()]; + } @catch(NSException* localException) { + JSLock::lock(SilenceAssertionsOnly); + throwError(exec, [localException reason]); + JSLock::unlock(SilenceAssertionsOnly); + } +} + +// ---------------------- ObjcArray ---------------------- + +ObjcArray::ObjcArray(ObjectStructPtr a, PassRefPtr<RootObject> rootObject) + : Array(rootObject) + , _array(a) +{ +} + +void ObjcArray::setValueAt(ExecState* exec, unsigned int index, JSValue aValue) const +{ + if (![_array.get() respondsToSelector:@selector(insertObject:atIndex:)]) { + throwError(exec, createTypeError(exec, "Array is not mutable.")); + return; + } + + if (index > [_array.get() count]) { + throwError(exec, createRangeError(exec, "Index exceeds array size.")); + return; + } + + // Always try to convert the value to an ObjC object, so it can be placed in the + // array. + ObjcValue oValue = convertValueToObjcValue (exec, aValue, ObjcObjectType); + + @try { + [_array.get() insertObject:oValue.objectValue atIndex:index]; + } @catch(NSException* localException) { + throwError(exec, createError(exec, "Objective-C exception.")); + } +} + +JSValue ObjcArray::valueAt(ExecState* exec, unsigned int index) const +{ + if (index > [_array.get() count]) + return throwError(exec, createRangeError(exec, "Index exceeds array size.")); + @try { + id obj = [_array.get() objectAtIndex:index]; + if (obj) + return convertObjcValueToValue (exec, &obj, ObjcObjectType, m_rootObject.get()); + } @catch(NSException* localException) { + return throwError(exec, createError(exec, "Objective-C exception.")); + } + return jsUndefined(); +} + +unsigned int ObjcArray::getLength() const +{ + return [_array.get() count]; +} + +const ClassInfo ObjcFallbackObjectImp::s_info = { "ObjcFallbackObject", 0, 0, 0 }; + +ObjcFallbackObjectImp::ObjcFallbackObjectImp(ExecState* exec, JSGlobalObject* globalObject, ObjcInstance* i, const Identifier& propertyName) + // FIXME: deprecatedGetDOMStructure uses the prototype off of the wrong global object + : JSObjectWithGlobalObject(globalObject, deprecatedGetDOMStructure<ObjcFallbackObjectImp>(exec)) + , _instance(i) + , _item(propertyName) +{ +} + +bool ObjcFallbackObjectImp::getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot& slot) +{ + // keep the prototype from getting called instead of just returning false + slot.setUndefined(); + return true; +} + +bool ObjcFallbackObjectImp::getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor& descriptor) +{ + // keep the prototype from getting called instead of just returning false + descriptor.setUndefined(); + return true; +} + +void ObjcFallbackObjectImp::put(ExecState*, const Identifier&, JSValue, PutPropertySlot&) +{ +} + +static EncodedJSValue JSC_HOST_CALL callObjCFallbackObject(ExecState* exec) +{ + JSValue thisValue = exec->hostThisValue(); + if (!thisValue.inherits(&ObjCRuntimeObject::s_info)) + return throwVMTypeError(exec); + + JSValue result = jsUndefined(); + + ObjCRuntimeObject* runtimeObject = static_cast<ObjCRuntimeObject*>(asObject(thisValue)); + ObjcInstance* objcInstance = runtimeObject->getInternalObjCInstance(); + + if (!objcInstance) + return JSValue::encode(RuntimeObject::throwInvalidAccessError(exec)); + + objcInstance->begin(); + + id targetObject = objcInstance->getObject(); + + if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)]){ + ObjcClass* objcClass = static_cast<ObjcClass*>(objcInstance->getClass()); + OwnPtr<ObjcMethod> fallbackMethod(new ObjcMethod(objcClass->isa(), @selector(invokeUndefinedMethodFromWebScript:withArguments:))); + const Identifier& nameIdentifier = static_cast<ObjcFallbackObjectImp*>(exec->callee())->propertyName(); + RetainPtr<CFStringRef> name(AdoptCF, CFStringCreateWithCharacters(0, nameIdentifier.characters(), nameIdentifier.length())); + fallbackMethod->setJavaScriptName(name.get()); + result = objcInstance->invokeObjcMethod(exec, fallbackMethod.get()); + } + + objcInstance->end(); + + return JSValue::encode(result); +} + +CallType ObjcFallbackObjectImp::getCallData(CallData& callData) +{ + id targetObject = _instance->getObject(); + if (![targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)]) + return CallTypeNone; + callData.native.function = callObjCFallbackObject; + return CallTypeHost; +} + +bool ObjcFallbackObjectImp::deleteProperty(ExecState*, const Identifier&) +{ + return false; +} + +JSValue ObjcFallbackObjectImp::defaultValue(ExecState* exec, PreferredPrimitiveType) const +{ + return _instance->getValueOfUndefinedField(exec, _item); +} + +bool ObjcFallbackObjectImp::toBoolean(ExecState *) const +{ + id targetObject = _instance->getObject(); + + if ([targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)]) + return true; + + return false; +} + +} +} diff --git a/Source/WebCore/bridge/objc/objc_utility.h b/Source/WebCore/bridge/objc/objc_utility.h new file mode 100644 index 0000000..4810752 --- /dev/null +++ b/Source/WebCore/bridge/objc/objc_utility.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2004 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef KJS_BINDINGS_OBJC_UTILITY_H +#define KJS_BINDINGS_OBJC_UTILITY_H + +#include <CoreFoundation/CoreFoundation.h> + +#include "objc_header.h" +#include <runtime/Error.h> +#include <runtime/JSObject.h> + +#ifdef __OBJC__ +@class NSString; +#else +class NSString; +#endif + +namespace JSC { +namespace Bindings { + +typedef union { + ObjectStructPtr objectValue; + bool booleanValue; + char charValue; + short shortValue; + int intValue; + long longValue; + long long longLongValue; + float floatValue; + double doubleValue; +} ObjcValue; + +typedef enum { + ObjcVoidType, + ObjcObjectType, + ObjcCharType, + ObjcUnsignedCharType, + ObjcShortType, + ObjcUnsignedShortType, + ObjcIntType, + ObjcUnsignedIntType, + ObjcLongType, + ObjcUnsignedLongType, + ObjcLongLongType, + ObjcUnsignedLongLongType, + ObjcFloatType, + ObjcDoubleType, + ObjcInvalidType +} ObjcValueType; + +class RootObject; + +ObjcValue convertValueToObjcValue(ExecState*, JSValue, ObjcValueType); +JSValue convertNSStringToString(ExecState* exec, NSString *nsstring); +JSValue convertObjcValueToValue(ExecState*, void* buffer, ObjcValueType, RootObject*); +ObjcValueType objcValueTypeForType(const char *type); + +bool convertJSMethodNameToObjc(const char *JSName, char *buffer, size_t bufferSize); + +JSObject *throwError(ExecState *, NSString *message); + +} // namespace Bindings +} // namespace JSC + +#endif diff --git a/Source/WebCore/bridge/objc/objc_utility.mm b/Source/WebCore/bridge/objc/objc_utility.mm new file mode 100644 index 0000000..dfba852 --- /dev/null +++ b/Source/WebCore/bridge/objc/objc_utility.mm @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2004 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "objc_utility.h" + +#include "objc_instance.h" +#include "runtime_array.h" +#include "runtime_object.h" +#include "WebScriptObject.h" +#include <runtime/JSGlobalObject.h> +#include <runtime/JSLock.h> +#include <wtf/Assertions.h> + +#if !defined(_C_LNG_LNG) +#define _C_LNG_LNG 'q' +#endif + +#if !defined(_C_ULNG_LNG) +#define _C_ULNG_LNG 'Q' +#endif + +#if !defined(_C_CONST) +#define _C_CONST 'r' +#endif + +#if !defined(_C_BYCOPY) +#define _C_BYCOPY 'O' +#endif + +#if !defined(_C_BYREF) +#define _C_BYREF 'R' +#endif + +#if !defined(_C_ONEWAY) +#define _C_ONEWAY 'V' +#endif + +#if !defined(_C_GCINVISIBLE) +#define _C_GCINVISIBLE '!' +#endif + +namespace JSC { +namespace Bindings { + +/* + By default, a JavaScript method name is produced by concatenating the + components of an ObjectiveC method name, replacing ':' with '_', and + escaping '_' and '$' with a leading '$', such that '_' becomes "$_" and + '$' becomes "$$". For example: + + ObjectiveC name Default JavaScript name + moveTo:: moveTo__ + moveTo_ moveTo$_ + moveTo$_ moveTo$$$_ + + This function performs the inverse of that operation. + + @result Fills 'buffer' with the ObjectiveC method name that corresponds to 'JSName'. + Returns true for success, false for failure. (Failure occurs when 'buffer' + is not big enough to hold the result.) +*/ +bool convertJSMethodNameToObjc(const char *JSName, char *buffer, size_t bufferSize) +{ + ASSERT(JSName && buffer); + + const char *sp = JSName; // source pointer + char *dp = buffer; // destination pointer + + char *end = buffer + bufferSize; + while (dp < end) { + if (*sp == '$') { + ++sp; + *dp = *sp; + } else if (*sp == '_') + *dp = ':'; + else + *dp = *sp; + + // If a future coder puts funny ++ operators above, we might write off the end + // of the buffer in the middle of this loop. Let's make sure to check for that. + ASSERT(dp < end); + + if (*sp == 0) { // We finished converting JSName + ASSERT(strlen(JSName) < bufferSize); + return true; + } + + ++sp; + ++dp; + } + + return false; // We ran out of buffer before converting JSName +} + +/* + + JavaScript to ObjC + Number coerced to char, short, int, long, float, double, or NSNumber, as appropriate + String NSString + wrapper id + Object WebScriptObject + null NSNull + [], other exception + +*/ +ObjcValue convertValueToObjcValue(ExecState* exec, JSValue value, ObjcValueType type) +{ + ObjcValue result; + double d = 0; + + if (value.isNumber() || value.isString() || value.isBoolean()) + d = value.toNumber(exec); + + switch (type) { + case ObjcObjectType: { + JSLock lock(SilenceAssertionsOnly); + + JSGlobalObject *originGlobalObject = exec->dynamicGlobalObject(); + RootObject* originRootObject = findRootObject(originGlobalObject); + + JSGlobalObject* globalObject = 0; + if (value.isObject() && asObject(value)->isGlobalObject()) + globalObject = static_cast<JSGlobalObject*>(asObject(value)); + + if (!globalObject) + globalObject = originGlobalObject; + + RootObject* rootObject = findRootObject(globalObject); + result.objectValue = rootObject + ? [webScriptObjectClass() _convertValueToObjcValue:value originRootObject:originRootObject rootObject:rootObject] + : nil; + } + break; + + case ObjcCharType: + case ObjcUnsignedCharType: + result.charValue = (char)d; + break; + case ObjcShortType: + case ObjcUnsignedShortType: + result.shortValue = (short)d; + break; + case ObjcIntType: + case ObjcUnsignedIntType: + result.intValue = (int)d; + break; + case ObjcLongType: + case ObjcUnsignedLongType: + result.longValue = (long)d; + break; + case ObjcLongLongType: + case ObjcUnsignedLongLongType: + result.longLongValue = (long long)d; + break; + case ObjcFloatType: + result.floatValue = (float)d; + break; + case ObjcDoubleType: + result.doubleValue = (double)d; + break; + case ObjcVoidType: + bzero(&result, sizeof(ObjcValue)); + break; + + case ObjcInvalidType: + default: + // FIXME: throw an exception? + break; + } + + return result; +} + +JSValue convertNSStringToString(ExecState* exec, NSString *nsstring) +{ + JSLock lock(SilenceAssertionsOnly); + + unichar *chars; + unsigned int length = [nsstring length]; + chars = (unichar *)malloc(sizeof(unichar)*length); + [nsstring getCharacters:chars]; + UString u((const UChar*)chars, length); + JSValue aValue = jsString(exec, u); + free((void *)chars); + return aValue; +} + +/* + ObjC to JavaScript + ---- ---------- + char number + short number + int number + long number + float number + double number + NSNumber boolean or number + NSString string + NSArray array + NSNull null + WebScriptObject underlying JavaScript object + WebUndefined undefined + id object wrapper + other should not happen +*/ +JSValue convertObjcValueToValue(ExecState* exec, void* buffer, ObjcValueType type, RootObject* rootObject) +{ + JSLock lock(SilenceAssertionsOnly); + + switch (type) { + case ObjcObjectType: { + id obj = *(id*)buffer; + if ([obj isKindOfClass:[NSString class]]) + return convertNSStringToString(exec, (NSString *)obj); + if ([obj isKindOfClass:webUndefinedClass()]) + return jsUndefined(); + if ((CFBooleanRef)obj == kCFBooleanTrue) + return jsBoolean(true); + if ((CFBooleanRef)obj == kCFBooleanFalse) + return jsBoolean(false); + if ([obj isKindOfClass:[NSNumber class]]) + return jsNumber([obj doubleValue]); + if ([obj isKindOfClass:[NSArray class]]) + return new (exec) RuntimeArray(exec, new ObjcArray(obj, rootObject)); + if ([obj isKindOfClass:webScriptObjectClass()]) { + JSObject* imp = [obj _imp]; + return imp ? imp : jsUndefined(); + } + if ([obj isKindOfClass:[NSNull class]]) + return jsNull(); + if (obj == 0) + return jsUndefined(); + return ObjcInstance::create(obj, rootObject)->createRuntimeObject(exec); + } + case ObjcCharType: + return jsNumber(*(char*)buffer); + case ObjcUnsignedCharType: + return jsNumber(*(unsigned char*)buffer); + case ObjcShortType: + return jsNumber(*(short*)buffer); + case ObjcUnsignedShortType: + return jsNumber(*(unsigned short*)buffer); + case ObjcIntType: + return jsNumber(*(int*)buffer); + case ObjcUnsignedIntType: + return jsNumber(*(unsigned int*)buffer); + case ObjcLongType: + return jsNumber(*(long*)buffer); + case ObjcUnsignedLongType: + return jsNumber(*(unsigned long*)buffer); + case ObjcLongLongType: + return jsNumber(*(long long*)buffer); + case ObjcUnsignedLongLongType: + return jsNumber(*(unsigned long long*)buffer); + case ObjcFloatType: + return jsNumber(*(float*)buffer); + case ObjcDoubleType: + return jsNumber(*(double*)buffer); + default: + // Should never get here. Argument types are filtered. + fprintf(stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)type); + ASSERT(false); + } + + return jsUndefined(); +} + +ObjcValueType objcValueTypeForType(const char *type) +{ + int typeLength = strlen(type); + ObjcValueType objcValueType = ObjcInvalidType; + + for (int i = 0; i < typeLength; ++i) { + char typeChar = type[i]; + switch (typeChar) { + case _C_CONST: + case _C_BYCOPY: + case _C_BYREF: + case _C_ONEWAY: + case _C_GCINVISIBLE: + // skip these type modifiers + break; + case _C_ID: + objcValueType = ObjcObjectType; + break; + case _C_CHR: + objcValueType = ObjcCharType; + break; + case _C_UCHR: + objcValueType = ObjcUnsignedCharType; + break; + case _C_SHT: + objcValueType = ObjcShortType; + break; + case _C_USHT: + objcValueType = ObjcUnsignedShortType; + break; + case _C_INT: + objcValueType = ObjcIntType; + break; + case _C_UINT: + objcValueType = ObjcUnsignedIntType; + break; + case _C_LNG: + objcValueType = ObjcLongType; + break; + case _C_ULNG: + objcValueType = ObjcUnsignedLongType; + break; + case _C_LNG_LNG: + objcValueType = ObjcLongLongType; + break; + case _C_ULNG_LNG: + objcValueType = ObjcUnsignedLongLongType; + break; + case _C_FLT: + objcValueType = ObjcFloatType; + break; + case _C_DBL: + objcValueType = ObjcDoubleType; + break; + case _C_VOID: + objcValueType = ObjcVoidType; + break; + default: + // Unhandled type. We don't handle C structs, unions, etc. + // FIXME: throw an exception? + ASSERT(false); + } + + if (objcValueType != ObjcInvalidType) + break; + } + + return objcValueType; +} + +JSObject *throwError(ExecState *exec, NSString *message) +{ + ASSERT(message); + size_t length = [message length]; + unichar *buffer = new unichar[length]; + [message getCharacters:buffer]; + JSObject *error = JSC::throwError(exec, JSC::createError(exec, UString(buffer, length))); + delete [] buffer; + return error; +} + +} +} |
