beee2fca6ac84878eb3070f08216f53ae471fa92
[WebKit-https.git] / JavaScriptGlue / UserObjectImp.cpp
1 #include "UserObjectImp.h"
2 #include "JavaScriptCore/IdentifierSequencedSet.h"
3
4 const ClassInfo UserObjectImp::info = {"UserObject", 0, 0, 0};
5
6 class UserObjectPrototypeImp : public UserObjectImp {
7   public:
8     UserObjectPrototypeImp();
9         static UserObjectPrototypeImp* GlobalUserObjectPrototypeImp();
10   private:
11         static UserObjectPrototypeImp* sUserObjectPrototypeImp;
12 };
13
14 UserObjectPrototypeImp* UserObjectPrototypeImp::sUserObjectPrototypeImp = NULL;
15
16 UserObjectPrototypeImp::UserObjectPrototypeImp()
17   : UserObjectImp()
18 {
19 }
20
21 UserObjectPrototypeImp* UserObjectPrototypeImp::GlobalUserObjectPrototypeImp()
22 {
23         if (!sUserObjectPrototypeImp)
24         {
25             sUserObjectPrototypeImp  = new UserObjectPrototypeImp();
26             static ProtectedPtr<UserObjectPrototypeImp> protectPrototype;
27         }
28         return sUserObjectPrototypeImp;
29 }
30
31
32 UserObjectImp::UserObjectImp(): ObjectImp(), fJSUserObject(NULL)
33 {
34 }
35
36 UserObjectImp::UserObjectImp(JSUserObject* userObject) : 
37         ObjectImp(UserObjectPrototypeImp::GlobalUserObjectPrototypeImp()), 
38         fJSUserObject((JSUserObject*)userObject->Retain()) 
39
40 }
41
42 UserObjectImp::~UserObjectImp() 
43 {
44         if (fJSUserObject)
45         {
46                 fJSUserObject->Release(); 
47         }
48 }
49     
50 const ClassInfo * UserObjectImp::classInfo() const 
51 {
52         return &info; 
53 }
54         
55 bool    UserObjectImp::implementsCall() const 
56 {
57         return fJSUserObject ? fJSUserObject->ImplementsCall() : false; 
58 }
59
60 ValueImp *UserObjectImp::callAsFunction(ExecState *exec, ObjectImp *thisObj, const List &args)
61 {
62     ValueImp *result = Undefined();
63     JSUserObject* jsThisObj = KJSValueToJSObject(thisObj, exec);
64     if (jsThisObj) {
65         CFIndex argCount = args.size();
66         CFArrayCallBacks arrayCallBacks;
67         JSTypeGetCFArrayCallBacks(&arrayCallBacks);
68         CFMutableArrayRef jsArgs = CFArrayCreateMutable(NULL, 0, &arrayCallBacks);
69         if (jsArgs) {
70             for (CFIndex i = 0; i < argCount; i++) {
71                 JSUserObject* jsArg = KJSValueToJSObject(args[i], exec);
72                 CFArrayAppendValue(jsArgs, (void*)jsArg);
73                 jsArg->Release();
74             }
75         }
76
77         int lockCount = Interpreter::lockCount();
78         int i;
79         for (i = 0; i < lockCount; i++) {
80             Interpreter::unlock();
81         }
82         
83         JSUserObject* jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs);
84         
85         for (i = 0; i < lockCount; i++) {
86             Interpreter::lock();
87         }
88         if (jsResult) {
89             result = JSObjectKJSValue(jsResult);
90             jsResult->Release();
91         }
92
93         ReleaseCFType(jsArgs);
94         jsThisObj->Release();
95     }
96     return result;
97 }
98
99
100 void UserObjectImp::getPropertyNames(ExecState *exec, IdentifierSequencedSet& propertyNames)
101 {
102     JSUserObject* ptr = GetJSUserObject();
103     if (ptr) {
104         CFArrayRef cfPropertyNames = ptr->CopyPropertyNames();
105         if (cfPropertyNames) {
106             CFIndex count = CFArrayGetCount(cfPropertyNames);
107             CFIndex i;
108             for (i = 0; i < count; i++) {
109                 CFStringRef propertyName = (CFStringRef)CFArrayGetValueAtIndex(cfPropertyNames, i);
110                 propertyNames.insert(CFStringToIdentifier(propertyName));
111             }
112             CFRelease(cfPropertyNames);
113         }
114     }
115     ObjectImp::getPropertyNames(exec, propertyNames);
116 }
117
118 ValueImp *UserObjectImp::userObjectGetter(ExecState *, const Identifier& propertyName, const PropertySlot& slot)
119 {
120     UserObjectImp *thisObj = static_cast<UserObjectImp *>(slot.slotBase());
121     CFStringRef cfPropName = IdentifierToCFString(propertyName);
122     JSUserObject *jsResult = thisObj->fJSUserObject->CopyProperty(cfPropName);
123     ReleaseCFType(cfPropName);
124     ValueImp *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     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         ValueImp *kjsValue = toPrimitive(exec);
141         if (kjsValue->type() != NullType && kjsValue->type() != UndefinedType) {
142             ObjectImp *kjsObject = kjsValue->toObject(exec);
143             if (kjsObject->getPropertySlot(exec, propertyName, slot))
144                 return true;
145         }
146     }
147     return ObjectImp::getOwnPropertySlot(exec, propertyName, slot);
148 }
149
150 void UserObjectImp::put(ExecState *exec, const Identifier &propertyName, ValueImp *value, int attr)
151 {
152     CFStringRef cfPropName = IdentifierToCFString(propertyName);
153     JSUserObject *jsValueObj = KJSValueToJSObject(value, exec);
154     
155     fJSUserObject->SetProperty(cfPropName, jsValueObj);
156     
157     if (jsValueObj) jsValueObj->Release();      
158     ReleaseCFType(cfPropName);
159 }
160         
161 JSUserObject* UserObjectImp::GetJSUserObject() const 
162
163         return fJSUserObject; 
164 }
165
166 ValueImp *UserObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
167 {
168     ValueImp *result = Undefined();
169     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
170     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : NULL;
171     if (cfValue) {
172         CFTypeID cfType = CFGetTypeID(cfValue);  // toPrimitive
173         if (cfValue == GetCFNull()) {
174             result = Null();
175         }
176         else if (cfType == CFBooleanGetTypeID()) {
177             if (cfValue == kCFBooleanTrue) {
178                 result = KJS::Boolean(true);
179             } else {
180                 result = KJS::Boolean(false);
181             }
182         } else if (cfType == CFStringGetTypeID()) {
183             result = KJS::String(CFStringToUString((CFStringRef)cfValue));
184         } else if (cfType == CFNumberGetTypeID()) {
185             double d = 0.0;
186             CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
187             result = KJS::Number(d);
188         } else if (cfType == CFURLGetTypeID()) {
189             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
190             if (absURL) {
191                 result = KJS::String(CFStringToUString(CFURLGetString(absURL)));
192                 ReleaseCFType(absURL);
193             }
194         }               
195         ReleaseCFType(cfValue);
196     }
197     if (jsObjPtr) 
198         jsObjPtr->Release();
199     return result;
200 }
201
202
203 bool UserObjectImp::toBoolean(ExecState *exec) const
204 {
205         bool result = false;
206         JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
207         CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : NULL;
208         if (cfValue)
209         {
210                 CFTypeID cfType = CFGetTypeID(cfValue);  // toPrimitive
211                 if (cfValue == GetCFNull())
212                 {
213                         //
214                 }
215                 else if (cfType == CFBooleanGetTypeID())
216                 {
217                         if (cfValue == kCFBooleanTrue)
218                         {
219                                 result = true;
220                         }
221                 }
222                 else if (cfType == CFStringGetTypeID())
223                 {
224                         if (CFStringGetLength((CFStringRef)cfValue))
225                         {
226                                 result = true;
227                         }
228                 }
229                 else if (cfType == CFNumberGetTypeID())
230                 {
231                         if (cfValue != kCFNumberNaN)
232                         {
233                                 double d;
234                                 if (CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d))
235                                 {
236                                         if (d != 0)
237                                         {
238                                                 result = true;
239                                         }
240                                 }
241                         }
242                 }
243                 else if (cfType == CFArrayGetTypeID())
244                 {
245                         if (CFArrayGetCount((CFArrayRef)cfValue))
246                         {
247                                 result = true;
248                         }
249                 }
250                 else if (cfType == CFDictionaryGetTypeID())
251                 {
252                         if (CFDictionaryGetCount((CFDictionaryRef)cfValue))
253                         {
254                                 result = true;
255                         }
256                 }
257                 else if (cfType == CFSetGetTypeID())
258                 {
259                         if (CFSetGetCount((CFSetRef)cfValue))
260                         {
261                                 result = true;
262                         }
263                 }
264                 else if (cfType == CFURLGetTypeID())
265                 {
266                         CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
267                         if (absURL)
268                         {
269                                 CFStringRef cfStr = CFURLGetString(absURL);
270                                 if (cfStr && CFStringGetLength(cfStr))
271                                 {
272                                         result = true;
273                                 }
274                                 ReleaseCFType(absURL);
275                         }
276                 }
277         }
278         if (jsObjPtr) jsObjPtr->Release();
279         ReleaseCFType(cfValue);
280         return result;
281 }
282
283 double UserObjectImp::toNumber(ExecState *exec) const
284 {
285         double result = 0;
286         JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
287         CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : NULL;
288         if (cfValue)
289         {
290                 CFTypeID cfType = CFGetTypeID(cfValue);
291                 
292                 if (cfValue == GetCFNull())
293                 {
294                         //
295                 }
296                 else if (cfType == CFBooleanGetTypeID())
297                 {
298                         if (cfValue == kCFBooleanTrue)
299                         {
300                                 result = 1;
301                         }
302                 }
303                 else if (cfType == CFStringGetTypeID())
304                 {
305                         result = CFStringGetDoubleValue((CFStringRef)cfValue);
306                 }
307                 else if (cfType == CFNumberGetTypeID())
308                 {
309                         CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &result);           
310                 }
311         }
312         ReleaseCFType(cfValue);
313         if (jsObjPtr) jsObjPtr->Release();
314         return result;
315 }
316
317 UString UserObjectImp::toString(ExecState *exec) const
318 {
319         UString result;
320         JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec), exec);
321         CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : NULL;
322         if (cfValue)
323         {
324                 CFTypeID cfType = CFGetTypeID(cfValue);
325                 if (cfValue == GetCFNull())
326                 {
327                         //
328                 }
329                 else if (cfType == CFBooleanGetTypeID())
330                 {
331                         if (cfValue == kCFBooleanTrue)
332                         {
333                                 result = "true";
334                         }
335                         else
336                         {
337                                 result = "false";
338                         }
339                 }
340                 else if (cfType == CFStringGetTypeID())
341                 {
342                         result = CFStringToUString((CFStringRef)cfValue);
343                 }
344                 else if (cfType == CFNumberGetTypeID())
345                 {
346                         if (cfValue == kCFNumberNaN)
347                         {
348                                 result = "Nan";
349                         }
350                         else if (CFNumberCompare(kCFNumberPositiveInfinity, (CFNumberRef)cfValue, NULL) == 0)
351                         {
352                                 result = "Infinity";
353                         }
354                         else if (CFNumberCompare(kCFNumberNegativeInfinity, (CFNumberRef)cfValue, NULL) == 0)
355                         {
356                                 result = "-Infinity";
357                         }
358                         else
359                         {
360                                 CFStringRef cfNumStr = NULL;
361                                 if (CFNumberIsFloatType((CFNumberRef)cfValue))
362                                 {
363                                         double d = 0;
364                                         CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
365                                         cfNumStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%f"), (float)d);
366                                 }
367                                 else
368                                 {
369                                         int i = 0;
370                                         CFNumberGetValue((CFNumberRef)cfValue, kCFNumberIntType, &i);
371                                         cfNumStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), (int)i);
372                                 }
373                                 
374                                 if (cfNumStr)
375                                 {
376                                         result = CFStringToUString(cfNumStr);
377                                         ReleaseCFType(cfNumStr);
378                                 }                               
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::mark()
413 {
414     ObjectImp::mark(); // call parent to mark self
415     if (fJSUserObject) {
416         fJSUserObject->Mark(); // mark child
417     }
418 }