#include "UserObjectImp.h" const ClassInfo UserObjectImp::info = {"UserObject", 0, 0, 0}; class UserObjectPrototypeImp : public UserObjectImp { public: UserObjectPrototypeImp(); static UserObjectPrototypeImp* GlobalUserObjectPrototypeImp(); private: static UserObjectPrototypeImp* sUserObjectPrototypeImp; }; UserObjectPrototypeImp* UserObjectPrototypeImp::sUserObjectPrototypeImp = NULL; UserObjectPrototypeImp::UserObjectPrototypeImp() : UserObjectImp() { } UserObjectPrototypeImp* UserObjectPrototypeImp::GlobalUserObjectPrototypeImp() { if (!sUserObjectPrototypeImp) { sUserObjectPrototypeImp = new UserObjectPrototypeImp(); static ProtectedValue protectPrototype = Value(sUserObjectPrototypeImp); } return sUserObjectPrototypeImp; } UserObjectImp::UserObjectImp(): ObjectImp(), fJSUserObject(NULL) { } UserObjectImp::UserObjectImp(JSUserObject* userObject) : ObjectImp(Object(UserObjectPrototypeImp::GlobalUserObjectPrototypeImp())), fJSUserObject((JSUserObject*)userObject->Retain()) { } UserObjectImp::~UserObjectImp() { if (fJSUserObject) { fJSUserObject->Release(); } } const ClassInfo * UserObjectImp::classInfo() const { return &info; } bool UserObjectImp::implementsCall() const { return fJSUserObject ? fJSUserObject->ImplementsCall() : false; } Value UserObjectImp::call(ExecState *exec, Object &thisObj, const List &args) { Value result = Undefined(); JSUserObject* jsThisObj = KJSValueToJSObject(thisObj, exec); if (jsThisObj) { CFIndex argCount = args.size(); CFArrayCallBacks arrayCallBacks; JSTypeGetCFArrayCallBacks(&arrayCallBacks); CFMutableArrayRef jsArgs = CFArrayCreateMutable(NULL, 0, &arrayCallBacks); if (jsArgs) { for (CFIndex i = 0; i < argCount; i++) { JSUserObject* jsArg = KJSValueToJSObject(args[i], exec); CFArrayAppendValue(jsArgs, (void*)jsArg); jsArg->Release(); } } #if 0 JSUserObject* jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs); #else int lockCount = Interpreter::lockCount(); int i; for (i = 0; i < lockCount; i++) { Interpreter::unlock(); } JSUserObject* jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs); for (i = 0; i < lockCount; i++) { Interpreter::lock(); } #endif if (jsResult) { result = JSObjectKJSValue(jsResult); jsResult->Release(); } ReleaseCFType(jsArgs); jsThisObj->Release(); } return result; } ReferenceList UserObjectImp::propList(ExecState *exec, bool recursive) { ReferenceList propList; JSUserObject* ptr = GetJSUserObject(); if (ptr) { Object theObject = toObject(exec); CFArrayRef propertyNames = ptr->CopyPropertyNames(); if (propertyNames) { CFIndex count = CFArrayGetCount(propertyNames); CFIndex i; for (i = 0; i < count; i++) { CFStringRef propertyName = (CFStringRef)CFArrayGetValueAtIndex(propertyNames, i); propList.append(Reference(theObject, CFStringToIdentifier(propertyName))); } CFRelease(propertyNames); } } return propList; } bool UserObjectImp::hasProperty(ExecState *exec, const Identifier &propertyName) const { Value prop = get(exec, propertyName); if (prop.type() != UndefinedType) { return true; } return ObjectImp::hasProperty(exec, propertyName); } #if JAG_PINK_OR_LATER Value UserObjectImp::get(ExecState *exec, const Identifier &propertyName) const { Value result = Undefined(); CFStringRef cfPropName = IdentifierToCFString(propertyName); JSUserObject* jsResult = fJSUserObject->CopyProperty(cfPropName); if (jsResult) { result = JSObjectKJSValue(jsResult); jsResult->Release(); } else { Value kjsValue = toPrimitive(exec); if (kjsValue.type() != NullType && kjsValue.type() != UndefinedType) { Object kjsObject = kjsValue.toObject(exec); Value kjsObjectProp = kjsObject.get(exec, propertyName); result = kjsObjectProp; } } ReleaseCFType(cfPropName); return result; } void UserObjectImp::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr) { CFStringRef cfPropName = IdentifierToCFString(propertyName); JSUserObject* jsValueObj = KJSValueToJSObject(value, exec); fJSUserObject->SetProperty(cfPropName, jsValueObj); if (jsValueObj) jsValueObj->Release(); ReleaseCFType(cfPropName); } #else //JAG_PINK_OR_LATER Value UserObjectImp::get(ExecState* exec, const UString& propertyName) const { Value result = Undefined(); CFStringRef cfPropName = UStringToCFString(propertyName); JSUserObject* jsResult = fJSUserObject->CopyProperty(cfPropName); if (jsResult) { result = JSObjectKJSValue(jsResult); jsResult->Release(); } else { Value kjsValue = toPrimitive(exec); if (kjsValue != Null() && kjsValue != Undefined()) { Object kjsObject = kjsValue.toObject(exec); Value kjsObjectProp = kjsObject.get(exec, propertyName); result = kjsObjectProp; } } ReleaseCFType(cfPropName); return result; } void UserObjectImp::put(ExecState* exec, const UString& propertyName, const Value& value, int attr) { CFStringRef cfPropName = UStringToCFString(propertyName); JSUserObject* jsValueObj = KJSValueToJSObject(value, exec); fJSUserObject->SetProperty(cfPropName, jsValueObj); if (jsValueObj) jsValueObj->Release(); ReleaseCFType(cfPropName); } #endif //JAG_PINK_OR_LATER JSUserObject* UserObjectImp::GetJSUserObject() const { return fJSUserObject; } Value UserObjectImp::toPrimitive(ExecState *exec, Type preferredType) const { Value result = Undefined(); JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : NULL; if (cfValue) { CFTypeID cfType = CFGetTypeID(cfValue); // toPrimitive if (cfValue == GetCFNull()) { result = Null(); } else if (cfType == CFBooleanGetTypeID()) { if (cfValue == kCFBooleanTrue) { result = KJS::Boolean(true); } else { result = KJS::Boolean(false); } } else if (cfType == CFStringGetTypeID()) { result = KJS::String(CFStringToUString((CFStringRef)cfValue)); } else if (cfType == CFNumberGetTypeID()) { double d = 0.0; CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d); result = KJS::Number(d); } else if (cfType == CFURLGetTypeID()) { CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue); if (absURL) { result = KJS::String(CFStringToUString(CFURLGetString(absURL))); ReleaseCFType(absURL); } } ReleaseCFType(cfValue); } if (jsObjPtr) jsObjPtr->Release(); return result; } bool UserObjectImp::toBoolean(ExecState *exec) const { bool result = false; JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : NULL; if (cfValue) { CFTypeID cfType = CFGetTypeID(cfValue); // toPrimitive if (cfValue == GetCFNull()) { // } else if (cfType == CFBooleanGetTypeID()) { if (cfValue == kCFBooleanTrue) { result = true; } } else if (cfType == CFStringGetTypeID()) { if (CFStringGetLength((CFStringRef)cfValue)) { result = true; } } else if (cfType == CFNumberGetTypeID()) { if (cfValue != kCFNumberNaN) { double d; if (CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d)) { if (d != 0) { result = true; } } } } else if (cfType == CFArrayGetTypeID()) { if (CFArrayGetCount((CFArrayRef)cfValue)) { result = true; } } else if (cfType == CFDictionaryGetTypeID()) { if (CFDictionaryGetCount((CFDictionaryRef)cfValue)) { result = true; } } else if (cfType == CFSetGetTypeID()) { if (CFSetGetCount((CFSetRef)cfValue)) { result = true; } } else if (cfType == CFURLGetTypeID()) { CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue); if (absURL) { CFStringRef cfStr = CFURLGetString(absURL); if (cfStr && CFStringGetLength(cfStr)) { result = true; } ReleaseCFType(absURL); } } } if (jsObjPtr) jsObjPtr->Release(); ReleaseCFType(cfValue); return result; } double UserObjectImp::toNumber(ExecState *exec) const { double result = 0; JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : NULL; if (cfValue) { CFTypeID cfType = CFGetTypeID(cfValue); if (cfValue == GetCFNull()) { // } else if (cfType == CFBooleanGetTypeID()) { if (cfValue == kCFBooleanTrue) { result = 1; } } else if (cfType == CFStringGetTypeID()) { result = CFStringGetDoubleValue((CFStringRef)cfValue); } else if (cfType == CFNumberGetTypeID()) { CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &result); } } ReleaseCFType(cfValue); if (jsObjPtr) jsObjPtr->Release(); return result; } UString UserObjectImp::toString(ExecState *exec) const { UString result; JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : NULL; if (cfValue) { CFTypeID cfType = CFGetTypeID(cfValue); if (cfValue == GetCFNull()) { // } else if (cfType == CFBooleanGetTypeID()) { if (cfValue == kCFBooleanTrue) { result = "true"; } else { result = "false"; } } else if (cfType == CFStringGetTypeID()) { result = CFStringToUString((CFStringRef)cfValue); } else if (cfType == CFNumberGetTypeID()) { if (cfValue == kCFNumberNaN) { result = "Nan"; } else if (CFNumberCompare(kCFNumberPositiveInfinity, (CFNumberRef)cfValue, NULL) == 0) { result = "Infinity"; } else if (CFNumberCompare(kCFNumberNegativeInfinity, (CFNumberRef)cfValue, NULL) == 0) { result = "-Infinity"; } else { CFStringRef cfNumStr = NULL; if (CFNumberIsFloatType((CFNumberRef)cfValue)) { double d = 0; CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d); cfNumStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%f"), (float)d); } else { int i = 0; CFNumberGetValue((CFNumberRef)cfValue, kCFNumberIntType, &i); cfNumStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), (int)i); } if (cfNumStr) { result = CFStringToUString(cfNumStr); ReleaseCFType(cfNumStr); } } } else if (cfType == CFArrayGetTypeID()) { // } else if (cfType == CFDictionaryGetTypeID()) { // } else if (cfType == CFSetGetTypeID()) { // } else if (cfType == CFURLGetTypeID()) { CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue); if (absURL) { CFStringRef cfStr = CFURLGetString(absURL); if (cfStr) { result = CFStringToUString(cfStr); } ReleaseCFType(absURL); } } } ReleaseCFType(cfValue); if (jsObjPtr) jsObjPtr->Release(); return result; } void UserObjectImp::mark() { ObjectImp::mark(); // call parent to mark self if (fJSUserObject) { fJSUserObject->Mark(); // mark child } }