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