#ifndef _KJS_BINDING_H_
#define _KJS_BINDING_H_
#include <kjs/interpreter.h>
#include <dom/dom_node.h>
#include <dom/dom_doc.h>
#include <qvariant.h>
#include <qptrdict.h>
#include <kurl.h>
#include <kjs/lookup.h>
#include <kjs/protect.h>
#if APPLE_CHANGES
#include <JavaScriptCore/runtime.h>
#endif
class KHTMLPart;
namespace KJS {
class DOMObject : public ObjectImp {
public:
DOMObject(const Object &proto) : ObjectImp(proto) {}
DOMObject() : ObjectImp() {}
virtual Value get(ExecState *exec, const Identifier &propertyName) const;
virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const
{ return ObjectImp::get(exec, propertyName); }
virtual void put(ExecState *exec, const Identifier &propertyName,
const Value &value, int attr = None);
virtual void tryPut(ExecState *exec, const Identifier &propertyName,
const Value& value, int attr = None)
{ ObjectImp::put(exec,propertyName,value,attr); }
virtual UString toString(ExecState *exec) const;
};
class DOMFunction : public ObjectImp {
public:
DOMFunction() : ObjectImp( ) {}
virtual Value get(ExecState *exec, const Identifier &propertyName) const;
virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const
{ return ObjectImp::get(exec, propertyName); }
virtual bool implementsCall() const { return true; }
virtual Value call(ExecState *exec, Object &thisObj, const List &args);
virtual Value tryCall(ExecState *exec, Object &thisObj, const List&args)
{ return ObjectImp::call(exec, thisObj, args); }
virtual bool toBoolean(ExecState *) const { return true; }
virtual Value toPrimitive(ExecState *exec, Type) const { return String(toString(exec)); }
virtual UString toString(ExecState *) const { return UString("[function]"); }
};
class ScriptInterpreter : public Interpreter
{
public:
ScriptInterpreter( const Object &global, KHTMLPart* part );
virtual ~ScriptInterpreter();
static DOMObject* getDOMObject( void* objectHandle ) {
return domObjects()[objectHandle];
}
static void putDOMObject( void* objectHandle, DOMObject* obj ) {
domObjects().insert( objectHandle, obj );
}
static bool deleteDOMObject( void* objectHandle ) {
return domObjects().remove( objectHandle );
}
static DOMObject* getDOMObjectForDocument( DOM::DocumentImpl* documentHandle, void *objectHandle );
static void putDOMObjectForDocument( DOM::DocumentImpl* documentHandle, void *objectHandle, DOMObject *obj );
static bool deleteDOMObjectsForDocument( DOM::DocumentImpl* documentHandle );
static void forgetDOMObject( void* objectHandle );
static void forgetDOMObjectsForDocument( DOM::DocumentImpl* documentHandle );
static void updateDOMObjectDocument(void *objectHandle, DOM::DocumentImpl *oldDoc, DOM::DocumentImpl *newDoc);
KHTMLPart* part() const { return m_part; }
virtual int rtti() { return 1; }
void setCurrentEvent( DOM::Event *evt ) { m_evt = evt; }
void setInlineCode( bool inlineCode ) { m_inlineCode = inlineCode; }
void setProcessingTimerCallback( bool timerCallback ) { m_timerCallback = timerCallback; }
bool wasRunByUserGesture() const;
virtual void mark();
DOM::Event *getCurrentEvent() const { return m_evt; }
#if APPLE_CHANGES
virtual bool isGlobalObject(const Value &v);
virtual Interpreter *interpreterForGlobalObject (const ValueImp *imp);
virtual bool isSafeScript (const Interpreter *target);
virtual void *createLanguageInstanceForValue (ExecState *exec, Bindings::Instance::BindingLanguage language, const Object &value, const Bindings::RootObject *origin, const Bindings::RootObject *current);
void *createObjcInstanceForValue (ExecState *exec, const Object &value, const Bindings::RootObject *origin, const Bindings::RootObject *current);
#endif
private:
KHTMLPart* m_part;
static QPtrDict<DOMObject> &domObjects();
static QPtrDict<QPtrDict<DOMObject> > &domObjectsPerDocument();
DOM::Event *m_evt;
bool m_inlineCode;
bool m_timerCallback;
};
template<class DOMObj, class KJSDOMObj>
inline Value cacheDOMObject(ExecState *exec, DOMObj domObj)
{
DOMObject *ret;
if (domObj.isNull())
return Null();
ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
if ((ret = interp->getDOMObject(domObj.handle())))
return Value(ret);
else {
ret = new KJSDOMObj(exec, domObj);
interp->putDOMObject(domObj.handle(),ret);
return Value(ret);
}
}
DOM::Node toNode(const Value&);
Value getStringOrNull(DOM::DOMString s);
QVariant ValueToVariant(ExecState* exec, const Value& val);
template <class FuncImp, class ThisImp, class ParentImp>
inline Value DOMObjectLookupGet(ExecState *exec, const Identifier &propertyName,
const HashTable* table, const ThisImp* thisObj)
{
const HashEntry* entry = Lookup::findEntry(table, propertyName);
if (!entry) return thisObj->ParentImp::tryGet(exec, propertyName);
if (entry->attr & Function)
return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
return thisObj->getValueProperty(exec, entry->value);
}
template <class ThisImp, class ParentImp>
inline Value DOMObjectLookupGetValue(ExecState *exec, const Identifier &propertyName,
const HashTable* table, const ThisImp* thisObj)
{
const HashEntry* entry = Lookup::findEntry(table, propertyName);
if (!entry) return thisObj->ParentImp::tryGet(exec, propertyName);
if (entry->attr & Function)
fprintf(stderr, "Function bit set! Shouldn't happen in lookupValue!\n" );
return thisObj->getValueProperty(exec, entry->value);
}
template <class ThisImp, class ParentImp>
inline void DOMObjectLookupPut(ExecState *exec, const Identifier &propertyName,
const Value& value, int attr,
const HashTable* table, ThisImp* thisObj)
{
const HashEntry* entry = Lookup::findEntry(table, propertyName);
if (!entry) thisObj->ParentImp::tryPut(exec, propertyName, value, attr);
else if (entry->attr & Function) thisObj->ObjectImp::put(exec, propertyName, value, attr);
else if (entry->attr & ReadOnly) #ifdef KJS_VERBOSE
fprintf(stderr,"Attempt to change value of readonly property '%s'\n",propertyName.ascii());
#else
; #endif
else
thisObj->putValue(exec, entry->value, value, attr);
}
template <class ClassCtor>
inline Object cacheGlobalObject(ExecState *exec, const Identifier &propertyName)
{
ValueImp *obj = static_cast<ObjectImp*>(exec->lexicalInterpreter()->globalObject().imp())->getDirect(propertyName);
if (obj)
return Object::dynamicCast(Value(obj));
else
{
Object newObject(new ClassCtor(exec));
exec->lexicalInterpreter()->globalObject().put(exec, propertyName, newObject, Internal);
return newObject;
}
}
#define DEFINE_PROTOTYPE(ClassName,ClassProto) \
namespace KJS { \
class ClassProto : public ObjectImp { \
friend Object cacheGlobalObject<ClassProto>(ExecState *exec, const Identifier &propertyName); \
public: \
static Object self(ExecState *exec) \
{ \
return cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \
} \
protected: \
ClassProto( ExecState *exec ) \
: ObjectImp( exec->lexicalInterpreter()->builtinObjectPrototype() ) {} \
\
public: \
virtual const ClassInfo *classInfo() const { return &info; } \
static const ClassInfo info; \
Value get(ExecState *exec, const Identifier &propertyName) const; \
bool hasProperty(ExecState *exec, const Identifier &propertyName) const; \
}; \
const ClassInfo ClassProto::info = { ClassName, 0, &ClassProto##Table, 0 }; \
};
#define IMPLEMENT_PROTOTYPE(ClassProto,ClassFunc) \
Value KJS::ClassProto::get(ExecState *exec, const Identifier &propertyName) const \
{ \
\
return lookupGetFunction<ClassFunc,ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
} \
bool KJS::ClassProto::hasProperty(ExecState *exec, const Identifier &propertyName) const \
{ \
return ObjectImp::hasProperty(exec, propertyName); \
}
#define IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassProto,ClassFunc,ParentProto) \
Value KJS::ClassProto::get(ExecState *exec, const Identifier &propertyName) const \
{ \
\
Value val = lookupGetFunction<ClassFunc,ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
if ( val.type() != UndefinedType ) return val; \
\
return ParentProto::self(exec).get( exec, propertyName ); \
} \
bool KJS::ClassProto::hasProperty(ExecState *exec, const Identifier &propertyName) const \
{ \
if (ObjectImp::hasProperty(exec, propertyName)) \
return true; \
return ParentProto::self(exec).hasProperty(exec, propertyName); \
}
#define IMPLEMENT_PROTOFUNC(ClassFunc) \
namespace KJS { \
class ClassFunc : public DOMFunction { \
public: \
ClassFunc(ExecState *exec, int i, int len) \
: DOMFunction( ), id(i) { \
Value protect(this); \
put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum); \
} \
\
virtual Value tryCall(ExecState *exec, Object &thisObj, const List &args); \
private: \
int id; \
}; \
};
};
#endif