JavaScriptCore:
[WebKit-https.git] / WebCore / khtml / ecma / kjs_binding.h
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.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser 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.
11  *
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  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #ifndef _KJS_BINDING_H_
23 #define _KJS_BINDING_H_
24
25 #include <kjs/interpreter.h>
26 #include <qvariant.h>
27 #include <qptrdict.h>
28 #include <kjs/lookup.h>
29 #include <kjs/protect.h>
30
31 #if APPLE_CHANGES
32 #include <JavaScriptCore/runtime.h>
33 #endif
34
35 class KHTMLPart;
36
37 namespace DOM {
38     class DocumentImpl;
39     class EventImpl;
40     class NodeImpl;
41 }
42
43 namespace KJS {
44
45   /**
46    * Base class for all objects in this binding - get() and put() run
47    * tryGet() and tryPut() respectively, and catch exceptions if they
48    * occur.
49    */
50   class DOMObject : public ObjectImp {
51   public:
52     DOMObject() : ObjectImp() {}
53     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
54     virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const
55       { return ObjectImp::get(exec, propertyName); }
56
57     virtual void put(ExecState *exec, const Identifier &propertyName,
58                      const Value &value, int attr = None);
59     virtual void tryPut(ExecState *exec, const Identifier &propertyName,
60                         const Value& value, int attr = None)
61       { ObjectImp::put(exec,propertyName,value,attr); }
62
63     virtual UString toString(ExecState *exec) const;
64   };
65
66   /**
67    * Base class for all functions in this binding - get() and call() run
68    * tryGet() and tryCall() respectively, and catch exceptions if they
69    * occur.
70    */
71   class DOMFunction : public ObjectImp {
72   public:
73     DOMFunction() : ObjectImp( /* proto? */ ) {}
74     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
75     virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const
76       { return ObjectImp::get(exec, propertyName); }
77
78     virtual bool implementsCall() const { return true; }
79     virtual Value call(ExecState *exec, Object &thisObj, const List &args);
80
81     virtual Value tryCall(ExecState *exec, Object &thisObj, const List&args)
82       { return ObjectImp::call(exec, thisObj, args); }
83     virtual bool toBoolean(ExecState *) const { return true; }
84     virtual Value toPrimitive(ExecState *exec, Type) const { return String(toString(exec)); }
85     virtual UString toString(ExecState *) const { return UString("[function]"); }
86   };
87
88   class DOMNode;
89
90   /**
91    * We inherit from Interpreter, to save a pointer to the HTML part
92    * that the interpreter runs for.
93    * The interpreter also stores the DOM object - >KJS::DOMObject cache.
94    */
95   class ScriptInterpreter : public Interpreter
96   {
97   public:
98     ScriptInterpreter( const Object &global, KHTMLPart* part );
99     virtual ~ScriptInterpreter();
100
101     static DOMObject* getDOMObject( void* objectHandle ) {
102       return domObjects()[objectHandle];
103     }
104     static void putDOMObject( void* objectHandle, DOMObject* obj ) {
105       domObjects().insert( objectHandle, obj );
106     }
107     static bool deleteDOMObject( void* objectHandle ) {
108       return domObjects().remove( objectHandle );
109     }
110
111     static void forgetDOMObject( void* objectHandle );
112
113
114     static DOMNode *getDOMNodeForDocument(DOM::DocumentImpl *document, DOM::NodeImpl *node);
115     static void putDOMNodeForDocument(DOM::DocumentImpl *document, DOM::NodeImpl *nodeHandle, DOMNode *nodeWrapper);
116     static void forgetDOMNodeForDocument(DOM::DocumentImpl *document, DOM::NodeImpl *node);
117     static void forgetAllDOMNodesForDocument(DOM::DocumentImpl *document);
118     static void updateDOMNodeDocument(DOM::NodeImpl *nodeHandle, DOM::DocumentImpl *oldDoc, DOM::DocumentImpl *newDoc);
119
120
121
122     KHTMLPart* part() const { return m_part; }
123
124     virtual int rtti() { return 1; }
125
126     /**
127      * Set the event that is triggering the execution of a script, if any
128      */
129     void setCurrentEvent( DOM::EventImpl *evt ) { m_evt = evt; }
130     void setInlineCode( bool inlineCode ) { m_inlineCode = inlineCode; }
131     void setProcessingTimerCallback( bool timerCallback ) { m_timerCallback = timerCallback; }
132     /**
133      * "Smart" window.open policy
134      */
135     bool wasRunByUserGesture() const;
136
137     virtual void mark();
138     
139     DOM::EventImpl *getCurrentEvent() const { return m_evt; }
140
141 #if APPLE_CHANGES
142     virtual bool isGlobalObject(const Value &v);
143     virtual Interpreter *interpreterForGlobalObject (const ValueImp *imp);
144     virtual bool isSafeScript (const Interpreter *target);
145     virtual void *createLanguageInstanceForValue (ExecState *exec, Bindings::Instance::BindingLanguage language, const Object &value, const Bindings::RootObject *origin, const Bindings::RootObject *current);
146     void *createObjcInstanceForValue (ExecState *exec, const Object &value, const Bindings::RootObject *origin, const Bindings::RootObject *current);
147 #endif
148
149   private:
150     KHTMLPart* m_part;
151
152     static QPtrDict<DOMObject> &domObjects();
153     static QPtrDict<QPtrDict<DOMNode> > &domNodesPerDocument();
154
155     DOM::EventImpl *m_evt;
156     bool m_inlineCode;
157     bool m_timerCallback;
158   };
159
160   /**
161    * Retrieve from cache, or create, a KJS object around a DOM object
162    */
163   template<class DOMObj, class KJSDOMObj>
164   inline ValueImp *cacheDOMObject(ExecState *exec, DOMObj *domObj)
165   {
166     if (!domObj)
167       return null();
168     ScriptInterpreter *interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
169     if (DOMObject *ret = interp->getDOMObject(domObj))
170       return ret;
171     DOMObject *ret = new KJSDOMObj(exec, domObj);
172     interp->putDOMObject(domObj, ret);
173     return ret;
174   }
175
176   // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
177   void setDOMException(ExecState *exec, int DOMExceptionCode);
178
179   // Helper class to call setDOMException on exit without adding lots of separate calls to that function.
180   class DOMExceptionTranslator {
181   public:
182     explicit DOMExceptionTranslator(ExecState *exec) : m_exec(exec), m_code(0) { }
183     ~DOMExceptionTranslator() { setDOMException(m_exec, m_code); }
184     operator int &() { return m_code; }
185   private:
186     ExecState *m_exec;
187     int m_code;
188   };
189
190   /**
191    *  Get a String object, or Null() if s is null
192    */
193   Value getStringOrNull(DOM::DOMString s);
194
195   /**
196    * Convert a KJS value into a QVariant
197    * Deprecated: Use variant instead.
198    */
199   QVariant ValueToVariant(ExecState* exec, const Value& val);
200
201   /**
202    * We need a modified version of lookupGet because
203    * we call tryGet instead of get, in DOMObjects.
204    */
205   template <class FuncImp, class ThisImp, class ParentImp>
206   inline Value DOMObjectLookupGet(ExecState *exec, const Identifier &propertyName,
207                                   const HashTable* table, const ThisImp* thisObj)
208   {
209     const HashEntry* entry = Lookup::findEntry(table, propertyName);
210
211     if (!entry) // not found, forward to parent
212       return thisObj->ParentImp::tryGet(exec, propertyName);
213
214     if (entry->attr & Function)
215       return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
216     return thisObj->getValueProperty(exec, entry->value);
217   }
218
219   /**
220    * Simplified version of DOMObjectLookupGet in case there are no
221    * functions, only "values".
222    */
223   template <class ThisImp, class ParentImp>
224   inline Value DOMObjectLookupGetValue(ExecState *exec, const Identifier &propertyName,
225                                        const HashTable* table, const ThisImp* thisObj)
226   {
227     const HashEntry* entry = Lookup::findEntry(table, propertyName);
228
229     if (!entry) // not found, forward to parent
230       return thisObj->ParentImp::tryGet(exec, propertyName);
231
232     if (entry->attr & Function)
233       fprintf(stderr, "Function bit set! Shouldn't happen in lookupValue!\n" );
234     return thisObj->getValueProperty(exec, entry->value);
235   }
236
237   /**
238    * We need a modified version of lookupPut because
239    * we call tryPut instead of put, in DOMObjects.
240    */
241   template <class ThisImp, class ParentImp>
242   inline void DOMObjectLookupPut(ExecState *exec, const Identifier &propertyName,
243                                  const Value& value, int attr,
244                                  const HashTable* table, ThisImp* thisObj)
245   {
246     const HashEntry* entry = Lookup::findEntry(table, propertyName);
247
248     if (!entry) // not found: forward to parent
249       thisObj->ParentImp::tryPut(exec, propertyName, value, attr);
250     else if (entry->attr & Function) // function: put as override property
251       thisObj->ObjectImp::put(exec, propertyName, value, attr);
252     else if (entry->attr & ReadOnly) // readonly! Can't put!
253 #ifdef KJS_VERBOSE
254       fprintf(stderr,"Attempt to change value of readonly property '%s'\n",propertyName.ascii());
255 #else
256     ; // do nothing
257 #endif
258     else
259       thisObj->putValue(exec, entry->value, value, attr);
260   }
261
262 } // namespace
263
264 #endif