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
UserObjectImp(PassRefPtr<Structure> structure,JSUserObject * userObject)37 UserObjectImp::UserObjectImp(PassRefPtr<Structure> structure, JSUserObject* userObject)
38 : JSObject(structure)
39 , fJSUserObject((JSUserObject*)userObject->Retain())
40 {
41 }
42
~UserObjectImp()43 UserObjectImp::~UserObjectImp()
44 {
45 if (fJSUserObject)
46 fJSUserObject->Release();
47 }
48
classInfo() const49 const ClassInfo * UserObjectImp::classInfo() const
50 {
51 return &info;
52 }
53
getCallData(CallData & callData)54 CallType UserObjectImp::getCallData(CallData& callData)
55 {
56 return fJSUserObject ? fJSUserObject->getCallData(callData) : CallTypeNone;
57 }
58
callAsFunction(ExecState * exec,JSObject * thisObj,const ArgList & args)59 JSValue UserObjectImp::callAsFunction(ExecState *exec, JSObject *thisObj, const ArgList &args)
60 {
61 JSValue result = jsUndefined();
62 JSUserObject* jsThisObj = KJSValueToJSObject(thisObj, exec);
63 if (jsThisObj) {
64 CFIndex argCount = args.size();
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(args.at(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
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)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
userObjectGetter(ExecState *,const Identifier & propertyName,const PropertySlot & slot)115 JSValue UserObjectImp::userObjectGetter(ExecState*, const Identifier& propertyName, const PropertySlot& slot)
116 {
117 UserObjectImp *thisObj = static_cast<UserObjectImp *>(asObject(slot.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
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)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
put(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot &)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
GetJSUserObject() const167 JSUserObject* UserObjectImp::GetJSUserObject() const
168 {
169 return fJSUserObject;
170 }
171
toPrimitive(ExecState * exec,JSType) const172 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
toBoolean(ExecState * exec) const209 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
toNumber(ExecState * exec) const289 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
toString(ExecState * exec) const323 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
markChildren(MarkStack & markStack)412 void UserObjectImp::markChildren(MarkStack& markStack)
413 {
414 JSObject::markChildren(markStack);
415 if (fJSUserObject)
416 fJSUserObject->Mark();
417 }
418