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