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