JavaScriptCore:
[WebKit-https.git] / WebCore / bindings / js / JSDOMWindowBase.cpp
1 /*
2  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reseved.
5  *  Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
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
20  *  USA
21  */
22
23 #include "config.h"
24 #include "JSDOMWindowBase.h"
25
26 #include "Base64.h"
27 #include "CString.h"
28 #include "Console.h"
29 #include "DOMWindow.h"
30 #include "Element.h"
31 #include "EventListener.h"
32 #include "EventNames.h"
33 #include "ExceptionCode.h"
34 #include "FloatRect.h"
35 #include "Frame.h"
36 #include "FrameLoadRequest.h"
37 #include "FrameLoader.h"
38 #include "FrameTree.h"
39 #include "GCController.h"
40 #include "HTMLDocument.h"
41 #include "JSAudioConstructor.h"
42 #include "JSDOMWindowCustom.h"
43 #include "JSEvent.h"
44 #include "JSEventListener.h"
45 #include "JSHTMLCollection.h"
46 #include "JSHTMLOptionElementConstructor.h"
47 #include "JSImageConstructor.h"
48 #include "JSNode.h"
49 #include "JSXMLHttpRequestConstructor.h"
50 #include "Logging.h"
51 #include "MediaPlayer.h"
52 #include "Page.h"
53 #include "PausedTimeouts.h"
54 #include "PlatformScreen.h"
55 #include "PluginInfoStore.h"
56 #include "RenderView.h"
57 #include "ScheduledAction.h"
58 #include "ScriptController.h"
59 #include "SecurityOrigin.h"
60 #include "Settings.h"
61 #include "WindowFeatures.h"
62 #include "htmlediting.h"
63 #include <kjs/Error.h>
64 #include <kjs/JSLock.h>
65 #include <wtf/AlwaysInline.h>
66 #include <wtf/MathExtras.h>
67
68 #if ENABLE(XSLT)
69 #include "JSXSLTProcessorConstructor.h"
70 #endif
71
72 using namespace KJS;
73
74 namespace WebCore {
75
76 static JSValue* windowProtoFuncAToB(ExecState*, JSObject*, JSValue*, const ArgList&);
77 static JSValue* windowProtoFuncBToA(ExecState*, JSObject*, JSValue*, const ArgList&);
78 static JSValue* windowProtoFuncOpen(ExecState*, JSObject*, JSValue*, const ArgList&);
79 static JSValue* windowProtoFuncSetTimeout(ExecState*, JSObject*, JSValue*, const ArgList&);
80 static JSValue* windowProtoFuncClearTimeoutOrInterval(ExecState*, JSObject*, JSValue*, const ArgList&);
81 static JSValue* windowProtoFuncSetInterval(ExecState*, JSObject*, JSValue*, const ArgList&);
82 static JSValue* windowProtoFuncAddEventListener(ExecState*, JSObject*, JSValue*, const ArgList&);
83 static JSValue* windowProtoFuncRemoveEventListener(ExecState*, JSObject*, JSValue*, const ArgList&);
84 static JSValue* windowProtoFuncShowModalDialog(ExecState*, JSObject*, JSValue*, const ArgList&);
85 static JSValue* windowProtoFuncNotImplemented(ExecState*, JSObject*, JSValue*, const ArgList&);
86
87 }
88
89 #include "JSDOMWindowBase.lut.h"
90
91 namespace WebCore {
92
93 using namespace EventNames;
94
95 static int lastUsedTimeoutId;
96
97 static int timerNestingLevel = 0;
98 const int cMaxTimerNestingLevel = 5;
99 const double cMinimumTimerInterval = 0.010;
100
101 class DOMWindowTimer : public TimerBase {
102 public:
103     DOMWindowTimer(int timeoutId, int nestingLevel, JSDOMWindowBase* object, ScheduledAction* action)
104         : m_timeoutId(timeoutId)
105         , m_nestingLevel(nestingLevel)
106         , m_object(object)
107         , m_action(action)
108     {
109     }
110
111     virtual ~DOMWindowTimer()
112     {
113         JSLock lock(false);
114         delete m_action;
115     }
116
117     int timeoutId() const { return m_timeoutId; }
118
119     int nestingLevel() const { return m_nestingLevel; }
120     void setNestingLevel(int n) { m_nestingLevel = n; }
121
122     ScheduledAction* action() const { return m_action; }
123     ScheduledAction* takeAction() { ScheduledAction* a = m_action; m_action = 0; return a; }
124
125 private:
126     virtual void fired();
127
128     int m_timeoutId;
129     int m_nestingLevel;
130     JSDOMWindowBase* m_object;
131     ScheduledAction* m_action;
132 };
133
134 ////////////////////// JSDOMWindowBase Object ////////////////////////
135
136 const ClassInfo JSDOMWindowBase::s_info = { "Window", 0, &JSDOMWindowBaseTable, 0 };
137
138 /*
139 @begin JSDOMWindowBaseTable
140 # -- Functions --
141   atob                  WebCore::windowProtoFuncAToB                 DontDelete|Function 1
142   btoa                  WebCore::windowProtoFuncBToA                 DontDelete|Function 1
143   open                  WebCore::windowProtoFuncOpen                 DontDelete|Function 3
144   setTimeout            WebCore::windowProtoFuncSetTimeout           DontDelete|Function 2
145   clearTimeout          WebCore::windowProtoFuncClearTimeoutOrInterval DontDelete|Function 1
146   setInterval           WebCore::windowProtoFuncSetInterval          DontDelete|Function 2
147   clearInterval         WebCore::windowProtoFuncClearTimeoutOrInterval DontDelete|Function 1
148   addEventListener      WebCore::windowProtoFuncAddEventListener     DontDelete|Function 3
149   removeEventListener   WebCore::windowProtoFuncRemoveEventListener  DontDelete|Function 3
150   showModalDialog       WebCore::windowProtoFuncShowModalDialog      DontDelete|Function 1
151 # Not implemented
152   captureEvents         WebCore::windowProtoFuncNotImplemented       DontDelete|Function 0
153   releaseEvents         WebCore::windowProtoFuncNotImplemented       DontDelete|Function 0
154
155 # -- Attributes --
156   crypto                WebCore::JSDOMWindowBase::Crypto             DontDelete|ReadOnly
157   event                 WebCore::JSDOMWindowBase::Event_             DontDelete
158 # -- Event Listeners --
159   onabort               WebCore::JSDOMWindowBase::Onabort            DontDelete
160   onblur                WebCore::JSDOMWindowBase::Onblur             DontDelete
161   onchange              WebCore::JSDOMWindowBase::Onchange           DontDelete
162   onclick               WebCore::JSDOMWindowBase::Onclick            DontDelete
163   ondblclick            WebCore::JSDOMWindowBase::Ondblclick         DontDelete
164   onerror               WebCore::JSDOMWindowBase::Onerror            DontDelete
165   onfocus               WebCore::JSDOMWindowBase::Onfocus            DontDelete
166   onkeydown             WebCore::JSDOMWindowBase::Onkeydown          DontDelete
167   onkeypress            WebCore::JSDOMWindowBase::Onkeypress         DontDelete
168   onkeyup               WebCore::JSDOMWindowBase::Onkeyup            DontDelete
169   onload                WebCore::JSDOMWindowBase::Onload             DontDelete
170   onmousedown           WebCore::JSDOMWindowBase::Onmousedown        DontDelete
171   onmousemove           WebCore::JSDOMWindowBase::Onmousemove        DontDelete
172   onmouseout            WebCore::JSDOMWindowBase::Onmouseout         DontDelete
173   onmouseover           WebCore::JSDOMWindowBase::Onmouseover        DontDelete
174   onmouseup             WebCore::JSDOMWindowBase::Onmouseup          DontDelete
175   onmousewheel          WebCore::JSDOMWindowBase::OnWindowMouseWheel DontDelete
176   onreset               WebCore::JSDOMWindowBase::Onreset            DontDelete
177   onresize              WebCore::JSDOMWindowBase::Onresize           DontDelete
178   onscroll              WebCore::JSDOMWindowBase::Onscroll           DontDelete
179   onsearch              WebCore::JSDOMWindowBase::Onsearch           DontDelete
180   onselect              WebCore::JSDOMWindowBase::Onselect           DontDelete
181   onsubmit              WebCore::JSDOMWindowBase::Onsubmit           DontDelete
182   onunload              WebCore::JSDOMWindowBase::Onunload           DontDelete
183   onbeforeunload        WebCore::JSDOMWindowBase::Onbeforeunload     DontDelete
184 # -- Constructors --
185   Audio                 WebCore::JSDOMWindowBase::Audio              DontDelete
186   Image                 WebCore::JSDOMWindowBase::Image              DontDelete
187   Option                WebCore::JSDOMWindowBase::Option             DontDelete
188   XMLHttpRequest        WebCore::JSDOMWindowBase::XMLHttpRequest     DontDelete
189   XSLTProcessor         WebCore::JSDOMWindowBase::XSLTProcessor      DontDelete
190 @end
191 */
192
193 JSDOMWindowBase::JSDOMWindowBase(JSObject* prototype, DOMWindow* window, JSDOMWindowShell* shell)
194     : JSGlobalObject(prototype, shell)
195     , m_impl(window)
196     , d(new JSDOMWindowBasePrivate(shell))
197 {
198     // Time in milliseconds before the script timeout handler kicks in.
199     setTimeoutTime(10000);
200
201     GlobalPropertyInfo staticGlobals[] = {
202         GlobalPropertyInfo(Identifier(globalExec(), "document"), jsNull(), DontDelete | ReadOnly),
203         GlobalPropertyInfo(Identifier(globalExec(), "window"), d->m_shell, DontDelete | ReadOnly)
204     };
205     
206     addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo));
207 }
208
209 void JSDOMWindowBase::updateDocument()
210 {
211     ASSERT(m_impl->document());
212     ExecState* exec = globalExec();
213     symbolTablePutWithAttributes(Identifier(exec, "document"), toJS(exec, m_impl->document()), DontDelete | ReadOnly);
214 }
215
216 JSDOMWindowBase::~JSDOMWindowBase()
217 {
218     if (m_impl->frame())
219         m_impl->frame()->script()->clearFormerWindow(asJSDOMWindow(this));
220
221     clearAllTimeouts();
222
223     // Clear any backpointers to the window
224
225     ListenersMap::iterator i2 = d->jsEventListeners.begin();
226     ListenersMap::iterator e2 = d->jsEventListeners.end();
227     for (; i2 != e2; ++i2)
228         i2->second->clearWindow();
229     i2 = d->jsHTMLEventListeners.begin();
230     e2 = d->jsHTMLEventListeners.end();
231     for (; i2 != e2; ++i2)
232         i2->second->clearWindow();
233
234     UnprotectedListenersMap::iterator i1 = d->jsUnprotectedEventListeners.begin();
235     UnprotectedListenersMap::iterator e1 = d->jsUnprotectedEventListeners.end();
236     for (; i1 != e1; ++i1)
237         i1->second->clearWindow();
238     i1 = d->jsUnprotectedHTMLEventListeners.begin();
239     e1 = d->jsUnprotectedHTMLEventListeners.end();
240     for (; i1 != e1; ++i1)
241         i1->second->clearWindow();
242 }
243
244 static bool allowPopUp(ExecState* exec)
245 {
246     Frame* frame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame();
247
248     ASSERT(frame);
249     if (frame->script()->processingUserGesture())
250         return true;
251     Settings* settings = frame->settings();
252     return settings && settings->JavaScriptCanOpenWindowsAutomatically();
253 }
254
255 static HashMap<String, String> parseModalDialogFeatures(const String& featuresArg)
256 {
257     HashMap<String, String> map;
258
259     Vector<String> features;
260     featuresArg.split(';', features);
261     Vector<String>::const_iterator end = features.end();
262     for (Vector<String>::const_iterator it = features.begin(); it != end; ++it) {
263         String s = *it;
264         int pos = s.find('=');
265         int colonPos = s.find(':');
266         if (pos >= 0 && colonPos >= 0)
267             continue; // ignore any strings that have both = and :
268         if (pos < 0)
269             pos = colonPos;
270         if (pos < 0) {
271             // null string for value means key without value
272             map.set(s.stripWhiteSpace().lower(), String());
273         } else {
274             String key = s.left(pos).stripWhiteSpace().lower();
275             String val = s.substring(pos + 1).stripWhiteSpace().lower();
276             int spacePos = val.find(' ');
277             if (spacePos != -1)
278                 val = val.left(spacePos);
279             map.set(key, val);
280         }
281     }
282
283     return map;
284 }
285
286 static Frame* createWindow(ExecState* exec, Frame* openerFrame, const String& url,
287     const String& frameName, const WindowFeatures& windowFeatures, JSValue* dialogArgs)
288 {
289     Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame();
290     ASSERT(activeFrame);
291
292     ResourceRequest request;
293
294     request.setHTTPReferrer(activeFrame->loader()->outgoingReferrer());
295     FrameLoadRequest frameRequest(request, frameName);
296
297     // FIXME: It's much better for client API if a new window starts with a URL, here where we
298     // know what URL we are going to open. Unfortunately, this code passes the empty string
299     // for the URL, but there's a reason for that. Before loading we have to set up the opener,
300     // openedByDOM, and dialogArguments values. Also, to decide whether to use the URL we currently
301     // do an allowsAccessFrom call using the window we create, which can't be done before creating it.
302     // We'd have to resolve all those issues to pass the URL instead of "".
303
304     bool created;
305     // We pass in the opener frame here so it can be used for looking up the frame name, in case the active frame
306     // is different from the opener frame, and the name references a frame relative to the opener frame, for example
307     // "_self" or "_parent".
308     Frame* newFrame = activeFrame->loader()->createWindow(openerFrame->loader(), frameRequest, windowFeatures, created);
309     if (!newFrame)
310         return 0;
311
312     newFrame->loader()->setOpener(openerFrame);
313     newFrame->loader()->setOpenedByDOM();
314
315     JSDOMWindow* newWindow = toJSDOMWindow(newFrame);
316
317     if (dialogArgs)
318         newWindow->putDirect(Identifier(exec, "dialogArguments"), dialogArgs);
319
320     if (!protocolIs(url, "javascript") || newWindow->allowsAccessFrom(exec)) {
321         KURL completedURL = url.isEmpty() ? KURL("") : activeFrame->document()->completeURL(url);
322         bool userGesture = activeFrame->script()->processingUserGesture();
323
324         if (created)
325             newFrame->loader()->changeLocation(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture);
326         else if (!url.isEmpty())
327             newFrame->loader()->scheduleLocationChange(completedURL.string(), activeFrame->loader()->outgoingReferrer(), false, userGesture);
328     }
329
330     return newFrame;
331 }
332
333 static bool canShowModalDialog(const Frame* frame)
334 {
335     if (!frame)
336         return false;
337     return frame->page()->chrome()->canRunModal();
338 }
339
340 static bool canShowModalDialogNow(const Frame* frame)
341 {
342     if (!frame)
343         return false;
344     return frame->page()->chrome()->canRunModalNow();
345 }
346
347 static JSValue* showModalDialog(ExecState* exec, Frame* frame, const String& url, JSValue* dialogArgs, const String& featureArgs)
348 {
349     if (!canShowModalDialogNow(frame) || !allowPopUp(exec))
350         return jsUndefined();
351
352     const HashMap<String, String> features = parseModalDialogFeatures(featureArgs);
353
354     const bool trusted = false;
355
356     // The following features from Microsoft's documentation are not implemented:
357     // - default font settings
358     // - width, height, left, and top specified in units other than "px"
359     // - edge (sunken or raised, default is raised)
360     // - dialogHide: trusted && boolFeature(features, "dialoghide"), makes dialog hide when you print
361     // - help: boolFeature(features, "help", true), makes help icon appear in dialog (what does it do on Windows?)
362     // - unadorned: trusted && boolFeature(features, "unadorned");
363
364     if (!frame)
365         return jsUndefined();
366
367     FloatRect screenRect = screenAvailableRect(frame->view());
368
369     WindowFeatures wargs;
370     wargs.width = WindowFeatures::floatFeature(features, "dialogwidth", 100, screenRect.width(), 620); // default here came from frame size of dialog in MacIE
371     wargs.widthSet = true;
372     wargs.height = WindowFeatures::floatFeature(features, "dialogheight", 100, screenRect.height(), 450); // default here came from frame size of dialog in MacIE
373     wargs.heightSet = true;
374
375     wargs.x = WindowFeatures::floatFeature(features, "dialogleft", screenRect.x(), screenRect.right() - wargs.width, -1);
376     wargs.xSet = wargs.x > 0;
377     wargs.y = WindowFeatures::floatFeature(features, "dialogtop", screenRect.y(), screenRect.bottom() - wargs.height, -1);
378     wargs.ySet = wargs.y > 0;
379
380     if (WindowFeatures::boolFeature(features, "center", true)) {
381         if (!wargs.xSet) {
382             wargs.x = screenRect.x() + (screenRect.width() - wargs.width) / 2;
383             wargs.xSet = true;
384         }
385         if (!wargs.ySet) {
386             wargs.y = screenRect.y() + (screenRect.height() - wargs.height) / 2;
387             wargs.ySet = true;
388         }
389     }
390
391     wargs.dialog = true;
392     wargs.resizable = WindowFeatures::boolFeature(features, "resizable");
393     wargs.scrollbarsVisible = WindowFeatures::boolFeature(features, "scroll", true);
394     wargs.statusBarVisible = WindowFeatures::boolFeature(features, "status", !trusted);
395     wargs.menuBarVisible = false;
396     wargs.toolBarVisible = false;
397     wargs.locationBarVisible = false;
398     wargs.fullscreen = false;
399
400     Frame* dialogFrame = createWindow(exec, frame, url, "", wargs, dialogArgs);
401     if (!dialogFrame)
402         return jsUndefined();
403
404     JSDOMWindow* dialogWindow = toJSDOMWindow(dialogFrame);
405
406     // Get the return value either just before clearing the dialog window's
407     // properties (in JSDOMWindowBase::clear), or when on return from runModal.
408     JSValue* returnValue = 0;
409     dialogWindow->setReturnValueSlot(&returnValue);
410     dialogFrame->page()->chrome()->runModal();
411     dialogWindow->setReturnValueSlot(0);
412
413     // If we don't have a return value, get it now.
414     // Either JSDOMWindowBase::clear was not called yet, or there was no return value,
415     // and in that case, there's no harm in trying again (no benefit either).
416     if (!returnValue)
417         returnValue = dialogWindow->getDirect(Identifier(exec, "returnValue"));
418
419     return returnValue ? returnValue : jsUndefined();
420 }
421
422 JSValue *JSDOMWindowBase::getValueProperty(ExecState *exec, int token) const
423 {
424    ASSERT(impl()->frame());
425
426    switch (token) {
427    case Crypto:
428       return jsUndefined(); // FIXME: implement this
429     case Event_:
430       if (!allowsAccessFrom(exec))
431         return jsUndefined();
432       if (!d->m_evt)
433         return jsUndefined();
434       return toJS(exec, d->m_evt);
435     case Image:
436       if (!allowsAccessFrom(exec))
437         return jsUndefined();
438       // FIXME: this property (and the few below) probably shouldn't create a new object every
439       // time
440       return new (exec) JSImageConstructor(exec, impl()->frame()->document());
441     case Option:
442       if (!allowsAccessFrom(exec))
443         return jsUndefined();
444       return new (exec) JSHTMLOptionElementConstructor(exec, impl()->frame()->document());
445     case XMLHttpRequest:
446       if (!allowsAccessFrom(exec))
447         return jsUndefined();
448       return new (exec) JSXMLHttpRequestConstructor(exec, impl()->frame()->document());
449     case Audio:
450 #if ENABLE(VIDEO)
451       if (!allowsAccessFrom(exec))
452         return jsUndefined();
453       if (!MediaPlayer::isAvailable())
454         return jsUndefined();
455       return new (exec) JSAudioConstructor(exec, impl()->frame()->document());
456 #else
457       return jsUndefined();
458 #endif
459     case XSLTProcessor:
460 #if ENABLE(XSLT)
461       if (!allowsAccessFrom(exec))
462         return jsUndefined();
463       return new (exec) JSXSLTProcessorConstructor(exec);
464 #else
465       return jsUndefined();
466 #endif
467    }
468
469    if (!allowsAccessFrom(exec))
470      return jsUndefined();
471
472    switch (token) {
473    case Onabort:
474      return getListener(exec, abortEvent);
475    case Onblur:
476      return getListener(exec, blurEvent);
477    case Onchange:
478      return getListener(exec, changeEvent);
479    case Onclick:
480      return getListener(exec, clickEvent);
481    case Ondblclick:
482      return getListener(exec, dblclickEvent);
483    case Onerror:
484      return getListener(exec, errorEvent);
485    case Onfocus:
486      return getListener(exec, focusEvent);
487    case Onkeydown:
488      return getListener(exec, keydownEvent);
489    case Onkeypress:
490      return getListener(exec, keypressEvent);
491    case Onkeyup:
492      return getListener(exec, keyupEvent);
493    case Onload:
494      return getListener(exec, loadEvent);
495    case Onmousedown:
496      return getListener(exec, mousedownEvent);
497    case Onmousemove:
498      return getListener(exec, mousemoveEvent);
499    case Onmouseout:
500      return getListener(exec, mouseoutEvent);
501    case Onmouseover:
502      return getListener(exec, mouseoverEvent);
503    case Onmouseup:
504      return getListener(exec, mouseupEvent);
505    case OnWindowMouseWheel:
506      return getListener(exec, mousewheelEvent);
507    case Onreset:
508      return getListener(exec, resetEvent);
509    case Onresize:
510      return getListener(exec,resizeEvent);
511    case Onscroll:
512      return getListener(exec,scrollEvent);
513    case Onsearch:
514      return getListener(exec,searchEvent);
515    case Onselect:
516      return getListener(exec,selectEvent);
517    case Onsubmit:
518      return getListener(exec,submitEvent);
519    case Onbeforeunload:
520      return getListener(exec, beforeunloadEvent);
521    case Onunload:
522      return getListener(exec, unloadEvent);
523    }
524    ASSERT_NOT_REACHED();
525    return jsUndefined();
526 }
527
528 JSValue* JSDOMWindowBase::childFrameGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
529 {
530     return toJS(exec, static_cast<JSDOMWindowBase*>(slot.slotBase())->impl()->frame()->tree()->child(AtomicString(propertyName))->domWindow());
531 }
532
533 JSValue* JSDOMWindowBase::indexGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)
534 {
535     return toJS(exec, static_cast<JSDOMWindowBase*>(slot.slotBase())->impl()->frame()->tree()->child(slot.index())->domWindow());
536 }
537
538 JSValue* JSDOMWindowBase::namedItemGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
539 {
540     JSDOMWindowBase* thisObj = static_cast<JSDOMWindowBase*>(slot.slotBase());
541     Document* doc = thisObj->impl()->frame()->document();
542     ASSERT(thisObj->allowsAccessFrom(exec));
543     ASSERT(doc);
544     ASSERT(doc->isHTMLDocument());
545
546     RefPtr<HTMLCollection> collection = doc->windowNamedItems(propertyName);
547     if (collection->length() == 1)
548         return toJS(exec, collection->firstItem());
549     return toJS(exec, collection.get());
550 }
551
552 bool JSDOMWindowBase::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
553 {
554     // Check for child frames by name before built-in properties to
555     // match Mozilla. This does not match IE, but some sites end up
556     // naming frames things that conflict with window properties that
557     // are in Moz but not IE. Since we have some of these, we have to do
558     // it the Moz way.
559     if (impl()->frame()->tree()->child(propertyName)) {
560         slot.setCustom(this, childFrameGetter);
561         return true;
562     }
563
564     const HashEntry* entry = JSDOMWindowBaseTable.entry(exec, propertyName);
565     if (entry) {
566         if (entry->attributes & Function) {
567             if (entry->functionValue == windowProtoFuncShowModalDialog) {
568                 if (!canShowModalDialog(impl()->frame()))
569                     return false;
570             }
571             if (allowsAccessFrom(exec))
572                 slot.setStaticEntry(this, entry, staticFunctionGetter);
573             else
574                 slot.setUndefined();
575         } else
576             slot.setStaticEntry(this, entry, staticValueGetter<JSDOMWindowBase>);
577         return true;
578     }
579
580     // Do prototype lookup early so that functions and attributes in the prototype can have
581     // precedence over the index and name getters.  
582     JSValue* proto = prototype();
583     if (proto->isObject()) {
584         if (static_cast<JSObject*>(proto)->getPropertySlot(exec, propertyName, slot)) {
585             if (!allowsAccessFrom(exec))
586                 slot.setUndefined();
587             return true;
588         }
589     }
590
591     // FIXME: Search the whole frame hierachy somewhere around here.
592     // We need to test the correct priority order.
593
594     // allow window[1] or parent[1] etc. (#56983)
595     bool ok;
596     unsigned i = propertyName.toArrayIndex(&ok);
597     if (ok && i < impl()->frame()->tree()->childCount()) {
598         slot.setCustomIndex(this, i, indexGetter);
599         return true;
600     }
601
602     if (!allowsAccessFrom(exec)) {
603         slot.setUndefined();
604         return true;
605     }
606
607     // Allow shortcuts like 'Image1' instead of document.images.Image1
608     Document* document = impl()->frame()->document();
609     if (document && document->isHTMLDocument()) {
610         AtomicStringImpl* atomicPropertyName = AtomicString::find(propertyName);
611         if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) {
612             slot.setCustom(this, namedItemGetter);
613             return true;
614         }
615     }
616
617     return Base::getOwnPropertySlot(exec, propertyName, slot);
618 }
619
620 void JSDOMWindowBase::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
621 {
622   const HashEntry* entry = JSDOMWindowBaseTable.entry(exec, propertyName);
623   if (entry) {
624      if (entry->attributes & Function) {
625        if (allowsAccessFrom(exec))
626          Base::put(exec, propertyName, value);
627        return;
628     }
629     if (entry->attributes & ReadOnly)
630       return;
631
632     switch (entry->integerValue) {
633     case Onabort:
634       if (allowsAccessFrom(exec))
635         setListener(exec, abortEvent,value);
636       return;
637     case Onblur:
638       if (allowsAccessFrom(exec))
639         setListener(exec, blurEvent,value);
640       return;
641     case Onchange:
642       if (allowsAccessFrom(exec))
643         setListener(exec, changeEvent,value);
644       return;
645     case Onclick:
646       if (allowsAccessFrom(exec))
647         setListener(exec,clickEvent,value);
648       return;
649     case Ondblclick:
650       if (allowsAccessFrom(exec))
651         setListener(exec, dblclickEvent,value);
652       return;
653     case Onerror:
654       if (allowsAccessFrom(exec))
655         setListener(exec, errorEvent, value);
656       return;
657     case Onfocus:
658       if (allowsAccessFrom(exec))
659         setListener(exec,focusEvent,value);
660       return;
661     case Onkeydown:
662       if (allowsAccessFrom(exec))
663         setListener(exec,keydownEvent,value);
664       return;
665     case Onkeypress:
666       if (allowsAccessFrom(exec))
667         setListener(exec,keypressEvent,value);
668       return;
669     case Onkeyup:
670       if (allowsAccessFrom(exec))
671         setListener(exec,keyupEvent,value);
672       return;
673     case Onload:
674       if (allowsAccessFrom(exec))
675         setListener(exec,loadEvent,value);
676       return;
677     case Onmousedown:
678       if (allowsAccessFrom(exec))
679         setListener(exec,mousedownEvent,value);
680       return;
681     case Onmousemove:
682       if (allowsAccessFrom(exec))
683         setListener(exec,mousemoveEvent,value);
684       return;
685     case Onmouseout:
686       if (allowsAccessFrom(exec))
687         setListener(exec,mouseoutEvent,value);
688       return;
689     case Onmouseover:
690       if (allowsAccessFrom(exec))
691         setListener(exec,mouseoverEvent,value);
692       return;
693     case Onmouseup:
694       if (allowsAccessFrom(exec))
695         setListener(exec,mouseupEvent,value);
696       return;
697     case OnWindowMouseWheel:
698       if (allowsAccessFrom(exec))
699         setListener(exec, mousewheelEvent,value);
700       return;
701     case Onreset:
702       if (allowsAccessFrom(exec))
703         setListener(exec,resetEvent,value);
704       return;
705     case Onresize:
706       if (allowsAccessFrom(exec))
707         setListener(exec,resizeEvent,value);
708       return;
709     case Onscroll:
710       if (allowsAccessFrom(exec))
711         setListener(exec,scrollEvent,value);
712       return;
713     case Onsearch:
714         if (allowsAccessFrom(exec))
715             setListener(exec,searchEvent,value);
716         return;
717     case Onselect:
718       if (allowsAccessFrom(exec))
719         setListener(exec,selectEvent,value);
720       return;
721     case Onsubmit:
722       if (allowsAccessFrom(exec))
723         setListener(exec,submitEvent,value);
724       return;
725     case Onbeforeunload:
726       if (allowsAccessFrom(exec))
727         setListener(exec, beforeunloadEvent, value);
728       return;
729     case Onunload:
730       if (allowsAccessFrom(exec))
731         setListener(exec, unloadEvent, value);
732       return;
733     default:
734       break;
735     }
736   }
737   if (allowsAccessFrom(exec))
738     Base::put(exec, propertyName, value);
739 }
740
741 String JSDOMWindowBase::crossDomainAccessErrorMessage(const JSGlobalObject* other) const
742 {
743     KURL originURL = asJSDOMWindow(other)->impl()->url();
744     KURL targetURL = impl()->frame()->document()->url();
745     if (originURL.isNull() || targetURL.isNull())
746         return String();
747
748     // FIXME: this error message should contain more specifics of why the same origin check has failed.
749     return String::format("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains, protocols and ports must match.\n",
750         targetURL.string().utf8().data(), originURL.string().utf8().data());
751 }
752
753 void JSDOMWindowBase::printErrorMessage(const String& message) const
754 {
755     if (message.isEmpty())
756         return;
757
758     Frame* frame = impl()->frame();
759     if (!frame)
760         return;
761
762     Settings* settings = frame->settings();
763     if (!settings)
764         return;
765     
766     if (settings->privateBrowsingEnabled())
767         return;
768
769     impl()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String()); // FIXME: provide a real line number and source URL.
770 }
771
772 ExecState* JSDOMWindowBase::globalExec()
773 {
774     // We need to make sure that any script execution happening in this
775     // frame does not destroy it
776     ASSERT(impl()->frame());
777     impl()->frame()->keepAlive();
778     return Base::globalExec();
779 }
780
781 bool JSDOMWindowBase::shouldInterruptScript() const
782 {
783     ASSERT(impl()->frame());
784     Page* page = impl()->frame()->page();
785
786     // See <rdar://problem/5479443>. We don't think that page can ever be NULL
787     // in this case, but if it is, we've gotten into a state where we may have
788     // hung the UI, with no way to ask the client whether to cancel execution.
789     // For now, our solution is just to cancel execution no matter what,
790     // ensuring that we never hang. We might want to consider other solutions
791     // if we discover problems with this one.
792     ASSERT(page);
793     if (!page)
794         return true;
795
796     return page->chrome()->shouldInterruptJavaScript();
797 }
798
799 void JSDOMWindowBase::setListener(ExecState* exec, const AtomicString& eventType, JSValue* func)
800 {
801     ASSERT(impl()->frame());
802     Document* doc = impl()->frame()->document();
803     if (!doc)
804         return;
805
806     doc->setHTMLWindowEventListener(eventType, findOrCreateJSEventListener(exec, func, true));
807 }
808
809 JSValue* JSDOMWindowBase::getListener(ExecState* exec, const AtomicString& eventType) const
810 {
811     ASSERT(impl()->frame());
812     Document* doc = impl()->frame()->document();
813     if (!doc)
814         return jsUndefined();
815
816     EventListener* listener = doc->getHTMLWindowEventListener(eventType);
817     if (listener && static_cast<JSEventListener*>(listener)->listenerObj())
818         return static_cast<JSEventListener*>(listener)->listenerObj();
819     return jsNull();
820 }
821
822 JSEventListener* JSDOMWindowBase::findJSEventListener(JSValue* val, bool html)
823 {
824     if (!val->isObject())
825         return 0;
826     JSObject* object = static_cast<JSObject*>(val);
827     ListenersMap& listeners = html ? d->jsHTMLEventListeners : d->jsEventListeners;
828     return listeners.get(object);
829 }
830
831 PassRefPtr<JSEventListener> JSDOMWindowBase::findOrCreateJSEventListener(ExecState* exec, JSValue* val, bool html)
832 {
833     JSEventListener* listener = findJSEventListener(val, html);
834     if (listener)
835         return listener;
836
837     if (!val->isObject())
838         return 0;
839     JSObject* object = static_cast<JSObject*>(val);
840
841     // Note that the JSEventListener constructor adds it to our jsEventListeners list
842     return JSEventListener::create(object, static_cast<JSDOMWindow*>(this), html).get();
843 }
844
845 JSUnprotectedEventListener* JSDOMWindowBase::findJSUnprotectedEventListener(ExecState* exec, JSValue* val, bool html)
846 {
847     if (!val->isObject())
848         return 0;
849     JSObject* object = static_cast<JSObject*>(val);
850     UnprotectedListenersMap& listeners = html ? d->jsUnprotectedHTMLEventListeners : d->jsUnprotectedEventListeners;
851     return listeners.get(object);
852 }
853
854 PassRefPtr<JSUnprotectedEventListener> JSDOMWindowBase::findOrCreateJSUnprotectedEventListener(ExecState* exec, JSValue* val, bool html)
855 {
856     JSUnprotectedEventListener* listener = findJSUnprotectedEventListener(exec, val, html);
857     if (listener)
858         return listener;
859     if (!val->isObject())
860         return 0;
861     JSObject* object = static_cast<JSObject*>(val);
862
863     // The JSUnprotectedEventListener constructor adds it to our jsUnprotectedEventListeners map.
864     return JSUnprotectedEventListener::create(object, static_cast<JSDOMWindow*>(this), html).get();
865 }
866
867 void JSDOMWindowBase::clearHelperObjectProperties()
868 {
869     d->m_evt = 0;
870 }
871
872 void JSDOMWindowBase::clear()
873 {
874   JSLock lock(false);
875
876   if (d->m_returnValueSlot && !*d->m_returnValueSlot)
877     *d->m_returnValueSlot = getDirect(Identifier(globalExec(), "returnValue"));
878
879   clearAllTimeouts();
880   clearHelperObjectProperties();
881 }
882
883 void JSDOMWindowBase::setCurrentEvent(Event* evt)
884 {
885     d->m_evt = evt;
886 }
887
888 Event* JSDOMWindowBase::currentEvent()
889 {
890     return d->m_evt;
891 }
892
893 JSObject* JSDOMWindowBase::toThisObject(ExecState*) const
894 {
895     return shell();
896 }
897
898 JSDOMWindowShell* JSDOMWindowBase::shell() const
899 {
900     return d->m_shell;
901 }
902
903 JSGlobalData* JSDOMWindowBase::commonJSGlobalData()
904 {
905     static JSGlobalData* globalData = JSGlobalData::create().releaseRef();
906     return globalData;
907 }
908
909 JSValue* windowProtoFuncAToB(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
910 {
911     JSDOMWindow* window = toJSDOMWindow(thisValue);
912     if (!window)
913         return throwError(exec, TypeError);
914     if (!window->allowsAccessFrom(exec))
915         return jsUndefined();
916
917     if (args.size() < 1)
918         return throwError(exec, SyntaxError, "Not enough arguments");
919
920     JSValue* v = args.at(exec, 0);
921     if (v->isNull())
922         return jsString(exec);
923
924     UString s = v->toString(exec);
925     if (!s.is8Bit()) {
926         setDOMException(exec, INVALID_CHARACTER_ERR);
927         return jsUndefined();
928     }
929
930     Vector<char> in(s.size());
931     for (int i = 0; i < s.size(); ++i)
932         in[i] = static_cast<char>(s.data()[i]);
933     Vector<char> out;
934
935     if (!base64Decode(in, out))
936         return throwError(exec, GeneralError, "Cannot decode base64");
937
938     return jsString(exec, String(out.data(), out.size()));
939 }
940
941 JSValue* windowProtoFuncBToA(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
942 {
943     JSDOMWindow* window = toJSDOMWindow(thisValue);
944     if (!window)
945         return throwError(exec, TypeError);
946     if (!window->allowsAccessFrom(exec))
947         return jsUndefined();
948
949     if (args.size() < 1)
950         return throwError(exec, SyntaxError, "Not enough arguments");
951
952     JSValue* v = args.at(exec, 0);
953     if (v->isNull())
954         return jsString(exec);
955
956     UString s = v->toString(exec);
957     if (!s.is8Bit()) {
958         setDOMException(exec, INVALID_CHARACTER_ERR);
959         return jsUndefined();
960     }
961
962     Vector<char> in(s.size());
963     for (int i = 0; i < s.size(); ++i)
964         in[i] = static_cast<char>(s.data()[i]);
965     Vector<char> out;
966
967     base64Encode(in, out);
968
969     return jsString(exec, String(out.data(), out.size()));
970 }
971
972 JSValue* windowProtoFuncOpen(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
973 {
974     JSDOMWindow* window = toJSDOMWindow(thisValue);
975     if (!window)
976         return throwError(exec, TypeError);
977     if (!window->allowsAccessFrom(exec))
978         return jsUndefined();
979
980     Frame* frame = window->impl()->frame();
981     if (!frame)
982         return jsUndefined();
983     Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame();
984     if (!activeFrame)
985         return  jsUndefined();
986
987     Page* page = frame->page();
988
989     String urlString = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0));
990     AtomicString frameName = args.at(exec, 1)->isUndefinedOrNull() ? "_blank" : AtomicString(args.at(exec, 1)->toString(exec));
991
992     // Because FrameTree::find() returns true for empty strings, we must check for empty framenames.
993     // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
994     if (!allowPopUp(exec) && (frameName.isEmpty() || !frame->tree()->find(frameName)))
995         return jsUndefined();
996
997     // Get the target frame for the special cases of _top and _parent.  In those
998     // cases, we can schedule a location change right now and return early.
999     bool topOrParent = false;
1000     if (frameName == "_top") {
1001         frame = frame->tree()->top();
1002         topOrParent = true;
1003     } else if (frameName == "_parent") {
1004         if (Frame* parent = frame->tree()->parent())
1005             frame = parent;
1006         topOrParent = true;
1007     }
1008     if (topOrParent) {
1009         if (!activeFrame->loader()->shouldAllowNavigation(frame))
1010             return jsUndefined();
1011
1012         String completedURL;
1013         if (!urlString.isEmpty())
1014             completedURL = activeFrame->document()->completeURL(urlString).string();
1015
1016         const JSDOMWindow* targetedWindow = toJSDOMWindow(frame);
1017         if (!completedURL.isEmpty() && (!protocolIs(completedURL, "javascript") || (targetedWindow && targetedWindow->allowsAccessFrom(exec)))) {
1018             bool userGesture = activeFrame->script()->processingUserGesture();
1019             frame->loader()->scheduleLocationChange(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture);
1020         }
1021         return toJS(exec, frame->domWindow());
1022     }
1023
1024     // In the case of a named frame or a new window, we'll use the createWindow() helper
1025     WindowFeatures windowFeatures(valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 2)));
1026     FloatRect windowRect(windowFeatures.x, windowFeatures.y, windowFeatures.width, windowFeatures.height);
1027     DOMWindow::adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), windowRect, windowRect);
1028
1029     windowFeatures.x = windowRect.x();
1030     windowFeatures.y = windowRect.y();
1031     windowFeatures.height = windowRect.height();
1032     windowFeatures.width = windowRect.width();
1033
1034     frame = createWindow(exec, frame, urlString, frameName, windowFeatures, 0);
1035
1036     if (!frame)
1037         return jsUndefined();
1038
1039     return toJS(exec, frame->domWindow()); // global object
1040 }
1041
1042 static JSValue* setTimeoutOrInterval(ExecState* exec, JSValue* thisValue, const ArgList& args, bool timeout)
1043 {
1044     JSDOMWindow* window = toJSDOMWindow(thisValue);
1045     if (!window)
1046         return throwError(exec, TypeError);
1047     if (!window->allowsAccessFrom(exec))
1048         return jsUndefined();
1049
1050     JSValue* v = args.at(exec, 0);
1051     int delay = args.at(exec, 1)->toInt32(exec);
1052     if (v->isString())
1053         return jsNumber(exec, window->installTimeout(static_cast<JSString*>(v)->value(), delay, timeout));
1054     CallData callData;
1055     if (v->getCallData(callData) == CallTypeNone)
1056         return jsUndefined();
1057     ArgList argsTail;
1058     args.getSlice(2, argsTail);
1059     return jsNumber(exec, window->installTimeout(exec, v, argsTail, delay, timeout));
1060 }
1061
1062 JSValue* windowProtoFuncClearTimeoutOrInterval(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
1063 {
1064     JSDOMWindow* window = toJSDOMWindow(thisValue);
1065     if (!window)
1066         return throwError(exec, TypeError);
1067     if (!window->allowsAccessFrom(exec))
1068         return jsUndefined();
1069
1070     window->clearTimeout(args.at(exec, 0)->toInt32(exec));
1071     return jsUndefined();
1072 }
1073
1074 JSValue* windowProtoFuncSetTimeout(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
1075 {
1076     return setTimeoutOrInterval(exec, thisValue, args, true);
1077 }
1078
1079 JSValue* windowProtoFuncSetInterval(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
1080 {
1081     return setTimeoutOrInterval(exec, thisValue, args, false);
1082 }
1083
1084 JSValue* windowProtoFuncAddEventListener(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
1085 {
1086     JSDOMWindow* window = toJSDOMWindow(thisValue);
1087     if (!window)
1088         return throwError(exec, TypeError);
1089     if (!window->allowsAccessFrom(exec))
1090         return jsUndefined();
1091
1092     Frame* frame = window->impl()->frame();
1093     if (!frame)
1094         return jsUndefined();
1095
1096     if (RefPtr<JSEventListener> listener = window->findOrCreateJSEventListener(exec, args.at(exec, 1))) {
1097         if (Document* doc = frame->document())
1098             doc->addWindowEventListener(AtomicString(args.at(exec, 0)->toString(exec)), listener.release(), args.at(exec, 2)->toBoolean(exec));
1099     }
1100
1101     return jsUndefined();
1102 }
1103
1104 JSValue* windowProtoFuncRemoveEventListener(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
1105 {
1106     JSDOMWindow* window = toJSDOMWindow(thisValue);
1107     if (!window)
1108         return throwError(exec, TypeError);
1109     if (!window->allowsAccessFrom(exec))
1110         return jsUndefined();
1111
1112     Frame* frame = window->impl()->frame();
1113     if (!frame)
1114         return jsUndefined();
1115
1116     if (JSEventListener* listener = window->findJSEventListener(args.at(exec, 1))) {
1117         if (Document* doc = frame->document())
1118             doc->removeWindowEventListener(AtomicString(args.at(exec, 0)->toString(exec)), listener, args.at(exec, 2)->toBoolean(exec));
1119     }
1120
1121     return jsUndefined();
1122 }
1123
1124 JSValue* windowProtoFuncShowModalDialog(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
1125 {
1126     JSDOMWindow* window = toJSDOMWindow(thisValue);
1127     if (!window)
1128         return throwError(exec, TypeError);
1129     if (!window->allowsAccessFrom(exec))
1130         return jsUndefined();
1131
1132     Frame* frame = window->impl()->frame();
1133     if (!frame)
1134         return jsUndefined();
1135
1136     return showModalDialog(exec, frame, valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0)), args.at(exec, 1), valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 2)));
1137 }
1138
1139 JSValue* windowProtoFuncNotImplemented(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
1140 {
1141     if (!toJSDOMWindow(thisValue))
1142         return throwError(exec, TypeError);
1143     return jsUndefined();
1144 }
1145
1146 void JSDOMWindowBase::setReturnValueSlot(JSValue** slot)
1147 {
1148     d->m_returnValueSlot = slot;
1149 }
1150
1151 ////////////////////// timeouts ////////////////////////
1152
1153 void JSDOMWindowBase::clearAllTimeouts()
1154 {
1155     deleteAllValues(d->m_timeouts);
1156     d->m_timeouts.clear();
1157 }
1158
1159 int JSDOMWindowBase::installTimeout(ScheduledAction* a, int t, bool singleShot)
1160 {
1161     int timeoutId = ++lastUsedTimeoutId;
1162
1163     // avoid wraparound going negative on us
1164     if (timeoutId <= 0)
1165         timeoutId = 1;
1166
1167     int nestLevel = timerNestingLevel + 1;
1168     DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, nestLevel, this, a);
1169     ASSERT(!d->m_timeouts.get(timeoutId));
1170     d->m_timeouts.set(timeoutId, timer);
1171     // Use a minimum interval of 10 ms to match other browsers, but only once we've
1172     // nested enough to notice that we're repeating.
1173     // Faster timers might be "better", but they're incompatible.
1174     double interval = max(0.001, t * 0.001);
1175     if (interval < cMinimumTimerInterval && nestLevel >= cMaxTimerNestingLevel)
1176         interval = cMinimumTimerInterval;
1177     if (singleShot)
1178         timer->startOneShot(interval);
1179     else
1180         timer->startRepeating(interval);
1181     return timeoutId;
1182 }
1183
1184 int JSDOMWindowBase::installTimeout(const UString& handler, int t, bool singleShot)
1185 {
1186     return installTimeout(new ScheduledAction(handler), t, singleShot);
1187 }
1188
1189 int JSDOMWindowBase::installTimeout(ExecState* exec, JSValue* func, const ArgList& args, int t, bool singleShot)
1190 {
1191     return installTimeout(new ScheduledAction(exec, func, args), t, singleShot);
1192 }
1193
1194 PausedTimeouts* JSDOMWindowBase::pauseTimeouts()
1195 {
1196     size_t count = d->m_timeouts.size();
1197     if (count == 0)
1198         return 0;
1199
1200     PausedTimeout* t = new PausedTimeout [count];
1201     PausedTimeouts* result = new PausedTimeouts(t, count);
1202
1203     JSDOMWindowBasePrivate::TimeoutsMap::iterator it = d->m_timeouts.begin();
1204     for (size_t i = 0; i != count; ++i, ++it) {
1205         int timeoutId = it->first;
1206         DOMWindowTimer* timer = it->second;
1207         t[i].timeoutId = timeoutId;
1208         t[i].nestingLevel = timer->nestingLevel();
1209         t[i].nextFireInterval = timer->nextFireInterval();
1210         t[i].repeatInterval = timer->repeatInterval();
1211         t[i].action = timer->takeAction();
1212     }
1213     ASSERT(it == d->m_timeouts.end());
1214
1215     deleteAllValues(d->m_timeouts);
1216     d->m_timeouts.clear();
1217
1218     return result;
1219 }
1220
1221 void JSDOMWindowBase::resumeTimeouts(PausedTimeouts* timeouts)
1222 {
1223     if (!timeouts)
1224         return;
1225     size_t count = timeouts->numTimeouts();
1226     PausedTimeout* array = timeouts->takeTimeouts();
1227     for (size_t i = 0; i != count; ++i) {
1228         int timeoutId = array[i].timeoutId;
1229         DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, array[i].nestingLevel, this, array[i].action);
1230         d->m_timeouts.set(timeoutId, timer);
1231         timer->start(array[i].nextFireInterval, array[i].repeatInterval);
1232     }
1233     delete [] array;
1234 }
1235
1236 void JSDOMWindowBase::clearTimeout(int timeoutId, bool delAction)
1237 {
1238     // timeout IDs have to be positive, and 0 and -1 are unsafe to
1239     // even look up since they are the empty and deleted value
1240     // respectively
1241     if (timeoutId <= 0)
1242         return;
1243
1244     delete d->m_timeouts.take(timeoutId);
1245 }
1246
1247 void JSDOMWindowBase::timerFired(DOMWindowTimer* timer)
1248 {
1249     // Simple case for non-one-shot timers.
1250     if (timer->isActive()) {
1251         int timeoutId = timer->timeoutId();
1252
1253         timer->action()->execute(shell());
1254         // The DOMWindowTimer object may have been deleted or replaced during execution,
1255         // so we re-fetch it.
1256         timer = d->m_timeouts.get(timeoutId);
1257         if (!timer)
1258             return;
1259
1260         if (timer->repeatInterval() && timer->repeatInterval() < cMinimumTimerInterval) {
1261             timer->setNestingLevel(timer->nestingLevel() + 1);
1262             if (timer->nestingLevel() >= cMaxTimerNestingLevel)
1263                 timer->augmentRepeatInterval(cMinimumTimerInterval - timer->repeatInterval());
1264         }
1265         return;
1266     }
1267
1268     // Delete timer before executing the action for one-shot timers.
1269     ScheduledAction* action = timer->takeAction();
1270     d->m_timeouts.remove(timer->timeoutId());
1271     delete timer;
1272     action->execute(shell());
1273
1274     JSLock lock(false);
1275     delete action;
1276 }
1277
1278 void JSDOMWindowBase::disconnectFrame()
1279 {
1280     clearAllTimeouts();
1281 }
1282
1283 JSDOMWindowBase::ListenersMap& JSDOMWindowBase::jsEventListeners()
1284 {
1285     return d->jsEventListeners;
1286 }
1287
1288 JSDOMWindowBase::ListenersMap& JSDOMWindowBase::jsHTMLEventListeners()
1289 {
1290     return d->jsHTMLEventListeners;
1291 }
1292
1293 JSDOMWindowBase::UnprotectedListenersMap& JSDOMWindowBase::jsUnprotectedEventListeners()
1294 {
1295     return d->jsUnprotectedEventListeners;
1296 }
1297
1298 JSDOMWindowBase::UnprotectedListenersMap& JSDOMWindowBase::jsUnprotectedHTMLEventListeners()
1299 {
1300     return d->jsUnprotectedHTMLEventListeners;
1301 }
1302
1303 void DOMWindowTimer::fired()
1304 {
1305     timerNestingLevel = m_nestingLevel;
1306     m_object->timerFired(this);
1307     timerNestingLevel = 0;
1308 }
1309
1310 JSValue* toJS(ExecState*, DOMWindow* domWindow)
1311 {
1312     if (!domWindow)
1313         return jsNull();
1314     Frame* frame = domWindow->frame();
1315     if (!frame)
1316         return jsNull();
1317     return frame->script()->windowShell();
1318 }
1319
1320 JSDOMWindow* toJSDOMWindow(Frame* frame)
1321 {
1322     if (!frame)
1323         return 0;
1324     return frame->script()->windowShell()->window();
1325 }
1326
1327 JSDOMWindow* toJSDOMWindow(JSValue* value)
1328 {
1329     if (!value->isObject())
1330         return 0;
1331     const ClassInfo* classInfo = static_cast<JSObject*>(value)->classInfo();
1332     if (classInfo == &JSDOMWindow::s_info)
1333         return static_cast<JSDOMWindow*>(value);
1334     if (classInfo == &JSDOMWindowShell::s_info)
1335         return static_cast<JSDOMWindowShell*>(value)->window();
1336     return 0;
1337 }
1338
1339 } // namespace WebCore