2011-04-13 Geoffrey Garen <ggaren@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).get();
162 }
163
164 void cacheDOMObjectWrapper(JSC::ExecState* exec, void* objectHandle, DOMObject* wrapper) 
165 {
166     DOMWrapperWorld* world = currentWorld(exec);
167     world->m_wrappers.set(objectHandle, Weak<DOMObject>(*world->globalData(), wrapper, world->domObjectHandleOwner()));
168 }
169
170 bool hasCachedDOMNodeWrapperUnchecked(Document* document, Node* node)
171 {
172     if (!document)
173         return hasCachedDOMObjectWrapperUnchecked(JSDOMWindow::commonJSGlobalData(), node);
174
175     JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
176     for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
177         if (iter->second->get(node))
178             return true;
179     }
180     return false;
181 }
182
183 void cacheDOMNodeWrapper(JSC::ExecState* exec, Document* document, Node* node, JSNode* wrapper)
184 {
185     ASSERT(wrapper);
186     if (!document)
187         cacheDOMObjectWrapper(exec, node, wrapper);
188     else
189         document->getWrapperCache(currentWorld(exec))->set(node, Weak<JSNode>(exec->globalData(), wrapper, currentWorld(exec)->jsNodeHandleOwner()));
190
191     if (currentWorld(exec)->isNormal()) {
192         node->setWrapper(exec->globalData(), wrapper);
193         ASSERT(node->wrapper() == (document ? document->getWrapperCache(currentWorld(exec))->get(node).get() : domObjectWrapperMapFor(exec).get(node).get()));
194     }
195 }
196
197 static inline bool isObservableThroughDOM(JSNode* jsNode, DOMWrapperWorld* world)
198 {
199     // Certain conditions implicitly make existence of a JS DOM node wrapper observable
200     // through the DOM, even if no explicit reference to it remains.
201
202     Node* node = jsNode->impl();
203
204     if (node->inDocument()) {
205         // If a node is in the document, and its wrapper has custom properties,
206         // the wrapper is observable because future access to the node through the
207         // DOM must reflect those properties.
208         if (jsNode->hasCustomProperties())
209             return true;
210
211         // If a node is in the document, and has event listeners, its wrapper is
212         // observable because its wrapper is responsible for marking those event listeners.
213         if (node->hasEventListeners())
214             return true; // Technically, we may overzealously mark a wrapper for a node that has only non-JS event listeners. Oh well.
215
216         // If a node owns another object with a wrapper with custom properties,
217         // the wrapper must be treated as observable, because future access to
218         // those objects through the DOM must reflect those properties.
219         // FIXME: It would be better if this logic could be in the node next to
220         // the custom markChildren functions rather than here.
221         // Note that for some compound objects like stylesheets and CSSStyleDeclarations,
222         // we don't descend to check children for custom properties, and just conservatively
223         // keep the node wrappers protecting them alive.
224         if (node->isElementNode()) {
225             if (NamedNodeMap* attributes = static_cast<Element*>(node)->attributeMap()) {
226                 if (DOMObject* wrapper = world->m_wrappers.get(attributes).get()) {
227                     // FIXME: This check seems insufficient, because NamedNodeMap items can have custom properties themselves.
228                     // Maybe it would be OK to just keep the wrapper alive, as it is done for CSSOM objects below.
229                     if (wrapper->hasCustomProperties())
230                         return true;
231                 }
232             }
233             if (node->isStyledElement()) {
234                 if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) {
235                     if (world->m_wrappers.get(style))
236                         return true;
237                 }
238             }
239             if (static_cast<Element*>(node)->hasTagName(canvasTag)) {
240                 if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) {
241                     if (DOMObject* wrapper = world->m_wrappers.get(context).get()) {
242                         if (wrapper->hasCustomProperties())
243                             return true;
244                     }
245                 }
246             } else if (static_cast<Element*>(node)->hasTagName(linkTag)) {
247                 if (StyleSheet* sheet = static_cast<HTMLLinkElement*>(node)->sheet()) {
248                     if (world->m_wrappers.get(sheet))
249                         return true;
250                 }
251             } else if (static_cast<Element*>(node)->hasTagName(styleTag)) {
252                 if (StyleSheet* sheet = static_cast<HTMLStyleElement*>(node)->sheet()) {
253                     if (world->m_wrappers.get(sheet))
254                         return true;
255                 }
256             }
257         } else if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
258             if (StyleSheet* sheet = static_cast<ProcessingInstruction*>(node)->sheet()) {
259                 if (world->m_wrappers.get(sheet))
260                     return true;
261             }
262         }
263     } else {
264         // If a wrapper is the last reference to an image or script element
265         // that is loading but not in the document, the wrapper is observable
266         // because it is the only thing keeping the image element alive, and if
267         // the image element is destroyed, its load event will not fire.
268         // FIXME: The DOM should manage this issue without the help of JavaScript wrappers.
269         if (node->hasTagName(imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())
270             return true;
271         if (node->hasTagName(scriptTag) && !static_cast<HTMLScriptElement*>(node)->haveFiredLoadEvent())
272             return true;
273 #if ENABLE(VIDEO)
274         if (node->hasTagName(audioTag) && !static_cast<HTMLAudioElement*>(node)->paused())
275             return true;
276 #endif
277     }
278
279     // If a node is firing event listeners, its wrapper is observable because
280     // its wrapper is responsible for marking those event listeners.
281     if (node->isFiringEventListeners())
282         return true;
283
284     return false;
285 }
286
287 void markDOMNodesForDocument(MarkStack& markStack, Document* document)
288 {
289     JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
290     for (JSWrapperCacheMap::iterator wrappersIter = wrapperCacheMap.begin(); wrappersIter != wrapperCacheMap.end(); ++wrappersIter) {
291         DOMWrapperWorld* world = wrappersIter->first;
292         JSWrapperCache* nodeDict = wrappersIter->second;
293
294         JSWrapperCache::iterator nodeEnd = nodeDict->end();
295         for (JSWrapperCache::iterator nodeIt = nodeDict->begin(); nodeIt != nodeEnd; ++nodeIt) {
296             JSNode* node = nodeIt->second.get();
297             if (!isObservableThroughDOM(node, world))
298                 continue;
299             markStack.deprecatedAppend(reinterpret_cast<JSCell**>(&node));
300         }
301     }
302 }
303
304 void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData, ScriptExecutionContext* scriptExecutionContext)
305 {
306     // If an element has pending activity that may result in event listeners being called
307     // (e.g. an XMLHttpRequest), we need to keep JS wrappers alive.
308
309     const HashMap<ActiveDOMObject*, void*>& activeObjects = scriptExecutionContext->activeDOMObjects();
310     HashMap<ActiveDOMObject*, void*>::const_iterator activeObjectsEnd = activeObjects.end();
311     for (HashMap<ActiveDOMObject*, void*>::const_iterator iter = activeObjects.begin(); iter != activeObjectsEnd; ++iter) {
312         if (iter->first->hasPendingActivity()) {
313             // Generally, an active object with pending activity must have a wrapper to mark its listeners.
314             // However, some ActiveDOMObjects don't have JS wrappers.
315             markDOMObjectWrapper(markStack, globalData, iter->second);
316         }
317     }
318
319     const HashSet<MessagePort*>& messagePorts = scriptExecutionContext->messagePorts();
320     HashSet<MessagePort*>::const_iterator portsEnd = messagePorts.end();
321     for (HashSet<MessagePort*>::const_iterator iter = messagePorts.begin(); iter != portsEnd; ++iter) {
322         // If the message port is remotely entangled, then always mark it as in-use because we can't determine reachability across threads.
323         if (!(*iter)->locallyEntangledPort() || (*iter)->hasPendingActivity())
324             markDOMObjectWrapper(markStack, globalData, *iter);
325     }
326 }
327
328 typedef std::pair<JSNode*, DOMWrapperWorld*> WrapperAndWorld;
329 typedef WTF::Vector<WrapperAndWorld, 8> WrapperSet;
330
331 static inline void takeWrappers(Node* node, Document* document, WrapperSet& wrapperSet)
332 {
333     if (document) {
334         JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
335         for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
336             JSNode* wrapper = iter->second->take(node).get();
337             if (!wrapper)
338                 continue;
339             wrapperSet.append(WrapperAndWorld(wrapper, iter->first));
340         }
341     } else {
342         for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {
343             DOMWrapperWorld* world = *worldIter;
344             if (JSNode* wrapper = static_cast<JSNode*>(world->m_wrappers.take(node).get()))
345                 wrapperSet.append(WrapperAndWorld(wrapper, world));
346         }
347     }
348 }
349
350 void updateDOMNodeDocument(Node* node, Document* oldDocument, Document* newDocument)
351 {
352     ASSERT(oldDocument != newDocument);
353
354     WrapperSet wrapperSet;
355     takeWrappers(node, oldDocument, wrapperSet);
356
357     for (unsigned i = 0; i < wrapperSet.size(); ++i) {
358         JSNode* wrapper = wrapperSet[i].first;
359         if (newDocument)
360             newDocument->getWrapperCache(wrapperSet[i].second)->set(node, Weak<JSNode>(*wrapperSet[i].second->globalData(), wrapper, wrapperSet[i].second->jsNodeHandleOwner()));
361         else
362             wrapperSet[i].second->m_wrappers.set(node, Weak<DOMObject>(*wrapperSet[i].second->globalData(), wrapper, wrapperSet[i].second->domObjectHandleOwner()));
363     }
364 }
365
366 void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void* object)
367 {
368     // FIXME: This could be changed to only mark wrappers that are "observable"
369     // as markDOMNodesForDocument does, allowing us to collect more wrappers,
370     // but doing this correctly would be challenging.
371     if (!object)
372         return;
373
374     for (JSGlobalDataWorldIterator worldIter(&globalData); worldIter; ++worldIter) {
375         if (DOMObject* wrapper = worldIter->m_wrappers.get(object).get())
376             markStack.deprecatedAppend(reinterpret_cast<JSCell**>(&wrapper));
377     }
378 }
379
380 void markDOMNodeWrapper(MarkStack& markStack, Document* document, Node* node)
381 {
382     if (document) {
383         JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
384         for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
385             JSNode* wrapper = iter->second->get(node).get();
386             if (!wrapper)
387                 continue;
388             markStack.deprecatedAppend(reinterpret_cast<JSCell**>(&wrapper));
389         }
390         return;
391     }
392
393     for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {
394         if (DOMObject* wrapper = worldIter->m_wrappers.get(node).get())
395             markStack.deprecatedAppend(reinterpret_cast<JSCell**>(&wrapper));
396     }
397 }
398
399 static void stringWrapperDestroyed(JSString*, void* context)
400 {
401     StringImpl* cacheKey = static_cast<StringImpl*>(context);
402     cacheKey->deref();
403 }
404
405 JSValue jsStringSlowCase(ExecState* exec, JSStringCache& stringCache, StringImpl* stringImpl)
406 {
407     JSString* wrapper = jsStringWithFinalizer(exec, UString(stringImpl), stringWrapperDestroyed, stringImpl);
408     stringCache.set(exec->globalData(), stringImpl, wrapper);
409     // ref explicitly instead of using a RefPtr-keyed hashtable because the wrapper can
410     // outlive the cache, so the stringImpl has to match the wrapper's lifetime.
411     stringImpl->ref();
412     return wrapper;
413 }
414
415 JSValue jsStringOrNull(ExecState* exec, const String& s)
416 {
417     if (s.isNull())
418         return jsNull();
419     return jsString(exec, s);
420 }
421
422 JSValue jsOwnedStringOrNull(ExecState* exec, const String& s)
423 {
424     if (s.isNull())
425         return jsNull();
426     return jsOwnedString(exec, stringToUString(s));
427 }
428
429 JSValue jsStringOrUndefined(ExecState* exec, const String& s)
430 {
431     if (s.isNull())
432         return jsUndefined();
433     return jsString(exec, s);
434 }
435
436 JSValue jsStringOrFalse(ExecState* exec, const String& s)
437 {
438     if (s.isNull())
439         return jsBoolean(false);
440     return jsString(exec, s);
441 }
442
443 JSValue jsString(ExecState* exec, const KURL& url)
444 {
445     return jsString(exec, url.string());
446 }
447
448 JSValue jsStringOrNull(ExecState* exec, const KURL& url)
449 {
450     if (url.isNull())
451         return jsNull();
452     return jsString(exec, url.string());
453 }
454
455 JSValue jsStringOrUndefined(ExecState* exec, const KURL& url)
456 {
457     if (url.isNull())
458         return jsUndefined();
459     return jsString(exec, url.string());
460 }
461
462 JSValue jsStringOrFalse(ExecState* exec, const KURL& url)
463 {
464     if (url.isNull())
465         return jsBoolean(false);
466     return jsString(exec, url.string());
467 }
468
469 AtomicStringImpl* findAtomicString(const Identifier& identifier)
470 {
471     if (identifier.isNull())
472         return 0;
473     StringImpl* impl = identifier.impl();
474     ASSERT(impl->existingHash());
475     return AtomicString::find(impl->characters(), impl->length(), impl->existingHash());
476 }
477
478 String valueToStringWithNullCheck(ExecState* exec, JSValue value)
479 {
480     if (value.isNull())
481         return String();
482     return ustringToString(value.toString(exec));
483 }
484
485 String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value)
486 {
487     if (value.isUndefinedOrNull())
488         return String();
489     return ustringToString(value.toString(exec));
490 }
491
492 JSValue jsDateOrNull(ExecState* exec, double value)
493 {
494     if (!isfinite(value))
495         return jsNull();
496     return new (exec) DateInstance(exec, exec->lexicalGlobalObject()->dateStructure(), value);
497 }
498
499 double valueToDate(ExecState* exec, JSValue value)
500 {
501     if (value.isNumber())
502         return value.uncheckedGetNumber();
503     if (!value.inherits(&DateInstance::s_info))
504         return std::numeric_limits<double>::quiet_NaN();
505     return static_cast<DateInstance*>(value.toObject(exec))->internalNumber();
506 }
507
508 void reportException(ExecState* exec, JSValue exception)
509 {
510     if (exception.isObject() && asObject(exception)->exceptionType() == Terminated)
511         return;
512
513     UString errorMessage = exception.toString(exec);
514     JSObject* exceptionObject = exception.toObject(exec);
515     int lineNumber = exceptionObject->get(exec, Identifier(exec, "line")).toInt32(exec);
516     UString exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL")).toString(exec);
517     exec->clearException();
518
519     if (ExceptionBase* exceptionBase = toExceptionBase(exception))
520         errorMessage = stringToUString(exceptionBase->message() + ": "  + exceptionBase->description());
521
522     ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();
523     ASSERT(scriptExecutionContext);
524
525     // Crash data indicates null-dereference crashes at this point in the Safari 4 Public Beta.
526     // It's harmless to return here without reporting the exception to the log and the debugger in this case.
527     if (!scriptExecutionContext)
528         return;
529
530     scriptExecutionContext->reportException(ustringToString(errorMessage), lineNumber, ustringToString(exceptionSourceURL), 0);
531 }
532
533 void reportCurrentException(ExecState* exec)
534 {
535     JSValue exception = exec->exception();
536     exec->clearException();
537     reportException(exec, exception);
538 }
539
540 void setDOMException(ExecState* exec, ExceptionCode ec)
541 {
542     if (!ec || exec->hadException())
543         return;
544
545     // FIXME: All callers to setDOMException need to pass in the right global object
546     // for now, we're going to assume the lexicalGlobalObject.  Which is wrong in cases like this:
547     // frames[0].document.createElement(null, null); // throws an exception which should have the subframes prototypes.
548     JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(exec);
549
550     ExceptionCodeDescription description;
551     getExceptionCodeDescription(ec, description);
552
553     JSValue errorObject;
554     switch (description.type) {
555         case DOMExceptionType:
556             errorObject = toJS(exec, globalObject, DOMCoreException::create(description));
557             break;
558         case RangeExceptionType:
559             errorObject = toJS(exec, globalObject, RangeException::create(description));
560             break;
561         case EventExceptionType:
562             errorObject = toJS(exec, globalObject, EventException::create(description));
563             break;
564         case XMLHttpRequestExceptionType:
565             errorObject = toJS(exec, globalObject, XMLHttpRequestException::create(description));
566             break;
567 #if ENABLE(SVG)
568         case SVGExceptionType:
569             errorObject = toJS(exec, globalObject, SVGException::create(description).get());
570             break;
571 #endif
572 #if ENABLE(XPATH)
573         case XPathExceptionType:
574             errorObject = toJS(exec, globalObject, XPathException::create(description));
575             break;
576 #endif
577 #if ENABLE(DATABASE)
578         case SQLExceptionType:
579             errorObject = toJS(exec, globalObject, SQLException::create(description));
580             break;
581 #endif
582 #if ENABLE(BLOB) || ENABLE(FILE_SYSTEM)
583         case FileExceptionType:
584             errorObject = toJS(exec, globalObject, FileException::create(description));
585             break;
586 #endif
587 #if ENABLE(INDEXED_DATABASE)
588         case IDBDatabaseExceptionType:
589             errorObject = toJS(exec, globalObject, IDBDatabaseException::create(description));
590             break;
591 #endif
592     }
593
594     ASSERT(errorObject);
595     throwError(exec, errorObject);
596 }
597
598 DOMWindow* activeDOMWindow(ExecState* exec)
599 {
600     return asJSDOMWindow(exec->lexicalGlobalObject())->impl();
601 }
602
603 DOMWindow* firstDOMWindow(ExecState* exec)
604 {
605     return asJSDOMWindow(exec->dynamicGlobalObject())->impl();
606 }
607
608 bool checkNodeSecurity(ExecState* exec, Node* node)
609 {
610     return node && allowsAccessFromFrame(exec, node->document()->frame());
611 }
612
613 bool allowsAccessFromFrame(ExecState* exec, Frame* frame)
614 {
615     if (!frame)
616         return false;
617     JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
618     return window && window->allowsAccessFrom(exec);
619 }
620
621 bool allowsAccessFromFrame(ExecState* exec, Frame* frame, String& message)
622 {
623     if (!frame)
624         return false;
625     JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
626     return window && window->allowsAccessFrom(exec, message);
627 }
628
629 void printErrorMessageForFrame(Frame* frame, const String& message)
630 {
631     if (!frame)
632         return;
633     frame->domWindow()->printErrorMessage(message);
634 }
635
636 // FIXME: We should remove or at least deprecate this function. Callers can use firstDOMWindow directly.
637 Frame* toDynamicFrame(ExecState* exec)
638 {
639     return firstDOMWindow(exec)->frame();
640 }
641
642 // FIXME: We should remove this function. Callers can use ScriptController directly.
643 bool processingUserGesture()
644 {
645     return ScriptController::processingUserGesture();
646 }
647
648 JSValue objectToStringFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName)
649 {
650     return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), 0, propertyName, objectProtoFuncToString);
651 }
652
653 Structure* getCachedDOMStructure(JSDOMGlobalObject* globalObject, const ClassInfo* classInfo)
654 {
655     JSDOMStructureMap& structures = globalObject->structures();
656     return structures.get(classInfo).get();
657 }
658
659 Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, const ClassInfo* classInfo)
660 {
661     JSDOMStructureMap& structures = globalObject->structures();
662     ASSERT(!structures.contains(classInfo));
663     return structures.set(classInfo, structure).first->second.get();
664 }
665
666 JSC::JSObject* toJSSequence(ExecState* exec, JSValue value, unsigned& length)
667 {
668     JSObject* object = value.getObject();
669     if (!object) {
670         throwTypeError(exec);
671         return 0;
672     }
673     JSValue lengthValue = object->get(exec, exec->propertyNames().length);
674     if (exec->hadException())
675         return 0;
676
677     if (lengthValue.isUndefinedOrNull()) {
678         throwTypeError(exec);
679         return 0;
680     }
681
682     length = lengthValue.toUInt32(exec);
683     if (exec->hadException())
684         return 0;
685
686     return object;
687 }
688
689 } // namespace WebCore