diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/JavaScriptGlue/JSUtils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/osswebengine/JavaScriptGlue/JSUtils.cpp Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2005 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "JSUtils.h" +#include "JSBase.h" +#include "JSObject.h" +#include "JSRun.h" +#include "UserObjectImp.h" +#include "JSValueWrapper.h" +#include "JSObject.h" +#include + +struct ObjectImpList { + JSObject* imp; + ObjectImpList* next; + CFTypeRef data; +}; + +static CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps); + + +//-------------------------------------------------------------------------- +// CFStringToUString +//-------------------------------------------------------------------------- + +UString CFStringToUString(CFStringRef inCFString) +{ + UString result; + if (inCFString) { + CFIndex len = CFStringGetLength(inCFString); + UniChar* buffer = (UniChar*)malloc(sizeof(UniChar) * len); + if (buffer) + { + CFStringGetCharacters(inCFString, CFRangeMake(0, len), buffer); + result = UString((const UChar *)buffer, len); + free(buffer); + } + } + return result; +} + + +//-------------------------------------------------------------------------- +// UStringToCFString +//-------------------------------------------------------------------------- +// Caller is responsible for releasing the returned CFStringRef +CFStringRef UStringToCFString(const UString& inUString) +{ + return CFStringCreateWithCharacters(0, (const UniChar*)inUString.data(), inUString.size()); +} + + +//-------------------------------------------------------------------------- +// CFStringToIdentifier +//-------------------------------------------------------------------------- + +Identifier CFStringToIdentifier(CFStringRef inCFString) +{ + return Identifier(CFStringToUString(inCFString)); +} + + +//-------------------------------------------------------------------------- +// IdentifierToCFString +//-------------------------------------------------------------------------- +// Caller is responsible for releasing the returned CFStringRef +CFStringRef IdentifierToCFString(const Identifier& inIdentifier) +{ + return UStringToCFString(inIdentifier.ustring()); +} + + +//-------------------------------------------------------------------------- +// KJSValueToJSObject +//-------------------------------------------------------------------------- +JSUserObject* KJSValueToJSObject(JSValue *inValue, ExecState *exec) +{ + JSUserObject* result = 0; + + if (inValue->isObject(&UserObjectImp::info)) { + UserObjectImp* userObjectImp = static_cast(inValue); + result = userObjectImp->GetJSUserObject(); + if (result) + result->Retain(); + } else { + JSValueWrapper* wrapperValue = new JSValueWrapper(inValue); + if (wrapperValue) { + JSObjectCallBacks callBacks; + JSValueWrapper::GetJSObectCallBacks(callBacks); + result = (JSUserObject*)JSObjectCreate(wrapperValue, &callBacks); + if (!result) { + delete wrapperValue; + } + } + } + return result; +} + +//-------------------------------------------------------------------------- +// JSObjectKJSValue +//-------------------------------------------------------------------------- +JSValue *JSObjectKJSValue(JSUserObject* ptr) +{ + JSLock lock; + + JSValue *result = jsUndefined(); + if (ptr) + { + bool handled = false; + + switch (ptr->DataType()) + { + case kJSUserObjectDataTypeJSValueWrapper: + { + JSValueWrapper* wrapper = (JSValueWrapper*)ptr->GetData(); + if (wrapper) + { + result = wrapper->GetValue(); + handled = true; + } + break; + } + + case kJSUserObjectDataTypeCFType: + { + CFTypeRef cfType = (CFTypeRef*)ptr->GetData(); + if (cfType) + { + CFTypeID typeID = CFGetTypeID(cfType); + if (typeID == CFStringGetTypeID()) + { + result = jsString(CFStringToUString((CFStringRef)cfType)); + handled = true; + } + else if (typeID == CFNumberGetTypeID()) + { + double num; + CFNumberGetValue((CFNumberRef)cfType, kCFNumberDoubleType, &num); + result = jsNumber(num); + handled = true; + } + else if (typeID == CFBooleanGetTypeID()) + { + result = jsBoolean(CFBooleanGetValue((CFBooleanRef)cfType)); + handled = true; + } + else if (typeID == CFNullGetTypeID()) + { + result = jsNull(); + handled = true; + } + } + break; + } + } + if (!handled) + { + result = new UserObjectImp(ptr); + } + } + return result; +} + + + + +//-------------------------------------------------------------------------- +// KJSValueToCFTypeInternal +//-------------------------------------------------------------------------- +// Caller is responsible for releasing the returned CFTypeRef +CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps) +{ + if (!inValue) + return 0; + + CFTypeRef result = 0; + + JSLock lock; + + switch (inValue->type()) + { + case BooleanType: + { + result = inValue->toBoolean(exec) ? kCFBooleanTrue : kCFBooleanFalse; + RetainCFType(result); + } + break; + + case StringType: + { + UString uString = inValue->toString(exec); + result = UStringToCFString(uString); + } + break; + + case NumberType: + { + double number1 = inValue->toNumber(exec); + double number2 = (double)inValue->toInteger(exec); + if (number1 == number2) + { + int intValue = (int)number2; + result = CFNumberCreate(0, kCFNumberIntType, &intValue); + } + else + { + result = CFNumberCreate(0, kCFNumberDoubleType, &number1); + } + } + break; + + case ObjectType: + { + if (inValue->isObject(&UserObjectImp::info)) { + UserObjectImp* userObjectImp = static_cast(inValue); + JSUserObject* ptr = userObjectImp->GetJSUserObject(); + if (ptr) + { + result = ptr->CopyCFValue(); + } + } + else + { + JSObject *object = inValue->toObject(exec); + UInt8 isArray = false; + + // if two objects reference each + JSObject* imp = object; + ObjectImpList* temp = inImps; + while (temp) { + if (imp == temp->imp) { + return CFRetain(GetCFNull()); + } + temp = temp->next; + } + + ObjectImpList imps; + imps.next = inImps; + imps.imp = imp; + + +//[...] HACK since we do not have access to the class info we use class name instead +#if 0 + if (object->inherits(&ArrayInstanceImp::info)) +#else + if (object->className() == "Array") +#endif + { + isArray = true; + JSInterpreter* intrepreter = (JSInterpreter*)exec->dynamicInterpreter(); + if (intrepreter && (intrepreter->Flags() & kJSFlagConvertAssociativeArray)) { + PropertyNameArray propNames; + object->getPropertyNames(exec, propNames); + PropertyNameArrayIterator iter = propNames.begin(); + PropertyNameArrayIterator end = propNames.end(); + while(iter != end && isArray) + { + Identifier propName = *iter; + UString ustr = propName.ustring(); + const UniChar* uniChars = (const UniChar*)ustr.data(); + int size = ustr.size(); + while (size--) { + if (uniChars[size] < '0' || uniChars[size] > '9') { + isArray = false; + break; + } + } + iter++; + } + } + } + + if (isArray) + { + // This is an KJS array + unsigned int length = object->get(exec, "length")->toUInt32(exec); + result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); + if (result) + { + for (unsigned i = 0; i < length; i++) + { + CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, i), exec, &imps); + CFArrayAppendValue((CFMutableArrayRef)result, cfValue); + ReleaseCFType(cfValue); + } + } + } + else + { + // Not an array, just treat it like a dictionary which contains (property name, property value) pairs + PropertyNameArray propNames; + object->getPropertyNames(exec, propNames); + { + result = CFDictionaryCreateMutable(0, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (result) + { + PropertyNameArrayIterator iter = propNames.begin(); + PropertyNameArrayIterator end = propNames.end(); + while(iter != end) + { + Identifier propName = *iter; + if (object->hasProperty(exec, propName)) + { + CFStringRef cfKey = IdentifierToCFString(propName); + CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, propName), exec, &imps); + if (cfKey && cfValue) + { + CFDictionaryAddValue((CFMutableDictionaryRef)result, cfKey, cfValue); + } + ReleaseCFType(cfKey); + ReleaseCFType(cfValue); + } + iter++; + } + } + } + } + } + } + break; + + case NullType: + case UndefinedType: + case UnspecifiedType: + result = RetainCFType(GetCFNull()); + break; + + default: + fprintf(stderr, "KJSValueToCFType: wrong value type %d\n", inValue->type()); + break; + } + + return result; +} + +CFTypeRef KJSValueToCFType(JSValue *inValue, ExecState *exec) +{ + return KJSValueToCFTypeInternal(inValue, exec, 0); +} + +CFTypeRef GetCFNull(void) +{ + static CFArrayRef sCFNull = CFArrayCreate(0, 0, 0, 0); + CFTypeRef result = JSGetCFNull(); + if (!result) + { + result = sCFNull; + } + return result; +} +