fix logic
[personal-kdelibs.git] / khtml / ecma / kjs_binding.h
blobbb490aaab75e679ca1a24f0255eb7a31bbd5b8fb
1 // -*- c-basic-offset: 2 -*-
2 /*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
5 * Copyright (C) 2003 Apple Computer, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #ifndef _KJS_BINDING_H_
23 #define _KJS_BINDING_H_
25 #include <khtml_export.h>
26 #include <kjs/interpreter.h>
27 #include <kjs/global.h>
28 #include <wtf/HashMap.h>
30 #include <dom/dom_node.h>
31 #include <QtCore/QVariant>
32 #include <QtCore/QHash>
33 #include <QtCore/QString>
34 #include <kurl.h>
35 #include <kjs/lookup.h>
36 #include <kjs/function.h>
37 #include <kjs/JSVariableObject.h>
39 #include <stdlib.h> // for abort
41 #define KJS_CHECK_THIS( ClassName, theObj ) \
42 if (!theObj || !theObj->inherits(&ClassName::info)) { \
43 KJS::UString errMsg = "Attempt at calling a function that expects a "; \
44 errMsg += ClassName::info.className; \
45 errMsg += " on a "; \
46 errMsg += theObj->className(); \
47 KJS::JSObject *err = KJS::Error::create(exec, KJS::TypeError, errMsg.ascii()); \
48 exec->setException(err); \
49 return err; \
52 namespace KParts {
53 class ReadOnlyPart;
54 class LiveConnectExtension;
57 namespace khtml {
58 class ChildFrame;
61 namespace KJS {
63 /**
64 * Base class for all objects in this binding. Doesn't manage exceptions any more
66 class DOMObject : public JSObject {
67 protected:
68 DOMObject() : JSObject() {}
69 DOMObject(JSObject *proto) : JSObject(proto) {}
70 public:
71 bool shouldMark() const { return !_prop.isEmpty(); }
72 virtual UString toString(ExecState *exec) const;
75 /**
76 * We inherit from Interpreter, to save a pointer to the HTML part
77 * that the interpreter runs for.
78 * The interpreter also stores the DOM object - >KJS::DOMObject cache.
80 class ScriptInterpreter : public Interpreter
82 public:
83 ScriptInterpreter( JSGlobalObject *global, khtml::ChildFrame* frame );
84 virtual ~ScriptInterpreter();
86 // We need to keep track of wrappers in 2 ways:
87 // - we want the same wrapper for the same node (see #145775)
88 // - we want to drop all the references from this interpreter on clear, so
89 // wrappers don't stick around. Hence we have a global set and a per-interpreter one.
91 // Reuses an existing wrapper, perhaps also updating the current map
92 // to refer to it as well.
93 DOMObject* getDOMObject( void* objectHandle ) {
94 DOMObject* existing = allDomObjects()->get( objectHandle );
95 if (existing)
96 m_domObjects.set(objectHandle, existing );
97 return existing;
100 void putDOMObject( void* objectHandle, DOMObject* obj ) {
101 allDomObjects()->set( objectHandle, obj );
102 m_domObjects.set( objectHandle, obj );
105 static void forgetDOMObject( void* objectHandle );
107 void clear() {
108 m_domObjects.clear(); // Global set will be cleared at GC time.
113 * Mark objects in the DOMObject cache.
115 virtual void mark(bool isMain);
116 KParts::ReadOnlyPart* part() const;
118 virtual int rtti() { return 1; }
121 * Set the event that is triggering the execution of a script, if any
123 void setCurrentEvent( DOM::Event *evt ) { m_evt = evt; }
124 void setInlineCode( bool inlineCode ) { m_inlineCode = inlineCode; }
125 void setProcessingTimerCallback( bool timerCallback ) { m_timerCallback = timerCallback; }
127 * "Smart" window.open policy
129 bool isWindowOpenAllowed() const;
132 * CPU guard API. This should be used instead of Interpreter
133 * methods as it manages the timeouts, including VG support
135 virtual bool shouldInterruptScript() const;
136 void startCPUGuard();
137 void stopCPUGuard();
139 static void turnOffCPUGuard() {
140 s_disableCPUGuard = true;
142 private:
143 khtml::ChildFrame* m_frame;
144 HashMap<void*, DOMObject*> m_domObjects;
145 static HashMap<void*, DOMObject*>* s_allDomObjects;
146 static HashMap<void*, DOMObject*>* allDomObjects() {
147 if (!s_allDomObjects)
148 s_allDomObjects = new HashMap<void*, DOMObject*>();
149 return s_allDomObjects;
152 DOM::Event *m_evt;
153 bool m_inlineCode;
154 bool m_timerCallback;
155 static bool s_disableCPUGuard;
159 A little helper for setting stuff up given an entry
161 template<class FuncImp, class ThisImp>
162 inline void getSlotFromEntry(const HashEntry* entry, ThisImp* thisObj, PropertySlot& slot)
164 if (entry->attr & Function)
165 slot.setStaticEntry(thisObj, entry, staticFunctionGetter<FuncImp>);
166 else
167 slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
172 Like getStaticPropertySlot but doesn't check the parent. Handy when there
173 are both functions and values
175 template <class FuncImp, class ThisImp>
176 inline bool getStaticOwnPropertySlot(const HashTable* table,
177 ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
179 const HashEntry* entry = Lookup::findEntry(table, propertyName);
181 if (!entry) // not found, forward to parent
182 return false;
184 if (entry->attr & Function)
185 slot.setStaticEntry(thisObj, entry, staticFunctionGetter<FuncImp>);
186 else
187 slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
189 return true;
193 Handler for local table-looked up things.
195 template<class ThisImp>
196 inline bool getStaticOwnValueSlot(const HashTable* table,
197 ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
199 const HashEntry* entry = Lookup::findEntry(table, propertyName);
200 if (!entry)
201 return false;
203 assert(!(entry->attr & Function));
204 slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
205 return true;
208 /* Helper for the below*/
209 template<class JSTypeImp>
210 JSValue *indexGetterAdapter(ExecState* exec, JSObject*, const Identifier& , const PropertySlot& slot)
212 JSTypeImp *thisObj = static_cast<JSTypeImp*>(slot.slotBase());
213 return thisObj->indexGetter(exec, slot.index());
217 Handler for index properties. Will call "length" method on the listObj
218 to determine whether it's in range, and arrange to have indexGetter called
220 template<class ThisImp, class BaseObj>
221 inline bool getIndexSlot(ThisImp* thisObj, const BaseObj& listObj,
222 const Identifier& propertyName, PropertySlot& slot)
224 bool ok;
225 unsigned u = propertyName.toUInt32(&ok);
226 if (ok && u < listObj.length()) {
227 slot.setCustomIndex(thisObj, u, indexGetterAdapter<ThisImp>);
228 return true;
230 return false;
234 Version that takes an external bound
236 template<class ThisImp>
237 inline bool getIndexSlot(ThisImp* thisObj, unsigned lengthLimit,
238 const Identifier& propertyName, PropertySlot& slot)
240 bool ok;
241 unsigned u = propertyName.toUInt32(&ok);
242 if (ok && u < lengthLimit) {
243 slot.setCustomIndex(thisObj, u, indexGetterAdapter<ThisImp>);
244 return true;
246 return false;
249 template<class ThisImp>
250 inline bool getIndexSlot(ThisImp* thisObj, int lengthLimit,
251 const Identifier& propertyName, PropertySlot& slot)
253 return getIndexSlot(thisObj, (unsigned)lengthLimit, propertyName, slot);
257 Version w/o the bounds check
259 template<class ThisImp>
260 inline bool getIndexSlot(ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
262 bool ok;
263 unsigned u = propertyName.toUInt32(&ok);
264 if (ok) {
265 slot.setCustomIndex(thisObj, u, indexGetterAdapter<ThisImp>);
266 return true;
268 return false;
271 /* Helper for below */
272 JSValue* valueGetterAdapter(ExecState* exec, JSObject*, const Identifier& , const PropertySlot& slot);
275 This sets up the slot to return a particular JSValue*; unlike
276 setValueSlot, it does not require there to be a location to point at
278 inline bool getImmediateValueSlot(JSObject* thisObj, JSValue* value, PropertySlot& slot) {
279 slot.setCustomValue(thisObj, value, valueGetterAdapter);
280 return true;
284 * Retrieve from cache, or create, a KJS object around a DOM object
286 template<class DOMObj, class KJSDOMObj>
287 inline JSValue* cacheDOMObject(ExecState *exec, DOMObj* domObj)
289 DOMObject *ret;
290 if (!domObj)
291 return jsNull();
292 ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
293 if ((ret = interp->getDOMObject(domObj)))
294 return ret;
295 else {
296 ret = new KJSDOMObj(exec, domObj);
297 interp->putDOMObject(domObj,ret);
298 return ret;
303 * Convert an object to a Node. Returns 0 if not possible.
305 DOM::NodeImpl* toNode(JSValue*);
307 * Get a String object, or Null() if s is null
309 JSValue* getStringOrNull(DOM::DOMString s);
312 * Null string if the value is null
314 DOM::DOMString valueToStringWithNullCheck(ExecState* exec, JSValue* v);
317 * Convert a KJS value into a QVariant
319 QVariant ValueToVariant(ExecState* exec, JSValue* val);
321 // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
322 void setDOMException(ExecState *exec, int DOMExceptionCode);
324 // Helper class to call setDOMException on exit without adding lots of separate calls to that function.
325 class DOMExceptionTranslator {
326 public:
327 explicit DOMExceptionTranslator(ExecState *exec) : m_exec(exec), m_code(0) { }
328 ~DOMExceptionTranslator() { setDOMException(m_exec, m_code); }
329 operator int &() { return m_code; }
330 operator int *() { return &m_code; }
332 bool triggered() {
333 return m_code;
335 private:
336 ExecState *m_exec;
337 int m_code;
340 JSValue* getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id);
342 // convenience function
343 inline JSCell* jsString(const QString& s) { return jsString(UString(s)); }
345 // This is used to create pseudo-constructor objects, like Mozillaish
346 // Element, HTMLDocument, etc., which do not act like real constructors,
347 // but do have the prototype property pointing to prototype of "instances"
348 #define DEFINE_PSEUDO_CONSTRUCTOR(ClassName) \
349 class ClassName : public DOMObject { \
350 public: \
351 ClassName(ExecState *); \
352 virtual const ClassInfo* classInfo() const { return &info; } \
353 static const ClassInfo info; \
354 static JSObject* self(ExecState *exec); \
355 virtual bool implementsHasInstance() const; \
358 #define IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,ParentProto) \
359 const ClassInfo Class::info = { ClassName, 0, 0, 0 }; \
360 Class::Class(ExecState* exec): DOMObject(ParentProto) {\
361 JSObject* proto = ProtoClass::self(exec); \
362 putDirect(exec->propertyNames().prototype, proto, DontDelete|ReadOnly); \
364 JSObject* Class::self(ExecState *exec) { \
365 return cacheGlobalObject<Class>(exec, "[[" ClassName ".constructor]]"); \
367 bool Class::implementsHasInstance() const { \
368 return true; \
371 #define IMPLEMENT_PSEUDO_CONSTRUCTOR(Class,ClassName,ProtoClass) \
372 IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,exec->lexicalInterpreter()->builtinObjectPrototype())
374 #define IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(Class,ClassName,ProtoClass,ParentProtoClass) \
375 IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,ParentProtoClass::self(exec))
377 // This declares a constant table, which merely maps everything in its
378 // table to its token value. Can be used as a prototype
379 #define DEFINE_CONSTANT_TABLE(Class) \
380 class Class : public DOMObject { \
381 public: \
382 Class(ExecState *exec): DOMObject(exec->lexicalInterpreter()->builtinObjectPrototype()) {} \
384 virtual bool getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot);\
385 JSValue* getValueProperty(ExecState *exec, int token) const; \
386 virtual const ClassInfo* classInfo() const { return &info; } \
387 static const ClassInfo info; \
388 static JSObject* self(ExecState *exec);\
389 static Identifier* s_name; \
390 static Identifier* name(); \
393 // Emits an implementation of a constant table
394 #define IMPLEMENT_CONSTANT_TABLE(Class,ClassName) \
395 bool Class::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) \
397 return getStaticValueSlot<Class, DOMObject>(exec, &Class##Table, this, propertyName, slot);\
399 JSValue* Class::getValueProperty(ExecState * /*exec*/, int token) const { \
400 /* We use the token as the value to return directly*/ \
401 return jsNumber((unsigned int)token); \
403 JSObject* Class::self(ExecState *exec) { \
404 return cacheGlobalObject<Class>(exec, *name()); \
406 Identifier* Class::s_name = 0; \
407 Identifier* Class::name() { \
408 if (!s_name) s_name = new Identifier("[[" ClassName ".constant_table]]"); \
409 return s_name; \
411 const ClassInfo Class::info = { ClassName, 0, &Class##Table, 0 };
413 // cacheGlobalObject<> is not in namespace KJS - need to use ::cacheGlobalObject<>
414 #define KJS_EMPTY_PROTOTYPE_IMP(ClassName, ClassProto, ProtoCode) \
415 class ClassProto : public JSObject { \
416 friend JSObject* KJS_CACHEGLOBALOBJECT_NS cacheGlobalObject<ClassProto>(ExecState *exec, const Identifier &propertyName); \
417 public: \
418 static JSObject* self(ExecState *exec) { \
419 return KJS_CACHEGLOBALOBJECT_NS cacheGlobalObject<ClassProto>(exec, *name()); \
421 virtual const ClassInfo *classInfo() const { return &info; } \
422 static const ClassInfo info; \
423 protected: \
424 ClassProto( ExecState *exec ) \
425 : JSObject( ProtoCode ) {} \
427 static Identifier* s_name; \
428 static Identifier* name() { \
429 if (!s_name) s_name = new Identifier("[[" ClassName ".prototype]]"); \
430 return s_name; \
432 }; \
433 Identifier* ClassProto::s_name = 0; \
434 const ClassInfo ClassProto::info = { ClassName, 0, 0, 0 };
436 #define KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE(ClassName, ClassProto, ClassProtoProto) \
437 KJS_EMPTY_PROTOTYPE_IMP(ClassName, ClassProto, ClassProtoProto::self(exec))
440 } // namespace
443 #endif