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