bdcd39297cc49aafc6fb6a017eb88e6a07b75475
[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                  Window::AToB                DontDelete|Function 1
156   btoa                  Window::BToA                DontDelete|Function 1
157   scroll                Window::Scroll              DontDelete|Function 2
158   scrollBy              Window::ScrollBy            DontDelete|Function 2
159   scrollTo              Window::ScrollTo            DontDelete|Function 2
160   moveBy                Window::MoveBy              DontDelete|Function 2
161   moveTo                Window::MoveTo              DontDelete|Function 2
162   resizeBy              Window::ResizeBy            DontDelete|Function 2
163   resizeTo              Window::ResizeTo            DontDelete|Function 2
164   open                  Window::Open                DontDelete|Function 3
165   setTimeout            Window::SetTimeout          DontDelete|Function 2
166   clearTimeout          Window::ClearTimeout        DontDelete|Function 1
167   setInterval           Window::SetInterval         DontDelete|Function 2
168   clearInterval         Window::ClearInterval       DontDelete|Function 1
169   captureEvents         Window::CaptureEvents       DontDelete|Function 0
170   releaseEvents         Window::ReleaseEvents       DontDelete|Function 0
171   addEventListener      Window::AddEventListener    DontDelete|Function 3
172   removeEventListener   Window::RemoveEventListener DontDelete|Function 3
173   showModalDialog       Window::ShowModalDialog     DontDelete|Function 1
174 # -- Attributes --
175   crypto                Window::Crypto              DontDelete|ReadOnly
176   event                 Window::Event_              DontDelete
177   location              Window::Location_           DontDelete
178   navigator             Window::Navigator_          DontDelete|ReadOnly
179   clientInformation     Window::ClientInformation   DontDelete|ReadOnly
180 # -- Event Listeners --
181   onabort               Window::Onabort             DontDelete
182   onblur                Window::Onblur              DontDelete
183   onchange              Window::Onchange            DontDelete
184   onclick               Window::Onclick             DontDelete
185   ondblclick            Window::Ondblclick          DontDelete
186   onerror               Window::Onerror             DontDelete
187   onfocus               Window::Onfocus             DontDelete
188   onkeydown             Window::Onkeydown           DontDelete
189   onkeypress            Window::Onkeypress          DontDelete
190   onkeyup               Window::Onkeyup             DontDelete
191   onload                Window::Onload              DontDelete
192   onmousedown           Window::Onmousedown         DontDelete
193   onmousemove           Window::Onmousemove         DontDelete
194   onmouseout            Window::Onmouseout          DontDelete
195   onmouseover           Window::Onmouseover         DontDelete
196   onmouseup             Window::Onmouseup           DontDelete
197   onmousewheel          Window::OnWindowMouseWheel  DontDelete
198   onreset               Window::Onreset             DontDelete
199   onresize              Window::Onresize            DontDelete
200   onscroll              Window::Onscroll            DontDelete
201   onsearch              Window::Onsearch            DontDelete
202   onselect              Window::Onselect            DontDelete
203   onsubmit              Window::Onsubmit            DontDelete
204   onunload              Window::Onunload            DontDelete
205   onbeforeunload        Window::Onbeforeunload      DontDelete
206 # -- Constructors --
207   Audio                 Window::Audio               DontDelete
208   DOMException          Window::DOMException        DontDelete
209   Image                 Window::Image               DontDelete
210   Option                Window::Option              DontDelete
211   XMLHttpRequest        Window::XMLHttpRequest      DontDelete
212   XSLTProcessor         Window::XSLTProcessor_      DontDelete
213 @end
214 */
215
216 Window::Window(DOMWindow* window)
217   : m_impl(window)
218   , d(new WindowPrivate)
219 {
220     // Window destruction is not thread-safe because of
221     // the non-thread-safe WebCore structures it references.
222     Collector::collectOnMainThreadOnly(this);
223 }
224
225 Window::~Window()
226 {
227     clearAllTimeouts();
228
229     // Clear any backpointers to the window
230
231     ListenersMap::iterator i2 = d->jsEventListeners.begin();
232     ListenersMap::iterator e2 = d->jsEventListeners.end();
233     for (; i2 != e2; ++i2)
234         i2->second->clearWindowObj();
235     i2 = d->jsHTMLEventListeners.begin();
236     e2 = d->jsHTMLEventListeners.end();
237     for (; i2 != e2; ++i2)
238         i2->second->clearWindowObj();
239
240     UnprotectedListenersMap::iterator i1 = d->jsUnprotectedEventListeners.begin();
241     UnprotectedListenersMap::iterator e1 = d->jsUnprotectedEventListeners.end();
242     for (; i1 != e1; ++i1)
243         i1->second->clearWindowObj();
244     i1 = d->jsUnprotectedHTMLEventListeners.begin();
245     e1 = d->jsUnprotectedHTMLEventListeners.end();
246     for (; i1 != e1; ++i1)
247         i1->second->clearWindowObj();
248 }
249
250 ScriptInterpreter* Window::interpreter() const
251 {
252     Frame* frame = impl()->frame();
253     if (!frame)
254         return 0;
255
256     return frame->scriptProxy()->interpreter();
257 }
258
259 Window *Window::retrieveWindow(Frame *f)
260 {
261     JSObject *o = retrieve(f)->getObject();
262
263     ASSERT(o || !f->settings() || !f->settings()->isJavaScriptEnabled());
264     return static_cast<Window *>(o);
265 }
266
267 Window *Window::retrieveActive(ExecState *exec)
268 {
269     JSValue *imp = exec->dynamicInterpreter()->globalObject();
270     ASSERT(imp);
271     return static_cast<Window*>(imp);
272 }
273
274 JSValue *Window::retrieve(Frame *p)
275 {
276     ASSERT(p);
277     if (KJSProxy *proxy = p->scriptProxy())
278         return proxy->interpreter()->globalObject(); // the Global object is the "window"
279   
280     return jsUndefined(); // This can happen with JS disabled on the domain of that window
281 }
282
283 Location *Window::location() const
284 {
285   if (!d->loc)
286     d->loc = new Location(impl()->frame());
287   return d->loc;
288 }
289
290 // reference our special objects during garbage collection
291 void Window::mark()
292 {
293   JSObject::mark();
294   if (d->loc && !d->loc->marked())
295     d->loc->mark();
296 }
297
298 static bool allowPopUp(ExecState *exec, Window *window)
299 {
300     Frame* frame = window->impl()->frame();
301     if (!frame)
302         return false;
303     if (static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->wasRunByUserGesture())
304         return true;
305     Settings* settings = frame->settings();
306     return settings && settings->JavaScriptCanOpenWindowsAutomatically();
307 }
308
309 static HashMap<String, String> parseModalDialogFeatures(ExecState *exec, JSValue *featuresArg)
310 {
311     HashMap<String, String> map;
312
313     Vector<String> features = valueToStringWithUndefinedOrNullCheck(exec, featuresArg).split(';');
314     Vector<String>::const_iterator end = features.end();
315     for (Vector<String>::const_iterator it = features.begin(); it != end; ++it) {
316         String s = *it;
317         int pos = s.find('=');
318         int colonPos = s.find(':');
319         if (pos >= 0 && colonPos >= 0)
320             continue; // ignore any strings that have both = and :
321         if (pos < 0)
322             pos = colonPos;
323         if (pos < 0) {
324             // null string for value means key without value
325             map.set(s.stripWhiteSpace().lower(), String());
326         } else {
327             String key = s.left(pos).stripWhiteSpace().lower();
328             String val = s.substring(pos + 1).stripWhiteSpace().lower();
329             int spacePos = val.find(' ');
330             if (spacePos != -1)
331                 val = val.left(spacePos);
332             map.set(key, val);
333         }
334     }
335
336     return map;
337 }
338
339 static bool boolFeature(const HashMap<String, String>& features, const char* key, bool defaultValue = false)
340 {
341     HashMap<String, String>::const_iterator it = features.find(key);
342     if (it == features.end())
343         return defaultValue;
344     const String& value = it->second;
345     return value.isNull() || value == "1" || value == "yes" || value == "on";
346 }
347
348 static float floatFeature(const HashMap<String, String> &features, const char *key, float min, float max, float defaultValue)
349 {
350     HashMap<String, String>::const_iterator it = features.find(key);
351     if (it == features.end())
352         return defaultValue;
353     // FIXME: Can't distinguish "0q" from string with no digits in it -- both return d == 0 and ok == false.
354     // Would be good to tell them apart somehow since string with no digits should be default value and
355     // "0q" should be minimum value.
356     bool ok;
357     double d = it->second.toDouble(&ok);
358     if ((d == 0 && !ok) || isnan(d))
359         return defaultValue;
360     if (d < min || max <= min)
361         return min;
362     if (d > max)
363         return max;
364     return static_cast<int>(d);
365 }
366
367 static Frame* createWindow(ExecState* exec, Frame* openerFrame, const String& url,
368     const String& frameName, const WindowFeatures& windowFeatures, JSValue* dialogArgs)
369 {
370     Frame* activeFrame = Window::retrieveActive(exec)->impl()->frame();
371     
372     ResourceRequest request;
373     if (activeFrame)
374         request.setHTTPReferrer(activeFrame->loader()->outgoingReferrer());
375     FrameLoadRequest frameRequest(request, frameName);
376
377     // FIXME: It's much better for client API if a new window starts with a URL, here where we
378     // know what URL we are going to open. Unfortunately, this code passes the empty string
379     // for the URL, but there's a reason for that. Before loading we have to set up the opener,
380     // openedByDOM, and dialogArguments values. Also, to decide whether to use the URL we currently
381     // do an isSafeScript call using the window we create, which can't be done before creating it.
382     // We'd have to resolve all those issues to pass the URL instead of "".
383
384     bool created;
385     Frame* newFrame = openerFrame->loader()->createWindow(frameRequest, windowFeatures, created);
386     if (!newFrame)
387         return 0;
388
389     newFrame->loader()->setOpener(openerFrame);
390     newFrame->loader()->setOpenedByDOM();
391
392     Window* newWindow = Window::retrieveWindow(newFrame);    
393     
394     if (dialogArgs)
395         newWindow->putDirect("dialogArguments", dialogArgs);
396
397     if (!url.startsWith("javascript:", false) || newWindow->isSafeScript(exec)) {
398         String completedURL = url.isEmpty() ? url : activeFrame->document()->completeURL(url);
399         bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
400         
401         if (created) {
402             newFrame->loader()->changeLocation(KURL(completedURL.deprecatedString()), activeFrame->loader()->outgoingReferrer(), false, userGesture);
403             if (Document* oldDoc = openerFrame->document()) {
404                 newFrame->document()->setDomainInternal(oldDoc->domain());
405                 newFrame->document()->setBaseURL(oldDoc->baseURL());
406             }
407         } else if (!url.isEmpty())
408             newFrame->loader()->scheduleLocationChange(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture);
409     }
410     
411     return newFrame;
412 }
413
414 static bool canShowModalDialog(const Window *window)
415 {
416     Frame* frame = window->impl()->frame();
417     if (!frame)
418         return false;
419
420     return frame->page()->chrome()->canRunModal();
421 }
422
423 static bool canShowModalDialogNow(const Window *window)
424 {
425     Frame* frame = window->impl()->frame();
426     if (!frame)
427         return false;
428
429     return frame->page()->chrome()->canRunModalNow();
430 }
431
432 static JSValue* showModalDialog(ExecState* exec, Window* openerWindow, const List& args)
433 {
434     if (!canShowModalDialogNow(openerWindow) || !allowPopUp(exec, openerWindow))
435         return jsUndefined();
436
437     const HashMap<String, String> features = parseModalDialogFeatures(exec, args[2]);
438
439     bool trusted = false;
440
441     WindowFeatures wargs;
442
443     // The following features from Microsoft's documentation are not implemented:
444     // - default font settings
445     // - width, height, left, and top specified in units other than "px"
446     // - edge (sunken or raised, default is raised)
447     // - dialogHide: trusted && boolFeature(features, "dialoghide"), makes dialog hide when you print
448     // - help: boolFeature(features, "help", true), makes help icon appear in dialog (what does it do on Windows?)
449     // - unadorned: trusted && boolFeature(features, "unadorned");
450     Frame* frame = openerWindow->impl()->frame();
451     if (!frame)
452         return jsUndefined();
453
454     FloatRect screenRect = screenAvailableRect(frame->view());
455
456     wargs.width = floatFeature(features, "dialogwidth", 100, screenRect.width(), 620); // default here came from frame size of dialog in MacIE
457     wargs.widthSet = true;
458     wargs.height = floatFeature(features, "dialogheight", 100, screenRect.height(), 450); // default here came from frame size of dialog in MacIE
459     wargs.heightSet = true;
460
461     wargs.x = floatFeature(features, "dialogleft", screenRect.x(), screenRect.right() - wargs.width, -1);
462     wargs.xSet = wargs.x > 0;
463     wargs.y = floatFeature(features, "dialogtop", screenRect.y(), screenRect.bottom() - wargs.height, -1);
464     wargs.ySet = wargs.y > 0;
465
466     if (boolFeature(features, "center", true)) {
467         if (!wargs.xSet) {
468             wargs.x = screenRect.x() + (screenRect.width() - wargs.width) / 2;
469             wargs.xSet = true;
470         }
471         if (!wargs.ySet) {
472             wargs.y = screenRect.y() + (screenRect.height() - wargs.height) / 2;
473             wargs.ySet = true;
474         }
475     }
476
477     wargs.dialog = true;
478     wargs.resizable = boolFeature(features, "resizable");
479     wargs.scrollbarsVisible = boolFeature(features, "scroll", true);
480     wargs.statusBarVisible = boolFeature(features, "status", !trusted);
481     wargs.menuBarVisible = false;
482     wargs.toolBarVisible = false;
483     wargs.locationBarVisible = false;
484     wargs.fullscreen = false;
485     
486     Frame* dialogFrame = createWindow(exec, frame, valueToStringWithUndefinedOrNullCheck(exec, args[0]), "", wargs, args[1]);
487     if (!dialogFrame)
488         return jsUndefined();
489
490     Window* dialogWindow = Window::retrieveWindow(dialogFrame);
491
492     // Get the return value either just before clearing the dialog window's
493     // properties (in Window::clear), or when on return from runModal.
494     JSValue* returnValue = 0;
495     dialogWindow->setReturnValueSlot(&returnValue);
496     dialogFrame->page()->chrome()->runModal();
497     dialogWindow->setReturnValueSlot(0);
498
499     // If we don't have a return value, get it now.
500     // Either Window::clear was not called yet, or there was no return value,
501     // and in that case, there's no harm in trying again (no benefit either).
502     if (!returnValue)
503         returnValue = dialogWindow->getDirect("returnValue");
504
505     return returnValue ? returnValue : jsUndefined();
506 }
507
508 JSValue *Window::getValueProperty(ExecState *exec, int token) const
509 {
510    ASSERT(impl()->frame());
511
512    switch (token) {
513    case Crypto:
514       if (!isSafeScript(exec))
515         return jsUndefined();
516       return jsUndefined(); // FIXME: implement this
517    case DOMException:
518       if (!isSafeScript(exec))
519         return jsUndefined();
520       return getDOMExceptionConstructor(exec);
521     case Event_:
522       if (!isSafeScript(exec))
523         return jsUndefined();
524       if (!d->m_evt)
525         return jsUndefined();
526       return toJS(exec, d->m_evt);
527     case Location_:
528       return location();
529     case Navigator_:
530     case ClientInformation: {
531       if (!isSafeScript(exec))
532         return jsUndefined();
533       // Store the navigator in the object so we get the same one each time.
534       Navigator *n = new Navigator(exec, impl()->frame());
535       // FIXME: this will make the "navigator" object accessible from windows that fail
536       // the security check the first time, but not subsequent times, seems weird.
537       const_cast<Window *>(this)->putDirect("navigator", n, DontDelete|ReadOnly);
538       const_cast<Window *>(this)->putDirect("clientInformation", n, DontDelete|ReadOnly);
539       return n;
540     }
541     case Image:
542       if (!isSafeScript(exec))
543         return jsUndefined();
544       // FIXME: this property (and the few below) probably shouldn't create a new object every
545       // time
546       return new ImageConstructorImp(exec, impl()->frame()->document());
547     case Option:
548       if (!isSafeScript(exec))
549         return jsUndefined();
550       return new JSHTMLOptionElementConstructor(exec, impl()->frame()->document());
551     case XMLHttpRequest:
552       if (!isSafeScript(exec))
553         return jsUndefined();
554       return new JSXMLHttpRequestConstructorImp(exec, impl()->frame()->document());
555     case Audio:
556 #if ENABLE(VIDEO)
557       return new JSHTMLAudioElementConstructor(exec, impl()->frame()->document());
558 #else
559       return jsUndefined();
560 #endif
561 #if ENABLE(XSLT)
562     case XSLTProcessor_:
563       if (!isSafeScript(exec))
564         return jsUndefined();
565       return new XSLTProcessorConstructorImp(exec);
566 #else
567     case XSLTProcessor_:
568       return jsUndefined();
569 #endif
570    }
571
572    if (!isSafeScript(exec))
573      return jsUndefined();
574
575    switch (token) {
576    case Onabort:
577      return getListener(exec, abortEvent);
578    case Onblur:
579      return getListener(exec, blurEvent);
580    case Onchange:
581      return getListener(exec, changeEvent);
582    case Onclick:
583      return getListener(exec, clickEvent);
584    case Ondblclick:
585      return getListener(exec, dblclickEvent);
586    case Onerror:
587      return getListener(exec, errorEvent);
588    case Onfocus:
589      return getListener(exec, focusEvent);
590    case Onkeydown:
591      return getListener(exec, keydownEvent);
592    case Onkeypress:
593      return getListener(exec, keypressEvent);
594    case Onkeyup:
595      return getListener(exec, keyupEvent);
596    case Onload:
597      return getListener(exec, loadEvent);
598    case Onmousedown:
599      return getListener(exec, mousedownEvent);
600    case Onmousemove:
601      return getListener(exec, mousemoveEvent);
602    case Onmouseout:
603      return getListener(exec, mouseoutEvent);
604    case Onmouseover:
605      return getListener(exec, mouseoverEvent);
606    case Onmouseup:
607      return getListener(exec, mouseupEvent);
608    case OnWindowMouseWheel:
609      return getListener(exec, mousewheelEvent);
610    case Onreset:
611      return getListener(exec, resetEvent);
612    case Onresize:
613      return getListener(exec,resizeEvent);
614    case Onscroll:
615      return getListener(exec,scrollEvent);
616    case Onsearch:
617      return getListener(exec,searchEvent);
618    case Onselect:
619      return getListener(exec,selectEvent);
620    case Onsubmit:
621      return getListener(exec,submitEvent);
622    case Onbeforeunload:
623       return getListener(exec, beforeunloadEvent);
624     case Onunload:
625      return getListener(exec, unloadEvent);
626    }
627    ASSERT(0);
628    return jsUndefined();
629 }
630
631 JSValue* Window::childFrameGetter(ExecState*, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
632 {
633     return retrieve(static_cast<Window*>(slot.slotBase())->impl()->frame()->tree()->child(AtomicString(propertyName)));
634 }
635
636 JSValue* Window::indexGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
637 {
638     return retrieve(static_cast<Window*>(slot.slotBase())->impl()->frame()->tree()->child(slot.index()));
639 }
640
641 JSValue *Window::namedItemGetter(ExecState *exec, JSObject *originalObject, const Identifier& propertyName, const PropertySlot& slot)
642 {
643   Window *thisObj = static_cast<Window *>(slot.slotBase());
644   Document *doc = thisObj->impl()->frame()->document();
645   ASSERT(thisObj->isSafeScript(exec) && doc && doc->isHTMLDocument());
646
647   String name = propertyName;
648   RefPtr<WebCore::HTMLCollection> collection = doc->windowNamedItems(name);
649   if (collection->length() == 1)
650     return toJS(exec, collection->firstItem());
651   return toJS(exec, collection.get());
652 }
653
654 bool Window::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
655 {
656   // Check for child frames by name before built-in properties to
657   // match Mozilla. This does not match IE, but some sites end up
658   // naming frames things that conflict with window properties that
659   // are in Moz but not IE. Since we have some of these, we have to do
660   // it the Moz way.
661   if (impl()->frame()->tree()->child(propertyName)) {
662     slot.setCustom(this, childFrameGetter);
663     return true;
664   }
665
666   const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName);
667   if (entry) {
668     if (entry->attr & Function) {
669       switch (entry->value) {
670       case ShowModalDialog:
671         if (!canShowModalDialog(this))
672           return false;
673         // fall through
674       default:
675         if (isSafeScript(exec))
676           slot.setStaticEntry(this, entry, staticFunctionGetter<WindowFunc>);
677         else
678           slot.setUndefined(this);
679       } 
680     } else
681       slot.setStaticEntry(this, entry, staticValueGetter<Window>);
682     return true;
683   }
684
685   // FIXME: Search the whole frame hierachy somewhere around here.
686   // We need to test the correct priority order.
687   
688   // allow window[1] or parent[1] etc. (#56983)
689   bool ok;
690   unsigned i = propertyName.toArrayIndex(&ok);
691   if (ok && i < impl()->frame()->tree()->childCount()) {
692     slot.setCustomIndex(this, i, indexGetter);
693     return true;
694   }
695
696   // allow shortcuts like 'Image1' instead of document.images.Image1
697   Document* doc = impl()->frame()->document();
698   if (doc && doc->isHTMLDocument()) {
699     if (!isSafeScript(exec)) {
700       slot.setUndefined(this);
701       return true;
702     }
703
704     AtomicString atomicPropertyName = propertyName;
705     if (static_cast<HTMLDocument*>(doc)->hasNamedItem(atomicPropertyName) || doc->getElementById(atomicPropertyName)) {
706       slot.setCustom(this, namedItemGetter);
707       return true;
708     }
709   }
710
711   if (!isSafeScript(exec)) {
712     slot.setUndefined(this);
713     return true;
714   }
715
716   return JSObject::getOwnPropertySlot(exec, propertyName, slot);
717 }
718
719 void Window::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
720 {
721   const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName);
722   if (entry) {
723      if (entry->attr & Function) {
724        if (isSafeScript(exec))
725          JSObject::put(exec, propertyName, value, attr);
726        return;
727     }
728     if (entry->attr & ReadOnly)
729       return;
730
731     switch (entry->value) {
732     case Location_: {
733       Frame* p = Window::retrieveActive(exec)->impl()->frame();
734       if (p) {
735         DeprecatedString dstUrl = p->loader()->completeURL(DeprecatedString(value->toString(exec))).url();
736         if (!dstUrl.startsWith("javascript:", false) || isSafeScript(exec)) {
737           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
738           // We want a new history item if this JS was called via a user gesture
739           impl()->frame()->loader()->scheduleLocationChange(dstUrl, p->loader()->outgoingReferrer(), false, userGesture);
740         }
741       }
742       return;
743     }
744     case Onabort:
745       if (isSafeScript(exec))
746         setListener(exec, abortEvent,value);
747       return;
748     case Onblur:
749       if (isSafeScript(exec))
750         setListener(exec, blurEvent,value);
751       return;
752     case Onchange:
753       if (isSafeScript(exec))
754         setListener(exec, changeEvent,value);
755       return;
756     case Onclick:
757       if (isSafeScript(exec))
758         setListener(exec,clickEvent,value);
759       return;
760     case Ondblclick:
761       if (isSafeScript(exec))
762         setListener(exec, dblclickEvent,value);
763       return;
764     case Onerror:
765       if (isSafeScript(exec))
766         setListener(exec, errorEvent, value);
767       return;
768     case Onfocus:
769       if (isSafeScript(exec))
770         setListener(exec,focusEvent,value);
771       return;
772     case Onkeydown:
773       if (isSafeScript(exec))
774         setListener(exec,keydownEvent,value);
775       return;
776     case Onkeypress:
777       if (isSafeScript(exec))
778         setListener(exec,keypressEvent,value);
779       return;
780     case Onkeyup:
781       if (isSafeScript(exec))
782         setListener(exec,keyupEvent,value);
783       return;
784     case Onload:
785       if (isSafeScript(exec))
786         setListener(exec,loadEvent,value);
787       return;
788     case Onmousedown:
789       if (isSafeScript(exec))
790         setListener(exec,mousedownEvent,value);
791       return;
792     case Onmousemove:
793       if (isSafeScript(exec))
794         setListener(exec,mousemoveEvent,value);
795       return;
796     case Onmouseout:
797       if (isSafeScript(exec))
798         setListener(exec,mouseoutEvent,value);
799       return;
800     case Onmouseover:
801       if (isSafeScript(exec))
802         setListener(exec,mouseoverEvent,value);
803       return;
804     case Onmouseup:
805       if (isSafeScript(exec))
806         setListener(exec,mouseupEvent,value);
807       return;
808     case OnWindowMouseWheel:
809       if (isSafeScript(exec))
810         setListener(exec, mousewheelEvent,value);
811       return;
812     case Onreset:
813       if (isSafeScript(exec))
814         setListener(exec,resetEvent,value);
815       return;
816     case Onresize:
817       if (isSafeScript(exec))
818         setListener(exec,resizeEvent,value);
819       return;
820     case Onscroll:
821       if (isSafeScript(exec))
822         setListener(exec,scrollEvent,value);
823       return;
824     case Onsearch:
825         if (isSafeScript(exec))
826             setListener(exec,searchEvent,value);
827         return;
828     case Onselect:
829       if (isSafeScript(exec))
830         setListener(exec,selectEvent,value);
831       return;
832     case Onsubmit:
833       if (isSafeScript(exec))
834         setListener(exec,submitEvent,value);
835       return;
836     case Onbeforeunload:
837       if (isSafeScript(exec))
838         setListener(exec, beforeunloadEvent, value);
839       return;
840     case Onunload:
841       if (isSafeScript(exec))
842         setListener(exec, unloadEvent, value);
843       return;
844     default:
845       break;
846     }
847   }
848   if (isSafeScript(exec))
849     JSObject::put(exec, propertyName, value, attr);
850 }
851
852 static bool shouldLoadAsEmptyDocument(const KURL &url)
853 {
854   return url.protocol().lower() == "about" || url.isEmpty();
855 }
856
857 bool Window::isSafeScript(const ScriptInterpreter *origin, const ScriptInterpreter *target)
858 {
859     if (origin == target)
860         return true;
861         
862     Frame* originFrame = origin->frame();
863     Frame* targetFrame = target->frame();
864
865     // JS may be attempting to access the "window" object, which should be valid,
866     // even if the document hasn't been constructed yet.  If the document doesn't
867     // exist yet allow JS to access the window object.
868     if (!targetFrame->document())
869         return true;
870
871     WebCore::Document *originDocument = originFrame->document();
872     WebCore::Document *targetDocument = targetFrame->document();
873
874     if (!targetDocument) {
875         return false;
876     }
877
878     WebCore::String targetDomain = targetDocument->domain();
879
880     // Always allow local pages to execute any JS.
881     if (targetDomain.isNull())
882         return true;
883
884     WebCore::String originDomain = originDocument->domain();
885
886     // if this document is being initially loaded as empty by its parent
887     // or opener, allow access from any document in the same domain as
888     // the parent or opener.
889     if (shouldLoadAsEmptyDocument(targetFrame->loader()->url())) {
890         Frame* ancestorFrame = targetFrame->loader()->opener() ? targetFrame->loader()->opener() : targetFrame->tree()->parent();
891         while (ancestorFrame && shouldLoadAsEmptyDocument(ancestorFrame->loader()->url()))
892             ancestorFrame = ancestorFrame->tree()->parent();
893         if (ancestorFrame)
894             originDomain = ancestorFrame->document()->domain();
895     }
896
897     if ( targetDomain == originDomain )
898         return true;
899
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     }
904     String message = String::format("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
905                   targetDocument->URL().latin1(), originDocument->URL().latin1());
906     if (Page* page = targetFrame->page())
907         page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, 1, String()); // FIXME: provide a real line number and source URL.
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 *WindowFunc::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   FrameView *widget = frame->view();
1246   Page* page = frame->page();
1247   JSValue *v = args[0];
1248   UString s = v->toString(exec);
1249   String str = s;
1250   String str2;
1251
1252   switch (id) {
1253   case Window::AToB:
1254   case Window::BToA: {
1255     if (args.size() < 1)
1256         return throwError(exec, SyntaxError, "Not enough arguments");
1257     if (v->isNull())
1258         return jsString();
1259     if (!s.is8Bit()) {
1260         setDOMException(exec, INVALID_CHARACTER_ERR);
1261         return jsUndefined();
1262     }
1263     
1264     Vector<char> in(s.size());
1265     for (int i = 0; i < s.size(); ++i)
1266         in[i] = static_cast<char>(s.data()[i].unicode());
1267     Vector<char> out;
1268
1269     if (id == Window::AToB) {
1270         if (!base64Decode(in, out))
1271             return throwError(exec, GeneralError, "Cannot decode base64");
1272     } else
1273         base64Encode(in, out);
1274     
1275     return jsString(String(out.data(), out.size()));
1276   }
1277   case Window::Open:
1278   {
1279       String urlString = valueToStringWithUndefinedOrNullCheck(exec, args[0]);
1280       AtomicString frameName = args[1]->isUndefinedOrNull() ? "_blank" : AtomicString(args[1]->toString(exec));
1281
1282       // Because FrameTree::find() returns true for empty strings, we must check for empty framenames.
1283       // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
1284       if (!allowPopUp(exec, window) && (frameName.isEmpty() || !frame->tree()->find(frameName)))
1285           return jsUndefined();
1286       
1287       // Get the target frame for the special cases of _top and _parent
1288       if (frameName == "_top")
1289           while (frame->tree()->parent())
1290                 frame = frame->tree()->parent();
1291       else if (frameName == "_parent")
1292           if (frame->tree()->parent())
1293               frame = frame->tree()->parent();
1294               
1295       // In those cases, we can schedule a location change right now and return early
1296       if (frameName == "_top" || frameName == "_parent") {
1297           String completedURL;
1298           Frame* activeFrame = Window::retrieveActive(exec)->impl()->frame();
1299           if (!urlString.isEmpty() && activeFrame)
1300               completedURL = activeFrame->document()->completeURL(urlString);
1301
1302           const Window* window = Window::retrieveWindow(frame);
1303           if (!completedURL.isEmpty() && (!completedURL.startsWith("javascript:", false) || (window && window->isSafeScript(exec)))) {
1304               bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1305               frame->loader()->scheduleLocationChange(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture);
1306           }
1307           return Window::retrieve(frame);
1308       }
1309       
1310       // In the case of a named frame or a new window, we'll use the createWindow() helper
1311       WindowFeatures windowFeatures;
1312       String features = valueToStringWithUndefinedOrNullCheck(exec, args[2]);
1313       parseWindowFeatures(features, windowFeatures);
1314       FloatRect windowRect(windowFeatures.x, windowFeatures.y, windowFeatures.width, windowFeatures.height);
1315       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), windowRect, windowRect);
1316
1317       windowFeatures.x = windowRect.x();
1318       windowFeatures.y = windowRect.y();
1319       windowFeatures.height = windowRect.height();
1320       windowFeatures.width = windowRect.width();
1321
1322       frame = createWindow(exec, frame, urlString, frameName, windowFeatures, 0);
1323
1324       if (!frame)
1325           return jsUndefined();
1326
1327       return Window::retrieve(frame); // global object
1328   }
1329   case Window::ScrollBy:
1330     window->updateLayout();
1331     if(args.size() >= 2 && widget)
1332       widget->scrollBy(args[0]->toInt32(exec), args[1]->toInt32(exec));
1333     return jsUndefined();
1334   case Window::Scroll:
1335   case Window::ScrollTo:
1336     window->updateLayout();
1337     if (args.size() >= 2 && widget)
1338       widget->setContentsPos(args[0]->toInt32(exec), args[1]->toInt32(exec));
1339     return jsUndefined();
1340   case Window::MoveBy:
1341     if (args.size() >= 2 && page) {
1342       FloatRect fr = page->chrome()->windowRect();
1343       FloatRect update = fr;
1344       update.move(args[0]->toFloat(exec), args[1]->toFloat(exec));
1345       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1346       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1347       page->chrome()->setWindowRect(fr);
1348     }
1349     return jsUndefined();
1350   case Window::MoveTo:
1351     if (args.size() >= 2 && page) {
1352       FloatRect fr = page->chrome()->windowRect();
1353       FloatRect sr = screenAvailableRect(page->mainFrame()->view());
1354       fr.setLocation(sr.location());
1355       FloatRect update = fr;
1356       update.move(args[0]->toFloat(exec), args[1]->toFloat(exec));     
1357       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1358       adjustWindowRect(sr, fr, update);
1359       page->chrome()->setWindowRect(fr);
1360     }
1361     return jsUndefined();
1362   case Window::ResizeBy:
1363     if (args.size() >= 2 && page) {
1364       FloatRect fr = page->chrome()->windowRect();
1365       FloatSize dest = fr.size() + FloatSize(args[0]->toFloat(exec), args[1]->toFloat(exec));
1366       FloatRect update(fr.location(), dest);
1367       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1368       page->chrome()->setWindowRect(fr);
1369     }
1370     return jsUndefined();
1371   case Window::ResizeTo:
1372     if (args.size() >= 2 && page) {
1373       FloatRect fr = page->chrome()->windowRect();
1374       FloatSize dest = FloatSize(args[0]->toFloat(exec), args[1]->toFloat(exec));
1375       FloatRect update(fr.location(), dest);
1376       adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
1377       page->chrome()->setWindowRect(fr);
1378     }
1379     return jsUndefined();
1380   case Window::SetTimeout:
1381     if (!window->isSafeScript(exec))
1382         return jsUndefined();
1383     if (v->isString()) {
1384       int i = args[1]->toInt32(exec);
1385       int r = (const_cast<Window*>(window))->installTimeout(s, i, true /*single shot*/);
1386       return jsNumber(r);
1387     }
1388     else if (v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1389       JSValue *func = args[0];
1390       int i = args[1]->toInt32(exec);
1391       
1392       List argsTail;
1393       args.slice(2, argsTail);
1394
1395       int r = (const_cast<Window*>(window))->installTimeout(func, argsTail, i, true /*single shot*/);
1396       return jsNumber(r);
1397     }
1398     else
1399       return jsUndefined();
1400   case Window::SetInterval:
1401     if (!window->isSafeScript(exec))
1402         return jsUndefined();
1403     if (args.size() >= 2 && v->isString()) {
1404       int i = args[1]->toInt32(exec);
1405       int r = (const_cast<Window*>(window))->installTimeout(s, i, false);
1406       return jsNumber(r);
1407     }
1408     else if (args.size() >= 2 && v->isObject() && static_cast<JSObject *>(v)->implementsCall()) {
1409       JSValue *func = args[0];
1410       int i = args[1]->toInt32(exec);
1411
1412       List argsTail;
1413       args.slice(2, argsTail);
1414
1415       int r = (const_cast<Window*>(window))->installTimeout(func, argsTail, i, false);
1416       return jsNumber(r);
1417     }
1418     else
1419       return jsUndefined();
1420   case Window::ClearTimeout:
1421   case Window::ClearInterval:
1422     if (!window->isSafeScript(exec))
1423         return jsUndefined();
1424     (const_cast<Window*>(window))->clearTimeout(v->toInt32(exec));
1425     return jsUndefined();
1426   case Window::CaptureEvents:
1427   case Window::ReleaseEvents:
1428     // If anyone implements these, they need the safe script security check.
1429     if (!window->isSafeScript(exec))
1430         return jsUndefined();
1431     // Not implemented.
1432     return jsUndefined();
1433   case Window::AddEventListener:
1434         if (!window->isSafeScript(exec))
1435             return jsUndefined();
1436         if (JSEventListener* listener = window->findOrCreateJSEventListener(args[1]))
1437             if (Document *doc = frame->document())
1438                 doc->addWindowEventListener(AtomicString(args[0]->toString(exec)), listener, args[2]->toBoolean(exec));
1439         return jsUndefined();
1440   case Window::RemoveEventListener:
1441         if (!window->isSafeScript(exec))
1442             return jsUndefined();
1443         if (JSEventListener* listener = window->findJSEventListener(args[1]))
1444             if (Document *doc = frame->document())
1445                 doc->removeWindowEventListener(AtomicString(args[0]->toString(exec)), listener, args[2]->toBoolean(exec));
1446         return jsUndefined();
1447   case Window::ShowModalDialog: {
1448     JSValue* result = showModalDialog(exec, window, args);
1449     return result;
1450   }
1451   }
1452   return jsUndefined();
1453 }
1454
1455 void Window::updateLayout() const
1456 {
1457   Frame* frame = impl()->frame();
1458   if (!frame)
1459     return;
1460   WebCore::Document* docimpl = frame->document();
1461   if (docimpl)
1462     docimpl->updateLayoutIgnorePendingStylesheets();
1463 }
1464
1465 void Window::setReturnValueSlot(JSValue** slot)
1466
1467     d->m_returnValueSlot = slot; 
1468 }
1469
1470 ////////////////////// ScheduledAction ////////////////////////
1471
1472 void ScheduledAction::execute(Window* window)
1473 {
1474     RefPtr<Frame> frame = window->impl()->frame();
1475     if (!frame)
1476         return;
1477
1478     KJSProxy* scriptProxy = frame->scriptProxy();
1479     if (!scriptProxy)
1480         return;
1481
1482     RefPtr<ScriptInterpreter> interpreter = scriptProxy->interpreter();
1483
1484     interpreter->setProcessingTimerCallback(true);
1485
1486     if (JSValue* func = m_func.get()) {
1487         JSLock lock;
1488         if (func->isObject() && static_cast<JSObject*>(func)->implementsCall()) {
1489             ExecState* exec = interpreter->globalExec();
1490             ASSERT(window == interpreter->globalObject());
1491             
1492             List args;
1493             size_t size = m_args.size();
1494             for (size_t i = 0; i < size; ++i) {
1495                 args.append(m_args[i]);
1496             }
1497
1498             interpreter->startTimeoutCheck();
1499             static_cast<JSObject*>(func)->call(exec, window, args);
1500             interpreter->stopTimeoutCheck();
1501             if (exec->hadException()) {
1502                 JSObject* exception = exec->exception()->toObject(exec);
1503                 exec->clearException();
1504                 String message = exception->get(exec, exec->propertyNames().message)->toString(exec);
1505                 int lineNumber = exception->get(exec, "line")->toInt32(exec);
1506                 if (Interpreter::shouldPrintExceptions())
1507                     printf("(timer):%s\n", message.utf8().data());
1508                 if (Page* page = frame->page())
1509                     page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, lineNumber, String());
1510             }
1511         }
1512     } else
1513         frame->loader()->executeScript(m_code);
1514
1515     // Update our document's rendering following the execution of the timeout callback.
1516     // FIXME: Why not use updateDocumentsRendering to update rendering of all documents?
1517     // FIXME: Is this really the right point to do the update? We need a place that works
1518     // for all possible entry points that might possibly execute script, but this seems
1519     // to be a bit too low-level.
1520     if (Document* doc = frame->document())
1521         doc->updateRendering();
1522   
1523     interpreter->setProcessingTimerCallback(false);
1524 }
1525
1526 ////////////////////// timeouts ////////////////////////
1527
1528 void Window::clearAllTimeouts()
1529 {
1530     deleteAllValues(d->m_timeouts);
1531     d->m_timeouts.clear();
1532 }
1533
1534 int Window::installTimeout(ScheduledAction* a, int t, bool singleShot)
1535 {
1536     int timeoutId = ++lastUsedTimeoutId;
1537
1538     // avoid wraparound going negative on us
1539     if (timeoutId <= 0)
1540         timeoutId = 1;
1541
1542     int nestLevel = timerNestingLevel + 1;
1543     DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, nestLevel, this, a);
1544     ASSERT(!d->m_timeouts.get(timeoutId));
1545     d->m_timeouts.set(timeoutId, timer);
1546     // Use a minimum interval of 10 ms to match other browsers, but only once we've
1547     // nested enough to notice that we're repeating.
1548     // Faster timers might be "better", but they're incompatible.
1549     double interval = max(0.001, t * 0.001);
1550     if (interval < cMinimumTimerInterval && nestLevel >= cMaxTimerNestingLevel)
1551         interval = cMinimumTimerInterval;
1552     if (singleShot)
1553         timer->startOneShot(interval);
1554     else
1555         timer->startRepeating(interval);
1556     return timeoutId;
1557 }
1558
1559 ScheduledAction::ScheduledAction(JSValue* func, const List& args)
1560     : m_func(func)
1561 {
1562     ListIterator it = args.begin();
1563     ListIterator end = args.end();
1564     while (it != end)
1565         m_args.append(*it);
1566 }
1567
1568 int Window::installTimeout(const UString& handler, int t, bool singleShot)
1569 {
1570     return installTimeout(new ScheduledAction(handler), t, singleShot);
1571 }
1572
1573 int Window::installTimeout(JSValue* func, const List& args, int t, bool singleShot)
1574 {
1575     return installTimeout(new ScheduledAction(func, args), t, singleShot);
1576 }
1577
1578 PausedTimeouts* Window::pauseTimeouts()
1579 {
1580     size_t count = d->m_timeouts.size();
1581     if (count == 0)
1582         return 0;
1583
1584     PausedTimeout* t = new PausedTimeout [count];
1585     PausedTimeouts* result = new PausedTimeouts(t, count);
1586
1587     WindowPrivate::TimeoutsMap::iterator it = d->m_timeouts.begin();
1588     for (size_t i = 0; i != count; ++i, ++it) {
1589         int timeoutId = it->first;
1590         DOMWindowTimer* timer = it->second;
1591         t[i].timeoutId = timeoutId;
1592         t[i].nestingLevel = timer->nestingLevel();
1593         t[i].nextFireInterval = timer->nextFireInterval();
1594         t[i].repeatInterval = timer->repeatInterval();
1595         t[i].action = timer->takeAction();
1596     }
1597     ASSERT(it == d->m_timeouts.end());
1598
1599     deleteAllValues(d->m_timeouts);
1600     d->m_timeouts.clear();
1601
1602     return result;
1603 }
1604
1605 void Window::resumeTimeouts(PausedTimeouts* timeouts)
1606 {
1607     if (!timeouts)
1608         return;
1609     size_t count = timeouts->numTimeouts();
1610     PausedTimeout* array = timeouts->takeTimeouts();
1611     for (size_t i = 0; i != count; ++i) {
1612         int timeoutId = array[i].timeoutId;
1613         DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, array[i].nestingLevel, this, array[i].action);
1614         d->m_timeouts.set(timeoutId, timer);
1615         timer->start(array[i].nextFireInterval, array[i].repeatInterval);
1616     }
1617     delete [] array;
1618 }
1619
1620 void Window::clearTimeout(int timeoutId, bool delAction)
1621 {
1622     // timeout IDs have to be positive, and 0 and -1 are unsafe to
1623     // even look up since they are the empty and deleted value
1624     // respectively
1625     if (timeoutId <= 0)
1626         return;
1627
1628     delete d->m_timeouts.take(timeoutId);
1629 }
1630
1631 void Window::timerFired(DOMWindowTimer* timer)
1632 {
1633     // Simple case for non-one-shot timers.
1634     if (timer->isActive()) {
1635         int timeoutId = timer->timeoutId();
1636
1637         timer->action()->execute(this);
1638         if (d->m_timeouts.contains(timeoutId) && timer->repeatInterval() && timer->repeatInterval() < cMinimumTimerInterval) {
1639             timer->setNestingLevel(timer->nestingLevel() + 1);
1640             if (timer->nestingLevel() >= cMaxTimerNestingLevel)
1641                 timer->augmentRepeatInterval(cMinimumTimerInterval - timer->repeatInterval());
1642         }
1643         return;
1644     }
1645
1646     // Delete timer before executing the action for one-shot timers.
1647     ScheduledAction* action = timer->takeAction();
1648     d->m_timeouts.remove(timer->timeoutId());
1649     delete timer;
1650     action->execute(this);
1651     
1652     JSLock lock;
1653     delete action;
1654 }
1655
1656 void Window::disconnectFrame()
1657 {
1658     clearAllTimeouts();
1659     if (d->loc)
1660         d->loc->m_frame = 0;
1661 }
1662
1663 Window::ListenersMap& Window::jsEventListeners()
1664 {
1665     return d->jsEventListeners;
1666 }
1667
1668 Window::ListenersMap& Window::jsHTMLEventListeners()
1669 {
1670     return d->jsHTMLEventListeners;
1671 }
1672
1673 Window::UnprotectedListenersMap& Window::jsUnprotectedEventListeners()
1674 {
1675     return d->jsUnprotectedEventListeners;
1676 }
1677
1678 Window::UnprotectedListenersMap& Window::jsUnprotectedHTMLEventListeners()
1679 {
1680     return d->jsUnprotectedHTMLEventListeners;
1681 }
1682
1683 ////////////////////// Location Object ////////////////////////
1684
1685 const ClassInfo Location::info = { "Location", 0, &LocationTable };
1686 /*
1687 @begin LocationTable 12
1688   assign        Location::Assign        DontDelete|Function 1
1689   hash          Location::Hash          DontDelete
1690   host          Location::Host          DontDelete
1691   hostname      Location::Hostname      DontDelete
1692   href          Location::Href          DontDelete
1693   pathname      Location::Pathname      DontDelete
1694   port          Location::Port          DontDelete
1695   protocol      Location::Protocol      DontDelete
1696   search        Location::Search        DontDelete
1697   toString      Location::ToString      DontEnum|DontDelete|Function 0
1698   replace       Location::Replace       DontDelete|Function 1
1699   reload        Location::Reload        DontDelete|Function 0
1700 @end
1701 */
1702 KJS_IMPLEMENT_PROTOTYPE_FUNCTION(LocationFunc)
1703 Location::Location(Frame *p) : m_frame(p)
1704 {
1705 }
1706
1707 JSValue *Location::getValueProperty(ExecState *exec, int token) const
1708 {
1709   KURL url = m_frame->loader()->url();
1710   switch (token) {
1711   case Hash:
1712     return jsString(url.ref().isNull() ? "" : "#" + url.ref());
1713   case Host: {
1714     // Note: this is the IE spec. The NS spec swaps the two, it says
1715     // "The hostname property is the concatenation of the host and port properties, separated by a colon."
1716     // Bleh.
1717     UString str = url.host();
1718     if (url.port())
1719         str += ":" + String::number((int)url.port());
1720     return jsString(str);
1721   }
1722   case Hostname:
1723     return jsString(url.host());
1724   case Href:
1725     if (!url.hasPath())
1726       return jsString(url.prettyURL() + "/");
1727     return jsString(url.prettyURL());
1728   case Pathname:
1729     return jsString(url.path().isEmpty() ? "/" : url.path());
1730   case Port:
1731     return jsString(url.port() ? String::number((int)url.port()) : "");
1732   case Protocol:
1733     return jsString(url.protocol() + ":");
1734   case Search:
1735     return jsString(url.query());
1736   default:
1737     ASSERT(0);
1738     return jsUndefined();
1739   }
1740 }
1741
1742 bool Location::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) 
1743 {
1744   if (!m_frame)
1745     return false;
1746   
1747   const Window* window = Window::retrieveWindow(m_frame);
1748   
1749   const HashEntry *entry = Lookup::findEntry(&LocationTable, propertyName);
1750   if (!entry || (entry->value != Replace && entry->value != Reload && entry->value != Assign))
1751     if (!window || !window->isSafeScript(exec)) {
1752       slot.setUndefined(this);
1753       return true;
1754     }
1755
1756   return getStaticPropertySlot<LocationFunc, Location, JSObject>(exec, &LocationTable, this, propertyName, slot);
1757 }
1758
1759 void Location::put(ExecState *exec, const Identifier &p, JSValue *v, int attr)
1760 {
1761   if (!m_frame)
1762     return;
1763
1764   DeprecatedString str = v->toString(exec);
1765   KURL url = m_frame->loader()->url();
1766   const Window* window = Window::retrieveWindow(m_frame);
1767   bool sameDomainAccess = window && window->isSafeScript(exec);
1768
1769   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
1770
1771   if (entry) {
1772       // cross-domain access to the location is allowed when assigning the whole location,
1773       // but not when assigning the individual pieces, since that might inadvertently
1774       // disclose other parts of the original location.
1775       if (entry->value != Href && !sameDomainAccess)
1776           return;
1777
1778       switch (entry->value) {
1779       case Href: {
1780           Frame* frame = Window::retrieveActive(exec)->impl()->frame();
1781           if (frame)
1782               url = frame->loader()->completeURL(str).url();
1783           else
1784               url = str;
1785           break;
1786       } 
1787       case Hash: {
1788           if (str.startsWith("#"))
1789               str = str.mid(1);
1790           
1791           if (url.ref() == str)
1792               return;
1793
1794           url.setRef(str);
1795           break;
1796       }
1797       case Host: {
1798           url.setHostAndPort(str);
1799           break;
1800       }
1801       case Hostname:
1802           url.setHost(str);
1803           break;
1804       case Pathname:
1805           url.setPath(str);
1806           break;
1807       case Port:
1808           url.setPort(str.toUInt());
1809           break;
1810       case Protocol:
1811           url.setProtocol(str);
1812           break;
1813       case Search:
1814           url.setQuery(str);
1815           break;
1816       default:
1817           // Disallow changing other properties in LocationTable. e.g., "window.location.toString = ...".
1818           // <http://bugs.webkit.org/show_bug.cgi?id=12720>
1819           return;
1820       }
1821   } else {
1822       if (sameDomainAccess)
1823           JSObject::put(exec, p, v, attr);
1824       return;
1825   }
1826
1827   Frame* activeFrame = Window::retrieveActive(exec)->impl()->frame();
1828   if (!url.url().startsWith("javascript:", false) || sameDomainAccess) {
1829     bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1830     m_frame->loader()->scheduleLocationChange(url.url(), activeFrame->loader()->outgoingReferrer(), false, userGesture);
1831   }
1832 }
1833
1834 JSValue *LocationFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
1835 {
1836   if (!thisObj->inherits(&Location::info))
1837     return throwError(exec, TypeError);
1838   Location *location = static_cast<Location *>(thisObj);
1839   Frame *frame = location->frame();
1840   if (frame) {
1841       
1842     Window* window = Window::retrieveWindow(frame);
1843     if (id != Location::Replace && !window->isSafeScript(exec))
1844         return jsUndefined();
1845       
1846     switch (id) {
1847     case Location::Replace:
1848     {
1849       DeprecatedString str = args[0]->toString(exec);
1850       Frame* p = Window::retrieveActive(exec)->impl()->frame();
1851       if ( p ) {
1852         const Window* window = Window::retrieveWindow(frame);
1853         if (!str.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
1854           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1855           frame->loader()->scheduleLocationChange(p->loader()->completeURL(str).url(), p->loader()->outgoingReferrer(), true, userGesture);
1856         }
1857       }
1858       break;
1859     }
1860     case Location::Reload:
1861     {
1862       const Window* window = Window::retrieveWindow(frame);
1863       if (!frame->loader()->url().url().startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
1864         bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1865         frame->loader()->scheduleRefresh(userGesture);
1866       }
1867       break;
1868     }
1869     case Location::Assign:
1870     {
1871         Frame *p = Window::retrieveActive(exec)->impl()->frame();
1872         if (p) {
1873             const Window *window = Window::retrieveWindow(frame);
1874             DeprecatedString dstUrl = p->loader()->completeURL(DeprecatedString(args[0]->toString(exec))).url();
1875             if (!dstUrl.startsWith("javascript:", false) || (window && window->isSafeScript(exec))) {
1876                 bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1877                 // We want a new history item if this JS was called via a user gesture
1878                 frame->loader()->scheduleLocationChange(dstUrl, p->loader()->outgoingReferrer(), false, userGesture);
1879             }
1880         }
1881         break;
1882     }
1883     case Location::ToString:
1884         if (!frame || !Window::retrieveWindow(frame)->isSafeScript(exec))
1885             return jsString();
1886
1887         if (!frame->loader()->url().hasPath())
1888             return jsString(frame->loader()->url().prettyURL() + "/");
1889         return jsString(frame->loader()->url().prettyURL());
1890     }
1891   }
1892   return jsUndefined();
1893 }
1894
1895 /////////////////////////////////////////////////////////////////////////////
1896
1897 PausedTimeouts::~PausedTimeouts()
1898 {
1899     PausedTimeout *array = m_array;
1900     if (!array)
1901         return;
1902     size_t count = m_length;
1903     for (size_t i = 0; i != count; ++i)
1904         delete array[i].action;
1905     delete [] array;
1906 }
1907
1908 void DOMWindowTimer::fired()
1909 {
1910     timerNestingLevel = m_nestingLevel;
1911     m_object->timerFired(this);
1912     timerNestingLevel = 0;
1913 }
1914
1915 } // namespace KJS
1916
1917 using namespace KJS;
1918
1919 namespace WebCore {
1920
1921 JSValue* toJS(ExecState*, DOMWindow* domWindow)
1922 {
1923     if (!domWindow)
1924         return jsNull();
1925     Frame* frame = domWindow->frame();
1926     if (!frame)
1927         return jsNull();
1928     return Window::retrieve(frame);
1929 }
1930     
1931 } // namespace WebCore