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