• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved.
4  *  Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
5  *  Copyright (C) 2009 Google, Inc. All rights reserved.
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #ifndef JSDOMBinding_h
23 #define JSDOMBinding_h
24 
25 #include "JSDOMGlobalObject.h"
26 #include "Document.h" // For DOMConstructorWithDocument
27 #include <runtime/Completion.h>
28 #include <runtime/Lookup.h>
29 #include <runtime/JSFunction.h>
30 #include <wtf/Noncopyable.h>
31 
32 namespace JSC {
33     class JSGlobalData;
34 }
35 
36 namespace WebCore {
37 
38     class Document;
39     class Frame;
40     class KURL;
41     class Node;
42     class String;
43     class JSNode;
44 
45     typedef int ExceptionCode;
46 
47 #if ENABLE(SVG)
48     class SVGElement;
49 #endif
50 
51     // Base class for all objects in this binding except Window.
52     class DOMObject : public JSC::JSObject {
53     protected:
DOMObject(PassRefPtr<JSC::Structure> structure)54         explicit DOMObject(PassRefPtr<JSC::Structure> structure)
55             : JSObject(structure)
56         {
57         }
58 
59 #ifndef NDEBUG
60         virtual ~DOMObject();
61 #endif
62     };
63 
64     // FIXME: This class should colapse into DOMObject once all DOMObjects are
65     // updated to store a globalObject pointer.
66     class DOMObjectWithGlobalPointer : public DOMObject {
67     public:
globalObject()68         JSDOMGlobalObject* globalObject() const { return m_globalObject; }
69 
scriptExecutionContext()70         ScriptExecutionContext* scriptExecutionContext() const
71         {
72             // FIXME: Should never be 0, but can be due to bug 27640.
73             return m_globalObject->scriptExecutionContext();
74         }
75 
76     protected:
DOMObjectWithGlobalPointer(PassRefPtr<JSC::Structure> structure,JSDOMGlobalObject * globalObject)77         DOMObjectWithGlobalPointer(PassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject)
78             : DOMObject(structure)
79             , m_globalObject(globalObject)
80         {
81             // FIXME: This ASSERT is valid, but fires in fast/dom/gc-6.html when trying to create
82             // new JavaScript objects on detached windows due to DOMWindow::document()
83             // needing to reach through the frame to get to the Document*.  See bug 27640.
84             // ASSERT(globalObject->scriptExecutionContext());
85         }
~DOMObjectWithGlobalPointer()86         virtual ~DOMObjectWithGlobalPointer() {}
87 
markChildren(JSC::MarkStack & markStack)88         void markChildren(JSC::MarkStack& markStack)
89         {
90             DOMObject::markChildren(markStack);
91             markStack.append(m_globalObject);
92         }
93 
94     private:
95         JSDOMGlobalObject* m_globalObject;
96     };
97 
98     // Base class for all constructor objects in the JSC bindings.
99     class DOMConstructorObject : public DOMObjectWithGlobalPointer {
100     public:
createStructure(JSC::JSValue prototype)101         static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)
102         {
103             return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType, JSC::HasStandardGetOwnPropertySlot | JSC::ImplementsHasInstance));
104         }
105 
106     protected:
DOMConstructorObject(PassRefPtr<JSC::Structure> structure,JSDOMGlobalObject * globalObject)107         DOMConstructorObject(PassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject)
108             : DOMObjectWithGlobalPointer(structure, globalObject)
109         {
110         }
111     };
112 
113     // Constructors using this base class depend on being in a Document and
114     // can never be used from a WorkerContext.
115     class DOMConstructorWithDocument : public DOMConstructorObject {
116     public:
document()117         Document* document() const
118         {
119             return static_cast<Document*>(scriptExecutionContext());
120         }
121 
122     protected:
DOMConstructorWithDocument(PassRefPtr<JSC::Structure> structure,JSDOMGlobalObject * globalObject)123         DOMConstructorWithDocument(PassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject)
124             : DOMConstructorObject(structure, globalObject)
125         {
126             ASSERT(globalObject->scriptExecutionContext()->isDocument());
127         }
128     };
129 
130     DOMObject* getCachedDOMObjectWrapper(JSC::JSGlobalData&, void* objectHandle);
131     void cacheDOMObjectWrapper(JSC::JSGlobalData&, void* objectHandle, DOMObject* wrapper);
132     void forgetDOMObject(JSC::JSGlobalData&, void* objectHandle);
133 
134     JSNode* getCachedDOMNodeWrapper(Document*, Node*);
135     void cacheDOMNodeWrapper(Document*, Node*, JSNode* wrapper);
136     void forgetDOMNode(Document*, Node*);
137     void forgetAllDOMNodesForDocument(Document*);
138     void updateDOMNodeDocument(Node*, Document* oldDocument, Document* newDocument);
139     void markDOMNodesForDocument(JSC::MarkStack&, Document*);
140     void markActiveObjectsForContext(JSC::MarkStack&, JSC::JSGlobalData&, ScriptExecutionContext*);
141     void markDOMObjectWrapper(JSC::MarkStack&, JSC::JSGlobalData& globalData, void* object);
142 
143     JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
144     JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, PassRefPtr<JSC::Structure>, const JSC::ClassInfo*);
145     JSC::Structure* getCachedDOMStructure(JSC::ExecState*, const JSC::ClassInfo*);
146     JSC::Structure* cacheDOMStructure(JSC::ExecState*, PassRefPtr<JSC::Structure>, const JSC::ClassInfo*);
147 
148     JSC::JSObject* getCachedDOMConstructor(JSC::ExecState*, const JSC::ClassInfo*);
149     void cacheDOMConstructor(JSC::ExecState*, const JSC::ClassInfo*, JSC::JSObject* constructor);
150 
deprecatedGlobalObjectForPrototype(JSC::ExecState * exec)151     inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec)
152     {
153         // FIXME: Callers to this function should be using the global object
154         // from which the object is being created, instead of assuming the lexical one.
155         // e.g. subframe.document.body should use the subframe's global object, not the lexical one.
156         return static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
157     }
158 
getDOMStructure(JSC::ExecState * exec,JSDOMGlobalObject * globalObject)159     template<class WrapperClass> inline JSC::Structure* getDOMStructure(JSC::ExecState* exec, JSDOMGlobalObject* globalObject)
160     {
161         if (JSC::Structure* structure = getCachedDOMStructure(globalObject, &WrapperClass::s_info))
162             return structure;
163         return cacheDOMStructure(globalObject, WrapperClass::createStructure(WrapperClass::createPrototype(exec, globalObject)), &WrapperClass::s_info);
164     }
deprecatedGetDOMStructure(JSC::ExecState * exec)165     template<class WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
166     {
167         // FIXME: This function is wrong.  It uses the wrong global object for creating the prototype structure.
168         return getDOMStructure<WrapperClass>(exec, deprecatedGlobalObjectForPrototype(exec));
169     }
getDOMPrototype(JSC::ExecState * exec,JSC::JSGlobalObject * globalObject)170     template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
171     {
172         return static_cast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(exec, static_cast<JSDOMGlobalObject*>(globalObject))->storedPrototype()));
173     }
174     #define CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, className, object) createDOMObjectWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
createDOMObjectWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * object)175     template<class WrapperClass, class DOMClass> inline DOMObject* createDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object)
176     {
177         ASSERT(object);
178         ASSERT(!getCachedDOMObjectWrapper(exec->globalData(), object));
179         // FIXME: new (exec) could use a different globalData than the globalData this wrapper is cached on.
180         WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, object);
181         cacheDOMObjectWrapper(exec->globalData(), object, wrapper);
182         return wrapper;
183     }
getDOMObjectWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * object)184     template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object)
185     {
186         if (!object)
187             return JSC::jsNull();
188         if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec->globalData(), object))
189             return wrapper;
190         return createDOMObjectWrapper<WrapperClass>(exec, globalObject, object);
191     }
192 
193 #if ENABLE(SVG)
194     #define CREATE_SVG_OBJECT_WRAPPER(exec, globalObject, className, object, context) createDOMObjectWrapper<JS##className>(exec, globalObject, static_cast<className*>(object), context)
createDOMObjectWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * object,SVGElement * context)195     template<class WrapperClass, class DOMClass> inline DOMObject* createDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object, SVGElement* context)
196     {
197         ASSERT(object);
198         ASSERT(!getCachedDOMObjectWrapper(exec->globalData(), object));
199         WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, object, context);
200         cacheDOMObjectWrapper(exec->globalData(), object, wrapper);
201         return wrapper;
202     }
getDOMObjectWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * object,SVGElement * context)203     template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object, SVGElement* context)
204     {
205         if (!object)
206             return JSC::jsNull();
207         if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec->globalData(), object))
208             return wrapper;
209         return createDOMObjectWrapper<WrapperClass>(exec, globalObject, object, context);
210     }
211 #endif
212 
213     #define CREATE_DOM_NODE_WRAPPER(exec, globalObject, className, object) createDOMNodeWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
createDOMNodeWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * node)214     template<class WrapperClass, class DOMClass> inline JSNode* createDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
215     {
216         ASSERT(node);
217         ASSERT(!getCachedDOMNodeWrapper(node->document(), node));
218         WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, node);
219         // FIXME: The entire function can be removed, once we fix caching.
220         // This function is a one-off hack to make Nodes cache in the right global object.
221         cacheDOMNodeWrapper(node->document(), node, wrapper);
222         return wrapper;
223     }
getDOMNodeWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * node)224     template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
225     {
226         if (!node)
227             return JSC::jsNull();
228         if (JSNode* wrapper = getCachedDOMNodeWrapper(node->document(), node))
229             return wrapper;
230         return createDOMNodeWrapper<WrapperClass>(exec, globalObject, node);
231     }
232 
233     const JSC::HashTable* getHashTableForGlobalData(JSC::JSGlobalData&, const JSC::HashTable* staticTable);
234 
235     void reportException(JSC::ExecState*, JSC::JSValue exception);
236     void reportCurrentException(JSC::ExecState*);
237 
238     // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
239     void setDOMException(JSC::ExecState*, ExceptionCode);
240 
241     JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
242     JSC::JSValue jsStringOrNull(JSC::ExecState*, const KURL&); // null if the URL is null
243 
244     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
245     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const KURL&); // undefined if the URL is null
246 
247     JSC::JSValue jsStringOrFalse(JSC::ExecState*, const String&); // boolean false if the string is null
248     JSC::JSValue jsStringOrFalse(JSC::ExecState*, const KURL&); // boolean false if the URL is null
249 
250     // See JavaScriptCore for explanation: Should be used for any UString that is already owned by another
251     // object, to let the engine know that collecting the JSString wrapper is unlikely to save memory.
252     JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const JSC::UString&);
253 
254     JSC::UString valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null
255     JSC::UString valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined
256 
257     // FIXME: These are a stop-gap until all toJS calls can be converted to pass a globalObject
258     template <typename T>
toJS(JSC::ExecState * exec,T * ptr)259     inline JSC::JSValue toJS(JSC::ExecState* exec, T* ptr)
260     {
261         return toJS(exec, deprecatedGlobalObjectForPrototype(exec), ptr);
262     }
263     template <typename T>
toJS(JSC::ExecState * exec,PassRefPtr<T> ptr)264     inline JSC::JSValue toJS(JSC::ExecState* exec, PassRefPtr<T> ptr)
265     {
266         return toJS(exec, deprecatedGlobalObjectForPrototype(exec), ptr.get());
267     }
268     template <typename T>
toJSNewlyCreated(JSC::ExecState * exec,T * ptr)269     inline JSC::JSValue toJSNewlyCreated(JSC::ExecState* exec, T* ptr)
270     {
271         return toJSNewlyCreated(exec, deprecatedGlobalObjectForPrototype(exec), ptr);
272     }
273 
274     template <typename T>
toJS(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,PassRefPtr<T> ptr)275     inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr)
276     {
277         return toJS(exec, globalObject, ptr.get());
278     }
279 
280     bool checkNodeSecurity(JSC::ExecState*, Node*);
281 
282     // Helpers for Window, History, and Location classes to implement cross-domain policy.
283     // Besides the cross-domain check, they need non-caching versions of staticFunctionGetter for
284     // because we do not want current property values involved at all.
285     bool allowsAccessFromFrame(JSC::ExecState*, Frame*);
286     bool allowsAccessFromFrame(JSC::ExecState*, Frame*, String& message);
287     bool shouldAllowNavigation(JSC::ExecState*, Frame*);
288     void printErrorMessageForFrame(Frame*, const String& message);
289     JSC::JSValue objectToStringFunctionGetter(JSC::ExecState*, const JSC::Identifier& propertyName, const JSC::PropertySlot&);
290 
291     Frame* toLexicalFrame(JSC::ExecState*);
292     Frame* toDynamicFrame(JSC::ExecState*);
293     bool processingUserGesture(JSC::ExecState*);
294     KURL completeURL(JSC::ExecState*, const String& relativeURL);
295 
296 } // namespace WebCore
297 
298 #endif // JSDOMBinding_h
299