Reviewed by Hyatt.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "kjs_window.h"
25
26 #include "Base64.h"
27 #include "Chrome.h"
28 #include "CString.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 "FrameView.h"
40 #include "HTMLDocument.h"
41 #include "JSCSSRule.h"
42 #include "JSCSSValue.h"
43 #include "JSDOMWindow.h"
44 #include "JSEvent.h"
45 #include "JSHTMLOptionElementConstructor.h"
46 #include "JSMutationEvent.h"
47 #include "JSNode.h"
48 #include "JSNodeFilter.h"
49 #include "JSRange.h"
50 #include "JSXMLHttpRequest.h"
51 #include "Logging.h"
52 #include "Page.h"
53 #include "PlugInInfoStore.h"
54 #include "RenderView.h"
55 #include "Screen.h"
56 #include "SelectionController.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 "kjs_traversal.h"
65 #include <wtf/MathExtras.h>
66
67 #if XSLT_SUPPORT
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 class DOMWindowTimer : public TimerBase {
83 public:
84     DOMWindowTimer(int timeoutId, int nestingLevel, Window* o, ScheduledAction* a)
85         : m_timeoutId(timeoutId), m_nestingLevel(nestingLevel), m_object(o), m_action(a) { }
86     virtual ~DOMWindowTimer() { delete m_action; }
87
88     int timeoutId() const { return m_timeoutId; }
89     
90     int nestingLevel() const { return m_nestingLevel; }
91     void setNestingLevel(int n) { m_nestingLevel = n; }
92     
93     ScheduledAction* action() const { return m_action; }
94     ScheduledAction* takeAction() { ScheduledAction* a = m_action; m_action = 0; return a; }
95
96 private:
97     virtual void fired();
98
99     int m_timeoutId;
100     int m_nestingLevel;
101     Window* m_object;
102     ScheduledAction* m_action;
103 };
104
105 class PausedTimeout {
106 public:
107     int timeoutId;
108     int nestingLevel;
109     double nextFireInterval;
110     double repeatInterval;
111     ScheduledAction *action;
112 };
113
114 ////////////////////// History Object ////////////////////////
115
116   class History : public DOMObject {
117     friend class HistoryFunc;
118   public:
119     History(ExecState *exec, Frame *f)
120       : m_frame(f)
121     {
122       setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype());
123     }
124     virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
125     JSValue *getValueProperty(ExecState *exec, int token) const;
126     virtual const ClassInfo* classInfo() const { return &info; }
127     static const ClassInfo info;
128     enum { Back, Forward, Go, Length };
129     virtual UString toString(ExecState *exec) const;
130     void disconnectFrame() { m_frame = 0; }
131   private:
132     Frame* m_frame;
133   };
134
135
136   class FrameArray : public DOMObject {
137   public:
138     FrameArray(ExecState *exec, Frame *f)
139       : m_frame(f)
140     {
141       setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype());
142     }
143     virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
144     JSValue *getValueProperty(ExecState *exec, int token);
145     virtual UString toString(ExecState *exec) const;
146     enum { Length, Location };
147     void disconnectFrame() { m_frame = 0; }
148   private:
149     static JSValue *indexGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
150     static JSValue *nameGetter(ExecState *, JSObject *, const Identifier&, const PropertySlot&);
151
152     virtual const ClassInfo* classInfo() const { return &info; }
153     static const ClassInfo info;
154
155     Frame* m_frame;
156   };
157
158 }
159
160 #include "kjs_window.lut.h"
161
162 namespace KJS {
163
164 ////////////////////// Screen Object ////////////////////////
165
166 // table for screen object
167 /*
168 @begin ScreenTable 7
169   height        Screen::Height          DontEnum|ReadOnly
170   width         Screen::Width           DontEnum|ReadOnly
171   colorDepth    Screen::ColorDepth      DontEnum|ReadOnly
172   pixelDepth    Screen::PixelDepth      DontEnum|ReadOnly
173   availLeft     Screen::AvailLeft       DontEnum|ReadOnly
174   availTop      Screen::AvailTop        DontEnum|ReadOnly
175   availHeight   Screen::AvailHeight     DontEnum|ReadOnly
176   availWidth    Screen::AvailWidth      DontEnum|ReadOnly
177 @end
178 */
179
180 const ClassInfo Screen::info = { "Screen", 0, &ScreenTable, 0 };
181
182 // We set the object prototype so that toString is implemented
183 Screen::Screen(ExecState* exec, Frame* f)
184     : m_frame(f)
185 {
186     setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype());
187 }
188
189 bool Screen::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
190 {
191   return getStaticValueSlot<Screen, JSObject>(exec, &ScreenTable, this, propertyName, slot);
192 }
193
194 JSValue* Screen::getValueProperty(ExecState*, int token) const
195 {
196   Widget* widget = m_frame ? m_frame->view() : 0;  
197
198   switch (token) {
199   case Height:
200     return jsNumber(screenRect(widget).height());
201   case Width:
202     return jsNumber(screenRect(widget).width());
203   case ColorDepth:
204   case PixelDepth:
205     return jsNumber(screenDepth(widget));
206   case AvailLeft:
207     return jsNumber(screenAvailableRect(widget).x());
208   case AvailTop:
209     return jsNumber(screenAvailableRect(widget).y());
210   case AvailHeight:
211     return jsNumber(screenAvailableRect(widget).height());
212   case AvailWidth:
213     return jsNumber(screenAvailableRect(widget).width());
214   default:
215     return jsUndefined();
216   }
217 }
218
219 ////////////////////// Window Object ////////////////////////
220
221 const ClassInfo Window::info = { "Window", 0, &WindowTable, 0 };
222
223 /*
224 @begin WindowTable 103
225   atob          Window::AToB            DontDelete|Function 1
226   btoa          Window::BToA            DontDelete|Function 1
227   closed        Window::Closed          DontDelete|ReadOnly
228   crypto        Window::Crypto          DontDelete|ReadOnly
229   defaultStatus Window::DefaultStatus   DontDelete
230   defaultstatus Window::DefaultStatus   DontDelete
231   status        Window::Status          DontDelete
232   DOMException  Window::DOMException    DontDelete
233   frames        Window::Frames          DontDelete|ReadOnly
234   history       Window::History_        DontDelete|ReadOnly
235   event         Window::Event_          DontDelete
236   innerHeight   Window::InnerHeight     DontDelete|ReadOnly
237   innerWidth    Window::InnerWidth      DontDelete|ReadOnly
238   length        Window::Length          DontDelete|ReadOnly
239   location      Window::Location_       DontDelete
240   locationbar   Window::Locationbar     DontDelete
241   name          Window::Name            DontDelete
242   navigator     Window::Navigator_      DontDelete|ReadOnly
243   clientInformation     Window::ClientInformation       DontDelete|ReadOnly
244   menubar       Window::Menubar         DontDelete|ReadOnly
245   offscreenBuffering    Window::OffscreenBuffering      DontDelete|ReadOnly
246   opener        Window::Opener          DontDelete|ReadOnly
247   outerHeight   Window::OuterHeight     DontDelete|ReadOnly
248   outerWidth    Window::OuterWidth      DontDelete|ReadOnly
249   pageXOffset   Window::PageXOffset     DontDelete|ReadOnly
250   pageYOffset   Window::PageYOffset     DontDelete|ReadOnly
251   parent        Window::Parent          DontDelete|ReadOnly
252   personalbar   Window::Personalbar     DontDelete|ReadOnly
253   screenX       Window::ScreenX         DontDelete|ReadOnly
254   screenY       Window::ScreenY         DontDelete|ReadOnly
255   screenLeft    Window::ScreenLeft      DontDelete|ReadOnly
256   screenTop     Window::ScreenTop       DontDelete|ReadOnly
257   scrollbars    Window::Scrollbars      DontDelete|ReadOnly
258   statusbar     Window::Statusbar       DontDelete|ReadOnly
259   toolbar       Window::Toolbar         DontDelete|ReadOnly
260   scroll        Window::Scroll          DontDelete|Function 2
261   scrollBy      Window::ScrollBy        DontDelete|Function 2
262   scrollTo      Window::ScrollTo        DontDelete|Function 2
263   scrollX       Window::ScrollX         DontDelete|ReadOnly
264   scrollY       Window::ScrollY         DontDelete|ReadOnly
265   moveBy        Window::MoveBy          DontDelete|Function 2
266   moveTo        Window::MoveTo          DontDelete|Function 2
267   resizeBy      Window::ResizeBy        DontDelete|Function 2
268   resizeTo      Window::ResizeTo        DontDelete|Function 2
269   self          Window::Self            DontDelete|ReadOnly
270   window        Window::Window_         DontDelete|ReadOnly
271   top           Window::Top             DontDelete|ReadOnly
272   screen        Window::Screen_         DontDelete|ReadOnly
273   Image         Window::Image           DontDelete
274   Option        Window::Option          DontDelete
275   XMLHttpRequest        Window::XMLHttpRequest  DontDelete
276   XSLTProcessor Window::XSLTProcessor_  DontDelete
277   alert         Window::Alert           DontDelete|Function 1
278   confirm       Window::Confirm         DontDelete|Function 1
279   prompt        Window::Prompt          DontDelete|Function 2
280   open          Window::Open            DontDelete|Function 3
281   print         Window::Print           DontDelete|Function 2
282   setTimeout    Window::SetTimeout      DontDelete|Function 2
283   clearTimeout  Window::ClearTimeout    DontDelete|Function 1
284   focus         Window::Focus           DontDelete|Function 0
285   getSelection  Window::GetSelection    DontDelete|Function 0
286   blur          Window::Blur            DontDelete|Function 0
287   close         Window::Close           DontDelete|Function 0
288   setInterval   Window::SetInterval     DontDelete|Function 2
289   clearInterval Window::ClearInterval   DontDelete|Function 1
290   captureEvents Window::CaptureEvents   DontDelete|Function 0
291   releaseEvents Window::ReleaseEvents   DontDelete|Function 0
292 # Warning, when adding a function to this object you need to add a case in Window::get
293   addEventListener      Window::AddEventListener        DontDelete|Function 3
294   removeEventListener   Window::RemoveEventListener     DontDelete|Function 3
295   onabort       Window::Onabort         DontDelete
296   onblur        Window::Onblur          DontDelete
297   onchange      Window::Onchange        DontDelete
298   onclick       Window::Onclick         DontDelete
299   ondblclick    Window::Ondblclick      DontDelete
300   onerror       Window::Onerror         DontDelete
301   onfocus       Window::Onfocus         DontDelete
302   onkeydown     Window::Onkeydown       DontDelete
303   onkeypress    Window::Onkeypress      DontDelete
304   onkeyup       Window::Onkeyup         DontDelete
305   onload        Window::Onload          DontDelete
306   onmousedown   Window::Onmousedown     DontDelete
307   onmousemove   Window::Onmousemove     DontDelete
308   onmouseout    Window::Onmouseout      DontDelete
309   onmouseover   Window::Onmouseover     DontDelete
310   onmouseup     Window::Onmouseup       DontDelete
311   onmousewheel  Window::OnWindowMouseWheel      DontDelete
312   onreset       Window::Onreset         DontDelete
313   onresize      Window::Onresize        DontDelete
314   onscroll      Window::Onscroll        DontDelete
315   onsearch      Window::Onsearch        DontDelete
316   onselect      Window::Onselect        DontDelete
317   onsubmit      Window::Onsubmit        DontDelete
318   onunload      Window::Onunload        DontDelete
319   onbeforeunload Window::Onbeforeunload DontDelete
320   frameElement  Window::FrameElement    DontDelete|ReadOnly
321   showModalDialog Window::ShowModalDialog    DontDelete|Function 1
322 @end
323 */
324 KJS_IMPLEMENT_PROTOTYPE_FUNCTION(WindowFunc)
325
326 Window::Window(DOMWindow* window)
327   : m_frame(window->frame())
328   , screen(0)
329   , history(0)
330   , frames(0)
331   , loc(0)
332   , m_selection(0)
333   , m_locationbar(0)
334   , m_menubar(0)
335   , m_personalbar(0)
336   , m_scrollbars(0)
337   , m_statusbar(0)
338   , m_toolbar(0)
339   , m_evt(0)
340   , m_returnValueSlot(0)
341 {
342 }
343
344 Window::~Window()
345 {
346     clearAllTimeouts();
347
348     // Clear any backpointers to the window
349
350     ListenersMap::iterator i2 = jsEventListeners.begin();
351     ListenersMap::iterator e2 = jsEventListeners.end();
352     for (; i2 != e2; ++i2)
353         i2->second->clearWindowObj();
354     i2 = jsHTMLEventListeners.begin();
355     e2 = jsHTMLEventListeners.end();
356     for (; i2 != e2; ++i2)
357         i2->second->clearWindowObj();
358
359     UnprotectedListenersMap::iterator i1 = jsUnprotectedEventListeners.begin();
360     UnprotectedListenersMap::iterator e1 = jsUnprotectedEventListeners.end();
361     for (; i1 != e1; ++i1)
362         i1->second->clearWindowObj();
363     i1 = jsUnprotectedHTMLEventListeners.begin();
364     e1 = jsUnprotectedHTMLEventListeners.end();
365     for (; i1 != e1; ++i1)
366         i1->second->clearWindowObj();
367 }
368
369 DOMWindow* Window::impl() const
370 {
371      return m_frame->domWindow();
372 }
373
374 ScriptInterpreter *Window::interpreter() const
375 {
376     return m_frame->scriptProxy()->interpreter();
377 }
378
379 Window *Window::retrieveWindow(Frame *f)
380 {
381     JSObject *o = retrieve(f)->getObject();
382
383     ASSERT(o || !f->settings()->isJavaScriptEnabled());
384     return static_cast<Window *>(o);
385 }
386
387 Window *Window::retrieveActive(ExecState *exec)
388 {
389     JSValue *imp = exec->dynamicInterpreter()->globalObject();
390     ASSERT(imp);
391     return static_cast<Window*>(imp);
392 }
393
394 JSValue *Window::retrieve(Frame *p)
395 {
396     ASSERT(p);
397     if (KJSProxy *proxy = p->scriptProxy())
398         return proxy->interpreter()->globalObject(); // the Global object is the "window"
399   
400     return jsUndefined(); // This can happen with JS disabled on the domain of that window
401 }
402
403 Location *Window::location() const
404 {
405   if (!loc)
406     loc = new Location(m_frame);
407   return loc;
408 }
409
410 Selection *Window::selection() const
411 {
412   if (!m_selection)
413     m_selection = new Selection(m_frame);
414   return m_selection;
415 }
416
417 BarInfo *Window::locationbar(ExecState *exec) const
418 {
419   if (!m_locationbar)
420     m_locationbar = new BarInfo(exec, m_frame, BarInfo::Locationbar);
421   return m_locationbar;
422 }
423
424 BarInfo *Window::menubar(ExecState *exec) const
425 {
426   if (!m_menubar)
427     m_menubar = new BarInfo(exec, m_frame, BarInfo::Menubar);
428   return m_menubar;
429 }
430
431 BarInfo *Window::personalbar(ExecState *exec) const
432 {
433   if (!m_personalbar)
434     m_personalbar = new BarInfo(exec, m_frame, BarInfo::Personalbar);
435   return m_personalbar;
436 }
437
438 BarInfo *Window::statusbar(ExecState *exec) const
439 {
440   if (!m_statusbar)
441     m_statusbar = new BarInfo(exec, m_frame, BarInfo::Statusbar);
442   return m_statusbar;
443 }
444
445 BarInfo *Window::toolbar(ExecState *exec) const
446 {
447   if (!m_toolbar)
448     m_toolbar = new BarInfo(exec, m_frame, BarInfo::Toolbar);
449   return m_toolbar;
450 }
451
452 BarInfo *Window::scrollbars(ExecState *exec) const
453 {
454   if (!m_scrollbars)
455     m_scrollbars = new BarInfo(exec, m_frame, BarInfo::Scrollbars);
456   return m_scrollbars;
457 }
458
459 // reference our special objects during garbage collection
460 void Window::mark()
461 {
462   JSObject::mark();
463   if (screen && !screen->marked())
464     screen->mark();
465   if (history && !history->marked())
466     history->mark();
467   if (frames && !frames->marked())
468     frames->mark();
469   if (loc && !loc->marked())
470     loc->mark();
471   if (m_selection && !m_selection->marked())
472     m_selection->mark();
473   if (m_locationbar && !m_locationbar->marked())
474     m_locationbar->mark();
475   if (m_menubar && !m_menubar->marked())
476     m_menubar->mark();
477   if (m_personalbar && !m_personalbar->marked())
478     m_personalbar->mark();
479   if (m_scrollbars && !m_scrollbars->marked())
480     m_scrollbars->mark();
481   if (m_statusbar && !m_statusbar->marked())
482     m_statusbar->mark();
483   if (m_toolbar && !m_toolbar->marked())
484     m_toolbar->mark();
485 }
486
487 UString Window::toString(ExecState *) const
488 {
489   return "[object Window]";
490 }
491
492 static bool allowPopUp(ExecState *exec, Window *window)
493 {
494     return window->frame()
495         && (window->frame()->settings()->JavaScriptCanOpenWindowsAutomatically()
496             || static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture());
497 }
498
499 static HashMap<String, String> parseModalDialogFeatures(ExecState *exec, JSValue *featuresArg)
500 {
501     HashMap<String, String> map;
502
503     Vector<String> features = String(featuresArg->toString(exec)).split(';');
504     Vector<String>::const_iterator end = features.end();
505     for (Vector<String>::const_iterator it = features.begin(); it != end; ++it) {
506         String s = *it;
507         int pos = s.find('=');
508         int colonPos = s.find(':');
509         if (pos >= 0 && colonPos >= 0)
510             continue; // ignore any strings that have both = and :
511         if (pos < 0)
512             pos = colonPos;
513         if (pos < 0) {
514             // null string for value means key without value
515             map.set(s.stripWhiteSpace().lower(), String());
516         } else {
517             String key = s.left(pos).stripWhiteSpace().lower();
518             String val = s.substring(pos + 1).stripWhiteSpace().lower();
519             int spacePos = val.find(' ');
520             if (spacePos != -1)
521                 val = val.left(spacePos);
522             map.set(key, val);
523         }
524     }
525
526     return map;
527 }
528
529 static bool boolFeature(const HashMap<String, String>& features, const char* key, bool defaultValue = false)
530 {
531     HashMap<String, String>::const_iterator it = features.find(key);
532     if (it == features.end())
533         return defaultValue;
534     const String& value = it->second;
535     return value.isNull() || value == "1" || value == "yes" || value == "on";
536 }
537
538 static float floatFeature(const HashMap<String, String> &features, const char *key, float min, float max, float defaultValue)
539 {
540     HashMap<String, String>::const_iterator it = features.find(key);
541     if (it == features.end())
542         return defaultValue;
543     // FIXME: Can't distinguish "0q" from string with no digits in it -- both return d == 0 and ok == false.
544     // Would be good to tell them apart somehow since string with no digits should be default value and
545     // "0q" should be minimum value.
546     bool ok;
547     double d = it->second.toDouble(&ok);
548     if ((d == 0 && !ok) || isnan(d))
549         return defaultValue;
550     if (d < min || max <= min)
551         return min;
552     if (d > max)
553         return max;
554     return static_cast<int>(d);
555 }
556
557 static Frame* createNewWindow(ExecState* exec, Window* openerWindow, const DeprecatedString &URL,
558     const String& frameName, const WindowFeatures& windowFeatures, JSValue* dialogArgs)
559 {
560     Frame* openerFrame = openerWindow->frame();
561     Frame* activeFrame = Window::retrieveActive(exec)->frame();
562
563     ResourceRequest request = ResourceRequest(KURL(""));
564     if (activeFrame)
565         request.setHTTPReferrer(activeFrame->loader()->outgoingReferrer());
566     FrameLoadRequest frameRequest(request, frameName);
567
568     // FIXME: It's much better for client API if a new window starts with a URL, here where we
569     // know what URL we are going to open. Unfortunately, this code passes the empty string
570     // for the URL, but there's a reason for that. Before loading we have to set up the opener,
571     // openedByJS, and dialogArguments values. Also, to decide whether to use the URL we currently
572     // do an isSafeScript call using the window we create, which can't be done before creating it.
573     // We'd have to resolve all those issues to pass the URL instead of "".
574
575     Frame* newFrame = openerFrame->loader()->createWindow(frameRequest, windowFeatures);
576     if (!newFrame)
577         return 0;
578
579     Window* newWindow = Window::retrieveWindow(newFrame);
580
581     newFrame->loader()->setOpener(openerFrame);
582     newFrame->loader()->setOpenedByJavaScript();
583     if (dialogArgs)
584         newWindow->putDirect("dialogArguments", dialogArgs);
585
586     Document *activeDoc = activeFrame ? activeFrame->document() : 0;
587     if (!URL.isEmpty() && activeDoc) {
588         DeprecatedString completedURL = activeDoc->completeURL(URL);
589         if (!completedURL.startsWith("javascript:", false) || newWindow->isSafeScript(exec)) {
590             bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
591             newFrame->loader()->changeLocation(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture);
592         }
593     }
594
595     return newFrame;
596 }
597
598 static bool canShowModalDialog(const Window *window)
599 {
600     if (Frame* frame = window->frame())
601         return frame->page()->chrome()->canRunModal();
602     return false;
603 }
604
605 static bool canShowModalDialogNow(const Window *window)
606 {
607     if (Frame* frame = window->frame())
608         return frame->page()->chrome()->canRunModalNow();
609     return false;
610 }
611
612 static JSValue* showModalDialog(ExecState* exec, Window* openerWindow, const List& args)
613 {
614     UString URL = args[0]->toString(exec);
615
616     if (!canShowModalDialogNow(openerWindow) || !allowPopUp(exec, openerWindow))
617         return jsUndefined();
618     
619     const HashMap<String, String> features = parseModalDialogFeatures(exec, args[2]);
620
621     bool trusted = false;
622
623     WindowFeatures wargs;
624
625     // The following features from Microsoft's documentation are not implemented:
626     // - default font settings
627     // - width, height, left, and top specified in units other than "px"
628     // - edge (sunken or raised, default is raised)
629     // - dialogHide: trusted && boolFeature(features, "dialoghide"), makes dialog hide when you print
630     // - help: boolFeature(features, "help", true), makes help icon appear in dialog (what does it do on Windows?)
631     // - unadorned: trusted && boolFeature(features, "unadorned");
632
633     FloatRect screenRect = screenAvailableRect(openerWindow->frame()->view());
634
635     wargs.width = floatFeature(features, "dialogwidth", 100, screenRect.width(), 620); // default here came from frame size of dialog in MacIE
636     wargs.widthSet = true;
637     wargs.height = floatFeature(features, "dialogheight", 100, screenRect.height(), 450); // default here came from frame size of dialog in MacIE
638     wargs.heightSet = true;
639
640     wargs.x = floatFeature(features, "dialogleft", screenRect.x(), screenRect.right() - wargs.width, -1);
641     wargs.xSet = wargs.x > 0;
642     wargs.y = floatFeature(features, "dialogtop", screenRect.y(), screenRect.bottom() - wargs.height, -1);
643     wargs.ySet = wargs.y > 0;
644
645     if (boolFeature(features, "center", true)) {
646         if (!wargs.xSet) {
647             wargs.x = screenRect.x() + (screenRect.width() - wargs.width) / 2;
648             wargs.xSet = true;
649         }
650         if (!wargs.ySet) {
651             wargs.y = screenRect.y() + (screenRect.height() - wargs.height) / 2;
652             wargs.ySet = true;
653         }
654     }
655
656     wargs.dialog = true;
657     wargs.resizable = boolFeature(features, "resizable");
658     wargs.scrollbarsVisible = boolFeature(features, "scroll", true);
659     wargs.statusBarVisible = boolFeature(features, "status", !trusted);
660     wargs.menuBarVisible = false;
661     wargs.toolBarVisible = false;
662     wargs.locationBarVisible = false;
663     wargs.fullscreen = false;
664     
665     Frame* dialogFrame = createNewWindow(exec, openerWindow, URL, "", wargs, args[1]);
666     if (!dialogFrame)
667         return jsUndefined();
668
669     Window* dialogWindow = Window::retrieveWindow(dialogFrame);
670
671     // Get the return value either just before clearing the dialog window's
672     // properties (in Window::clear), or when on return from runModal.
673     JSValue* returnValue = 0;
674     dialogWindow->setReturnValueSlot(&returnValue);
675     dialogFrame->page()->chrome()->runModal();
676     dialogWindow->setReturnValueSlot(0);
677
678     // If we don't have a return value, get it now.
679     // Either Window::clear was not called yet, or there was no return value,
680     // and in that case, there's no harm in trying again (no benefit either).
681     if (!returnValue)
682         returnValue = dialogWindow->getDirect("returnValue");
683
684     return returnValue ? returnValue : jsUndefined();
685 }
686
687 JSValue *Window::getValueProperty(ExecState *exec, int token) const
688 {
689    ASSERT(token == Closed || m_frame);
690
691    switch (token) {
692    case Closed:
693       return jsBoolean(!m_frame);
694    case Crypto:
695       return jsUndefined(); // ###
696    case DefaultStatus:
697       return jsString(UString(m_frame->jsDefaultStatusBarText()));
698    case DOMException:
699       return getDOMExceptionConstructor(exec);
700    case Status:
701       return jsString(UString(m_frame->jsStatusBarText()));
702     case Frames:
703       if (!frames)
704         frames = new FrameArray(exec, m_frame);
705       return frames;
706     case History_:
707       if (!history)
708         history = new History(exec, m_frame);
709       return history;
710     case Event_:
711       if (!m_evt)
712         return jsUndefined();
713       return toJS(exec, m_evt);
714     case InnerHeight:
715       if (!m_frame->view())
716         return jsUndefined();
717       return jsNumber(m_frame->view()->visibleHeight());
718     case InnerWidth:
719       if (!m_frame->view())
720         return jsUndefined();
721       return jsNumber(m_frame->view()->visibleWidth());
722     case Length:
723       return jsNumber(m_frame->tree()->childCount());
724     case Location_:
725       return location();
726     case Name:
727       return jsString(m_frame->tree()->name());
728     case Navigator_:
729     case ClientInformation: {
730       // Store the navigator in the object so we get the same one each time.
731       Navigator *n = new Navigator(exec, m_frame);
732       // FIXME: this will make the "navigator" object accessible from windows that fail
733       // the security check the first time, but not subsequent times, seems weird.
734       const_cast<Window *>(this)->putDirect("navigator", n, DontDelete|ReadOnly);
735       const_cast<Window *>(this)->putDirect("clientInformation", n, DontDelete|ReadOnly);
736       return n;
737     }
738     case Locationbar:
739       return locationbar(exec);
740     case Menubar:
741       return menubar(exec);
742     case OffscreenBuffering:
743       return jsBoolean(true);
744     case Opener:
745       if (m_frame->loader()->opener())
746         return retrieve(m_frame->loader()->opener());
747       return jsNull();
748     case OuterHeight:
749         return jsNumber(m_frame->page()->chrome()->windowRect().height());
750     case OuterWidth:
751         return jsNumber(m_frame->page()->chrome()->windowRect().width());
752     case PageXOffset:
753       if (!m_frame->view())
754         return jsUndefined();
755       updateLayout();
756       return jsNumber(m_frame->view()->contentsX());
757     case PageYOffset:
758       if (!m_frame->view())
759         return jsUndefined();
760       updateLayout();
761       return jsNumber(m_frame->view()->contentsY());
762     case Parent:
763       return retrieve(m_frame->tree()->parent() ? m_frame->tree()->parent() : m_frame);
764     case Personalbar:
765       return personalbar(exec);
766     case ScreenLeft:
767     case ScreenX:
768       return jsNumber(m_frame->page()->chrome()->windowRect().x());
769     case ScreenTop:
770     case ScreenY:
771       return jsNumber(m_frame->page()->chrome()->windowRect().y());
772     case ScrollX:
773       if (!m_frame->view())
774         return jsUndefined();
775       updateLayout();
776       return jsNumber(m_frame->view()->contentsX());
777     case ScrollY:
778       if (!m_frame->view())
779         return jsUndefined();
780       updateLayout();
781       return jsNumber(m_frame->view()->contentsY());
782     case Scrollbars:
783       return scrollbars(exec);
784     case Statusbar:
785       return statusbar(exec);
786     case Toolbar:
787       return toolbar(exec);
788     case Self:
789     case Window_:
790       return retrieve(m_frame);
791     case Top:
792       return retrieve(m_frame->page()->mainFrame());
793     case Screen_:
794       if (!screen)
795         screen = new Screen(exec, m_frame);
796       return screen;
797     case Image:
798       // FIXME: this property (and the few below) probably shouldn't create a new object every
799       // time
800       return new ImageConstructorImp(exec, m_frame->document());
801     case Option:
802       return new JSHTMLOptionElementConstructor(exec, m_frame->document());
803     case XMLHttpRequest:
804       return new JSXMLHttpRequestConstructorImp(exec, m_frame->document());
805 #ifdef XSLT_SUPPORT
806     case XSLTProcessor_:
807       return new XSLTProcessorConstructorImp(exec);
808 #else
809     case XSLTProcessor_:
810       return jsUndefined();
811 #endif
812     case FrameElement:
813       if (Document* doc = m_frame->document())
814         if (Element* fe = doc->ownerElement())
815           if (checkNodeSecurity(exec, fe))
816             return toJS(exec, fe);
817       return jsUndefined();
818    }
819
820    if (!isSafeScript(exec))
821      return jsUndefined();
822
823    switch (token) {
824    case Onabort:
825      return getListener(exec, abortEvent);
826    case Onblur:
827      return getListener(exec, blurEvent);
828    case Onchange:
829      return getListener(exec, changeEvent);
830    case Onclick:
831      return getListener(exec, clickEvent);
832    case Ondblclick:
833      return getListener(exec, dblclickEvent);
834    case Onerror:
835      return getListener(exec, errorEvent);
836    case Onfocus:
837      return getListener(exec, focusEvent);
838    case Onkeydown:
839      return getListener(exec, keydownEvent);
840    case Onkeypress:
841      return getListener(exec, keypressEvent);
842    case Onkeyup:
843      return getListener(exec, keyupEvent);
844    case Onload:
845      return getListener(exec, loadEvent);
846    case Onmousedown:
847      return getListener(exec, mousedownEvent);
848    case Onmousemove:
849      return getListener(exec, mousemoveEvent);
850    case Onmouseout:
851      return getListener(exec, mouseoutEvent);
852    case Onmouseover:
853      return getListener(exec, mouseoverEvent);
854    case Onmouseup:
855      return getListener(exec, mouseupEvent);
856    case OnWindowMouseWheel:
857      return getListener(exec, mousewheelEvent);
858    case Onreset:
859      return getListener(exec, resetEvent);
860    case Onresize:
861      return getListener(exec,resizeEvent);
862    case Onscroll:
863      return getListener(exec,scrollEvent);
864    case Onsearch:
865      return getListener(exec,searchEvent);
866    case Onselect:
867      return getListener(exec,selectEvent);
868    case Onsubmit:
869      return getListener(exec,submitEvent);
870    case Onbeforeunload:
871       return getListener(exec, beforeunloadEvent);
872     case Onunload:
873      return getListener(exec, unloadEvent);
874    }
875    ASSERT(0);
876    return jsUndefined();
877 }
878
879 JSValue* Window::childFrameGetter(ExecState*, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
880 {
881     return retrieve(static_cast<Window*>(slot.slotBase())->m_frame->tree()->child(AtomicString(propertyName)));
882 }
883
884 JSValue* Window::indexGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
885 {
886     return retrieve(static_cast<Window*>(slot.slotBase())->m_frame->tree()->child(slot.index()));
887 }
888
889 JSValue *Window::namedItemGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
890 {
891   Window *thisObj = static_cast<Window *>(slot.slotBase());
892   Document *doc = thisObj->m_frame->document();
893   ASSERT(thisObj->isSafeScript(exec) && doc && doc->isHTMLDocument());
894
895   String name = propertyName;
896   RefPtr<WebCore::HTMLCollection> collection = doc->windowNamedItems(name);
897   if (collection->length() == 1)
898     return toJS(exec, collection->firstItem());
899   else 
900     return getHTMLCollection(exec, collection.get());
901 }
902
903 bool Window::getOverridePropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
904 {
905   // we don't want any properties other than "closed" on a closed window
906   if (!m_frame) {
907     if (propertyName == "closed") {
908       slot.setStaticEntry(this, Lookup::findEntry(&WindowTable, "closed"), staticValueGetter<Window>);
909       return true;
910     }
911     if (propertyName == "close") {
912       const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName);
913       slot.setStaticEntry(this, entry, staticFunctionGetter<WindowFunc>);
914       return true;
915     }
916
917     slot.setUndefined(this);
918     return true;
919   }
920
921   // Look for overrides first
922   JSValue **val = getDirectLocation(propertyName);
923   if (val) {
924     if (isSafeScript(exec))
925       slot.setValueSlot(this, val);
926     else
927       slot.setUndefined(this);
928     return true;
929   }
930   
931   return false;
932 }
933
934 bool Window::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
935 {
936   // Check for child frames by name before built-in properties to
937   // match Mozilla. This does not match IE, but some sites end up
938   // naming frames things that conflict with window properties that
939   // are in Moz but not IE. Since we have some of these, we have to do
940   // it the Moz way.
941   AtomicString atomicPropertyName = propertyName;
942   if (m_frame->tree()->child(atomicPropertyName)) {
943     slot.setCustom(this, childFrameGetter);
944     return true;
945   }
946   
947   const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName);
948   if (entry) {
949     if (entry->attr & Function) {
950       switch (entry->value) {
951       case Focus:
952       case Blur:
953       case Close:
954         slot.setStaticEntry(this, entry, staticFunctionGetter<WindowFunc>);
955         break;
956       case ShowModalDialog:
957         if (!canShowModalDialog(this))
958           return false;
959         // fall through
960       default:
961         if (isSafeScript(exec))
962           slot.setStaticEntry(this, entry, staticFunctionGetter<WindowFunc>);
963         else
964           slot.setUndefined(this);
965       } 
966     } else
967       slot.setStaticEntry(this, entry, staticValueGetter<Window>);
968     return true;
969   }
970
971   // FIXME: Search the whole frame hierachy somewhere around here.
972   // We need to test the correct priority order.
973   
974   // allow window[1] or parent[1] etc. (#56983)
975   bool ok;
976   unsigned i = propertyName.toArrayIndex(&ok);
977   if (ok && i < m_frame->tree()->childCount()) {
978     slot.setCustomIndex(this, i, indexGetter);
979     return true;
980   }
981
982   // allow shortcuts like 'Image1' instead of document.images.Image1
983   Document *doc = m_frame->document();
984   if (isSafeScript(exec) && doc && doc->isHTMLDocument()) {
985     AtomicString atomicPropertyName = propertyName;
986     if (static_cast<HTMLDocument*>(doc)->hasNamedItem(atomicPropertyName) || doc->getElementById(atomicPropertyName)) {
987       slot.setCustom(this, namedItemGetter);
988       return true;
989     }
990   }
991
992   if (!isSafeScript(exec)) {
993     slot.setUndefined(this);
994     return true;
995   }
996
997   return JSObject::getOwnPropertySlot(exec, propertyName, slot);
998 }
999
1000 void Window::put(ExecState* exec, const Identifier &propertyName, JSValue *value, int attr)
1001 {
1002   // Called by an internal KJS call.
1003   // If yes, save time and jump directly to JSObject.
1004   if ((attr != None && attr != DontDelete)
1005        // Same thing if we have a local override (e.g. "var location")
1006        || (JSObject::getDirect(propertyName) && isSafeScript(exec))) {
1007     JSObject::put( exec, propertyName, value, attr );
1008     return;
1009   }
1010
1011   const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName);
1012   if (entry) {
1013     switch(entry->value) {
1014     case Status:
1015       m_frame->setJSStatusBarText(value->toString(exec));
1016       return;
1017     case DefaultStatus:
1018       m_frame->setJSDefaultStatusBarText(value->toString(exec));
1019       return;
1020     case Location_: {
1021       Frame* p = Window::retrieveActive(exec)->m_frame;
1022       if (p) {
1023         DeprecatedString dstUrl = p->document()->completeURL(DeprecatedString(value->toString(exec)));
1024         if (!dstUrl.startsWith("javascript:", false) || isSafeScript(exec)) {
1025           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1026           // We want a new history item if this JS was called via a user gesture
1027           m_frame->loader()->scheduleLocationChange(dstUrl, p->loader()->outgoingReferrer(), !userGesture, userGesture);
1028         }
1029       }
1030       return;
1031     }
1032     case Onabort:
1033       if (isSafeScript(exec))
1034         setListener(exec, abortEvent,value);
1035       return;
1036     case Onblur:
1037       if (isSafeScript(exec))
1038         setListener(exec, blurEvent,value);
1039       return;
1040     case Onchange:
1041       if (isSafeScript(exec))
1042         setListener(exec, changeEvent,value);
1043       return;
1044     case Onclick:
1045       if (isSafeScript(exec))
1046         setListener(exec,clickEvent,value);
1047       return;
1048     case Ondblclick:
1049       if (isSafeScript(exec))
1050         setListener(exec, dblclickEvent,value);
1051       return;
1052     case Onerror:
1053       if (isSafeScript(exec))
1054         setListener(exec, errorEvent, value);
1055       return;
1056     case Onfocus:
1057       if (isSafeScript(exec))
1058         setListener(exec,focusEvent,value);
1059       return;
1060     case Onkeydown:
1061       if (isSafeScript(exec))
1062         setListener(exec,keydownEvent,value);
1063       return;
1064     case Onkeypress:
1065       if (isSafeScript(exec))
1066         setListener(exec,keypressEvent,value);
1067       return;
1068     case Onkeyup:
1069       if (isSafeScript(exec))
1070         setListener(exec,keyupEvent,value);
1071       return;
1072     case Onload:
1073       if (isSafeScript(exec))
1074         setListener(exec,loadEvent,value);
1075       return;
1076     case Onmousedown:
1077       if (isSafeScript(exec))
1078         setListener(exec,mousedownEvent,value);
1079       return;
1080     case Onmousemove:
1081       if (isSafeScript(exec))
1082         setListener(exec,mousemoveEvent,value);
1083       return;
1084     case Onmouseout:
1085       if (isSafeScript(exec))
1086         setListener(exec,mouseoutEvent,value);
1087       return;
1088     case Onmouseover:
1089       if (isSafeScript(exec))
1090         setListener(exec,mouseoverEvent,value);
1091       return;
1092     case Onmouseup:
1093       if (isSafeScript(exec))
1094         setListener(exec,mouseupEvent,value);
1095       return;
1096     case OnWindowMouseWheel:
1097       if (isSafeScript(exec))
1098         setListener(exec, mousewheelEvent,value);
1099       return;
1100     case Onreset:
1101       if (isSafeScript(exec))
1102         setListener(exec,resetEvent,value);
1103       return;
1104     case Onresize:
1105       if (isSafeScript(exec))
1106         setListener(exec,resizeEvent,value);
1107       return;
1108     case Onscroll:
1109       if (isSafeScript(exec))
1110         setListener(exec,scrollEvent,value);
1111       return;
1112     case Onsearch:
1113         if (isSafeScript(exec))
1114             setListener(exec,searchEvent,value);
1115         return;
1116     case Onselect:
1117       if (isSafeScript(exec))
1118         setListener(exec,selectEvent,value);
1119       return;
1120     case Onsubmit:
1121       if (isSafeScript(exec))
1122         setListener(exec,submitEvent,value);
1123       return;
1124     case Onbeforeunload:
1125       if (isSafeScript(exec))
1126         setListener(exec, beforeunloadEvent, value);
1127       return;
1128     case Onunload:
1129       if (isSafeScript(exec))
1130         setListener(exec, unloadEvent, value);
1131       return;
1132     case Name:
1133       if (isSafeScript(exec))
1134         m_frame->tree()->setName(value->toString(exec));
1135       return;
1136     default:
1137       break;
1138     }
1139   }
1140   if (isSafeScript(exec))
1141     JSObject::put(exec, propertyName, value, attr);
1142 }
1143
1144 bool Window::toBoolean(ExecState *) const
1145 {
1146   return m_frame;
1147 }
1148
1149 void Window::scheduleClose()
1150 {
1151   m_frame->scheduleClose();
1152 }
1153
1154 static bool shouldLoadAsEmptyDocument(const KURL &url)
1155 {
1156   return url.protocol().lower() == "about" || url.isEmpty();
1157 }
1158
1159 bool Window::isSafeScript(const ScriptInterpreter *origin, const ScriptInterpreter *target)
1160 {
1161     if (origin == target)
1162         return true;
1163         
1164     Frame* originFrame = origin->frame();
1165     Frame* targetFrame = target->frame();
1166
1167     // JS may be attempting to access the "window" object, which should be valid,
1168     // even if the document hasn't been constructed yet.  If the document doesn't
1169     // exist yet allow JS to access the window object.
1170     if (!targetFrame->document())
1171         return true;
1172
1173     WebCore::Document *originDocument = originFrame->document();
1174     WebCore::Document *targetDocument = targetFrame->document();
1175
1176     if (!targetDocument) {
1177         return false;
1178     }
1179
1180     WebCore::String targetDomain = targetDocument->domain();
1181
1182     // Always allow local pages to execute any JS.
1183     if (targetDomain.isNull())
1184         return true;
1185
1186     WebCore::String originDomain = originDocument->domain();
1187
1188     // if this document is being initially loaded as empty by its parent
1189     // or opener, allow access from any document in the same domain as
1190     // the parent or opener.
1191     if (shouldLoadAsEmptyDocument(targetFrame->loader()->url())) {
1192         Frame* ancestorFrame = targetFrame->loader()->opener() ? targetFrame->loader()->opener() : targetFrame->tree()->parent();
1193         while (ancestorFrame && shouldLoadAsEmptyDocument(ancestorFrame->loader()->url()))
1194             ancestorFrame = ancestorFrame->tree()->parent();
1195         if (ancestorFrame)
1196             originDomain = ancestorFrame->document()->domain();
1197     }
1198
1199     if ( targetDomain == originDomain )
1200         return true;
1201
1202     if (Interpreter::shouldPrintExceptions()) {
1203         printf("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
1204              targetDocument->URL().latin1(), originDocument->URL().latin1());
1205     }
1206     String message = String::format("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
1207                   targetDocument->URL().latin1(), originDocument->URL().latin1());
1208     if (Page* page = targetFrame->page())
1209         page->chrome()->addMessageToConsole(message, 1, String()); // FIXME: provide a real line number and source URL.
1210
1211     return false;
1212 }
1213
1214 bool Window::isSafeScript(ExecState *exec) const
1215 {
1216   if (!m_frame) // frame deleted ? can't grant access
1217     return false;
1218   Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame();
1219   if (!activeFrame)
1220     return false;
1221   if (activeFrame == m_frame) // Not calling from another frame, no problem.
1222     return true;
1223
1224   // JS may be attempting to access the "window" object, which should be valid,
1225   // even if the document hasn't been constructed yet.  If the document doesn't
1226   // exist yet allow JS to access the window object.
1227   if (!m_frame->document())
1228       return true;
1229
1230   WebCore::Document* thisDocument = m_frame->document();
1231   WebCore::Document* actDocument = activeFrame->document();
1232
1233   WebCore::String actDomain;
1234
1235   if (!actDocument)
1236     actDomain = activeFrame->loader()->url().host();
1237   else
1238     actDomain = actDocument->domain();
1239   
1240   // FIXME: this really should be explicitly checking for the "file:" protocol instead
1241   // Always allow local pages to execute any JS.
1242   if (actDomain.isEmpty())
1243     return true;
1244   
1245   WebCore::String thisDomain = thisDocument->domain();
1246
1247   // if this document is being initially loaded as empty by its parent
1248   // or opener, allow access from any document in the same domain as
1249   // the parent or opener.
1250   if (shouldLoadAsEmptyDocument(m_frame->loader()->url())) {
1251     Frame* ancestorFrame = m_frame->loader()->opener()
1252         ? m_frame->loader()->opener() : m_frame->tree()->parent();
1253     while (ancestorFrame && shouldLoadAsEmptyDocument(ancestorFrame->loader()->url()))
1254       ancestorFrame = ancestorFrame->tree()->parent();
1255     if (ancestorFrame)
1256       thisDomain = ancestorFrame->document()->domain();
1257   }
1258
1259   // FIXME: this should check that URL scheme and port match too, probably
1260   if (actDomain == thisDomain)
1261     return true;
1262
1263   if (Interpreter::shouldPrintExceptions()) {
1264       printf("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
1265              thisDocument->URL().latin1(), actDocument->URL().latin1());
1266   }
1267   String message = String::format("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
1268                   thisDocument->URL().latin1(), actDocument->URL().latin1());
1269   if (Page* page = m_frame->page())
1270       page->chrome()->addMessageToConsole(message, 1, String());
1271   
1272   return false;
1273 }
1274
1275 void Window::setListener(ExecState *exec, const AtomicString &eventType, JSValue *func)
1276 {
1277   if (!isSafeScript(exec))
1278     return;
1279   WebCore::Document *doc = m_frame->document();
1280   if (!doc)
1281     return;
1282
1283   doc->setHTMLWindowEventListener(eventType, getJSEventListener(func,true));
1284 }
1285
1286 JSValue *Window::getListener(ExecState *exec, const AtomicString &eventType) const
1287 {
1288   if (!isSafeScript(exec))
1289     return jsUndefined();
1290   WebCore::Document *doc = m_frame->document();
1291   if (!doc)
1292     return jsUndefined();
1293
1294   WebCore::EventListener *listener = doc->getHTMLWindowEventListener(eventType);
1295   if (listener && static_cast<JSEventListener*>(listener)->listenerObj())
1296     return static_cast<JSEventListener*>(listener)->listenerObj();
1297   else
1298     return jsNull();
1299 }
1300
1301 JSEventListener *Window::getJSEventListener(JSValue *val, bool html)
1302 {
1303   if (!val->isObject())
1304     return 0;
1305   JSObject *object = static_cast<JSObject *>(val);
1306
1307   ListenersMap& listeners = html ? jsHTMLEventListeners : jsEventListeners;
1308   if (JSEventListener* listener = listeners.get(object))
1309     return listener;
1310
1311   // Note that the JSEventListener constructor adds it to our jsEventListeners list
1312   return new JSEventListener(object, this, html);
1313 }
1314
1315 JSUnprotectedEventListener *Window::getJSUnprotectedEventListener(JSValue *val, bool html)
1316 {
1317   if (!val->isObject())
1318     return 0;
1319   JSObject* object = static_cast<JSObject *>(val);
1320
1321   UnprotectedListenersMap& listeners = html ? jsUnprotectedHTMLEventListeners : jsUnprotectedEventListeners;
1322   if (JSUnprotectedEventListener* listener = listeners.get(object))
1323     return listener;
1324
1325   // The JSUnprotectedEventListener constructor adds it to our jsUnprotectedEventListeners map.
1326   return new JSUnprotectedEventListener(object, this, html);
1327 }
1328
1329 void Window::clearHelperObjectProperties()
1330 {
1331   screen = 0;
1332   history = 0;
1333   frames = 0;
1334   loc = 0;
1335   m_selection = 0;
1336   m_locationbar = 0;
1337   m_menubar = 0;
1338   m_personalbar = 0;
1339   m_scrollbars = 0;
1340   m_statusbar = 0;
1341   m_toolbar = 0;
1342   m_evt = 0;
1343 }
1344
1345 void Window::clear()
1346 {
1347   JSLock lock;
1348
1349   if (m_returnValueSlot && !*m_returnValueSlot)
1350     *m_returnValueSlot = getDirect("returnValue");
1351
1352   clearAllTimeouts();
1353   clearProperties();
1354   clearHelperObjectProperties();
1355   setPrototype(JSDOMWindowPrototype::self()); // clear the prototype
1356
1357   // Now recreate a working global object for the next URL that will use us; but only if we haven't been
1358   // disconnected yet
1359   if (m_frame)
1360     interpreter()->initGlobalObject();
1361
1362   // there's likely to be lots of garbage now
1363   Collector::collect();
1364 }
1365
1366 void Window::setCurrentEvent(Event *evt)
1367 {
1368   m_evt = evt;
1369 }
1370
1371 static void setWindowFeature(const String& keyString, const String& valueString, WindowFeatures& windowFeatures)
1372 {
1373     int value;
1374     
1375     if (valueString.length() == 0 || // listing a key with no value is shorthand for key=yes
1376         valueString == "yes")
1377         value = 1;
1378     else
1379         value = valueString.toInt();
1380     
1381     if (keyString == "left" || keyString == "screenx") {
1382         windowFeatures.xSet = true;
1383         windowFeatures.x = value;
1384     } else if (keyString == "top" || keyString == "screeny") {
1385         windowFeatures.ySet = true;
1386         windowFeatures.y = value;
1387     } else if (keyString == "width" || keyString == "innerwidth") {
1388         windowFeatures.widthSet = true;
1389         windowFeatures.width = value;
1390     } else if (keyString == "height" || keyString == "innerheight") {
1391         windowFeatures.heightSet = true;
1392         windowFeatures.height = value;
1393     } else if (keyString == "menubar")
1394         windowFeatures.menuBarVisible = value;
1395     else if (keyString == "toolbar")
1396         windowFeatures.toolBarVisible = value;
1397     else if (keyString == "location")
1398         windowFeatures.locationBarVisible = value;
1399     else if (keyString == "status")
1400         windowFeatures.statusBarVisible = value;
1401     else if (keyString == "resizable")
1402         windowFeatures.resizable = value;
1403     else if (keyString == "fullscreen")
1404         windowFeatures.fullscreen = value;
1405     else if (keyString == "scrollbars")
1406         windowFeatures.scrollbarsVisible = value;
1407 }
1408
1409 // Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
1410 static bool isSeparator(::UChar c)
1411 {
1412     return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0';
1413 }
1414
1415 static void parseWindowFeatures(const String& features, WindowFeatures& windowFeatures)
1416 {
1417     /*
1418      The IE rule is: all features except for channelmode and fullscreen default to YES, but
1419      if the user specifies a feature string, all features default to NO. (There is no public
1420      standard that applies to this method.)
1421      
1422      <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
1423      */
1424     
1425     windowFeatures.dialog = false;
1426     windowFeatures.fullscreen = false;
1427     
1428     windowFeatures.xSet = false;
1429     windowFeatures.ySet = false;
1430     windowFeatures.widthSet = false;
1431     windowFeatures.heightSet = false;
1432     
1433     if (features.length() == 0) {
1434         windowFeatures.menuBarVisible = true;
1435         windowFeatures.statusBarVisible = true;
1436         windowFeatures.toolBarVisible = true;
1437         windowFeatures.locationBarVisible = true;
1438         windowFeatures.scrollbarsVisible = true;
1439         windowFeatures.resizable = true;
1440         
1441         return;
1442     }
1443     
1444     windowFeatures.menuBarVisible = false;
1445     windowFeatures.statusBarVisible = false;
1446     windowFeatures.toolBarVisible = false;
1447     windowFeatures.locationBarVisible = false;
1448     windowFeatures.scrollbarsVisible = false;
1449     windowFeatures.resizable = false;
1450     
1451     // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
1452     int keyBegin, keyEnd;
1453     int valueBegin, valueEnd;
1454     
1455     int i = 0;
1456     int length = features.length();
1457     String buffer = features.lower();
1458     while (i < length) {
1459         // skip to first non-separator, but don't skip past the end of the string
1460         while (isSeparator(buffer[i])) {
1461             if (i >= length)
1462                 break;
1463             i++;
1464         }
1465         keyBegin = i;
1466         
1467         // skip to first separator
1468         while (!isSeparator(buffer[i]))
1469             i++;
1470         keyEnd = i;
1471         
1472         // skip to first '=', but don't skip past a ',' or the end of the string
1473         while (buffer[i] != '=') {
1474             if (buffer[i] == ',' || i >= length)
1475                 break;
1476             i++;
1477         }
1478         
1479         // skip to first non-separator, but don't skip past a ',' or the end of the string
1480         while (isSeparator(buffer[i])) {
1481             if (buffer[i] == ',' || i >= length)
1482                 break;
1483             i++;
1484         }
1485         valueBegin = i;
1486         
1487         // skip to first separator
1488         while (!isSeparator(buffer[i]))
1489             i++;
1490         valueEnd = i;
1491         
1492         assert(i <= length);
1493
1494         String keyString(buffer.substring(keyBegin, keyEnd - keyBegin));
1495         String valueString(buffer.substring(valueBegin, valueEnd - valueBegin));
1496         setWindowFeature(keyString, valueString, windowFeatures);
1497     }
1498 }
1499
1500 static void constrainToVisible(const FloatRect& screen, WindowFeatures& windowFeatures)
1501 {
1502     windowFeatures.x += screen.x();
1503     if (windowFeatures.x < screen.x() || windowFeatures.x >= screen.right())
1504         windowFeatures.x = screen.x(); // only safe choice until size is determined
1505     
1506     windowFeatures.y += screen.y();
1507     if (windowFeatures.y < screen.y() || windowFeatures.y >= screen.bottom())
1508         windowFeatures.y = screen.y(); // only safe choice until size is determined
1509     
1510     if (windowFeatures.height > screen.height()) // should actually check workspace
1511         windowFeatures.height = screen.height();
1512     if (windowFeatures.height < 100)
1513         windowFeatures.height = 100;
1514     
1515     if (windowFeatures.width > screen.width()) // should actually check workspace
1516         windowFeatures.width = screen.width();
1517     if (windowFeatures.width < 100)
1518         windowFeatures.width = 100;
1519 }
1520
1521 JSValue *WindowFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
1522 {
1523   if (!thisObj->inherits(&Window::info))
1524     return throwError(exec, TypeError);
1525   Window *window = static_cast<Window *>(thisObj);
1526   Frame *frame = window->m_frame;
1527   if (!frame)
1528     return jsUndefined();
1529
1530   FrameView *widget = frame->view();
1531   Page* page = frame->page();
1532   JSValue *v = args[0];
1533   UString s = v->toString(exec);
1534   String str = s;
1535   String str2;
1536
1537   switch (id) {
1538   case Window::Alert:
1539     if (frame && frame->document())
1540       frame->document()->updateRendering();
1541     if (page)
1542         page->chrome()->runJavaScriptAlert(frame, str);
1543     return jsUndefined();
1544   case Window::AToB:
1545   case Window::BToA: {
1546     if (args.size() < 1)
1547         return throwError(exec, SyntaxError, "Not enough arguments");
1548     if (v->isNull())
1549         return jsString();
1550     if (!s.is8Bit()) {
1551         setDOMException(exec, INVALID_CHARACTER_ERR);
1552         return jsUndefined();
1553     }
1554     
1555     Vector<char> in(s.size());
1556     for (int i = 0; i < s.size(); ++i)
1557         in[i] = static_cast<char>(s.data()[i].unicode());
1558     Vector<char> out;
1559
1560     if (id == Window::AToB) {
1561         if (!base64Decode(in, out))
1562             return throwError(exec, GeneralError, "Cannot decode base64");
1563     } else
1564         base64Encode(in, out);
1565     
1566     return jsString(String(out.data(), out.size()));
1567   }
1568   case Window::Confirm: {
1569     if (frame && frame->document())
1570       frame->document()->updateRendering();
1571     bool result = false;
1572     if (page)
1573         result = page->chrome()->runJavaScriptConfirm(frame, str);
1574     return jsBoolean(result);
1575   }
1576   case Window::Prompt:
1577   {
1578     if (frame && frame->document())
1579       frame->document()->updateRendering();
1580     String message = args.size() >= 2 ? args[1]->toString(exec) : UString();
1581     if (page && page->chrome()->runJavaScriptPrompt(frame, str, message, str2))
1582         return jsString(str2);
1583
1584     return jsNull();
1585   }
1586   case Window::Open:
1587   {
1588       AtomicString frameName = args[1]->isUndefinedOrNull()
1589         ? "_blank" : AtomicString(args[1]->toString(exec));
1590       // Because FrameTree::find() returns true for empty strings, we must check for empty framenames.
1591       // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
1592       if (!allowPopUp(exec, window) && (frameName.isEmpty() || !frame->tree()->find(frameName)))
1593           return jsUndefined();
1594       
1595       WindowFeatures windowFeatures;
1596       String features = args[2]->isUndefinedOrNull() ? UString() : args[2]->toString(exec);
1597       parseWindowFeatures(features, windowFeatures);
1598       constrainToVisible(screenRect(page->mainFrame()->view()), windowFeatures);
1599       
1600       // prepare arguments
1601       KURL url;
1602       Frame* activeFrame = Window::retrieveActive(exec)->m_frame;
1603       if (!str.isEmpty() && activeFrame)
1604           url = activeFrame->document()->completeURL(str.deprecatedString());
1605
1606       ResourceRequest resRequest(url);
1607       FrameLoadRequest frameRequest(resRequest, frameName);
1608       if (frameRequest.frameName() == "_top") {
1609           while (frame->tree()->parent())
1610               frame = frame->tree()->parent();
1611           
1612           const Window* window = Window::retrieveWindow(frame);
1613           if (!url.url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
1614               bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1615               frame->loader()->scheduleLocationChange(url.url(), activeFrame->loader()->outgoingReferrer(), false/*don't lock history*/, userGesture);
1616           }
1617           return Window::retrieve(frame);
1618       }
1619       if (frameRequest.frameName() == "_parent") {
1620           if (frame->tree()->parent())
1621               frame = frame->tree()->parent();
1622           
1623           const Window* window = Window::retrieveWindow(frame);
1624           if (!url.url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
1625               bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1626               frame->loader()->scheduleLocationChange(url.url(), activeFrame->loader()->outgoingReferrer(), false/*don't lock history*/, userGesture);
1627           }
1628           return Window::retrieve(frame);
1629       }
1630       
1631       // request window (new or existing if framename is set)
1632       frameRequest.resourceRequest().setHTTPReferrer(activeFrame->loader()->outgoingReferrer());
1633       Frame* newFrame = frame->loader()->createWindow(frameRequest, windowFeatures);
1634       if (!newFrame)
1635           return jsUndefined();
1636       newFrame->loader()->setOpener(frame);
1637       newFrame->loader()->setOpenedByJavaScript();
1638       
1639       if (!newFrame->document()) {
1640           Document* oldDoc = frame->document();
1641           if (oldDoc && oldDoc->baseURL() != 0)
1642               newFrame->loader()->begin(oldDoc->baseURL());
1643           else
1644               newFrame->loader()->begin();
1645           newFrame->loader()->write("<HTML><BODY>");
1646           newFrame->loader()->end();          
1647           if (oldDoc) {
1648               newFrame->document()->setDomain(oldDoc->domain(), true);
1649               newFrame->document()->setBaseURL(oldDoc->baseURL());
1650           }
1651       }
1652       if (!url.isEmpty()) {
1653           const Window* window = Window::retrieveWindow(newFrame);
1654           if (!url.url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
1655               bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1656               newFrame->loader()->scheduleLocationChange(url.url(), activeFrame->loader()->outgoingReferrer(), false, userGesture);
1657           }
1658       }
1659       return Window::retrieve(newFrame); // global object
1660   }
1661   case Window::Print:
1662     frame->print();
1663     return jsUndefined();
1664   case Window::ScrollBy:
1665     window->updateLayout();
1666     if(args.size() >= 2 && widget)
1667       widget->scrollBy(args[0]->toInt32(exec), args[1]->toInt32(exec));
1668     return jsUndefined();
1669   case Window::Scroll:
1670   case Window::ScrollTo:
1671     window->updateLayout();
1672     if (args.size() >= 2 && widget)
1673       widget->setContentsPos(args[0]->toInt32(exec), args[1]->toInt32(exec));
1674     return jsUndefined();
1675   case Window::MoveBy:
1676     if (args.size() >= 2 && page) {
1677       FloatRect r = page->chrome()->windowRect();
1678       r.move(args[0]->toNumber(exec), args[1]->toNumber(exec));
1679       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1680       if (screenRect(page->mainFrame()->view()).contains(r))
1681         page->chrome()->setWindowRect(r);
1682     }
1683     return jsUndefined();
1684   case Window::MoveTo:
1685     if (args.size() >= 2 && page) {
1686       FloatRect r = page->chrome()->windowRect();
1687       FloatRect sr = screenRect(page->mainFrame()->view());
1688       r.setLocation(sr.location());
1689       r.move(args[0]->toNumber(exec), args[1]->toNumber(exec));
1690       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1691       if (sr.contains(r))
1692         page->chrome()->setWindowRect(r);
1693     }
1694     return jsUndefined();
1695   case Window::ResizeBy:
1696     if (args.size() >= 2 && page) {
1697       FloatRect r = page->chrome()->windowRect();
1698       FloatSize dest = r.size() + FloatSize(args[0]->toNumber(exec), args[1]->toNumber(exec));
1699       FloatRect sg = screenRect(page->mainFrame()->view());
1700       // Security check: within desktop limits and bigger than 100x100 (per spec)
1701       if (r.x() + dest.width() <= sg.right() && r.y() + dest.height() <= sg.bottom()
1702            && dest.width() >= 100 && dest.height() >= 100)
1703         page->chrome()->setWindowRect(FloatRect(r.location(), dest));
1704     }
1705     return jsUndefined();
1706   case Window::ResizeTo:
1707     if (args.size() >= 2 && page) {
1708       FloatRect r = page->chrome()->windowRect();
1709       FloatSize dest = FloatSize(args[0]->toNumber(exec), args[1]->toNumber(exec));
1710       FloatRect sg = screenRect(page->mainFrame()->view());
1711       // Security check: within desktop limits and bigger than 100x100 (per spec)
1712       if (r.x() + dest.width() <= sg.right() && r.y() + dest.height() <= sg.bottom() &&
1713            dest.width() >= 100 && dest.height() >= 100)
1714         page->chrome()->setWindowRect(FloatRect(r.location(), dest));
1715     }
1716     return jsUndefined();
1717   case Window::SetTimeout:
1718     if (!window->isSafeScript(exec))
1719         return jsUndefined();
1720     if (args.size() >= 2 && v->isString()) {
1721       int i = args[1]->toInt32(exec);
1722       int r = (const_cast<Window*>(window))->installTimeout(s, i, true /*single shot*/);
1723       return jsNumber(r);
1724     }
1725     else if (args.size() >= 2 && v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1726       JSValue *func = args[0];
1727       int i = args[1]->toInt32(exec);
1728
1729       // All arguments after the second should go to the function
1730       // FIXME: could be more efficient
1731       List funcArgs = args.copyTail().copyTail();
1732
1733       int r = (const_cast<Window*>(window))->installTimeout(func, funcArgs, i, true /*single shot*/);
1734       return jsNumber(r);
1735     }
1736     else
1737       return jsUndefined();
1738   case Window::SetInterval:
1739     if (!window->isSafeScript(exec))
1740         return jsUndefined();
1741     if (args.size() >= 2 && v->isString()) {
1742       int i = args[1]->toInt32(exec);
1743       int r = (const_cast<Window*>(window))->installTimeout(s, i, false);
1744       return jsNumber(r);
1745     }
1746     else if (args.size() >= 2 && v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1747       JSValue *func = args[0];
1748       int i = args[1]->toInt32(exec);
1749
1750       // All arguments after the second should go to the function
1751       // FIXME: could be more efficient
1752       List funcArgs = args.copyTail().copyTail();
1753
1754       int r = (const_cast<Window*>(window))->installTimeout(func, funcArgs, i, false);
1755       return jsNumber(r);
1756     }
1757     else
1758       return jsUndefined();
1759   case Window::ClearTimeout:
1760   case Window::ClearInterval:
1761     if (!window->isSafeScript(exec))
1762         return jsUndefined();
1763     (const_cast<Window*>(window))->clearTimeout(v->toInt32(exec));
1764     return jsUndefined();
1765   case Window::Focus:
1766     frame->focusWindow();
1767     return jsUndefined();
1768   case Window::GetSelection:
1769     if (!window->isSafeScript(exec))
1770         return jsUndefined();
1771     return window->selection();
1772   case Window::Blur:
1773     frame->unfocusWindow();
1774     return jsUndefined();
1775   case Window::Close:
1776     // Do not close windows that have history unless they were opened by JavaScript.
1777     if (frame->loader()->openedByJavaScript() || frame->loader()->getHistoryLength() <= 1)
1778       const_cast<Window*>(window)->scheduleClose();
1779     return jsUndefined();
1780   case Window::CaptureEvents:
1781   case Window::ReleaseEvents:
1782     // If anyone implements these, they need the safe script security check.
1783     if (!window->isSafeScript(exec))
1784         return jsUndefined();
1785     // Not implemented.
1786     return jsUndefined();
1787   case Window::AddEventListener:
1788         if (!window->isSafeScript(exec))
1789             return jsUndefined();
1790         if (JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]))
1791             if (Document *doc = frame->document())
1792                 doc->addWindowEventListener(AtomicString(args[0]->toString(exec)), listener, args[2]->toBoolean(exec));
1793         return jsUndefined();
1794   case Window::RemoveEventListener:
1795         if (!window->isSafeScript(exec))
1796             return jsUndefined();
1797         if (JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]))
1798             if (Document *doc = frame->document())
1799                 doc->removeWindowEventListener(AtomicString(args[0]->toString(exec)), listener, args[2]->toBoolean(exec));
1800         return jsUndefined();
1801   case Window::ShowModalDialog: {
1802     JSValue* result = showModalDialog(exec, window, args);
1803     return result;
1804   }
1805   }
1806   return jsUndefined();
1807 }
1808
1809 void Window::updateLayout() const
1810 {
1811   WebCore::Document* docimpl = m_frame->document();
1812   if (docimpl)
1813     docimpl->updateLayoutIgnorePendingStylesheets();
1814 }
1815
1816 ////////////////////// ScheduledAction ////////////////////////
1817
1818 void ScheduledAction::execute(Window* window)
1819 {
1820     RefPtr<Frame> frame = window->m_frame;
1821     if (!frame)
1822         return;
1823
1824     KJSProxy* scriptProxy = frame->scriptProxy();
1825     if (!scriptProxy)
1826         return;
1827
1828     RefPtr<ScriptInterpreter> interpreter = scriptProxy->interpreter();
1829
1830     interpreter->setProcessingTimerCallback(true);
1831
1832     if (JSValue* func = m_func.get()) {
1833         if (func->isObject() && static_cast<JSObject*>(func)->implementsCall()) {
1834             ExecState* exec = interpreter->globalExec();
1835             ASSERT(window == interpreter->globalObject());
1836             JSLock lock;
1837             interpreter->startTimeoutCheck();
1838             static_cast<JSObject*>(func)->call(exec, window, m_args);
1839             interpreter->stopTimeoutCheck();
1840             if (exec->hadException()) {
1841                 JSObject* exception = exec->exception()->toObject(exec);
1842                 exec->clearException();
1843                 String message = exception->get(exec, messagePropertyName)->toString(exec);
1844                 int lineNumber = exception->get(exec, "line")->toInt32(exec);
1845                 if (Interpreter::shouldPrintExceptions())
1846                     printf("(timer):%s\n", message.utf8().data());
1847                 if (Page* page = frame->page())
1848                     page->chrome()->addMessageToConsole(message, lineNumber, String());
1849             }
1850         }
1851     } else
1852         frame->loader()->executeScript(0, m_code);
1853
1854     // Update our document's rendering following the execution of the timeout callback.
1855     // FIXME: Why not use updateDocumentsRendering to update rendering of all documents?
1856     // FIXME: Is this really the right point to do the update? We need a place that works
1857     // for all possible entry points that might possibly execute script, but this seems
1858     // to be a bit too low-level.
1859     if (Document* doc = frame->document())
1860         doc->updateRendering();
1861   
1862     interpreter->setProcessingTimerCallback(false);
1863 }
1864
1865 ////////////////////// timeouts ////////////////////////
1866
1867 void Window::clearAllTimeouts()
1868 {
1869     deleteAllValues(m_timeouts);
1870     m_timeouts.clear();
1871 }
1872
1873 int Window::installTimeout(ScheduledAction* a, int t, bool singleShot)
1874 {
1875     int timeoutId = ++lastUsedTimeoutId;
1876     int nestLevel = timerNestingLevel + 1;
1877     DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, nestLevel, this, a);
1878     ASSERT(!m_timeouts.get(timeoutId));
1879     m_timeouts.set(timeoutId, timer);
1880     // Use a minimum interval of 10 ms to match other browsers, but only once we've
1881     // nested enough to notice that we're repeating.
1882     // Faster timers might be "better", but they're incompatible.
1883     double interval = max(0.001, t * 0.001);
1884     if (interval < cMinimumTimerInterval && nestLevel >= cMaxTimerNestingLevel)
1885         interval = cMinimumTimerInterval;
1886     if (singleShot)
1887         timer->startOneShot(interval);
1888     else
1889         timer->startRepeating(interval);
1890     return timeoutId;
1891 }
1892
1893 int Window::installTimeout(const UString& handler, int t, bool singleShot)
1894 {
1895     return installTimeout(new ScheduledAction(handler), t, singleShot);
1896 }
1897
1898 int Window::installTimeout(JSValue* func, const List& args, int t, bool singleShot)
1899 {
1900     return installTimeout(new ScheduledAction(func, args), t, singleShot);
1901 }
1902
1903 PausedTimeouts* Window::pauseTimeouts()
1904 {
1905     size_t count = m_timeouts.size();
1906     if (count == 0)
1907         return 0;
1908
1909     PausedTimeout* t = new PausedTimeout [count];
1910     PausedTimeouts* result = new PausedTimeouts(t, count);
1911
1912     TimeoutsMap::iterator it = m_timeouts.begin();
1913     for (size_t i = 0; i != count; ++i, ++it) {
1914         int timeoutId = it->first;
1915         DOMWindowTimer* timer = it->second;
1916         t[i].timeoutId = timeoutId;
1917         t[i].nestingLevel = timer->nestingLevel();
1918         t[i].nextFireInterval = timer->nextFireInterval();
1919         t[i].repeatInterval = timer->repeatInterval();
1920         t[i].action = timer->takeAction();
1921     }
1922     ASSERT(it == m_timeouts.end());
1923
1924     deleteAllValues(m_timeouts);
1925     m_timeouts.clear();
1926
1927     return result;
1928 }
1929
1930 void Window::resumeTimeouts(PausedTimeouts* timeouts)
1931 {
1932     if (!timeouts)
1933         return;
1934     size_t count = timeouts->numTimeouts();
1935     PausedTimeout* array = timeouts->takeTimeouts();
1936     for (size_t i = 0; i != count; ++i) {
1937         int timeoutId = array[i].timeoutId;
1938         DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, array[i].nestingLevel, this, array[i].action);
1939         m_timeouts.set(timeoutId, timer);
1940         timer->start(array[i].nextFireInterval, array[i].repeatInterval);
1941     }
1942     delete [] array;
1943 }
1944
1945 void Window::clearTimeout(int timeoutId, bool delAction)
1946 {
1947     TimeoutsMap::iterator it = m_timeouts.find(timeoutId);
1948     if (it == m_timeouts.end())
1949         return;
1950     DOMWindowTimer* timer = it->second;
1951     m_timeouts.remove(it);
1952     delete timer;
1953 }
1954
1955 void Window::timerFired(DOMWindowTimer* timer)
1956 {
1957     // Simple case for non-one-shot timers.
1958     if (timer->isActive()) {
1959         int timeoutId = timer->timeoutId();
1960
1961         timer->action()->execute(this);
1962         if (m_timeouts.contains(timeoutId) && timer->repeatInterval() && timer->repeatInterval() < cMinimumTimerInterval) {
1963             timer->setNestingLevel(timer->nestingLevel() + 1);
1964             if (timer->nestingLevel() >= cMaxTimerNestingLevel)
1965                 timer->augmentRepeatInterval(cMinimumTimerInterval - timer->repeatInterval());
1966         }
1967         return;
1968     }
1969
1970     // Delete timer before executing the action for one-shot timers.
1971     ScheduledAction* action = timer->takeAction();
1972     m_timeouts.remove(timer->timeoutId());
1973     delete timer;
1974     action->execute(this);
1975     delete action;
1976 }
1977
1978 void Window::disconnectFrame()
1979 {
1980     clearAllTimeouts();
1981     m_frame = 0;
1982     if (loc)
1983         loc->m_frame = 0;
1984     if (m_selection)
1985         m_selection->m_frame = 0;
1986     if (m_locationbar)
1987         m_locationbar->m_frame = 0;
1988     if (m_menubar)
1989         m_menubar->m_frame = 0;
1990     if (m_personalbar)
1991         m_personalbar->m_frame = 0;
1992     if (m_statusbar)
1993         m_statusbar->m_frame = 0;
1994     if (m_toolbar)
1995         m_toolbar->m_frame = 0;
1996     if (m_scrollbars)
1997         m_scrollbars->m_frame = 0;
1998     if (frames)
1999         frames->disconnectFrame();
2000     if (history)
2001         history->disconnectFrame();
2002 }
2003
2004 const ClassInfo FrameArray::info = { "FrameArray", 0, &FrameArrayTable, 0 };
2005
2006 /*
2007 @begin FrameArrayTable 2
2008 length          FrameArray::Length      DontDelete|ReadOnly
2009 location        FrameArray::Location    DontDelete|ReadOnly
2010 @end
2011 */
2012
2013 JSValue *FrameArray::getValueProperty(ExecState *exec, int token)
2014 {
2015   switch (token) {
2016   case Length:
2017     return jsNumber(m_frame->tree()->childCount());
2018   case Location:
2019     // non-standard property, but works in NS and IE
2020     if (JSObject *obj = Window::retrieveWindow(m_frame))
2021       return obj->get(exec, "location");
2022     return jsUndefined();
2023   default:
2024     ASSERT(0);
2025     return jsUndefined();
2026   }
2027 }
2028
2029 JSValue* FrameArray::indexGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
2030 {
2031     return Window::retrieve(static_cast<FrameArray*>(slot.slotBase())->m_frame->tree()->child(slot.index()));
2032 }
2033   
2034 JSValue* FrameArray::nameGetter(ExecState*, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
2035 {
2036     return Window::retrieve(static_cast<FrameArray*>(slot.slotBase())->m_frame->tree()->child(AtomicString(propertyName)));
2037 }
2038
2039 bool FrameArray::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
2040 {
2041   if (!m_frame) {
2042     slot.setUndefined(this);
2043     return true;
2044   }
2045
2046   const HashEntry* entry = Lookup::findEntry(&FrameArrayTable, propertyName);
2047   if (entry) {
2048     slot.setStaticEntry(this, entry, staticValueGetter<FrameArray>);
2049     return true;
2050   }
2051
2052   // check for the name or number
2053   if (m_frame->tree()->child(propertyName)) {
2054     slot.setCustom(this, nameGetter);
2055     return true;
2056   }
2057
2058   bool ok;
2059   unsigned i = propertyName.toArrayIndex(&ok);
2060   if (ok && i < m_frame->tree()->childCount()) {
2061     slot.setCustomIndex(this, i, indexGetter);
2062     return true;
2063   }
2064
2065   return JSObject::getOwnPropertySlot(exec, propertyName, slot);
2066 }
2067
2068 UString FrameArray::toString(ExecState *) const
2069 {
2070   return "[object FrameArray]";
2071 }
2072
2073 ////////////////////// Location Object ////////////////////////
2074
2075 const ClassInfo Location::info = { "Location", 0, &LocationTable, 0 };
2076 /*
2077 @begin LocationTable 12
2078   assign        Location::Assign        DontDelete|Function 1
2079   hash          Location::Hash          DontDelete
2080   host          Location::Host          DontDelete
2081   hostname      Location::Hostname      DontDelete
2082   href          Location::Href          DontDelete
2083   pathname      Location::Pathname      DontDelete
2084   port          Location::Port          DontDelete
2085   protocol      Location::Protocol      DontDelete
2086   search        Location::Search        DontDelete
2087   toString      Location::ToString      DontDelete|Function 0
2088   replace       Location::Replace       DontDelete|Function 1
2089   reload        Location::Reload        DontDelete|Function 0
2090 @end
2091 */
2092 KJS_IMPLEMENT_PROTOTYPE_FUNCTION(LocationFunc)
2093 Location::Location(Frame *p) : m_frame(p)
2094 {
2095 }
2096
2097 JSValue *Location::getValueProperty(ExecState *exec, int token) const
2098 {
2099   KURL url = m_frame->loader()->url();
2100   switch (token) {
2101   case Hash:
2102     return jsString(url.ref().isNull() ? "" : "#" + url.ref());
2103   case Host: {
2104     // Note: this is the IE spec. The NS spec swaps the two, it says
2105     // "The hostname property is the concatenation of the host and port properties, separated by a colon."
2106     // Bleh.
2107     UString str = url.host();
2108     if (url.port())
2109         str += ":" + String::number((int)url.port());
2110     return jsString(str);
2111   }
2112   case Hostname:
2113     return jsString(url.host());
2114   case Href:
2115     if (!url.hasPath())
2116       return jsString(url.prettyURL() + "/");
2117     return jsString(url.prettyURL());
2118   case Pathname:
2119     return jsString(url.path().isEmpty() ? "/" : url.path());
2120   case Port:
2121     return jsString(url.port() ? String::number((int)url.port()) : "");
2122   case Protocol:
2123     return jsString(url.protocol() + ":");
2124   case Search:
2125     return jsString(url.query());
2126   default:
2127     ASSERT(0);
2128     return jsUndefined();
2129   }
2130 }
2131
2132 bool Location::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) 
2133 {
2134   if (!m_frame)
2135     return false;
2136   
2137   const Window* window = Window::retrieveWindow(m_frame);
2138   
2139   const HashEntry *entry = Lookup::findEntry(&LocationTable, propertyName);
2140   if (!entry || (entry->value != Replace && entry->value != Reload && entry->value != Assign))
2141     if (!window || !window->isSafeScript(exec)) {
2142       slot.setUndefined(this);
2143       return true;
2144     }
2145
2146   return getStaticPropertySlot<LocationFunc, Location, JSObject>(exec, &LocationTable, this, propertyName, slot);
2147 }
2148
2149 void Location::put(ExecState *exec, const Identifier &p, JSValue *v, int attr)
2150 {
2151   if (!m_frame)
2152     return;
2153
2154   DeprecatedString str = v->toString(exec);
2155   KURL url = m_frame->loader()->url();
2156   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
2157   if (entry)
2158     switch (entry->value) {
2159     case Href: {
2160       Frame* p = Window::retrieveActive(exec)->frame();
2161       if ( p )
2162         url = p->document()->completeURL( str );
2163       else
2164         url = str;
2165       break;
2166     }
2167     case Hash: {
2168       if (str.startsWith("#"))
2169         str = str.mid(1);
2170
2171       if (url.ref() == str)
2172           return;
2173
2174       url.setRef(str);
2175       break;
2176     }
2177     case Host: {
2178       DeprecatedString host = str.left(str.find(":"));
2179       DeprecatedString port = str.mid(str.find(":")+1);
2180       url.setHost(host);
2181       url.setPort(port.toUInt());
2182       break;
2183     }
2184     case Hostname:
2185       url.setHost(str);
2186       break;
2187     case Pathname:
2188       url.setPath(str);
2189       break;
2190     case Port:
2191       url.setPort(str.toUInt());
2192       break;
2193     case Protocol:
2194       url.setProtocol(str);
2195       break;
2196     case Search:
2197       url.setQuery(str);
2198       break;
2199     }
2200   else {
2201     JSObject::put(exec, p, v, attr);
2202     return;
2203   }
2204
2205   const Window* window = Window::retrieveWindow(m_frame);
2206   Frame* activeFrame = Window::retrieveActive(exec)->frame();
2207   if (!url.url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2208     bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2209     // We want a new history item if this JS was called via a user gesture
2210     m_frame->loader()->scheduleLocationChange(url.url(), activeFrame->loader()->outgoingReferrer(), !userGesture, userGesture);
2211   }
2212 }
2213
2214 JSValue *Location::toPrimitive(ExecState *exec, JSType) const
2215 {
2216   return jsString(toString(exec));
2217 }
2218
2219 UString Location::toString(ExecState* exec) const
2220 {
2221   if (!m_frame || !Window::retrieveWindow(m_frame)->isSafeScript(exec))
2222     return UString();
2223
2224   if (!m_frame->loader()->url().hasPath())
2225     return m_frame->loader()->url().prettyURL()+"/";
2226   return m_frame->loader()->url().prettyURL();
2227 }
2228
2229 JSValue *LocationFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2230 {
2231   if (!thisObj->inherits(&Location::info))
2232     return throwError(exec, TypeError);
2233   Location *location = static_cast<Location *>(thisObj);
2234   Frame *frame = location->frame();
2235   if (frame) {
2236       
2237     Window* window = Window::retrieveWindow(frame);
2238     if (id != Location::Replace && !window->isSafeScript(exec))
2239         return jsUndefined();
2240       
2241     switch (id) {
2242     case Location::Replace:
2243     {
2244       DeprecatedString str = args[0]->toString(exec);
2245       Frame* p = Window::retrieveActive(exec)->frame();
2246       if ( p ) {
2247         const Window* window = Window::retrieveWindow(frame);
2248         if (!str.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2249           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2250           frame->loader()->scheduleLocationChange(p->document()->completeURL(str), p->loader()->outgoingReferrer(), true /*lock history*/, userGesture);
2251         }
2252       }
2253       break;
2254     }
2255     case Location::Reload:
2256     {
2257       const Window* window = Window::retrieveWindow(frame);
2258       if (!frame->loader()->url().url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2259         bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2260         frame->loader()->scheduleRefresh(userGesture);
2261       }
2262       break;
2263     }
2264     case Location::Assign:
2265     {
2266         Frame *p = Window::retrieveActive(exec)->frame();
2267         if (p) {
2268             const Window *window = Window::retrieveWindow(frame);
2269             DeprecatedString dstUrl = p->document()->completeURL(DeprecatedString(args[0]->toString(exec)));
2270             if (!dstUrl.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2271                 bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2272                 // We want a new history item if this JS was called via a user gesture
2273                 frame->loader()->scheduleLocationChange(dstUrl, p->loader()->outgoingReferrer(), !userGesture, userGesture);
2274             }
2275         }
2276         break;
2277     }
2278     case Location::ToString:
2279       return jsString(location->toString(exec));
2280     }
2281   }
2282   return jsUndefined();
2283 }
2284
2285 ////////////////////// Selection Object ////////////////////////
2286
2287 const ClassInfo Selection::info = { "Selection", 0, &SelectionTable, 0 };
2288 /*
2289 @begin SelectionTable 19
2290   anchorNode                Selection::AnchorNode               DontDelete|ReadOnly
2291   anchorOffset              Selection::AnchorOffset             DontDelete|ReadOnly
2292   focusNode                 Selection::FocusNode                DontDelete|ReadOnly
2293   focusOffset               Selection::FocusOffset              DontDelete|ReadOnly
2294   baseNode                  Selection::BaseNode                 DontDelete|ReadOnly
2295   baseOffset                Selection::BaseOffset               DontDelete|ReadOnly
2296   extentNode                Selection::ExtentNode               DontDelete|ReadOnly
2297   extentOffset              Selection::ExtentOffset             DontDelete|ReadOnly
2298   isCollapsed               Selection::IsCollapsed              DontDelete|ReadOnly
2299   type                      Selection::_Type                    DontDelete|ReadOnly
2300   rangeCount                Selection::RangeCount               DontDelete|ReadOnly
2301   toString                  Selection::ToString                 DontDelete|Function 0
2302   collapse                  Selection::Collapse                 DontDelete|Function 2
2303   collapseToEnd             Selection::CollapseToEnd            DontDelete|Function 0
2304   collapseToStart           Selection::CollapseToStart          DontDelete|Function 0
2305   empty                     Selection::Empty                    DontDelete|Function 0
2306   setBaseAndExtent          Selection::SetBaseAndExtent         DontDelete|Function 4
2307   setPosition               Selection::SetPosition              DontDelete|Function 2
2308   modify                    Selection::Modify                   DontDelete|Function 3
2309   getRangeAt                Selection::GetRangeAt               DontDelete|Function 1
2310   removeAllRanges           Selection::RemoveAllRanges          DontDelete|Function 0
2311   addRange                  Selection::AddRange                 DontDelete|Function 1
2312 @end
2313 */
2314 KJS_IMPLEMENT_PROTOTYPE_FUNCTION(SelectionFunc)
2315 Selection::Selection(Frame *p) : m_frame(p)
2316 {
2317 }
2318
2319 JSValue *Selection::getValueProperty(ExecState *exec, int token) const
2320 {
2321     SelectionController* s = m_frame->selectionController();
2322     const Window* window = Window::retrieveWindow(m_frame);
2323     if (!window)
2324         return jsUndefined();
2325         
2326     switch (token) {
2327     case AnchorNode:
2328         return toJS(exec, s->anchorNode());
2329     case BaseNode:
2330         return toJS(exec, s->baseNode());
2331     case AnchorOffset:
2332         return jsNumber(s->anchorOffset());
2333     case BaseOffset:
2334         return jsNumber(s->baseOffset());
2335     case FocusNode:
2336         return toJS(exec, s->focusNode());
2337     case ExtentNode:
2338         return toJS(exec, s->extentNode());
2339     case FocusOffset:
2340         return jsNumber(s->focusOffset());
2341     case ExtentOffset:
2342         return jsNumber(s->extentOffset());
2343     case IsCollapsed:
2344         return jsBoolean(s->isCollapsed());
2345     case _Type:
2346         return jsString(s->type());
2347     case RangeCount:
2348         return jsNumber(s->rangeCount());
2349     default:
2350         ASSERT(0);
2351         return jsUndefined();
2352     }
2353 }
2354
2355 bool Selection::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
2356 {
2357   if (!m_frame)
2358       return false;
2359
2360   return getStaticPropertySlot<SelectionFunc, Selection, JSObject>(exec, &SelectionTable, this, propertyName, slot);
2361 }
2362
2363 JSValue *Selection::toPrimitive(ExecState *exec, JSType) const
2364 {
2365   return jsString(toString(exec));
2366 }
2367
2368 UString Selection::toString(ExecState *) const
2369 {
2370     return UString(m_frame->selectionController()->toString());
2371 }
2372
2373 JSValue *SelectionFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2374 {
2375     if (!thisObj->inherits(&Selection::info))
2376         return throwError(exec, TypeError);
2377     Selection *selection = static_cast<Selection *>(thisObj);
2378     Frame *frame = selection->frame();
2379     if (frame) {
2380         SelectionController* s = frame->selectionController();
2381         
2382         switch (id) {
2383             case Selection::Collapse:
2384                 s->collapse(toNode(args[0]), args[1]->toInt32(exec));
2385                 break;
2386             case Selection::CollapseToEnd:
2387                 s->collapseToEnd();
2388                 break;
2389             case Selection::CollapseToStart:
2390                 s->collapseToStart();
2391                 break;
2392             case Selection::Empty:
2393                 s->empty();
2394                 break;
2395             case Selection::SetBaseAndExtent:
2396                 s->setBaseAndExtent(toNode(args[0]), args[1]->toInt32(exec), toNode(args[2]), args[3]->toInt32(exec));
2397                 break;
2398             case Selection::SetPosition:
2399                 s->setPosition(toNode(args[0]), args[1]->toInt32(exec));
2400                 break;
2401             case Selection::Modify:
2402                 s->modify(args[0]->toString(exec), args[1]->toString(exec), args[2]->toString(exec));
2403                 break;
2404             case Selection::GetRangeAt:
2405                 return toJS(exec, s->getRangeAt(args[0]->toInt32(exec)).get());
2406             case Selection::RemoveAllRanges:
2407                 s->removeAllRanges();
2408                 break;
2409             case Selection::AddRange:
2410                 s->addRange(toRange(args[0]));
2411                 break;
2412             case Selection::ToString:
2413                 return jsString(s->toString());
2414         }
2415     }
2416
2417     return jsUndefined();
2418 }
2419
2420 ////////////////////// BarInfo Object ////////////////////////
2421
2422 const ClassInfo BarInfo::info = { "BarInfo", 0, &BarInfoTable, 0 };
2423 /*
2424 @begin BarInfoTable 1
2425   visible                BarInfo::Visible                        DontDelete|ReadOnly
2426 @end
2427 */
2428 BarInfo::BarInfo(ExecState *exec, Frame *f, Type barType) 
2429   : m_frame(f)
2430   , m_type(barType)
2431 {
2432   setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype());
2433 }
2434
2435 JSValue *BarInfo::getValueProperty(ExecState *exec, int token) const
2436 {
2437     ASSERT(token == Visible);
2438     switch (m_type) {
2439     case Locationbar:
2440         return jsBoolean(m_frame->page()->chrome()->toolbarsVisible());
2441     case Toolbar:
2442         return jsBoolean(m_frame->page()->chrome()->toolbarsVisible());
2443     case Personalbar:
2444         return jsBoolean(m_frame->page()->chrome()->toolbarsVisible());
2445     case Menubar: 
2446         return jsBoolean(m_frame->page()->chrome()->menubarVisible());
2447     case Scrollbars: 
2448         return jsBoolean(m_frame->page()->chrome()->scrollbarsVisible());
2449     case Statusbar:
2450         return jsBoolean(m_frame->page()->chrome()->statusbarVisible());
2451     default:
2452         return jsBoolean(false);
2453     }
2454 }
2455
2456 bool BarInfo::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
2457 {
2458   if (!m_frame)
2459     return false;
2460   
2461   return getStaticValueSlot<BarInfo, JSObject>(exec, &BarInfoTable, this, propertyName, slot);
2462 }
2463
2464 ////////////////////// History Object ////////////////////////
2465
2466 const ClassInfo History::info = { "History", 0, &HistoryTable, 0 };
2467 /*
2468 @begin HistoryTable 4
2469   length        History::Length         DontDelete|ReadOnly
2470   back          History::Back           DontDelete|Function 0
2471   forward       History::Forward        DontDelete|Function 0
2472   go            History::Go             DontDelete|Function 1
2473 @end
2474 */
2475 KJS_IMPLEMENT_PROTOTYPE_FUNCTION(HistoryFunc)
2476
2477 bool History::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
2478 {
2479   return getStaticPropertySlot<HistoryFunc, History, JSObject>(exec, &HistoryTable, this, propertyName, slot);
2480 }
2481
2482 JSValue *History::getValueProperty(ExecState *, int token) const
2483 {
2484     ASSERT(token == Length);
2485     return m_frame ? jsNumber(m_frame->loader()->getHistoryLength()) : jsNumber(0);
2486 }
2487
2488 UString History::toString(ExecState *exec) const
2489 {
2490   return "[object History]";
2491 }
2492
2493 JSValue *HistoryFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2494 {
2495   if (!thisObj->inherits(&History::info))
2496     return throwError(exec, TypeError);
2497   History *history = static_cast<History *>(thisObj);
2498
2499   int steps;
2500   switch (id) {
2501   case History::Back:
2502     steps = -1;
2503     break;
2504   case History::Forward:
2505     steps = 1;
2506     break;
2507   case History::Go:
2508     steps = args[0]->toInt32(exec);
2509     break;
2510   default:
2511     return jsUndefined();
2512   }
2513
2514   if (Frame* frame = history->m_frame)
2515       frame->loader()->scheduleHistoryNavigation(steps);
2516   return jsUndefined();
2517 }
2518
2519 /////////////////////////////////////////////////////////////////////////////
2520
2521 PausedTimeouts::~PausedTimeouts()
2522 {
2523     PausedTimeout *array = m_array;
2524     if (!array)
2525         return;
2526     size_t count = m_length;
2527     for (size_t i = 0; i != count; ++i)
2528         delete array[i].action;
2529     delete [] array;
2530 }
2531
2532 void DOMWindowTimer::fired()
2533 {
2534     timerNestingLevel = m_nestingLevel;
2535     m_object->timerFired(this);
2536     timerNestingLevel = 0;
2537 }
2538
2539 } // namespace KJS
2540
2541 using namespace KJS;
2542
2543 namespace WebCore {
2544
2545 JSValue* toJS(ExecState*, DOMWindow* domWindow)
2546 {
2547     if (!domWindow)
2548         return jsNull();
2549     Frame* frame = domWindow->frame();
2550     if (!frame)
2551         return jsNull();
2552     return Window::retrieve(frame);
2553 }
2554
2555 DOMWindow* toDOMWindow(JSValue* val)
2556 {
2557     return val->isObject(&JSDOMWindow::info) ? static_cast<JSDOMWindow*>(val)->impl() : 0;
2558 }
2559     
2560 } // namespace WebCore