]>
Commit | Line | Data |
---|---|---|
b37bf2e1 | 1 | /* |
9dae56ea | 2 | * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. |
b37bf2e1 A |
3 | * Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
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 | * | |
14 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | |
15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
17 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
18 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
19 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
21 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
22 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 | */ | |
26 | ||
f9bf01c6 | 27 | #include "APIShims.h" |
b37bf2e1 | 28 | #include "APICast.h" |
9dae56ea | 29 | #include "Error.h" |
b37bf2e1 A |
30 | #include "JSCallbackFunction.h" |
31 | #include "JSClassRef.h" | |
b37bf2e1 | 32 | #include "JSGlobalObject.h" |
9dae56ea A |
33 | #include "JSLock.h" |
34 | #include "JSObjectRef.h" | |
35 | #include "JSString.h" | |
b37bf2e1 | 36 | #include "JSStringRef.h" |
9dae56ea | 37 | #include "OpaqueJSString.h" |
b37bf2e1 | 38 | #include "PropertyNameArray.h" |
b37bf2e1 A |
39 | #include <wtf/Vector.h> |
40 | ||
9dae56ea A |
41 | namespace JSC { |
42 | ||
43 | template <class Base> | |
ba379fdc | 44 | inline JSCallbackObject<Base>* JSCallbackObject<Base>::asCallbackObject(JSValue value) |
9dae56ea A |
45 | { |
46 | ASSERT(asObject(value)->inherits(&info)); | |
47 | return static_cast<JSCallbackObject*>(asObject(value)); | |
48 | } | |
b37bf2e1 A |
49 | |
50 | template <class Base> | |
f9bf01c6 | 51 | JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, NonNullPassRefPtr<Structure> structure, JSClassRef jsClass, void* data) |
9dae56ea A |
52 | : Base(structure) |
53 | , m_callbackObjectData(new JSCallbackObjectData(data, jsClass)) | |
b37bf2e1 A |
54 | { |
55 | init(exec); | |
56 | } | |
57 | ||
9dae56ea A |
58 | // Global object constructor. |
59 | // FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one. | |
b37bf2e1 A |
60 | template <class Base> |
61 | JSCallbackObject<Base>::JSCallbackObject(JSClassRef jsClass) | |
9dae56ea A |
62 | : Base() |
63 | , m_callbackObjectData(new JSCallbackObjectData(0, jsClass)) | |
b37bf2e1 A |
64 | { |
65 | ASSERT(Base::isGlobalObject()); | |
66 | init(static_cast<JSGlobalObject*>(this)->globalExec()); | |
67 | } | |
68 | ||
69 | template <class Base> | |
70 | void JSCallbackObject<Base>::init(ExecState* exec) | |
71 | { | |
72 | ASSERT(exec); | |
73 | ||
74 | Vector<JSObjectInitializeCallback, 16> initRoutines; | |
9dae56ea | 75 | JSClassRef jsClass = classRef(); |
b37bf2e1 A |
76 | do { |
77 | if (JSObjectInitializeCallback initialize = jsClass->initialize) | |
78 | initRoutines.append(initialize); | |
79 | } while ((jsClass = jsClass->parentClass)); | |
80 | ||
81 | // initialize from base to derived | |
82 | for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) { | |
f9bf01c6 | 83 | APICallbackShim callbackShim(exec); |
b37bf2e1 A |
84 | JSObjectInitializeCallback initialize = initRoutines[i]; |
85 | initialize(toRef(exec), toRef(this)); | |
86 | } | |
87 | } | |
88 | ||
89 | template <class Base> | |
90 | JSCallbackObject<Base>::~JSCallbackObject() | |
91 | { | |
92 | JSObjectRef thisRef = toRef(this); | |
93 | ||
9dae56ea A |
94 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
95 | if (JSObjectFinalizeCallback finalize = jsClass->finalize) | |
b37bf2e1 | 96 | finalize(thisRef); |
b37bf2e1 A |
97 | } |
98 | ||
99 | template <class Base> | |
100 | UString JSCallbackObject<Base>::className() const | |
101 | { | |
9dae56ea | 102 | UString thisClassName = classRef()->className(); |
ba379fdc | 103 | if (!thisClassName.isEmpty()) |
9dae56ea | 104 | return thisClassName; |
b37bf2e1 A |
105 | |
106 | return Base::className(); | |
107 | } | |
108 | ||
109 | template <class Base> | |
110 | bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | |
111 | { | |
112 | JSContextRef ctx = toRef(exec); | |
113 | JSObjectRef thisRef = toRef(this); | |
9dae56ea | 114 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 115 | |
9dae56ea | 116 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 A |
117 | // optional optimization to bypass getProperty in cases when we only need to know if the property exists |
118 | if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) { | |
9dae56ea A |
119 | if (!propertyNameRef) |
120 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
f9bf01c6 | 121 | APICallbackShim callbackShim(exec); |
9dae56ea | 122 | if (hasProperty(ctx, thisRef, propertyNameRef.get())) { |
b37bf2e1 A |
123 | slot.setCustom(this, callbackGetter); |
124 | return true; | |
125 | } | |
126 | } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { | |
9dae56ea A |
127 | if (!propertyNameRef) |
128 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
129 | JSValueRef exception = 0; |
130 | JSValueRef value; | |
131 | { | |
f9bf01c6 | 132 | APICallbackShim callbackShim(exec); |
ba379fdc A |
133 | value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); |
134 | } | |
ba379fdc | 135 | if (exception) { |
f9bf01c6 | 136 | exec->setException(toJS(exec, exception)); |
ba379fdc | 137 | slot.setValue(jsUndefined()); |
b37bf2e1 A |
138 | return true; |
139 | } | |
f9bf01c6 A |
140 | if (value) { |
141 | slot.setValue(toJS(exec, value)); | |
142 | return true; | |
143 | } | |
b37bf2e1 A |
144 | } |
145 | ||
9dae56ea | 146 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
b37bf2e1 A |
147 | if (staticValues->contains(propertyName.ustring().rep())) { |
148 | slot.setCustom(this, staticValueGetter); | |
149 | return true; | |
150 | } | |
151 | } | |
152 | ||
9dae56ea | 153 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
b37bf2e1 A |
154 | if (staticFunctions->contains(propertyName.ustring().rep())) { |
155 | slot.setCustom(this, staticFunctionGetter); | |
156 | return true; | |
157 | } | |
158 | } | |
159 | } | |
160 | ||
161 | return Base::getOwnPropertySlot(exec, propertyName, slot); | |
162 | } | |
163 | ||
164 | template <class Base> | |
165 | bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) | |
166 | { | |
9dae56ea | 167 | return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); |
b37bf2e1 A |
168 | } |
169 | ||
f9bf01c6 A |
170 | template <class Base> |
171 | bool JSCallbackObject<Base>::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) | |
172 | { | |
173 | PropertySlot slot; | |
174 | if (getOwnPropertySlot(exec, propertyName, slot)) { | |
175 | // Ideally we should return an access descriptor, but returning a value descriptor is better than nothing. | |
176 | JSValue value = slot.getValue(exec, propertyName); | |
177 | if (!exec->hadException()) | |
178 | descriptor.setValue(value); | |
179 | // We don't know whether the property is configurable, but assume it is. | |
180 | descriptor.setConfigurable(true); | |
181 | // We don't know whether the property is enumerable (we could call getOwnPropertyNames() to find out), but assume it isn't. | |
182 | descriptor.setEnumerable(false); | |
183 | return true; | |
184 | } | |
185 | ||
186 | return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); | |
187 | } | |
188 | ||
b37bf2e1 | 189 | template <class Base> |
ba379fdc | 190 | void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) |
b37bf2e1 A |
191 | { |
192 | JSContextRef ctx = toRef(exec); | |
193 | JSObjectRef thisRef = toRef(this); | |
9dae56ea | 194 | RefPtr<OpaqueJSString> propertyNameRef; |
ba379fdc | 195 | JSValueRef valueRef = toRef(exec, value); |
b37bf2e1 | 196 | |
9dae56ea | 197 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 198 | if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { |
9dae56ea A |
199 | if (!propertyNameRef) |
200 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
201 | JSValueRef exception = 0; |
202 | bool result; | |
203 | { | |
f9bf01c6 | 204 | APICallbackShim callbackShim(exec); |
ba379fdc A |
205 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); |
206 | } | |
f9bf01c6 A |
207 | if (exception) |
208 | exec->setException(toJS(exec, exception)); | |
ba379fdc | 209 | if (result || exception) |
b37bf2e1 A |
210 | return; |
211 | } | |
212 | ||
9dae56ea | 213 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
b37bf2e1 A |
214 | if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) { |
215 | if (entry->attributes & kJSPropertyAttributeReadOnly) | |
216 | return; | |
217 | if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { | |
9dae56ea A |
218 | if (!propertyNameRef) |
219 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
220 | JSValueRef exception = 0; |
221 | bool result; | |
222 | { | |
f9bf01c6 | 223 | APICallbackShim callbackShim(exec); |
ba379fdc A |
224 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); |
225 | } | |
f9bf01c6 A |
226 | if (exception) |
227 | exec->setException(toJS(exec, exception)); | |
ba379fdc | 228 | if (result || exception) |
b37bf2e1 A |
229 | return; |
230 | } else | |
231 | throwError(exec, ReferenceError, "Attempt to set a property that is not settable."); | |
232 | } | |
233 | } | |
234 | ||
9dae56ea | 235 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
b37bf2e1 A |
236 | if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) { |
237 | if (entry->attributes & kJSPropertyAttributeReadOnly) | |
238 | return; | |
9dae56ea | 239 | JSCallbackObject<Base>::putDirect(propertyName, value); // put as override property |
b37bf2e1 A |
240 | return; |
241 | } | |
242 | } | |
243 | } | |
244 | ||
9dae56ea | 245 | return Base::put(exec, propertyName, value, slot); |
b37bf2e1 A |
246 | } |
247 | ||
248 | template <class Base> | |
249 | bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, const Identifier& propertyName) | |
250 | { | |
251 | JSContextRef ctx = toRef(exec); | |
252 | JSObjectRef thisRef = toRef(this); | |
9dae56ea | 253 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 254 | |
9dae56ea | 255 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 256 | if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) { |
9dae56ea A |
257 | if (!propertyNameRef) |
258 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
259 | JSValueRef exception = 0; |
260 | bool result; | |
261 | { | |
f9bf01c6 | 262 | APICallbackShim callbackShim(exec); |
ba379fdc A |
263 | result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception); |
264 | } | |
f9bf01c6 A |
265 | if (exception) |
266 | exec->setException(toJS(exec, exception)); | |
ba379fdc | 267 | if (result || exception) |
b37bf2e1 A |
268 | return true; |
269 | } | |
270 | ||
9dae56ea | 271 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
b37bf2e1 A |
272 | if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) { |
273 | if (entry->attributes & kJSPropertyAttributeDontDelete) | |
274 | return false; | |
275 | return true; | |
276 | } | |
277 | } | |
278 | ||
9dae56ea | 279 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
b37bf2e1 A |
280 | if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) { |
281 | if (entry->attributes & kJSPropertyAttributeDontDelete) | |
282 | return false; | |
283 | return true; | |
284 | } | |
285 | } | |
286 | } | |
287 | ||
288 | return Base::deleteProperty(exec, propertyName); | |
289 | } | |
290 | ||
291 | template <class Base> | |
292 | bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, unsigned propertyName) | |
293 | { | |
9dae56ea | 294 | return deleteProperty(exec, Identifier::from(exec, propertyName)); |
b37bf2e1 A |
295 | } |
296 | ||
297 | template <class Base> | |
9dae56ea | 298 | ConstructType JSCallbackObject<Base>::getConstructData(ConstructData& constructData) |
b37bf2e1 | 299 | { |
9dae56ea A |
300 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
301 | if (jsClass->callAsConstructor) { | |
302 | constructData.native.function = construct; | |
303 | return ConstructTypeHost; | |
304 | } | |
305 | } | |
306 | return ConstructTypeNone; | |
b37bf2e1 A |
307 | } |
308 | ||
309 | template <class Base> | |
9dae56ea | 310 | JSObject* JSCallbackObject<Base>::construct(ExecState* exec, JSObject* constructor, const ArgList& args) |
b37bf2e1 A |
311 | { |
312 | JSContextRef execRef = toRef(exec); | |
9dae56ea | 313 | JSObjectRef constructorRef = toRef(constructor); |
b37bf2e1 | 314 | |
9dae56ea | 315 | for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 A |
316 | if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) { |
317 | int argumentCount = static_cast<int>(args.size()); | |
318 | Vector<JSValueRef, 16> arguments(argumentCount); | |
319 | for (int i = 0; i < argumentCount; i++) | |
ba379fdc A |
320 | arguments[i] = toRef(exec, args.at(i)); |
321 | JSValueRef exception = 0; | |
322 | JSObject* result; | |
323 | { | |
f9bf01c6 | 324 | APICallbackShim callbackShim(exec); |
ba379fdc A |
325 | result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception)); |
326 | } | |
f9bf01c6 A |
327 | if (exception) |
328 | exec->setException(toJS(exec, exception)); | |
ba379fdc | 329 | return result; |
b37bf2e1 A |
330 | } |
331 | } | |
332 | ||
9dae56ea | 333 | ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here |
b37bf2e1 A |
334 | return 0; |
335 | } | |
336 | ||
337 | template <class Base> | |
ba379fdc | 338 | bool JSCallbackObject<Base>::hasInstance(ExecState* exec, JSValue value, JSValue) |
b37bf2e1 A |
339 | { |
340 | JSContextRef execRef = toRef(exec); | |
341 | JSObjectRef thisRef = toRef(this); | |
342 | ||
9dae56ea | 343 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 344 | if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) { |
ba379fdc A |
345 | JSValueRef valueRef = toRef(exec, value); |
346 | JSValueRef exception = 0; | |
347 | bool result; | |
348 | { | |
f9bf01c6 | 349 | APICallbackShim callbackShim(exec); |
ba379fdc A |
350 | result = hasInstance(execRef, thisRef, valueRef, &exception); |
351 | } | |
f9bf01c6 A |
352 | if (exception) |
353 | exec->setException(toJS(exec, exception)); | |
ba379fdc | 354 | return result; |
b37bf2e1 | 355 | } |
9dae56ea A |
356 | } |
357 | return false; | |
b37bf2e1 A |
358 | } |
359 | ||
b37bf2e1 | 360 | template <class Base> |
9dae56ea | 361 | CallType JSCallbackObject<Base>::getCallData(CallData& callData) |
b37bf2e1 | 362 | { |
9dae56ea A |
363 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
364 | if (jsClass->callAsFunction) { | |
365 | callData.native.function = call; | |
366 | return CallTypeHost; | |
367 | } | |
368 | } | |
369 | return CallTypeNone; | |
b37bf2e1 A |
370 | } |
371 | ||
372 | template <class Base> | |
ba379fdc | 373 | JSValue JSCallbackObject<Base>::call(ExecState* exec, JSObject* functionObject, JSValue thisValue, const ArgList& args) |
b37bf2e1 A |
374 | { |
375 | JSContextRef execRef = toRef(exec); | |
9dae56ea A |
376 | JSObjectRef functionRef = toRef(functionObject); |
377 | JSObjectRef thisObjRef = toRef(thisValue.toThisObject(exec)); | |
b37bf2e1 | 378 | |
9dae56ea | 379 | for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(functionObject)->classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 A |
380 | if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) { |
381 | int argumentCount = static_cast<int>(args.size()); | |
382 | Vector<JSValueRef, 16> arguments(argumentCount); | |
383 | for (int i = 0; i < argumentCount; i++) | |
ba379fdc A |
384 | arguments[i] = toRef(exec, args.at(i)); |
385 | JSValueRef exception = 0; | |
386 | JSValue result; | |
387 | { | |
f9bf01c6 | 388 | APICallbackShim callbackShim(exec); |
ba379fdc A |
389 | result = toJS(exec, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception)); |
390 | } | |
f9bf01c6 A |
391 | if (exception) |
392 | exec->setException(toJS(exec, exception)); | |
ba379fdc | 393 | return result; |
b37bf2e1 A |
394 | } |
395 | } | |
396 | ||
9dae56ea | 397 | ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here |
ba379fdc | 398 | return JSValue(); |
b37bf2e1 A |
399 | } |
400 | ||
401 | template <class Base> | |
f9bf01c6 | 402 | void JSCallbackObject<Base>::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) |
b37bf2e1 A |
403 | { |
404 | JSContextRef execRef = toRef(exec); | |
405 | JSObjectRef thisRef = toRef(this); | |
406 | ||
9dae56ea | 407 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 408 | if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) { |
f9bf01c6 | 409 | APICallbackShim callbackShim(exec); |
b37bf2e1 A |
410 | getPropertyNames(execRef, thisRef, toRef(&propertyNames)); |
411 | } | |
412 | ||
9dae56ea A |
413 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
414 | typedef OpaqueJSClassStaticValuesTable::const_iterator iterator; | |
b37bf2e1 A |
415 | iterator end = staticValues->end(); |
416 | for (iterator it = staticValues->begin(); it != end; ++it) { | |
417 | UString::Rep* name = it->first.get(); | |
418 | StaticValueEntry* entry = it->second; | |
f9bf01c6 | 419 | if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))) |
9dae56ea | 420 | propertyNames.add(Identifier(exec, name)); |
b37bf2e1 A |
421 | } |
422 | } | |
423 | ||
9dae56ea A |
424 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
425 | typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator; | |
b37bf2e1 A |
426 | iterator end = staticFunctions->end(); |
427 | for (iterator it = staticFunctions->begin(); it != end; ++it) { | |
428 | UString::Rep* name = it->first.get(); | |
429 | StaticFunctionEntry* entry = it->second; | |
f9bf01c6 | 430 | if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)) |
9dae56ea | 431 | propertyNames.add(Identifier(exec, name)); |
b37bf2e1 A |
432 | } |
433 | } | |
434 | } | |
435 | ||
f9bf01c6 | 436 | Base::getOwnPropertyNames(exec, propertyNames, mode); |
b37bf2e1 A |
437 | } |
438 | ||
439 | template <class Base> | |
440 | double JSCallbackObject<Base>::toNumber(ExecState* exec) const | |
441 | { | |
9dae56ea A |
442 | // We need this check to guard against the case where this object is rhs of |
443 | // a binary expression where lhs threw an exception in its conversion to | |
444 | // primitive | |
445 | if (exec->hadException()) | |
446 | return NaN; | |
b37bf2e1 A |
447 | JSContextRef ctx = toRef(exec); |
448 | JSObjectRef thisRef = toRef(this); | |
449 | ||
9dae56ea | 450 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
b37bf2e1 | 451 | if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { |
ba379fdc A |
452 | JSValueRef exception = 0; |
453 | JSValueRef value; | |
454 | { | |
f9bf01c6 | 455 | APICallbackShim callbackShim(exec); |
ba379fdc | 456 | value = convertToType(ctx, thisRef, kJSTypeNumber, &exception); |
9dae56ea | 457 | } |
ba379fdc A |
458 | if (exception) { |
459 | exec->setException(toJS(exec, exception)); | |
460 | return 0; | |
461 | } | |
462 | ||
463 | double dValue; | |
f9bf01c6 A |
464 | if (value) |
465 | return toJS(exec, value).getNumber(dValue) ? dValue : NaN; | |
b37bf2e1 A |
466 | } |
467 | ||
468 | return Base::toNumber(exec); | |
469 | } | |
470 | ||
471 | template <class Base> | |
472 | UString JSCallbackObject<Base>::toString(ExecState* exec) const | |
473 | { | |
474 | JSContextRef ctx = toRef(exec); | |
475 | JSObjectRef thisRef = toRef(this); | |
476 | ||
9dae56ea | 477 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
b37bf2e1 | 478 | if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { |
ba379fdc | 479 | JSValueRef exception = 0; |
9dae56ea A |
480 | JSValueRef value; |
481 | { | |
f9bf01c6 | 482 | APICallbackShim callbackShim(exec); |
ba379fdc | 483 | value = convertToType(ctx, thisRef, kJSTypeString, &exception); |
9dae56ea | 484 | } |
ba379fdc A |
485 | if (exception) { |
486 | exec->setException(toJS(exec, exception)); | |
487 | return ""; | |
488 | } | |
f9bf01c6 A |
489 | if (value) |
490 | return toJS(exec, value).getString(exec); | |
b37bf2e1 A |
491 | } |
492 | ||
493 | return Base::toString(exec); | |
494 | } | |
495 | ||
496 | template <class Base> | |
497 | void JSCallbackObject<Base>::setPrivate(void* data) | |
498 | { | |
9dae56ea | 499 | m_callbackObjectData->privateData = data; |
b37bf2e1 A |
500 | } |
501 | ||
502 | template <class Base> | |
503 | void* JSCallbackObject<Base>::getPrivate() | |
504 | { | |
9dae56ea | 505 | return m_callbackObjectData->privateData; |
b37bf2e1 A |
506 | } |
507 | ||
508 | template <class Base> | |
509 | bool JSCallbackObject<Base>::inherits(JSClassRef c) const | |
510 | { | |
9dae56ea | 511 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
b37bf2e1 A |
512 | if (jsClass == c) |
513 | return true; | |
514 | ||
515 | return false; | |
516 | } | |
517 | ||
518 | template <class Base> | |
4e4e5a6f | 519 | JSValue JSCallbackObject<Base>::staticValueGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) |
b37bf2e1 | 520 | { |
4e4e5a6f | 521 | JSCallbackObject* thisObj = asCallbackObject(slotBase); |
b37bf2e1 A |
522 | |
523 | JSObjectRef thisRef = toRef(thisObj); | |
9dae56ea | 524 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 525 | |
9dae56ea A |
526 | for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) |
527 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) | |
b37bf2e1 A |
528 | if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) |
529 | if (JSObjectGetPropertyCallback getProperty = entry->getProperty) { | |
9dae56ea A |
530 | if (!propertyNameRef) |
531 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
532 | JSValueRef exception = 0; |
533 | JSValueRef value; | |
534 | { | |
f9bf01c6 | 535 | APICallbackShim callbackShim(exec); |
ba379fdc A |
536 | value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); |
537 | } | |
f9bf01c6 A |
538 | if (exception) { |
539 | exec->setException(toJS(exec, exception)); | |
540 | return jsUndefined(); | |
541 | } | |
ba379fdc A |
542 | if (value) |
543 | return toJS(exec, value); | |
b37bf2e1 | 544 | } |
f9bf01c6 | 545 | |
b37bf2e1 A |
546 | return throwError(exec, ReferenceError, "Static value property defined with NULL getProperty callback."); |
547 | } | |
548 | ||
549 | template <class Base> | |
4e4e5a6f | 550 | JSValue JSCallbackObject<Base>::staticFunctionGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) |
b37bf2e1 | 551 | { |
4e4e5a6f | 552 | JSCallbackObject* thisObj = asCallbackObject(slotBase); |
b37bf2e1 A |
553 | |
554 | // Check for cached or override property. | |
9dae56ea | 555 | PropertySlot slot2(thisObj); |
b37bf2e1 | 556 | if (thisObj->Base::getOwnPropertySlot(exec, propertyName, slot2)) |
9dae56ea | 557 | return slot2.getValue(exec, propertyName); |
b37bf2e1 | 558 | |
9dae56ea A |
559 | for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { |
560 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { | |
b37bf2e1 A |
561 | if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) { |
562 | if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) { | |
9dae56ea | 563 | JSObject* o = new (exec) JSCallbackFunction(exec, callAsFunction, propertyName); |
b37bf2e1 A |
564 | thisObj->putDirect(propertyName, o, entry->attributes); |
565 | return o; | |
566 | } | |
567 | } | |
568 | } | |
569 | } | |
570 | ||
571 | return throwError(exec, ReferenceError, "Static function property defined with NULL callAsFunction callback."); | |
572 | } | |
573 | ||
574 | template <class Base> | |
4e4e5a6f | 575 | JSValue JSCallbackObject<Base>::callbackGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) |
b37bf2e1 | 576 | { |
4e4e5a6f | 577 | JSCallbackObject* thisObj = asCallbackObject(slotBase); |
b37bf2e1 A |
578 | |
579 | JSObjectRef thisRef = toRef(thisObj); | |
9dae56ea | 580 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 581 | |
9dae56ea | 582 | for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) |
b37bf2e1 | 583 | if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { |
9dae56ea A |
584 | if (!propertyNameRef) |
585 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
586 | JSValueRef exception = 0; |
587 | JSValueRef value; | |
588 | { | |
f9bf01c6 | 589 | APICallbackShim callbackShim(exec); |
ba379fdc A |
590 | value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); |
591 | } | |
f9bf01c6 A |
592 | if (exception) { |
593 | exec->setException(toJS(exec, exception)); | |
594 | return jsUndefined(); | |
595 | } | |
ba379fdc A |
596 | if (value) |
597 | return toJS(exec, value); | |
b37bf2e1 A |
598 | } |
599 | ||
600 | return throwError(exec, ReferenceError, "hasProperty callback returned true for a property that doesn't exist."); | |
601 | } | |
602 | ||
9dae56ea | 603 | } // namespace JSC |