Reviewed by Oliver.
[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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
21  *  USA
22  */
23
24 #include "config.h"
25 #include "kjs_window.h"
26
27 #include "Base64.h"
28 #include "CString.h"
29 #include "Chrome.h"
30 #include "DOMWindow.h"
31 #include "Element.h"
32 #include "EventListener.h"
33 #include "EventNames.h"
34 #include "ExceptionCode.h"
35 #include "FloatRect.h"
36 #include "Frame.h"
37 #include "FrameLoadRequest.h"
38 #include "FrameLoader.h"
39 #include "FrameTree.h"
40 #include "FrameView.h"
41 #include "GCController.h"
42 #include "HTMLDocument.h"
43 #include "JSCSSRule.h"
44 #include "JSCSSValue.h"
45 #include "JSDOMExceptionConstructor.h"
46 #include "JSDOMWindow.h"
47 #include "JSEvent.h"
48 #include "JSHTMLAudioElementConstructor.h"
49 #include "JSHTMLCollection.h"
50 #include "JSHTMLOptionElementConstructor.h"
51 #include "JSMutationEvent.h"
52 #include "JSNode.h"
53 #include "JSNodeFilter.h"
54 #include "JSRange.h"
55 #include "JSXMLHttpRequest.h"
56 #include "Logging.h"
57 #include "Page.h"
58 #include "PlatformScreen.h"
59 #include "PlugInInfoStore.h"
60 #include "RenderView.h"
61 #include "SecurityOrigin.h"
62 #include "Settings.h"
63 #include "WindowFeatures.h"
64 #include "htmlediting.h"
65 #include "kjs_css.h"
66 #include "kjs_events.h"
67 #include "kjs_navigator.h"
68 #include "kjs_proxy.h"
69 #include <wtf/MathExtras.h>
70
71 #if ENABLE(XSLT)
72 #include "JSXSLTProcessor.h"
73 #endif
74
75 using namespace WebCore;
76 using namespace EventNames;
77
78 namespace KJS {
79
80 static int lastUsedTimeoutId;
81
82 static int timerNestingLevel = 0;
83 const int cMaxTimerNestingLevel = 5;
84 const double cMinimumTimerInterval = 0.010;
85
86 struct WindowPrivate {
87     WindowPrivate() 
88         : loc(0)
89         , m_evt(0)
90         , m_returnValueSlot(0)
91     {
92     }
93
94     Window::ListenersMap jsEventListeners;
95     Window::ListenersMap jsHTMLEventListeners;
96     Window::UnprotectedListenersMap jsUnprotectedEventListeners;
97     Window::UnprotectedListenersMap jsUnprotectedHTMLEventListeners;
98     mutable Location* loc;
99     WebCore::Event *m_evt;
100     JSValue** m_returnValueSlot;
101     typedef HashMap<int, DOMWindowTimer*> TimeoutsMap;
102     TimeoutsMap m_timeouts;
103 };
104
105 class DOMWindowTimer : public TimerBase {
106 public:
107     DOMWindowTimer(int timeoutId, int nestingLevel, Window* o, ScheduledAction* a)
108         : m_timeoutId(timeoutId), m_nestingLevel(nestingLevel), m_object(o), m_action(a) { }
109     virtual ~DOMWindowTimer() 
110     { 
111         JSLock lock;
112         delete m_action; 
113     }
114
115     int timeoutId() const { return m_timeoutId; }
116     
117     int nestingLevel() const { return m_nestingLevel; }
118     void setNestingLevel(int n) { m_nestingLevel = n; }
119     
120     ScheduledAction* action() const { return m_action; }
121     ScheduledAction* takeAction() { ScheduledAction* a = m_action; m_action = 0; return a; }
122
123 private:
124     virtual void fired();
125
126     int m_timeoutId;
127     int m_nestingLevel;
128     Window* m_object;
129     ScheduledAction* m_action;
130 };
131
132 class PausedTimeout {
133 public:
134     int timeoutId;
135     int nestingLevel;
136     double nextFireInterval;
137     double repeatInterval;
138     ScheduledAction *action;
139 };
140
141 } // namespace KJS
142
143 #include "kjs_window.lut.h"
144
145 namespace KJS {
146
147 ////////////////////// Window Object ////////////////////////
148
149 const ClassInfo Window::info = { "Window", 0, &WindowTable };
150
151 /*
152 @begin WindowTable 118
153 # Warning, when adding a function to this object you need to add a case in Window::get
154 # -- Functions --
155   atob                  &WindowProtoFuncAToB::create                DontDelete|Function 1
156   btoa                  &WindowProtoFuncBToA::create                DontDelete|Function 1
157   scroll                &WindowProtoFuncScrollTo::create            DontDelete|Function 2
158   scrollBy              &WindowProtoFuncScrollBy::create            DontDelete|Function 2
159   scrollTo              &WindowProtoFuncScrollTo::create            DontDelete|Function 2
160   moveBy                &WindowProtoFuncMoveBy::create              DontDelete|Function 2
161   moveTo                &WindowProtoFuncMoveTo::create              DontDelete|Function 2
162   resizeBy              &WindowProtoFuncResizeBy::create            DontDelete|Function 2
163   resizeTo              &WindowProtoFuncResizeTo::create            DontDelete|Function 2
164   open                  &WindowProtoFuncOpen::create                DontDelete|Function 3
165   setTimeout            &WindowProtoFuncSetTimeout::create          DontDelete|Function 2
166   clearTimeout          &WindowProtoFuncClearTimeout::create        DontDelete|Function 1
167   setInterval           &WindowProtoFuncSetInterval::create         DontDelete|Function 2
168   clearInterval         &WindowProtoFuncClearTimeout::create        DontDelete|Function 1
169   addEventListener      &WindowProtoFuncAddEventListener::create    DontDelete|Function 3
170   removeEventListener   &WindowProtoFuncRemoveEventListener::create DontDelete|Function 3
171   showModalDialog       &WindowProtoFuncShowModalDialog::create     DontDelete|Function 1
172 # Not implemented
173   captureEvents         &WindowProtoFuncNotImplemented::create      DontDelete|Function 0
174   releaseEvents         &WindowProtoFuncNotImplemented::create      DontDelete|Function 0
175
176 # -- Attributes --
177   crypto                Window::Crypto              DontDelete|ReadOnly
178   event                 Window::Event_              DontDelete
179   location              Window::Location_           DontDelete
180   navigator             Window::Navigator_          DontDelete|ReadOnly
181   clientInformation     Window::ClientInformation   DontDelete|ReadOnly
182 # -- Event Listeners --
183   onabort               Window::Onabort             DontDelete
184   onblur                Window::Onblur              DontDelete
185   onchange              Window::Onchange            DontDelete
186   onclick               Window::Onclick             DontDelete
187   ondblclick            Window::Ondblclick          DontDelete
188   onerror               Window::Onerror             DontDelete
189   onfocus               Window::Onfocus             DontDelete
190   onkeydown             Window::Onkeydown           DontDelete
191   onkeypress            Window::Onkeypress          DontDelete
192   onkeyup               Window::Onkeyup             DontDelete
193   onload                Window::Onload              DontDelete
194   onmousedown           Window::Onmousedown         DontDelete
195   onmousemove           Window::Onmousemove         DontDelete
196   onmouseout            Window::Onmouseout          DontDelete
197   onmouseover           Window::Onmouseover         DontDelete
198   onmouseup             Window::Onmouseup           DontDelete
199   onmousewheel          Window::OnWindowMouseWheel  DontDelete
200   onreset               Window::Onreset             DontDelete
201   onresize              Window::Onresize            DontDelete
202   onscroll              Window::Onscroll            DontDelete
203   onsearch              Window::Onsearch            DontDelete
204   onselect              Window::Onselect            DontDelete
205   onsubmit              Window::Onsubmit            DontDelete
206   onunload              Window::Onunload            DontDelete
207   onbeforeunload        Window::Onbeforeunload      DontDelete
208 # -- Constructors --
209   Audio                 Window::Audio               DontDelete
210   DOMException          Window::DOMException        DontDelete
211   Image                 Window::Image               DontDelete
212   Option                Window::Option              DontDelete
213   XMLHttpRequest        Window::XMLHttpRequest      DontDelete
214   XSLTProcessor         Window::XSLTProcessor_      DontDelete
215 @end
216 */
217
218 Window::Window(DOMWindow* window)
219   : m_impl(window)
220   , d(new WindowPrivate)
221 {
222     // Window destruction is not thread-safe because of
223     // the non-thread-safe WebCore structures it references.
224     Collector::collectOnMainThreadOnly(this);
225 }
226
227 Window::~Window()
228 {
229     clearAllTimeouts();
230
231     // Clear any backpointers to the window
232
233     ListenersMap::iterator i2 = d->jsEventListeners.begin();
234     ListenersMap::iterator e2 = d->jsEventListeners.end();
235     for (; i2 != e2; ++i2)
236         i2->second->clearWindowObj();
237     i2 = d->jsHTMLEventListeners.begin();
238     e2 = d->jsHTMLEventListeners.end();
239     for (; i2 != e2; ++i2)
240         i2->second->clearWindowObj();
241
242     UnprotectedListenersMap::iterator i1 = d->jsUnprotectedEventListeners.begin();
243     UnprotectedListenersMap::iterator e1 = d->jsUnprotectedEventListeners.end();
244     for (; i1 != e1; ++i1)
245         i1->second->clearWindowObj();
246     i1 = d->jsUnprotectedHTMLEventListeners.begin();
247     e1 = d->jsUnprotectedHTMLEventListeners.end();
248     for (; i1 != e1; ++i1)
249         i1->second->clearWindowObj();
250 }
251
252 ScriptInterpreter* Window::interpreter() const
253 {
254     Frame* frame = impl()->frame();
255     if (!frame)
256         return 0;
257
258     return frame->scriptProxy()->interpreter();
259 }
260
261 Window *Window::retrieveWindow(Frame *f)
262 {
263     JSObject *o = retrieve(f)->getObject();
264
265     ASSERT(o || !f->settings() || !f->settings()->isJavaScriptEnabled());
266     return static_cast<Window *>(o);
267 }
268
269 Window *Window::retrieveActive(ExecState *exec)
270 {
271     JSValue *imp = exec->dynamicInterpreter()->globalObject();
272     ASSERT(imp);
273     return static_cast<Window*>(imp);
274 }
275
276 JSValue *Window::retrieve(Frame *p)
277 {
278     ASSERT(p);
279     if (KJSProxy *proxy = p->scriptProxy())
280         return proxy->interpreter()->globalObject(); // the Global object is the "window"
281   
282     return jsUndefined(); // This can happen with JS disabled on the domain of that window
283 }
284
285 Location *Window::location() const
286 {
287   if (!d->loc)
288     d->loc = new Location(impl()->frame());
289   return d->loc;
290 }
291
292 // reference our special objects during garbage collection
293 void Window::mark()
294 {
295   JSObject::mark();
296   if (d->loc && !d->loc->marked())
297     d->loc->mark();
298 }
299
300 static bool allowPopUp(ExecState *exec, Window *window)
301 {
302     Frame* frame = window->impl()->frame();
303     if (!frame)
304         return false;
305     if (static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->wasRunByUserGesture())
306         return true;
307     Settings* settings = frame->settings();
308     return settings && settings->JavaScriptCanOpenWindowsAutomatically();
309 }
310
311 static HashMap<String, String> parseModalDialogFeatures(ExecState *exec, JSValue *featuresArg)
312 {
313     HashMap<String, String> map;
314
315     Vector<String> features = valueToStringWithUndefinedOrNullCheck(exec, featuresArg).split(';');
316     Vector<String>::const_iterator end = features.end();
317     for (Vector<String>::const_iterator it = features.begin(); it != end; ++it) {
318         String s = *it;
319         int pos = s.find('=');
320         int colonPos = s.find(':');
321         if (pos >= 0 && colonPos >= 0)
322             continue; // ignore any strings that have both = and :
323         if (pos < 0)
324             pos = colonPos;
325         if (pos < 0) {
326             // null string for value means key without value
327             map.set(s.stripWhiteSpace().lower(), String());
328         } else {
329             String key = s.left(pos).stripWhiteSpace().lower();
330             String val = s.substring(pos + 1).stripWhiteSpace().lower();
331             int spacePos = val.find(' ');
332             if (spacePos != -1)
333                 val = val.left(spacePos);
334             map.set(key, val);
335         }
336     }
337
338     return map;
339 }
340
341 static bool boolFeature(const HashMap<String, String>& features, const char* key, bool defaultValue = false)
342 {
343     HashMap<String, String>::const_iterator it = features.find(key);
344     if (it == features.end())
345         return defaultValue;
346     const String& value = it->second;
347     return value.isNull() || value == "1" || value == "yes" || value == "on";
348 }
349
350 static float floatFeature(const HashMap<String, String> &features, const char *key, float min, float max, float defaultValue)
351 {
352     HashMap<String, String>::const_iterator it = features.find(key);
353     if (it == features.end())
354         return defaultValue;
355     // FIXME: Can't distinguish "0q" from string with no digits in it -- both return d == 0 and ok == false.
356     // Would be good to tell them apart somehow since string with no digits should be default value and
357     // "0q" should be minimum value.
358     bool ok;
359     double d = it->second.toDouble(&ok);
360     if ((d == 0 && !ok) || isnan(d))
361         return defaultValue;
362     if (d < min || max <= min)
363         return min;
364     if (d > max)
365         return max;
366     return static_cast<int>(d);
367 }
368
369 static Frame* createWindow(ExecState* exec, Frame* openerFrame, const String& url,
370     const String& frameName, const WindowFeatures& windowFeatures, JSValue* dialogArgs)
371 {
372     Frame* activeFrame = Window::retrieveActive(exec)->impl()->frame();
373     
374     ResourceRequest request;
375     if (activeFrame)
376         request.setHTTPReferrer(activeFrame->loader()->outgoingReferrer());
377     FrameLoadRequest frameRequest(request, frameName);
378
379     // FIXME: It's much better for client API if a new window starts with a URL, here where we
380     // know what URL we are going to open. Unfortunately, this code passes the empty string
381     // for the URL, but there's a reason for that. Before loading we have to set up the opener,
382     // openedByDOM, and dialogArguments values. Also, to decide whether to use the URL we currently
383     // do an isSafeScript call using the window we create, which can't be done before creating it.
384     // We'd have to resolve all those issues to pass the URL instead of "".
385
386     bool created;
387     Frame* newFrame = openerFrame->loader()->createWindow(frameRequest, windowFeatures, created);
388     if (!newFrame)
389         return 0;
390
391     newFrame->loader()->setOpener(openerFrame);
392     newFrame->loader()->setOpenedByDOM();
393
394     Window* newWindow = Window::retrieveWindow(newFrame);    
395     
396     if (dialogArgs)
397         newWindow->putDirect("dialogArguments", dialogArgs);
398
399     if (!url.startsWith("javascript:", false) || newWindow->isSafeScript(exec)) {
400         String completedURL = url.isEmpty() ? url : activeFrame->document()->completeURL(url);
401         bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
402         
403         if (created) {
404             newFrame->loader()->changeLocation(KURL(completedURL.deprecatedString()), activeFrame->loader()->outgoingReferrer(), false, userGesture);
405             if (Document* oldDoc = openerFrame->document()) {
406                 newFrame->document()->setDomainInternal(oldDoc->domain());
407                 newFrame->document()->setBaseURL(oldDoc->baseURL());
408             }
409         } else if (!url.isEmpty())
410             newFrame->loader()->scheduleLocationChange(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture);
411     }
412     
413     return newFrame;
414 }
415
416 static bool canShowModalDialog(const Window *window)
417 {
418     Frame* frame = window->impl()->frame();
419     if (!frame)
420         return false;
421
422     return frame->page()->chrome()->canRunModal();
423 }
424
425 static bool canShowModalDialogNow(const Window *window)
426 {
427     Frame* frame = window->impl()->frame();
428     if (!frame)
429         return false;
430
431     return frame->page()->chrome()->canRunModalNow();
432 }
433
434 static JSValue* showModalDialog(ExecState* exec, Window* openerWindow, const List& args)
435 {
436     if (!canShowModalDialogNow(openerWindow) || !allowPopUp(exec, openerWindow))
437         return jsUndefined();
438
439     const HashMap<String, String> features = parseModalDialogFeatures(exec, args[2]);
440
441     bool trusted = false;
442
443     WindowFeatures wargs;
444
445     // The following features from Microsoft's documentation are not implemented:
446     // - default font settings
447     // - width, height, left, and top specified in units other than "px"
448     // - edge (sunken or raised, default is raised)
449     // - dialogHide: trusted && boolFeature(features, "dialoghide"), makes dialog hide when you print
450     // - help: boolFeature(features, "help", true), makes help icon appear in dialog (what does it do on Windows?)
451     // - unadorned: trusted && boolFeature(features, "unadorned");
452     Frame* frame = openerWindow->impl()->frame();
453     if (!frame)
454         return jsUndefined();
455
456     FloatRect screenRect = screenAvailableRect(frame->view());
457
458     wargs.width = floatFeature(features, "dialogwidth", 100, screenRect.width(), 620); // default here came from frame size of dialog in MacIE
459     wargs.widthSet = true;
460     wargs.height = floatFeature(features, "dialogheight", 100, screenRect.height(), 450); // default here came from frame size of dialog in MacIE
461     wargs.heightSet = true;
462
463     wargs.x = floatFeature(features, "dialogleft", screenRect.x(), screenRect.right() - wargs.width, -1);
464     wargs.xSet = wargs.x > 0;
465     wargs.y = floatFeature(features, "dialogtop", screenRect.y(), screenRect.bottom() - wargs.height, -1);
466     wargs.ySet = wargs.y > 0;
467
468     if (boolFeature(features, "center", true)) {
469         if (!wargs.xSet) {
470             wargs.x = screenRect.x() + (screenRect.width() - wargs.width) / 2;
471             wargs.xSet = true;
472         }
473         if (!wargs.ySet) {
474             wargs.y = screenRect.y() + (screenRect.height() - wargs.height) / 2;
475             wargs.ySet = true;
476         }
477     }
478
479     wargs.dialog = true;
480     wargs.resizable = boolFeature(features, "resizable");
481     wargs.scrollbarsVisible = boolFeature(features, "scroll", true);
482     wargs.statusBarVisible = boolFeature(features, "status", !trusted);
483     wargs.menuBarVisible = false;
484     wargs.toolBarVisible = false;
485     wargs.locationBarVisible = false;
486     wargs.fullscreen = false;
487     
488     Frame* dialogFrame = createWindow(exec, frame, valueToStringWithUndefinedOrNullCheck(exec, args[0]), "", wargs, args[1]);
489     if (!dialogFrame)
490         return jsUndefined();
491
492     Window* dialogWindow = Window::retrieveWindow(dialogFrame);
493
494     // Get the return value either just before clearing the dialog window's
495     // properties (in Window::clear), or when on return from runModal.
496     JSValue* returnValue = 0;
497     dialogWindow->setReturnValueSlot(&returnValue);
498     dialogFrame->page()->chrome()->runModal();
499     dialogWindow->setReturnValueSlot(0);
500
501     // If we don't have a return value, get it now.
502     // Either Window::clear was not called yet, or there was no return value,
503     // and in that case, there's no harm in trying again (no benefit either).
504     if (!returnValue)
505         returnValue = dialogWindow->getDirect("returnValue");
506
507     return returnValue ? returnValue : jsUndefined();
508 }
509
510 JSValue *Window::getValueProperty(ExecState *exec, int token) const
511 {
512    ASSERT(impl()->frame());
513
514    switch (token) {
515    case Crypto:
516       if (!isSafeScript(exec))
517         return jsUndefined();
518       return jsUndefined(); // FIXME: implement this
519    case DOMException:
520       if (!isSafeScript(exec))
521         return jsUndefined();
522       return getDOMExceptionConstructor(exec);
523     case Event_:
524       if (!isSafeScript(exec))
525         return jsUndefined();
526       if (!d->m_evt)
527         return jsUndefined();
528       return toJS(exec, d->m_evt);
529     case Location_:
530       return location();
531     case Navigator_:
532     case ClientInformation: {
533       if (!isSafeScript(exec))
534         return jsUndefined();
535       // Store the navigator in the object so we get the same one each time.
536       Navigator *n = new Navigator(exec, impl()->frame());
537       // FIXME: this will make the "navigator" object accessible from windows that fail
538       // the security check the first time, but not subsequent times, seems weird.
539       const_cast<Window *>(this)->putDirect("navigator", n, DontDelete|ReadOnly);
540       const_cast<Window *>(this)->putDirect("clientInformation", n, DontDelete|ReadOnly);
541       return n;
542     }
543     case Image:
544       if (!isSafeScript(exec))
545         return jsUndefined();
546       // FIXME: this property (and the few below) probably shouldn't create a new object every
547       // time
548       return new ImageConstructorImp(exec, impl()->frame()->document());
549     case Option:
550       if (!isSafeScript(exec))
551         return jsUndefined();
552       return new JSHTMLOptionElementConstructor(exec, impl()->frame()->document());
553     case XMLHttpRequest:
554       if (!isSafeScript(exec))
555         return jsUndefined();
556       return new JSXMLHttpRequestConstructorImp(exec, impl()->frame()->document());
557     case Audio:
558 #if ENABLE(VIDEO)
559       return new JSHTMLAudioElementConstructor(exec, impl()->frame()->document());
560 #else
561       return jsUndefined();
562 #endif
563 #if ENABLE(XSLT)
564     case XSLTProcessor_:
565       if (!isSafeScript(exec))
566         return jsUndefined();
567       return new XSLTProcessorConstructorImp(exec);
568 #else
569     case XSLTProcessor_:
570       return jsUndefined();
571 #endif
572    }
573
574    if (!isSafeScript(exec))
575      return jsUndefined();
576
577    switch (token) {
578    case Onabort:
579      return getListener(exec, abortEvent);
580    case Onblur:
581      return getListener(exec, blurEvent);
582    case Onchange:
583      return getListener(exec, changeEvent);
584    case Onclick:
585      return getListener(exec, clickEvent);
586    case Ondblclick:
587      return getListener(exec, dblclickEvent);
588    case Onerror:
589      return getListener(exec, errorEvent);
590    case Onfocus:
591      return getListener(exec, focusEvent);
592    case Onkeydown:
593      return getListener(exec, keydownEvent);
594    case Onkeypress:
595      return getListener(exec, keypressEvent);
596    case Onkeyup:
597      return getListener(exec, keyupEvent);
598    case Onload:
599      return getListener(exec, loadEvent);
600    case Onmousedown:
601      return getListener(exec, mousedownEvent);
602    case Onmousemove:
603      return getListener(exec, mousemoveEvent);
604    case Onmouseout:
605      return getListener(exec, mouseoutEvent);
606    case Onmouseover:
607      return getListener(exec, mouseoverEvent);
608    case Onmouseup:
609      return getListener(exec, mouseupEvent);
610    case OnWindowMouseWheel:
611      return getListener(exec, mousewheelEvent);
612    case Onreset:
613      return getListener(exec, resetEvent);
614    case Onresize:
615      return getListener(exec,resizeEvent);
616    case Onscroll:
617      return getListener(exec,scrollEvent);
618    case Onsearch:
619      return getListener(exec,searchEvent);
620    case Onselect:
621      return getListener(exec,selectEvent);
622    case Onsubmit:
623      return getListener(exec,submitEvent);
624    case Onbeforeunload:
625       return getListener(exec, beforeunloadEvent);
626     case Onunload:
627      return getListener(exec, unloadEvent);
628    }
629    ASSERT(0);
630    return jsUndefined();
631 }
632
633 JSValue* Window::childFrameGetter(ExecState*, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
634 {
635     return retrieve(static_cast<Window*>(slot.slotBase())->impl()->frame()->tree()->child(AtomicString(propertyName)));
636 }
637
638 JSValue* Window::indexGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
639 {
640     return retrieve(static_cast<Window*>(slot.slotBase())->impl()->frame()->tree()->child(slot.index()));
641 }
642
643 JSValue *Window::namedItemGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
644 {
645   Window *thisObj = static_cast<Window *>(slot.slotBase());
646   Document *doc = thisObj->impl()->frame()->document();
647   ASSERT(thisObj->isSafeScript(exec) && doc && doc->isHTMLDocument());
648
649   String name = propertyName;
650   RefPtr<WebCore::HTMLCollection> collection = doc->windowNamedItems(name);
651   if (collection->length() == 1)
652     return toJS(exec, collection->firstItem());
653   return toJS(exec, collection.get());
654 }
655
656 bool Window::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
657 {
658   // Check for child frames by name before built-in properties to
659   // match Mozilla. This does not match IE, but some sites end up
660   // naming frames things that conflict with window properties that
661   // are in Moz but not IE. Since we have some of these, we have to do
662   // it the Moz way.
663   if (impl()->frame()->tree()->child(propertyName)) {
664     slot.setCustom(this, childFrameGetter);
665     return true;
666   }
667
668   const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName);
669   if (entry) {
670     if (entry->attr & Function) {
671       if (entry->value.functionValue == &WindowProtoFuncShowModalDialog::create) {
672         if (!canShowModalDialog(this))
673           return false;
674       }
675       if (isSafeScript(exec))
676         slot.setStaticEntry(this, entry, staticFunctionGetter);
677       else
678         slot.setUndefined(this);
679     } else
680       slot.setStaticEntry(this, entry, staticValueGetter<Window>);
681     return true;
682   }
683
684   // FIXME: Search the whole frame hierachy somewhere around here.
685   // We need to test the correct priority order.
686   
687   // allow window[1] or parent[1] etc. (#56983)
688   bool ok;
689   unsigned i = propertyName.toArrayIndex(&ok);
690   if (ok && i < impl()->frame()->tree()->childCount()) {
691     slot.setCustomIndex(this, i, indexGetter);
692     return true;
693   }
694
695   // allow shortcuts like 'Image1' instead of document.images.Image1
696   Document* doc = impl()->frame()->document();
697   if (doc && doc->isHTMLDocument()) {
698     if (!isSafeScript(exec)) {
699       slot.setUndefined(this);
700       return true;
701     }
702
703     AtomicString atomicPropertyName = propertyName;
704     if (static_cast<HTMLDocument*>(doc)->hasNamedItem(atomicPropertyName) || doc->getElementById(atomicPropertyName)) {
705       slot.setCustom(this, namedItemGetter);
706       return true;
707     }
708   }
709
710   if (!isSafeScript(exec)) {
711     slot.setUndefined(this);
712     return true;
713   }
714
715   return JSObject::getOwnPropertySlot(exec, propertyName, slot);
716 }
717
718 void Window::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
719 {
720   const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName);
721   if (entry) {
722      if (entry->attr & Function) {
723        if (isSafeScript(exec))
724          JSObject::put(exec, propertyName, value, attr);
725        return;
726     }
727     if (entry->attr & ReadOnly)
728       return;
729
730     switch (entry->value.intValue) {
731     case Location_: {
732       Frame* p = Window::retrieveActive(exec)->impl()->frame();
733       if (p) {
734         if (!p->loader()->shouldAllowNavigation(impl()->frame()))
735           return;
736         DeprecatedString dstUrl = p->loader()->completeURL(DeprecatedString(value->toString(exec))).url();
737         if (!dstUrl.startsWith("javascript:", false) || isSafeScript(exec)) {
738           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
739           // We want a new history item if this JS was called via a user gesture
740           impl()->frame()->loader()->scheduleLocationChange(dstUrl, p->loader()->outgoingReferrer(), false, userGesture);
741         }
742       }
743       return;
744     }
745     case Onabort:
746       if (isSafeScript(exec))
747         setListener(exec, abortEvent,value);
748       return;
749     case Onblur:
750       if (isSafeScript(exec))
751         setListener(exec, blurEvent,value);
752       return;
753     case Onchange:
754       if (isSafeScript(exec))
755         setListener(exec, changeEvent,value);
756       return;
757     case Onclick:
758       if (isSafeScript(exec))
759         setListener(exec,clickEvent,value);
760       return;
761     case Ondblclick:
762       if (isSafeScript(exec))
763         setListener(exec, dblclickEvent,value);
764       return;
765     case Onerror:
766       if (isSafeScript(exec))
767         setListener(exec, errorEvent, value);
768       return;
769     case Onfocus:
770       if (isSafeScript(exec))
771         setListener(exec,focusEvent,value);
772       return;
773     case Onkeydown:
774       if (isSafeScript(exec))
775         setListener(exec,keydownEvent,value);
776       return;
777     case Onkeypress:
778       if (isSafeScript(exec))
779         setListener(exec,keypressEvent,value);
780       return;
781     case Onkeyup:
782       if (isSafeScript(exec))
783         setListener(exec,keyupEvent,value);
784       return;
785     case Onload:
786       if (isSafeScript(exec))
787         setListener(exec,loadEvent,value);
788       return;
789     case Onmousedown:
790       if (isSafeScript(exec))
791         setListener(exec,mousedownEvent,value);
792       return;
793     case Onmousemove:
794       if (isSafeScript(exec))
795         setListener(exec,mousemoveEvent,value);
796       return;
797     case Onmouseout:
798       if (isSafeScript(exec))
799         setListener(exec,mouseoutEvent,value);
800       return;
801     case Onmouseover:
802       if (isSafeScript(exec))
803         setListener(exec,mouseoverEvent,value);
804       return;
805     case Onmouseup:
806       if (isSafeScript(exec))
807         setListener(exec,mouseupEvent,value);
808       return;
809     case OnWindowMouseWheel:
810       if (isSafeScript(exec))
811         setListener(exec, mousewheelEvent,value);
812       return;
813     case Onreset:
814       if (isSafeScript(exec))
815         setListener(exec,resetEvent,value);
816       return;
817     case Onresize:
818       if (isSafeScript(exec))
819         setListener(exec,resizeEvent,value);
820       return;
821     case Onscroll:
822       if (isSafeScript(exec))
823         setListener(exec,scrollEvent,value);
824       return;
825     case Onsearch:
826         if (isSafeScript(exec))
827             setListener(exec,searchEvent,value);
828         return;
829     case Onselect:
830       if (isSafeScript(exec))
831         setListener(exec,selectEvent,value);
832       return;
833     case Onsubmit:
834       if (isSafeScript(exec))
835         setListener(exec,submitEvent,value);
836       return;
837     case Onbeforeunload:
838       if (isSafeScript(exec))
839         setListener(exec, beforeunloadEvent, value);
840       return;
841     case Onunload:
842       if (isSafeScript(exec))
843         setListener(exec, unloadEvent, value);
844       return;
845     default:
846       break;
847     }
848   }
849   if (isSafeScript(exec))
850     JSObject::put(exec, propertyName, value, attr);
851 }
852
853 static bool shouldLoadAsEmptyDocument(const KURL &url)
854 {
855   return url.protocol().lower() == "about" || url.isEmpty();
856 }
857
858 bool Window::isSafeScript(const ScriptInterpreter *origin, const ScriptInterpreter *target)
859 {
860     if (origin == target)
861         return true;
862         
863     Frame* originFrame = origin->frame();
864     Frame* targetFrame = target->frame();
865
866     // JS may be attempting to access the "window" object, which should be valid,
867     // even if the document hasn't been constructed yet.  If the document doesn't
868     // exist yet allow JS to access the window object.
869     if (!targetFrame->document())
870         return true;
871
872     WebCore::Document *originDocument = originFrame->document();
873     WebCore::Document *targetDocument = targetFrame->document();
874
875     if (!targetDocument) {
876         return false;
877     }
878
879     WebCore::String targetDomain = targetDocument->domain();
880
881     // Always allow local pages to execute any JS.
882     if (targetDomain.isNull())
883         return true;
884
885     WebCore::String originDomain = originDocument->domain();
886
887     // if this document is being initially loaded as empty by its parent
888     // or opener, allow access from any document in the same domain as
889     // the parent or opener.
890     if (shouldLoadAsEmptyDocument(targetFrame->loader()->url())) {
891         Frame* ancestorFrame = targetFrame->loader()->opener() ? targetFrame->loader()->opener() : targetFrame->tree()->parent();
892         while (ancestorFrame && shouldLoadAsEmptyDocument(ancestorFrame->loader()->url()))
893             ancestorFrame = ancestorFrame->tree()->parent();
894         if (ancestorFrame)
895             originDomain = ancestorFrame->document()->domain();
896     }
897
898     if (targetDomain == originDomain)
899         return true;
900
901     if (!originFrame->settings()->privateBrowsingEnabled()) {
902         if (Interpreter::shouldPrintExceptions())
903             printf("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
904                    targetDocument->URL().latin1(), originDocument->URL().latin1());
905         String message = String::format("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
906                                         targetDocument->URL().latin1(), originDocument->URL().latin1());
907         if (Page* page = targetFrame->page())
908             page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, 1, String()); // FIXME: provide a real line number and source URL.
909     }
910
911     return false;
912 }
913
914 bool Window::isSafeScript(ExecState *exec) const
915 {
916   Frame* frame = impl()->frame();
917   if (!frame)
918     return false;
919   Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame();
920   if (!activeFrame)
921     return false;
922   if (activeFrame == frame)
923     return true;
924
925   WebCore::Document* thisDocument = frame->document();
926
927   // JS may be attempting to access the "window" object, which should be valid,
928   // even if the document hasn't been constructed yet.  If the document doesn't
929   // exist yet allow JS to access the window object.
930   if (!thisDocument)
931       return true;
932
933   WebCore::Document* actDocument = activeFrame->document();
934
935   const SecurityOrigin& actSecurityOrigin = actDocument->securityOrigin();
936   const SecurityOrigin& thisSecurityOrigin = thisDocument->securityOrigin();
937
938   if (actSecurityOrigin.canAccess(thisSecurityOrigin))
939     return true;
940
941     if (!frame->settings()->privateBrowsingEnabled()) {
942         // FIXME: this error message should contain more specifics of why the same origin check has failed.
943         String message = String::format("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains, protocols and ports must match.\n",
944                                         thisDocument->URL().utf8().data(), actDocument->URL().utf8().data());
945         
946         if (Interpreter::shouldPrintExceptions())
947             printf("%s", message.utf8().data());
948         
949         if (Page* page = frame->page())
950             page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, 1, String());
951     }
952
953   return false;
954 }
955
956 void Window::setListener(ExecState *exec, const AtomicString &eventType, JSValue *func)
957 {
958   if (!isSafeScript(exec))
959     return;
960   Frame* frame = impl()->frame();
961   if (!frame)
962     return;
963   Document* doc = frame->document();
964   if (!doc)
965     return;
966
967   doc->setHTMLWindowEventListener(eventType, findOrCreateJSEventListener(func,true));
968 }
969
970 JSValue *Window::getListener(ExecState *exec, const AtomicString &eventType) const
971 {
972   if (!isSafeScript(exec))
973     return jsUndefined();
974   Frame* frame = impl()->frame();
975   if (!frame)
976     return jsUndefined();
977   Document* doc = frame->document();
978   if (!doc)
979     return jsUndefined();
980
981   WebCore::EventListener *listener = doc->getHTMLWindowEventListener(eventType);
982   if (listener && static_cast<JSEventListener*>(listener)->listenerObj())
983     return static_cast<JSEventListener*>(listener)->listenerObj();
984   else
985     return jsNull();
986 }
987
988 JSEventListener* Window::findJSEventListener(JSValue* val, bool html)
989 {
990     if (!val->isObject())
991         return 0;
992     JSObject* object = static_cast<JSObject*>(val);
993     ListenersMap& listeners = html ? d->jsHTMLEventListeners : d->jsEventListeners;
994     return listeners.get(object);
995 }
996
997 JSEventListener *Window::findOrCreateJSEventListener(JSValue *val, bool html)
998 {
999   JSEventListener *listener = findJSEventListener(val, html);
1000   if (listener)
1001     return listener;
1002
1003   if (!val->isObject())
1004     return 0;
1005   JSObject *object = static_cast<JSObject *>(val);
1006
1007   // Note that the JSEventListener constructor adds it to our jsEventListeners list
1008   return new JSEventListener(object, this, html);
1009 }
1010
1011 JSUnprotectedEventListener* Window::findJSUnprotectedEventListener(JSValue* val, bool html)
1012 {
1013     if (!val->isObject())
1014         return 0;
1015     JSObject* object = static_cast<JSObject*>(val);
1016     UnprotectedListenersMap& listeners = html ? d->jsUnprotectedHTMLEventListeners : d->jsUnprotectedEventListeners;
1017     return listeners.get(object);
1018 }
1019
1020 JSUnprotectedEventListener *Window::findOrCreateJSUnprotectedEventListener(JSValue *val, bool html)
1021 {
1022   JSUnprotectedEventListener *listener = findJSUnprotectedEventListener(val, html);
1023   if (listener)
1024     return listener;
1025
1026   if (!val->isObject())
1027     return 0;
1028   JSObject *object = static_cast<JSObject *>(val);
1029
1030   // The JSUnprotectedEventListener constructor adds it to our jsUnprotectedEventListeners map.
1031   return new JSUnprotectedEventListener(object, this, html);
1032 }
1033
1034 void Window::clearHelperObjectProperties()
1035 {
1036   d->loc = 0;
1037   d->m_evt = 0;
1038 }
1039
1040 void Window::clear()
1041 {
1042   JSLock lock;
1043
1044   if (d->m_returnValueSlot && !*d->m_returnValueSlot)
1045     *d->m_returnValueSlot = getDirect("returnValue");
1046
1047   clearAllTimeouts();
1048   clearProperties();
1049   clearHelperObjectProperties();
1050   setPrototype(JSDOMWindowPrototype::self()); // clear the prototype
1051
1052   // Now recreate a working global object for the next URL that will use us; but only if we haven't been
1053   // disconnected yet
1054   if (Frame* frame = impl()->frame())
1055     frame->scriptProxy()->interpreter()->resetGlobalObjectProperties();
1056
1057   // there's likely to be lots of garbage now
1058   gcController().garbageCollectSoon();
1059 }
1060
1061 void Window::setCurrentEvent(Event *evt)
1062 {
1063   d->m_evt = evt;
1064 }
1065
1066 static void setWindowFeature(const String& keyString, const String& valueString, WindowFeatures& windowFeatures)
1067 {
1068     int value;
1069     
1070     if (valueString.length() == 0 || // listing a key with no value is shorthand for key=yes
1071         valueString == "yes")
1072         value = 1;
1073     else
1074         value = valueString.toInt();
1075     
1076     if (keyString == "left" || keyString == "screenx") {
1077         windowFeatures.xSet = true;
1078         windowFeatures.x = value;
1079     } else if (keyString == "top" || keyString == "screeny") {
1080         windowFeatures.ySet = true;
1081         windowFeatures.y = value;
1082     } else if (keyString == "width" || keyString == "innerwidth") {
1083         windowFeatures.widthSet = true;
1084         windowFeatures.width = value;
1085     } else if (keyString == "height" || keyString == "innerheight") {
1086         windowFeatures.heightSet = true;
1087         windowFeatures.height = value;
1088     } else if (keyString == "menubar")
1089         windowFeatures.menuBarVisible = value;
1090     else if (keyString == "toolbar")
1091         windowFeatures.toolBarVisible = value;
1092     else if (keyString == "location")
1093         windowFeatures.locationBarVisible = value;
1094     else if (keyString == "status")
1095         windowFeatures.statusBarVisible = value;
1096     else if (keyString == "resizable")
1097         windowFeatures.resizable = value;
1098     else if (keyString == "fullscreen")
1099         windowFeatures.fullscreen = value;
1100     else if (keyString == "scrollbars")
1101         windowFeatures.scrollbarsVisible = value;
1102 }
1103
1104 // Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
1105 static bool isSeparator(::UChar c)
1106 {
1107     return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0';
1108 }
1109
1110 static void parseWindowFeatures(const String& features, WindowFeatures& windowFeatures)
1111 {
1112     /*
1113      The IE rule is: all features except for channelmode and fullscreen default to YES, but
1114      if the user specifies a feature string, all features default to NO. (There is no public
1115      standard that applies to this method.)
1116      
1117      <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
1118      */
1119     
1120     windowFeatures.dialog = false;
1121     windowFeatures.fullscreen = false;
1122     
1123     windowFeatures.xSet = false;
1124     windowFeatures.ySet = false;
1125     windowFeatures.widthSet = false;
1126     windowFeatures.heightSet = false;
1127     
1128     if (features.length() == 0) {
1129         windowFeatures.menuBarVisible = true;
1130         windowFeatures.statusBarVisible = true;
1131         windowFeatures.toolBarVisible = true;
1132         windowFeatures.locationBarVisible = true;
1133         windowFeatures.scrollbarsVisible = true;
1134         windowFeatures.resizable = true;
1135         
1136         return;
1137     }
1138     
1139     windowFeatures.menuBarVisible = false;
1140     windowFeatures.statusBarVisible = false;
1141     windowFeatures.toolBarVisible = false;
1142     windowFeatures.locationBarVisible = false;
1143     windowFeatures.scrollbarsVisible = false;
1144     windowFeatures.resizable = false;
1145     
1146     // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
1147     int keyBegin, keyEnd;
1148     int valueBegin, valueEnd;
1149     
1150     int i = 0;
1151     int length = features.length();
1152     String buffer = features.lower();
1153     while (i < length) {
1154         // skip to first non-separator, but don't skip past the end of the string
1155         while (isSeparator(buffer[i])) {
1156             if (i >= length)
1157                 break;
1158             i++;
1159         }
1160         keyBegin = i;
1161         
1162         // skip to first separator
1163         while (!isSeparator(buffer[i]))
1164             i++;
1165         keyEnd = i;
1166         
1167         // skip to first '=', but don't skip past a ',' or the end of the string
1168         while (buffer[i] != '=') {
1169             if (buffer[i] == ',' || i >= length)
1170                 break;
1171             i++;
1172         }
1173         
1174         // skip to first non-separator, but don't skip past a ',' or the end of the string
1175         while (isSeparator(buffer[i])) {
1176             if (buffer[i] == ',' || i >= length)
1177                 break;
1178             i++;
1179         }
1180         valueBegin = i;
1181         
1182         // skip to first separator
1183         while (!isSeparator(buffer[i]))
1184             i++;
1185         valueEnd = i;
1186         
1187         ASSERT(i <= length);
1188
1189         String keyString(buffer.substring(keyBegin, keyEnd - keyBegin));
1190         String valueString(buffer.substring(valueBegin, valueEnd - valueBegin));
1191         setWindowFeature(keyString, valueString, windowFeatures);
1192     }
1193 }
1194
1195 // Explain the 4 things this function does.
1196 // 1) Validates the pending changes are not changing to NaN
1197 // 2) Constrains the window rect to no smaller than 100 in each dimension and no
1198 //    bigger than the the float rect's dimensions.
1199 // 3) Constrain window rect to within the top and left boundaries of the screen rect
1200 // 4) Constraint the window rect to within the bottom and right boundaries of the
1201 //    screen rect.
1202 // 5) Translate the window rect coordinates to be within the coordinate space of
1203 //    the screen rect.
1204 static void adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges)
1205 {
1206     // Make sure we're in a valid state before adjusting dimensions
1207     ASSERT(!isnan(screen.x()) && !isnan(screen.y()) && !isnan(screen.width()) && !isnan(screen.height()) &&
1208            !isnan(window.x()) && !isnan(window.y()) && !isnan(window.width()) && !isnan(window.height()));
1209     
1210     // Update window values if they are not NaN
1211     if (!isnan(pendingChanges.x()))
1212         window.setX(pendingChanges.x());
1213     if (!isnan(pendingChanges.y()))
1214         window.setY(pendingChanges.y());
1215     if (!isnan(pendingChanges.width()))
1216         window.setWidth(pendingChanges.width());
1217     if (!isnan(pendingChanges.height()))
1218         window.setHeight(pendingChanges.height());
1219     
1220     // Resize the window to between 100 and the screen width and height if it's
1221     // outside of those ranges.
1222     window.setWidth(min(max(100.0f, window.width()), screen.width()));
1223     window.setHeight(min(max(100.0f, window.height()), screen.height()));
1224     
1225     // Constrain the window to the top and left of the screen if it's left or
1226     // above it.
1227     window.setX(max(window.x(), screen.x()));
1228     window.setY(max(window.y(), screen.y()));
1229
1230     // Constrain the window to the bottom and right of the screen if it's past
1231     // the right or below it.
1232     window.setX(window.x() - max(0.0f, window.right() - screen.width() - screen.x()));
1233     window.setY(window.y() - max(0.0f, window.bottom() - screen.height() - screen.y()));
1234 }
1235
1236 JSValue* WindowProtoFuncAToB::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1237 {
1238     if (!thisObj->inherits(&Window::info))
1239         return throwError(exec, TypeError);
1240     Window* window = static_cast<Window*>(thisObj);
1241     Frame* frame = window->impl()->frame();
1242     if (!frame)
1243         return jsUndefined();
1244
1245     JSValue* v = args[0];
1246     UString s = v->toString(exec);
1247
1248     if (args.size() < 1)
1249         return throwError(exec, SyntaxError, "Not enough arguments");
1250     if (v->isNull())
1251         return jsString();
1252     if (!s.is8Bit()) {
1253         setDOMException(exec, INVALID_CHARACTER_ERR);
1254         return jsUndefined();
1255     }
1256     
1257     Vector<char> in(s.size());
1258     for (int i = 0; i < s.size(); ++i)
1259         in[i] = static_cast<char>(s.data()[i].unicode());
1260     Vector<char> out;
1261
1262     if (!base64Decode(in, out))
1263         return throwError(exec, GeneralError, "Cannot decode base64");
1264     
1265     return jsString(String(out.data(), out.size()));
1266 }
1267
1268 JSValue* WindowProtoFuncBToA::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1269 {
1270     if (!thisObj->inherits(&Window::info))
1271         return throwError(exec, TypeError);
1272     Window* window = static_cast<Window*>(thisObj);
1273     Frame* frame = window->impl()->frame();
1274     if (!frame)
1275         return jsUndefined();
1276
1277     JSValue* v = args[0];
1278     UString s = v->toString(exec);
1279
1280     if (args.size() < 1)
1281         return throwError(exec, SyntaxError, "Not enough arguments");
1282     if (v->isNull())
1283         return jsString();
1284     if (!s.is8Bit()) {
1285         setDOMException(exec, INVALID_CHARACTER_ERR);
1286         return jsUndefined();
1287     }
1288     
1289     Vector<char> in(s.size());
1290     for (int i = 0; i < s.size(); ++i)
1291         in[i] = static_cast<char>(s.data()[i].unicode());
1292     Vector<char> out;
1293
1294     base64Encode(in, out);
1295     
1296     return jsString(String(out.data(), out.size()));
1297 }
1298
1299 JSValue* WindowProtoFuncOpen::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1300 {
1301     if (!thisObj->inherits(&Window::info))
1302         return throwError(exec, TypeError);
1303     Window* window = static_cast<Window*>(thisObj);
1304     Frame* frame = window->impl()->frame();
1305     if (!frame)
1306         return jsUndefined();
1307     Frame* activeFrame = Window::retrieveActive(exec)->impl()->frame();
1308     if (!activeFrame)
1309         return  jsUndefined();
1310
1311     Page* page = frame->page();
1312
1313     String urlString = valueToStringWithUndefinedOrNullCheck(exec, args[0]);
1314     AtomicString frameName = args[1]->isUndefinedOrNull() ? "_blank" : AtomicString(args[1]->toString(exec));
1315
1316     // Because FrameTree::find() returns true for empty strings, we must check for empty framenames.
1317     // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
1318     if (!allowPopUp(exec, window) && (frameName.isEmpty() || !frame->tree()->find(frameName)))
1319         return jsUndefined();
1320
1321     // Get the target frame for the special cases of _top and _parent.  In those 
1322     // cases, we can schedule a location change right now and return early.
1323     bool topOrParent = false;
1324     if (frameName == "_top") {
1325         frame = frame->tree()->top();
1326         topOrParent = true;
1327     } else if (frameName == "_parent") {
1328         if (Frame* parent = frame->tree()->parent())
1329             frame = parent;
1330         if (!activeFrame->loader()->shouldAllowNavigation(frame))
1331             return jsUndefined();
1332         topOrParent = true;
1333     }
1334     if (topOrParent) {
1335         String completedURL;
1336         if (!urlString.isEmpty())
1337             completedURL = activeFrame->document()->completeURL(urlString);
1338
1339         const Window* window = Window::retrieveWindow(frame);
1340         if (!completedURL.isEmpty() && (!completedURL.startsWith("javascript:", false) || (window && window->isSafeScript(exec)))) {
1341             bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1342             frame->loader()->scheduleLocationChange(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture);
1343         }
1344         return Window::retrieve(frame);
1345     }
1346     
1347     // In the case of a named frame or a new window, we'll use the createWindow() helper
1348     WindowFeatures windowFeatures;
1349     String features = valueToStringWithUndefinedOrNullCheck(exec, args[2]);
1350     parseWindowFeatures(features, windowFeatures);
1351     FloatRect windowRect(windowFeatures.x, windowFeatures.y, windowFeatures.width, windowFeatures.height);
1352     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), windowRect, windowRect);
1353
1354     windowFeatures.x = windowRect.x();
1355     windowFeatures.y = windowRect.y();
1356     windowFeatures.height = windowRect.height();
1357     windowFeatures.width = windowRect.width();
1358
1359     frame = createWindow(exec, frame, urlString, frameName, windowFeatures, 0);
1360
1361     if (!frame)
1362         return jsUndefined();
1363
1364     return Window::retrieve(frame); // global object
1365 }
1366
1367 JSValue* WindowProtoFuncScrollBy::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1368 {
1369     if (!thisObj->inherits(&Window::info))
1370         return throwError(exec, TypeError);
1371     Window* window = static_cast<Window*>(thisObj);
1372     Frame* frame = window->impl()->frame();
1373     if (!frame)
1374         return jsUndefined();
1375
1376     FrameView *widget = frame->view();
1377
1378     window->updateLayout();
1379     if(args.size() >= 2 && widget)
1380       widget->scrollBy(args[0]->toInt32(exec), args[1]->toInt32(exec));
1381     return jsUndefined();
1382 }
1383
1384 JSValue* WindowProtoFuncScrollTo::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1385 {
1386     // Also the implementation for window.scroll()
1387
1388     if (!thisObj->inherits(&Window::info))
1389         return throwError(exec, TypeError);
1390     Window* window = static_cast<Window*>(thisObj);
1391     Frame* frame = window->impl()->frame();
1392     if (!frame)
1393         return jsUndefined();
1394
1395     FrameView *widget = frame->view();
1396
1397     window->updateLayout();
1398     if (args.size() >= 2 && widget)
1399       widget->setContentsPos(args[0]->toInt32(exec), args[1]->toInt32(exec));
1400     return jsUndefined();
1401 }
1402
1403 JSValue* WindowProtoFuncMoveBy::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1404 {
1405     if (!thisObj->inherits(&Window::info))
1406         return throwError(exec, TypeError);
1407     Window* window = static_cast<Window*>(thisObj);
1408     Frame* frame = window->impl()->frame();
1409     if (!frame)
1410         return jsUndefined();
1411
1412     Page* page = frame->page();
1413
1414     if (args.size() >= 2 && page) {
1415       FloatRect fr = page->chrome()->windowRect();
1416       FloatRect update = fr;
1417       update.move(args[0]->toFloat(exec), args[1]->toFloat(exec));
1418       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1419       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1420       page->chrome()->setWindowRect(fr);
1421     }
1422     return jsUndefined();
1423 }
1424
1425 JSValue* WindowProtoFuncMoveTo::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1426 {
1427     if (!thisObj->inherits(&Window::info))
1428         return throwError(exec, TypeError);
1429     Window* window = static_cast<Window*>(thisObj);
1430     Frame* frame = window->impl()->frame();
1431     if (!frame)
1432         return jsUndefined();
1433
1434     Page* page = frame->page();
1435
1436     if (args.size() >= 2 && page) {
1437       FloatRect fr = page->chrome()->windowRect();
1438       FloatRect sr = screenAvailableRect(page->mainFrame()->view());
1439       fr.setLocation(sr.location());
1440       FloatRect update = fr;
1441       update.move(args[0]->toFloat(exec), args[1]->toFloat(exec));     
1442       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1443       adjustWindowRect(sr, fr, update);
1444       page->chrome()->setWindowRect(fr);
1445     }
1446     return jsUndefined();
1447 }
1448
1449 JSValue* WindowProtoFuncResizeBy::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1450 {
1451     if (!thisObj->inherits(&Window::info))
1452         return throwError(exec, TypeError);
1453     Window* window = static_cast<Window*>(thisObj);
1454     Frame* frame = window->impl()->frame();
1455     if (!frame)
1456         return jsUndefined();
1457
1458     Page* page = frame->page();
1459
1460     if (args.size() >= 2 && page) {
1461       FloatRect fr = page->chrome()->windowRect();
1462       FloatSize dest = fr.size() + FloatSize(args[0]->toFloat(exec), args[1]->toFloat(exec));
1463       FloatRect update(fr.location(), dest);
1464       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1465       page->chrome()->setWindowRect(fr);
1466     }
1467     return jsUndefined();
1468 }
1469
1470 JSValue* WindowProtoFuncResizeTo::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1471 {
1472     if (!thisObj->inherits(&Window::info))
1473         return throwError(exec, TypeError);
1474     Window* window = static_cast<Window*>(thisObj);
1475     Frame* frame = window->impl()->frame();
1476     if (!frame)
1477         return jsUndefined();
1478
1479     Page* page = frame->page();
1480
1481     if (args.size() >= 2 && page) {
1482       FloatRect fr = page->chrome()->windowRect();
1483       FloatSize dest = FloatSize(args[0]->toFloat(exec), args[1]->toFloat(exec));
1484       FloatRect update(fr.location(), dest);
1485       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1486       page->chrome()->setWindowRect(fr);
1487     }
1488     return jsUndefined();
1489 }
1490
1491 JSValue* WindowProtoFuncSetTimeout::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1492 {
1493     if (!thisObj->inherits(&Window::info))
1494         return throwError(exec, TypeError);
1495     Window* window = static_cast<Window*>(thisObj);
1496     Frame* frame = window->impl()->frame();
1497     if (!frame)
1498         return jsUndefined();
1499
1500     JSValue *v = args[0];
1501     UString s = v->toString(exec);
1502
1503     if (!window->isSafeScript(exec))
1504         return jsUndefined();
1505     if (v->isString()) {
1506       int i = args[1]->toInt32(exec);
1507       int r = (const_cast<Window*>(window))->installTimeout(s, i, true /*single shot*/);
1508       return jsNumber(r);
1509     }
1510     else if (v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1511       JSValue *func = args[0];
1512       int i = args[1]->toInt32(exec);
1513       
1514       List argsTail;
1515       args.getSlice(2, argsTail);
1516
1517       int r = (const_cast<Window*>(window))->installTimeout(func, argsTail, i, true /*single shot*/);
1518       return jsNumber(r);
1519     }
1520     else
1521       return jsUndefined();
1522 }
1523
1524 JSValue* WindowProtoFuncClearTimeout::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1525 {
1526     // Also the implementation for window.clearInterval()
1527
1528     if (!thisObj->inherits(&Window::info))
1529         return throwError(exec, TypeError);
1530     Window* window = static_cast<Window*>(thisObj);
1531     Frame* frame = window->impl()->frame();
1532     if (!frame)
1533         return jsUndefined();
1534
1535     JSValue *v = args[0];
1536
1537     if (!window->isSafeScript(exec))
1538         return jsUndefined();
1539     (const_cast<Window*>(window))->clearTimeout(v->toInt32(exec));
1540     return jsUndefined();
1541 }
1542
1543 JSValue* WindowProtoFuncSetInterval::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1544 {
1545     if (!thisObj->inherits(&Window::info))
1546         return throwError(exec, TypeError);
1547     Window* window = static_cast<Window*>(thisObj);
1548     Frame* frame = window->impl()->frame();
1549     if (!frame)
1550         return jsUndefined();
1551
1552     JSValue *v = args[0];
1553     UString s = v->toString(exec);
1554
1555     if (!window->isSafeScript(exec))
1556         return jsUndefined();
1557     if (args.size() >= 2 && v->isString()) {
1558       int i = args[1]->toInt32(exec);
1559       int r = (const_cast<Window*>(window))->installTimeout(s, i, false);
1560       return jsNumber(r);
1561     }
1562     else if (args.size() >= 2 && v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1563       JSValue *func = args[0];
1564       int i = args[1]->toInt32(exec);
1565
1566       List argsTail;
1567       args.getSlice(2, argsTail);
1568
1569       int r = (const_cast<Window*>(window))->installTimeout(func, argsTail, i, false);
1570       return jsNumber(r);
1571     }
1572     else
1573       return jsUndefined();
1574
1575 }
1576
1577 JSValue* WindowProtoFuncAddEventListener::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1578 {
1579     if (!thisObj->inherits(&Window::info))
1580         return throwError(exec, TypeError);
1581     Window* window = static_cast<Window*>(thisObj);
1582     Frame* frame = window->impl()->frame();
1583     if (!frame)
1584         return jsUndefined();
1585
1586     if (!window->isSafeScript(exec))
1587         return jsUndefined();
1588     if (JSEventListener* listener = window->findOrCreateJSEventListener(args[1]))
1589         if (Document *doc = frame->document())
1590             doc->addWindowEventListener(AtomicString(args[0]->toString(exec)), listener, args[2]->toBoolean(exec));
1591     return jsUndefined();
1592 }
1593
1594 JSValue* WindowProtoFuncRemoveEventListener::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1595 {
1596     if (!thisObj->inherits(&Window::info))
1597         return throwError(exec, TypeError);
1598     Window* window = static_cast<Window*>(thisObj);
1599     Frame* frame = window->impl()->frame();
1600     if (!frame)
1601         return jsUndefined();
1602
1603     if (!window->isSafeScript(exec))
1604         return jsUndefined();
1605     if (JSEventListener* listener = window->findJSEventListener(args[1]))
1606         if (Document *doc = frame->document())
1607             doc->removeWindowEventListener(AtomicString(args[0]->toString(exec)), listener, args[2]->toBoolean(exec));
1608     return jsUndefined();
1609 }
1610
1611 JSValue* WindowProtoFuncShowModalDialog::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1612 {
1613     if (!thisObj->inherits(&Window::info))
1614         return throwError(exec, TypeError);
1615     Window* window = static_cast<Window*>(thisObj);
1616     Frame* frame = window->impl()->frame();
1617     if (!frame)
1618         return jsUndefined();
1619
1620     return showModalDialog(exec, window, args);
1621 }
1622
1623 JSValue* WindowProtoFuncNotImplemented::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1624 {
1625     if (!thisObj->inherits(&Window::info))
1626         return throwError(exec, TypeError);
1627     Window* window = static_cast<Window*>(thisObj);
1628     Frame* frame = window->impl()->frame();
1629     if (!frame)
1630         return jsUndefined();
1631
1632     // If anyone implements these, they need the safe script security check.
1633     if (!window->isSafeScript(exec))
1634         return jsUndefined();
1635     // Not implemented.
1636     return jsUndefined();
1637 }
1638
1639 void Window::updateLayout() const
1640 {
1641   Frame* frame = impl()->frame();
1642   if (!frame)
1643     return;
1644   WebCore::Document* docimpl = frame->document();
1645   if (docimpl)
1646     docimpl->updateLayoutIgnorePendingStylesheets();
1647 }
1648
1649 void Window::setReturnValueSlot(JSValue** slot)
1650
1651     d->m_returnValueSlot = slot; 
1652 }
1653
1654 ////////////////////// ScheduledAction ////////////////////////
1655
1656 void ScheduledAction::execute(Window* window)
1657 {
1658     RefPtr<Frame> frame = window->impl()->frame();
1659     if (!frame)
1660         return;
1661
1662     KJSProxy* scriptProxy = frame->scriptProxy();
1663     if (!scriptProxy)
1664         return;
1665
1666     RefPtr<ScriptInterpreter> interpreter = scriptProxy->interpreter();
1667
1668     interpreter->setProcessingTimerCallback(true);
1669
1670     if (JSValue* func = m_func.get()) {
1671         JSLock lock;
1672         if (func->isObject() && static_cast<JSObject*>(func)->implementsCall()) {
1673             ExecState* exec = interpreter->globalExec();
1674             ASSERT(window == interpreter->globalObject());
1675             
1676             List args;
1677             size_t size = m_args.size();
1678             for (size_t i = 0; i < size; ++i) {
1679                 args.append(m_args[i]);
1680             }
1681
1682             interpreter->startTimeoutCheck();
1683             static_cast<JSObject*>(func)->call(exec, window, args);
1684             interpreter->stopTimeoutCheck();
1685             if (exec->hadException()) {
1686                 JSObject* exception = exec->exception()->toObject(exec);
1687                 exec->clearException();
1688                 String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
1689                 int lineNumber = exception->get(exec, "line")->toInt32(exec);
1690                 if (Interpreter::shouldPrintExceptions())
1691                     printf("(timer):%s\n", message.utf8().data());
1692                 if (Page* page = frame->page())
1693                     page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, lineNumber, String());
1694             }
1695         }
1696     } else
1697         frame->loader()->executeScript(m_code);
1698
1699     // Update our document's rendering following the execution of the timeout callback.
1700     // FIXME: Why not use updateDocumentsRendering to update rendering of all documents?
1701     // FIXME: Is this really the right point to do the update? We need a place that works
1702     // for all possible entry points that might possibly execute script, but this seems
1703     // to be a bit too low-level.
1704     if (Document* doc = frame->document())
1705         doc->updateRendering();
1706   
1707     interpreter->setProcessingTimerCallback(false);
1708 }
1709
1710 ////////////////////// timeouts ////////////////////////
1711
1712 void Window::clearAllTimeouts()
1713 {
1714     deleteAllValues(d->m_timeouts);
1715     d->m_timeouts.clear();
1716 }
1717
1718 int Window::installTimeout(ScheduledAction* a, int t, bool singleShot)
1719 {
1720     int timeoutId = ++lastUsedTimeoutId;
1721
1722     // avoid wraparound going negative on us
1723     if (timeoutId <= 0)
1724         timeoutId = 1;
1725
1726     int nestLevel = timerNestingLevel + 1;
1727     DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, nestLevel, this, a);
1728     ASSERT(!d->m_timeouts.get(timeoutId));
1729     d->m_timeouts.set(timeoutId, timer);
1730     // Use a minimum interval of 10 ms to match other browsers, but only once we've
1731     // nested enough to notice that we're repeating.
1732     // Faster timers might be "better", but they're incompatible.
1733     double interval = max(0.001, t * 0.001);
1734     if (interval < cMinimumTimerInterval && nestLevel >= cMaxTimerNestingLevel)
1735         interval = cMinimumTimerInterval;
1736     if (singleShot)
1737         timer->startOneShot(interval);
1738     else
1739         timer->startRepeating(interval);
1740     return timeoutId;
1741 }
1742
1743 ScheduledAction::ScheduledAction(JSValue* func, const List& args)
1744     : m_func(func)
1745 {
1746     List::const_iterator end = args.end();
1747     for (List::const_iterator it = args.begin(); it != end; ++it)
1748         m_args.append(*it);
1749 }
1750
1751 int Window::installTimeout(const UString& handler, int t, bool singleShot)
1752 {
1753     return installTimeout(new ScheduledAction(handler), t, singleShot);
1754 }
1755
1756 int Window::installTimeout(JSValue* func, const List& args, int t, bool singleShot)
1757 {
1758     return installTimeout(new ScheduledAction(func, args), t, singleShot);
1759 }
1760
1761 PausedTimeouts* Window::pauseTimeouts()
1762 {
1763     size_t count = d->m_timeouts.size();
1764     if (count == 0)
1765         return 0;
1766
1767     PausedTimeout* t = new PausedTimeout [count];
1768     PausedTimeouts* result = new PausedTimeouts(t, count);
1769
1770     WindowPrivate::TimeoutsMap::iterator it = d->m_timeouts.begin();
1771     for (size_t i = 0; i != count; ++i, ++it) {
1772         int timeoutId = it->first;
1773         DOMWindowTimer* timer = it->second;
1774         t[i].timeoutId = timeoutId;
1775         t[i].nestingLevel = timer->nestingLevel();
1776         t[i].nextFireInterval = timer->nextFireInterval();
1777         t[i].repeatInterval = timer->repeatInterval();
1778         t[i].action = timer->takeAction();
1779     }
1780     ASSERT(it == d->m_timeouts.end());
1781
1782     deleteAllValues(d->m_timeouts);
1783     d->m_timeouts.clear();
1784
1785     return result;
1786 }
1787
1788 void Window::resumeTimeouts(PausedTimeouts* timeouts)
1789 {
1790     if (!timeouts)
1791         return;
1792     size_t count = timeouts->numTimeouts();
1793     PausedTimeout* array = timeouts->takeTimeouts();
1794     for (size_t i = 0; i != count; ++i) {
1795         int timeoutId = array[i].timeoutId;
1796         DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, array[i].nestingLevel, this, array[i].action);
1797         d->m_timeouts.set(timeoutId, timer);
1798         timer->start(array[i].nextFireInterval, array[i].repeatInterval);
1799     }
1800     delete [] array;
1801 }
1802
1803 void Window::clearTimeout(int timeoutId, bool delAction)
1804 {
1805     // timeout IDs have to be positive, and 0 and -1 are unsafe to
1806     // even look up since they are the empty and deleted value
1807     // respectively
1808     if (timeoutId <= 0)
1809         return;
1810
1811     delete d->m_timeouts.take(timeoutId);
1812 }
1813
1814 void Window::timerFired(DOMWindowTimer* timer)
1815 {
1816     // Simple case for non-one-shot timers.
1817     if (timer->isActive()) {
1818         int timeoutId = timer->timeoutId();
1819
1820         timer->action()->execute(this);
1821         if (d->m_timeouts.contains(timeoutId) && timer->repeatInterval() && timer->repeatInterval() < cMinimumTimerInterval) {
1822             timer->setNestingLevel(timer->nestingLevel() + 1);
1823             if (timer->nestingLevel() >= cMaxTimerNestingLevel)
1824                 timer->augmentRepeatInterval(cMinimumTimerInterval - timer->repeatInterval());
1825         }
1826         return;
1827     }
1828
1829     // Delete timer before executing the action for one-shot timers.
1830     ScheduledAction* action = timer->takeAction();
1831     d->m_timeouts.remove(timer->timeoutId());
1832     delete timer;
1833     action->execute(this);
1834     
1835     JSLock lock;
1836     delete action;
1837 }
1838
1839 void Window::disconnectFrame()
1840 {
1841     clearAllTimeouts();
1842     if (d->loc)
1843         d->loc->m_frame = 0;
1844 }
1845
1846 Window::ListenersMap& Window::jsEventListeners()
1847 {
1848     return d->jsEventListeners;
1849 }
1850
1851 Window::ListenersMap& Window::jsHTMLEventListeners()
1852 {
1853     return d->jsHTMLEventListeners;
1854 }
1855
1856 Window::UnprotectedListenersMap& Window::jsUnprotectedEventListeners()
1857 {
1858     return d->jsUnprotectedEventListeners;
1859 }
1860
1861 Window::UnprotectedListenersMap& Window::jsUnprotectedHTMLEventListeners()
1862 {
1863     return d->jsUnprotectedHTMLEventListeners;
1864 }
1865
1866 ////////////////////// Location Object ////////////////////////
1867
1868 const ClassInfo Location::info = { "Location", 0, &LocationTable };
1869 /*
1870 @begin LocationTable 12
1871   assign        &LocationProtoFuncAssign::create        DontDelete|Function 1
1872   hash          Location::Hash                          DontDelete
1873   host          Location::Host                          DontDelete
1874   hostname      Location::Hostname                      DontDelete
1875   href          Location::Href                          DontDelete
1876   pathname      Location::Pathname                      DontDelete
1877   port          Location::Port                          DontDelete
1878   protocol      Location::Protocol                      DontDelete
1879   search        Location::Search                        DontDelete
1880   toString      &LocationProtoFuncToString::create      DontEnum|DontDelete|Function 0
1881   replace       &LocationProtoFuncReplace::create       DontDelete|Function 1
1882   reload        &LocationProtoFuncReload::create        DontDelete|Function 0
1883 @end
1884 */
1885
1886 Location::Location(Frame *p) : m_frame(p)
1887 {
1888 }
1889
1890 JSValue *Location::getValueProperty(ExecState *exec, int token) const
1891 {
1892   KURL url = m_frame->loader()->url();
1893   switch (token) {
1894   case Hash:
1895     return jsString(url.ref().isNull() ? "" : "#" + url.ref());
1896   case Host: {
1897     // Note: this is the IE spec. The NS spec swaps the two, it says
1898     // "The hostname property is the concatenation of the host and port properties, separated by a colon."
1899     // Bleh.
1900     UString str = url.host();
1901     if (url.port())
1902         str += ":" + String::number((int)url.port());
1903     return jsString(str);
1904   }
1905   case Hostname:
1906     return jsString(url.host());
1907   case Href:
1908     if (!url.hasPath())
1909       return jsString(url.prettyURL() + "/");
1910     return jsString(url.prettyURL());
1911   case Pathname:
1912     return jsString(url.path().isEmpty() ? "/" : url.path());
1913   case Port:
1914     return jsString(url.port() ? String::number((int)url.port()) : "");
1915   case Protocol:
1916     return jsString(url.protocol() + ":");
1917   case Search:
1918     return jsString(url.query());
1919   default:
1920     ASSERT(0);
1921     return jsUndefined();
1922   }
1923 }
1924
1925 bool Location::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) 
1926 {
1927   if (!m_frame)
1928     return false;
1929   
1930   const Window* window = Window::retrieveWindow(m_frame);
1931   
1932   const HashEntry *entry = Lookup::findEntry(&LocationTable, propertyName);
1933   if (!entry || !(entry->attr & KJS::Function) || (entry->value.functionValue != &LocationProtoFuncReplace::create
1934                                                    && entry->value.functionValue != &LocationProtoFuncReload::create
1935                                                    && entry->value.functionValue != &LocationProtoFuncAssign::create))  {
1936     if (!window || !window->isSafeScript(exec)) {
1937       slot.setUndefined(this);
1938       return true;
1939     }
1940   }
1941
1942   return getStaticPropertySlot<Location, JSObject>(exec, &LocationTable, this, propertyName, slot);
1943 }
1944
1945 void Location::put(ExecState *exec, const Identifier &p, JSValue *v, int attr)
1946 {
1947   if (!m_frame)
1948     return;
1949
1950   DeprecatedString str = v->toString(exec);
1951   KURL url = m_frame->loader()->url();
1952   const Window* window = Window::retrieveWindow(m_frame);
1953   bool sameDomainAccess = window && window->isSafeScript(exec);
1954
1955   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
1956
1957   if (entry) {
1958       // cross-domain access to the location is allowed when assigning the whole location,
1959       // but not when assigning the individual pieces, since that might inadvertently
1960       // disclose other parts of the original location.
1961       if (entry->value.intValue != Href && !sameDomainAccess)
1962           return;
1963
1964       switch (entry->value.intValue) {
1965       case Href: {
1966           Frame* frame = Window::retrieveActive(exec)->impl()->frame();
1967           if (!frame)
1968               return;
1969           if (!frame->loader()->shouldAllowNavigation(m_frame))
1970               return;
1971           url = frame->loader()->completeURL(str).url();
1972           break;
1973       } 
1974       case Hash: {
1975           if (str.startsWith("#"))
1976               str = str.mid(1);
1977           
1978           if (url.ref() == str)
1979               return;
1980
1981           url.setRef(str);
1982           break;
1983       }
1984       case Host: {
1985           url.setHostAndPort(str);
1986           break;
1987       }
1988       case Hostname:
1989           url.setHost(str);
1990           break;
1991       case Pathname:
1992           url.setPath(str);
1993           break;
1994       case Port:
1995           url.setPort(str.toUInt());
1996           break;
1997       case Protocol:
1998           url.setProtocol(str);
1999           break;
2000       case Search:
2001           url.setQuery(str);
2002           break;
2003       default:
2004           // Disallow changing other properties in LocationTable. e.g., "window.location.toString = ...".
2005           // <http://bugs.webkit.org/show_bug.cgi?id=12720>
2006           return;
2007       }
2008   } else {
2009       if (sameDomainAccess)
2010           JSObject::put(exec, p, v, attr);
2011       return;
2012   }
2013
2014   Frame* activeFrame = Window::retrieveActive(exec)->impl()->frame();
2015   if (!url.url().startsWith("javascript:", false) || sameDomainAccess) {
2016     bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2017     m_frame->loader()->scheduleLocationChange(url.url(), activeFrame->loader()->outgoingReferrer(), false, userGesture);
2018   }
2019 }
2020
2021 JSValue* LocationProtoFuncReplace::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
2022 {
2023     if (!thisObj->inherits(&Location::info))
2024         return throwError(exec, TypeError);
2025     Location* location = static_cast<Location*>(thisObj);
2026     Frame* frame = location->frame();
2027     if (!frame)
2028         return jsUndefined();
2029
2030     Frame* p = Window::retrieveActive(exec)->impl()->frame();
2031     if (p) {
2032       if (!p->loader()->shouldAllowNavigation(frame))
2033         return jsUndefined();
2034       DeprecatedString str = args[0]->toString(exec);
2035       const Window* window = Window::retrieveWindow(frame);
2036       if (!str.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2037         bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2038         frame->loader()->scheduleLocationChange(p->loader()->completeURL(str).url(), p->loader()->outgoingReferrer(), true, userGesture);
2039       }
2040     }
2041
2042     return jsUndefined();
2043 }
2044
2045 JSValue* LocationProtoFuncReload::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
2046 {
2047     if (!thisObj->inherits(&Location::info))
2048         return throwError(exec, TypeError);
2049     Location* location = static_cast<Location*>(thisObj);
2050     Frame* frame = location->frame();
2051     if (!frame)
2052         return jsUndefined();
2053
2054     Window* window = Window::retrieveWindow(frame);
2055     if (!window->isSafeScript(exec))
2056         return jsUndefined();
2057
2058     if (!frame->loader()->url().url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2059       bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2060       frame->loader()->scheduleRefresh(userGesture);
2061     }
2062     return jsUndefined();
2063 }
2064
2065 JSValue* LocationProtoFuncAssign::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
2066 {
2067     if (!thisObj->inherits(&Location::info))
2068         return throwError(exec, TypeError);
2069     Location* location = static_cast<Location*>(thisObj);
2070     Frame* frame = location->frame();
2071     if (!frame)
2072         return jsUndefined();
2073
2074     Frame *p = Window::retrieveActive(exec)->impl()->frame();
2075     if (p) {
2076         if (!p->loader()->shouldAllowNavigation(frame))
2077           return jsUndefined();
2078         const Window *window = Window::retrieveWindow(frame);
2079         DeprecatedString dstUrl = p->loader()->completeURL(DeprecatedString(args[0]->toString(exec))).url();
2080         if (!dstUrl.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2081             bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2082             // We want a new history item if this JS was called via a user gesture
2083             frame->loader()->scheduleLocationChange(dstUrl, p->loader()->outgoingReferrer(), false, userGesture);
2084         }
2085     }
2086
2087     return jsUndefined();
2088 }
2089
2090 JSValue* LocationProtoFuncToString::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
2091 {
2092     if (!thisObj->inherits(&Location::info))
2093         return throwError(exec, TypeError);
2094     Location* location = static_cast<Location*>(thisObj);
2095     Frame* frame = location->frame();
2096     if (!frame)
2097         return jsUndefined();
2098
2099     Window* window = Window::retrieveWindow(frame);
2100     if (!window->isSafeScript(exec))
2101         return jsUndefined();
2102
2103     if (!frame || !Window::retrieveWindow(frame)->isSafeScript(exec))
2104         return jsString();
2105
2106     if (!frame->loader()->url().hasPath())
2107         return jsString(frame->loader()->url().prettyURL() + "/");
2108     return jsString(frame->loader()->url().prettyURL());
2109 }
2110
2111 /////////////////////////////////////////////////////////////////////////////
2112
2113 PausedTimeouts::~PausedTimeouts()
2114 {
2115     PausedTimeout *array = m_array;
2116     if (!array)
2117         return;
2118     size_t count = m_length;
2119     for (size_t i = 0; i != count; ++i)
2120         delete array[i].action;
2121     delete [] array;
2122 }
2123
2124 void DOMWindowTimer::fired()
2125 {
2126     timerNestingLevel = m_nestingLevel;
2127     m_object->timerFired(this);
2128     timerNestingLevel = 0;
2129 }
2130
2131 } // namespace KJS
2132
2133 using namespace KJS;
2134
2135 namespace WebCore {
2136
2137 JSValue* toJS(ExecState*, DOMWindow* domWindow)
2138 {
2139     if (!domWindow)
2140         return jsNull();
2141     Frame* frame = domWindow->frame();
2142     if (!frame)
2143         return jsNull();
2144     return Window::retrieve(frame);
2145 }
2146     
2147 } // namespace WebCore