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