69246783086f69943a9d2379c7c79ad64844bf62
[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         Ref<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     Optional<uint32_t> index = parseIndex(propertyName);
218     if (index && index.value() < thisObject->impl().frame()->tree().scopedChildCount()) {
219         slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum,
220             toJS(exec, thisObject->impl().frame()->tree().scopedChild(index.value())->document()->domWindow()));
221         return true;
222     }
223
224     if (!allowsAccess) {
225         thisObject->printErrorMessage(errorMessage);
226         slot.setUndefined();
227         return true;
228     }
229
230     // Allow shortcuts like 'Image1' instead of document.images.Image1
231     Document* document = thisObject->impl().frame()->document();
232     if (is<HTMLDocument>(*document)) {
233         AtomicStringImpl* atomicPropertyName = propertyName.publicName();
234         if (atomicPropertyName && downcast<HTMLDocument>(*document).hasWindowNamedItem(*atomicPropertyName)) {
235             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter);
236             return true;
237         }
238     }
239
240     return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
241 }
242
243 bool JSDOMWindow::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
244 {
245     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
246     
247     if (!thisObject->impl().frame()) {
248         // FIXME: We should have a message here that explains why the property access/function call was
249         // not allowed. 
250         slot.setUndefined();
251         return true;
252     }
253
254     // We need to check for cross-domain access here without printing the generic warning message
255     // because we always allow access to some function, just different ones depending whether access
256     // is allowed.
257     String errorMessage;
258     bool allowsAccess = shouldAllowAccessToDOMWindow(exec, thisObject->impl(), errorMessage);
259
260     // Look for overrides before looking at any of our own properties, but ignore overrides completely
261     // if this is cross-domain access.
262     if (allowsAccess && JSGlobalObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot))
263         return true;
264     
265     Identifier propertyName = Identifier::from(exec, index);
266     
267     // Check for child frames by name before built-in properties to
268     // match Mozilla. This does not match IE, but some sites end up
269     // naming frames things that conflict with window properties that
270     // are in Moz but not IE. Since we have some of these, we have to do
271     // it the Moz way.
272     if (thisObject->impl().frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))) {
273         slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter);
274         return true;
275     }
276     
277     // Do prototype lookup early so that functions and attributes in the prototype can have
278     // precedence over the index and name getters.  
279     JSValue proto = thisObject->prototype();
280     if (proto.isObject()) {
281         if (asObject(proto)->getPropertySlot(exec, index, slot)) {
282             if (!allowsAccess) {
283                 thisObject->printErrorMessage(errorMessage);
284                 slot.setUndefined();
285             }
286             return true;
287         }
288     }
289
290     // FIXME: Search the whole frame hierarchy somewhere around here.
291     // We need to test the correct priority order.
292
293     // allow window[1] or parent[1] etc. (#56983)
294     if (index < thisObject->impl().frame()->tree().scopedChildCount()) {
295         slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum,
296             toJS(exec, thisObject->impl().frame()->tree().scopedChild(index)->document()->domWindow()));
297         return true;
298     }
299
300     if (!allowsAccess) {
301         thisObject->printErrorMessage(errorMessage);
302         slot.setUndefined();
303         return true;
304     }
305
306     // Allow shortcuts like 'Image1' instead of document.images.Image1
307     Document* document = thisObject->impl().frame()->document();
308     if (is<HTMLDocument>(*document)) {
309         AtomicStringImpl* atomicPropertyName = propertyName.impl();
310         if (atomicPropertyName && downcast<HTMLDocument>(*document).hasWindowNamedItem(*atomicPropertyName)) {
311             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter);
312             return true;
313         }
314     }
315
316     return Base::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
317 }
318
319 void JSDOMWindow::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
320 {
321     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
322     if (!thisObject->impl().frame())
323         return;
324
325     // Optimization: access JavaScript global variables directly before involving the DOM.
326     if (thisObject->JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) {
327         if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
328             JSGlobalObject::put(thisObject, exec, propertyName, value, slot);
329         return;
330     }
331
332     if (lookupPut(exec, propertyName, thisObject, value, *s_info.staticPropHashTable, slot))
333         return;
334
335     if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
336         Base::put(thisObject, exec, propertyName, value, slot);
337 }
338
339 void JSDOMWindow::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)
340 {
341     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
342     if (!thisObject->impl().frame())
343         return;
344     
345     Identifier propertyName = Identifier::from(exec, index);
346
347     // Optimization: access JavaScript global variables directly before involving the DOM.
348     if (thisObject->JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) {
349         if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
350             JSGlobalObject::putByIndex(thisObject, exec, index, value, shouldThrow);
351         return;
352     }
353     
354     if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
355         Base::putByIndex(thisObject, exec, index, value, shouldThrow);
356 }
357
358 bool JSDOMWindow::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
359 {
360     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
361     // Only allow deleting properties by frames in the same origin.
362     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
363         return false;
364     return Base::deleteProperty(thisObject, exec, propertyName);
365 }
366
367 bool JSDOMWindow::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
368 {
369     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
370     // Only allow deleting properties by frames in the same origin.
371     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
372         return false;
373     return Base::deletePropertyByIndex(thisObject, exec, propertyName);
374 }
375
376 uint32_t JSDOMWindow::getEnumerableLength(ExecState* exec, JSObject* object)
377 {
378     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
379     // Only allow the window to enumerated by frames in the same origin.
380     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
381         return 0;
382     return Base::getEnumerableLength(exec, thisObject);
383 }
384
385 void JSDOMWindow::getStructurePropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
386 {
387     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
388     // Only allow the window to enumerated by frames in the same origin.
389     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
390         return;
391     Base::getStructurePropertyNames(thisObject, exec, propertyNames, mode);
392 }
393
394 void JSDOMWindow::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
395 {
396     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
397     // Only allow the window to enumerated by frames in the same origin.
398     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
399         return;
400     Base::getGenericPropertyNames(thisObject, exec, propertyNames, mode);
401 }
402
403 void JSDOMWindow::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
404 {
405     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
406     // Only allow the window to enumerated by frames in the same origin.
407     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
408         return;
409     Base::getPropertyNames(thisObject, exec, propertyNames, mode);
410 }
411
412 void JSDOMWindow::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
413 {
414     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
415     // Only allow the window to enumerated by frames in the same origin.
416     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
417         return;
418     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
419 }
420
421 bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow)
422 {
423     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
424     // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
425     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
426         return false;
427
428     // Don't allow shadowing location using accessor properties.
429     if (descriptor.isAccessorDescriptor() && propertyName == Identifier::fromString(exec, "location"))
430         return false;
431
432     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
433 }
434
435 // Custom Attributes
436
437 void JSDOMWindow::setLocation(ExecState* exec, JSValue value)
438 {
439 #if ENABLE(DASHBOARD_SUPPORT)
440     // To avoid breaking old widgets, make "var location =" in a top-level frame create
441     // a property named "location" instead of performing a navigation (<rdar://problem/5688039>).
442     if (Frame* activeFrame = activeDOMWindow(exec).frame()) {
443         if (activeFrame->settings().usesDashboardBackwardCompatibilityMode() && !activeFrame->tree().parent()) {
444             if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, impl()))
445                 putDirect(exec->vm(), Identifier::fromString(exec, "location"), value);
446             return;
447         }
448     }
449 #endif
450
451     String locationString = value.toString(exec)->value(exec);
452     if (exec->hadException())
453         return;
454
455     if (Location* location = impl().location())
456         location->setHref(locationString, activeDOMWindow(exec), firstDOMWindow(exec));
457 }
458
459 JSValue JSDOMWindow::event(ExecState* exec) const
460 {
461     Event* event = currentEvent();
462     if (!event)
463         return jsUndefined();
464     return toJS(exec, const_cast<JSDOMWindow*>(this), event);
465 }
466
467 JSValue JSDOMWindow::image(ExecState* exec) const
468 {
469     return getDOMConstructor<JSImageConstructor>(exec->vm(), this);
470 }
471
472 #if ENABLE(IOS_TOUCH_EVENTS)
473 JSValue JSDOMWindow::touch(ExecState* exec) const
474 {
475     return getDOMConstructor<JSTouchConstructor>(exec->vm(), this);
476 }
477
478 JSValue JSDOMWindow::touchList(ExecState* exec) const
479 {
480     return getDOMConstructor<JSTouchListConstructor>(exec->vm(), this);
481 }
482 #endif
483
484 // Custom functions
485
486 JSValue JSDOMWindow::open(ExecState* exec)
487 {
488     String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0));
489     if (exec->hadException())
490         return jsUndefined();
491     AtomicString frameName = exec->argument(1).isUndefinedOrNull() ? "_blank" : exec->argument(1).toString(exec)->value(exec);
492     if (exec->hadException())
493         return jsUndefined();
494     String windowFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2));
495     if (exec->hadException())
496         return jsUndefined();
497
498     RefPtr<DOMWindow> openedWindow = impl().open(urlString, frameName, windowFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec));
499     if (!openedWindow)
500         return jsUndefined();
501     return toJS(exec, openedWindow.get());
502 }
503
504 class DialogHandler {
505 public:
506     explicit DialogHandler(ExecState* exec)
507         : m_exec(exec)
508     {
509     }
510
511     void dialogCreated(DOMWindow&);
512     JSValue returnValue() const;
513
514 private:
515     ExecState* m_exec;
516     RefPtr<Frame> m_frame;
517 };
518
519 inline void DialogHandler::dialogCreated(DOMWindow& dialog)
520 {
521     m_frame = dialog.frame();
522     
523     // FIXME: This looks like a leak between the normal world and an isolated
524     //        world if dialogArguments comes from an isolated world.
525     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec->vm()));
526     if (JSValue dialogArguments = m_exec->argument(1))
527         globalObject->putDirect(m_exec->vm(), Identifier::fromString(m_exec, "dialogArguments"), dialogArguments);
528 }
529
530 inline JSValue DialogHandler::returnValue() const
531 {
532     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec->vm()));
533     if (!globalObject)
534         return jsUndefined();
535     Identifier identifier = Identifier::fromString(m_exec, "returnValue");
536     PropertySlot slot(globalObject);
537     if (!JSGlobalObject::getOwnPropertySlot(globalObject, m_exec, identifier, slot))
538         return jsUndefined();
539     return slot.getValue(m_exec, identifier);
540 }
541
542 JSValue JSDOMWindow::showModalDialog(ExecState* exec)
543 {
544     String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0));
545     if (exec->hadException())
546         return jsUndefined();
547     String dialogFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2));
548     if (exec->hadException())
549         return jsUndefined();
550
551     DialogHandler handler(exec);
552
553     impl().showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec), [&handler](DOMWindow& dialog) {
554         handler.dialogCreated(dialog);
555     });
556
557     return handler.returnValue();
558 }
559
560 static JSValue handlePostMessage(DOMWindow* impl, ExecState* exec)
561 {
562     MessagePortArray messagePorts;
563     ArrayBufferArray arrayBuffers;
564
565     // This function has variable arguments and can be:
566     // Per current spec:
567     //   postMessage(message, targetOrigin)
568     //   postMessage(message, targetOrigin, {sequence of transferrables})
569     // Legacy non-standard implementations in webkit allowed:
570     //   postMessage(message, {sequence of transferrables}, targetOrigin);
571     int targetOriginArgIndex = 1;
572     if (exec->argumentCount() > 2) {
573         int transferablesArgIndex = 2;
574         if (exec->argument(2).isString()) {
575             targetOriginArgIndex = 2;
576             transferablesArgIndex = 1;
577         }
578         fillMessagePortArray(exec, exec->argument(transferablesArgIndex), messagePorts, arrayBuffers);
579     }
580     if (exec->hadException())
581         return jsUndefined();
582
583     RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0),
584                                                                          &messagePorts,
585                                                                          &arrayBuffers);
586
587     if (exec->hadException())
588         return jsUndefined();
589
590     String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(targetOriginArgIndex));
591     if (exec->hadException())
592         return jsUndefined();
593
594     ExceptionCode ec = 0;
595     impl->postMessage(message.release(), &messagePorts, targetOrigin, activeDOMWindow(exec), ec);
596     setDOMException(exec, ec);
597
598     return jsUndefined();
599 }
600
601 JSValue JSDOMWindow::postMessage(ExecState* exec)
602 {
603     return handlePostMessage(&impl(), exec);
604 }
605
606 JSValue JSDOMWindow::setTimeout(ExecState* exec)
607 {
608     ContentSecurityPolicy* contentSecurityPolicy = impl().document() ? impl().document()->contentSecurityPolicy() : 0;
609     std::unique_ptr<ScheduledAction> action = ScheduledAction::create(exec, globalObject()->world(), contentSecurityPolicy);
610     if (exec->hadException())
611         return jsUndefined();
612
613     if (!action)
614         return jsNumber(0);
615
616     int delay = exec->argument(1).toInt32(exec);
617
618     ExceptionCode ec = 0;
619     int result = impl().setTimeout(WTF::move(action), delay, ec);
620     setDOMException(exec, ec);
621
622     return jsNumber(result);
623 }
624
625 JSValue JSDOMWindow::setInterval(ExecState* exec)
626 {
627     ContentSecurityPolicy* contentSecurityPolicy = impl().document() ? impl().document()->contentSecurityPolicy() : 0;
628     std::unique_ptr<ScheduledAction> action = ScheduledAction::create(exec, globalObject()->world(), contentSecurityPolicy);
629     if (exec->hadException())
630         return jsUndefined();
631     int delay = exec->argument(1).toInt32(exec);
632
633     if (!action)
634         return jsNumber(0);
635
636     ExceptionCode ec = 0;
637     int result = impl().setInterval(WTF::move(action), delay, ec);
638     setDOMException(exec, ec);
639
640     return jsNumber(result);
641 }
642
643 JSValue JSDOMWindow::addEventListener(ExecState* exec)
644 {
645     Frame* frame = impl().frame();
646     if (!frame)
647         return jsUndefined();
648
649     JSValue listener = exec->argument(1);
650     if (!listener.isObject())
651         return jsUndefined();
652
653     impl().addEventListener(exec->argument(0).toString(exec)->toAtomicString(exec), JSEventListener::create(asObject(listener), this, false, globalObject()->world()), exec->argument(2).toBoolean(exec));
654     return jsUndefined();
655 }
656
657 JSValue JSDOMWindow::removeEventListener(ExecState* exec)
658 {
659     Frame* frame = impl().frame();
660     if (!frame)
661         return jsUndefined();
662
663     JSValue listener = exec->argument(1);
664     if (!listener.isObject())
665         return jsUndefined();
666
667     impl().removeEventListener(exec->argument(0).toString(exec)->toAtomicString(exec), JSEventListener::create(asObject(listener), this, false, globalObject()->world()).ptr(), exec->argument(2).toBoolean(exec));
668     return jsUndefined();
669 }
670
671 DOMWindow* JSDOMWindow::toWrapped(JSValue value)
672 {
673     if (!value.isObject())
674         return 0;
675     JSObject* object = asObject(value);
676     if (object->inherits(JSDOMWindow::info()))
677         return &jsCast<JSDOMWindow*>(object)->impl();
678     if (object->inherits(JSDOMWindowShell::info()))
679         return &jsCast<JSDOMWindowShell*>(object)->impl();
680     return 0;
681 }
682
683 } // namespace WebCore