|         |      1 /* | 
|         |      2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved. | 
|         |      3  * | 
|         |      4  * Redistribution and use in source and binary forms, with or without | 
|         |      5  * modification, are permitted provided that the following conditions | 
|         |      6  * are met: | 
|         |      7  * | 
|         |      8  * 1.  Redistributions of source code must retain the above copyright | 
|         |      9  *     notice, this list of conditions and the following disclaimer.  | 
|         |     10  * 2.  Redistributions in binary form must reproduce the above copyright | 
|         |     11  *     notice, this list of conditions and the following disclaimer in the | 
|         |     12  *     documentation and/or other materials provided with the distribution.  | 
|         |     13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of | 
|         |     14  *     its contributors may be used to endorse or promote products derived | 
|         |     15  *     from this software without specific prior written permission.  | 
|         |     16  * | 
|         |     17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | 
|         |     18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 
|         |     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
|         |     20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | 
|         |     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 
|         |     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
|         |     23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 
|         |     24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|         |     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 
|         |     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|         |     27  */ | 
|         |     28  | 
|         |     29 #include "config.h" | 
|         |     30 #include "UserObjectImp.h" | 
|         |     31 #include <JavaScriptCore/PropertyNameArray.h> | 
|         |     32  | 
|         |     33 const ClassInfo UserObjectImp::info = {"UserObject", 0, 0, 0}; | 
|         |     34  | 
|         |     35 UserObjectImp::UserObjectImp(JSUserObject* userObject) | 
|         |     36     : fJSUserObject((JSUserObject*)userObject->Retain()) | 
|         |     37 { | 
|         |     38 } | 
|         |     39  | 
|         |     40 UserObjectImp::~UserObjectImp() | 
|         |     41 { | 
|         |     42     if (fJSUserObject) | 
|         |     43         fJSUserObject->Release(); | 
|         |     44 } | 
|         |     45  | 
|         |     46 const ClassInfo * UserObjectImp::classInfo() const | 
|         |     47 { | 
|         |     48     return &info; | 
|         |     49 } | 
|         |     50  | 
|         |     51 bool UserObjectImp::implementsCall() const | 
|         |     52 { | 
|         |     53     return fJSUserObject ? fJSUserObject->ImplementsCall() : false; | 
|         |     54 } | 
|         |     55  | 
|         |     56 JSValue *UserObjectImp::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) | 
|         |     57 { | 
|         |     58     JSValue *result = jsUndefined(); | 
|         |     59     JSUserObject* jsThisObj = KJSValueToJSObject(thisObj, exec); | 
|         |     60     if (jsThisObj) { | 
|         |     61         CFIndex argCount = args.size(); | 
|         |     62         CFArrayCallBacks arrayCallBacks; | 
|         |     63         JSTypeGetCFArrayCallBacks(&arrayCallBacks); | 
|         |     64         CFMutableArrayRef jsArgs = CFArrayCreateMutable(0, 0, &arrayCallBacks); | 
|         |     65         if (jsArgs) { | 
|         |     66             for (CFIndex i = 0; i < argCount; i++) { | 
|         |     67                 JSUserObject* jsArg = KJSValueToJSObject(args[i], exec); | 
|         |     68                 CFArrayAppendValue(jsArgs, (void*)jsArg); | 
|         |     69                 jsArg->Release(); | 
|         |     70             } | 
|         |     71         } | 
|         |     72  | 
|         |     73         JSUserObject* jsResult; | 
|         |     74         { // scope | 
|         |     75             JSLock::DropAllLocks dropLocks; | 
|         |     76  | 
|         |     77             // implementsCall should have guarded against a NULL fJSUserObject. | 
|         |     78             assert(fJSUserObject); | 
|         |     79             jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs); | 
|         |     80         } | 
|         |     81  | 
|         |     82         if (jsResult) { | 
|         |     83             result = JSObjectKJSValue(jsResult); | 
|         |     84             jsResult->Release(); | 
|         |     85         } | 
|         |     86  | 
|         |     87         ReleaseCFType(jsArgs); | 
|         |     88         jsThisObj->Release(); | 
|         |     89     } | 
|         |     90     return result; | 
|         |     91 } | 
|         |     92  | 
|         |     93  | 
|         |     94 void UserObjectImp::getPropertyNames(ExecState *exec, PropertyNameArray& propertyNames) | 
|         |     95 { | 
|         |     96     JSUserObject* ptr = GetJSUserObject(); | 
|         |     97     if (ptr) { | 
|         |     98         CFArrayRef cfPropertyNames = ptr->CopyPropertyNames(); | 
|         |     99         if (cfPropertyNames) { | 
|         |    100             CFIndex count = CFArrayGetCount(cfPropertyNames); | 
|         |    101             CFIndex i; | 
|         |    102             for (i = 0; i < count; i++) { | 
|         |    103                 CFStringRef propertyName = (CFStringRef)CFArrayGetValueAtIndex(cfPropertyNames, i); | 
|         |    104                 propertyNames.add(CFStringToIdentifier(propertyName)); | 
|         |    105             } | 
|         |    106             CFRelease(cfPropertyNames); | 
|         |    107         } | 
|         |    108     } | 
|         |    109     JSObject::getPropertyNames(exec, propertyNames); | 
|         |    110 } | 
|         |    111  | 
|         |    112 JSValue *UserObjectImp::userObjectGetter(ExecState *, JSObject *, const Identifier& propertyName, const PropertySlot& slot) | 
|         |    113 { | 
|         |    114     UserObjectImp *thisObj = static_cast<UserObjectImp *>(slot.slotBase()); | 
|         |    115     // getOwnPropertySlot should have guarded against a null fJSUserObject. | 
|         |    116     assert(thisObj->fJSUserObject); | 
|         |    117      | 
|         |    118     CFStringRef cfPropName = IdentifierToCFString(propertyName); | 
|         |    119     JSUserObject *jsResult = thisObj->fJSUserObject->CopyProperty(cfPropName); | 
|         |    120     ReleaseCFType(cfPropName); | 
|         |    121     JSValue *result = JSObjectKJSValue(jsResult); | 
|         |    122     jsResult->Release(); | 
|         |    123  | 
|         |    124     return result; | 
|         |    125 } | 
|         |    126  | 
|         |    127 bool UserObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) | 
|         |    128 { | 
|         |    129     if (!fJSUserObject) | 
|         |    130         return false; | 
|         |    131  | 
|         |    132     CFStringRef cfPropName = IdentifierToCFString(propertyName); | 
|         |    133     JSUserObject *jsResult = fJSUserObject->CopyProperty(cfPropName); | 
|         |    134     ReleaseCFType(cfPropName); | 
|         |    135     if (jsResult) { | 
|         |    136         slot.setCustom(this, userObjectGetter); | 
|         |    137         jsResult->Release(); | 
|         |    138         return true; | 
|         |    139     } else { | 
|         |    140         JSValue *kjsValue = toPrimitive(exec); | 
|         |    141         if (kjsValue->type() != NullType && kjsValue->type() != UndefinedType) { | 
|         |    142             JSObject *kjsObject = kjsValue->toObject(exec); | 
|         |    143             if (kjsObject->getPropertySlot(exec, propertyName, slot)) | 
|         |    144                 return true; | 
|         |    145         } | 
|         |    146     } | 
|         |    147     return JSObject::getOwnPropertySlot(exec, propertyName, slot); | 
|         |    148 } | 
|         |    149  | 
|         |    150 void UserObjectImp::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr) | 
|         |    151 { | 
|         |    152     if (!fJSUserObject) | 
|         |    153         return; | 
|         |    154      | 
|         |    155     CFStringRef cfPropName = IdentifierToCFString(propertyName); | 
|         |    156     JSUserObject *jsValueObj = KJSValueToJSObject(value, exec); | 
|         |    157  | 
|         |    158     fJSUserObject->SetProperty(cfPropName, jsValueObj); | 
|         |    159  | 
|         |    160     if (jsValueObj) jsValueObj->Release(); | 
|         |    161     ReleaseCFType(cfPropName); | 
|         |    162 } | 
|         |    163  | 
|         |    164 JSUserObject* UserObjectImp::GetJSUserObject() const | 
|         |    165 { | 
|         |    166     return fJSUserObject; | 
|         |    167 } | 
|         |    168  | 
|         |    169 JSValue *UserObjectImp::toPrimitive(ExecState *exec, JSType preferredType) const | 
|         |    170 { | 
|         |    171     JSValue *result = jsUndefined(); | 
|         |    172     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); | 
|         |    173     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0; | 
|         |    174     if (cfValue) { | 
|         |    175         CFTypeID cfType = CFGetTypeID(cfValue);  // toPrimitive | 
|         |    176         if (cfValue == GetCFNull()) { | 
|         |    177             result = jsNull(); | 
|         |    178         } | 
|         |    179         else if (cfType == CFBooleanGetTypeID()) { | 
|         |    180             if (cfValue == kCFBooleanTrue) { | 
|         |    181                 result = jsBoolean(true); | 
|         |    182             } else { | 
|         |    183                 result = jsBoolean(false); | 
|         |    184             } | 
|         |    185         } else if (cfType == CFStringGetTypeID()) { | 
|         |    186             result = jsString(CFStringToUString((CFStringRef)cfValue)); | 
|         |    187         } else if (cfType == CFNumberGetTypeID()) { | 
|         |    188             double d = 0.0; | 
|         |    189             CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d); | 
|         |    190             result = jsNumber(d); | 
|         |    191         } else if (cfType == CFURLGetTypeID()) { | 
|         |    192             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue); | 
|         |    193             if (absURL) { | 
|         |    194                 result = jsString(CFStringToUString(CFURLGetString(absURL))); | 
|         |    195                 ReleaseCFType(absURL); | 
|         |    196             } | 
|         |    197         } | 
|         |    198         ReleaseCFType(cfValue); | 
|         |    199     } | 
|         |    200     if (jsObjPtr) | 
|         |    201         jsObjPtr->Release(); | 
|         |    202     return result; | 
|         |    203 } | 
|         |    204  | 
|         |    205  | 
|         |    206 bool UserObjectImp::toBoolean(ExecState *exec) const | 
|         |    207 { | 
|         |    208     bool result = false; | 
|         |    209     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); | 
|         |    210     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0; | 
|         |    211     if (cfValue) | 
|         |    212     { | 
|         |    213         CFTypeID cfType = CFGetTypeID(cfValue);  // toPrimitive | 
|         |    214         if (cfValue == GetCFNull()) | 
|         |    215         { | 
|         |    216             // | 
|         |    217         } | 
|         |    218         else if (cfType == CFBooleanGetTypeID()) | 
|         |    219         { | 
|         |    220             if (cfValue == kCFBooleanTrue) | 
|         |    221             { | 
|         |    222                 result = true; | 
|         |    223             } | 
|         |    224         } | 
|         |    225         else if (cfType == CFStringGetTypeID()) | 
|         |    226         { | 
|         |    227             if (CFStringGetLength((CFStringRef)cfValue)) | 
|         |    228             { | 
|         |    229                 result = true; | 
|         |    230             } | 
|         |    231         } | 
|         |    232         else if (cfType == CFNumberGetTypeID()) | 
|         |    233         { | 
|         |    234             if (cfValue != kCFNumberNaN) | 
|         |    235             { | 
|         |    236                 double d; | 
|         |    237                 if (CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d)) | 
|         |    238                 { | 
|         |    239                     if (d != 0) | 
|         |    240                     { | 
|         |    241                         result = true; | 
|         |    242                     } | 
|         |    243                 } | 
|         |    244             } | 
|         |    245         } | 
|         |    246         else if (cfType == CFArrayGetTypeID()) | 
|         |    247         { | 
|         |    248             if (CFArrayGetCount((CFArrayRef)cfValue)) | 
|         |    249             { | 
|         |    250                 result = true; | 
|         |    251             } | 
|         |    252         } | 
|         |    253         else if (cfType == CFDictionaryGetTypeID()) | 
|         |    254         { | 
|         |    255             if (CFDictionaryGetCount((CFDictionaryRef)cfValue)) | 
|         |    256             { | 
|         |    257                 result = true; | 
|         |    258             } | 
|         |    259         } | 
|         |    260         else if (cfType == CFSetGetTypeID()) | 
|         |    261         { | 
|         |    262             if (CFSetGetCount((CFSetRef)cfValue)) | 
|         |    263             { | 
|         |    264                 result = true; | 
|         |    265             } | 
|         |    266         } | 
|         |    267         else if (cfType == CFURLGetTypeID()) | 
|         |    268         { | 
|         |    269             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue); | 
|         |    270             if (absURL) | 
|         |    271             { | 
|         |    272                 CFStringRef cfStr = CFURLGetString(absURL); | 
|         |    273                 if (cfStr && CFStringGetLength(cfStr)) | 
|         |    274                 { | 
|         |    275                     result = true; | 
|         |    276                 } | 
|         |    277                 ReleaseCFType(absURL); | 
|         |    278             } | 
|         |    279         } | 
|         |    280     } | 
|         |    281     if (jsObjPtr) jsObjPtr->Release(); | 
|         |    282     ReleaseCFType(cfValue); | 
|         |    283     return result; | 
|         |    284 } | 
|         |    285  | 
|         |    286 double UserObjectImp::toNumber(ExecState *exec) const | 
|         |    287 { | 
|         |    288     double result = 0; | 
|         |    289     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); | 
|         |    290     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0; | 
|         |    291     if (cfValue) | 
|         |    292     { | 
|         |    293         CFTypeID cfType = CFGetTypeID(cfValue); | 
|         |    294  | 
|         |    295         if (cfValue == GetCFNull()) | 
|         |    296         { | 
|         |    297             // | 
|         |    298         } | 
|         |    299         else if (cfType == CFBooleanGetTypeID()) | 
|         |    300         { | 
|         |    301             if (cfValue == kCFBooleanTrue) | 
|         |    302             { | 
|         |    303                 result = 1; | 
|         |    304             } | 
|         |    305         } | 
|         |    306         else if (cfType == CFStringGetTypeID()) | 
|         |    307         { | 
|         |    308             result = CFStringGetDoubleValue((CFStringRef)cfValue); | 
|         |    309         } | 
|         |    310         else if (cfType == CFNumberGetTypeID()) | 
|         |    311         { | 
|         |    312             CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &result); | 
|         |    313         } | 
|         |    314     } | 
|         |    315     ReleaseCFType(cfValue); | 
|         |    316     if (jsObjPtr) jsObjPtr->Release(); | 
|         |    317     return result; | 
|         |    318 } | 
|         |    319  | 
|         |    320 UString UserObjectImp::toString(ExecState *exec) const | 
|         |    321 { | 
|         |    322     UString result; | 
|         |    323     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec); | 
|         |    324     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0; | 
|         |    325     if (cfValue) | 
|         |    326     { | 
|         |    327         CFTypeID cfType = CFGetTypeID(cfValue); | 
|         |    328         if (cfValue == GetCFNull()) | 
|         |    329         { | 
|         |    330             // | 
|         |    331         } | 
|         |    332         else if (cfType == CFBooleanGetTypeID()) | 
|         |    333         { | 
|         |    334             if (cfValue == kCFBooleanTrue) | 
|         |    335             { | 
|         |    336                 result = "true"; | 
|         |    337             } | 
|         |    338             else | 
|         |    339             { | 
|         |    340                 result = "false"; | 
|         |    341             } | 
|         |    342         } | 
|         |    343         else if (cfType == CFStringGetTypeID()) | 
|         |    344         { | 
|         |    345             result = CFStringToUString((CFStringRef)cfValue); | 
|         |    346         } | 
|         |    347         else if (cfType == CFNumberGetTypeID()) | 
|         |    348         { | 
|         |    349             if (cfValue == kCFNumberNaN) | 
|         |    350             { | 
|         |    351                 result = "Nan"; | 
|         |    352             } | 
|         |    353             else if (CFNumberCompare(kCFNumberPositiveInfinity, (CFNumberRef)cfValue, 0) == 0) | 
|         |    354             { | 
|         |    355                 result = "Infinity"; | 
|         |    356             } | 
|         |    357             else if (CFNumberCompare(kCFNumberNegativeInfinity, (CFNumberRef)cfValue, 0) == 0) | 
|         |    358             { | 
|         |    359                 result = "-Infinity"; | 
|         |    360             } | 
|         |    361             else | 
|         |    362             { | 
|         |    363                 CFStringRef cfNumStr; | 
|         |    364                 double d = 0; | 
|         |    365                 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d); | 
|         |    366                 if (CFNumberIsFloatType((CFNumberRef)cfValue)) | 
|         |    367                 { | 
|         |    368                     cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%f"), d); | 
|         |    369                 } | 
|         |    370                 else | 
|         |    371                 { | 
|         |    372                     cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%.0f"), d); | 
|         |    373                 } | 
|         |    374                 result = CFStringToUString(cfNumStr); | 
|         |    375                 ReleaseCFType(cfNumStr); | 
|         |    376             } | 
|         |    377         } | 
|         |    378         else if (cfType == CFArrayGetTypeID()) | 
|         |    379         { | 
|         |    380             // | 
|         |    381         } | 
|         |    382         else if (cfType == CFDictionaryGetTypeID()) | 
|         |    383         { | 
|         |    384             // | 
|         |    385         } | 
|         |    386         else if (cfType == CFSetGetTypeID()) | 
|         |    387         { | 
|         |    388             // | 
|         |    389         } | 
|         |    390         else if (cfType == CFURLGetTypeID()) | 
|         |    391         { | 
|         |    392             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue); | 
|         |    393             if (absURL) | 
|         |    394             { | 
|         |    395                 CFStringRef cfStr = CFURLGetString(absURL); | 
|         |    396                 if (cfStr) | 
|         |    397                 { | 
|         |    398                     result = CFStringToUString(cfStr); | 
|         |    399                 } | 
|         |    400                 ReleaseCFType(absURL); | 
|         |    401             } | 
|         |    402         } | 
|         |    403     } | 
|         |    404     ReleaseCFType(cfValue); | 
|         |    405     if (jsObjPtr) jsObjPtr->Release(); | 
|         |    406     return result; | 
|         |    407 } | 
|         |    408  | 
|         |    409 void UserObjectImp::mark() | 
|         |    410 { | 
|         |    411     JSObject::mark(); | 
|         |    412     if (fJSUserObject) | 
|         |    413         fJSUserObject->Mark(); | 
|         |    414 } |