02608fa6e4e2f571e4b371e6819f89323a892a9a
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMWindowCustom.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22 #include "JSDOMWindowCustom.h"
23
24 #include "Frame.h"
25 #include "HTMLCollection.h"
26 #include "HTMLDocument.h"
27 #include "JSEvent.h"
28 #include "JSEventListener.h"
29 #include "JSHTMLAudioElement.h"
30 #include "JSHTMLCollection.h"
31 #include "JSHTMLOptionElement.h"
32 #include "JSImageConstructor.h"
33 #include "JSMessagePortCustom.h"
34 #include "JSWorker.h"
35 #include "Location.h"
36 #include "ScheduledAction.h"
37 #include "Settings.h"
38
39 #if ENABLE(IOS_TOUCH_EVENTS)
40 #include "JSTouchConstructorIOS.h"
41 #include "JSTouchListConstructorIOS.h"
42 #endif
43
44 #if ENABLE(WEB_AUDIO)
45 #include "JSAudioContext.h"
46 #endif
47
48 #if ENABLE(WEB_SOCKETS)
49 #include "JSWebSocket.h"
50 #endif
51
52 #if ENABLE(USER_MESSAGE_HANDLERS)
53 #include "JSWebKitNamespace.h"
54 #endif
55
56 using namespace JSC;
57
58 namespace WebCore {
59
60 void JSDOMWindow::visitAdditionalChildren(SlotVisitor& visitor)
61 {
62     if (Frame* frame = impl().frame())
63         visitor.addOpaqueRoot(frame);
64 }
65
66 static EncodedJSValue childFrameGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName propertyName)
67 {
68     return JSValue::encode(toJS(exec, jsCast<JSDOMWindow*>(slotBase)->impl().frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))->document()->domWindow()));
69 }
70
71 static EncodedJSValue namedItemGetter(ExecState* exec, JSObject* slotBase, EncodedJSValue, PropertyName propertyName)
72 {
73     JSDOMWindowBase* thisObj = jsCast<JSDOMWindow*>(slotBase);
74     Document* document = thisObj->impl().frame()->document();
75
76     ASSERT(BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObj->impl()));
77     ASSERT(is<HTMLDocument>(document));
78
79     AtomicStringImpl* atomicPropertyName = propertyName.publicName();
80     if (!atomicPropertyName || !downcast<HTMLDocument>(*document).hasWindowNamedItem(*atomicPropertyName))
81         return JSValue::encode(jsUndefined());
82
83     if (UNLIKELY(downcast<HTMLDocument>(*document).windowNamedItemContainsMultipleElements(*atomicPropertyName))) {
84         RefPtr<HTMLCollection> collection = document->windowNamedItems(atomicPropertyName);
85         ASSERT(collection->length() > 1);
86         return JSValue::encode(toJS(exec, thisObj->globalObject(), WTF::getPtr(collection)));
87     }
88
89     return JSValue::encode(toJS(exec, thisObj->globalObject(), downcast<HTMLDocument>(*document).windowNamedItem(*atomicPropertyName)));
90 }
91
92 #if ENABLE(USER_MESSAGE_HANDLERS)
93 static EncodedJSValue jsDOMWindowWebKit(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName)
94 {
95     JSDOMWindow* castedThis = toJSDOMWindow(JSValue::decode(thisValue));
96     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->impl()))
97         return JSValue::encode(jsUndefined());
98     return JSValue::encode(toJS(exec, castedThis->globalObject(), castedThis->impl().webkitNamespace()));
99 }
100 #endif
101
102 bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
103 {
104     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
105     // When accessing a Window cross-domain, functions are always the native built-in ones, and they
106     // are not affected by properties changed on the Window or anything in its prototype chain.
107     // This is consistent with the behavior of Firefox.
108
109     // We don't want any properties other than "close" and "closed" on a frameless window (i.e. one whose page got closed,
110     // or whose iframe got removed).
111     // FIXME: This doesn't fully match Firefox, which allows at least toString in addition to those.
112     if (!thisObject->impl().frame()) {
113         // The following code is safe for cross-domain and same domain use.
114         // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype).
115         if (propertyName == exec->propertyNames().closed) {
116             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, jsDOMWindowClosed);
117             return true;
118         }
119         if (propertyName == exec->propertyNames().close) {
120             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
121             return true;
122         }
123
124         // FIXME: We should have a message here that explains why the property access/function call was
125         // not allowed. 
126         slot.setUndefined();
127         return true;
128     } else
129         slot.setWatchpointSet(thisObject->m_windowCloseWatchpoints);
130
131     // We need to check for cross-domain access here without printing the generic warning message
132     // because we always allow access to some function, just different ones depending whether access
133     // is allowed.
134     String errorMessage;
135     bool allowsAccess = shouldAllowAccessToDOMWindow(exec, thisObject->impl(), errorMessage);
136     
137     // Look for overrides before looking at any of our own properties, but ignore overrides completely
138     // if this is cross-domain access.
139     if (allowsAccess && JSGlobalObject::getOwnPropertySlot(thisObject, exec, propertyName, slot))
140         return true;
141     
142     // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the
143     // prototype due to the blanket same origin (shouldAllowAccessToDOMWindow) check at the end of getOwnPropertySlot.
144     // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of
145     // what prototype is actually set on this object.
146     if (propertyName == exec->propertyNames().blur) {
147         slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>);
148         return true;
149     } else if (propertyName == exec->propertyNames().close) {
150         slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
151         return true;
152     } else if (propertyName == exec->propertyNames().focus) {
153         slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>);
154         return true;
155     } else if (propertyName == exec->propertyNames().postMessage) {
156         slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>);
157         return true;
158     } else if (propertyName == exec->propertyNames().showModalDialog) {
159         if (!DOMWindow::canShowModalDialog(thisObject->impl().frame())) {
160             slot.setUndefined();
161             return true;
162         }
163     } else if (propertyName == exec->propertyNames().toString) {
164         // Allow access to toString() cross-domain, but always Object.prototype.toString.
165         if (!allowsAccess) {
166             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter);
167             return true;
168         }
169     }
170
171     const HashTableValue* entry = JSDOMWindow::info()->staticPropHashTable->entry(propertyName);
172     if (entry) {
173         slot.setCacheableCustom(thisObject, allowsAccess ? entry->attributes() : ReadOnly | DontDelete | DontEnum, entry->propertyGetter());
174         return true;
175     }
176
177 #if ENABLE(USER_MESSAGE_HANDLERS)
178     if (propertyName == exec->propertyNames().webkit && thisObject->impl().shouldHaveWebKitNamespaceForWorld(thisObject->world())) {
179         slot.setCacheableCustom(thisObject, allowsAccess ? DontDelete | ReadOnly : ReadOnly | DontDelete | DontEnum, jsDOMWindowWebKit);
180         return true;
181     }
182 #endif
183
184     // Do prototype lookup early so that functions and attributes in the prototype can have
185     // precedence over the index and name getters.  
186     JSValue proto = thisObject->prototype();
187     if (proto.isObject()) {
188         if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) {
189             if (!allowsAccess) {
190                 thisObject->printErrorMessage(errorMessage);
191                 slot.setUndefined();
192             }
193             return true;
194         }
195     }
196
197     // After this point it is no longer valid to cache any results because of
198     // the impure nature of the property accesses which follow. We can move this 
199     // statement further down when we add ways to mitigate these impurities with, 
200     // for example, watchpoints.
201     slot.disableCaching();
202
203     // Check for child frames by name before built-in properties to
204     // match Mozilla. This does not match IE, but some sites end up
205     // naming frames things that conflict with window properties that
206     // are in Moz but not IE. Since we have some of these, we have to do
207     // it the Moz way.
208     if (thisObject->impl().frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))) {
209         slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter);
210         return true;
211     }
212
213     // FIXME: Search the whole frame hierarchy somewhere around here.
214     // We need to test the correct priority order.
215
216     // allow window[1] or parent[1] etc. (#56983)
217     unsigned i = propertyName.asIndex();
218     if (i < thisObject->impl().frame()->tree().scopedChildCount()) {
219         ASSERT(i != PropertyName::NotAnIndex);
220         slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum,
221             toJS(exec, thisObject->impl().frame()->tree().scopedChild(i)->document()->domWindow()));
222         return true;
223     }
224
225     if (!allowsAccess) {
226         thisObject->printErrorMessage(errorMessage);
227         slot.setUndefined();
228         return true;
229     }
230
231     // Allow shortcuts like 'Image1' instead of document.images.Image1
232     Document* document = thisObject->impl().frame()->document();
233     if (is<HTMLDocument>(*document)) {
234         AtomicStringImpl* atomicPropertyName = propertyName.publicName();
235         if (atomicPropertyName && downcast<HTMLDocument>(*document).hasWindowNamedItem(*atomicPropertyName)) {
236             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter);
237             return true;
238         }
239     }
240
241     return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
242 }
243
244 bool JSDOMWindow::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
245 {
246     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
247     
248     if (!thisObject->impl().frame()) {
249         // FIXME: We should have a message here that explains why the property access/function call was
250         // not allowed. 
251         slot.setUndefined();
252         return true;
253     }
254
255     // We need to check for cross-domain access here without printing the generic warning message
256     // because we always allow access to some function, just different ones depending whether access
257     // is allowed.
258     String errorMessage;
259     bool allowsAccess = shouldAllowAccessToDOMWindow(exec, thisObject->impl(), errorMessage);
260
261     // Look for overrides before looking at any of our own properties, but ignore overrides completely
262     // if this is cross-domain access.
263     if (allowsAccess && JSGlobalObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot))
264         return true;
265     
266     PropertyName propertyName = Identifier::from(exec, index);
267     
268     // Check for child frames by name before built-in properties to
269     // match Mozilla. This does not match IE, but some sites end up
270     // naming frames things that conflict with window properties that
271     // are in Moz but not IE. Since we have some of these, we have to do
272     // it the Moz way.
273     if (thisObject->impl().frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))) {
274         slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter);
275         return true;
276     }
277     
278     // Do prototype lookup early so that functions and attributes in the prototype can have
279     // precedence over the index and name getters.  
280     JSValue proto = thisObject->prototype();
281     if (proto.isObject()) {
282         if (asObject(proto)->getPropertySlot(exec, index, slot)) {
283             if (!allowsAccess) {
284                 thisObject->printErrorMessage(errorMessage);
285                 slot.setUndefined();
286             }
287             return true;
288         }
289     }
290
291     // FIXME: Search the whole frame hierarchy somewhere around here.
292     // We need to test the correct priority order.
293
294     // allow window[1] or parent[1] etc. (#56983)
295     if (index < thisObject->impl().frame()->tree().scopedChildCount()) {
296         ASSERT(index != PropertyName::NotAnIndex);
297         slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum,
298             toJS(exec, thisObject->impl().frame()->tree().scopedChild(index)->document()->domWindow()));
299         return true;
300     }
301
302     if (!allowsAccess) {
303         thisObject->printErrorMessage(errorMessage);
304         slot.setUndefined();
305         return true;
306     }
307
308     // Allow shortcuts like 'Image1' instead of document.images.Image1
309     Document* document = thisObject->impl().frame()->document();
310     if (is<HTMLDocument>(*document)) {
311         AtomicStringImpl* atomicPropertyName = propertyName.publicName();
312         if (atomicPropertyName && downcast<HTMLDocument>(*document).hasWindowNamedItem(*atomicPropertyName)) {
313             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter);
314             return true;
315         }
316     }
317
318     return Base::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
319 }
320
321 void JSDOMWindow::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
322 {
323     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
324     if (!thisObject->impl().frame())
325         return;
326
327     // Optimization: access JavaScript global variables directly before involving the DOM.
328     if (thisObject->JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) {
329         if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
330             JSGlobalObject::put(thisObject, exec, propertyName, value, slot);
331         return;
332     }
333
334     if (lookupPut(exec, propertyName, thisObject, value, *s_info.staticPropHashTable, slot))
335         return;
336
337     if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
338         Base::put(thisObject, exec, propertyName, value, slot);
339 }
340
341 void JSDOMWindow::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)
342 {
343     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
344     if (!thisObject->impl().frame())
345         return;
346     
347     PropertyName propertyName = Identifier::from(exec, index);
348
349     // Optimization: access JavaScript global variables directly before involving the DOM.
350     if (thisObject->JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) {
351         if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
352             JSGlobalObject::putByIndex(thisObject, exec, index, value, shouldThrow);
353         return;
354     }
355     
356     if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
357         Base::putByIndex(thisObject, exec, index, value, shouldThrow);
358 }
359
360 bool JSDOMWindow::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
361 {
362     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
363     // Only allow deleting properties by frames in the same origin.
364     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
365         return false;
366     return Base::deleteProperty(thisObject, exec, propertyName);
367 }
368
369 bool JSDOMWindow::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
370 {
371     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
372     // Only allow deleting properties by frames in the same origin.
373     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
374         return false;
375     return Base::deletePropertyByIndex(thisObject, exec, propertyName);
376 }
377
378 uint32_t JSDOMWindow::getEnumerableLength(ExecState* exec, JSObject* object)
379 {
380     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
381     // Only allow the window to enumerated by frames in the same origin.
382     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
383         return 0;
384     return Base::getEnumerableLength(exec, thisObject);
385 }
386
387 void JSDOMWindow::getStructurePropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
388 {
389     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
390     // Only allow the window to enumerated by frames in the same origin.
391     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
392         return;
393     Base::getStructurePropertyNames(thisObject, exec, propertyNames, mode);
394 }
395
396 void JSDOMWindow::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
397 {
398     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
399     // Only allow the window to enumerated by frames in the same origin.
400     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
401         return;
402     Base::getGenericPropertyNames(thisObject, exec, propertyNames, mode);
403 }
404
405 void JSDOMWindow::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
406 {
407     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
408     // Only allow the window to enumerated by frames in the same origin.
409     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
410         return;
411     Base::getPropertyNames(thisObject, exec, propertyNames, mode);
412 }
413
414 void JSDOMWindow::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
415 {
416     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
417     // Only allow the window to enumerated by frames in the same origin.
418     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
419         return;
420     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
421 }
422
423 bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow)
424 {
425     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
426     // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
427     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
428         return false;
429
430     // Don't allow shadowing location using accessor properties.
431     if (descriptor.isAccessorDescriptor() && propertyName == Identifier(exec, "location"))
432         return false;
433
434     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
435 }
436
437 // Custom Attributes
438
439 void JSDOMWindow::setLocation(ExecState* exec, JSValue value)
440 {
441 #if ENABLE(DASHBOARD_SUPPORT)
442     // To avoid breaking old widgets, make "var location =" in a top-level frame create
443     // a property named "location" instead of performing a navigation (<rdar://problem/5688039>).
444     if (Frame* activeFrame = activeDOMWindow(exec).frame()) {
445         if (activeFrame->settings().usesDashboardBackwardCompatibilityMode() && !activeFrame->tree().parent()) {
446             if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, impl()))
447                 putDirect(exec->vm(), Identifier(exec, "location"), value);
448             return;
449         }
450     }
451 #endif
452
453     String locationString = value.toString(exec)->value(exec);
454     if (exec->hadException())
455         return;
456
457     if (Location* location = impl().location())
458         location->setHref(locationString, activeDOMWindow(exec), firstDOMWindow(exec));
459 }
460
461 JSValue JSDOMWindow::event(ExecState* exec) const
462 {
463     Event* event = currentEvent();
464     if (!event)
465         return jsUndefined();
466     return toJS(exec, const_cast<JSDOMWindow*>(this), event);
467 }
468
469 JSValue JSDOMWindow::image(ExecState* exec) const
470 {
471     return getDOMConstructor<JSImageConstructor>(exec->vm(), this);
472 }
473
474 #if ENABLE(IOS_TOUCH_EVENTS)
475 JSValue JSDOMWindow::touch(ExecState* exec) const
476 {
477     return getDOMConstructor<JSTouchConstructor>(exec->vm(), this);
478 }
479
480 JSValue JSDOMWindow::touchList(ExecState* exec) const
481 {
482     return getDOMConstructor<JSTouchListConstructor>(exec->vm(), this);
483 }
484 #endif
485
486 // Custom functions
487
488 JSValue JSDOMWindow::open(ExecState* exec)
489 {
490     String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0));
491     if (exec->hadException())
492         return jsUndefined();
493     AtomicString frameName = exec->argument(1).isUndefinedOrNull() ? "_blank" : exec->argument(1).toString(exec)->value(exec);
494     if (exec->hadException())
495         return jsUndefined();
496     String windowFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2));
497     if (exec->hadException())
498         return jsUndefined();
499
500     RefPtr<DOMWindow> openedWindow = impl().open(urlString, frameName, windowFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec));
501     if (!openedWindow)
502         return jsUndefined();
503     return toJS(exec, openedWindow.get());
504 }
505
506 class DialogHandler {
507 public:
508     explicit DialogHandler(ExecState* exec)
509         : m_exec(exec)
510     {
511     }
512
513     void dialogCreated(DOMWindow&);
514     JSValue returnValue() const;
515
516 private:
517     ExecState* m_exec;
518     RefPtr<Frame> m_frame;
519 };
520
521 inline void DialogHandler::dialogCreated(DOMWindow& dialog)
522 {
523     m_frame = dialog.frame();
524     
525     // FIXME: This looks like a leak between the normal world and an isolated
526     //        world if dialogArguments comes from an isolated world.
527     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec->vm()));
528     if (JSValue dialogArguments = m_exec->argument(1))
529         globalObject->putDirect(m_exec->vm(), Identifier(m_exec, "dialogArguments"), dialogArguments);
530 }
531
532 inline JSValue DialogHandler::returnValue() const
533 {
534     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec->vm()));
535     if (!globalObject)
536         return jsUndefined();
537     Identifier identifier(m_exec, "returnValue");
538     PropertySlot slot(globalObject);
539     if (!JSGlobalObject::getOwnPropertySlot(globalObject, m_exec, identifier, slot))
540         return jsUndefined();
541     return slot.getValue(m_exec, identifier);
542 }
543
544 JSValue JSDOMWindow::showModalDialog(ExecState* exec)
545 {
546     String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0));
547     if (exec->hadException())
548         return jsUndefined();
549     String dialogFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2));
550     if (exec->hadException())
551         return jsUndefined();
552
553     DialogHandler handler(exec);
554
555     impl().showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec), [&handler](DOMWindow& dialog) {
556         handler.dialogCreated(dialog);
557     });
558
559     return handler.returnValue();
560 }
561
562 static JSValue handlePostMessage(DOMWindow* impl, ExecState* exec)
563 {
564     MessagePortArray messagePorts;
565     ArrayBufferArray arrayBuffers;
566
567     // This function has variable arguments and can be:
568     // Per current spec:
569     //   postMessage(message, targetOrigin)
570     //   postMessage(message, targetOrigin, {sequence of transferrables})
571     // Legacy non-standard implementations in webkit allowed:
572     //   postMessage(message, {sequence of transferrables}, targetOrigin);
573     int targetOriginArgIndex = 1;
574     if (exec->argumentCount() > 2) {
575         int transferablesArgIndex = 2;
576         if (exec->argument(2).isString()) {
577             targetOriginArgIndex = 2;
578             transferablesArgIndex = 1;
579         }
580         fillMessagePortArray(exec, exec->argument(transferablesArgIndex), messagePorts, arrayBuffers);
581     }
582     if (exec->hadException())
583         return jsUndefined();
584
585     RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0),
586                                                                          &messagePorts,
587                                                                          &arrayBuffers);
588
589     if (exec->hadException())
590         return jsUndefined();
591
592     String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(targetOriginArgIndex));
593     if (exec->hadException())
594         return jsUndefined();
595
596     ExceptionCode ec = 0;
597     impl->postMessage(message.release(), &messagePorts, targetOrigin, activeDOMWindow(exec), ec);
598     setDOMException(exec, ec);
599
600     return jsUndefined();
601 }
602
603 JSValue JSDOMWindow::postMessage(ExecState* exec)
604 {
605     return handlePostMessage(&impl(), exec);
606 }
607
608 JSValue JSDOMWindow::setTimeout(ExecState* exec)
609 {
610     ContentSecurityPolicy* contentSecurityPolicy = impl().document() ? impl().document()->contentSecurityPolicy() : 0;
611     std::unique_ptr<ScheduledAction> action = ScheduledAction::create(exec, globalObject()->world(), contentSecurityPolicy);
612     if (exec->hadException())
613         return jsUndefined();
614
615     if (!action)
616         return jsNumber(0);
617
618     int delay = exec->argument(1).toInt32(exec);
619
620     ExceptionCode ec = 0;
621     int result = impl().setTimeout(WTF::move(action), delay, ec);
622     setDOMException(exec, ec);
623
624     return jsNumber(result);
625 }
626
627 JSValue JSDOMWindow::setInterval(ExecState* exec)
628 {
629     ContentSecurityPolicy* contentSecurityPolicy = impl().document() ? impl().document()->contentSecurityPolicy() : 0;
630     std::unique_ptr<ScheduledAction> action = ScheduledAction::create(exec, globalObject()->world(), contentSecurityPolicy);
631     if (exec->hadException())
632         return jsUndefined();
633     int delay = exec->argument(1).toInt32(exec);
634
635     if (!action)
636         return jsNumber(0);
637
638     ExceptionCode ec = 0;
639     int result = impl().setInterval(WTF::move(action), delay, ec);
640     setDOMException(exec, ec);
641
642     return jsNumber(result);
643 }
644
645 JSValue JSDOMWindow::addEventListener(ExecState* exec)
646 {
647     Frame* frame = impl().frame();
648     if (!frame)
649         return jsUndefined();
650
651     JSValue listener = exec->argument(1);
652     if (!listener.isObject())
653         return jsUndefined();
654
655     impl().addEventListener(exec->argument(0).toString(exec)->toAtomicString(exec), JSEventListener::create(asObject(listener), this, false, globalObject()->world()), exec->argument(2).toBoolean(exec));
656     return jsUndefined();
657 }
658
659 JSValue JSDOMWindow::removeEventListener(ExecState* exec)
660 {
661     Frame* frame = impl().frame();
662     if (!frame)
663         return jsUndefined();
664
665     JSValue listener = exec->argument(1);
666     if (!listener.isObject())
667         return jsUndefined();
668
669     impl().removeEventListener(exec->argument(0).toString(exec)->toAtomicString(exec), JSEventListener::create(asObject(listener), this, false, globalObject()->world()).ptr(), exec->argument(2).toBoolean(exec));
670     return jsUndefined();
671 }
672
673 DOMWindow* JSDOMWindow::toWrapped(JSValue value)
674 {
675     if (!value.isObject())
676         return 0;
677     JSObject* object = asObject(value);
678     if (object->inherits(JSDOMWindow::info()))
679         return &jsCast<JSDOMWindow*>(object)->impl();
680     if (object->inherits(JSDOMWindowShell::info()))
681         return &jsCast<JSDOMWindowShell*>(object)->impl();
682     return 0;
683 }
684
685 } // namespace WebCore