Home | History | Annotate | Download | only in JavaScriptGlue
      1 /*
      2  * Copyright (C) 2005, 2008, 2009 Apple 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 
     32 #include <JavaScriptCore/JSString.h>
     33 #include <JavaScriptCore/PropertyNameArray.h>
     34 
     35 const ClassInfo UserObjectImp::info = { "UserObject", 0, 0, 0 };
     36 
     37 UserObjectImp::UserObjectImp(PassRefPtr<Structure> structure, JSUserObject* userObject)
     38     : JSObject(structure)
     39     , fJSUserObject((JSUserObject*)userObject->Retain())
     40 {
     41 }
     42 
     43 UserObjectImp::~UserObjectImp()
     44 {
     45     if (fJSUserObject)
     46         fJSUserObject->Release();
     47 }
     48 
     49 const ClassInfo * UserObjectImp::classInfo() const
     50 {
     51     return &info;
     52 }
     53 
     54 CallType UserObjectImp::getCallData(CallData& callData)
     55 {
     56     return fJSUserObject ? fJSUserObject->getCallData(callData) : CallTypeNone;
     57 }
     58 
     59 JSValue UserObjectImp::callAsFunction(ExecState *exec, JSObject *thisObj, const ArgList &args)
     60 {
     61     JSValue result = jsUndefined();
     62     JSUserObject* jsThisObj = KJSValueToJSObject(thisObj, exec);
     63     if (jsThisObj) {
     64         CFIndex argCount = args.size();
     65         CFArrayCallBacks arrayCallBacks;
     66         JSTypeGetCFArrayCallBacks(&arrayCallBacks);
     67         CFMutableArrayRef jsArgs = CFArrayCreateMutable(0, 0, &arrayCallBacks);
     68         if (jsArgs) {
     69             for (CFIndex i = 0; i < argCount; i++) {
     70                 JSUserObject* jsArg = KJSValueToJSObject(args.at(i), exec);
     71                 CFArrayAppendValue(jsArgs, (void*)jsArg);
     72                 jsArg->Release();
     73             }
     74         }
     75 
     76         JSUserObject* jsResult;
     77         { // scope
     78             JSGlueAPICallback apiCallback(exec);
     79 
     80             // getCallData should have guarded against a NULL fJSUserObject.
     81             assert(fJSUserObject);
     82             jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs);
     83         }
     84 
     85         if (jsResult) {
     86             result = JSObjectKJSValue(jsResult);
     87             jsResult->Release();
     88         }
     89 
     90         ReleaseCFType(jsArgs);
     91         jsThisObj->Release();
     92     }
     93     return result;
     94 }
     95 
     96 
     97 void UserObjectImp::getOwnPropertyNames(ExecState *exec, PropertyNameArray& propertyNames, EnumerationMode mode)
     98 {
     99     JSUserObject* ptr = GetJSUserObject();
    100     if (ptr) {
    101         CFArrayRef cfPropertyNames = ptr->CopyPropertyNames();
    102         if (cfPropertyNames) {
    103             CFIndex count = CFArrayGetCount(cfPropertyNames);
    104             CFIndex i;
    105             for (i = 0; i < count; i++) {
    106                 CFStringRef propertyName = (CFStringRef)CFArrayGetValueAtIndex(cfPropertyNames, i);
    107                 propertyNames.add(CFStringToIdentifier(propertyName, exec));
    108             }
    109             CFRelease(cfPropertyNames);
    110         }
    111     }
    112     JSObject::getOwnPropertyNames(exec, propertyNames, mode);
    113 }
    114 
    115 JSValue UserObjectImp::userObjectGetter(ExecState*, const Identifier& propertyName, const PropertySlot& slot)
    116 {
    117     UserObjectImp *thisObj = static_cast<UserObjectImp *>(asObject(slot.slotBase()));
    118     // getOwnPropertySlot should have guarded against a null fJSUserObject.
    119     assert(thisObj->fJSUserObject);
    120 
    121     CFStringRef cfPropName = IdentifierToCFString(propertyName);
    122     JSUserObject *jsResult = thisObj->fJSUserObject->CopyProperty(cfPropName);
    123     ReleaseCFType(cfPropName);
    124     JSValue result = JSObjectKJSValue(jsResult);
    125     jsResult->Release();
    126 
    127     return result;
    128 }
    129 
    130 bool UserObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
    131 {
    132     if (!fJSUserObject)
    133         return false;
    134 
    135     CFStringRef cfPropName = IdentifierToCFString(propertyName);
    136     JSUserObject *jsResult = fJSUserObject->CopyProperty(cfPropName);
    137     ReleaseCFType(cfPropName);
    138     if (jsResult) {
    139         slot.setCustom(this, userObjectGetter);
    140         jsResult->Release();
    141         return true;
    142     } else {
    143         JSValue kjsValue = toPrimitive(exec);
    144         if (!kjsValue.isUndefinedOrNull()) {
    145             JSObject* kjsObject = kjsValue.toObject(exec);
    146             if (kjsObject->getPropertySlot(exec, propertyName, slot))
    147                 return true;
    148         }
    149     }
    150     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
    151 }
    152 
    153 void UserObjectImp::put(ExecState *exec, const Identifier &propertyName, JSValue value, PutPropertySlot&)
    154 {
    155     if (!fJSUserObject)
    156         return;
    157 
    158     CFStringRef cfPropName = IdentifierToCFString(propertyName);
    159     JSUserObject *jsValueObj = KJSValueToJSObject(value, exec);
    160 
    161     fJSUserObject->SetProperty(cfPropName, jsValueObj);
    162 
    163     if (jsValueObj) jsValueObj->Release();
    164     ReleaseCFType(cfPropName);
    165 }
    166 
    167 JSUserObject* UserObjectImp::GetJSUserObject() const
    168 {
    169     return fJSUserObject;
    170 }
    171 
    172 JSValue UserObjectImp::toPrimitive(ExecState *exec, JSType) const
    173 {
    174     JSValue result = jsUndefined();
    175     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
    176     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
    177     if (cfValue) {
    178         CFTypeID cfType = CFGetTypeID(cfValue);  // toPrimitive
    179         if (cfValue == GetCFNull()) {
    180             result = jsNull();
    181         }
    182         else if (cfType == CFBooleanGetTypeID()) {
    183             if (cfValue == kCFBooleanTrue) {
    184                 result = jsBoolean(true);
    185             } else {
    186                 result = jsBoolean(false);
    187             }
    188         } else if (cfType == CFStringGetTypeID()) {
    189             result = jsString(exec, CFStringToUString((CFStringRef)cfValue));
    190         } else if (cfType == CFNumberGetTypeID()) {
    191             double d = 0.0;
    192             CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
    193             result = jsNumber(exec, d);
    194         } else if (cfType == CFURLGetTypeID()) {
    195             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
    196             if (absURL) {
    197                 result = jsString(exec, CFStringToUString(CFURLGetString(absURL)));
    198                 ReleaseCFType(absURL);
    199             }
    200         }
    201         ReleaseCFType(cfValue);
    202     }
    203     if (jsObjPtr)
    204         jsObjPtr->Release();
    205     return result;
    206 }
    207 
    208 
    209 bool UserObjectImp::toBoolean(ExecState *exec) const
    210 {
    211     bool result = false;
    212     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
    213     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
    214     if (cfValue)
    215     {
    216         CFTypeID cfType = CFGetTypeID(cfValue);  // toPrimitive
    217         if (cfValue == GetCFNull())
    218         {
    219             //
    220         }
    221         else if (cfType == CFBooleanGetTypeID())
    222         {
    223             if (cfValue == kCFBooleanTrue)
    224             {
    225                 result = true;
    226             }
    227         }
    228         else if (cfType == CFStringGetTypeID())
    229         {
    230             if (CFStringGetLength((CFStringRef)cfValue))
    231             {
    232                 result = true;
    233             }
    234         }
    235         else if (cfType == CFNumberGetTypeID())
    236         {
    237             if (cfValue != kCFNumberNaN)
    238             {
    239                 double d;
    240                 if (CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d))
    241                 {
    242                     if (d != 0)
    243                     {
    244                         result = true;
    245                     }
    246                 }
    247             }
    248         }
    249         else if (cfType == CFArrayGetTypeID())
    250         {
    251             if (CFArrayGetCount((CFArrayRef)cfValue))
    252             {
    253                 result = true;
    254             }
    255         }
    256         else if (cfType == CFDictionaryGetTypeID())
    257         {
    258             if (CFDictionaryGetCount((CFDictionaryRef)cfValue))
    259             {
    260                 result = true;
    261             }
    262         }
    263         else if (cfType == CFSetGetTypeID())
    264         {
    265             if (CFSetGetCount((CFSetRef)cfValue))
    266             {
    267                 result = true;
    268             }
    269         }
    270         else if (cfType == CFURLGetTypeID())
    271         {
    272             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
    273             if (absURL)
    274             {
    275                 CFStringRef cfStr = CFURLGetString(absURL);
    276                 if (cfStr && CFStringGetLength(cfStr))
    277                 {
    278                     result = true;
    279                 }
    280                 ReleaseCFType(absURL);
    281             }
    282         }
    283     }
    284     if (jsObjPtr) jsObjPtr->Release();
    285     ReleaseCFType(cfValue);
    286     return result;
    287 }
    288 
    289 double UserObjectImp::toNumber(ExecState *exec) const
    290 {
    291     double result = 0;
    292     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
    293     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
    294     if (cfValue)
    295     {
    296         CFTypeID cfType = CFGetTypeID(cfValue);
    297 
    298         if (cfValue == GetCFNull())
    299         {
    300             //
    301         }
    302         else if (cfType == CFBooleanGetTypeID())
    303         {
    304             if (cfValue == kCFBooleanTrue)
    305             {
    306                 result = 1;
    307             }
    308         }
    309         else if (cfType == CFStringGetTypeID())
    310         {
    311             result = CFStringGetDoubleValue((CFStringRef)cfValue);
    312         }
    313         else if (cfType == CFNumberGetTypeID())
    314         {
    315             CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &result);
    316         }
    317     }
    318     ReleaseCFType(cfValue);
    319     if (jsObjPtr) jsObjPtr->Release();
    320     return result;
    321 }
    322 
    323 UString UserObjectImp::toString(ExecState *exec) const
    324 {
    325     UString result;
    326     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
    327     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
    328     if (cfValue)
    329     {
    330         CFTypeID cfType = CFGetTypeID(cfValue);
    331         if (cfValue == GetCFNull())
    332         {
    333             //
    334         }
    335         else if (cfType == CFBooleanGetTypeID())
    336         {
    337             if (cfValue == kCFBooleanTrue)
    338             {
    339                 result = "true";
    340             }
    341             else
    342             {
    343                 result = "false";
    344             }
    345         }
    346         else if (cfType == CFStringGetTypeID())
    347         {
    348             result = CFStringToUString((CFStringRef)cfValue);
    349         }
    350         else if (cfType == CFNumberGetTypeID())
    351         {
    352             if (cfValue == kCFNumberNaN)
    353             {
    354                 result = "Nan";
    355             }
    356             else if (CFNumberCompare(kCFNumberPositiveInfinity, (CFNumberRef)cfValue, 0) == 0)
    357             {
    358                 result = "Infinity";
    359             }
    360             else if (CFNumberCompare(kCFNumberNegativeInfinity, (CFNumberRef)cfValue, 0) == 0)
    361             {
    362                 result = "-Infinity";
    363             }
    364             else
    365             {
    366                 CFStringRef cfNumStr;
    367                 double d = 0;
    368                 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
    369                 if (CFNumberIsFloatType((CFNumberRef)cfValue))
    370                 {
    371                     cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%f"), d);
    372                 }
    373                 else
    374                 {
    375                     cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%.0f"), d);
    376                 }
    377                 result = CFStringToUString(cfNumStr);
    378                 ReleaseCFType(cfNumStr);
    379             }
    380         }
    381         else if (cfType == CFArrayGetTypeID())
    382         {
    383             //
    384         }
    385         else if (cfType == CFDictionaryGetTypeID())
    386         {
    387             //
    388         }
    389         else if (cfType == CFSetGetTypeID())
    390         {
    391             //
    392         }
    393         else if (cfType == CFURLGetTypeID())
    394         {
    395             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
    396             if (absURL)
    397             {
    398                 CFStringRef cfStr = CFURLGetString(absURL);
    399                 if (cfStr)
    400                 {
    401                     result = CFStringToUString(cfStr);
    402                 }
    403                 ReleaseCFType(absURL);
    404             }
    405         }
    406     }
    407     ReleaseCFType(cfValue);
    408     if (jsObjPtr) jsObjPtr->Release();
    409     return result;
    410 }
    411 
    412 void UserObjectImp::markChildren(MarkStack& markStack)
    413 {
    414     JSObject::markChildren(markStack);
    415     if (fJSUserObject)
    416         fJSUserObject->Mark();
    417 }
    418