2011-03-28 Oliver Hunt <oliver@apple.com>
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMBinding.cpp
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
4  *  Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "config.h"
22 #include "JSDOMBinding.h"
23
24 #include "debugger/DebuggerCallFrame.h"
25
26 #include "ActiveDOMObject.h"
27 #include "DOMCoreException.h"
28 #include "DOMObjectHashTableMap.h"
29 #include "Document.h"
30 #include "EventException.h"
31 #include "ExceptionBase.h"
32 #include "ExceptionCode.h"
33 #include "Frame.h"
34 #include "HTMLAudioElement.h"
35 #include "HTMLCanvasElement.h"
36 #include "HTMLFrameElementBase.h"
37 #include "HTMLImageElement.h"
38 #include "HTMLLinkElement.h"
39 #include "HTMLNames.h"
40 #include "HTMLScriptElement.h"
41 #include "HTMLStyleElement.h"
42 #include "JSDOMCoreException.h"
43 #include "JSDOMWindowCustom.h"
44 #include "JSEventException.h"
45 #include "JSExceptionBase.h"
46 #include "JSMainThreadExecState.h"
47 #include "JSNode.h"
48 #include "JSRangeException.h"
49 #include "JSXMLHttpRequestException.h"
50 #include "KURL.h"
51 #include "MessagePort.h"
52 #include "ProcessingInstruction.h"
53 #include "RangeException.h"
54 #include "ScriptCachedFrameData.h"
55 #include "ScriptCallStack.h"
56 #include "ScriptController.h"
57 #include "Settings.h"
58 #include "WebCoreJSClientData.h"
59 #include "XMLHttpRequestException.h"
60 #include <runtime/DateInstance.h>
61 #include <runtime/Error.h>
62 #include <runtime/JSFunction.h>
63 #include <wtf/MathExtras.h>
64 #include <wtf/StdLibExtras.h>
65
66 #if ENABLE(SVG)
67 #include "JSSVGException.h"
68 #include "SVGException.h"
69 #endif
70
71 #if ENABLE(XPATH)
72 #include "JSXPathException.h"
73 #include "XPathException.h"
74 #endif
75
76 #if ENABLE(DATABASE)
77 #include "JSSQLException.h"
78 #include "SQLException.h"
79 #endif
80
81 #if ENABLE(BLOB) || ENABLE(FILE_SYSTEM)
82 #include "FileException.h"
83 #include "JSFileException.h"
84 #endif
85
86 #if ENABLE(INDEXED_DATABASE)
87 #include "IDBDatabaseException.h"
88 #include "JSIDBDatabaseException.h"
89 #endif
90
91 using namespace JSC;
92
93 namespace WebCore {
94
95 using namespace HTMLNames;
96
97 typedef Document::JSWrapperCache JSWrapperCache;
98 typedef Document::JSWrapperCacheMap JSWrapperCacheMap;
99
100 class JSGlobalDataWorldIterator {
101 public:
102     JSGlobalDataWorldIterator(JSGlobalData* globalData)
103         : m_pos(static_cast<WebCoreJSClientData*>(globalData->clientData)->m_worldSet.begin())
104         , m_end(static_cast<WebCoreJSClientData*>(globalData->clientData)->m_worldSet.end())
105     {
106     }
107
108     operator bool()
109     {
110         return m_pos != m_end;
111     }
112
113     DOMWrapperWorld* operator*()
114     {
115         ASSERT(m_pos != m_end);
116         return *m_pos;
117     }
118
119     DOMWrapperWorld* operator->()
120     {
121         ASSERT(m_pos != m_end);
122         return *m_pos;
123     }
124
125     JSGlobalDataWorldIterator& operator++()
126     {
127         ++m_pos;
128         return *this;
129     }
130
131 private:
132     HashSet<DOMWrapperWorld*>::iterator m_pos;
133     HashSet<DOMWrapperWorld*>::iterator m_end;
134 };
135
136 const JSC::HashTable* getHashTableForGlobalData(JSGlobalData& globalData, const JSC::HashTable* staticTable)
137 {
138     return DOMObjectHashTableMap::mapFor(globalData).get(staticTable);
139 }
140
141 bool hasCachedDOMObjectWrapperUnchecked(JSGlobalData* globalData, void* objectHandle)
142 {
143     for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
144         if (worldIter->m_wrappers.get(objectHandle))
145             return true;
146     }
147     return false;
148 }
149
150 bool hasCachedDOMObjectWrapper(JSGlobalData* globalData, void* objectHandle)
151 {
152     for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
153         if (worldIter->m_wrappers.get(objectHandle))
154             return true;
155     }
156     return false;
157 }
158
159 DOMObject* getCachedDOMObjectWrapper(JSC::ExecState* exec, void* objectHandle) 
160 {
161     return domObjectWrapperMapFor(exec).get(objectHandle);
162 }
163
164 void cacheDOMObjectWrapper(JSC::ExecState* exec, void* objectHandle, DOMObject* wrapper) 
165 {
166     domObjectWrapperMapFor(exec).set(exec->globalData(), objectHandle, wrapper);
167 }
168
169 bool hasCachedDOMNodeWrapperUnchecked(Document* document, Node* node)
170 {
171     if (!document)
172         return hasCachedDOMObjectWrapperUnchecked(JSDOMWindow::commonJSGlobalData(), node);
173
174     JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
175     for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
176         if (iter->second->get(node))
177             return true;
178     }
179     return false;
180 }
181
182 void cacheDOMNodeWrapper(JSC::ExecState* exec, Document* document, Node* node, JSNode* wrapper)
183 {
184     if (!document)
185         domObjectWrapperMapFor(exec).set(exec->globalData(), node, wrapper);
186     else
187         document->getWrapperCache(currentWorld(exec))->set(exec->globalData(), node, wrapper);
188
189     if (currentWorld(exec)->isNormal())
190         node->setWrapper(exec->globalData(), wrapper);
191 }
192
193 static inline bool isObservableThroughDOM(JSNode* jsNode, DOMWrapperWorld* world)
194 {
195     // Certain conditions implicitly make existence of a JS DOM node wrapper observable
196     // through the DOM, even if no explicit reference to it remains.
197
198     Node* node = jsNode->impl();
199
200     if (node->inDocument()) {
201         // If a node is in the document, and its wrapper has custom properties,
202         // the wrapper is observable because future access to the node through the
203         // DOM must reflect those properties.
204         if (jsNode->hasCustomProperties())
205             return true;
206
207         // If a node is in the document, and has event listeners, its wrapper is
208         // observable because its wrapper is responsible for marking those event listeners.
209         if (node->hasEventListeners())
210             return true; // Technically, we may overzealously mark a wrapper for a node that has only non-JS event listeners. Oh well.
211
212         // If a node owns another object with a wrapper with custom properties,
213         // the wrapper must be treated as observable, because future access to
214         // those objects through the DOM must reflect those properties.
215         // FIXME: It would be better if this logic could be in the node next to
216         // the custom markChildren functions rather than here.
217         // Note that for some compound objects like stylesheets and CSSStyleDeclarations,
218         // we don't descend to check children for custom properties, and just conservatively
219         // keep the node wrappers protecting them alive.
220         if (node->isElementNode()) {
221             if (NamedNodeMap* attributes = static_cast<Element*>(node)->attributeMap()) {
222                 if (DOMObject* wrapper = world->m_wrappers.get(attributes)) {
223                     // FIXME: This check seems insufficient, because NamedNodeMap items can have custom properties themselves.
224                     // Maybe it would be OK to just keep the wrapper alive, as it is done for CSSOM objects below.
225                     if (wrapper->hasCustomProperties())
226                         return true;
227                 }
228             }
229             if (node->isStyledElement()) {
230                 if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) {
231                     if (world->m_wrappers.get(style))
232                         return true;
233                 }
234             }
235             if (static_cast<Element*>(node)->hasTagName(canvasTag)) {
236                 if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) {
237                     if (DOMObject* wrapper = world->m_wrappers.get(context)) {
238                         if (wrapper->hasCustomProperties())
239                             return true;
240                     }
241                 }
242             } else if (static_cast<Element*>(node)->hasTagName(linkTag)) {
243                 if (StyleSheet* sheet = static_cast<HTMLLinkElement*>(node)->sheet()) {
244                     if (world->m_wrappers.get(sheet))
245                         return true;
246                 }
247             } else if (static_cast<Element*>(node)->hasTagName(styleTag)) {
248                 if (StyleSheet* sheet = static_cast<HTMLStyleElement*>(node)->sheet()) {
249                     if (world->m_wrappers.get(sheet))
250                         return true;
251                 }
252             }
253         } else if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
254             if (StyleSheet* sheet = static_cast<ProcessingInstruction*>(node)->sheet()) {
255                 if (world->m_wrappers.get(sheet))
256                     return true;
257             }
258         }
259     } else {
260         // If a wrapper is the last reference to an image or script element
261         // that is loading but not in the document, the wrapper is observable
262         // because it is the only thing keeping the image element alive, and if
263         // the image element is destroyed, its load event will not fire.
264         // FIXME: The DOM should manage this issue without the help of JavaScript wrappers.
265         if (node->hasTagName(imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())
266             return true;
267         if (node->hasTagName(scriptTag) && !static_cast<HTMLScriptElement*>(node)->haveFiredLoadEvent())
268             return true;
269 #if ENABLE(VIDEO)
270         if (node->hasTagName(audioTag) && !static_cast<HTMLAudioElement*>(node)->paused())
271             return true;
272 #endif
273     }
274
275     // If a node is firing event listeners, its wrapper is observable because
276     // its wrapper is responsible for marking those event listeners.
277     if (node->isFiringEventListeners())
278         return true;
279
280     return false;
281 }
282
283 void markDOMNodesForDocument(MarkStack& markStack, Document* document)
284 {
285     JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
286     for (JSWrapperCacheMap::iterator wrappersIter = wrapperCacheMap.begin(); wrappersIter != wrapperCacheMap.end(); ++wrappersIter) {
287         DOMWrapperWorld* world = wrappersIter->first;
288         JSWrapperCache* nodeDict = wrappersIter->second;
289
290         JSWrapperCache::iterator nodeEnd = nodeDict->end();
291         for (JSWrapperCache::iterator nodeIt = nodeDict->begin(); nodeIt != nodeEnd; ++nodeIt) {
292             if (isObservableThroughDOM(nodeIt.get().second, world))
293                 markStack.deprecatedAppend(nodeIt.getSlot().second);
294         }
295     }
296 }
297
298 void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData, ScriptExecutionContext* scriptExecutionContext)
299 {
300     // If an element has pending activity that may result in event listeners being called
301     // (e.g. an XMLHttpRequest), we need to keep JS wrappers alive.
302
303     const HashMap<ActiveDOMObject*, void*>& activeObjects = scriptExecutionContext->activeDOMObjects();
304     HashMap<ActiveDOMObject*, void*>::const_iterator activeObjectsEnd = activeObjects.end();
305     for (HashMap<ActiveDOMObject*, void*>::const_iterator iter = activeObjects.begin(); iter != activeObjectsEnd; ++iter) {
306         if (iter->first->hasPendingActivity()) {
307             // Generally, an active object with pending activity must have a wrapper to mark its listeners.
308             // However, some ActiveDOMObjects don't have JS wrappers.
309             markDOMObjectWrapper(markStack, globalData, iter->second);
310         }
311     }
312
313     const HashSet<MessagePort*>& messagePorts = scriptExecutionContext->messagePorts();
314     HashSet<MessagePort*>::const_iterator portsEnd = messagePorts.end();
315     for (HashSet<MessagePort*>::const_iterator iter = messagePorts.begin(); iter != portsEnd; ++iter) {
316         // If the message port is remotely entangled, then always mark it as in-use because we can't determine reachability across threads.
317         if (!(*iter)->locallyEntangledPort() || (*iter)->hasPendingActivity())
318             markDOMObjectWrapper(markStack, globalData, *iter);
319     }
320 }
321
322 typedef std::pair<JSNode*, DOMWrapperWorld*> WrapperAndWorld;
323 typedef WTF::Vector<WrapperAndWorld, 8> WrapperSet;
324
325 static inline void takeWrappers(Node* node, Document* document, WrapperSet& wrapperSet)
326 {
327     if (document) {
328         JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
329         for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
330             if (JSNode* wrapper = iter->second->take(node))
331                 wrapperSet.append(WrapperAndWorld(wrapper, iter->first));
332         }
333     } else {
334         for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {
335             DOMWrapperWorld* world = *worldIter;
336             if (JSNode* wrapper = static_cast<JSNode*>(world->m_wrappers.take(node)))
337                 wrapperSet.append(WrapperAndWorld(wrapper, world));
338         }
339     }
340 }
341
342 void updateDOMNodeDocument(Node* node, Document* oldDocument, Document* newDocument)
343 {
344     ASSERT(oldDocument != newDocument);
345
346     WrapperSet wrapperSet;
347     takeWrappers(node, oldDocument, wrapperSet);
348
349     for (unsigned i = 0; i < wrapperSet.size(); ++i) {
350         JSNode* wrapper = wrapperSet[i].first;
351         if (newDocument)
352             newDocument->getWrapperCache(wrapperSet[i].second)->set(*wrapperSet[i].second->globalData(), node, wrapper);
353         else
354             wrapperSet[i].second->m_wrappers.set(*wrapperSet[i].second->globalData(), node, wrapper);
355     }
356 }
357
358 void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void* object)
359 {
360     // FIXME: This could be changed to only mark wrappers that are "observable"
361     // as markDOMNodesForDocument does, allowing us to collect more wrappers,
362     // but doing this correctly would be challenging.
363     if (!object)
364         return;
365
366     for (JSGlobalDataWorldIterator worldIter(&globalData); worldIter; ++worldIter) {
367         if (HandleSlot wrapperSlot = worldIter->m_wrappers.getSlot(object))
368             markStack.deprecatedAppend(wrapperSlot);
369     }
370 }
371
372 void markDOMNodeWrapper(MarkStack& markStack, Document* document, Node* node)
373 {
374     if (document) {
375         JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
376         for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
377             if (HandleSlot wrapperSlot = iter->second->getSlot(node))
378                 markStack.deprecatedAppend(wrapperSlot);
379         }
380         return;
381     }
382
383     for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {
384         if (HandleSlot wrapperSlot = worldIter->m_wrappers.getSlot(node))
385             markStack.deprecatedAppend(wrapperSlot);
386     }
387 }
388
389 static void stringWrapperDestroyed(JSString*, void* context)
390 {
391     StringImpl* cacheKey = static_cast<StringImpl*>(context);
392     cacheKey->deref();
393 }
394
395 JSValue jsStringSlowCase(ExecState* exec, JSStringCache& stringCache, StringImpl* stringImpl)
396 {
397     JSString* wrapper = jsStringWithFinalizer(exec, UString(stringImpl), stringWrapperDestroyed, stringImpl);
398     stringCache.set(exec->globalData(), stringImpl, wrapper);
399     // ref explicitly instead of using a RefPtr-keyed hashtable because the wrapper can
400     // outlive the cache, so the stringImpl has to match the wrapper's lifetime.
401     stringImpl->ref();
402     return wrapper;
403 }
404
405 JSValue jsStringOrNull(ExecState* exec, const String& s)
406 {
407     if (s.isNull())
408         return jsNull();
409     return jsString(exec, s);
410 }
411
412 JSValue jsOwnedStringOrNull(ExecState* exec, const String& s)
413 {
414     if (s.isNull())
415         return jsNull();
416     return jsOwnedString(exec, stringToUString(s));
417 }
418
419 JSValue jsStringOrUndefined(ExecState* exec, const String& s)
420 {
421     if (s.isNull())
422         return jsUndefined();
423     return jsString(exec, s);
424 }
425
426 JSValue jsStringOrFalse(ExecState* exec, const String& s)
427 {
428     if (s.isNull())
429         return jsBoolean(false);
430     return jsString(exec, s);
431 }
432
433 JSValue jsString(ExecState* exec, const KURL& url)
434 {
435     return jsString(exec, url.string());
436 }
437
438 JSValue jsStringOrNull(ExecState* exec, const KURL& url)
439 {
440     if (url.isNull())
441         return jsNull();
442     return jsString(exec, url.string());
443 }
444
445 JSValue jsStringOrUndefined(ExecState* exec, const KURL& url)
446 {
447     if (url.isNull())
448         return jsUndefined();
449     return jsString(exec, url.string());
450 }
451
452 JSValue jsStringOrFalse(ExecState* exec, const KURL& url)
453 {
454     if (url.isNull())
455         return jsBoolean(false);
456     return jsString(exec, url.string());
457 }
458
459 AtomicStringImpl* findAtomicString(const Identifier& identifier)
460 {
461     if (identifier.isNull())
462         return 0;
463     StringImpl* impl = identifier.impl();
464     ASSERT(impl->existingHash());
465     return AtomicString::find(impl->characters(), impl->length(), impl->existingHash());
466 }
467
468 String valueToStringWithNullCheck(ExecState* exec, JSValue value)
469 {
470     if (value.isNull())
471         return String();
472     return ustringToString(value.toString(exec));
473 }
474
475 String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value)
476 {
477     if (value.isUndefinedOrNull())
478         return String();
479     return ustringToString(value.toString(exec));
480 }
481
482 JSValue jsDateOrNull(ExecState* exec, double value)
483 {
484     if (!isfinite(value))
485         return jsNull();
486     return new (exec) DateInstance(exec, exec->lexicalGlobalObject()->dateStructure(), value);
487 }
488
489 double valueToDate(ExecState* exec, JSValue value)
490 {
491     if (value.isNumber())
492         return value.uncheckedGetNumber();
493     if (!value.inherits(&DateInstance::s_info))
494         return std::numeric_limits<double>::quiet_NaN();
495     return static_cast<DateInstance*>(value.toObject(exec))->internalNumber();
496 }
497
498 void reportException(ExecState* exec, JSValue exception)
499 {
500     if (exception.isObject() && asObject(exception)->exceptionType() == Terminated)
501         return;
502
503     UString errorMessage = exception.toString(exec);
504     JSObject* exceptionObject = exception.toObject(exec);
505     int lineNumber = exceptionObject->get(exec, Identifier(exec, "line")).toInt32(exec);
506     UString exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL")).toString(exec);
507     exec->clearException();
508
509     if (ExceptionBase* exceptionBase = toExceptionBase(exception))
510         errorMessage = stringToUString(exceptionBase->message() + ": "  + exceptionBase->description());
511
512     ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();
513     ASSERT(scriptExecutionContext);
514
515     // Crash data indicates null-dereference crashes at this point in the Safari 4 Public Beta.
516     // It's harmless to return here without reporting the exception to the log and the debugger in this case.
517     if (!scriptExecutionContext)
518         return;
519
520     scriptExecutionContext->reportException(ustringToString(errorMessage), lineNumber, ustringToString(exceptionSourceURL), 0);
521 }
522
523 void reportCurrentException(ExecState* exec)
524 {
525     JSValue exception = exec->exception();
526     exec->clearException();
527     reportException(exec, exception);
528 }
529
530 void setDOMException(ExecState* exec, ExceptionCode ec)
531 {
532     if (!ec || exec->hadException())
533         return;
534
535     // FIXME: All callers to setDOMException need to pass in the right global object
536     // for now, we're going to assume the lexicalGlobalObject.  Which is wrong in cases like this:
537     // frames[0].document.createElement(null, null); // throws an exception which should have the subframes prototypes.
538     JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(exec);
539
540     ExceptionCodeDescription description;
541     getExceptionCodeDescription(ec, description);
542
543     JSValue errorObject;
544     switch (description.type) {
545         case DOMExceptionType:
546             errorObject = toJS(exec, globalObject, DOMCoreException::create(description));
547             break;
548         case RangeExceptionType:
549             errorObject = toJS(exec, globalObject, RangeException::create(description));
550             break;
551         case EventExceptionType:
552             errorObject = toJS(exec, globalObject, EventException::create(description));
553             break;
554         case XMLHttpRequestExceptionType:
555             errorObject = toJS(exec, globalObject, XMLHttpRequestException::create(description));
556             break;
557 #if ENABLE(SVG)
558         case SVGExceptionType:
559             errorObject = toJS(exec, globalObject, SVGException::create(description).get());
560             break;
561 #endif
562 #if ENABLE(XPATH)
563         case XPathExceptionType:
564             errorObject = toJS(exec, globalObject, XPathException::create(description));
565             break;
566 #endif
567 #if ENABLE(DATABASE)
568         case SQLExceptionType:
569             errorObject = toJS(exec, globalObject, SQLException::create(description));
570             break;
571 #endif
572 #if ENABLE(BLOB) || ENABLE(FILE_SYSTEM)
573         case FileExceptionType:
574             errorObject = toJS(exec, globalObject, FileException::create(description));
575             break;
576 #endif
577 #if ENABLE(INDEXED_DATABASE)
578         case IDBDatabaseExceptionType:
579             errorObject = toJS(exec, globalObject, IDBDatabaseException::create(description));
580             break;
581 #endif
582     }
583
584     ASSERT(errorObject);
585     throwError(exec, errorObject);
586 }
587
588 DOMWindow* activeDOMWindow(ExecState* exec)
589 {
590     return asJSDOMWindow(exec->lexicalGlobalObject())->impl();
591 }
592
593 DOMWindow* firstDOMWindow(ExecState* exec)
594 {
595     return asJSDOMWindow(exec->dynamicGlobalObject())->impl();
596 }
597
598 bool checkNodeSecurity(ExecState* exec, Node* node)
599 {
600     return node && allowsAccessFromFrame(exec, node->document()->frame());
601 }
602
603 bool allowsAccessFromFrame(ExecState* exec, Frame* frame)
604 {
605     if (!frame)
606         return false;
607     JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
608     return window && window->allowsAccessFrom(exec);
609 }
610
611 bool allowsAccessFromFrame(ExecState* exec, Frame* frame, String& message)
612 {
613     if (!frame)
614         return false;
615     JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
616     return window && window->allowsAccessFrom(exec, message);
617 }
618
619 void printErrorMessageForFrame(Frame* frame, const String& message)
620 {
621     if (!frame)
622         return;
623     frame->domWindow()->printErrorMessage(message);
624 }
625
626 // FIXME: We should remove or at least deprecate this function. Callers can use firstDOMWindow directly.
627 Frame* toDynamicFrame(ExecState* exec)
628 {
629     return firstDOMWindow(exec)->frame();
630 }
631
632 // FIXME: We should remove this function. Callers can use ScriptController directly.
633 bool processingUserGesture()
634 {
635     return ScriptController::processingUserGesture();
636 }
637
638 JSValue objectToStringFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName)
639 {
640     return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), 0, propertyName, objectProtoFuncToString);
641 }
642
643 Structure* getCachedDOMStructure(JSDOMGlobalObject* globalObject, const ClassInfo* classInfo)
644 {
645     JSDOMStructureMap& structures = globalObject->structures();
646     return structures.get(classInfo).get();
647 }
648
649 Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, const ClassInfo* classInfo)
650 {
651     JSDOMStructureMap& structures = globalObject->structures();
652     ASSERT(!structures.contains(classInfo));
653     return structures.set(classInfo, structure).first->second.get();
654 }
655
656 JSC::JSObject* toJSSequence(ExecState* exec, JSValue value, unsigned& length)
657 {
658     JSObject* object = value.getObject();
659     if (!object) {
660         throwTypeError(exec);
661         return 0;
662     }
663     JSValue lengthValue = object->get(exec, exec->propertyNames().length);
664     if (exec->hadException())
665         return 0;
666
667     if (lengthValue.isUndefinedOrNull()) {
668         throwTypeError(exec);
669         return 0;
670     }
671
672     length = lengthValue.toUInt32(exec);
673     if (exec->hadException())
674         return 0;
675
676     return object;
677 }
678
679 } // namespace WebCore