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