190be483ae83f257d7c56252fe940f7bc82648cd
[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 "BindingSecurity.h"
25 #include "Frame.h"
26 #include "HTMLCollection.h"
27 #include "HTMLDocument.h"
28 #include "JSEvent.h"
29 #include "JSEventListener.h"
30 #include "JSHTMLAudioElement.h"
31 #include "JSHTMLCollection.h"
32 #include "JSHTMLOptionElement.h"
33 #include "JSImageConstructor.h"
34 #include "JSMessagePortCustom.h"
35 #include "Location.h"
36 #include "ScheduledAction.h"
37 #include "Settings.h"
38 #include "SharedWorkerRepository.h"
39
40 #if ENABLE(WORKERS)
41 #include "JSWorker.h"
42 #endif
43
44 #if ENABLE(SHARED_WORKERS)
45 #include "JSSharedWorker.h"
46 #endif
47
48 #if ENABLE(WEB_AUDIO)
49 #include "JSAudioContext.h"
50 #endif
51
52 #if ENABLE(WEB_SOCKETS)
53 #include "JSWebSocket.h"
54 #endif
55
56 using namespace JSC;
57
58 namespace WebCore {
59
60 void JSDOMWindow::visitChildren(JSCell* cell, SlotVisitor& visitor)
61 {
62     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
63     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
64     COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
65     ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
66     Base::visitChildren(thisObject, visitor);
67
68     thisObject->impl()->visitJSEventListeners(visitor);
69     if (Frame* frame = thisObject->impl()->frame())
70         visitor.addOpaqueRoot(frame);
71 }
72
73 template<NativeFunction nativeFunction, int length>
74 JSValue nonCachingStaticFunctionGetter(ExecState* exec, JSValue, PropertyName propertyName)
75 {
76     return JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), length, propertyName.publicName(), nativeFunction);
77 }
78
79 static JSValue childFrameGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName)
80 {
81     return toJS(exec, jsCast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))->document()->domWindow());
82 }
83
84 static JSValue indexGetter(ExecState* exec, JSValue slotBase, unsigned index)
85 {
86     return toJS(exec, jsCast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree().scopedChild(index)->document()->domWindow());
87 }
88
89 static JSValue namedItemGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName)
90 {
91     JSDOMWindowBase* thisObj = jsCast<JSDOMWindow*>(asObject(slotBase));
92     Document* document = thisObj->impl()->frame()->document();
93
94     ASSERT(BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObj->impl()));
95     ASSERT(document);
96     ASSERT(document->isHTMLDocument());
97
98     AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
99     if (!atomicPropertyName || !toHTMLDocument(document)->hasWindowNamedItem(atomicPropertyName))
100         return jsUndefined();
101
102     if (UNLIKELY(toHTMLDocument(document)->windowNamedItemContainsMultipleElements(atomicPropertyName))) {
103         RefPtr<HTMLCollection> collection = document->windowNamedItems(atomicPropertyName);
104         ASSERT(!collection->isEmpty());
105         ASSERT(!collection->hasExactlyOneItem());
106         return toJS(exec, thisObj->globalObject(), WTF::getPtr(collection));
107     }
108
109     return toJS(exec, thisObj->globalObject(), toHTMLDocument(document)->windowNamedItem(atomicPropertyName));
110 }
111
112 bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
113 {
114     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
115     // When accessing a Window cross-domain, functions are always the native built-in ones, and they
116     // are not affected by properties changed on the Window or anything in its prototype chain.
117     // This is consistent with the behavior of Firefox.
118
119     const HashEntry* entry;
120
121     // We don't want any properties other than "close" and "closed" on a frameless window (i.e. one whose page got closed,
122     // or whose iframe got removed).
123     // FIXME: This doesn't fully match Firefox, which allows at least toString in addition to those.
124     if (!thisObject->impl()->frame()) {
125         // The following code is safe for cross-domain and same domain use.
126         // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype).
127         entry = s_info.propHashTable(exec)->entry(exec, propertyName);
128         if (entry && !(entry->attributes() & JSC::Function) && entry->propertyGetter() == jsDOMWindowClosed) {
129             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, entry->propertyGetter());
130             return true;
131         }
132         entry = JSDOMWindowPrototype::info()->propHashTable(exec)->entry(exec, propertyName);
133         if (entry && (entry->attributes() & JSC::Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) {
134             slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
135             return true;
136         }
137
138         // FIXME: We should have a message here that explains why the property access/function call was
139         // not allowed. 
140         slot.setUndefined();
141         return true;
142     }
143
144     // We need to check for cross-domain access here without printing the generic warning message
145     // because we always allow access to some function, just different ones depending whether access
146     // is allowed.
147     String errorMessage;
148     bool allowsAccess = shouldAllowAccessToDOMWindow(exec, thisObject->impl(), errorMessage);
149     
150     // Look for overrides before looking at any of our own properties, but ignore overrides completely
151     // if this is cross-domain access.
152     if (allowsAccess && JSGlobalObject::getOwnPropertySlot(thisObject, exec, propertyName, slot))
153         return true;
154     
155     // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the
156     // prototype due to the blanket same origin (shouldAllowAccessToDOMWindow) check at the end of getOwnPropertySlot.
157     // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of
158     // what prototype is actually set on this object.
159     entry = JSDOMWindowPrototype::info()->propHashTable(exec)->entry(exec, propertyName);
160     if (entry) {
161         if (entry->attributes() & JSC::Function) {
162             if (entry->function() == jsDOMWindowPrototypeFunctionBlur) {
163                 if (!allowsAccess) {
164                     slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>);
165                     return true;
166                 }
167             } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) {
168                 if (!allowsAccess) {
169                     slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
170                     return true;
171                 }
172             } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) {
173                 if (!allowsAccess) {
174                     slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>);
175                     return true;
176                 }
177             } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) {
178                 if (!allowsAccess) {
179                     slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>);
180                     return true;
181                 }
182             } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) {
183                 if (!DOMWindow::canShowModalDialog(thisObject->impl()->frame())) {
184                     slot.setUndefined();
185                     return true;
186                 }
187             }
188         }
189     } else {
190         // Allow access to toString() cross-domain, but always Object.prototype.toString.
191         if (propertyName == exec->propertyNames().toString) {
192             if (!allowsAccess) {
193                 slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter);
194                 return true;
195             }
196         }
197     }
198
199     entry = JSDOMWindow::info()->propHashTable(exec)->entry(exec, propertyName);
200     if (entry) {
201         slot.setCustom(thisObject, allowsAccess ? entry->attributes() : ReadOnly | DontDelete | DontEnum, entry->propertyGetter());
202         return true;
203     }
204
205     // Check for child frames by name before built-in properties to
206     // match Mozilla. This does not match IE, but some sites end up
207     // naming frames things that conflict with window properties that
208     // are in Moz but not IE. Since we have some of these, we have to do
209     // it the Moz way.
210     if (thisObject->impl()->frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))) {
211         slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter);
212         return true;
213     }
214
215     // Do prototype lookup early so that functions and attributes in the prototype can have
216     // precedence over the index and name getters.  
217     JSValue proto = thisObject->prototype();
218     if (proto.isObject()) {
219         if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) {
220             if (!allowsAccess) {
221                 thisObject->printErrorMessage(errorMessage);
222                 slot.setUndefined();
223             }
224             return true;
225         }
226     }
227
228     // FIXME: Search the whole frame hierarchy somewhere around here.
229     // We need to test the correct priority order.
230
231     // allow window[1] or parent[1] etc. (#56983)
232     unsigned i = propertyName.asIndex();
233     if (i < thisObject->impl()->frame()->tree().scopedChildCount()) {
234         ASSERT(i != PropertyName::NotAnIndex);
235         slot.setCustomIndex(thisObject, ReadOnly | DontDelete | DontEnum, i, indexGetter);
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 (document->isHTMLDocument()) {
248         AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
249         if (atomicPropertyName && toHTMLDocument(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.setCustomIndex(thisObject, ReadOnly | DontDelete | DontEnum, index, indexGetter);
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 (document->isHTMLDocument()) {
324         AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
325         if (atomicPropertyName && toHTMLDocument(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<JSDOMWindow>(exec, propertyName, value, *s_info.propHashTable(exec), thisObject))
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 void JSDOMWindow::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
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;
397     Base::getPropertyNames(thisObject, exec, propertyNames, mode);
398 }
399
400 void JSDOMWindow::getOwnPropertyNames(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::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
407 }
408
409 bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow)
410 {
411     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
412     // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
413     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl()))
414         return false;
415
416     // Don't allow shadowing location using accessor properties.
417     if (descriptor.isAccessorDescriptor() && propertyName == Identifier(exec, "location"))
418         return false;
419
420     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
421 }
422
423 // Custom Attributes
424
425 void JSDOMWindow::setLocation(ExecState* exec, JSValue value)
426 {
427 #if ENABLE(DASHBOARD_SUPPORT)
428     // To avoid breaking old widgets, make "var location =" in a top-level frame create
429     // a property named "location" instead of performing a navigation (<rdar://problem/5688039>).
430     if (Frame* activeFrame = activeDOMWindow(exec)->frame()) {
431         if (activeFrame->settings().usesDashboardBackwardCompatibilityMode() && !activeFrame->tree().parent()) {
432             if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, impl()))
433                 putDirect(exec->vm(), Identifier(exec, "location"), value);
434             return;
435         }
436     }
437 #endif
438
439     String locationString = value.toString(exec)->value(exec);
440     if (exec->hadException())
441         return;
442
443     if (Location* location = impl()->location())
444         location->setHref(locationString, activeDOMWindow(exec), firstDOMWindow(exec));
445 }
446
447 JSValue JSDOMWindow::event(ExecState* exec) const
448 {
449     Event* event = currentEvent();
450     if (!event)
451         return jsUndefined();
452     return toJS(exec, const_cast<JSDOMWindow*>(this), event);
453 }
454
455 JSValue JSDOMWindow::image(ExecState* exec) const
456 {
457     return getDOMConstructor<JSImageConstructor>(exec->vm(), this);
458 }
459
460 // Custom functions
461
462 JSValue JSDOMWindow::open(ExecState* exec)
463 {
464     String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0));
465     if (exec->hadException())
466         return jsUndefined();
467     AtomicString frameName = exec->argument(1).isUndefinedOrNull() ? "_blank" : exec->argument(1).toString(exec)->value(exec);
468     if (exec->hadException())
469         return jsUndefined();
470     String windowFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2));
471     if (exec->hadException())
472         return jsUndefined();
473
474     RefPtr<DOMWindow> openedWindow = impl()->open(urlString, frameName, windowFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec));
475     if (!openedWindow)
476         return jsUndefined();
477     return toJS(exec, openedWindow.get());
478 }
479
480 class DialogHandler {
481 public:
482     explicit DialogHandler(ExecState* exec)
483         : m_exec(exec)
484     {
485     }
486
487     void dialogCreated(DOMWindow*);
488     JSValue returnValue() const;
489
490 private:
491     ExecState* m_exec;
492     RefPtr<Frame> m_frame;
493 };
494
495 inline void DialogHandler::dialogCreated(DOMWindow* dialog)
496 {
497     m_frame = dialog->frame();
498     // FIXME: This looks like a leak between the normal world and an isolated
499     //        world if dialogArguments comes from an isolated world.
500     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec->vm()));
501     if (JSValue dialogArguments = m_exec->argument(1))
502         globalObject->putDirect(m_exec->vm(), Identifier(m_exec, "dialogArguments"), dialogArguments);
503 }
504
505 inline JSValue DialogHandler::returnValue() const
506 {
507     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec->vm()));
508     if (!globalObject)
509         return jsUndefined();
510     Identifier identifier(m_exec, "returnValue");
511     PropertySlot slot(globalObject);
512     if (!JSGlobalObject::getOwnPropertySlot(globalObject, m_exec, identifier, slot))
513         return jsUndefined();
514     return slot.getValue(m_exec, identifier);
515 }
516
517 static void setUpDialog(DOMWindow* dialog, void* handler)
518 {
519     static_cast<DialogHandler*>(handler)->dialogCreated(dialog);
520 }
521
522 JSValue JSDOMWindow::showModalDialog(ExecState* exec)
523 {
524     String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0));
525     if (exec->hadException())
526         return jsUndefined();
527     String dialogFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2));
528     if (exec->hadException())
529         return jsUndefined();
530
531     DialogHandler handler(exec);
532
533     impl()->showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec), setUpDialog, &handler);
534
535     return handler.returnValue();
536 }
537
538 static JSValue handlePostMessage(DOMWindow* impl, ExecState* exec)
539 {
540     MessagePortArray messagePorts;
541     ArrayBufferArray arrayBuffers;
542
543     // This function has variable arguments and can be:
544     // Per current spec:
545     //   postMessage(message, targetOrigin)
546     //   postMessage(message, targetOrigin, {sequence of transferrables})
547     // Legacy non-standard implementations in webkit allowed:
548     //   postMessage(message, {sequence of transferrables}, targetOrigin);
549     int targetOriginArgIndex = 1;
550     if (exec->argumentCount() > 2) {
551         int transferablesArgIndex = 2;
552         if (exec->argument(2).isString()) {
553             targetOriginArgIndex = 2;
554             transferablesArgIndex = 1;
555         }
556         fillMessagePortArray(exec, exec->argument(transferablesArgIndex), messagePorts, arrayBuffers);
557     }
558     if (exec->hadException())
559         return jsUndefined();
560
561     RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0),
562                                                                          &messagePorts,
563                                                                          &arrayBuffers);
564
565     if (exec->hadException())
566         return jsUndefined();
567
568     String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(targetOriginArgIndex));
569     if (exec->hadException())
570         return jsUndefined();
571
572     ExceptionCode ec = 0;
573     impl->postMessage(message.release(), &messagePorts, targetOrigin, activeDOMWindow(exec), ec);
574     setDOMException(exec, ec);
575
576     return jsUndefined();
577 }
578
579 JSValue JSDOMWindow::postMessage(ExecState* exec)
580 {
581     return handlePostMessage(impl(), exec);
582 }
583
584 JSValue JSDOMWindow::setTimeout(ExecState* exec)
585 {
586     ContentSecurityPolicy* contentSecurityPolicy = impl()->document() ? impl()->document()->contentSecurityPolicy() : 0;
587     OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), contentSecurityPolicy);
588     if (exec->hadException())
589         return jsUndefined();
590
591     if (!action)
592         return jsNumber(0);
593
594     int delay = exec->argument(1).toInt32(exec);
595
596     ExceptionCode ec = 0;
597     int result = impl()->setTimeout(action.release(), delay, ec);
598     setDOMException(exec, ec);
599
600     return jsNumber(result);
601 }
602
603 JSValue JSDOMWindow::setInterval(ExecState* exec)
604 {
605     ContentSecurityPolicy* contentSecurityPolicy = impl()->document() ? impl()->document()->contentSecurityPolicy() : 0;
606     OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), contentSecurityPolicy);
607     if (exec->hadException())
608         return jsUndefined();
609     int delay = exec->argument(1).toInt32(exec);
610
611     if (!action)
612         return jsNumber(0);
613
614     ExceptionCode ec = 0;
615     int result = impl()->setInterval(action.release(), delay, ec);
616     setDOMException(exec, ec);
617
618     return jsNumber(result);
619 }
620
621 JSValue JSDOMWindow::addEventListener(ExecState* exec)
622 {
623     Frame* frame = impl()->frame();
624     if (!frame)
625         return jsUndefined();
626
627     JSValue listener = exec->argument(1);
628     if (!listener.isObject())
629         return jsUndefined();
630
631     impl()->addEventListener(exec->argument(0).toString(exec)->value(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), exec->argument(2).toBoolean(exec));
632     return jsUndefined();
633 }
634
635 JSValue JSDOMWindow::removeEventListener(ExecState* exec)
636 {
637     Frame* frame = impl()->frame();
638     if (!frame)
639         return jsUndefined();
640
641     JSValue listener = exec->argument(1);
642     if (!listener.isObject())
643         return jsUndefined();
644
645     impl()->removeEventListener(exec->argument(0).toString(exec)->value(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), exec->argument(2).toBoolean(exec));
646     return jsUndefined();
647 }
648
649 DOMWindow* toDOMWindow(JSValue value)
650 {
651     if (!value.isObject())
652         return 0;
653     JSObject* object = asObject(value);
654     if (object->inherits(JSDOMWindow::info()))
655         return jsCast<JSDOMWindow*>(object)->impl();
656     if (object->inherits(JSDOMWindowShell::info()))
657         return jsCast<JSDOMWindowShell*>(object)->impl();
658     return 0;
659 }
660
661 } // namespace WebCore