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