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