blob: a341449c2c3fc3923fcdbe7974c58cf46c819588 [file] [log] [blame]
thatcher43a8c5172006-01-19 02:40:56 +00001/*
2 * Copyright (C) 2005 Apple Computer, 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
mjs3bfb61b2006-03-02 09:12:06 +000029#include "config.h"
mjs7f5285a2005-09-06 08:10:03 +000030#include "UserObjectImp.h"
mjsb3598b82006-07-16 21:06:28 +000031#include <JavaScriptCore/PropertyNameArray.h>
mjs7f5285a2005-09-06 08:10:03 +000032
33const ClassInfo UserObjectImp::info = {"UserObject", 0, 0, 0};
34
ggaren42d6fcd2007-02-22 22:10:38 +000035UserObjectImp::UserObjectImp(JSUserObject* userObject)
36 : fJSUserObject((JSUserObject*)userObject->Retain())
darin09654692005-10-10 23:32:34 +000037{
mjs7f5285a2005-09-06 08:10:03 +000038}
39
darin09654692005-10-10 23:32:34 +000040UserObjectImp::~UserObjectImp()
mjs7f5285a2005-09-06 08:10:03 +000041{
darin09654692005-10-10 23:32:34 +000042 if (fJSUserObject)
darin09654692005-10-10 23:32:34 +000043 fJSUserObject->Release();
mjs7f5285a2005-09-06 08:10:03 +000044}
darin09654692005-10-10 23:32:34 +000045
46const ClassInfo * UserObjectImp::classInfo() const
mjs7f5285a2005-09-06 08:10:03 +000047{
darin09654692005-10-10 23:32:34 +000048 return &info;
mjs7f5285a2005-09-06 08:10:03 +000049}
darin09654692005-10-10 23:32:34 +000050
51bool UserObjectImp::implementsCall() const
mjs7f5285a2005-09-06 08:10:03 +000052{
darin09654692005-10-10 23:32:34 +000053 return fJSUserObject ? fJSUserObject->ImplementsCall() : false;
mjs7f5285a2005-09-06 08:10:03 +000054}
55
darinb139ea12005-12-11 02:03:35 +000056JSValue *UserObjectImp::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
mjs7f5285a2005-09-06 08:10:03 +000057{
darinb139ea12005-12-11 02:03:35 +000058 JSValue *result = jsUndefined();
mjs1edef722005-10-07 04:22:50 +000059 JSUserObject* jsThisObj = KJSValueToJSObject(thisObj, exec);
60 if (jsThisObj) {
61 CFIndex argCount = args.size();
62 CFArrayCallBacks arrayCallBacks;
63 JSTypeGetCFArrayCallBacks(&arrayCallBacks);
darin09654692005-10-10 23:32:34 +000064 CFMutableArrayRef jsArgs = CFArrayCreateMutable(0, 0, &arrayCallBacks);
mjs1edef722005-10-07 04:22:50 +000065 if (jsArgs) {
66 for (CFIndex i = 0; i < argCount; i++) {
67 JSUserObject* jsArg = KJSValueToJSObject(args[i], exec);
68 CFArrayAppendValue(jsArgs, (void*)jsArg);
69 jsArg->Release();
70 }
71 }
mjs7f5285a2005-09-06 08:10:03 +000072
mjsfc415252005-11-23 05:40:07 +000073 JSUserObject* jsResult;
74 { // scope
mjsa564fe12005-11-27 03:10:03 +000075 JSLock::DropAllLocks dropLocks;
mjsfc415252005-11-23 05:40:07 +000076
77 // implementsCall should have guarded against a NULL fJSUserObject.
78 assert(fJSUserObject);
79 jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs);
mjs1edef722005-10-07 04:22:50 +000080 }
darin09654692005-10-10 23:32:34 +000081
mjs1edef722005-10-07 04:22:50 +000082 if (jsResult) {
83 result = JSObjectKJSValue(jsResult);
84 jsResult->Release();
85 }
mjs7f5285a2005-09-06 08:10:03 +000086
mjs1edef722005-10-07 04:22:50 +000087 ReleaseCFType(jsArgs);
88 jsThisObj->Release();
89 }
90 return result;
mjs7f5285a2005-09-06 08:10:03 +000091}
92
93
mjsb3598b82006-07-16 21:06:28 +000094void UserObjectImp::getPropertyNames(ExecState *exec, PropertyNameArray& propertyNames)
mjs7f5285a2005-09-06 08:10:03 +000095{
mjs1edef722005-10-07 04:22:50 +000096 JSUserObject* ptr = GetJSUserObject();
97 if (ptr) {
98 CFArrayRef cfPropertyNames = ptr->CopyPropertyNames();
99 if (cfPropertyNames) {
100 CFIndex count = CFArrayGetCount(cfPropertyNames);
101 CFIndex i;
102 for (i = 0; i < count; i++) {
103 CFStringRef propertyName = (CFStringRef)CFArrayGetValueAtIndex(cfPropertyNames, i);
mjsb3598b82006-07-16 21:06:28 +0000104 propertyNames.add(CFStringToIdentifier(propertyName));
mjs1edef722005-10-07 04:22:50 +0000105 }
106 CFRelease(cfPropertyNames);
107 }
108 }
mjsb3598b82006-07-16 21:06:28 +0000109 JSObject::getPropertyNames(exec, propertyNames);
mjs7f5285a2005-09-06 08:10:03 +0000110}
111
ggarenf336dd72005-12-14 01:00:12 +0000112JSValue *UserObjectImp::userObjectGetter(ExecState *, JSObject *, const Identifier& propertyName, const PropertySlot& slot)
mjs7f5285a2005-09-06 08:10:03 +0000113{
mjs1edef722005-10-07 04:22:50 +0000114 UserObjectImp *thisObj = static_cast<UserObjectImp *>(slot.slotBase());
ggarenab4c7222005-11-11 05:15:02 +0000115 // getOwnPropertySlot should have guarded against a null fJSUserObject.
116 assert(thisObj->fJSUserObject);
117
darin09654692005-10-10 23:32:34 +0000118 CFStringRef cfPropName = IdentifierToCFString(propertyName);
mjs1edef722005-10-07 04:22:50 +0000119 JSUserObject *jsResult = thisObj->fJSUserObject->CopyProperty(cfPropName);
120 ReleaseCFType(cfPropName);
darinb139ea12005-12-11 02:03:35 +0000121 JSValue *result = JSObjectKJSValue(jsResult);
mjs1edef722005-10-07 04:22:50 +0000122 jsResult->Release();
123
124 return result;
mjs7f5285a2005-09-06 08:10:03 +0000125}
126
mjs1edef722005-10-07 04:22:50 +0000127bool UserObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
mjs7f5285a2005-09-06 08:10:03 +0000128{
ggarenab4c7222005-11-11 05:15:02 +0000129 if (!fJSUserObject)
130 return false;
131
darin09654692005-10-10 23:32:34 +0000132 CFStringRef cfPropName = IdentifierToCFString(propertyName);
mjs1edef722005-10-07 04:22:50 +0000133 JSUserObject *jsResult = fJSUserObject->CopyProperty(cfPropName);
134 ReleaseCFType(cfPropName);
135 if (jsResult) {
136 slot.setCustom(this, userObjectGetter);
137 jsResult->Release();
138 return true;
139 } else {
darinb139ea12005-12-11 02:03:35 +0000140 JSValue *kjsValue = toPrimitive(exec);
mjs1edef722005-10-07 04:22:50 +0000141 if (kjsValue->type() != NullType && kjsValue->type() != UndefinedType) {
darinb139ea12005-12-11 02:03:35 +0000142 JSObject *kjsObject = kjsValue->toObject(exec);
mjs1edef722005-10-07 04:22:50 +0000143 if (kjsObject->getPropertySlot(exec, propertyName, slot))
144 return true;
145 }
146 }
darinb139ea12005-12-11 02:03:35 +0000147 return JSObject::getOwnPropertySlot(exec, propertyName, slot);
mjs7f5285a2005-09-06 08:10:03 +0000148}
149
darinb139ea12005-12-11 02:03:35 +0000150void UserObjectImp::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
mjs7f5285a2005-09-06 08:10:03 +0000151{
ggarenab4c7222005-11-11 05:15:02 +0000152 if (!fJSUserObject)
153 return;
154
darin09654692005-10-10 23:32:34 +0000155 CFStringRef cfPropName = IdentifierToCFString(propertyName);
mjs1edef722005-10-07 04:22:50 +0000156 JSUserObject *jsValueObj = KJSValueToJSObject(value, exec);
darin09654692005-10-10 23:32:34 +0000157
mjs1edef722005-10-07 04:22:50 +0000158 fJSUserObject->SetProperty(cfPropName, jsValueObj);
darin09654692005-10-10 23:32:34 +0000159
160 if (jsValueObj) jsValueObj->Release();
mjs1edef722005-10-07 04:22:50 +0000161 ReleaseCFType(cfPropName);
mjs7f5285a2005-09-06 08:10:03 +0000162}
darin09654692005-10-10 23:32:34 +0000163
164JSUserObject* UserObjectImp::GetJSUserObject() const
165{
166 return fJSUserObject;
mjs7f5285a2005-09-06 08:10:03 +0000167}
168
ggaren9044b932006-02-10 08:42:21 +0000169JSValue *UserObjectImp::toPrimitive(ExecState *exec, JSType preferredType) const
mjs7f5285a2005-09-06 08:10:03 +0000170{
darinb139ea12005-12-11 02:03:35 +0000171 JSValue *result = jsUndefined();
mjs1edef722005-10-07 04:22:50 +0000172 JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
darin09654692005-10-10 23:32:34 +0000173 CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
mjs1edef722005-10-07 04:22:50 +0000174 if (cfValue) {
175 CFTypeID cfType = CFGetTypeID(cfValue); // toPrimitive
176 if (cfValue == GetCFNull()) {
darin9bd60642005-12-11 00:35:59 +0000177 result = jsNull();
mjs1edef722005-10-07 04:22:50 +0000178 }
179 else if (cfType == CFBooleanGetTypeID()) {
180 if (cfValue == kCFBooleanTrue) {
darin9bd60642005-12-11 00:35:59 +0000181 result = jsBoolean(true);
mjs1edef722005-10-07 04:22:50 +0000182 } else {
darin9bd60642005-12-11 00:35:59 +0000183 result = jsBoolean(false);
mjs1edef722005-10-07 04:22:50 +0000184 }
185 } else if (cfType == CFStringGetTypeID()) {
darin9bd60642005-12-11 00:35:59 +0000186 result = jsString(CFStringToUString((CFStringRef)cfValue));
mjs1edef722005-10-07 04:22:50 +0000187 } else if (cfType == CFNumberGetTypeID()) {
188 double d = 0.0;
189 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
darin9bd60642005-12-11 00:35:59 +0000190 result = jsNumber(d);
mjs1edef722005-10-07 04:22:50 +0000191 } else if (cfType == CFURLGetTypeID()) {
192 CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
193 if (absURL) {
darin9bd60642005-12-11 00:35:59 +0000194 result = jsString(CFStringToUString(CFURLGetString(absURL)));
mjs1edef722005-10-07 04:22:50 +0000195 ReleaseCFType(absURL);
196 }
darin09654692005-10-10 23:32:34 +0000197 }
mjs1edef722005-10-07 04:22:50 +0000198 ReleaseCFType(cfValue);
199 }
darin09654692005-10-10 23:32:34 +0000200 if (jsObjPtr)
mjs1edef722005-10-07 04:22:50 +0000201 jsObjPtr->Release();
202 return result;
mjs7f5285a2005-09-06 08:10:03 +0000203}
204
205
206bool UserObjectImp::toBoolean(ExecState *exec) const
207{
darin09654692005-10-10 23:32:34 +0000208 bool result = false;
209 JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
210 CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
211 if (cfValue)
212 {
213 CFTypeID cfType = CFGetTypeID(cfValue); // toPrimitive
214 if (cfValue == GetCFNull())
215 {
216 //
217 }
218 else if (cfType == CFBooleanGetTypeID())
219 {
220 if (cfValue == kCFBooleanTrue)
221 {
222 result = true;
223 }
224 }
225 else if (cfType == CFStringGetTypeID())
226 {
227 if (CFStringGetLength((CFStringRef)cfValue))
228 {
229 result = true;
230 }
231 }
232 else if (cfType == CFNumberGetTypeID())
233 {
234 if (cfValue != kCFNumberNaN)
235 {
236 double d;
237 if (CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d))
238 {
239 if (d != 0)
240 {
241 result = true;
242 }
243 }
244 }
245 }
246 else if (cfType == CFArrayGetTypeID())
247 {
248 if (CFArrayGetCount((CFArrayRef)cfValue))
249 {
250 result = true;
251 }
252 }
253 else if (cfType == CFDictionaryGetTypeID())
254 {
255 if (CFDictionaryGetCount((CFDictionaryRef)cfValue))
256 {
257 result = true;
258 }
259 }
260 else if (cfType == CFSetGetTypeID())
261 {
262 if (CFSetGetCount((CFSetRef)cfValue))
263 {
264 result = true;
265 }
266 }
267 else if (cfType == CFURLGetTypeID())
268 {
269 CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
270 if (absURL)
271 {
272 CFStringRef cfStr = CFURLGetString(absURL);
273 if (cfStr && CFStringGetLength(cfStr))
274 {
275 result = true;
276 }
277 ReleaseCFType(absURL);
278 }
279 }
280 }
281 if (jsObjPtr) jsObjPtr->Release();
282 ReleaseCFType(cfValue);
283 return result;
mjs7f5285a2005-09-06 08:10:03 +0000284}
285
286double UserObjectImp::toNumber(ExecState *exec) const
287{
darin09654692005-10-10 23:32:34 +0000288 double result = 0;
289 JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
290 CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
291 if (cfValue)
292 {
293 CFTypeID cfType = CFGetTypeID(cfValue);
294
295 if (cfValue == GetCFNull())
296 {
297 //
298 }
299 else if (cfType == CFBooleanGetTypeID())
300 {
301 if (cfValue == kCFBooleanTrue)
302 {
303 result = 1;
304 }
305 }
306 else if (cfType == CFStringGetTypeID())
307 {
308 result = CFStringGetDoubleValue((CFStringRef)cfValue);
309 }
310 else if (cfType == CFNumberGetTypeID())
311 {
312 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &result);
313 }
314 }
315 ReleaseCFType(cfValue);
316 if (jsObjPtr) jsObjPtr->Release();
317 return result;
mjs7f5285a2005-09-06 08:10:03 +0000318}
319
320UString UserObjectImp::toString(ExecState *exec) const
321{
darin09654692005-10-10 23:32:34 +0000322 UString result;
323 JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
324 CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
325 if (cfValue)
326 {
327 CFTypeID cfType = CFGetTypeID(cfValue);
328 if (cfValue == GetCFNull())
329 {
330 //
331 }
332 else if (cfType == CFBooleanGetTypeID())
333 {
334 if (cfValue == kCFBooleanTrue)
335 {
336 result = "true";
337 }
338 else
339 {
340 result = "false";
341 }
342 }
343 else if (cfType == CFStringGetTypeID())
344 {
345 result = CFStringToUString((CFStringRef)cfValue);
346 }
347 else if (cfType == CFNumberGetTypeID())
348 {
349 if (cfValue == kCFNumberNaN)
350 {
351 result = "Nan";
352 }
353 else if (CFNumberCompare(kCFNumberPositiveInfinity, (CFNumberRef)cfValue, 0) == 0)
354 {
355 result = "Infinity";
356 }
357 else if (CFNumberCompare(kCFNumberNegativeInfinity, (CFNumberRef)cfValue, 0) == 0)
358 {
359 result = "-Infinity";
360 }
361 else
362 {
darinfa0c87f2007-02-16 21:56:43 +0000363 CFStringRef cfNumStr;
364 double d = 0;
365 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
darin09654692005-10-10 23:32:34 +0000366 if (CFNumberIsFloatType((CFNumberRef)cfValue))
367 {
darinfa0c87f2007-02-16 21:56:43 +0000368 cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%f"), d);
darin09654692005-10-10 23:32:34 +0000369 }
370 else
371 {
darinfa0c87f2007-02-16 21:56:43 +0000372 cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%.0f"), d);
darin09654692005-10-10 23:32:34 +0000373 }
darinfa0c87f2007-02-16 21:56:43 +0000374 result = CFStringToUString(cfNumStr);
375 ReleaseCFType(cfNumStr);
darin09654692005-10-10 23:32:34 +0000376 }
377 }
378 else if (cfType == CFArrayGetTypeID())
379 {
380 //
381 }
382 else if (cfType == CFDictionaryGetTypeID())
383 {
384 //
385 }
386 else if (cfType == CFSetGetTypeID())
387 {
388 //
389 }
390 else if (cfType == CFURLGetTypeID())
391 {
392 CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
393 if (absURL)
394 {
395 CFStringRef cfStr = CFURLGetString(absURL);
396 if (cfStr)
397 {
398 result = CFStringToUString(cfStr);
399 }
400 ReleaseCFType(absURL);
401 }
402 }
403 }
404 ReleaseCFType(cfValue);
405 if (jsObjPtr) jsObjPtr->Release();
406 return result;
mjs7f5285a2005-09-06 08:10:03 +0000407}
408
409void UserObjectImp::mark()
410{
darinb139ea12005-12-11 02:03:35 +0000411 JSObject::mark();
ggarenab4c7222005-11-11 05:15:02 +0000412 if (fJSUserObject)
413 fJSUserObject->Mark();
mjs7f5285a2005-09-06 08:10:03 +0000414}