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