Unzip initialization lists and constructors in JSCell hierarchy (5/7)
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMBinding.h
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 "JSDOMWrapper.h"
27 #include "DOMWrapperWorld.h"
28 #include "Document.h"
29 #include "Element.h"
30 #include "StyleBase.h"
31 #include <heap/Weak.h>
32 #include <runtime/FunctionPrototype.h>
33 #include <runtime/Lookup.h>
34 #include <runtime/ObjectPrototype.h>
35 #include <wtf/Forward.h>
36 #include <wtf/Noncopyable.h>
37
38 namespace WebCore {
39
40     class Frame;
41     class KURL;
42
43     typedef int ExceptionCode;
44
45     // Base class for all constructor objects in the JSC bindings.
46     class DOMConstructorObject : public JSDOMWrapper {
47     public:
48         static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
49         {
50             return JSC::Structure::create(globalData, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
51         }
52
53     protected:
54         static const unsigned StructureFlags = JSC::ImplementsHasInstance | JSC::OverridesVisitChildren | JSDOMWrapper::StructureFlags;
55         DOMConstructorObject(JSC::Structure* structure, JSDOMGlobalObject* globalObject)
56             : JSDOMWrapper(structure, globalObject)
57         {
58             finishCreation(globalObject->globalData(), globalObject);
59         }
60     };
61
62     // Constructors using this base class depend on being in a Document and
63     // can never be used from a WorkerContext.
64     class DOMConstructorWithDocument : public DOMConstructorObject {
65     public:
66         Document* document() const
67         {
68             return static_cast<Document*>(scriptExecutionContext());
69         }
70
71     protected:
72         DOMConstructorWithDocument(JSC::Structure* structure, JSDOMGlobalObject* globalObject)
73             : DOMConstructorObject(structure, globalObject)
74         {
75             ASSERT(globalObject->scriptExecutionContext()->isDocument());
76         }
77     };
78     
79     JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
80     JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, JSC::Structure*, const JSC::ClassInfo*);
81
82     inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec)
83     {
84         // FIXME: Callers to this function should be using the global object
85         // from which the object is being created, instead of assuming the lexical one.
86         // e.g. subframe.document.body should use the subframe's global object, not the lexical one.
87         return static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
88     }
89
90     template<class WrapperClass> inline JSC::Structure* getDOMStructure(JSC::ExecState* exec, JSDOMGlobalObject* globalObject)
91     {
92         if (JSC::Structure* structure = getCachedDOMStructure(globalObject, &WrapperClass::s_info))
93             return structure;
94         return cacheDOMStructure(globalObject, WrapperClass::createStructure(exec->globalData(), globalObject, WrapperClass::createPrototype(exec, globalObject)), &WrapperClass::s_info);
95     }
96
97     template<class WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
98     {
99         // FIXME: This function is wrong.  It uses the wrong global object for creating the prototype structure.
100         return getDOMStructure<WrapperClass>(exec, deprecatedGlobalObjectForPrototype(exec));
101     }
102
103     template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
104     {
105         return static_cast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(exec, static_cast<JSDOMGlobalObject*>(globalObject))->storedPrototype()));
106     }
107
108     // Overload these functions to provide a fast path for wrapper access.
109     inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld*, void*) { return 0; }
110     inline bool setInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; }
111     inline bool clearInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; }
112
113     // Overload these functions to provide a custom WeakHandleOwner.
114     inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld* world, void*) { return world->defaultWrapperOwner(); }
115     inline void* wrapperContext(DOMWrapperWorld*, void* domObject) { return domObject; }
116
117     template <typename DOMClass> inline JSDOMWrapper* getCachedWrapper(DOMWrapperWorld* world, DOMClass* domObject)
118     {
119         if (JSDOMWrapper* wrapper = getInlineCachedWrapper(world, domObject))
120             return wrapper;
121         return world->m_wrappers.get(domObject).get();
122     }
123
124     template <typename DOMClass> inline void cacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper)
125     {
126         if (setInlineCachedWrapper(world, domObject, wrapper))
127             return;
128         ASSERT(!world->m_wrappers.contains(domObject));
129         world->m_wrappers.set(domObject, JSC::Weak<JSDOMWrapper>(*world->globalData(), wrapper, wrapperOwner(world, domObject), wrapperContext(world, domObject)));
130     }
131
132     template <typename DOMClass> inline void uncacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper)
133     {
134         if (clearInlineCachedWrapper(world, domObject, wrapper))
135             return;
136         ASSERT(world->m_wrappers.find(domObject)->second.get() == wrapper);
137         world->m_wrappers.remove(domObject);
138     }
139     
140     #define CREATE_DOM_WRAPPER(exec, globalObject, className, object) createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
141     template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
142     {
143         ASSERT(node);
144         ASSERT(!getCachedWrapper(currentWorld(exec), node));
145         WrapperClass* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, node);
146         // FIXME: The entire function can be removed, once we fix caching.
147         // This function is a one-off hack to make Nodes cache in the right global object.
148         cacheWrapper(currentWorld(exec), node, wrapper);
149         return wrapper;
150     }
151
152     template<class WrapperClass, class DOMClass> inline JSC::JSValue wrap(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject)
153     {
154         if (!domObject)
155             return JSC::jsNull();
156         if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), domObject))
157             return wrapper;
158         return createWrapper<WrapperClass>(exec, globalObject, domObject);
159     }
160
161     inline void* root(Node* node)
162     {
163         if (node->inDocument())
164             return node->document();
165
166         while (node->parentOrHostNode())
167             node = node->parentOrHostNode();
168         return node;
169     }
170
171     inline void* root(StyleBase* styleBase)
172     {
173         while (styleBase->parent())
174             styleBase = styleBase->parent();
175
176         if (Node* node = styleBase->node())
177             return root(node);
178         return styleBase;
179     }
180
181     const JSC::HashTable* getHashTableForGlobalData(JSC::JSGlobalData&, const JSC::HashTable* staticTable);
182
183     void reportException(JSC::ExecState*, JSC::JSValue exception);
184     void reportCurrentException(JSC::ExecState*);
185
186     // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
187     void setDOMException(JSC::ExecState*, ExceptionCode);
188
189     JSC::JSValue jsString(JSC::ExecState*, const String&); // empty if the string is null
190     JSC::JSValue jsStringSlowCase(JSC::ExecState*, JSStringCache&, StringImpl*);
191     JSC::JSValue jsString(JSC::ExecState*, const KURL&); // empty if the URL is null
192     inline JSC::JSValue jsString(JSC::ExecState* exec, const AtomicString& s)
193     { 
194         return jsString(exec, s.string());
195     }
196         
197     JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
198     JSC::JSValue jsStringOrNull(JSC::ExecState*, const KURL&); // null if the URL is null
199
200     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
201     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const KURL&); // undefined if the URL is null
202
203     JSC::JSValue jsStringOrFalse(JSC::ExecState*, const String&); // boolean false if the string is null
204     JSC::JSValue jsStringOrFalse(JSC::ExecState*, const KURL&); // boolean false if the URL is null
205
206     // See JavaScriptCore for explanation: Should be used for any string that is already owned by another
207     // object, to let the engine know that collecting the JSString wrapper is unlikely to save memory.
208     JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const String&); 
209
210     String identifierToString(const JSC::Identifier&);
211     String ustringToString(const JSC::UString&);
212     JSC::UString stringToUString(const String&);
213
214     AtomicString identifierToAtomicString(const JSC::Identifier&);
215     AtomicString ustringToAtomicString(const JSC::UString&);
216     AtomicStringImpl* findAtomicString(const JSC::Identifier&);
217
218     String valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null
219     String valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined
220
221     inline int32_t finiteInt32Value(JSC::JSValue value, JSC::ExecState* exec, bool& okay)
222     {
223         double number = value.toNumber(exec);
224         okay = isfinite(number);
225         return JSC::toInt32(number);
226     }
227
228     // Returns a Date instance for the specified value, or null if the value is NaN or infinity.
229     JSC::JSValue jsDateOrNull(JSC::ExecState*, double);
230     // NaN if the value can't be converted to a date.
231     double valueToDate(JSC::ExecState*, JSC::JSValue);
232
233     template <typename T>
234     inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr)
235     {
236         return toJS(exec, globalObject, ptr.get());
237     }
238
239     // Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec.
240     JSC::JSObject* toJSSequence(JSC::ExecState*, JSC::JSValue, unsigned&);
241
242     bool checkNodeSecurity(JSC::ExecState*, Node*);
243
244     // Helpers for Window, History, and Location classes to implement cross-domain policy.
245     // Besides the cross-domain check, they need non-caching versions of staticFunctionGetter for
246     // because we do not want current property values involved at all.
247     // FIXME: These functions should be named frameAllowsAccessFrom, because the access is *to* the frame.
248     bool allowsAccessFromFrame(JSC::ExecState*, Frame*);
249     bool allowsAccessFromFrame(JSC::ExecState*, Frame*, String& message);
250     DOMWindow* activeDOMWindow(JSC::ExecState*);
251     DOMWindow* firstDOMWindow(JSC::ExecState*);
252
253     void printErrorMessageForFrame(Frame*, const String& message);
254     JSC::JSValue objectToStringFunctionGetter(JSC::ExecState*, JSC::JSValue, const JSC::Identifier& propertyName);
255
256     Frame* toDynamicFrame(JSC::ExecState*);
257
258     inline JSC::JSValue jsString(JSC::ExecState* exec, const String& s)
259     {
260         StringImpl* stringImpl = s.impl();
261         if (!stringImpl || !stringImpl->length())
262             return jsEmptyString(exec);
263
264         if (stringImpl->length() == 1 && stringImpl->characters()[0] <= 0xFF)
265             return jsString(exec, stringToUString(s));
266
267         JSStringCache& stringCache = currentWorld(exec)->m_stringCache;
268         JSStringCache::iterator it = stringCache.find(stringImpl);
269         if (it != stringCache.end())
270             return it->second.get();
271
272         return jsStringSlowCase(exec, stringCache, stringImpl);
273     }
274
275     inline DOMObjectWrapperMap& domObjectWrapperMapFor(JSC::ExecState* exec)
276     {
277         return currentWorld(exec)->m_wrappers;
278     }
279
280     inline String ustringToString(const JSC::UString& u)
281     {
282         return u.impl();
283     }
284
285     inline JSC::UString stringToUString(const String& s)
286     {
287         return JSC::UString(s.impl());
288     }
289
290     inline String identifierToString(const JSC::Identifier& i)
291     {
292         return i.impl();
293     }
294
295     inline AtomicString ustringToAtomicString(const JSC::UString& u)
296     {
297         return AtomicString(u.impl());
298     }
299
300     inline AtomicString identifierToAtomicString(const JSC::Identifier& identifier)
301     {
302         return AtomicString(identifier.impl());
303     }
304
305 } // namespace WebCore
306
307 #endif // JSDOMBinding_h