]>
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" |
14957cd0 | 30 | #include "ExceptionHelpers.h" |
b37bf2e1 A |
31 | #include "JSCallbackFunction.h" |
32 | #include "JSClassRef.h" | |
14957cd0 | 33 | #include "JSFunction.h" |
b37bf2e1 | 34 | #include "JSGlobalObject.h" |
9dae56ea A |
35 | #include "JSLock.h" |
36 | #include "JSObjectRef.h" | |
37 | #include "JSString.h" | |
b37bf2e1 | 38 | #include "JSStringRef.h" |
9dae56ea | 39 | #include "OpaqueJSString.h" |
b37bf2e1 | 40 | #include "PropertyNameArray.h" |
b37bf2e1 A |
41 | #include <wtf/Vector.h> |
42 | ||
9dae56ea A |
43 | namespace JSC { |
44 | ||
45 | template <class Base> | |
ba379fdc | 46 | inline JSCallbackObject<Base>* JSCallbackObject<Base>::asCallbackObject(JSValue value) |
9dae56ea | 47 | { |
14957cd0 | 48 | ASSERT(asObject(value)->inherits(&s_info)); |
9dae56ea A |
49 | return static_cast<JSCallbackObject*>(asObject(value)); |
50 | } | |
b37bf2e1 A |
51 | |
52 | template <class Base> | |
14957cd0 A |
53 | JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef jsClass, void* data) |
54 | : Base(globalObject, structure) | |
55 | , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(data, jsClass))) | |
b37bf2e1 | 56 | { |
14957cd0 | 57 | ASSERT(Base::inherits(&s_info)); |
b37bf2e1 A |
58 | init(exec); |
59 | } | |
60 | ||
9dae56ea A |
61 | // Global object constructor. |
62 | // FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one. | |
b37bf2e1 | 63 | template <class Base> |
14957cd0 A |
64 | JSCallbackObject<Base>::JSCallbackObject(JSGlobalData& globalData, JSClassRef jsClass, Structure* structure) |
65 | : Base(globalData, structure) | |
66 | , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(0, jsClass))) | |
b37bf2e1 | 67 | { |
14957cd0 | 68 | ASSERT(Base::inherits(&s_info)); |
b37bf2e1 A |
69 | ASSERT(Base::isGlobalObject()); |
70 | init(static_cast<JSGlobalObject*>(this)->globalExec()); | |
71 | } | |
72 | ||
73 | template <class Base> | |
74 | void JSCallbackObject<Base>::init(ExecState* exec) | |
75 | { | |
76 | ASSERT(exec); | |
77 | ||
78 | Vector<JSObjectInitializeCallback, 16> initRoutines; | |
9dae56ea | 79 | JSClassRef jsClass = classRef(); |
b37bf2e1 A |
80 | do { |
81 | if (JSObjectInitializeCallback initialize = jsClass->initialize) | |
82 | initRoutines.append(initialize); | |
83 | } while ((jsClass = jsClass->parentClass)); | |
84 | ||
85 | // initialize from base to derived | |
86 | for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) { | |
f9bf01c6 | 87 | APICallbackShim callbackShim(exec); |
b37bf2e1 A |
88 | JSObjectInitializeCallback initialize = initRoutines[i]; |
89 | initialize(toRef(exec), toRef(this)); | |
90 | } | |
b37bf2e1 | 91 | |
14957cd0 A |
92 | bool needsFinalizer = false; |
93 | for (JSClassRef jsClassPtr = classRef(); jsClassPtr && !needsFinalizer; jsClassPtr = jsClassPtr->parentClass) | |
94 | needsFinalizer = jsClassPtr->finalize; | |
95 | if (needsFinalizer) { | |
96 | HandleSlot slot = exec->globalData().allocateGlobalHandle(); | |
97 | HandleHeap::heapFor(slot)->makeWeak(slot, m_callbackObjectData.get(), classRef()); | |
98 | HandleHeap::heapFor(slot)->writeBarrier(slot, this); | |
99 | *slot = this; | |
100 | } | |
b37bf2e1 A |
101 | } |
102 | ||
103 | template <class Base> | |
104 | UString JSCallbackObject<Base>::className() const | |
105 | { | |
9dae56ea | 106 | UString thisClassName = classRef()->className(); |
ba379fdc | 107 | if (!thisClassName.isEmpty()) |
9dae56ea | 108 | return thisClassName; |
b37bf2e1 A |
109 | |
110 | return Base::className(); | |
111 | } | |
112 | ||
113 | template <class Base> | |
114 | bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | |
115 | { | |
116 | JSContextRef ctx = toRef(exec); | |
117 | JSObjectRef thisRef = toRef(this); | |
9dae56ea | 118 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 119 | |
9dae56ea | 120 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 A |
121 | // optional optimization to bypass getProperty in cases when we only need to know if the property exists |
122 | if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) { | |
9dae56ea A |
123 | if (!propertyNameRef) |
124 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
f9bf01c6 | 125 | APICallbackShim callbackShim(exec); |
9dae56ea | 126 | if (hasProperty(ctx, thisRef, propertyNameRef.get())) { |
b37bf2e1 A |
127 | slot.setCustom(this, callbackGetter); |
128 | return true; | |
129 | } | |
130 | } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { | |
9dae56ea A |
131 | if (!propertyNameRef) |
132 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
133 | JSValueRef exception = 0; |
134 | JSValueRef value; | |
135 | { | |
f9bf01c6 | 136 | APICallbackShim callbackShim(exec); |
ba379fdc A |
137 | value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); |
138 | } | |
ba379fdc | 139 | if (exception) { |
14957cd0 | 140 | throwError(exec, toJS(exec, exception)); |
ba379fdc | 141 | slot.setValue(jsUndefined()); |
b37bf2e1 A |
142 | return true; |
143 | } | |
f9bf01c6 A |
144 | if (value) { |
145 | slot.setValue(toJS(exec, value)); | |
146 | return true; | |
147 | } | |
b37bf2e1 A |
148 | } |
149 | ||
9dae56ea | 150 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
14957cd0 A |
151 | if (staticValues->contains(propertyName.impl())) { |
152 | JSValue value = getStaticValue(exec, propertyName); | |
153 | if (value) { | |
154 | slot.setValue(value); | |
155 | return true; | |
156 | } | |
b37bf2e1 A |
157 | } |
158 | } | |
159 | ||
9dae56ea | 160 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
14957cd0 | 161 | if (staticFunctions->contains(propertyName.impl())) { |
b37bf2e1 A |
162 | slot.setCustom(this, staticFunctionGetter); |
163 | return true; | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
168 | return Base::getOwnPropertySlot(exec, propertyName, slot); | |
169 | } | |
170 | ||
f9bf01c6 A |
171 | template <class Base> |
172 | bool JSCallbackObject<Base>::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) | |
173 | { | |
174 | PropertySlot slot; | |
175 | if (getOwnPropertySlot(exec, propertyName, slot)) { | |
176 | // Ideally we should return an access descriptor, but returning a value descriptor is better than nothing. | |
177 | JSValue value = slot.getValue(exec, propertyName); | |
178 | if (!exec->hadException()) | |
179 | descriptor.setValue(value); | |
180 | // We don't know whether the property is configurable, but assume it is. | |
181 | descriptor.setConfigurable(true); | |
182 | // We don't know whether the property is enumerable (we could call getOwnPropertyNames() to find out), but assume it isn't. | |
183 | descriptor.setEnumerable(false); | |
184 | return true; | |
185 | } | |
186 | ||
187 | return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); | |
188 | } | |
189 | ||
b37bf2e1 | 190 | template <class Base> |
ba379fdc | 191 | void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) |
b37bf2e1 A |
192 | { |
193 | JSContextRef ctx = toRef(exec); | |
194 | JSObjectRef thisRef = toRef(this); | |
9dae56ea | 195 | RefPtr<OpaqueJSString> propertyNameRef; |
ba379fdc | 196 | JSValueRef valueRef = toRef(exec, value); |
b37bf2e1 | 197 | |
9dae56ea | 198 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 199 | if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { |
9dae56ea A |
200 | if (!propertyNameRef) |
201 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
202 | JSValueRef exception = 0; |
203 | bool result; | |
204 | { | |
f9bf01c6 | 205 | APICallbackShim callbackShim(exec); |
ba379fdc A |
206 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); |
207 | } | |
f9bf01c6 | 208 | if (exception) |
14957cd0 | 209 | throwError(exec, toJS(exec, exception)); |
ba379fdc | 210 | if (result || exception) |
b37bf2e1 A |
211 | return; |
212 | } | |
213 | ||
9dae56ea | 214 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
14957cd0 | 215 | if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) { |
b37bf2e1 A |
216 | if (entry->attributes & kJSPropertyAttributeReadOnly) |
217 | return; | |
218 | if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { | |
9dae56ea A |
219 | if (!propertyNameRef) |
220 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
221 | JSValueRef exception = 0; |
222 | bool result; | |
223 | { | |
f9bf01c6 | 224 | APICallbackShim callbackShim(exec); |
ba379fdc A |
225 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); |
226 | } | |
f9bf01c6 | 227 | if (exception) |
14957cd0 | 228 | throwError(exec, toJS(exec, exception)); |
ba379fdc | 229 | if (result || exception) |
b37bf2e1 | 230 | return; |
14957cd0 | 231 | } |
b37bf2e1 A |
232 | } |
233 | } | |
234 | ||
9dae56ea | 235 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
14957cd0 | 236 | if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { |
b37bf2e1 A |
237 | if (entry->attributes & kJSPropertyAttributeReadOnly) |
238 | return; | |
14957cd0 | 239 | JSCallbackObject<Base>::putDirect(exec->globalData(), 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 | 265 | if (exception) |
14957cd0 | 266 | throwError(exec, toJS(exec, exception)); |
ba379fdc | 267 | if (result || exception) |
b37bf2e1 A |
268 | return true; |
269 | } | |
270 | ||
9dae56ea | 271 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
14957cd0 | 272 | if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) { |
b37bf2e1 A |
273 | if (entry->attributes & kJSPropertyAttributeDontDelete) |
274 | return false; | |
275 | return true; | |
276 | } | |
277 | } | |
278 | ||
9dae56ea | 279 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
14957cd0 | 280 | if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { |
b37bf2e1 A |
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> | |
14957cd0 | 310 | EncodedJSValue JSCallbackObject<Base>::construct(ExecState* exec) |
b37bf2e1 | 311 | { |
14957cd0 | 312 | JSObject* constructor = exec->callee(); |
b37bf2e1 | 313 | JSContextRef execRef = toRef(exec); |
9dae56ea | 314 | JSObjectRef constructorRef = toRef(constructor); |
b37bf2e1 | 315 | |
9dae56ea | 316 | for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 317 | if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) { |
14957cd0 | 318 | int argumentCount = static_cast<int>(exec->argumentCount()); |
b37bf2e1 A |
319 | Vector<JSValueRef, 16> arguments(argumentCount); |
320 | for (int i = 0; i < argumentCount; i++) | |
14957cd0 | 321 | arguments[i] = toRef(exec, exec->argument(i)); |
ba379fdc A |
322 | JSValueRef exception = 0; |
323 | JSObject* result; | |
324 | { | |
f9bf01c6 | 325 | APICallbackShim callbackShim(exec); |
ba379fdc A |
326 | result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception)); |
327 | } | |
f9bf01c6 | 328 | if (exception) |
14957cd0 A |
329 | throwError(exec, toJS(exec, exception)); |
330 | return JSValue::encode(result); | |
b37bf2e1 A |
331 | } |
332 | } | |
333 | ||
9dae56ea | 334 | ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here |
14957cd0 | 335 | return JSValue::encode(JSValue()); |
b37bf2e1 A |
336 | } |
337 | ||
338 | template <class Base> | |
ba379fdc | 339 | bool JSCallbackObject<Base>::hasInstance(ExecState* exec, JSValue value, JSValue) |
b37bf2e1 A |
340 | { |
341 | JSContextRef execRef = toRef(exec); | |
342 | JSObjectRef thisRef = toRef(this); | |
343 | ||
9dae56ea | 344 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 345 | if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) { |
ba379fdc A |
346 | JSValueRef valueRef = toRef(exec, value); |
347 | JSValueRef exception = 0; | |
348 | bool result; | |
349 | { | |
f9bf01c6 | 350 | APICallbackShim callbackShim(exec); |
ba379fdc A |
351 | result = hasInstance(execRef, thisRef, valueRef, &exception); |
352 | } | |
f9bf01c6 | 353 | if (exception) |
14957cd0 | 354 | throwError(exec, toJS(exec, exception)); |
ba379fdc | 355 | return result; |
b37bf2e1 | 356 | } |
9dae56ea A |
357 | } |
358 | return false; | |
b37bf2e1 A |
359 | } |
360 | ||
b37bf2e1 | 361 | template <class Base> |
9dae56ea | 362 | CallType JSCallbackObject<Base>::getCallData(CallData& callData) |
b37bf2e1 | 363 | { |
9dae56ea A |
364 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
365 | if (jsClass->callAsFunction) { | |
366 | callData.native.function = call; | |
367 | return CallTypeHost; | |
368 | } | |
369 | } | |
370 | return CallTypeNone; | |
b37bf2e1 A |
371 | } |
372 | ||
373 | template <class Base> | |
14957cd0 | 374 | EncodedJSValue JSCallbackObject<Base>::call(ExecState* exec) |
b37bf2e1 A |
375 | { |
376 | JSContextRef execRef = toRef(exec); | |
14957cd0 A |
377 | JSObjectRef functionRef = toRef(exec->callee()); |
378 | JSObjectRef thisObjRef = toRef(exec->hostThisValue().toThisObject(exec)); | |
b37bf2e1 | 379 | |
14957cd0 | 380 | for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(toJS(functionRef))->classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 381 | if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) { |
14957cd0 | 382 | int argumentCount = static_cast<int>(exec->argumentCount()); |
b37bf2e1 A |
383 | Vector<JSValueRef, 16> arguments(argumentCount); |
384 | for (int i = 0; i < argumentCount; i++) | |
14957cd0 | 385 | arguments[i] = toRef(exec, exec->argument(i)); |
ba379fdc A |
386 | JSValueRef exception = 0; |
387 | JSValue result; | |
388 | { | |
f9bf01c6 | 389 | APICallbackShim callbackShim(exec); |
ba379fdc A |
390 | result = toJS(exec, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception)); |
391 | } | |
f9bf01c6 | 392 | if (exception) |
14957cd0 A |
393 | throwError(exec, toJS(exec, exception)); |
394 | return JSValue::encode(result); | |
b37bf2e1 A |
395 | } |
396 | } | |
397 | ||
9dae56ea | 398 | ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here |
14957cd0 | 399 | return JSValue::encode(JSValue()); |
b37bf2e1 A |
400 | } |
401 | ||
402 | template <class Base> | |
f9bf01c6 | 403 | void JSCallbackObject<Base>::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) |
b37bf2e1 A |
404 | { |
405 | JSContextRef execRef = toRef(exec); | |
406 | JSObjectRef thisRef = toRef(this); | |
407 | ||
9dae56ea | 408 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
b37bf2e1 | 409 | if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) { |
f9bf01c6 | 410 | APICallbackShim callbackShim(exec); |
b37bf2e1 A |
411 | getPropertyNames(execRef, thisRef, toRef(&propertyNames)); |
412 | } | |
413 | ||
9dae56ea A |
414 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
415 | typedef OpaqueJSClassStaticValuesTable::const_iterator iterator; | |
b37bf2e1 A |
416 | iterator end = staticValues->end(); |
417 | for (iterator it = staticValues->begin(); it != end; ++it) { | |
14957cd0 | 418 | StringImpl* name = it->first.get(); |
b37bf2e1 | 419 | StaticValueEntry* entry = it->second; |
f9bf01c6 | 420 | if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))) |
9dae56ea | 421 | propertyNames.add(Identifier(exec, name)); |
b37bf2e1 A |
422 | } |
423 | } | |
424 | ||
9dae56ea A |
425 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
426 | typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator; | |
b37bf2e1 A |
427 | iterator end = staticFunctions->end(); |
428 | for (iterator it = staticFunctions->begin(); it != end; ++it) { | |
14957cd0 | 429 | StringImpl* name = it->first.get(); |
b37bf2e1 | 430 | StaticFunctionEntry* entry = it->second; |
f9bf01c6 | 431 | if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)) |
9dae56ea | 432 | propertyNames.add(Identifier(exec, name)); |
b37bf2e1 A |
433 | } |
434 | } | |
435 | } | |
436 | ||
f9bf01c6 | 437 | Base::getOwnPropertyNames(exec, propertyNames, mode); |
b37bf2e1 A |
438 | } |
439 | ||
440 | template <class Base> | |
441 | double JSCallbackObject<Base>::toNumber(ExecState* exec) const | |
442 | { | |
9dae56ea A |
443 | // We need this check to guard against the case where this object is rhs of |
444 | // a binary expression where lhs threw an exception in its conversion to | |
445 | // primitive | |
446 | if (exec->hadException()) | |
447 | return NaN; | |
b37bf2e1 A |
448 | JSContextRef ctx = toRef(exec); |
449 | JSObjectRef thisRef = toRef(this); | |
450 | ||
9dae56ea | 451 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
b37bf2e1 | 452 | if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { |
ba379fdc A |
453 | JSValueRef exception = 0; |
454 | JSValueRef value; | |
455 | { | |
f9bf01c6 | 456 | APICallbackShim callbackShim(exec); |
ba379fdc | 457 | value = convertToType(ctx, thisRef, kJSTypeNumber, &exception); |
9dae56ea | 458 | } |
ba379fdc | 459 | if (exception) { |
14957cd0 | 460 | throwError(exec, toJS(exec, exception)); |
ba379fdc A |
461 | return 0; |
462 | } | |
463 | ||
464 | double dValue; | |
f9bf01c6 A |
465 | if (value) |
466 | return toJS(exec, value).getNumber(dValue) ? dValue : NaN; | |
b37bf2e1 A |
467 | } |
468 | ||
469 | return Base::toNumber(exec); | |
470 | } | |
471 | ||
472 | template <class Base> | |
473 | UString JSCallbackObject<Base>::toString(ExecState* exec) const | |
474 | { | |
475 | JSContextRef ctx = toRef(exec); | |
476 | JSObjectRef thisRef = toRef(this); | |
477 | ||
9dae56ea | 478 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
b37bf2e1 | 479 | if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { |
ba379fdc | 480 | JSValueRef exception = 0; |
9dae56ea A |
481 | JSValueRef value; |
482 | { | |
f9bf01c6 | 483 | APICallbackShim callbackShim(exec); |
ba379fdc | 484 | value = convertToType(ctx, thisRef, kJSTypeString, &exception); |
9dae56ea | 485 | } |
ba379fdc | 486 | if (exception) { |
14957cd0 | 487 | throwError(exec, toJS(exec, exception)); |
ba379fdc A |
488 | return ""; |
489 | } | |
f9bf01c6 A |
490 | if (value) |
491 | return toJS(exec, value).getString(exec); | |
b37bf2e1 A |
492 | } |
493 | ||
494 | return Base::toString(exec); | |
495 | } | |
496 | ||
497 | template <class Base> | |
498 | void JSCallbackObject<Base>::setPrivate(void* data) | |
499 | { | |
9dae56ea | 500 | m_callbackObjectData->privateData = data; |
b37bf2e1 A |
501 | } |
502 | ||
503 | template <class Base> | |
504 | void* JSCallbackObject<Base>::getPrivate() | |
505 | { | |
9dae56ea | 506 | return m_callbackObjectData->privateData; |
b37bf2e1 A |
507 | } |
508 | ||
509 | template <class Base> | |
510 | bool JSCallbackObject<Base>::inherits(JSClassRef c) const | |
511 | { | |
9dae56ea | 512 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
b37bf2e1 A |
513 | if (jsClass == c) |
514 | return true; | |
515 | ||
516 | return false; | |
517 | } | |
518 | ||
519 | template <class Base> | |
14957cd0 | 520 | JSValue JSCallbackObject<Base>::getStaticValue(ExecState* exec, const Identifier& propertyName) |
b37bf2e1 | 521 | { |
14957cd0 | 522 | JSObjectRef thisRef = toRef(this); |
9dae56ea | 523 | RefPtr<OpaqueJSString> propertyNameRef; |
b37bf2e1 | 524 | |
14957cd0 | 525 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
9dae56ea | 526 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) |
14957cd0 | 527 | if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) |
b37bf2e1 | 528 | if (JSObjectGetPropertyCallback getProperty = entry->getProperty) { |
9dae56ea A |
529 | if (!propertyNameRef) |
530 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); | |
ba379fdc A |
531 | JSValueRef exception = 0; |
532 | JSValueRef value; | |
533 | { | |
f9bf01c6 | 534 | APICallbackShim callbackShim(exec); |
ba379fdc A |
535 | value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); |
536 | } | |
f9bf01c6 | 537 | if (exception) { |
14957cd0 | 538 | throwError(exec, toJS(exec, exception)); |
f9bf01c6 A |
539 | return jsUndefined(); |
540 | } | |
ba379fdc A |
541 | if (value) |
542 | return toJS(exec, value); | |
b37bf2e1 | 543 | } |
f9bf01c6 | 544 | |
14957cd0 | 545 | return JSValue(); |
b37bf2e1 A |
546 | } |
547 | ||
548 | template <class Base> | |
4e4e5a6f | 549 | JSValue JSCallbackObject<Base>::staticFunctionGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) |
b37bf2e1 | 550 | { |
4e4e5a6f | 551 | JSCallbackObject* thisObj = asCallbackObject(slotBase); |
b37bf2e1 A |
552 | |
553 | // Check for cached or override property. | |
9dae56ea | 554 | PropertySlot slot2(thisObj); |
b37bf2e1 | 555 | if (thisObj->Base::getOwnPropertySlot(exec, propertyName, slot2)) |
9dae56ea | 556 | return slot2.getValue(exec, propertyName); |
b37bf2e1 | 557 | |
9dae56ea A |
558 | for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { |
559 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { | |
14957cd0 | 560 | if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { |
b37bf2e1 | 561 | if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) { |
14957cd0 A |
562 | |
563 | JSObject* o = new (exec) JSCallbackFunction(exec, asGlobalObject(thisObj->getAnonymousValue(0)), callAsFunction, propertyName); | |
564 | thisObj->putDirect(exec->globalData(), propertyName, o, entry->attributes); | |
b37bf2e1 A |
565 | return o; |
566 | } | |
567 | } | |
568 | } | |
569 | } | |
570 | ||
14957cd0 | 571 | return throwError(exec, createReferenceError(exec, "Static function property defined with NULL callAsFunction callback.")); |
b37bf2e1 A |
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 | 592 | if (exception) { |
14957cd0 | 593 | throwError(exec, toJS(exec, exception)); |
f9bf01c6 A |
594 | return jsUndefined(); |
595 | } | |
ba379fdc A |
596 | if (value) |
597 | return toJS(exec, value); | |
b37bf2e1 A |
598 | } |
599 | ||
14957cd0 | 600 | return throwError(exec, createReferenceError(exec, "hasProperty callback returned true for a property that doesn't exist.")); |
b37bf2e1 A |
601 | } |
602 | ||
9dae56ea | 603 | } // namespace JSC |