Add support for private names
[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 "CSSImportRule.h"
26 #include "CSSStyleDeclaration.h"
27 #include "CSSStyleSheet.h"
28 #include "JSDOMGlobalObject.h"
29 #include "JSDOMWrapper.h"
30 #include "DOMWrapperWorld.h"
31 #include "Document.h"
32 #include "Element.h"
33 #include "MediaList.h"
34 #include "StylePropertySet.h"
35 #include "StyledElement.h"
36 #include <heap/Weak.h>
37 #include <runtime/FunctionPrototype.h>
38 #include <runtime/JSArray.h>
39 #include <runtime/Lookup.h>
40 #include <runtime/ObjectPrototype.h>
41 #include <wtf/Forward.h>
42 #include <wtf/Noncopyable.h>
43 #include <wtf/Vector.h>
44
45 namespace WebCore {
46
47 enum ParameterDefaultPolicy {
48     DefaultIsUndefined,
49     DefaultIsNullString
50 };
51
52 #define MAYBE_MISSING_PARAMETER(exec, index, policy) (((policy) == DefaultIsNullString && (index) >= (exec)->argumentCount()) ? (JSValue()) : ((exec)->argument(index)))
53
54     class Frame;
55     class KURL;
56
57     typedef int ExceptionCode;
58
59     // Base class for all constructor objects in the JSC bindings.
60     class DOMConstructorObject : public JSDOMWrapper {
61         typedef JSDOMWrapper Base;
62     public:
63         static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
64         {
65             return JSC::Structure::create(globalData, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);
66         }
67
68     protected:
69         static const unsigned StructureFlags = JSC::ImplementsHasInstance | JSC::OverridesVisitChildren | JSDOMWrapper::StructureFlags;
70         DOMConstructorObject(JSC::Structure* structure, JSDOMGlobalObject* globalObject)
71             : JSDOMWrapper(structure, globalObject)
72         {
73         }
74     };
75
76     // Constructors using this base class depend on being in a Document and
77     // can never be used from a WorkerContext.
78     class DOMConstructorWithDocument : public DOMConstructorObject {
79         typedef DOMConstructorObject Base;
80     public:
81         Document* document() const
82         {
83             return static_cast<Document*>(scriptExecutionContext());
84         }
85
86     protected:
87         DOMConstructorWithDocument(JSC::Structure* structure, JSDOMGlobalObject* globalObject)
88             : DOMConstructorObject(structure, globalObject)
89         {
90         }
91
92         void finishCreation(JSDOMGlobalObject* globalObject)
93         {
94             Base::finishCreation(globalObject->globalData());
95             ASSERT(globalObject->scriptExecutionContext()->isDocument());
96         }
97     };
98     
99     JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
100     JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, JSC::Structure*, const JSC::ClassInfo*);
101
102     inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec)
103     {
104         // FIXME: Callers to this function should be using the global object
105         // from which the object is being created, instead of assuming the lexical one.
106         // e.g. subframe.document.body should use the subframe's global object, not the lexical one.
107         return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
108     }
109
110     template<class WrapperClass> inline JSC::Structure* getDOMStructure(JSC::ExecState* exec, JSDOMGlobalObject* globalObject)
111     {
112         if (JSC::Structure* structure = getCachedDOMStructure(globalObject, &WrapperClass::s_info))
113             return structure;
114         return cacheDOMStructure(globalObject, WrapperClass::createStructure(exec->globalData(), globalObject, WrapperClass::createPrototype(exec, globalObject)), &WrapperClass::s_info);
115     }
116
117     template<class WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
118     {
119         // FIXME: This function is wrong.  It uses the wrong global object for creating the prototype structure.
120         return getDOMStructure<WrapperClass>(exec, deprecatedGlobalObjectForPrototype(exec));
121     }
122
123     template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
124     {
125         return JSC::jsCast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(exec, JSC::jsCast<JSDOMGlobalObject*>(globalObject))->storedPrototype()));
126     }
127
128     // Overload these functions to provide a fast path for wrapper access.
129     inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld*, void*) { return 0; }
130     inline bool setInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; }
131     inline bool clearInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; }
132
133     template <typename DOMClass> inline JSDOMWrapper* getCachedWrapper(DOMWrapperWorld* world, DOMClass* domObject)
134     {
135         if (JSDOMWrapper* wrapper = getInlineCachedWrapper(world, domObject))
136             return wrapper;
137         return world->m_wrappers.get(domObject);
138     }
139
140     template <typename DOMClass> inline void cacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper)
141     {
142         if (setInlineCachedWrapper(world, domObject, wrapper))
143             return;
144         JSC::PassWeak<JSDOMWrapper> passWeak(wrapper, wrapperOwner(world, domObject), wrapperContext(world, domObject));
145         DOMObjectWrapperMap::AddResult result = world->m_wrappers.add(domObject, passWeak);
146         ASSERT_UNUSED(result, result.isNewEntry);
147     }
148
149     template <typename DOMClass> inline void uncacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper)
150     {
151         if (clearInlineCachedWrapper(world, domObject, wrapper))
152             return;
153         ASSERT(world->m_wrappers.find(domObject)->second.was(wrapper));
154         world->m_wrappers.remove(domObject);
155     }
156     
157     #define CREATE_DOM_WRAPPER(exec, globalObject, className, object) createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
158     template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
159     {
160         ASSERT(node);
161         ASSERT(!getCachedWrapper(currentWorld(exec), node));
162         WrapperClass* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, node);
163         // FIXME: The entire function can be removed, once we fix caching.
164         // This function is a one-off hack to make Nodes cache in the right global object.
165         cacheWrapper(currentWorld(exec), node, wrapper);
166         return wrapper;
167     }
168
169     template<class WrapperClass, class DOMClass> inline JSC::JSValue wrap(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject)
170     {
171         if (!domObject)
172             return JSC::jsNull();
173         if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), domObject))
174             return wrapper;
175         return createWrapper<WrapperClass>(exec, globalObject, domObject);
176     }
177
178     inline void* root(Node* node)
179     {
180         if (node->inDocument())
181             return node->document();
182
183         while (node->parentOrHostNode())
184             node = node->parentOrHostNode();
185         return node;
186     }
187
188     inline void* root(StyleSheet*);
189
190     inline void* root(CSSRule* rule)
191     {
192         if (rule->parentRule())
193             return root(rule->parentRule());
194         if (rule->parentStyleSheet())
195             return root(rule->parentStyleSheet());
196         return rule;
197     }
198
199     inline void* root(StyleSheet* styleSheet)
200     {
201         if (styleSheet->ownerRule())
202             return root(styleSheet->ownerRule());
203         if (styleSheet->ownerNode())
204             return root(styleSheet->ownerNode());
205         return styleSheet;
206     }
207
208     inline void* root(CSSStyleDeclaration* style)
209     {
210         if (CSSRule* parentRule = style->parentRule())
211             return root(parentRule);
212         if (CSSStyleSheet* styleSheet = style->parentStyleSheet())
213             return root(styleSheet);
214         return style;
215     }
216
217     inline void* root(MediaList* mediaList)
218     {
219         if (CSSRule* parentRule = mediaList->parentRule())
220             return root(parentRule);
221         if (CSSStyleSheet* parentStyleSheet = mediaList->parentStyleSheet())
222             return root(parentStyleSheet);
223         return mediaList;
224     }
225
226     const JSC::HashTable* getHashTableForGlobalData(JSC::JSGlobalData&, const JSC::HashTable* staticTable);
227
228     void reportException(JSC::ExecState*, JSC::JSValue exception);
229     void reportCurrentException(JSC::ExecState*);
230
231     // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
232     void setDOMException(JSC::ExecState*, ExceptionCode);
233
234     JSC::JSValue jsString(JSC::ExecState*, const String&); // empty if the string is null
235     JSC::JSValue jsStringSlowCase(JSC::ExecState*, JSStringCache&, StringImpl*);
236     JSC::JSValue jsString(JSC::ExecState*, const KURL&); // empty if the URL is null
237     inline JSC::JSValue jsString(JSC::ExecState* exec, const AtomicString& s)
238     { 
239         return jsString(exec, s.string());
240     }
241         
242     JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
243     JSC::JSValue jsStringOrNull(JSC::ExecState*, const KURL&); // null if the URL is null
244
245     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
246     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const KURL&); // undefined if the URL is null
247
248     JSC::JSValue jsStringOrFalse(JSC::ExecState*, const String&); // boolean false if the string is null
249     JSC::JSValue jsStringOrFalse(JSC::ExecState*, const KURL&); // boolean false if the URL is null
250
251     // See JavaScriptCore for explanation: Should be used for any string that is already owned by another
252     // object, to let the engine know that collecting the JSString wrapper is unlikely to save memory.
253     JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const String&); 
254
255     String propertyNameToString(JSC::PropertyName);
256     String ustringToString(const JSC::UString&);
257     JSC::UString stringToUString(const String&);
258
259     AtomicString propertyNameToAtomicString(JSC::PropertyName);
260     AtomicString ustringToAtomicString(const JSC::UString&);
261     AtomicStringImpl* findAtomicString(JSC::PropertyName);
262
263     String valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null
264     String valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined
265
266     inline int32_t finiteInt32Value(JSC::JSValue value, JSC::ExecState* exec, bool& okay)
267     {
268         double number = value.toNumber(exec);
269         okay = isfinite(number);
270         return JSC::toInt32(number);
271     }
272
273     // Returns a Date instance for the specified value, or null if the value is NaN or infinity.
274     JSC::JSValue jsDateOrNull(JSC::ExecState*, double);
275     // NaN if the value can't be converted to a date.
276     double valueToDate(JSC::ExecState*, JSC::JSValue);
277
278     template <typename T>
279     inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr)
280     {
281         return toJS(exec, globalObject, ptr.get());
282     }
283
284     template <typename T, size_t inlineCapacity>
285     JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>& iterator)
286     {
287         JSC::MarkedArgumentBuffer list;
288         typename Vector<T, inlineCapacity>::const_iterator end = iterator.end();
289
290         for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
291             list.append(toJS(exec, globalObject, WTF::getPtr(*iter)));
292
293         return JSC::constructArray(exec, globalObject, list);
294     }
295
296     template<>
297     inline JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<String>& iterator)
298     {
299         JSC::MarkedArgumentBuffer array;
300         Vector<String>::const_iterator end = iterator.end();
301
302         for (Vector<String>::const_iterator it = iterator.begin(); it != end; ++it)
303             array.append(jsString(exec, stringToUString(*it)));
304
305         return JSC::constructArray(exec, globalObject, array);
306     }
307
308     template <class T>
309     Vector<T> toNativeArray(JSC::ExecState* exec, JSC::JSValue value)
310     {
311         if (!isJSArray(value))
312             return Vector<T>();
313
314         Vector<T> result;
315         JSC::JSArray* array = asArray(value);
316
317         for (unsigned i = 0; i < array->length(); ++i) {
318             String indexedValue = ustringToString(array->getIndex(i).toString(exec)->value(exec));
319             result.append(indexedValue);
320         }
321         return result;
322     }
323
324     // Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec.
325     JSC::JSObject* toJSSequence(JSC::ExecState*, JSC::JSValue, unsigned&);
326
327     // FIXME: Implement allowAccessToContext(JSC::ExecState*, ScriptExecutionContext*);
328     bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
329     bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*);
330     bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, String& message);
331     // FIXME: Implement allowAccessToDOMWindow(JSC::ExecState*, DOMWindow*);
332
333     // FIXME: Remove these functions in favor of activeContext and
334     // firstContext, which return ScriptExecutionContext*. We prefer to use
335     // ScriptExecutionContext* as the context object in the bindings.
336     DOMWindow* activeDOMWindow(JSC::ExecState*);
337     DOMWindow* firstDOMWindow(JSC::ExecState*);
338
339     void printErrorMessageForFrame(Frame*, const String& message);
340     JSC::JSValue objectToStringFunctionGetter(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);
341
342     inline JSC::JSValue jsString(JSC::ExecState* exec, const String& s)
343     {
344         StringImpl* stringImpl = s.impl();
345         if (!stringImpl || !stringImpl->length())
346             return jsEmptyString(exec);
347
348         if (stringImpl->length() == 1 && stringImpl->characters()[0] <= 0xFF)
349             return jsString(exec, stringToUString(s));
350
351         JSStringCache& stringCache = currentWorld(exec)->m_stringCache;
352         JSStringCache::iterator it = stringCache.find(stringImpl);
353         if (it != stringCache.end())
354             return it->second.get();
355
356         return jsStringSlowCase(exec, stringCache, stringImpl);
357     }
358
359     inline DOMObjectWrapperMap& domObjectWrapperMapFor(JSC::ExecState* exec)
360     {
361         return currentWorld(exec)->m_wrappers;
362     }
363
364     inline String ustringToString(const JSC::UString& u)
365     {
366         return u.impl();
367     }
368
369     inline JSC::UString stringToUString(const String& s)
370     {
371         return JSC::UString(s.impl());
372     }
373
374     inline String propertyNameToString(JSC::PropertyName propertyName)
375     {
376         return propertyName.publicName();
377     }
378
379     inline AtomicString ustringToAtomicString(const JSC::UString& u)
380     {
381         return AtomicString(u.impl());
382     }
383
384     inline AtomicString propertyNameToAtomicString(JSC::PropertyName propertyName)
385     {
386         return AtomicString(propertyName.publicName());
387     }
388
389     inline Vector<unsigned long> jsUnsignedLongArrayToVector(JSC::ExecState* exec, JSC::JSValue value)
390     {
391         unsigned length;
392         JSC::JSObject* object = toJSSequence(exec, value, length);
393         if (exec->hadException())
394             return Vector<unsigned long>();
395
396         Vector<unsigned long> result;
397         for (unsigned i = 0; i < length; i++) {
398             JSC::JSValue indexedValue;
399             indexedValue = object->get(exec, i);
400             if (exec->hadException() || indexedValue.isUndefinedOrNull() || !indexedValue.isNumber())
401                 return Vector<unsigned long>();
402             result.append(indexedValue.toUInt32(exec));
403         }
404         return result;
405     }
406 } // namespace WebCore
407
408 #endif // JSDOMBinding_h