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