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