/* * Copyright (C) 2005, 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. * 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 "UserObjectImp.h" #include #include const ClassInfo UserObjectImp::s_info = { "UserObject", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(UserObjectImp) }; UserObjectImp::UserObjectImp(JSGlobalData& globalData, Structure* structure, JSUserObject* userObject) : JSNonFinalObject(globalData, structure) , fJSUserObject((JSUserObject*)userObject->Retain()) { } UserObjectImp::~UserObjectImp() { if (fJSUserObject) fJSUserObject->Release(); } CallType UserObjectImp::getCallData(JSCell* cell, CallData& callData) { UserObjectImp* thisObject = jsCast(cell); return thisObject->fJSUserObject ? thisObject->fJSUserObject->getCallData(callData) : CallTypeNone; } 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; } void UserObjectImp::getOwnPropertyNames(JSObject* object, ExecState *exec, PropertyNameArray& propertyNames, EnumerationMode mode) { UserObjectImp* thisObject = jsCast(object); JSUserObject* ptr = thisObject->GetJSUserObject(); if (ptr) { CFArrayRef cfPropertyNames = ptr->CopyPropertyNames(); if (cfPropertyNames) { CFIndex count = CFArrayGetCount(cfPropertyNames); CFIndex i; for (i = 0; i < count; i++) { CFStringRef propertyName = (CFStringRef)CFArrayGetValueAtIndex(cfPropertyNames, i); propertyNames.add(CFStringToIdentifier(propertyName, exec)); } CFRelease(cfPropertyNames); } } JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode); } JSValue UserObjectImp::userObjectGetter(ExecState*, JSValue slotBase, const Identifier& propertyName) { UserObjectImp *thisObj = static_cast(asObject(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; } bool UserObjectImp::getOwnPropertySlot(JSCell* cell, ExecState *exec, const Identifier& propertyName, PropertySlot& slot) { UserObjectImp* thisObject = jsCast(cell); if (!thisObject->fJSUserObject) return false; CFStringRef cfPropName = IdentifierToCFString(propertyName); JSUserObject* jsResult = thisObject->fJSUserObject->CopyProperty(cfPropName); ReleaseCFType(cfPropName); if (jsResult) { slot.setCustom(thisObject, userObjectGetter); jsResult->Release(); return true; } else { JSValue kjsValue = thisObject->toPrimitive(exec); if (!kjsValue.isUndefinedOrNull()) { JSObject* kjsObject = kjsValue.toObject(exec); if (kjsObject->getPropertySlot(exec, propertyName, slot)) return true; } } return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); } void UserObjectImp::put(JSCell* cell, ExecState *exec, const Identifier &propertyName, JSValue value, PutPropertySlot&) { UserObjectImp* thisObject = jsCast(cell); if (!thisObject->fJSUserObject) return; CFStringRef cfPropName = IdentifierToCFString(propertyName); JSUserObject *jsValueObj = KJSValueToJSObject(value, exec); thisObject->fJSUserObject->SetProperty(cfPropName, jsValueObj); if (jsValueObj) jsValueObj->Release(); ReleaseCFType(cfPropName); } JSUserObject* UserObjectImp::GetJSUserObject() const { return fJSUserObject; } JSValue UserObjectImp::toPrimitive(ExecState *exec, PreferredPrimitiveType) const { JSValue result = jsUndefined(); JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec, exec->lexicalGlobalObject()), 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(exec, 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(exec, 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->lexicalGlobalObject()), 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; } void UserObjectImp::visitChildren(JSCell* cell, SlotVisitor& visitor) { UserObjectImp* thisObject = jsCast(cell); JSObject::visitChildren(thisObject, visitor); if (thisObject->fJSUserObject) thisObject->fJSUserObject->Mark(); }