2 * Copyright (C) 2005, 2008, 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "UserObjectImp.h"
32 #include <JavaScriptCore/JSString.h>
33 #include <JavaScriptCore/PropertyNameArray.h>
35 const ClassInfo UserObjectImp::s_info = { "UserObject", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(UserObjectImp) };
37 UserObjectImp::UserObjectImp(JSGlobalData& globalData, Structure* structure, JSUserObject* userObject)
38 : JSNonFinalObject(globalData, structure)
39 , fJSUserObject((JSUserObject*)userObject->Retain())
43 UserObjectImp::~UserObjectImp()
46 fJSUserObject->Release();
49 CallType UserObjectImp::getCallData(JSCell* cell, CallData& callData)
51 UserObjectImp* thisObject = jsCast<UserObjectImp*>(cell);
52 return thisObject->fJSUserObject ? thisObject->fJSUserObject->getCallData(callData) : CallTypeNone;
55 JSValue UserObjectImp::callAsFunction(ExecState *exec)
57 JSValue result = jsUndefined();
58 JSUserObject* jsThisObj = KJSValueToJSObject(exec->hostThisValue().toThisObject(exec), exec);
60 CFIndex argCount = exec->argumentCount();
61 CFArrayCallBacks arrayCallBacks;
62 JSTypeGetCFArrayCallBacks(&arrayCallBacks);
63 CFMutableArrayRef jsArgs = CFArrayCreateMutable(0, 0, &arrayCallBacks);
65 for (CFIndex i = 0; i < argCount; i++) {
66 JSUserObject* jsArg = KJSValueToJSObject(exec->argument(i), exec);
67 CFArrayAppendValue(jsArgs, (void*)jsArg);
72 JSUserObject* jsResult;
74 JSGlueAPICallback apiCallback(exec);
76 // getCallData should have guarded against a NULL fJSUserObject.
77 assert(fJSUserObject);
78 jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs);
82 result = JSObjectKJSValue(jsResult);
86 ReleaseCFType(jsArgs);
93 void UserObjectImp::getOwnPropertyNames(JSObject* object, ExecState *exec, PropertyNameArray& propertyNames, EnumerationMode mode)
95 UserObjectImp* thisObject = jsCast<UserObjectImp*>(object);
96 JSUserObject* ptr = thisObject->GetJSUserObject();
98 CFArrayRef cfPropertyNames = ptr->CopyPropertyNames();
99 if (cfPropertyNames) {
100 CFIndex count = CFArrayGetCount(cfPropertyNames);
102 for (i = 0; i < count; i++) {
103 CFStringRef propertyName = (CFStringRef)CFArrayGetValueAtIndex(cfPropertyNames, i);
104 propertyNames.add(CFStringToIdentifier(propertyName, exec));
106 CFRelease(cfPropertyNames);
109 JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
112 JSValue UserObjectImp::userObjectGetter(ExecState*, JSValue slotBase, const Identifier& propertyName)
114 UserObjectImp *thisObj = static_cast<UserObjectImp *>(asObject(slotBase));
115 // getOwnPropertySlot should have guarded against a null fJSUserObject.
116 assert(thisObj->fJSUserObject);
118 CFStringRef cfPropName = IdentifierToCFString(propertyName);
119 JSUserObject *jsResult = thisObj->fJSUserObject->CopyProperty(cfPropName);
120 ReleaseCFType(cfPropName);
121 JSValue result = JSObjectKJSValue(jsResult);
127 bool UserObjectImp::getOwnPropertySlot(JSCell* cell, ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
129 UserObjectImp* thisObject = jsCast<UserObjectImp*>(cell);
130 if (!thisObject->fJSUserObject)
133 CFStringRef cfPropName = IdentifierToCFString(propertyName);
134 JSUserObject* jsResult = thisObject->fJSUserObject->CopyProperty(cfPropName);
135 ReleaseCFType(cfPropName);
137 slot.setCustom(thisObject, userObjectGetter);
141 JSValue kjsValue = thisObject->toPrimitive(exec);
142 if (!kjsValue.isUndefinedOrNull()) {
143 JSObject* kjsObject = kjsValue.toObject(exec);
144 if (kjsObject->getPropertySlot(exec, propertyName, slot))
148 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
151 void UserObjectImp::put(JSCell* cell, ExecState *exec, const Identifier &propertyName, JSValue value, PutPropertySlot&)
153 UserObjectImp* thisObject = jsCast<UserObjectImp*>(cell);
154 if (!thisObject->fJSUserObject)
157 CFStringRef cfPropName = IdentifierToCFString(propertyName);
158 JSUserObject *jsValueObj = KJSValueToJSObject(value, exec);
160 thisObject->fJSUserObject->SetProperty(cfPropName, jsValueObj);
162 if (jsValueObj) jsValueObj->Release();
163 ReleaseCFType(cfPropName);
166 JSUserObject* UserObjectImp::GetJSUserObject() const
168 return fJSUserObject;
171 JSValue UserObjectImp::toPrimitive(ExecState *exec, PreferredPrimitiveType) const
173 JSValue result = jsUndefined();
174 JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec, exec->lexicalGlobalObject()), exec);
175 CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
177 CFTypeID cfType = CFGetTypeID(cfValue); // toPrimitive
178 if (cfValue == GetCFNull()) {
181 else if (cfType == CFBooleanGetTypeID()) {
182 if (cfValue == kCFBooleanTrue) {
183 result = jsBoolean(true);
185 result = jsBoolean(false);
187 } else if (cfType == CFStringGetTypeID()) {
188 result = jsString(exec, CFStringToUString((CFStringRef)cfValue));
189 } else if (cfType == CFNumberGetTypeID()) {
191 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
192 result = jsNumber(d);
193 } else if (cfType == CFURLGetTypeID()) {
194 CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
196 result = jsString(exec, CFStringToUString(CFURLGetString(absURL)));
197 ReleaseCFType(absURL);
200 ReleaseCFType(cfValue);
208 bool UserObjectImp::toBoolean(ExecState *exec) const
211 JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec, exec->lexicalGlobalObject()), exec);
212 CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
215 CFTypeID cfType = CFGetTypeID(cfValue); // toPrimitive
216 if (cfValue == GetCFNull())
220 else if (cfType == CFBooleanGetTypeID())
222 if (cfValue == kCFBooleanTrue)
227 else if (cfType == CFStringGetTypeID())
229 if (CFStringGetLength((CFStringRef)cfValue))
234 else if (cfType == CFNumberGetTypeID())
236 if (cfValue != kCFNumberNaN)
239 if (CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d))
248 else if (cfType == CFArrayGetTypeID())
250 if (CFArrayGetCount((CFArrayRef)cfValue))
255 else if (cfType == CFDictionaryGetTypeID())
257 if (CFDictionaryGetCount((CFDictionaryRef)cfValue))
262 else if (cfType == CFSetGetTypeID())
264 if (CFSetGetCount((CFSetRef)cfValue))
269 else if (cfType == CFURLGetTypeID())
271 CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
274 CFStringRef cfStr = CFURLGetString(absURL);
275 if (cfStr && CFStringGetLength(cfStr))
279 ReleaseCFType(absURL);
283 if (jsObjPtr) jsObjPtr->Release();
284 ReleaseCFType(cfValue);
288 void UserObjectImp::visitChildren(JSCell* cell, SlotVisitor& visitor)
290 UserObjectImp* thisObject = jsCast<UserObjectImp*>(cell);
291 JSObject::visitChildren(thisObject, visitor);
292 if (thisObject->fJSUserObject)
293 thisObject->fJSUserObject->Mark();