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