JavaScriptGlue/UserObjectImp.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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)
       
    60 {
       
    61     JSValue result = jsUndefined();
       
    62     JSUserObject* jsThisObj = KJSValueToJSObject(exec->hostThisValue().toThisObject(exec), exec);
       
    63     if (jsThisObj) {
       
    64         CFIndex argCount = exec->argumentCount();
       
    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(exec->argument(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*, JSValue slotBase, const Identifier& propertyName)
       
   116 {
       
   117     UserObjectImp *thisObj = static_cast<UserObjectImp *>(asObject(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 }