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