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

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

Approved by Maciej, RS by Beth.


JSObjectMakeFunction -> JSObjectMakeFunctionWithCallback
JSObjectMakeFunctionWithBody -> JSObjectMakeFunction


because the latter is more common, and more fundamental, than the former.

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