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