JavaScriptCore:
[WebKit-https.git] / JavaScriptGlue / UserObjectImp.cpp
1 /*
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
29 #include "config.h"
30 #include "UserObjectImp.h"
31 #include <JavaScriptCore/PropertyNameArray.h>
32
33 const ClassInfo UserObjectImp::info = { "UserObject", 0, 0, 0 };
34
35 UserObjectImp::UserObjectImp(JSUserObject* userObject)
36     : fJSUserObject((JSUserObject*)userObject->Retain())
37 {
38 }
39
40 UserObjectImp::~UserObjectImp()
41 {
42     if (fJSUserObject)
43         fJSUserObject->Release();
44 }
45
46 const ClassInfo * UserObjectImp::classInfo() const
47 {
48     return &info;
49 }
50
51 CallType UserObjectImp::getCallData(CallData& callData)
52 {
53     return fJSUserObject ? fJSUserObject->getCallData(callData) : CallTypeNone;
54 }
55
56 JSValue *UserObjectImp::callAsFunction(ExecState *exec, JSObject *thisObj, const ArgList &args)
57 {
58     JSValue *result = jsUndefined();
59     JSUserObject* jsThisObj = KJSValueToJSObject(thisObj, exec);
60     if (jsThisObj) {
61         CFIndex argCount = args.size();
62         CFArrayCallBacks arrayCallBacks;
63         JSTypeGetCFArrayCallBacks(&arrayCallBacks);
64         CFMutableArrayRef jsArgs = CFArrayCreateMutable(0, 0, &arrayCallBacks);
65         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         }
72
73         JSUserObject* jsResult;
74         { // scope
75             JSLock::DropAllLocks dropLocks;
76
77             // getCallData should have guarded against a NULL fJSUserObject.
78             assert(fJSUserObject);
79             jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs);
80         }
81
82         if (jsResult) {
83             result = JSObjectKJSValue(jsResult);
84             jsResult->Release();
85         }
86
87         ReleaseCFType(jsArgs);
88         jsThisObj->Release();
89     }
90     return result;
91 }
92
93
94 void UserObjectImp::getPropertyNames(ExecState *exec, PropertyNameArray& propertyNames)
95 {
96     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);
104                 propertyNames.add(CFStringToIdentifier(propertyName));
105             }
106             CFRelease(cfPropertyNames);
107         }
108     }
109     JSObject::getPropertyNames(exec, propertyNames);
110 }
111
112 JSValue* UserObjectImp::userObjectGetter(ExecState*, const Identifier& propertyName, const PropertySlot& slot)
113 {
114     UserObjectImp *thisObj = static_cast<UserObjectImp *>(slot.slotBase());
115     // getOwnPropertySlot should have guarded against a null fJSUserObject.
116     assert(thisObj->fJSUserObject);
117     
118     CFStringRef cfPropName = IdentifierToCFString(propertyName);
119     JSUserObject *jsResult = thisObj->fJSUserObject->CopyProperty(cfPropName);
120     ReleaseCFType(cfPropName);
121     JSValue *result = JSObjectKJSValue(jsResult);
122     jsResult->Release();
123
124     return result;
125 }
126
127 bool UserObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
128 {
129     if (!fJSUserObject)
130         return false;
131
132     CFStringRef cfPropName = IdentifierToCFString(propertyName);
133     JSUserObject *jsResult = fJSUserObject->CopyProperty(cfPropName);
134     ReleaseCFType(cfPropName);
135     if (jsResult) {
136         slot.setCustom(this, userObjectGetter);
137         jsResult->Release();
138         return true;
139     } else {
140         JSValue *kjsValue = toPrimitive(exec);
141         if (kjsValue->type() != NullType && kjsValue->type() != UndefinedType) {
142             JSObject *kjsObject = kjsValue->toObject(exec);
143             if (kjsObject->getPropertySlot(exec, propertyName, slot))
144                 return true;
145         }
146     }
147     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
148 }
149
150 void UserObjectImp::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
151 {
152     if (!fJSUserObject)
153         return;
154     
155     CFStringRef cfPropName = IdentifierToCFString(propertyName);
156     JSUserObject *jsValueObj = KJSValueToJSObject(value, exec);
157
158     fJSUserObject->SetProperty(cfPropName, jsValueObj);
159
160     if (jsValueObj) jsValueObj->Release();
161     ReleaseCFType(cfPropName);
162 }
163
164 JSUserObject* UserObjectImp::GetJSUserObject() const
165 {
166     return fJSUserObject;
167 }
168
169 JSValue *UserObjectImp::toPrimitive(ExecState *exec, JSType preferredType) const
170 {
171     JSValue *result = jsUndefined();
172     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
173     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
174     if (cfValue) {
175         CFTypeID cfType = CFGetTypeID(cfValue);  // toPrimitive
176         if (cfValue == GetCFNull()) {
177             result = jsNull();
178         }
179         else if (cfType == CFBooleanGetTypeID()) {
180             if (cfValue == kCFBooleanTrue) {
181                 result = jsBoolean(true);
182             } else {
183                 result = jsBoolean(false);
184             }
185         } else if (cfType == CFStringGetTypeID()) {
186             result = jsString(CFStringToUString((CFStringRef)cfValue));
187         } else if (cfType == CFNumberGetTypeID()) {
188             double d = 0.0;
189             CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
190             result = jsNumber(d);
191         } else if (cfType == CFURLGetTypeID()) {
192             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
193             if (absURL) {
194                 result = jsString(CFStringToUString(CFURLGetString(absURL)));
195                 ReleaseCFType(absURL);
196             }
197         }
198         ReleaseCFType(cfValue);
199     }
200     if (jsObjPtr)
201         jsObjPtr->Release();
202     return result;
203 }
204
205
206 bool UserObjectImp::toBoolean(ExecState *exec) const
207 {
208     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;
284 }
285
286 double UserObjectImp::toNumber(ExecState *exec) const
287 {
288     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;
318 }
319
320 UString UserObjectImp::toString(ExecState *exec) const
321 {
322     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             {
363                 CFStringRef cfNumStr;
364                 double d = 0;
365                 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
366                 if (CFNumberIsFloatType((CFNumberRef)cfValue))
367                 {
368                     cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%f"), d);
369                 }
370                 else
371                 {
372                     cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%.0f"), d);
373                 }
374                 result = CFStringToUString(cfNumStr);
375                 ReleaseCFType(cfNumStr);
376             }
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;
407 }
408
409 void UserObjectImp::mark()
410 {
411     JSObject::mark();
412     if (fJSUserObject)
413         fJSUserObject->Mark();
414 }