• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::s_info = { "UserObject", &JSNonFinalObject::s_info, 0, 0 };
36 
UserObjectImp(JSGlobalData & globalData,Structure * structure,JSUserObject * userObject)37 UserObjectImp::UserObjectImp(JSGlobalData& globalData, Structure* structure, JSUserObject* userObject)
38     : JSNonFinalObject(globalData, structure)
39     , fJSUserObject((JSUserObject*)userObject->Retain())
40 {
41 }
42 
~UserObjectImp()43 UserObjectImp::~UserObjectImp()
44 {
45     if (fJSUserObject)
46         fJSUserObject->Release();
47 }
48 
getCallData(CallData & callData)49 CallType UserObjectImp::getCallData(CallData& callData)
50 {
51     return fJSUserObject ? fJSUserObject->getCallData(callData) : CallTypeNone;
52 }
53 
callAsFunction(ExecState * exec)54 JSValue UserObjectImp::callAsFunction(ExecState *exec)
55 {
56     JSValue result = jsUndefined();
57     JSUserObject* jsThisObj = KJSValueToJSObject(exec->hostThisValue().toThisObject(exec), exec);
58     if (jsThisObj) {
59         CFIndex argCount = exec->argumentCount();
60         CFArrayCallBacks arrayCallBacks;
61         JSTypeGetCFArrayCallBacks(&arrayCallBacks);
62         CFMutableArrayRef jsArgs = CFArrayCreateMutable(0, 0, &arrayCallBacks);
63         if (jsArgs) {
64             for (CFIndex i = 0; i < argCount; i++) {
65                 JSUserObject* jsArg = KJSValueToJSObject(exec->argument(i), exec);
66                 CFArrayAppendValue(jsArgs, (void*)jsArg);
67                 jsArg->Release();
68             }
69         }
70 
71         JSUserObject* jsResult;
72         { // scope
73             JSGlueAPICallback apiCallback(exec);
74 
75             // getCallData should have guarded against a NULL fJSUserObject.
76             assert(fJSUserObject);
77             jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs);
78         }
79 
80         if (jsResult) {
81             result = JSObjectKJSValue(jsResult);
82             jsResult->Release();
83         }
84 
85         ReleaseCFType(jsArgs);
86         jsThisObj->Release();
87     }
88     return result;
89 }
90 
91 
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)92 void UserObjectImp::getOwnPropertyNames(ExecState *exec, PropertyNameArray& propertyNames, EnumerationMode mode)
93 {
94     JSUserObject* ptr = GetJSUserObject();
95     if (ptr) {
96         CFArrayRef cfPropertyNames = ptr->CopyPropertyNames();
97         if (cfPropertyNames) {
98             CFIndex count = CFArrayGetCount(cfPropertyNames);
99             CFIndex i;
100             for (i = 0; i < count; i++) {
101                 CFStringRef propertyName = (CFStringRef)CFArrayGetValueAtIndex(cfPropertyNames, i);
102                 propertyNames.add(CFStringToIdentifier(propertyName, exec));
103             }
104             CFRelease(cfPropertyNames);
105         }
106     }
107     JSObject::getOwnPropertyNames(exec, propertyNames, mode);
108 }
109 
userObjectGetter(ExecState *,JSValue slotBase,const Identifier & propertyName)110 JSValue UserObjectImp::userObjectGetter(ExecState*, JSValue slotBase, const Identifier& propertyName)
111 {
112     UserObjectImp *thisObj = static_cast<UserObjectImp *>(asObject(slotBase));
113     // getOwnPropertySlot should have guarded against a null fJSUserObject.
114     assert(thisObj->fJSUserObject);
115 
116     CFStringRef cfPropName = IdentifierToCFString(propertyName);
117     JSUserObject *jsResult = thisObj->fJSUserObject->CopyProperty(cfPropName);
118     ReleaseCFType(cfPropName);
119     JSValue result = JSObjectKJSValue(jsResult);
120     jsResult->Release();
121 
122     return result;
123 }
124 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)125 bool UserObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
126 {
127     if (!fJSUserObject)
128         return false;
129 
130     CFStringRef cfPropName = IdentifierToCFString(propertyName);
131     JSUserObject *jsResult = fJSUserObject->CopyProperty(cfPropName);
132     ReleaseCFType(cfPropName);
133     if (jsResult) {
134         slot.setCustom(this, userObjectGetter);
135         jsResult->Release();
136         return true;
137     } else {
138         JSValue kjsValue = toPrimitive(exec);
139         if (!kjsValue.isUndefinedOrNull()) {
140             JSObject* kjsObject = kjsValue.toObject(exec);
141             if (kjsObject->getPropertySlot(exec, propertyName, slot))
142                 return true;
143         }
144     }
145     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
146 }
147 
put(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot &)148 void UserObjectImp::put(ExecState *exec, const Identifier &propertyName, JSValue value, PutPropertySlot&)
149 {
150     if (!fJSUserObject)
151         return;
152 
153     CFStringRef cfPropName = IdentifierToCFString(propertyName);
154     JSUserObject *jsValueObj = KJSValueToJSObject(value, exec);
155 
156     fJSUserObject->SetProperty(cfPropName, jsValueObj);
157 
158     if (jsValueObj) jsValueObj->Release();
159     ReleaseCFType(cfPropName);
160 }
161 
GetJSUserObject() const162 JSUserObject* UserObjectImp::GetJSUserObject() const
163 {
164     return fJSUserObject;
165 }
166 
toPrimitive(ExecState * exec,PreferredPrimitiveType) const167 JSValue UserObjectImp::toPrimitive(ExecState *exec, PreferredPrimitiveType) const
168 {
169     JSValue result = jsUndefined();
170     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec, exec->lexicalGlobalObject()), exec);
171     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
172     if (cfValue) {
173         CFTypeID cfType = CFGetTypeID(cfValue);  // toPrimitive
174         if (cfValue == GetCFNull()) {
175             result = jsNull();
176         }
177         else if (cfType == CFBooleanGetTypeID()) {
178             if (cfValue == kCFBooleanTrue) {
179                 result = jsBoolean(true);
180             } else {
181                 result = jsBoolean(false);
182             }
183         } else if (cfType == CFStringGetTypeID()) {
184             result = jsString(exec, CFStringToUString((CFStringRef)cfValue));
185         } else if (cfType == CFNumberGetTypeID()) {
186             double d = 0.0;
187             CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
188             result = jsNumber(d);
189         } else if (cfType == CFURLGetTypeID()) {
190             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
191             if (absURL) {
192                 result = jsString(exec, CFStringToUString(CFURLGetString(absURL)));
193                 ReleaseCFType(absURL);
194             }
195         }
196         ReleaseCFType(cfValue);
197     }
198     if (jsObjPtr)
199         jsObjPtr->Release();
200     return result;
201 }
202 
203 
toBoolean(ExecState * exec) const204 bool UserObjectImp::toBoolean(ExecState *exec) const
205 {
206     bool result = false;
207     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec, exec->lexicalGlobalObject()), exec);
208     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
209     if (cfValue)
210     {
211         CFTypeID cfType = CFGetTypeID(cfValue);  // toPrimitive
212         if (cfValue == GetCFNull())
213         {
214             //
215         }
216         else if (cfType == CFBooleanGetTypeID())
217         {
218             if (cfValue == kCFBooleanTrue)
219             {
220                 result = true;
221             }
222         }
223         else if (cfType == CFStringGetTypeID())
224         {
225             if (CFStringGetLength((CFStringRef)cfValue))
226             {
227                 result = true;
228             }
229         }
230         else if (cfType == CFNumberGetTypeID())
231         {
232             if (cfValue != kCFNumberNaN)
233             {
234                 double d;
235                 if (CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d))
236                 {
237                     if (d != 0)
238                     {
239                         result = true;
240                     }
241                 }
242             }
243         }
244         else if (cfType == CFArrayGetTypeID())
245         {
246             if (CFArrayGetCount((CFArrayRef)cfValue))
247             {
248                 result = true;
249             }
250         }
251         else if (cfType == CFDictionaryGetTypeID())
252         {
253             if (CFDictionaryGetCount((CFDictionaryRef)cfValue))
254             {
255                 result = true;
256             }
257         }
258         else if (cfType == CFSetGetTypeID())
259         {
260             if (CFSetGetCount((CFSetRef)cfValue))
261             {
262                 result = true;
263             }
264         }
265         else if (cfType == CFURLGetTypeID())
266         {
267             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
268             if (absURL)
269             {
270                 CFStringRef cfStr = CFURLGetString(absURL);
271                 if (cfStr && CFStringGetLength(cfStr))
272                 {
273                     result = true;
274                 }
275                 ReleaseCFType(absURL);
276             }
277         }
278     }
279     if (jsObjPtr) jsObjPtr->Release();
280     ReleaseCFType(cfValue);
281     return result;
282 }
283 
toNumber(ExecState * exec) const284 double UserObjectImp::toNumber(ExecState *exec) const
285 {
286     double result = 0;
287     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec, exec->lexicalGlobalObject()), exec);
288     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
289     if (cfValue)
290     {
291         CFTypeID cfType = CFGetTypeID(cfValue);
292 
293         if (cfValue == GetCFNull())
294         {
295             //
296         }
297         else if (cfType == CFBooleanGetTypeID())
298         {
299             if (cfValue == kCFBooleanTrue)
300             {
301                 result = 1;
302             }
303         }
304         else if (cfType == CFStringGetTypeID())
305         {
306             result = CFStringGetDoubleValue((CFStringRef)cfValue);
307         }
308         else if (cfType == CFNumberGetTypeID())
309         {
310             CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &result);
311         }
312     }
313     ReleaseCFType(cfValue);
314     if (jsObjPtr) jsObjPtr->Release();
315     return result;
316 }
317 
toString(ExecState * exec) const318 UString UserObjectImp::toString(ExecState *exec) const
319 {
320     UString result;
321     JSUserObject* jsObjPtr = KJSValueToJSObject(toObject(exec, exec->lexicalGlobalObject()), exec);
322     CFTypeRef cfValue = jsObjPtr ? jsObjPtr->CopyCFValue() : 0;
323     if (cfValue)
324     {
325         CFTypeID cfType = CFGetTypeID(cfValue);
326         if (cfValue == GetCFNull())
327         {
328             //
329         }
330         else if (cfType == CFBooleanGetTypeID())
331         {
332             if (cfValue == kCFBooleanTrue)
333             {
334                 result = "true";
335             }
336             else
337             {
338                 result = "false";
339             }
340         }
341         else if (cfType == CFStringGetTypeID())
342         {
343             result = CFStringToUString((CFStringRef)cfValue);
344         }
345         else if (cfType == CFNumberGetTypeID())
346         {
347             if (cfValue == kCFNumberNaN)
348             {
349                 result = "Nan";
350             }
351             else if (CFNumberCompare(kCFNumberPositiveInfinity, (CFNumberRef)cfValue, 0) == 0)
352             {
353                 result = "Infinity";
354             }
355             else if (CFNumberCompare(kCFNumberNegativeInfinity, (CFNumberRef)cfValue, 0) == 0)
356             {
357                 result = "-Infinity";
358             }
359             else
360             {
361                 CFStringRef cfNumStr;
362                 double d = 0;
363                 CFNumberGetValue((CFNumberRef)cfValue, kCFNumberDoubleType, &d);
364                 if (CFNumberIsFloatType((CFNumberRef)cfValue))
365                 {
366                     cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%f"), d);
367                 }
368                 else
369                 {
370                     cfNumStr = CFStringCreateWithFormat(0, 0, CFSTR("%.0f"), d);
371                 }
372                 result = CFStringToUString(cfNumStr);
373                 ReleaseCFType(cfNumStr);
374             }
375         }
376         else if (cfType == CFArrayGetTypeID())
377         {
378             //
379         }
380         else if (cfType == CFDictionaryGetTypeID())
381         {
382             //
383         }
384         else if (cfType == CFSetGetTypeID())
385         {
386             //
387         }
388         else if (cfType == CFURLGetTypeID())
389         {
390             CFURLRef absURL = CFURLCopyAbsoluteURL((CFURLRef)cfValue);
391             if (absURL)
392             {
393                 CFStringRef cfStr = CFURLGetString(absURL);
394                 if (cfStr)
395                 {
396                     result = CFStringToUString(cfStr);
397                 }
398                 ReleaseCFType(absURL);
399             }
400         }
401     }
402     ReleaseCFType(cfValue);
403     if (jsObjPtr) jsObjPtr->Release();
404     return result;
405 }
406 
markChildren(MarkStack & markStack)407 void UserObjectImp::markChildren(MarkStack& markStack)
408 {
409     JSObject::markChildren(markStack);
410     if (fJSUserObject)
411         fJSUserObject->Mark();
412 }
413