dd63d2ae55cb59657d87c3d00b2af69df3c27c34
[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         DeprecatedString dstUrl = p->loader()->completeURL(DeprecatedString(value->toString(exec))).url();
735         if (!dstUrl.startsWith("javascript:", false) || isSafeScript(exec)) {
736           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
737           // We want a new history item if this JS was called via a user gesture
738           impl()->frame()->loader()->scheduleLocationChange(dstUrl, p->loader()->outgoingReferrer(), false, userGesture);
739         }
740       }
741       return;
742     }
743     case Onabort:
744       if (isSafeScript(exec))
745         setListener(exec, abortEvent,value);
746       return;
747     case Onblur:
748       if (isSafeScript(exec))
749         setListener(exec, blurEvent,value);
750       return;
751     case Onchange:
752       if (isSafeScript(exec))
753         setListener(exec, changeEvent,value);
754       return;
755     case Onclick:
756       if (isSafeScript(exec))
757         setListener(exec,clickEvent,value);
758       return;
759     case Ondblclick:
760       if (isSafeScript(exec))
761         setListener(exec, dblclickEvent,value);
762       return;
763     case Onerror:
764       if (isSafeScript(exec))
765         setListener(exec, errorEvent, value);
766       return;
767     case Onfocus:
768       if (isSafeScript(exec))
769         setListener(exec,focusEvent,value);
770       return;
771     case Onkeydown:
772       if (isSafeScript(exec))
773         setListener(exec,keydownEvent,value);
774       return;
775     case Onkeypress:
776       if (isSafeScript(exec))
777         setListener(exec,keypressEvent,value);
778       return;
779     case Onkeyup:
780       if (isSafeScript(exec))
781         setListener(exec,keyupEvent,value);
782       return;
783     case Onload:
784       if (isSafeScript(exec))
785         setListener(exec,loadEvent,value);
786       return;
787     case Onmousedown:
788       if (isSafeScript(exec))
789         setListener(exec,mousedownEvent,value);
790       return;
791     case Onmousemove:
792       if (isSafeScript(exec))
793         setListener(exec,mousemoveEvent,value);
794       return;
795     case Onmouseout:
796       if (isSafeScript(exec))
797         setListener(exec,mouseoutEvent,value);
798       return;
799     case Onmouseover:
800       if (isSafeScript(exec))
801         setListener(exec,mouseoverEvent,value);
802       return;
803     case Onmouseup:
804       if (isSafeScript(exec))
805         setListener(exec,mouseupEvent,value);
806       return;
807     case OnWindowMouseWheel:
808       if (isSafeScript(exec))
809         setListener(exec, mousewheelEvent,value);
810       return;
811     case Onreset:
812       if (isSafeScript(exec))
813         setListener(exec,resetEvent,value);
814       return;
815     case Onresize:
816       if (isSafeScript(exec))
817         setListener(exec,resizeEvent,value);
818       return;
819     case Onscroll:
820       if (isSafeScript(exec))
821         setListener(exec,scrollEvent,value);
822       return;
823     case Onsearch:
824         if (isSafeScript(exec))
825             setListener(exec,searchEvent,value);
826         return;
827     case Onselect:
828       if (isSafeScript(exec))
829         setListener(exec,selectEvent,value);
830       return;
831     case Onsubmit:
832       if (isSafeScript(exec))
833         setListener(exec,submitEvent,value);
834       return;
835     case Onbeforeunload:
836       if (isSafeScript(exec))
837         setListener(exec, beforeunloadEvent, value);
838       return;
839     case Onunload:
840       if (isSafeScript(exec))
841         setListener(exec, unloadEvent, value);
842       return;
843     default:
844       break;
845     }
846   }
847   if (isSafeScript(exec))
848     JSObject::put(exec, propertyName, value, attr);
849 }
850
851 static bool shouldLoadAsEmptyDocument(const KURL &url)
852 {
853   return url.protocol().lower() == "about" || url.isEmpty();
854 }
855
856 bool Window::isSafeScript(const ScriptInterpreter *origin, const ScriptInterpreter *target)
857 {
858     if (origin == target)
859         return true;
860         
861     Frame* originFrame = origin->frame();
862     Frame* targetFrame = target->frame();
863
864     // JS may be attempting to access the "window" object, which should be valid,
865     // even if the document hasn't been constructed yet.  If the document doesn't
866     // exist yet allow JS to access the window object.
867     if (!targetFrame->document())
868         return true;
869
870     WebCore::Document *originDocument = originFrame->document();
871     WebCore::Document *targetDocument = targetFrame->document();
872
873     if (!targetDocument) {
874         return false;
875     }
876
877     WebCore::String targetDomain = targetDocument->domain();
878
879     // Always allow local pages to execute any JS.
880     if (targetDomain.isNull())
881         return true;
882
883     WebCore::String originDomain = originDocument->domain();
884
885     // if this document is being initially loaded as empty by its parent
886     // or opener, allow access from any document in the same domain as
887     // the parent or opener.
888     if (shouldLoadAsEmptyDocument(targetFrame->loader()->url())) {
889         Frame* ancestorFrame = targetFrame->loader()->opener() ? targetFrame->loader()->opener() : targetFrame->tree()->parent();
890         while (ancestorFrame && shouldLoadAsEmptyDocument(ancestorFrame->loader()->url()))
891             ancestorFrame = ancestorFrame->tree()->parent();
892         if (ancestorFrame)
893             originDomain = ancestorFrame->document()->domain();
894     }
895
896     if (targetDomain == originDomain)
897         return true;
898
899     if (!originFrame->settings()->privateBrowsingEnabled()) {
900         if (Interpreter::shouldPrintExceptions())
901             printf("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
902                    targetDocument->URL().latin1(), originDocument->URL().latin1());
903         String message = String::format("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         if (Page* page = targetFrame->page())
906             page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, 1, String()); // FIXME: provide a real line number and source URL.
907     }
908
909     return false;
910 }
911
912 bool Window::isSafeScript(ExecState *exec) const
913 {
914   Frame* frame = impl()->frame();
915   if (!frame)
916     return false;
917   Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame();
918   if (!activeFrame)
919     return false;
920   if (activeFrame == frame)
921     return true;
922
923   WebCore::Document* thisDocument = frame->document();
924
925   // JS may be attempting to access the "window" object, which should be valid,
926   // even if the document hasn't been constructed yet.  If the document doesn't
927   // exist yet allow JS to access the window object.
928   if (!thisDocument)
929       return true;
930
931   WebCore::Document* actDocument = activeFrame->document();
932
933   const SecurityOrigin& actSecurityOrigin = actDocument->securityOrigin();
934   const SecurityOrigin& thisSecurityOrigin = thisDocument->securityOrigin();
935
936   if (actSecurityOrigin.canAccess(thisSecurityOrigin))
937     return true;
938
939   // FIXME: this error message should contain more specifics of why the same origin check has failed.
940   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",
941                                   thisDocument->URL().utf8().data(), actDocument->URL().utf8().data());
942
943   if (Interpreter::shouldPrintExceptions())
944     printf("%s", message.utf8().data());
945
946   if (Page* page = frame->page())
947     page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, 1, String());
948
949   return false;
950 }
951
952 void Window::setListener(ExecState *exec, const AtomicString &eventType, JSValue *func)
953 {
954   if (!isSafeScript(exec))
955     return;
956   Frame* frame = impl()->frame();
957   if (!frame)
958     return;
959   Document* doc = frame->document();
960   if (!doc)
961     return;
962
963   doc->setHTMLWindowEventListener(eventType, findOrCreateJSEventListener(func,true));
964 }
965
966 JSValue *Window::getListener(ExecState *exec, const AtomicString &eventType) const
967 {
968   if (!isSafeScript(exec))
969     return jsUndefined();
970   Frame* frame = impl()->frame();
971   if (!frame)
972     return jsUndefined();
973   Document* doc = frame->document();
974   if (!doc)
975     return jsUndefined();
976
977   WebCore::EventListener *listener = doc->getHTMLWindowEventListener(eventType);
978   if (listener && static_cast<JSEventListener*>(listener)->listenerObj())
979     return static_cast<JSEventListener*>(listener)->listenerObj();
980   else
981     return jsNull();
982 }
983
984 JSEventListener* Window::findJSEventListener(JSValue* val, bool html)
985 {
986     if (!val->isObject())
987         return 0;
988     JSObject* object = static_cast<JSObject*>(val);
989     ListenersMap& listeners = html ? d->jsHTMLEventListeners : d->jsEventListeners;
990     return listeners.get(object);
991 }
992
993 JSEventListener *Window::findOrCreateJSEventListener(JSValue *val, bool html)
994 {
995   JSEventListener *listener = findJSEventListener(val, html);
996   if (listener)
997     return listener;
998
999   if (!val->isObject())
1000     return 0;
1001   JSObject *object = static_cast<JSObject *>(val);
1002
1003   // Note that the JSEventListener constructor adds it to our jsEventListeners list
1004   return new JSEventListener(object, this, html);
1005 }
1006
1007 JSUnprotectedEventListener* Window::findJSUnprotectedEventListener(JSValue* val, bool html)
1008 {
1009     if (!val->isObject())
1010         return 0;
1011     JSObject* object = static_cast<JSObject*>(val);
1012     UnprotectedListenersMap& listeners = html ? d->jsUnprotectedHTMLEventListeners : d->jsUnprotectedEventListeners;
1013     return listeners.get(object);
1014 }
1015
1016 JSUnprotectedEventListener *Window::findOrCreateJSUnprotectedEventListener(JSValue *val, bool html)
1017 {
1018   JSUnprotectedEventListener *listener = findJSUnprotectedEventListener(val, html);
1019   if (listener)
1020     return listener;
1021
1022   if (!val->isObject())
1023     return 0;
1024   JSObject *object = static_cast<JSObject *>(val);
1025
1026   // The JSUnprotectedEventListener constructor adds it to our jsUnprotectedEventListeners map.
1027   return new JSUnprotectedEventListener(object, this, html);
1028 }
1029
1030 void Window::clearHelperObjectProperties()
1031 {
1032   d->loc = 0;
1033   d->m_evt = 0;
1034 }
1035
1036 void Window::clear()
1037 {
1038   JSLock lock;
1039
1040   if (d->m_returnValueSlot && !*d->m_returnValueSlot)
1041     *d->m_returnValueSlot = getDirect("returnValue");
1042
1043   clearAllTimeouts();
1044   clearProperties();
1045   clearHelperObjectProperties();
1046   setPrototype(JSDOMWindowPrototype::self()); // clear the prototype
1047
1048   // Now recreate a working global object for the next URL that will use us; but only if we haven't been
1049   // disconnected yet
1050   if (Frame* frame = impl()->frame())
1051     frame->scriptProxy()->interpreter()->initGlobalObject();
1052
1053   // there's likely to be lots of garbage now
1054   gcController().garbageCollectSoon();
1055 }
1056
1057 void Window::setCurrentEvent(Event *evt)
1058 {
1059   d->m_evt = evt;
1060 }
1061
1062 static void setWindowFeature(const String& keyString, const String& valueString, WindowFeatures& windowFeatures)
1063 {
1064     int value;
1065     
1066     if (valueString.length() == 0 || // listing a key with no value is shorthand for key=yes
1067         valueString == "yes")
1068         value = 1;
1069     else
1070         value = valueString.toInt();
1071     
1072     if (keyString == "left" || keyString == "screenx") {
1073         windowFeatures.xSet = true;
1074         windowFeatures.x = value;
1075     } else if (keyString == "top" || keyString == "screeny") {
1076         windowFeatures.ySet = true;
1077         windowFeatures.y = value;
1078     } else if (keyString == "width" || keyString == "innerwidth") {
1079         windowFeatures.widthSet = true;
1080         windowFeatures.width = value;
1081     } else if (keyString == "height" || keyString == "innerheight") {
1082         windowFeatures.heightSet = true;
1083         windowFeatures.height = value;
1084     } else if (keyString == "menubar")
1085         windowFeatures.menuBarVisible = value;
1086     else if (keyString == "toolbar")
1087         windowFeatures.toolBarVisible = value;
1088     else if (keyString == "location")
1089         windowFeatures.locationBarVisible = value;
1090     else if (keyString == "status")
1091         windowFeatures.statusBarVisible = value;
1092     else if (keyString == "resizable")
1093         windowFeatures.resizable = value;
1094     else if (keyString == "fullscreen")
1095         windowFeatures.fullscreen = value;
1096     else if (keyString == "scrollbars")
1097         windowFeatures.scrollbarsVisible = value;
1098 }
1099
1100 // Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
1101 static bool isSeparator(::UChar c)
1102 {
1103     return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0';
1104 }
1105
1106 static void parseWindowFeatures(const String& features, WindowFeatures& windowFeatures)
1107 {
1108     /*
1109      The IE rule is: all features except for channelmode and fullscreen default to YES, but
1110      if the user specifies a feature string, all features default to NO. (There is no public
1111      standard that applies to this method.)
1112      
1113      <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
1114      */
1115     
1116     windowFeatures.dialog = false;
1117     windowFeatures.fullscreen = false;
1118     
1119     windowFeatures.xSet = false;
1120     windowFeatures.ySet = false;
1121     windowFeatures.widthSet = false;
1122     windowFeatures.heightSet = false;
1123     
1124     if (features.length() == 0) {
1125         windowFeatures.menuBarVisible = true;
1126         windowFeatures.statusBarVisible = true;
1127         windowFeatures.toolBarVisible = true;
1128         windowFeatures.locationBarVisible = true;
1129         windowFeatures.scrollbarsVisible = true;
1130         windowFeatures.resizable = true;
1131         
1132         return;
1133     }
1134     
1135     windowFeatures.menuBarVisible = false;
1136     windowFeatures.statusBarVisible = false;
1137     windowFeatures.toolBarVisible = false;
1138     windowFeatures.locationBarVisible = false;
1139     windowFeatures.scrollbarsVisible = false;
1140     windowFeatures.resizable = false;
1141     
1142     // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
1143     int keyBegin, keyEnd;
1144     int valueBegin, valueEnd;
1145     
1146     int i = 0;
1147     int length = features.length();
1148     String buffer = features.lower();
1149     while (i < length) {
1150         // skip to first non-separator, but don't skip past the end of the string
1151         while (isSeparator(buffer[i])) {
1152             if (i >= length)
1153                 break;
1154             i++;
1155         }
1156         keyBegin = i;
1157         
1158         // skip to first separator
1159         while (!isSeparator(buffer[i]))
1160             i++;
1161         keyEnd = i;
1162         
1163         // skip to first '=', but don't skip past a ',' or the end of the string
1164         while (buffer[i] != '=') {
1165             if (buffer[i] == ',' || i >= length)
1166                 break;
1167             i++;
1168         }
1169         
1170         // skip to first non-separator, but don't skip past a ',' or the end of the string
1171         while (isSeparator(buffer[i])) {
1172             if (buffer[i] == ',' || i >= length)
1173                 break;
1174             i++;
1175         }
1176         valueBegin = i;
1177         
1178         // skip to first separator
1179         while (!isSeparator(buffer[i]))
1180             i++;
1181         valueEnd = i;
1182         
1183         ASSERT(i <= length);
1184
1185         String keyString(buffer.substring(keyBegin, keyEnd - keyBegin));
1186         String valueString(buffer.substring(valueBegin, valueEnd - valueBegin));
1187         setWindowFeature(keyString, valueString, windowFeatures);
1188     }
1189 }
1190
1191 // Explain the 4 things this function does.
1192 // 1) Validates the pending changes are not changing to NaN
1193 // 2) Constrains the window rect to no smaller than 100 in each dimension and no
1194 //    bigger than the the float rect's dimensions.
1195 // 3) Constrain window rect to within the top and left boundaries of the screen rect
1196 // 4) Constraint the window rect to within the bottom and right boundaries of the
1197 //    screen rect.
1198 // 5) Translate the window rect coordinates to be within the coordinate space of
1199 //    the screen rect.
1200 static void adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges)
1201 {
1202     // Make sure we're in a valid state before adjusting dimensions
1203     ASSERT(!isnan(screen.x()) && !isnan(screen.y()) && !isnan(screen.width()) && !isnan(screen.height()) &&
1204            !isnan(window.x()) && !isnan(window.y()) && !isnan(window.width()) && !isnan(window.height()));
1205     
1206     // Update window values if they are not NaN
1207     if (!isnan(pendingChanges.x()))
1208         window.setX(pendingChanges.x());
1209     if (!isnan(pendingChanges.y()))
1210         window.setY(pendingChanges.y());
1211     if (!isnan(pendingChanges.width()))
1212         window.setWidth(pendingChanges.width());
1213     if (!isnan(pendingChanges.height()))
1214         window.setHeight(pendingChanges.height());
1215     
1216     // Resize the window to between 100 and the screen width and height if it's
1217     // outside of those ranges.
1218     window.setWidth(min(max(100.0f, window.width()), screen.width()));
1219     window.setHeight(min(max(100.0f, window.height()), screen.height()));
1220     
1221     // Constrain the window to the top and left of the screen if it's left or
1222     // above it.
1223     window.setX(max(window.x(), screen.x()));
1224     window.setY(max(window.y(), screen.y()));
1225
1226     // Constrain the window to the bottom and right of the screen if it's past
1227     // the right or below it.
1228     window.setX(window.x() - max(0.0f, window.right() - screen.width()));
1229     window.setY(window.y() - max(0.0f, window.bottom() - screen.height()));
1230     
1231     // Adjust the window rect to be in the coordinate space of the screen rect
1232     window.setX(window.x() + screen.x());
1233     window.setY(window.y() + 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
1308     Page* page = frame->page();
1309
1310     String urlString = valueToStringWithUndefinedOrNullCheck(exec, args[0]);
1311     AtomicString frameName = args[1]->isUndefinedOrNull() ? "_blank" : AtomicString(args[1]->toString(exec));
1312
1313     // Because FrameTree::find() returns true for empty strings, we must check for empty framenames.
1314     // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
1315     if (!allowPopUp(exec, window) && (frameName.isEmpty() || !frame->tree()->find(frameName)))
1316         return jsUndefined();
1317
1318     // Get the target frame for the special cases of _top and _parent
1319     if (frameName == "_top")
1320         while (frame->tree()->parent())
1321               frame = frame->tree()->parent();
1322     else if (frameName == "_parent")
1323         if (frame->tree()->parent())
1324             frame = frame->tree()->parent();
1325
1326     // In those cases, we can schedule a location change right now and return early
1327     if (frameName == "_top" || frameName == "_parent") {
1328         String completedURL;
1329         Frame* activeFrame = Window::retrieveActive(exec)->impl()->frame();
1330         if (!urlString.isEmpty() && activeFrame)
1331             completedURL = activeFrame->document()->completeURL(urlString);
1332
1333         const Window* window = Window::retrieveWindow(frame);
1334         if (!completedURL.isEmpty() && (!completedURL.startsWith("javascript:", false) || (window && window->isSafeScript(exec)))) {
1335             bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1336             frame->loader()->scheduleLocationChange(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture);
1337         }
1338         return Window::retrieve(frame);
1339     }
1340     
1341     // In the case of a named frame or a new window, we'll use the createWindow() helper
1342     WindowFeatures windowFeatures;
1343     String features = valueToStringWithUndefinedOrNullCheck(exec, args[2]);
1344     parseWindowFeatures(features, windowFeatures);
1345     FloatRect windowRect(windowFeatures.x, windowFeatures.y, windowFeatures.width, windowFeatures.height);
1346     adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), windowRect, windowRect);
1347
1348     windowFeatures.x = windowRect.x();
1349     windowFeatures.y = windowRect.y();
1350     windowFeatures.height = windowRect.height();
1351     windowFeatures.width = windowRect.width();
1352
1353     frame = createWindow(exec, frame, urlString, frameName, windowFeatures, 0);
1354
1355     if (!frame)
1356         return jsUndefined();
1357
1358     return Window::retrieve(frame); // global object
1359 }
1360
1361 JSValue* WindowProtoFuncScrollBy::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1362 {
1363     if (!thisObj->inherits(&Window::info))
1364         return throwError(exec, TypeError);
1365     Window* window = static_cast<Window*>(thisObj);
1366     Frame* frame = window->impl()->frame();
1367     if (!frame)
1368         return jsUndefined();
1369
1370     FrameView *widget = frame->view();
1371
1372     window->updateLayout();
1373     if(args.size() >= 2 && widget)
1374       widget->scrollBy(args[0]->toInt32(exec), args[1]->toInt32(exec));
1375     return jsUndefined();
1376 }
1377
1378 JSValue* WindowProtoFuncScrollTo::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1379 {
1380     // Also the implementation for window.scroll()
1381
1382     if (!thisObj->inherits(&Window::info))
1383         return throwError(exec, TypeError);
1384     Window* window = static_cast<Window*>(thisObj);
1385     Frame* frame = window->impl()->frame();
1386     if (!frame)
1387         return jsUndefined();
1388
1389     FrameView *widget = frame->view();
1390
1391     window->updateLayout();
1392     if (args.size() >= 2 && widget)
1393       widget->setContentsPos(args[0]->toInt32(exec), args[1]->toInt32(exec));
1394     return jsUndefined();
1395 }
1396
1397 JSValue* WindowProtoFuncMoveBy::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1398 {
1399     if (!thisObj->inherits(&Window::info))
1400         return throwError(exec, TypeError);
1401     Window* window = static_cast<Window*>(thisObj);
1402     Frame* frame = window->impl()->frame();
1403     if (!frame)
1404         return jsUndefined();
1405
1406     Page* page = frame->page();
1407
1408     if (args.size() >= 2 && page) {
1409       FloatRect fr = page->chrome()->windowRect();
1410       FloatRect update = fr;
1411       update.move(args[0]->toFloat(exec), args[1]->toFloat(exec));
1412       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1413       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1414       page->chrome()->setWindowRect(fr);
1415     }
1416     return jsUndefined();
1417 }
1418
1419 JSValue* WindowProtoFuncMoveTo::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1420 {
1421     if (!thisObj->inherits(&Window::info))
1422         return throwError(exec, TypeError);
1423     Window* window = static_cast<Window*>(thisObj);
1424     Frame* frame = window->impl()->frame();
1425     if (!frame)
1426         return jsUndefined();
1427
1428     Page* page = frame->page();
1429
1430     if (args.size() >= 2 && page) {
1431       FloatRect fr = page->chrome()->windowRect();
1432       FloatRect sr = screenAvailableRect(page->mainFrame()->view());
1433       fr.setLocation(sr.location());
1434       FloatRect update = fr;
1435       update.move(args[0]->toFloat(exec), args[1]->toFloat(exec));     
1436       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1437       adjustWindowRect(sr, fr, update);
1438       page->chrome()->setWindowRect(fr);
1439     }
1440     return jsUndefined();
1441 }
1442
1443 JSValue* WindowProtoFuncResizeBy::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1444 {
1445     if (!thisObj->inherits(&Window::info))
1446         return throwError(exec, TypeError);
1447     Window* window = static_cast<Window*>(thisObj);
1448     Frame* frame = window->impl()->frame();
1449     if (!frame)
1450         return jsUndefined();
1451
1452     Page* page = frame->page();
1453
1454     if (args.size() >= 2 && page) {
1455       FloatRect fr = page->chrome()->windowRect();
1456       FloatSize dest = fr.size() + FloatSize(args[0]->toFloat(exec), args[1]->toFloat(exec));
1457       FloatRect update(fr.location(), dest);
1458       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1459       page->chrome()->setWindowRect(fr);
1460     }
1461     return jsUndefined();
1462 }
1463
1464 JSValue* WindowProtoFuncResizeTo::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1465 {
1466     if (!thisObj->inherits(&Window::info))
1467         return throwError(exec, TypeError);
1468     Window* window = static_cast<Window*>(thisObj);
1469     Frame* frame = window->impl()->frame();
1470     if (!frame)
1471         return jsUndefined();
1472
1473     Page* page = frame->page();
1474
1475     if (args.size() >= 2 && page) {
1476       FloatRect fr = page->chrome()->windowRect();
1477       FloatSize dest = FloatSize(args[0]->toFloat(exec), args[1]->toFloat(exec));
1478       FloatRect update(fr.location(), dest);
1479       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1480       page->chrome()->setWindowRect(fr);
1481     }
1482     return jsUndefined();
1483 }
1484
1485 JSValue* WindowProtoFuncSetTimeout::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1486 {
1487     if (!thisObj->inherits(&Window::info))
1488         return throwError(exec, TypeError);
1489     Window* window = static_cast<Window*>(thisObj);
1490     Frame* frame = window->impl()->frame();
1491     if (!frame)
1492         return jsUndefined();
1493
1494     JSValue *v = args[0];
1495     UString s = v->toString(exec);
1496
1497     if (!window->isSafeScript(exec))
1498         return jsUndefined();
1499     if (v->isString()) {
1500       int i = args[1]->toInt32(exec);
1501       int r = (const_cast<Window*>(window))->installTimeout(s, i, true /*single shot*/);
1502       return jsNumber(r);
1503     }
1504     else if (v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1505       JSValue *func = args[0];
1506       int i = args[1]->toInt32(exec);
1507       
1508       List argsTail;
1509       args.getSlice(2, argsTail);
1510
1511       int r = (const_cast<Window*>(window))->installTimeout(func, argsTail, i, true /*single shot*/);
1512       return jsNumber(r);
1513     }
1514     else
1515       return jsUndefined();
1516 }
1517
1518 JSValue* WindowProtoFuncClearTimeout::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1519 {
1520     // Also the implementation for window.clearInterval()
1521
1522     if (!thisObj->inherits(&Window::info))
1523         return throwError(exec, TypeError);
1524     Window* window = static_cast<Window*>(thisObj);
1525     Frame* frame = window->impl()->frame();
1526     if (!frame)
1527         return jsUndefined();
1528
1529     JSValue *v = args[0];
1530
1531     if (!window->isSafeScript(exec))
1532         return jsUndefined();
1533     (const_cast<Window*>(window))->clearTimeout(v->toInt32(exec));
1534     return jsUndefined();
1535 }
1536
1537 JSValue* WindowProtoFuncSetInterval::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1538 {
1539     if (!thisObj->inherits(&Window::info))
1540         return throwError(exec, TypeError);
1541     Window* window = static_cast<Window*>(thisObj);
1542     Frame* frame = window->impl()->frame();
1543     if (!frame)
1544         return jsUndefined();
1545
1546     JSValue *v = args[0];
1547     UString s = v->toString(exec);
1548
1549     if (!window->isSafeScript(exec))
1550         return jsUndefined();
1551     if (args.size() >= 2 && v->isString()) {
1552       int i = args[1]->toInt32(exec);
1553       int r = (const_cast<Window*>(window))->installTimeout(s, i, false);
1554       return jsNumber(r);
1555     }
1556     else if (args.size() >= 2 && v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1557       JSValue *func = args[0];
1558       int i = args[1]->toInt32(exec);
1559
1560       List argsTail;
1561       args.getSlice(2, argsTail);
1562
1563       int r = (const_cast<Window*>(window))->installTimeout(func, argsTail, i, false);
1564       return jsNumber(r);
1565     }
1566     else
1567       return jsUndefined();
1568
1569 }
1570
1571 JSValue* WindowProtoFuncAddEventListener::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1572 {
1573     if (!thisObj->inherits(&Window::info))
1574         return throwError(exec, TypeError);
1575     Window* window = static_cast<Window*>(thisObj);
1576     Frame* frame = window->impl()->frame();
1577     if (!frame)
1578         return jsUndefined();
1579
1580     if (!window->isSafeScript(exec))
1581         return jsUndefined();
1582     if (JSEventListener* listener = window->findOrCreateJSEventListener(args[1]))
1583         if (Document *doc = frame->document())
1584             doc->addWindowEventListener(AtomicString(args[0]->toString(exec)), listener, args[2]->toBoolean(exec));
1585     return jsUndefined();
1586 }
1587
1588 JSValue* WindowProtoFuncRemoveEventListener::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1589 {
1590     if (!thisObj->inherits(&Window::info))
1591         return throwError(exec, TypeError);
1592     Window* window = static_cast<Window*>(thisObj);
1593     Frame* frame = window->impl()->frame();
1594     if (!frame)
1595         return jsUndefined();
1596
1597     if (!window->isSafeScript(exec))
1598         return jsUndefined();
1599     if (JSEventListener* listener = window->findJSEventListener(args[1]))
1600         if (Document *doc = frame->document())
1601             doc->removeWindowEventListener(AtomicString(args[0]->toString(exec)), listener, args[2]->toBoolean(exec));
1602     return jsUndefined();
1603 }
1604
1605 JSValue* WindowProtoFuncShowModalDialog::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1606 {
1607     if (!thisObj->inherits(&Window::info))
1608         return throwError(exec, TypeError);
1609     Window* window = static_cast<Window*>(thisObj);
1610     Frame* frame = window->impl()->frame();
1611     if (!frame)
1612         return jsUndefined();
1613
1614     return showModalDialog(exec, window, args);
1615 }
1616
1617 JSValue* WindowProtoFuncNotImplemented::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
1618 {
1619     if (!thisObj->inherits(&Window::info))
1620         return throwError(exec, TypeError);
1621     Window* window = static_cast<Window*>(thisObj);
1622     Frame* frame = window->impl()->frame();
1623     if (!frame)
1624         return jsUndefined();
1625
1626     // If anyone implements these, they need the safe script security check.
1627     if (!window->isSafeScript(exec))
1628         return jsUndefined();
1629     // Not implemented.
1630     return jsUndefined();
1631 }
1632
1633 void Window::updateLayout() const
1634 {
1635   Frame* frame = impl()->frame();
1636   if (!frame)
1637     return;
1638   WebCore::Document* docimpl = frame->document();
1639   if (docimpl)
1640     docimpl->updateLayoutIgnorePendingStylesheets();
1641 }
1642
1643 void Window::setReturnValueSlot(JSValue** slot)
1644
1645     d->m_returnValueSlot = slot; 
1646 }
1647
1648 ////////////////////// ScheduledAction ////////////////////////
1649
1650 void ScheduledAction::execute(Window* window)
1651 {
1652     RefPtr<Frame> frame = window->impl()->frame();
1653     if (!frame)
1654         return;
1655
1656     KJSProxy* scriptProxy = frame->scriptProxy();
1657     if (!scriptProxy)
1658         return;
1659
1660     RefPtr<ScriptInterpreter> interpreter = scriptProxy->interpreter();
1661
1662     interpreter->setProcessingTimerCallback(true);
1663
1664     if (JSValue* func = m_func.get()) {
1665         JSLock lock;
1666         if (func->isObject() && static_cast<JSObject*>(func)->implementsCall()) {
1667             ExecState* exec = interpreter->globalExec();
1668             ASSERT(window == interpreter->globalObject());
1669             
1670             List args;
1671             size_t size = m_args.size();
1672             for (size_t i = 0; i < size; ++i) {
1673                 args.append(m_args[i]);
1674             }
1675
1676             interpreter->startTimeoutCheck();
1677             static_cast<JSObject*>(func)->call(exec, window, args);
1678             interpreter->stopTimeoutCheck();
1679             if (exec->hadException()) {
1680                 JSObject* exception = exec->exception()->toObject(exec);
1681                 exec->clearException();
1682                 String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
1683                 int lineNumber = exception->get(exec, "line")->toInt32(exec);
1684                 if (Interpreter::shouldPrintExceptions())
1685                     printf("(timer):%s\n", message.utf8().data());
1686                 if (Page* page = frame->page())
1687                     page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, lineNumber, String());
1688             }
1689         }
1690     } else
1691         frame->loader()->executeScript(m_code);
1692
1693     // Update our document's rendering following the execution of the timeout callback.
1694     // FIXME: Why not use updateDocumentsRendering to update rendering of all documents?
1695     // FIXME: Is this really the right point to do the update? We need a place that works
1696     // for all possible entry points that might possibly execute script, but this seems
1697     // to be a bit too low-level.
1698     if (Document* doc = frame->document())
1699         doc->updateRendering();
1700   
1701     interpreter->setProcessingTimerCallback(false);
1702 }
1703
1704 ////////////////////// timeouts ////////////////////////
1705
1706 void Window::clearAllTimeouts()
1707 {
1708     deleteAllValues(d->m_timeouts);
1709     d->m_timeouts.clear();
1710 }
1711
1712 int Window::installTimeout(ScheduledAction* a, int t, bool singleShot)
1713 {
1714     int timeoutId = ++lastUsedTimeoutId;
1715
1716     // avoid wraparound going negative on us
1717     if (timeoutId <= 0)
1718         timeoutId = 1;
1719
1720     int nestLevel = timerNestingLevel + 1;
1721     DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, nestLevel, this, a);
1722     ASSERT(!d->m_timeouts.get(timeoutId));
1723     d->m_timeouts.set(timeoutId, timer);
1724     // Use a minimum interval of 10 ms to match other browsers, but only once we've
1725     // nested enough to notice that we're repeating.
1726     // Faster timers might be "better", but they're incompatible.
1727     double interval = max(0.001, t * 0.001);
1728     if (interval < cMinimumTimerInterval && nestLevel >= cMaxTimerNestingLevel)
1729         interval = cMinimumTimerInterval;
1730     if (singleShot)
1731         timer->startOneShot(interval);
1732     else
1733         timer->startRepeating(interval);
1734     return timeoutId;
1735 }
1736
1737 ScheduledAction::ScheduledAction(JSValue* func, const List& args)
1738     : m_func(func)
1739 {
1740     List::const_iterator end = args.end();
1741     for (List::const_iterator it = args.begin(); it != end; ++it)
1742         m_args.append(*it);
1743 }
1744
1745 int Window::installTimeout(const UString& handler, int t, bool singleShot)
1746 {
1747     return installTimeout(new ScheduledAction(handler), t, singleShot);
1748 }
1749
1750 int Window::installTimeout(JSValue* func, const List& args, int t, bool singleShot)
1751 {
1752     return installTimeout(new ScheduledAction(func, args), t, singleShot);
1753 }
1754
1755 PausedTimeouts* Window::pauseTimeouts()
1756 {
1757     size_t count = d->m_timeouts.size();
1758     if (count == 0)
1759         return 0;
1760
1761     PausedTimeout* t = new PausedTimeout [count];
1762     PausedTimeouts* result = new PausedTimeouts(t, count);
1763
1764     WindowPrivate::TimeoutsMap::iterator it = d->m_timeouts.begin();
1765     for (size_t i = 0; i != count; ++i, ++it) {
1766         int timeoutId = it->first;
1767         DOMWindowTimer* timer = it->second;
1768         t[i].timeoutId = timeoutId;
1769         t[i].nestingLevel = timer->nestingLevel();
1770         t[i].nextFireInterval = timer->nextFireInterval();
1771         t[i].repeatInterval = timer->repeatInterval();
1772         t[i].action = timer->takeAction();
1773     }
1774     ASSERT(it == d->m_timeouts.end());
1775
1776     deleteAllValues(d->m_timeouts);
1777     d->m_timeouts.clear();
1778
1779     return result;
1780 }
1781
1782 void Window::resumeTimeouts(PausedTimeouts* timeouts)
1783 {
1784     if (!timeouts)
1785         return;
1786     size_t count = timeouts->numTimeouts();
1787     PausedTimeout* array = timeouts->takeTimeouts();
1788     for (size_t i = 0; i != count; ++i) {
1789         int timeoutId = array[i].timeoutId;
1790         DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, array[i].nestingLevel, this, array[i].action);
1791         d->m_timeouts.set(timeoutId, timer);
1792         timer->start(array[i].nextFireInterval, array[i].repeatInterval);
1793     }
1794     delete [] array;
1795 }
1796
1797 void Window::clearTimeout(int timeoutId, bool delAction)
1798 {
1799     // timeout IDs have to be positive, and 0 and -1 are unsafe to
1800     // even look up since they are the empty and deleted value
1801     // respectively
1802     if (timeoutId <= 0)
1803         return;
1804
1805     delete d->m_timeouts.take(timeoutId);
1806 }
1807
1808 void Window::timerFired(DOMWindowTimer* timer)
1809 {
1810     // Simple case for non-one-shot timers.
1811     if (timer->isActive()) {
1812         int timeoutId = timer->timeoutId();
1813
1814         timer->action()->execute(this);
1815         if (d->m_timeouts.contains(timeoutId) && timer->repeatInterval() && timer->repeatInterval() < cMinimumTimerInterval) {
1816             timer->setNestingLevel(timer->nestingLevel() + 1);
1817             if (timer->nestingLevel() >= cMaxTimerNestingLevel)
1818                 timer->augmentRepeatInterval(cMinimumTimerInterval - timer->repeatInterval());
1819         }
1820         return;
1821     }
1822
1823     // Delete timer before executing the action for one-shot timers.
1824     ScheduledAction* action = timer->takeAction();
1825     d->m_timeouts.remove(timer->timeoutId());
1826     delete timer;
1827     action->execute(this);
1828     
1829     JSLock lock;
1830     delete action;
1831 }
1832
1833 void Window::disconnectFrame()
1834 {
1835     clearAllTimeouts();
1836     if (d->loc)
1837         d->loc->m_frame = 0;
1838 }
1839
1840 Window::ListenersMap& Window::jsEventListeners()
1841 {
1842     return d->jsEventListeners;
1843 }
1844
1845 Window::ListenersMap& Window::jsHTMLEventListeners()
1846 {
1847     return d->jsHTMLEventListeners;
1848 }
1849
1850 Window::UnprotectedListenersMap& Window::jsUnprotectedEventListeners()
1851 {
1852     return d->jsUnprotectedEventListeners;
1853 }
1854
1855 Window::UnprotectedListenersMap& Window::jsUnprotectedHTMLEventListeners()
1856 {
1857     return d->jsUnprotectedHTMLEventListeners;
1858 }
1859
1860 ////////////////////// Location Object ////////////////////////
1861
1862 const ClassInfo Location::info = { "Location", 0, &LocationTable };
1863 /*
1864 @begin LocationTable 12
1865   assign        &LocationProtoFuncAssign::create        DontDelete|Function 1
1866   hash          Location::Hash                          DontDelete
1867   host          Location::Host                          DontDelete
1868   hostname      Location::Hostname                      DontDelete
1869   href          Location::Href                          DontDelete
1870   pathname      Location::Pathname                      DontDelete
1871   port          Location::Port                          DontDelete
1872   protocol      Location::Protocol                      DontDelete
1873   search        Location::Search                        DontDelete
1874   toString      &LocationProtoFuncToString::create      DontEnum|DontDelete|Function 0
1875   replace       &LocationProtoFuncReplace::create       DontDelete|Function 1
1876   reload        &LocationProtoFuncReload::create        DontDelete|Function 0
1877 @end
1878 */
1879
1880 Location::Location(Frame *p) : m_frame(p)
1881 {
1882 }
1883
1884 JSValue *Location::getValueProperty(ExecState *exec, int token) const
1885 {
1886   KURL url = m_frame->loader()->url();
1887   switch (token) {
1888   case Hash:
1889     return jsString(url.ref().isNull() ? "" : "#" + url.ref());
1890   case Host: {
1891     // Note: this is the IE spec. The NS spec swaps the two, it says
1892     // "The hostname property is the concatenation of the host and port properties, separated by a colon."
1893     // Bleh.
1894     UString str = url.host();
1895     if (url.port())
1896         str += ":" + String::number((int)url.port());
1897     return jsString(str);
1898   }
1899   case Hostname:
1900     return jsString(url.host());
1901   case Href:
1902     if (!url.hasPath())
1903       return jsString(url.prettyURL() + "/");
1904     return jsString(url.prettyURL());
1905   case Pathname:
1906     return jsString(url.path().isEmpty() ? "/" : url.path());
1907   case Port:
1908     return jsString(url.port() ? String::number((int)url.port()) : "");
1909   case Protocol:
1910     return jsString(url.protocol() + ":");
1911   case Search:
1912     return jsString(url.query());
1913   default:
1914     ASSERT(0);
1915     return jsUndefined();
1916   }
1917 }
1918
1919 bool Location::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) 
1920 {
1921   if (!m_frame)
1922     return false;
1923   
1924   const Window* window = Window::retrieveWindow(m_frame);
1925   
1926   const HashEntry *entry = Lookup::findEntry(&LocationTable, propertyName);
1927   if (!entry || !(entry->attr & KJS::Function) || (entry->value.functionValue != &LocationProtoFuncReplace::create
1928                                                    && entry->value.functionValue != &LocationProtoFuncReload::create
1929                                                    && entry->value.functionValue != &LocationProtoFuncAssign::create))  {
1930     if (!window || !window->isSafeScript(exec)) {
1931       slot.setUndefined(this);
1932       return true;
1933     }
1934   }
1935
1936   return getStaticPropertySlot<Location, JSObject>(exec, &LocationTable, this, propertyName, slot);
1937 }
1938
1939 void Location::put(ExecState *exec, const Identifier &p, JSValue *v, int attr)
1940 {
1941   if (!m_frame)
1942     return;
1943
1944   DeprecatedString str = v->toString(exec);
1945   KURL url = m_frame->loader()->url();
1946   const Window* window = Window::retrieveWindow(m_frame);
1947   bool sameDomainAccess = window && window->isSafeScript(exec);
1948
1949   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
1950
1951   if (entry) {
1952       // cross-domain access to the location is allowed when assigning the whole location,
1953       // but not when assigning the individual pieces, since that might inadvertently
1954       // disclose other parts of the original location.
1955       if (entry->value.intValue != Href && !sameDomainAccess)
1956           return;
1957
1958       switch (entry->value.intValue) {
1959       case Href: {
1960           Frame* frame = Window::retrieveActive(exec)->impl()->frame();
1961           if (frame)
1962               url = frame->loader()->completeURL(str).url();
1963           else
1964               url = str;
1965           break;
1966       } 
1967       case Hash: {
1968           if (str.startsWith("#"))
1969               str = str.mid(1);
1970           
1971           if (url.ref() == str)
1972               return;
1973
1974           url.setRef(str);
1975           break;
1976       }
1977       case Host: {
1978           url.setHostAndPort(str);
1979           break;
1980       }
1981       case Hostname:
1982           url.setHost(str);
1983           break;
1984       case Pathname:
1985           url.setPath(str);
1986           break;
1987       case Port:
1988           url.setPort(str.toUInt());
1989           break;
1990       case Protocol:
1991           url.setProtocol(str);
1992           break;
1993       case Search:
1994           url.setQuery(str);
1995           break;
1996       default:
1997           // Disallow changing other properties in LocationTable. e.g., "window.location.toString = ...".
1998           // <http://bugs.webkit.org/show_bug.cgi?id=12720>
1999           return;
2000       }
2001   } else {
2002       if (sameDomainAccess)
2003           JSObject::put(exec, p, v, attr);
2004       return;
2005   }
2006
2007   Frame* activeFrame = Window::retrieveActive(exec)->impl()->frame();
2008   if (!url.url().startsWith("javascript:", false) || sameDomainAccess) {
2009     bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2010     m_frame->loader()->scheduleLocationChange(url.url(), activeFrame->loader()->outgoingReferrer(), false, userGesture);
2011   }
2012 }
2013
2014 JSValue* LocationProtoFuncReplace::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
2015 {
2016     if (!thisObj->inherits(&Location::info))
2017         return throwError(exec, TypeError);
2018     Location* location = static_cast<Location*>(thisObj);
2019     Frame* frame = location->frame();
2020     if (!frame)
2021         return jsUndefined();
2022
2023     DeprecatedString str = args[0]->toString(exec);
2024     Frame* p = Window::retrieveActive(exec)->impl()->frame();
2025     if ( p ) {
2026       const Window* window = Window::retrieveWindow(frame);
2027       if (!str.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2028         bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2029         frame->loader()->scheduleLocationChange(p->loader()->completeURL(str).url(), p->loader()->outgoingReferrer(), true, userGesture);
2030       }
2031     }
2032
2033     return jsUndefined();
2034 }
2035
2036 JSValue* LocationProtoFuncReload::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
2037 {
2038     if (!thisObj->inherits(&Location::info))
2039         return throwError(exec, TypeError);
2040     Location* location = static_cast<Location*>(thisObj);
2041     Frame* frame = location->frame();
2042     if (!frame)
2043         return jsUndefined();
2044
2045     Window* window = Window::retrieveWindow(frame);
2046     if (!window->isSafeScript(exec))
2047         return jsUndefined();
2048
2049     if (!frame->loader()->url().url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2050       bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2051       frame->loader()->scheduleRefresh(userGesture);
2052     }
2053     return jsUndefined();
2054 }
2055
2056 JSValue* LocationProtoFuncAssign::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
2057 {
2058     if (!thisObj->inherits(&Location::info))
2059         return throwError(exec, TypeError);
2060     Location* location = static_cast<Location*>(thisObj);
2061     Frame* frame = location->frame();
2062     if (!frame)
2063         return jsUndefined();
2064
2065     Window* window = Window::retrieveWindow(frame);
2066     if (!window->isSafeScript(exec))
2067         return jsUndefined();
2068
2069     Frame *p = Window::retrieveActive(exec)->impl()->frame();
2070     if (p) {
2071         const Window *window = Window::retrieveWindow(frame);
2072         DeprecatedString dstUrl = p->loader()->completeURL(DeprecatedString(args[0]->toString(exec))).url();
2073         if (!dstUrl.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
2074             bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2075             // We want a new history item if this JS was called via a user gesture
2076             frame->loader()->scheduleLocationChange(dstUrl, p->loader()->outgoingReferrer(), false, userGesture);
2077         }
2078     }
2079
2080     return jsUndefined();
2081 }
2082
2083 JSValue* LocationProtoFuncToString::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
2084 {
2085     if (!thisObj->inherits(&Location::info))
2086         return throwError(exec, TypeError);
2087     Location* location = static_cast<Location*>(thisObj);
2088     Frame* frame = location->frame();
2089     if (!frame)
2090         return jsUndefined();
2091
2092     Window* window = Window::retrieveWindow(frame);
2093     if (!window->isSafeScript(exec))
2094         return jsUndefined();
2095
2096     if (!frame || !Window::retrieveWindow(frame)->isSafeScript(exec))
2097         return jsString();
2098
2099     if (!frame->loader()->url().hasPath())
2100         return jsString(frame->loader()->url().prettyURL() + "/");
2101     return jsString(frame->loader()->url().prettyURL());
2102 }
2103
2104 /////////////////////////////////////////////////////////////////////////////
2105
2106 PausedTimeouts::~PausedTimeouts()
2107 {
2108     PausedTimeout *array = m_array;
2109     if (!array)
2110         return;
2111     size_t count = m_length;
2112     for (size_t i = 0; i != count; ++i)
2113         delete array[i].action;
2114     delete [] array;
2115 }
2116
2117 void DOMWindowTimer::fired()
2118 {
2119     timerNestingLevel = m_nestingLevel;
2120     m_object->timerFired(this);
2121     timerNestingLevel = 0;
2122 }
2123
2124 } // namespace KJS
2125
2126 using namespace KJS;
2127
2128 namespace WebCore {
2129
2130 JSValue* toJS(ExecState*, DOMWindow* domWindow)
2131 {
2132     if (!domWindow)
2133         return jsNull();
2134     Frame* frame = domWindow->frame();
2135     if (!frame)
2136         return jsNull();
2137     return Window::retrieve(frame);
2138 }
2139     
2140 } // namespace WebCore