Rubber-stamped by Brady Eidson.
[webbrowser.git] / JavaScriptGlue / UserObjectImp.cpp
blob125e3498001024c579e79d6654fc0f40f4b073cf
1 /*
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
6 * are met:
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.
29 #include "config.h"
30 #include "UserObjectImp.h"
32 #include <JavaScriptCore/JSString.h>
33 #include <JavaScriptCore/PropertyNameArray.h>
35 const ClassInfo UserObjectImp::info = { "UserObject", 0, 0, 0 };
37 UserObjectImp::UserObjectImp(PassRefPtr<Structure> structure, JSUserObject* userObject)
38 : JSObject(structure)
39 , fJSUserObject((JSUserObject*)userObject->Retain())
43 UserObjectImp::~UserObjectImp()
45 if (fJSUserObject)
46 fJSUserObject->Release();
49 const ClassInfo * UserObjectImp::classInfo() const
51 return &info;
54 CallType UserObjectImp::getCallData(CallData& callData)
56 return fJSUserObject ? fJSUserObject->getCallData(callData) : CallTypeNone;
59 JSValue UserObjectImp::callAsFunction(ExecState *exec, JSObject *thisObj, const ArgList &args)
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();
76 JSUserObject* jsResult;
77 { // scope
78 JSLock::DropAllLocks dropLocks(exec);
80 // getCallData should have guarded against a NULL fJSUserObject.
81 assert(fJSUserObject);
82 jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs);
85 if (jsResult) {
86 result = JSObjectKJSValue(jsResult);
87 jsResult->Release();
90 ReleaseCFType(jsArgs);
91 jsThisObj->Release();
93 return result;
97 void UserObjectImp::getOwnPropertyNames(ExecState *exec, PropertyNameArray& propertyNames)
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));
109 CFRelease(cfPropertyNames);
112 JSObject::getOwnPropertyNames(exec, propertyNames);
115 JSValue UserObjectImp::userObjectGetter(ExecState*, const Identifier& propertyName, const PropertySlot& slot)
117 UserObjectImp *thisObj = static_cast<UserObjectImp *>(asObject(slot.slotBase()));
118 // getOwnPropertySlot should have guarded against a null fJSUserObject.
119 assert(thisObj->fJSUserObject);
121 CFStringRef cfPropName = IdentifierToCFString(propertyName);
122 JSUserObject *jsResult = thisObj->fJSUserObject->CopyProperty(cfPropName);
123 ReleaseCFType(cfPropName);
124 JSValue result = JSObjectKJSValue(jsResult);
125 jsResult->Release();
127 return result;
130 bool UserObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
132 if (!fJSUserObject)
133 return false;
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;
150 return JSObject::getOwnPropertySlot(exec, propertyName, slot);
153 void UserObjectImp::put(ExecState *exec, const Identifier &propertyName, JSValue value, PutPropertySlot&)
155 if (!fJSUserObject)
156 return;
158 CFStringRef cfPropName = IdentifierToCFString(propertyName);
159 JSUserObject *jsValueObj = KJSValueToJSObject(value, exec);
161 fJSUserObject->SetProperty(cfPropName, jsValueObj);
163 if (jsValueObj) jsValueObj->Release();
164 ReleaseCFType(cfPropName);
167 JSUserObject* UserObjectImp::GetJSUserObject() const
169 return fJSUserObject;
172 JSValue UserObjectImp::toPrimitive(ExecState *exec, JSType) const
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();
182 else if (cfType == CFBooleanGetTypeID()) {
183 if (cfValue == kCFBooleanTrue) {
184 result = jsBoolean(true);
185 } else {
186 result = jsBoolean(false);
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);
201 ReleaseCFType(cfValue);
203 if (jsObjPtr)
204 jsObjPtr->Release();
205 return result;
209 bool UserObjectImp::toBoolean(ExecState *exec) const
211 bool result = false;
212 JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
213 CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
214 if (cfValue)
216 CFTypeID cfType = CFGetTypeID(cfValue); // toPrimitive
217 if (cfValue == GetCFNull())
221 else if (cfType == CFBooleanGetTypeID())
223 if (cfValue == kCFBooleanTrue)
225 result = true;
228 else if (cfType == CFStringGetTypeID())
230 if (CFStringGetLength((CFStringRef)cfValue))
232 result = true;
235 else if (cfType == CFNumberGetTypeID())
237 if (cfValue != kCFNumberNaN)
239 double d;
240 if (CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d))
242 if (d != 0)
244 result = true;
249 else if (cfType == CFArrayGetTypeID())
251 if (CFArrayGetCount((CFArrayRef)cfValue))
253 result = true;
256 else if (cfType == CFDictionaryGetTypeID())
258 if (CFDictionaryGetCount((CFDictionaryRef)cfValue))
260 result = true;
263 else if (cfType == CFSetGetTypeID())
265 if (CFSetGetCount((CFSetRef)cfValue))
267 result = true;
270 else if (cfType == CFURLGetTypeID())
272 CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
273 if (absURL)
275 CFStringRef cfStr = CFURLGetString(absURL);
276 if (cfStr && CFStringGetLength(cfStr))
278 result = true;
280 ReleaseCFType(absURL);
284 if (jsObjPtr) jsObjPtr->Release();
285 ReleaseCFType(cfValue);
286 return result;
289 double UserObjectImp::toNumber(ExecState *exec) const
291 double result = 0;
292 JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
293 CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
294 if (cfValue)
296 CFTypeID cfType = CFGetTypeID(cfValue);
298 if (cfValue == GetCFNull())
302 else if (cfType == CFBooleanGetTypeID())
304 if (cfValue == kCFBooleanTrue)
306 result = 1;
309 else if (cfType == CFStringGetTypeID())
311 result = CFStringGetDoubleValue((CFStringRef)cfValue);
313 else if (cfType == CFNumberGetTypeID())
315 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &result);
318 ReleaseCFType(cfValue);
319 if (jsObjPtr) jsObjPtr->Release();
320 return result;
323 UString UserObjectImp::toString(ExecState *exec) const
325 UString result;
326 JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
327 CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
328 if (cfValue)
330 CFTypeID cfType = CFGetTypeID(cfValue);
331 if (cfValue == GetCFNull())
335 else if (cfType == CFBooleanGetTypeID())
337 if (cfValue == kCFBooleanTrue)
339 result = "true";
341 else
343 result = "false";
346 else if (cfType == CFStringGetTypeID())
348 result = CFStringToUString((CFStringRef)cfValue);
350 else if (cfType == CFNumberGetTypeID())
352 if (cfValue == kCFNumberNaN)
354 result = "Nan";
356 else if (CFNumberCompare(kCFNumberPositiveInfinity, (CFNumberRef)cfValue, 0) == 0)
358 result = "Infinity";
360 else if (CFNumberCompare(kCFNumberNegativeInfinity, (CFNumberRef)cfValue, 0) == 0)
362 result = "-Infinity";
364 else
366 CFStringRef cfNumStr;
367 double d = 0;
368 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
369 if (CFNumberIsFloatType((CFNumberRef)cfValue))
371 cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%f"), d);
373 else
375 cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%.0f"), d);
377 result = CFStringToUString(cfNumStr);
378 ReleaseCFType(cfNumStr);
381 else if (cfType == CFArrayGetTypeID())
385 else if (cfType == CFDictionaryGetTypeID())
389 else if (cfType == CFSetGetTypeID())
393 else if (cfType == CFURLGetTypeID())
395 CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
396 if (absURL)
398 CFStringRef cfStr = CFURLGetString(absURL);
399 if (cfStr)
401 result = CFStringToUString(cfStr);
403 ReleaseCFType(absURL);
407 ReleaseCFType(cfValue);
408 if (jsObjPtr) jsObjPtr->Release();
409 return result;
412 void UserObjectImp::markChildren(MarkStack& markStack)
414 JSObject::markChildren(markStack);
415 if (fJSUserObject)
416 fJSUserObject->Mark();