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