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