JSValue *UserObjectImp::toPrimitive(ExecState *exec, JSType preferredType) const { JSValue *result = jsUndefined(); JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0; if (cfValue) { CFTypeID cfType = CFGetTypeID(cfValue); // toPrimitive if (cfValue == GetCFNull()) { result = jsNull(); } else if (cfType == CFBooleanGetTypeID()) { if (cfValue == kCFBooleanTrue) { result = jsBoolean(true); } else { result = jsBoolean(false); } } else if (cfType == CFStringGetTypeID()) { result = jsString(CFStringToUString((CFStringRef)cfValue)); } else if (cfType == CFNumberGetTypeID()) { double d = 0.0; CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d); result = jsNumber(d); } else if (cfType == CFURLGetTypeID()) { CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue); if (absURL) { result = jsString(CFStringToUString(CFURLGetString(absURL))); ReleaseCFType(absURL); } } ReleaseCFType(cfValue); } if (jsObjPtr) jsObjPtr->Release(); return result; }
double UserObjectImp::toNumber(ExecState *exec) const { double result = 0; JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0; 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; }
void UserObjectImp::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr) { if (!fJSUserObject) return; CFStringRef cfPropName = IdentifierToCFString(propertyName); JSUserObject *jsValueObj = KJSValueToJSObject(value, exec); fJSUserObject->SetProperty(cfPropName, jsValueObj); if (jsValueObj) jsValueObj->Release(); ReleaseCFType(cfPropName); }
JSValue *UserObjectImp::userObjectGetter(ExecState *, JSObject *, const Identifier& propertyName, const PropertySlot& slot) { UserObjectImp *thisObj = static_cast<UserObjectImp *>(slot.slotBase()); // getOwnPropertySlot should have guarded against a null fJSUserObject. assert(thisObj->fJSUserObject); CFStringRef cfPropName = IdentifierToCFString(propertyName); JSUserObject *jsResult = thisObj->fJSUserObject->CopyProperty(cfPropName); ReleaseCFType(cfPropName); JSValue *result = JSObjectKJSValue(jsResult); jsResult->Release(); return result; }
UInt8 JSUserObject::Equal(JSBase* other) { UInt8 result = false; JSUserObject* obj = (JSUserObject*)other; if (obj->GetTypeID() == kJSObjectTypeID) { if (fCallBacks.equal) { result = fCallBacks.equal(GetData(), obj->GetData()); } else { CFTypeRef cf1 = CopyCFValue(); CFTypeRef cf2 = obj->CopyCFValue(); if (cf1 && cf2) { result = CFEqual(cf1, cf2); } ReleaseCFType(cf2); ReleaseCFType(cf1); } } return result; }
bool UserObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) { if (!fJSUserObject) return false; CFStringRef cfPropName = IdentifierToCFString(propertyName); JSUserObject *jsResult = fJSUserObject->CopyProperty(cfPropName); ReleaseCFType(cfPropName); if (jsResult) { slot.setCustom(this, userObjectGetter); jsResult->Release(); return true; } else { JSValue *kjsValue = toPrimitive(exec); if (kjsValue->type() != NullType && kjsValue->type() != UndefinedType) { JSObject *kjsObject = kjsValue->toObject(exec); if (kjsObject->getPropertySlot(exec, propertyName, slot)) return true; } } return JSObject::getOwnPropertySlot(exec, propertyName, slot); }
JSValue *UserObjectImp::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) { JSValue *result = jsUndefined(); JSUserObject* jsThisObj = KJSValueToJSObject(thisObj, exec); if (jsThisObj) { CFIndex argCount = args.size(); CFArrayCallBacks arrayCallBacks; JSTypeGetCFArrayCallBacks(&arrayCallBacks); CFMutableArrayRef jsArgs = CFArrayCreateMutable(0, 0, &arrayCallBacks); if (jsArgs) { for (CFIndex i = 0; i < argCount; i++) { JSUserObject* jsArg = KJSValueToJSObject(args[i], exec); CFArrayAppendValue(jsArgs, (void*)jsArg); jsArg->Release(); } } JSUserObject* jsResult; { // scope JSLock::DropAllLocks dropLocks; // implementsCall should have guarded against a NULL fJSUserObject. assert(fJSUserObject); jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs); } if (jsResult) { result = JSObjectKJSValue(jsResult); jsResult->Release(); } ReleaseCFType(jsArgs); jsThisObj->Release(); } return result; }
JSValue UserObjectImp::callAsFunction(ExecState *exec) { JSValue result = jsUndefined(); JSUserObject* jsThisObj = KJSValueToJSObject(exec->hostThisValue().toThisObject(exec), exec); if (jsThisObj) { CFIndex argCount = exec->argumentCount(); CFArrayCallBacks arrayCallBacks; JSTypeGetCFArrayCallBacks(&arrayCallBacks); CFMutableArrayRef jsArgs = CFArrayCreateMutable(0, 0, &arrayCallBacks); if (jsArgs) { for (CFIndex i = 0; i < argCount; i++) { JSUserObject* jsArg = KJSValueToJSObject(exec->argument(i), exec); CFArrayAppendValue(jsArgs, (void*)jsArg); jsArg->Release(); } } JSUserObject* jsResult; { // scope JSGlueAPICallback apiCallback(exec); // getCallData should have guarded against a NULL fJSUserObject. assert(fJSUserObject); jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs); } if (jsResult) { result = JSObjectKJSValue(jsResult); jsResult->Release(); } ReleaseCFType(jsArgs); jsThisObj->Release(); } return result; }
UString UserObjectImp::toString(ExecState *exec) const { UString result; JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0; 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, 0) == 0) { result = "Infinity"; } else if (CFNumberCompare(kCFNumberNegativeInfinity, (CFNumberRef)cfValue, 0) == 0) { result = "-Infinity"; } else { CFStringRef cfNumStr; double d = 0; CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d); if (CFNumberIsFloatType((CFNumberRef)cfValue)) { cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%f"), d); } else { cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%.0f"), d); } 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; }
bool UserObjectImp::toBoolean(ExecState *exec) const { bool result = false; JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0; 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; }
//-------------------------------------------------------------------------- // KJSValueToCFTypeInternal //-------------------------------------------------------------------------- // Caller is responsible for releasing the returned CFTypeRef CFTypeRef KJSValueToCFTypeInternal(JSValue inValue, ExecState *exec, ObjectImpList* inImps) { if (!inValue) return 0; CFTypeRef result = 0; JSGlueAPIEntry entry; if (inValue.isBoolean()) { result = inValue.toBoolean(exec) ? kCFBooleanTrue : kCFBooleanFalse; RetainCFType(result); return result; } if (inValue.isString()) { UString uString = inValue.toString(exec); result = UStringToCFString(uString); return result; } if (inValue.isNumber()) { 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); } return result; } if (inValue.isObject()) { if (inValue.inherits(&UserObjectImp::info)) { UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(asObject(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; JSGlueGlobalObject* globalObject = static_cast<JSGlueGlobalObject*>(exec->dynamicGlobalObject()); if (globalObject && (globalObject->Flags() & kJSFlagConvertAssociativeArray)) { PropertyNameArray propNames(exec); object->getPropertyNames(exec, propNames); PropertyNameArray::const_iterator iter = propNames.begin(); PropertyNameArray::const_iterator end = propNames.end(); while(iter != end && isArray) { Identifier propName = *iter; UString ustr = propName.ustring(); const UniChar* uniChars = (const UniChar*)ustr.characters(); int size = ustr.length(); 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, Identifier(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(exec); object->getPropertyNames(exec, propNames); { result = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (result) { PropertyNameArray::const_iterator iter = propNames.begin(); PropertyNameArray::const_iterator 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++; } } } } } return result; } if (inValue.isUndefinedOrNull()) { result = RetainCFType(GetCFNull()); return result; } ASSERT_NOT_REACHED(); return 0; }
void JSSetCFNull(CFTypeRef nullRef) { ReleaseCFType(sJSCFNullRef); sJSCFNullRef = RetainCFType(nullRef); }