2010-09-08 Ryuan Choi <ryuan.choi@samsung.com>
[WebKit-https.git] / JavaScriptGlue / UserObjectImp.cpp
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)
60 {
61     JSValue result = jsUndefined();
62     JSUserObject* jsThisObj = KJSValueToJSObject(exec->hostThisValue().toThisObject(exec), exec);
63     if (jsThisObj) {
64         CFIndex argCount = exec->argumentCount();
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(exec->argument(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*, JSValue slotBase, const Identifier& propertyName)
116 {
117     UserObjectImp *thisObj = static_cast<UserObjectImp *>(asObject(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 }