kjs_binding.h

00001 // -*- c-basic-offset: 2 -*-
00002 /*
00003  *  This file is part of the KDE libraries
00004  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
00005  *  Copyright (C) 2003 Apple Computer, Inc.
00006  *
00007  *  This library is free software; you can redistribute it and/or
00008  *  modify it under the terms of the GNU Library General Public
00009  *  License as published by the Free Software Foundation; either
00010  *  version 2 of the License, or (at your option) any later version.
00011  *
00012  *  This library is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *  Library General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU Library General Public
00018  *  License along with this library; if not, write to the Free Software
00019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020  */
00021 
00022 #ifndef _KJS_BINDING_H_
00023 #define _KJS_BINDING_H_
00024 
00025 #include <kjs/interpreter.h>
00026 #include <kjs/function_object.h> 
00027 
00028 #include <dom/dom_node.h>
00029 #include <qvariant.h>
00030 #include <qptrdict.h>
00031 #include <kurl.h>
00032 #include <kjs/lookup.h>
00033 
00034 namespace KParts {
00035   class ReadOnlyPart;
00036   class LiveConnectExtension;
00037 }
00038 
00039 namespace khtml {
00040   class ChildFrame;
00041 }
00042 
00043 namespace KJS {
00044 
00050   class DOMObject : public ObjectImp {
00051   public:
00052     DOMObject(const Object &proto) : ObjectImp(proto) {}
00053     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
00054     virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const
00055       { return ObjectImp::get(exec, propertyName); }
00056     virtual bool implementsHasInstance() const { return true; }
00057     virtual Boolean hasInstance(ExecState *exec, const Value &value);
00058     virtual void put(ExecState *exec, const Identifier &propertyName,
00059                      const Value &value, int attr = None);
00060     virtual void tryPut(ExecState *exec, const Identifier &propertyName,
00061                         const Value& value, int attr = None);
00062 
00063     virtual UString toString(ExecState *exec) const;
00064   };
00065 
00071   class DOMFunction : public InternalFunctionImp {
00072   public:
00073     DOMFunction(ExecState* exec) : InternalFunctionImp(
00074       static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
00075       ) {}
00076     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
00077     virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const
00078       { return ObjectImp::get(exec, propertyName); }
00079 
00080     virtual bool implementsCall() const { return true; }
00081     virtual Value call(ExecState *exec, Object &thisObj, const List &args);
00082 
00083     virtual Value tryCall(ExecState *exec, Object &thisObj, const List&args)
00084       { return ObjectImp::call(exec, thisObj, args); }
00085     virtual bool toBoolean(ExecState *) const { return true; }
00086   };
00087 
00093   class KDE_EXPORT ScriptInterpreter : public Interpreter
00094   {
00095   public:
00096     ScriptInterpreter( const Object &global, khtml::ChildFrame* frame );
00097     virtual ~ScriptInterpreter();
00098 
00099     DOMObject* getDOMObject( void* objectHandle ) const {
00100       return m_domObjects[objectHandle];
00101     }
00102     void putDOMObject( void* objectHandle, DOMObject* obj ) {
00103       m_domObjects.insert( objectHandle, obj );
00104     }
00105     void customizedDOMObject( DOMObject* obj ) {
00106       m_customizedDomObjects.replace( obj, this );
00107     }
00108     bool deleteDOMObject( void* objectHandle ) {
00109       DOMObject* obj = m_domObjects.take( objectHandle );
00110       if (obj) {
00111         m_customizedDomObjects.remove( obj );
00112         return true;
00113       }
00114       else
00115         return false;
00116     }
00117     void clear() {
00118       m_customizedDomObjects.clear();
00119       m_domObjects.clear();
00120     }
00124     static void forgetDOMObject( void* objectHandle );
00125 
00129     virtual void mark();
00130     KParts::ReadOnlyPart* part() const;
00131 
00132     virtual int rtti() { return 1; }
00133 
00137     void setCurrentEvent( DOM::Event *evt ) { m_evt = evt; }
00138     void setInlineCode( bool inlineCode ) { m_inlineCode = inlineCode; }
00139     void setProcessingTimerCallback( bool timerCallback ) { m_timerCallback = timerCallback; }
00143     bool isWindowOpenAllowed() const;
00144 
00145   private:
00146     khtml::ChildFrame* m_frame;
00147     QPtrDict<DOMObject> m_domObjects;
00148     QPtrDict<void> m_customizedDomObjects; //Objects which had custom properties set,
00149                                            //and should not be GC'd. key is DOMObject*
00150     DOM::Event *m_evt;
00151     bool m_inlineCode;
00152     bool m_timerCallback;
00153   };
00157   template<class DOMObj, class KJSDOMObj>
00158   inline Value cacheDOMObject(ExecState *exec, DOMObj domObj)
00159   {
00160     DOMObject *ret;
00161     if (domObj.isNull())
00162       return Null();
00163     ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter());
00164     if ((ret = interp->getDOMObject(domObj.handle())))
00165       return Value(ret);
00166     else {
00167       ret = new KJSDOMObj(exec, domObj);
00168       interp->putDOMObject(domObj.handle(),ret);
00169       return Value(ret);
00170     }
00171   }
00172 
00176   DOM::Node toNode(const Value&);
00180   Value getString(DOM::DOMString s);
00181 
00185   QVariant ValueToVariant(ExecState* exec, const Value& val);
00186 
00191   template <class FuncImp, class ThisImp, class ParentImp>
00192   inline Value DOMObjectLookupGet(ExecState *exec, const Identifier &propertyName,
00193                                   const HashTable* table, const ThisImp* thisObj)
00194   {
00195     const HashEntry* entry = Lookup::findEntry(table, propertyName);
00196 
00197     if (!entry) // not found, forward to parent
00198       return thisObj->ParentImp::tryGet(exec, propertyName);
00199 
00200     if (entry->attr & Function) {
00201       return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
00202     }
00203     return thisObj->getValueProperty(exec, entry->value);
00204   }
00205 
00210   template <class ThisImp, class ParentImp>
00211   inline Value DOMObjectLookupGetValue(ExecState *exec, const Identifier &propertyName,
00212                                        const HashTable* table, const ThisImp* thisObj)
00213   {
00214     const HashEntry* entry = Lookup::findEntry(table, propertyName);
00215 
00216     if (!entry) // not found, forward to parent
00217       return thisObj->ParentImp::tryGet(exec, propertyName);
00218 
00219     if (entry->attr & Function)
00220       fprintf(stderr, "Function bit set! Shouldn't happen in lookupValue!\n" );
00221     return thisObj->getValueProperty(exec, entry->value);
00222   }
00223 
00228   template <class ThisImp, class ParentImp>
00229   inline void DOMObjectLookupPut(ExecState *exec, const Identifier &propertyName,
00230                                  const Value& value, int attr,
00231                                  const HashTable* table, ThisImp* thisObj)
00232   {
00233     const HashEntry* entry = Lookup::findEntry(table, propertyName);
00234 
00235     if (!entry) // not found: forward to parent
00236       thisObj->ParentImp::tryPut(exec, propertyName, value, attr);
00237     else if (entry->attr & Function) // function: put as override property
00238       thisObj->ObjectImp::put(exec, propertyName, value, attr);
00239     else if (entry->attr & ReadOnly) // readonly! Can't put!
00240 #ifdef KJS_VERBOSE
00241       fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii());
00242 #else
00243     ; // do nothing
00244 #endif
00245     else
00246       thisObj->putValueProperty(exec, entry->value, value, attr);
00247   }
00248 
00249   // Modified version of IMPLEMENT_PROTOFUNC, to use DOMFunction and tryCall
00250 #define IMPLEMENT_PROTOFUNC_DOM(ClassFunc) \
00251   namespace KJS { \
00252   class ClassFunc : public DOMFunction { \
00253   public: \
00254     ClassFunc(ExecState *exec, int i, int len) \
00255        : DOMFunction( exec ), id(i) { \
00256        Value protect(this); \
00257        put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum); \
00258     } \
00259  \
00260     virtual Value tryCall(ExecState *exec, Object &thisObj, const List &args); \
00261   private: \
00262     int id; \
00263   }; \
00264   }
00265 
00266   Value getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id);
00267 
00268 
00269 // This is used to create pseudo-constructor objects, like Mozillaish
00270 // Element, HTMLDocument, etc., which do not act like real constructors,
00271 // but do have the prototype property pointing to prototype of "instances"
00272 #define DEFINE_PSEUDO_CONSTRUCTOR(ClassName) \
00273   class ClassName : public DOMObject { \
00274       public: \
00275           ClassName(ExecState *); \
00276           virtual const ClassInfo* classInfo() const { return &info; } \
00277           static const ClassInfo info; \
00278           static Object self(ExecState *exec); \
00279   };
00280 
00281 #define IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,ParentProto) \
00282     const ClassInfo Class::info = { ClassName, 0, 0, 0 }; \
00283     Class::Class(ExecState* exec): DOMObject(ParentProto) {\
00284         Object proto = ProtoClass::self(exec); \
00285         putDirect(prototypePropertyName, proto.imp(), DontDelete|ReadOnly); \
00286     }\
00287     Object Class::self(ExecState *exec) { \
00288         return Object(cacheGlobalObject<Class>(exec, "[[" ClassName ".constructor]]")); \
00289     }
00290 
00291 #define IMPLEMENT_PSEUDO_CONSTRUCTOR(Class,ClassName,ProtoClass) \
00292     IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,exec->lexicalInterpreter()->builtinObjectPrototype())
00293 
00294 #define IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(Class,ClassName,ProtoClass,ParentProtoClass) \
00295     IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,ParentProtoClass::self(exec))
00296 
00297 // This is used to implement a constant table. Can be used as a prototype
00298 #define CREATE_CONSTANT_TABLE(Class,ClassName) \
00299    class Class : public DOMObject { \
00300    public: \
00301      Class(ExecState *exec): DOMObject(exec->interpreter()->builtinObjectPrototype()) {} \
00302      virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const { \
00303         return DOMObjectLookupGetValue<Class, DOMObject>(exec, propertyName, &Class##Table, this);\
00304      } \
00305      Value getValueProperty(ExecState * /*exec*/, int token) const { \
00306         /* We use the token as the value to return directly*/ \
00307         return Number((unsigned int)token); \
00308      }  \
00309      virtual const ClassInfo* classInfo() const { return &info; } \
00310      static const ClassInfo info; \
00311      static Object self(ExecState *exec) { \
00312         return Object(cacheGlobalObject<Class>(exec, "[[" ClassName ".constant_table]]")); \
00313      } \
00314    }; \
00315    const ClassInfo Class::info = { ClassName, 0, &Class##Table, 0 };
00316 
00317 } // namespace
00318 
00319 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys