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