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 "PlatformString.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, unloadEvent);
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, unloadEvent, 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 DOMString& keyString, const DOMString& 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 // Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
1449 static bool isSeparator(QChar c)
1450 {
1451     return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0';
1452 }
1453
1454 static void parseWindowFeatures(const DOMString& features, WindowArgs& windowArgs)
1455 {
1456     /*
1457      The IE rule is: all features except for channelmode and fullscreen default to YES, but
1458      if the user specifies a feature string, all features default to NO. (There is no public
1459      standard that applies to this method.)
1460      
1461      <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
1462      */
1463     
1464     windowArgs.dialog = false;
1465     windowArgs.fullscreen = false;
1466     
1467     windowArgs.xSet = false;
1468     windowArgs.ySet = false;
1469     windowArgs.widthSet = false;
1470     windowArgs.heightSet = false;
1471     
1472     if (features.length() == 0) {
1473         windowArgs.menuBarVisible = true;
1474         windowArgs.statusBarVisible = true;
1475         windowArgs.toolBarVisible = true;
1476         windowArgs.locationBarVisible = true;
1477         windowArgs.scrollBarsVisible = true;
1478         windowArgs.resizable = true;
1479         
1480         return;
1481     }
1482     
1483     windowArgs.menuBarVisible = false;
1484     windowArgs.statusBarVisible = false;
1485     windowArgs.toolBarVisible = false;
1486     windowArgs.locationBarVisible = false;
1487     windowArgs.scrollBarsVisible = false;
1488     windowArgs.resizable = false;
1489     
1490     // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
1491     int keyBegin, keyEnd;
1492     int valueBegin, valueEnd;
1493     
1494     int i = 0;
1495     int length = features.length();
1496     DOMString buffer = features.lower();
1497     while (i < length) {
1498         // skip to first non-separator, but don't skip past the end of the string
1499         while (isSeparator(buffer[i])) {
1500             if (i >= length)
1501                 break;
1502             i++;
1503         }
1504         keyBegin = i;
1505         
1506         // skip to first separator
1507         while (!isSeparator(buffer[i]))
1508             i++;
1509         keyEnd = i;
1510         
1511         // skip to first '=', but don't skip past a ',' or the end of the string
1512         while (buffer[i] != '=') {
1513             if (buffer[i] == ',' || i >= length)
1514                 break;
1515             i++;
1516         }
1517         
1518         // skip to first non-separator, but don't skip past a ',' or the end of the string
1519         while (isSeparator(buffer[i])) {
1520             if (buffer[i] == ',' || i >= length)
1521                 break;
1522             i++;
1523         }
1524         valueBegin = i;
1525         
1526         // skip to first separator
1527         while (!isSeparator(buffer[i]))
1528             i++;
1529         valueEnd = i;
1530         
1531         assert(i <= length);
1532
1533         DOMString keyString(buffer.substring(keyBegin, keyEnd - keyBegin));
1534         DOMString valueString(buffer.substring(valueBegin, valueEnd - valueBegin));
1535         setWindowFeature(keyString, valueString, windowArgs);
1536     }
1537 }
1538
1539 static void constrainToVisible(const IntRect& screen, WindowArgs& windowArgs)
1540 {
1541     windowArgs.x += screen.x();
1542     if (windowArgs.x < screen.x() || windowArgs.x >= screen.right())
1543         windowArgs.x = screen.x(); // only safe choice until size is determined
1544     
1545     windowArgs.y += screen.y();
1546     if (windowArgs.y < screen.y() || windowArgs.y >= screen.bottom())
1547         windowArgs.y = screen.y(); // only safe choice until size is determined
1548     
1549     if (windowArgs.height > screen.height()) // should actually check workspace
1550         windowArgs.height = screen.height();
1551     if (windowArgs.height < 100)
1552         windowArgs.height = 100;
1553     
1554     if (windowArgs.width > screen.width()) // should actually check workspace
1555         windowArgs.width = screen.width();
1556     if (windowArgs.width < 100)
1557         windowArgs.width = 100;
1558 }
1559
1560 JSValue *WindowFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
1561 {
1562   if (!thisObj->inherits(&Window::info))
1563     return throwError(exec, TypeError);
1564   Window *window = static_cast<Window *>(thisObj);
1565   Frame *frame = window->m_frame;
1566   if (!frame)
1567     return jsUndefined();
1568
1569   FrameView *widget = frame->view();
1570   JSValue *v = args[0];
1571   UString s = v->toString(exec);
1572   DOMString str = s.domString();
1573   DOMString str2;
1574
1575   switch (id) {
1576   case Window::Alert:
1577     if (frame && frame->document())
1578       frame->document()->updateRendering();
1579     frame->runJavaScriptAlert(str);
1580     return jsUndefined();
1581   case Window::Confirm:
1582     if (frame && frame->document())
1583       frame->document()->updateRendering();
1584     return jsBoolean(frame->runJavaScriptConfirm(str));
1585   case Window::Prompt:
1586   {
1587     if (frame && frame->document())
1588       frame->document()->updateRendering();
1589     DOMString message = args.size() >= 2 ? args[1]->toString(exec).domString() : DOMString();
1590     bool ok = frame->runJavaScriptPrompt(str, message, str2);
1591     if (ok)
1592         return jsString(str2);
1593     else
1594         return jsNull();
1595   }
1596   case Window::Open:
1597   {
1598       QString frameName = args[1]->isUndefinedOrNull() ? QString("_blank") : args[1]->toString(exec).qstring();
1599       if (!allowPopUp(exec, window)
1600             && !(frameName == "_top" || frameName == "_parent" || frameName == "_self" || frame->findFrame(frameName)))
1601           return jsUndefined();
1602       
1603       WindowArgs windowArgs;
1604       DOMString features = args[2]->isUndefinedOrNull() ? DOMString() : args[2]->toString(exec).domString();
1605       parseWindowFeatures(features, windowArgs);
1606       constrainToVisible(screenRect(widget), windowArgs);
1607       
1608       // prepare arguments
1609       KURL url;
1610       Frame* activePart = Window::retrieveActive(exec)->m_frame;
1611       if (!str.isEmpty() && activePart)
1612           url = activePart->document()->completeURL(str.qstring());
1613
1614       URLArgs uargs;
1615       uargs.frameName = frameName;
1616       if (uargs.frameName == "_top") {
1617           while (frame->treeNode()->parent())
1618               frame = frame->treeNode()->parent();
1619           
1620           const Window* window = Window::retrieveWindow(frame);
1621           if (!url.url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
1622               bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1623               frame->scheduleLocationChange(url.url(), activePart->referrer(), false/*don't lock history*/, userGesture);
1624           }
1625           return Window::retrieve(frame);
1626       }
1627       if (uargs.frameName == "_parent") {
1628           if (frame->treeNode()->parent())
1629               frame = frame->treeNode()->parent();
1630           
1631           const Window* window = Window::retrieveWindow(frame);
1632           if (!url.url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
1633               bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1634               frame->scheduleLocationChange(url.url(), activePart->referrer(), false/*don't lock history*/, userGesture);
1635           }
1636           return Window::retrieve(frame);
1637       }
1638       uargs.serviceType = "text/html";
1639       
1640       // request window (new or existing if framename is set)
1641       ObjectContents* newPart = 0;
1642       uargs.metaData().set("referrer", activePart->referrer());
1643       frame->browserExtension()->createNewWindow("", uargs, windowArgs, newPart);
1644       if (!newPart || !newPart->inherits("Frame"))
1645           return jsUndefined();
1646       Frame *newFrame = static_cast<Frame*>(newPart);
1647       newFrame->setOpener(frame);
1648       newFrame->setOpenedByJS(true);
1649       
1650       if (!newFrame->document()) {
1651           DocumentImpl* oldDoc = frame->document();
1652           if (oldDoc && oldDoc->baseURL() != 0)
1653               newFrame->begin(oldDoc->baseURL());
1654           else
1655               newFrame->begin();
1656           newFrame->write("<HTML><BODY>");
1657           newFrame->end();          
1658           if (oldDoc) {
1659               newFrame->document()->setDomain(oldDoc->domain(), true);
1660               newFrame->document()->setBaseURL(oldDoc->baseURL());
1661           }
1662       }
1663       if (!url.isEmpty()) {
1664           const Window* window = Window::retrieveWindow(newFrame);
1665           if (!url.url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
1666               bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1667               newFrame->scheduleLocationChange(url.url(), activePart->referrer(), false, userGesture);
1668           }
1669       }
1670       return Window::retrieve(newFrame); // global object
1671   }
1672   case Window::Print:
1673     frame->print();
1674     return jsUndefined();
1675   case Window::ScrollBy:
1676     window->updateLayout();
1677     if(args.size() >= 2 && widget)
1678       widget->scrollBy(args[0]->toInt32(exec), args[1]->toInt32(exec));
1679     return jsUndefined();
1680   case Window::Scroll:
1681   case Window::ScrollTo:
1682     window->updateLayout();
1683     if (args.size() >= 2 && widget)
1684       widget->setContentsPos(args[0]->toInt32(exec), args[1]->toInt32(exec));
1685     return jsUndefined();
1686   case Window::MoveBy:
1687     if(args.size() >= 2 && widget)
1688     {
1689       QWidget* tl = widget->topLevelWidget();
1690       IntRect sg = screenRect(widget);
1691       IntPoint dest = tl->pos() + IntPoint(args[0]->toInt32(exec), args[1]->toInt32(exec));
1692       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1693       if (sg.contains(IntRect(dest, IntSize(tl->width(), tl->height()))))
1694         tl->move(dest);
1695     }
1696     return jsUndefined();
1697   case Window::MoveTo:
1698     if(args.size() >= 2 && widget)
1699     {
1700       QWidget* tl = widget->topLevelWidget();
1701       IntRect sg = screenRect(widget);
1702       IntPoint dest(args[0]->toInt32(exec) + sg.x(), args[1]->toInt32(exec) + sg.y());
1703       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1704       if (sg.contains(IntRect(dest, IntSize(tl->width(), tl->height()))))
1705         tl->move(dest);
1706     }
1707     return jsUndefined();
1708   case Window::ResizeBy:
1709     if(args.size() >= 2 && widget)
1710     {
1711       QWidget* tl = widget->topLevelWidget();
1712       IntSize dest = tl->size() + IntSize(args[0]->toInt32(exec), args[1]->toInt32(exec));
1713       IntRect sg = screenRect(widget);
1714       // Security check: within desktop limits and bigger than 100x100 (per spec)
1715       if (tl->x() + dest.width() <= sg.right() && tl->y() + dest.height() <= sg.bottom()
1716            && dest.width() >= 100 && dest.height() >= 100)
1717       {
1718         // Take into account the window frame
1719         int deltaWidth = tl->frameGeometry().width() - tl->width();
1720         int deltaHeight = tl->frameGeometry().height() - tl->height();
1721         tl->resize(dest.width() - deltaWidth, dest.height() - deltaHeight);
1722       }
1723     }
1724     return jsUndefined();
1725   case Window::ResizeTo:
1726     if (args.size() >= 2 && widget) {
1727       QWidget* tl = widget->topLevelWidget();
1728       IntSize dest = IntSize(args[0]->toInt32(exec), args[1]->toInt32(exec));
1729       IntRect sg = screenRect(widget);
1730       // Security check: within desktop limits and bigger than 100x100 (per spec)
1731       if (tl->x() + dest.width() <= sg.right() && tl->y() + dest.height() <= sg.bottom() &&
1732            dest.width() >= 100 && dest.height() >= 100)
1733       {
1734         // Take into account the window frame
1735         int deltaWidth = tl->frameGeometry().width() - tl->width();
1736         int deltaHeight = tl->frameGeometry().height() - tl->height();
1737         tl->resize(dest.width() - deltaWidth, dest.height() - deltaHeight);
1738       }
1739     }
1740     return jsUndefined();
1741   case Window::SetTimeout:
1742     if (!window->isSafeScript(exec))
1743         return jsUndefined();
1744     if (args.size() >= 2 && v->isString()) {
1745       int i = args[1]->toInt32(exec);
1746       int r = (const_cast<Window*>(window))->installTimeout(s, i, true /*single shot*/);
1747       return jsNumber(r);
1748     }
1749     else if (args.size() >= 2 && v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1750       JSValue *func = args[0];
1751       int i = args[1]->toInt32(exec);
1752
1753       // All arguments after the second should go to the function
1754       // FIXME: could be more efficient
1755       List funcArgs = args.copyTail().copyTail();
1756
1757       int r = (const_cast<Window*>(window))->installTimeout(func, funcArgs, i, true /*single shot*/);
1758       return jsNumber(r);
1759     }
1760     else
1761       return jsUndefined();
1762   case Window::SetInterval:
1763     if (!window->isSafeScript(exec))
1764         return jsUndefined();
1765     if (args.size() >= 2 && v->isString()) {
1766       int i = args[1]->toInt32(exec);
1767       int r = (const_cast<Window*>(window))->installTimeout(s, i, false);
1768       return jsNumber(r);
1769     }
1770     else if (args.size() >= 2 && v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1771       JSValue *func = args[0];
1772       int i = args[1]->toInt32(exec);
1773
1774       // All arguments after the second should go to the function
1775       // FIXME: could be more efficient
1776       List funcArgs = args.copyTail().copyTail();
1777
1778       int r = (const_cast<Window*>(window))->installTimeout(func, funcArgs, i, false);
1779       return jsNumber(r);
1780     }
1781     else
1782       return jsUndefined();
1783   case Window::ClearTimeout:
1784   case Window::ClearInterval:
1785     if (!window->isSafeScript(exec))
1786         return jsUndefined();
1787     (const_cast<Window*>(window))->clearTimeout(v->toInt32(exec));
1788     return jsUndefined();
1789   case Window::Focus:
1790     if (widget)
1791       widget->setActiveWindow();
1792     return jsUndefined();
1793   case Window::GetSelection:
1794     if (!window->isSafeScript(exec))
1795         return jsUndefined();
1796     return window->selection();
1797   case Window::Blur:
1798     frame->unfocusWindow();
1799     return jsUndefined();
1800   case Window::Close:
1801     /* From http://developer.netscape.com/docs/manuals/js/client/jsref/window.htm :
1802        The close method closes only windows opened by JavaScript using the open method.
1803        If you attempt to close any other window, a confirm is generated, which
1804        lets the user choose whether the window closes.
1805        This is a security feature to prevent "mail bombs" containing self.close().
1806        However, if the window has only one document (the current one) in its
1807        session history, the close is allowed without any confirm. This is a
1808        special case for one-off windows that need to open other windows and
1809        then dispose of themselves.
1810     */
1811     if (!frame->openedByJS())
1812     {
1813       // To conform to the SPEC, we only ask if the window
1814       // has more than one entry in the history (NS does that too).
1815       History history(exec, frame);
1816       if ( history.get( exec, lengthPropertyName )->toInt32(exec) <= 1
1817            // FIXME: How are we going to handle this?
1818            )
1819         (const_cast<Window*>(window))->scheduleClose();
1820     }
1821     else
1822     {
1823       (const_cast<Window*>(window))->scheduleClose();
1824     }
1825     return jsUndefined();
1826   case Window::CaptureEvents:
1827   case Window::ReleaseEvents:
1828         // If anyone implements these, they need the safescript security check.
1829         if (!window->isSafeScript(exec))
1830             return jsUndefined();
1831
1832     // Do nothing for now. These are NS-specific legacy calls.
1833     break;
1834   case Window::AddEventListener:
1835         if (!window->isSafeScript(exec))
1836             return jsUndefined();
1837         if (JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]))
1838             if (DocumentImpl *doc = frame->document())
1839                 doc->addWindowEventListener(AtomicString(args[0]->toString(exec).domString()), listener, args[2]->toBoolean(exec));
1840         return jsUndefined();
1841   case Window::RemoveEventListener:
1842         if (!window->isSafeScript(exec))
1843             return jsUndefined();
1844         if (JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]))
1845             if (DocumentImpl *doc = frame->document())
1846                 doc->removeWindowEventListener(AtomicString(args[0]->toString(exec).domString()), listener, args[2]->toBoolean(exec));
1847         return jsUndefined();
1848   case Window::ShowModalDialog:
1849     return showModalDialog(exec, window, args);
1850   }
1851   return jsUndefined();
1852 }
1853
1854 void Window::updateLayout() const
1855 {
1856   DOM::DocumentImpl* docimpl = m_frame->document();
1857   if (docimpl)
1858     docimpl->updateLayoutIgnorePendingStylesheets();
1859 }
1860
1861 ////////////////////// ScheduledAction ////////////////////////
1862
1863 void ScheduledAction::execute(Window *window)
1864 {
1865     if (!window->m_frame || !window->m_frame->jScript())
1866         return;
1867
1868     ScriptInterpreter *interpreter = window->m_frame->jScript()->interpreter();
1869
1870     interpreter->setProcessingTimerCallback(true);
1871   
1872     if (JSValue* func = m_func.get()) {
1873         if (func->isObject() && static_cast<JSObject *>(func)->implementsCall()) {
1874             ExecState *exec = interpreter->globalExec();
1875             ASSERT(window == interpreter->globalObject());
1876             JSLock lock;
1877             static_cast<JSObject *>(func)->call(exec, window, m_args);
1878             if (exec->hadException()) {
1879                 JSObject* exception = exec->exception()->toObject(exec);
1880                 exec->clearException();
1881                 DOMString message = exception->get(exec, messagePropertyName)->toString(exec).domString();
1882                 int lineNumber = exception->get(exec, "line")->toInt32(exec);
1883                 if (Interpreter::shouldPrintExceptions())
1884                     printf("(timer):%s\n", message.qstring().utf8().data());
1885                 window->m_frame->addMessageToConsole(message, lineNumber, DOMString());
1886             }
1887         }
1888     } else
1889         window->m_frame->executeScript(0, m_code);
1890   
1891     // Update our document's rendering following the execution of the timeout callback.
1892     // FIXME: Why? Why not other documents, for example?
1893     DocumentImpl *doc = window->m_frame->document();
1894     if (doc)
1895         doc->updateRendering();
1896   
1897     interpreter->setProcessingTimerCallback(false);
1898 }
1899
1900 ////////////////////// WindowQObject ////////////////////////
1901
1902 WindowQObject::WindowQObject(Window *w)
1903     : m_parent(w)
1904 {
1905     connect(w->m_frame, SIGNAL(destroyed()), this, SLOT(parentDestroyed()));
1906 }
1907
1908 void WindowQObject::parentDestroyed()
1909 {
1910     deleteAllValues(m_timeouts);
1911     m_timeouts.clear();
1912 }
1913
1914 int WindowQObject::installTimeout(ScheduledAction* a, int t, bool singleShot)
1915 {
1916     int timeoutId = ++lastUsedTimeoutId;
1917     DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, this, a);
1918     ASSERT(!m_timeouts.get(timeoutId));
1919     m_timeouts.set(timeoutId, timer);
1920     // Use a minimum interval of 10 ms to match other browsers.
1921     // Faster timers might be "better", but they're incompatible.
1922     double interval = t <= 10 ? 0.010 : t * 0.001;
1923     if (singleShot)
1924         timer->startOneShot(interval);
1925     else
1926         timer->startRepeating(interval);
1927     return timeoutId;
1928 }
1929
1930 int WindowQObject::installTimeout(const UString& handler, int t, bool singleShot)
1931 {
1932     return installTimeout(new ScheduledAction(handler.qstring()), t, singleShot);
1933 }
1934
1935 int WindowQObject::installTimeout(JSValue* func, const List& args, int t, bool singleShot)
1936 {
1937     return installTimeout(new ScheduledAction(func, args), t, singleShot);
1938 }
1939
1940 PausedTimeouts *WindowQObject::pauseTimeouts()
1941 {
1942     size_t count = m_timeouts.size();
1943     if (count == 0)
1944         return 0;
1945
1946     PausedTimeout* t = new PausedTimeout [count];
1947     PausedTimeouts* result = new PausedTimeouts(t, count);
1948
1949     TimeoutsMap::iterator it = m_timeouts.begin();
1950     for (size_t i = 0; i != count; ++i, ++it) {
1951         int timeoutId = it->first;
1952         DOMWindowTimer* timer = it->second;
1953         t[i].timeoutId = timeoutId;
1954         t[i].nextFireInterval = timer->nextFireInterval();
1955         t[i].repeatInterval = timer->repeatInterval();
1956         t[i].action = timer->takeAction();
1957     }
1958     ASSERT(it == m_timeouts.end());
1959
1960     deleteAllValues(m_timeouts);
1961     m_timeouts.clear();
1962
1963     return result;
1964 }
1965
1966 void WindowQObject::resumeTimeouts(PausedTimeouts *timeouts)
1967 {
1968     if (!timeouts)
1969         return;
1970     size_t count = timeouts->numTimeouts();
1971     PausedTimeout *array = timeouts->takeTimeouts();
1972     for (size_t i = 0; i != count; ++i) {
1973         int timeoutId = array[i].timeoutId;
1974         DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, this, array[i].action);
1975         m_timeouts.set(timeoutId, timer);
1976         timer->start(array[i].nextFireInterval, array[i].repeatInterval);
1977     }
1978     delete [] array;
1979 }
1980
1981 void WindowQObject::clearTimeout(int timeoutId, bool delAction)
1982 {
1983     TimeoutsMap::iterator it = m_timeouts.find(timeoutId);
1984     if (it == m_timeouts.end())
1985         return;
1986     DOMWindowTimer* timer = it->second;
1987     m_timeouts.remove(it);
1988     delete timer;
1989 }
1990
1991 void WindowQObject::timerFired(DOMWindowTimer* timer)
1992 {
1993     // Simple case for non-one-shot timers.
1994     if (timer->isActive()) {
1995         timer->action()->execute(m_parent);
1996         return;
1997     }
1998
1999     // Delete timer before executing the action for one-shot timers.
2000     ScheduledAction* action = timer->takeAction();
2001     m_timeouts.remove(timer->timeoutId());
2002     delete timer;
2003     action->execute(m_parent);
2004     delete action;
2005 }
2006
2007 const ClassInfo FrameArray::info = { "FrameArray", 0, &FrameArrayTable, 0 };
2008
2009 /*
2010 @begin FrameArrayTable 2
2011 length          FrameArray::Length      DontDelete|ReadOnly
2012 location        FrameArray::Location    DontDelete|ReadOnly
2013 @end
2014 */
2015
2016 JSValue *FrameArray::getValueProperty(ExecState *exec, int token)
2017 {
2018   switch (token) {
2019   case Length: {
2020     QPtrList<ObjectContents> frames = m_frame->frames();
2021     unsigned int len = frames.count();
2022     return jsNumber(len);
2023   }
2024   case Location:
2025     // non-standard property, but works in NS and IE
2026     if (JSObject *obj = Window::retrieveWindow(m_frame))
2027       return obj->get(exec, "location");
2028     return jsUndefined();
2029   default:
2030     ASSERT(0);
2031     return jsUndefined();
2032   }
2033 }
2034
2035 JSValue *FrameArray::indexGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
2036 {
2037   FrameArray *thisObj = static_cast<FrameArray *>(slot.slotBase());
2038   ObjectContents *frame = thisObj->m_frame->frames().at(slot.index());
2039
2040   if (frame && frame->inherits("Frame")) {
2041     Frame *khtml = static_cast<Frame*>(frame);
2042     return Window::retrieve(khtml);
2043   }
2044
2045   return jsUndefined();
2046 }
2047
2048 JSValue *FrameArray::nameGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
2049 {
2050   FrameArray *thisObj = static_cast<FrameArray *>(slot.slotBase());
2051   ObjectContents *frame = thisObj->m_frame->findFrame(propertyName.qstring());
2052
2053   if (frame && frame->inherits("Frame")) {
2054     Frame *khtml = static_cast<Frame*>(frame);
2055     return  Window::retrieve(khtml);
2056   }
2057
2058   return jsUndefined();
2059 }
2060
2061 bool FrameArray::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
2062 {
2063   if (m_frame.isNull()) {
2064     slot.setUndefined(this);
2065     return true;
2066   }
2067
2068   const HashEntry* entry = Lookup::findEntry(&FrameArrayTable, propertyName);
2069   if (entry) {
2070     slot.setStaticEntry(this, entry, staticValueGetter<FrameArray>);
2071     return true;
2072   }
2073
2074   // check for the name or number
2075   ObjectContents *frame = m_frame->findFrame(propertyName.qstring());
2076   if (frame) {
2077     slot.setCustom(this, nameGetter);
2078     return true;
2079   }
2080
2081   bool ok;
2082   unsigned int i = propertyName.toArrayIndex(&ok);
2083   if (ok && i < m_frame->frames().count()) {
2084     slot.setCustomIndex(this, i, indexGetter);
2085     return true;
2086   }
2087
2088   return JSObject::getOwnPropertySlot(exec, propertyName, slot);
2089 }
2090
2091 UString FrameArray::toString(ExecState *) const
2092 {
2093   return "[object FrameArray]";
2094 }
2095
2096 ////////////////////// Location Object ////////////////////////
2097
2098 const ClassInfo Location::info = { "Location", 0, 0, 0 };
2099 /*
2100 @begin LocationTable 12
2101   assign        Location::Assign        DontDelete|Function 1
2102   hash          Location::Hash          DontDelete
2103   host          Location::Host          DontDelete
2104   hostname      Location::Hostname      DontDelete
2105   href          Location::Href          DontDelete
2106   pathname      Location::Pathname      DontDelete
2107   port          Location::Port          DontDelete
2108   protocol      Location::Protocol      DontDelete
2109   search        Location::Search        DontDelete
2110   [[==]]        Location::EqualEqual    DontDelete|ReadOnly
2111   toString      Location::ToString      DontDelete|Function 0
2112   replace       Location::Replace       DontDelete|Function 1
2113   reload        Location::Reload        DontDelete|Function 0
2114 @end
2115 */
2116 KJS_IMPLEMENT_PROTOFUNC(LocationFunc)
2117 Location::Location(Frame *p) : m_frame(p)
2118 {
2119 }
2120
2121 JSValue *Location::getValueProperty(ExecState *exec, int token) const
2122 {
2123   KURL url = m_frame->url();
2124   switch (token) {
2125   case Hash:
2126     return jsString(url.ref().isNull() ? QString("") : "#" + url.ref());
2127   case Host: {
2128     // Note: this is the IE spec. The NS spec swaps the two, it says
2129     // "The hostname property is the concatenation of the host and port properties, separated by a colon."
2130     // Bleh.
2131     UString str = url.host();
2132     if (url.port())
2133             str += ":" + QString::number((int)url.port());
2134     return jsString(str);
2135   }
2136   case Hostname:
2137     return jsString(url.host());
2138   case Href:
2139     if (!url.hasPath())
2140       return jsString(url.prettyURL() + "/");
2141     else
2142       return jsString(url.prettyURL());
2143   case Pathname:
2144     return jsString(url.path().isEmpty() ? QString("/") : url.path());
2145   case Port:
2146     return jsString(url.port() ? QString::number((int)url.port()) : QString::fromLatin1(""));
2147   case Protocol:
2148     return jsString(url.protocol()+":");
2149   case Search:
2150     return jsString(url.query());
2151   default:
2152     ASSERT(0);
2153     return jsUndefined();
2154   }
2155 }
2156
2157 bool Location::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) 
2158 {
2159   if (m_frame.isNull())
2160     return false;
2161   
2162   const Window* window = Window::retrieveWindow(m_frame);
2163   if (!window || !window->isSafeScript(exec)) {
2164       slot.setUndefined(this);
2165       return true;
2166   }
2167
2168   return getStaticPropertySlot<LocationFunc, Location, JSObject>(exec, &LocationTable, this, propertyName, slot);
2169 }
2170
2171 void Location::put(ExecState *exec, const Identifier &p, JSValue *v, int attr)
2172 {
2173   if (m_frame.isNull())
2174     return;
2175
2176   QString str = v->toString(exec).qstring();
2177   KURL url = m_frame->url();
2178   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
2179   if (entry)
2180     switch (entry->value) {
2181     case Href: {
2182       Frame* p = Window::retrieveActive(exec)->frame();
2183       if ( p )
2184         url = p->document()->completeURL( str );
2185       else
2186         url = str;
2187       break;
2188     }
2189     case Hash:
2190       url.setRef(str);
2191       break;
2192     case Host: {
2193       QString host = str.left(str.find(":"));
2194       QString port = str.mid(str.find(":")+1);
2195       url.setHost(host);
2196       url.setPort(port.toUInt());
2197       break;
2198     }
2199     case Hostname:
2200       url.setHost(str);
2201       break;
2202     case Pathname:
2203       url.setPath(str);
2204       break;
2205     case Port:
2206       url.setPort(str.toUInt());
2207       break;
2208     case Protocol:
2209       url.setProtocol(str);
2210       break;
2211     case Search:
2212       url.setQuery(str);
2213       break;
2214     }
2215   else {
2216     JSObject::put(exec, p, v, attr);
2217     return;
2218   }
2219
2220   const Window* window = Window::retrieveWindow(m_frame);
2221   Frame* activePart = Window::retrieveActive(exec)->frame();
2222   if (!url.url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2223     bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2224     // We want a new history item if this JS was called via a user gesture
2225     m_frame->scheduleLocationChange(url.url(), activePart->referrer(), !userGesture, userGesture);
2226   }
2227 }
2228
2229 JSValue *Location::toPrimitive(ExecState *exec, Type) const
2230 {
2231   return jsString(toString(exec));
2232 }
2233
2234 UString Location::toString(ExecState *) const
2235 {
2236   if (!m_frame->url().hasPath())
2237     return m_frame->url().prettyURL()+"/";
2238   else
2239     return m_frame->url().prettyURL();
2240 }
2241
2242 JSValue *LocationFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2243 {
2244   if (!thisObj->inherits(&Location::info))
2245     return throwError(exec, TypeError);
2246   Location *location = static_cast<Location *>(thisObj);
2247   Frame *frame = location->frame();
2248   if (frame) {
2249       
2250     Window* window = Window::retrieveWindow(frame);
2251     if (!window->isSafeScript(exec) && id != Location::Replace)
2252         return jsUndefined();
2253       
2254     switch (id) {
2255     case Location::Replace:
2256     {
2257       QString str = args[0]->toString(exec).qstring();
2258       Frame* p = Window::retrieveActive(exec)->frame();
2259       if ( p ) {
2260         const Window* window = Window::retrieveWindow(frame);
2261         if (!str.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2262           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2263           frame->scheduleLocationChange(p->document()->completeURL(str), p->referrer(), true /*lock history*/, userGesture);
2264         }
2265       }
2266       break;
2267     }
2268     case Location::Reload:
2269     {
2270       const Window* window = Window::retrieveWindow(frame);
2271       Frame* activePart = Window::retrieveActive(exec)->frame();
2272       if (!frame->url().url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2273         bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2274         frame->scheduleLocationChange(frame->url().url(), activePart->referrer(), true/*lock history*/, userGesture);
2275       }
2276       break;
2277     }
2278     case Location::Assign:
2279     {
2280         Frame *p = Window::retrieveActive(exec)->frame();
2281         if (p) {
2282             const Window *window = Window::retrieveWindow(frame);
2283             QString dstUrl = p->document()->completeURL(args[0]->toString(exec).qstring());
2284             if (!dstUrl.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2285                 bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2286                 // We want a new history item if this JS was called via a user gesture
2287                 frame->scheduleLocationChange(dstUrl, p->referrer(), !userGesture, userGesture);
2288             }
2289         }
2290         break;
2291     }
2292     case Location::ToString:
2293       return jsString(location->toString(exec));
2294     }
2295   } else
2296     kdDebug(6070) << "LocationFunc::tryExecute - no frame!" << endl;
2297   return jsUndefined();
2298 }
2299
2300 ////////////////////// Selection Object ////////////////////////
2301
2302 const ClassInfo Selection::info = { "Selection", 0, 0, 0 };
2303 /*
2304 @begin SelectionTable 19
2305   anchorNode                Selection::AnchorNode               DontDelete|ReadOnly
2306   anchorOffset              Selection::AnchorOffset             DontDelete|ReadOnly
2307   focusNode                 Selection::FocusNode                DontDelete|ReadOnly
2308   focusOffset               Selection::FocusOffset              DontDelete|ReadOnly
2309   baseNode                  Selection::BaseNode                 DontDelete|ReadOnly
2310   baseOffset                Selection::BaseOffset               DontDelete|ReadOnly
2311   extentNode                Selection::ExtentNode               DontDelete|ReadOnly
2312   extentOffset              Selection::ExtentOffset             DontDelete|ReadOnly
2313   isCollapsed               Selection::IsCollapsed              DontDelete|ReadOnly
2314   type                      Selection::_Type                    DontDelete|ReadOnly
2315   [[==]]                    Selection::EqualEqual               DontDelete|ReadOnly
2316   toString                  Selection::ToString                 DontDelete|Function 0
2317   collapse                  Selection::Collapse                 DontDelete|Function 2
2318   collapseToEnd             Selection::CollapseToEnd            DontDelete|Function 0
2319   collapseToStart           Selection::CollapseToStart          DontDelete|Function 0
2320   empty                     Selection::Empty                    DontDelete|Function 0
2321   setBaseAndExtent          Selection::SetBaseAndExtent         DontDelete|Function 4
2322   setPosition               Selection::SetPosition              DontDelete|Function 2
2323   modify                    Selection::Modify                   DontDelete|Function 3
2324   getRangeAt                Selection::GetRangeAt               DontDelete|Function 1
2325 @end
2326 */
2327 KJS_IMPLEMENT_PROTOFUNC(SelectionFunc)
2328 Selection::Selection(Frame *p) : m_frame(p)
2329 {
2330 }
2331
2332 JSValue *Selection::getValueProperty(ExecState *exec, int token) const
2333 {
2334     SelectionController s = m_frame->selection();
2335     const Window* window = Window::retrieveWindow(m_frame);
2336     if (!window)
2337         return jsUndefined();
2338         
2339     switch (token) {
2340     case AnchorNode:
2341         return getDOMNode(exec, s.anchorNode());
2342     case BaseNode:
2343         return getDOMNode(exec, s.baseNode());
2344     case AnchorOffset:
2345         return jsNumber(s.anchorOffset());
2346     case BaseOffset:
2347         return jsNumber(s.baseOffset());
2348     case FocusNode:
2349         return getDOMNode(exec, s.focusNode());
2350     case ExtentNode:
2351         return getDOMNode(exec, s.extentNode());
2352     case FocusOffset:
2353         return jsNumber(s.focusOffset());
2354     case ExtentOffset:
2355         return jsNumber(s.extentOffset());
2356     case IsCollapsed:
2357         return jsBoolean(s.isCollapsed());
2358     case _Type:
2359         return jsString(s.type());
2360     default:
2361         ASSERT(0);
2362         return jsUndefined();
2363     }
2364 }
2365
2366 bool Selection::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
2367 {
2368   if (m_frame.isNull())
2369       return false;
2370
2371   return getStaticPropertySlot<SelectionFunc, Selection, JSObject>(exec, &SelectionTable, this, propertyName, slot);
2372 }
2373
2374 JSValue *Selection::toPrimitive(ExecState *exec, Type) const
2375 {
2376   return jsString(toString(exec));
2377 }
2378
2379 UString Selection::toString(ExecState *) const
2380 {
2381     return UString((m_frame->selection()).toString());
2382 }
2383
2384 JSValue *SelectionFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2385 {
2386     if (!thisObj->inherits(&Selection::info))
2387         return throwError(exec, TypeError);
2388     Selection *selection = static_cast<Selection *>(thisObj);
2389     Frame *frame = selection->frame();
2390     if (frame) {
2391         SelectionController s = frame->selection();
2392         
2393         switch (id) {
2394             case Selection::Collapse:
2395                 s.collapse(toNode(args[0]), args[1]->toInt32(exec));
2396                 break;
2397             case Selection::CollapseToEnd:
2398                 s.collapseToEnd();
2399                 break;
2400             case Selection::CollapseToStart:
2401                 s.collapseToStart();
2402                 break;
2403             case Selection::Empty:
2404                 s.empty();
2405                 break;
2406             case Selection::SetBaseAndExtent:
2407                 s.setBaseAndExtent(toNode(args[0]), args[1]->toInt32(exec), toNode(args[2]), args[3]->toInt32(exec));
2408                 break;
2409             case Selection::SetPosition:
2410                 s.setPosition(toNode(args[0]), args[1]->toInt32(exec));
2411                 break;
2412             case Selection::Modify:
2413                 s.modify(args[0]->toString(exec).domString(), args[1]->toString(exec).domString(), args[2]->toString(exec).domString());
2414                 break;
2415             case Selection::GetRangeAt:
2416                 return getDOMRange(exec, s.getRangeAt(args[0]->toInt32(exec)).get());
2417             case Selection::ToString:
2418                 return jsString(s.toString());
2419         }
2420         
2421         frame->setSelection(s);
2422     }
2423
2424     return jsUndefined();
2425 }
2426
2427 ////////////////////// BarInfo Object ////////////////////////
2428
2429 const ClassInfo BarInfo::info = { "BarInfo", 0, 0, 0 };
2430 /*
2431 @begin BarInfoTable 1
2432   visible                BarInfo::Visible                        DontDelete|ReadOnly
2433 @end
2434 */
2435 BarInfo::BarInfo(ExecState *exec, Frame *p, Type barType) 
2436   : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype())
2437   , m_frame(p)
2438   , m_type(barType)
2439 {
2440 }
2441
2442 JSValue *BarInfo::getValueProperty(ExecState *exec, int token) const
2443 {
2444     ASSERT(token == Visible);
2445     switch (m_type) {
2446     case Locationbar:
2447         return jsBoolean(m_frame->locationbarVisible());
2448     case Menubar: 
2449         return jsBoolean(m_frame->locationbarVisible());
2450     case Personalbar:
2451         return jsBoolean(m_frame->personalbarVisible());
2452     case Scrollbars: 
2453         return jsBoolean(m_frame->scrollbarsVisible());
2454     case Statusbar:
2455         return jsBoolean(m_frame->statusbarVisible());
2456     case Toolbar:
2457         return jsBoolean(m_frame->toolbarVisible());
2458     default:
2459         return jsBoolean(false);
2460     }
2461 }
2462
2463 bool BarInfo::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
2464 {
2465   if (m_frame.isNull())
2466     return false;
2467   
2468   return getStaticValueSlot<BarInfo, JSObject>(exec, &BarInfoTable, this, propertyName, slot);
2469 }
2470
2471 ////////////////////// History Object ////////////////////////
2472
2473 const ClassInfo History::info = { "History", 0, 0, 0 };
2474 /*
2475 @begin HistoryTable 4
2476   length        History::Length         DontDelete|ReadOnly
2477   back          History::Back           DontDelete|Function 0
2478   forward       History::Forward        DontDelete|Function 0
2479   go            History::Go             DontDelete|Function 1
2480 @end
2481 */
2482 KJS_IMPLEMENT_PROTOFUNC(HistoryFunc)
2483
2484 bool History::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
2485 {
2486   return getStaticPropertySlot<HistoryFunc, History, JSObject>(exec, &HistoryTable, this, propertyName, slot);
2487 }
2488
2489 JSValue *History::getValueProperty(ExecState *, int token) const
2490 {
2491   switch (token) {
2492   case Length:
2493   {
2494     BrowserExtension *ext = m_frame->browserExtension();
2495     if (!ext)
2496       return jsNumber(0);
2497
2498     return jsNumber(ext->getHistoryLength());
2499   }
2500   default:
2501     kdWarning() << "Unhandled token in History::getValueProperty : " << token << endl;
2502     return jsUndefined();
2503   }
2504 }
2505
2506 UString History::toString(ExecState *exec) const
2507 {
2508   return "[object History]";
2509 }
2510
2511 JSValue *HistoryFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
2512 {
2513   if (!thisObj->inherits(&History::info))
2514     return throwError(exec, TypeError);
2515   History *history = static_cast<History *>(thisObj);
2516
2517   int steps;
2518   switch (id) {
2519   case History::Back:
2520     steps = -1;
2521     break;
2522   case History::Forward:
2523     steps = 1;
2524     break;
2525   case History::Go:
2526     steps = args[0]->toInt32(exec);
2527     break;
2528   default:
2529     return jsUndefined();
2530   }
2531
2532   history->m_frame->scheduleHistoryNavigation(steps);
2533   return jsUndefined();
2534 }
2535
2536 /////////////////////////////////////////////////////////////////////////////
2537
2538 PausedTimeouts::~PausedTimeouts()
2539 {
2540     PausedTimeout *array = m_array;
2541     if (!array)
2542         return;
2543     size_t count = m_length;
2544     for (size_t i = 0; i != count; ++i)
2545         delete array[i].action;
2546     delete [] array;
2547 }
2548
2549 void DOMWindowTimer::fired()
2550 {
2551     m_object->timerFired(this);
2552 }
2553
2554 } // namespace KJS