source: webkit/trunk/JavaScriptCore/API/JSCallbackObject.cpp@ 15444

Last change on this file since 15444 was 15444, checked in by ggaren, 19 years ago

RS by Maciej.


Global replace in the API of argc/argv with argumentCount/arguments.

File size: 16.4 KB
Line 
1// -*- mode: c++; c-basic-offset: 4 -*-
2/*
3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
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
27#include "APICast.h"
28#include "JSCallbackObject.h"
29#include "JSStringRef.h"
30#include "JSClassRef.h"
31#include "JSObjectRef.h"
32#include "internal.h"
33#include "reference.h"
34#include "reference_list.h"
35
36namespace KJS {
37
38const ClassInfo JSCallbackObject::info = { "CallbackObject", 0, 0, 0 };
39
40JSCallbackObject::JSCallbackObject(JSContextRef context, JSClassRef jsClass)
41 : JSObject()
42{
43 init(context, jsClass);
44}
45
46JSCallbackObject::JSCallbackObject(JSContextRef context, JSClassRef jsClass, JSValue* prototype)
47 : JSObject(prototype)
48{
49 init(context, jsClass);
50}
51
52void JSCallbackObject::init(JSContextRef context, JSClassRef jsClass)
53{
54 ExecState* exec = toJS(context);
55
56 m_privateData = 0;
57 m_class = JSClassRetain(jsClass);
58
59 JSObjectRef thisRef = toRef(this);
60
61 do {
62 if (JSObjectInitializeCallback initialize = jsClass->callbacks.initialize)
63 initialize(context, thisRef, toRef(exec->exceptionSlot()));
64 } while ((jsClass = jsClass->parent));
65}
66
67JSCallbackObject::~JSCallbackObject()
68{
69 JSObjectRef thisRef = toRef(this);
70
71 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
72 if (JSObjectFinalizeCallback finalize = jsClass->callbacks.finalize)
73 finalize(thisRef);
74
75 JSClassRelease(m_class);
76}
77
78UString JSCallbackObject::className() const
79{
80 return classInfo()->className;
81}
82
83bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
84{
85 JSContextRef context = toRef(exec);
86 JSObjectRef thisRef = toRef(this);
87 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
88
89 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
90 // optional optimization to bypass getProperty in cases when we only need to know if the property exists
91 if (JSObjectHasPropertyCallback hasProperty = jsClass->callbacks.hasProperty) {
92 if (hasProperty(context, thisRef, propertyNameRef)) {
93 slot.setCustom(this, callbackGetter);
94 return true;
95 }
96 } else if (JSObjectGetPropertyCallback getProperty = jsClass->callbacks.getProperty) {
97 if (JSValueRef value = getProperty(context, thisRef, propertyNameRef, toRef(exec->exceptionSlot()))) {
98 // cache the value so we don't have to compute it again
99 // FIXME: This violates the PropertySlot design a little bit.
100 // We should either use this optimization everywhere, or nowhere.
101 slot.setCustom(reinterpret_cast<JSObject*>(toJS(value)), cachedValueGetter);
102 return true;
103 }
104 }
105
106 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
107 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
108 if (entry->getProperty) {
109 slot.setCustom(this, staticValueGetter);
110 return true;
111 }
112 }
113 }
114
115 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
116 if (staticFunctions->contains(propertyName.ustring().rep())) {
117 slot.setCustom(this, staticFunctionGetter);
118 return true;
119 }
120 }
121 }
122
123 return JSObject::getOwnPropertySlot(exec, propertyName, slot);
124}
125
126bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
127{
128 return getOwnPropertySlot(exec, Identifier::from(propertyName), slot);
129}
130
131void JSCallbackObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
132{
133 JSContextRef context = toRef(exec);
134 JSObjectRef thisRef = toRef(this);
135 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
136 JSValueRef valueRef = toRef(value);
137
138 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
139 if (JSObjectSetPropertyCallback setProperty = jsClass->callbacks.setProperty) {
140 if (setProperty(context, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
141 return;
142 }
143
144 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
145 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
146 if (entry->attributes & kJSPropertyAttributeReadOnly)
147 return;
148 if (JSObjectSetPropertyCallback setProperty = entry->setProperty) {
149 if (setProperty(context, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
150 return;
151 }
152 }
153 }
154
155 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
156 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
157 if (entry->attributes & kJSPropertyAttributeReadOnly)
158 return;
159 putDirect(propertyName, value, attr); // put as override property
160 return;
161 }
162 }
163 }
164
165 return JSObject::put(exec, propertyName, value, attr);
166}
167
168void JSCallbackObject::put(ExecState* exec, unsigned propertyName, JSValue* value, int attr)
169{
170 return put(exec, Identifier::from(propertyName), value, attr);
171}
172
173bool JSCallbackObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
174{
175 JSContextRef context = toRef(exec);
176 JSObjectRef thisRef = toRef(this);
177 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
178
179 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
180 if (JSObjectDeletePropertyCallback deleteProperty = jsClass->callbacks.deleteProperty) {
181 if (deleteProperty(context, thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
182 return true;
183 }
184
185 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
186 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
187 if (entry->attributes & kJSPropertyAttributeDontDelete)
188 return false;
189 return true;
190 }
191 }
192
193 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
194 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
195 if (entry->attributes & kJSPropertyAttributeDontDelete)
196 return false;
197 return true;
198 }
199 }
200 }
201
202 return JSObject::deleteProperty(exec, propertyName);
203}
204
205bool JSCallbackObject::deleteProperty(ExecState* exec, unsigned propertyName)
206{
207 return deleteProperty(exec, Identifier::from(propertyName));
208}
209
210bool JSCallbackObject::implementsConstruct() const
211{
212 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
213 if (jsClass->callbacks.callAsConstructor)
214 return true;
215
216 return false;
217}
218
219JSObject* JSCallbackObject::construct(ExecState* exec, const List& args)
220{
221 JSContextRef execRef = toRef(exec);
222 JSObjectRef thisRef = toRef(this);
223
224 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
225 if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callbacks.callAsConstructor) {
226 size_t argumentCount = args.size();
227 JSValueRef arguments[argumentCount];
228 for (size_t i = 0; i < argumentCount; i++)
229 arguments[i] = toRef(args[i]);
230 return toJS(callAsConstructor(execRef, thisRef, argumentCount, arguments, toRef(exec->exceptionSlot())));
231 }
232 }
233
234 ASSERT(0); // implementsConstruct should prevent us from reaching here
235 return 0;
236}
237
238bool JSCallbackObject::implementsHasInstance() const
239{
240 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
241 if (jsClass->callbacks.hasInstance)
242 return true;
243
244 return false;
245}
246
247bool JSCallbackObject::hasInstance(ExecState *exec, JSValue *value)
248{
249 JSContextRef execRef = toRef(exec);
250 JSObjectRef thisRef = toRef(this);
251
252 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
253 if (JSObjectHasInstanceCallback hasInstance = jsClass->callbacks.hasInstance)
254 return hasInstance(execRef, thisRef, toRef(value), toRef(exec->exceptionSlot()));
255
256 ASSERT(0); // implementsHasInstance should prevent us from reaching here
257 return 0;
258}
259
260
261bool JSCallbackObject::implementsCall() const
262{
263 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
264 if (jsClass->callbacks.callAsFunction)
265 return true;
266
267 return false;
268}
269
270JSValue* JSCallbackObject::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
271{
272 JSContextRef execRef = toRef(exec);
273 JSObjectRef thisRef = toRef(this);
274 JSObjectRef thisObjRef = toRef(thisObj);
275
276 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
277 if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callbacks.callAsFunction) {
278 size_t argumentCount = args.size();
279 JSValueRef arguments[argumentCount];
280 for (size_t i = 0; i < argumentCount; i++)
281 arguments[i] = toRef(args[i]);
282 return toJS(callAsFunction(execRef, thisRef, thisObjRef, argumentCount, arguments, toRef(exec->exceptionSlot())));
283 }
284 }
285
286 ASSERT(0); // implementsCall should prevent us from reaching here
287 return 0;
288}
289
290void JSCallbackObject::getPropertyList(ReferenceList& propertyList, bool recursive)
291{
292 JSObjectRef thisRef = toRef(this);
293
294 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
295 if (JSObjectAddPropertiesToListCallback addPropertiesToList = jsClass->callbacks.addPropertiesToList)
296 addPropertiesToList(thisRef, toRef(&propertyList));
297
298 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
299 typedef __JSClass::StaticValuesTable::const_iterator iterator;
300 iterator end = staticValues->end();
301 for (iterator it = staticValues->begin(); it != end; ++it) {
302 UString::Rep* name = it->first.get();
303 StaticValueEntry* entry = it->second;
304 if (entry->getProperty && !(entry->attributes & kJSPropertyAttributeDontEnum))
305 propertyList.append(Reference(this, Identifier(name)));
306 }
307 }
308
309 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
310 typedef __JSClass::StaticFunctionsTable::const_iterator iterator;
311 iterator end = staticFunctions->end();
312 for (iterator it = staticFunctions->begin(); it != end; ++it) {
313 UString::Rep* name = it->first.get();
314 StaticFunctionEntry* entry = it->second;
315 if (!(entry->attributes & kJSPropertyAttributeDontEnum))
316 propertyList.append(Reference(this, Identifier(name)));
317 }
318 }
319 }
320
321 JSObject::getPropertyList(propertyList, recursive);
322}
323
324double JSCallbackObject::toNumber(ExecState* exec) const
325{
326 JSContextRef context = toRef(exec);
327 JSObjectRef thisRef = toRef(this);
328
329 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
330 if (JSObjectConvertToTypeCallback convertToType = jsClass->callbacks.convertToType)
331 if (JSValueRef value = convertToType(context, thisRef, kJSTypeNumber, toRef(exec->exceptionSlot())))
332 return toJS(value)->getNumber();
333
334 return JSObject::toNumber(exec);
335}
336
337UString JSCallbackObject::toString(ExecState* exec) const
338{
339 JSContextRef context = toRef(exec);
340 JSObjectRef thisRef = toRef(this);
341
342 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
343 if (JSObjectConvertToTypeCallback convertToType = jsClass->callbacks.convertToType)
344 if (JSValueRef value = convertToType(context, thisRef, kJSTypeString, toRef(exec->exceptionSlot())))
345 return toJS(value)->getString();
346
347 return JSObject::toString(exec);
348}
349
350void JSCallbackObject::setPrivate(void* data)
351{
352 m_privateData = data;
353}
354
355void* JSCallbackObject::getPrivate()
356{
357 return m_privateData;
358}
359
360bool JSCallbackObject::inherits(JSClassRef c) const
361{
362 for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
363 if (jsClass == c)
364 return true;
365
366 return false;
367}
368
369JSValue* JSCallbackObject::cachedValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
370{
371 JSValue* v = slot.slotBase();
372 ASSERT(v);
373 return v;
374}
375
376JSValue* JSCallbackObject::staticValueGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
377{
378 ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
379 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
380
381 JSObjectRef thisRef = toRef(thisObj);
382 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
383
384 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent)
385 if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues)
386 if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep()))
387 if (JSObjectGetPropertyCallback getProperty = entry->getProperty)
388 if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
389 return toJS(value);
390
391 return jsUndefined();
392}
393
394JSValue* JSCallbackObject::staticFunctionGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
395{
396 ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
397 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
398
399 if (JSValue* cachedOrOverrideValue = thisObj->getDirect(propertyName))
400 return cachedOrOverrideValue;
401
402 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent) {
403 if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
404 if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
405 JSValue* v = toJS(JSObjectMakeFunction(toRef(exec), entry->callAsFunction));
406 thisObj->putDirect(propertyName, v, entry->attributes);
407 return v;
408 }
409 }
410 }
411
412 return jsUndefined();
413}
414
415JSValue* JSCallbackObject::callbackGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
416{
417 ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
418 JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
419
420 JSObjectRef thisRef = toRef(thisObj);
421 JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
422
423 for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent)
424 if (JSObjectGetPropertyCallback getProperty = jsClass->callbacks.getProperty)
425 if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
426 return toJS(value);
427
428 return jsUndefined();
429}
430
431} // namespace KJS
Note: See TracBrowser for help on using the repository browser.