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

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

Reviewed by Maciej.


More API action.


  • Headerdoc finished

Semantic Changes:

  • Added a JSContextRef argument to many functions, because you need a JSContextRef for doing virtually anything. I expect to add this argument to even more functions in a future patch.


  • Removed the globalObjectPrototype argument to JSContextCreate because you can't create an object until you have a context, so it's impossible to pass a prototype object to JSContextCreate. That's OK because (1) there's no reason to give the global object a prototype and (2) if you really want to, you can just use a separate call to JSObjectSetPrototype.


  • Removed the JSClassRef argument to JSClassCreate because it was unnecessary, and you need to be able to make the global object's class before you've created a JSContext.


  • Added an optional exception parameter to JSFunctionMakeWithBody because anything less would be uncivilized.


  • Made the return value parameter to JSObjectGetProperty optional to match all other return value parameters in the API.


  • Made JSObjectSetPrivate/JSObjectGetPrivate work on JSCallbackFunctions and JSCallbackConstructors. You could use an abstract base class or strategic placement of m_privateData in the class structure to implement this, but the former seemed like overkill, and the latter seemed too dangerous.


  • Fixed a bug where JSPropertyEnumeratorGetNext would skip the first property.

Cosmetic Changes:

  • Reversed the logic of the JSChar #ifdef to avoid confusing headerdoc


  • Removed function names from @function declarations because headeroc can parse them automatically, and I wanted to rule out manual mismatch.
  • Changed Error::create to take a const UString& instead of a UString* because it was looking at me funny.


  • Renamed JSStringBufferCreateWithCFString to JSStringBufferCreateCF because the latter is more concise and it matches JSStringBufferCreateUTF8.


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