JSDOMWindowCustom.cpp revision 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00
1/*
2 * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "JSDOMWindowCustom.h"
22
23#include "Frame.h"
24#include "HTMLCollection.h"
25#include "HTMLDocument.h"
26#include "History.h"
27#include "JSArrayBuffer.h"
28#include "JSAudioConstructor.h"
29#include "JSDataView.h"
30#include "JSEvent.h"
31#include "JSEventListener.h"
32#include "JSEventSource.h"
33#include "JSFloat32Array.h"
34#include "JSHTMLCollection.h"
35#include "JSHistory.h"
36#include "JSImageConstructor.h"
37#include "JSInt16Array.h"
38#include "JSInt32Array.h"
39#include "JSInt8Array.h"
40#include "JSLocation.h"
41#include "JSMessageChannel.h"
42#include "JSMessagePortCustom.h"
43#include "JSOptionConstructor.h"
44#include "JSUint16Array.h"
45#include "JSUint32Array.h"
46#include "JSUint8Array.h"
47#include "JSWebKitCSSMatrix.h"
48#include "JSWebKitPoint.h"
49#include "JSWorker.h"
50#include "JSXMLHttpRequest.h"
51#include "JSXSLTProcessor.h"
52#include "Location.h"
53#include "MediaPlayer.h"
54#include "ScheduledAction.h"
55#include "Settings.h"
56#include "SharedWorkerRepository.h"
57#include <runtime/JSFunction.h>
58
59#if ENABLE(SHARED_WORKERS)
60#include "JSSharedWorker.h"
61#endif
62
63#if ENABLE(WEB_AUDIO)
64#include "JSAudioContext.h"
65#endif
66
67#if ENABLE(WEB_SOCKETS)
68#include "JSWebSocket.h"
69#endif
70
71using namespace JSC;
72
73namespace WebCore {
74
75void JSDOMWindow::markChildren(MarkStack& markStack)
76{
77    Base::markChildren(markStack);
78
79    impl()->markJSEventListeners(markStack);
80
81    JSGlobalData& globalData = *Heap::heap(this)->globalData();
82
83    markDOMObjectWrapper(markStack, globalData, impl()->optionalConsole());
84    markDOMObjectWrapper(markStack, globalData, impl()->optionalHistory());
85    markDOMObjectWrapper(markStack, globalData, impl()->optionalLocationbar());
86    markDOMObjectWrapper(markStack, globalData, impl()->optionalMenubar());
87    markDOMObjectWrapper(markStack, globalData, impl()->optionalNavigator());
88    markDOMObjectWrapper(markStack, globalData, impl()->optionalPersonalbar());
89    markDOMObjectWrapper(markStack, globalData, impl()->optionalScreen());
90    markDOMObjectWrapper(markStack, globalData, impl()->optionalScrollbars());
91    markDOMObjectWrapper(markStack, globalData, impl()->optionalSelection());
92    markDOMObjectWrapper(markStack, globalData, impl()->optionalStatusbar());
93    markDOMObjectWrapper(markStack, globalData, impl()->optionalToolbar());
94    markDOMObjectWrapper(markStack, globalData, impl()->optionalLocation());
95    markDOMObjectWrapper(markStack, globalData, impl()->optionalMedia());
96#if ENABLE(DOM_STORAGE)
97    markDOMObjectWrapper(markStack, globalData, impl()->optionalSessionStorage());
98    markDOMObjectWrapper(markStack, globalData, impl()->optionalLocalStorage());
99#endif
100#if ENABLE(OFFLINE_WEB_APPLICATIONS)
101    markDOMObjectWrapper(markStack, globalData, impl()->optionalApplicationCache());
102#endif
103}
104
105template<NativeFunction nativeFunction, int length>
106JSValue nonCachingStaticFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName)
107{
108    return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), length, propertyName, nativeFunction);
109}
110
111static JSValue childFrameGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
112{
113    return toJS(exec, static_cast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree()->child(identifierToAtomicString(propertyName))->domWindow());
114}
115
116static JSValue indexGetter(ExecState* exec, JSValue slotBase, unsigned index)
117{
118    return toJS(exec, static_cast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree()->child(index)->domWindow());
119}
120
121static JSValue namedItemGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
122{
123    JSDOMWindowBase* thisObj = static_cast<JSDOMWindow*>(asObject(slotBase));
124    Document* document = thisObj->impl()->frame()->document();
125
126    ASSERT(thisObj->allowsAccessFrom(exec));
127    ASSERT(document);
128    ASSERT(document->isHTMLDocument());
129
130    RefPtr<HTMLCollection> collection = document->windowNamedItems(identifierToString(propertyName));
131    if (collection->length() == 1)
132        return toJS(exec, collection->firstItem());
133    return toJS(exec, collection.get());
134}
135
136bool JSDOMWindow::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
137{
138    // When accessing a Window cross-domain, functions are always the native built-in ones, and they
139    // are not affected by properties changed on the Window or anything in its prototype chain.
140    // This is consistent with the behavior of Firefox.
141
142    const HashEntry* entry;
143
144    // We don't want any properties other than "close" and "closed" on a closed window.
145    if (!impl()->frame()) {
146        // The following code is safe for cross-domain and same domain use.
147        // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype).
148        entry = s_info.propHashTable(exec)->entry(exec, propertyName);
149        if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) {
150            slot.setCustom(this, entry->propertyGetter());
151            return true;
152        }
153        entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName);
154        if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) {
155            slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
156            return true;
157        }
158
159        // FIXME: We should have a message here that explains why the property access/function call was
160        // not allowed.
161        slot.setUndefined();
162        return true;
163    }
164
165    // We need to check for cross-domain access here without printing the generic warning message
166    // because we always allow access to some function, just different ones depending whether access
167    // is allowed.
168    String errorMessage;
169    bool allowsAccess = allowsAccessFrom(exec, errorMessage);
170
171    // Look for overrides before looking at any of our own properties, but ignore overrides completely
172    // if this is cross-domain access.
173    if (allowsAccess && JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot))
174        return true;
175
176    // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the
177    // prototype due to the blanket same origin (allowsAccessFrom) check at the end of getOwnPropertySlot.
178    // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of
179    // what prototype is actually set on this object.
180    entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName);
181    if (entry) {
182        if (entry->attributes() & Function) {
183            if (entry->function() == jsDOMWindowPrototypeFunctionBlur) {
184                if (!allowsAccess) {
185                    slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>);
186                    return true;
187                }
188            } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) {
189                if (!allowsAccess) {
190                    slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
191                    return true;
192                }
193            } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) {
194                if (!allowsAccess) {
195                    slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>);
196                    return true;
197                }
198            } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) {
199                if (!allowsAccess) {
200                    slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>);
201                    return true;
202                }
203            } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) {
204                if (!DOMWindow::canShowModalDialog(impl()->frame())) {
205                    slot.setUndefined();
206                    return true;
207                }
208            }
209        }
210    } else {
211        // Allow access to toString() cross-domain, but always Object.prototype.toString.
212        if (propertyName == exec->propertyNames().toString) {
213            if (!allowsAccess) {
214                slot.setCustom(this, objectToStringFunctionGetter);
215                return true;
216            }
217        }
218    }
219
220    entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName);
221    if (entry) {
222        slot.setCustom(this, entry->propertyGetter());
223        return true;
224    }
225
226    // Check for child frames by name before built-in properties to
227    // match Mozilla. This does not match IE, but some sites end up
228    // naming frames things that conflict with window properties that
229    // are in Moz but not IE. Since we have some of these, we have to do
230    // it the Moz way.
231    if (impl()->frame()->tree()->child(identifierToAtomicString(propertyName))) {
232        slot.setCustom(this, childFrameGetter);
233        return true;
234    }
235
236    // Do prototype lookup early so that functions and attributes in the prototype can have
237    // precedence over the index and name getters.
238    JSValue proto = prototype();
239    if (proto.isObject()) {
240        if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) {
241            if (!allowsAccess) {
242                printErrorMessage(errorMessage);
243                slot.setUndefined();
244            }
245            return true;
246        }
247    }
248
249    // FIXME: Search the whole frame hierarchy somewhere around here.
250    // We need to test the correct priority order.
251
252    // allow window[1] or parent[1] etc. (#56983)
253    bool ok;
254    unsigned i = propertyName.toArrayIndex(ok);
255    if (ok && i < impl()->frame()->tree()->childCount()) {
256        slot.setCustomIndex(this, i, indexGetter);
257        return true;
258    }
259
260    if (!allowsAccess) {
261        printErrorMessage(errorMessage);
262        slot.setUndefined();
263        return true;
264    }
265
266    // Allow shortcuts like 'Image1' instead of document.images.Image1
267    Document* document = impl()->frame()->document();
268    if (document->isHTMLDocument()) {
269        AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
270        if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) {
271            slot.setCustom(this, namedItemGetter);
272            return true;
273        }
274    }
275
276    return Base::getOwnPropertySlot(exec, propertyName, slot);
277}
278
279bool JSDOMWindow::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
280{
281    // Never allow cross-domain getOwnPropertyDescriptor
282    if (!allowsAccessFrom(exec))
283        return false;
284
285    const HashEntry* entry;
286
287    // We don't want any properties other than "close" and "closed" on a closed window.
288    if (!impl()->frame()) {
289        // The following code is safe for cross-domain and same domain use.
290        // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype).
291        entry = s_info.propHashTable(exec)->entry(exec, propertyName);
292        if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) {
293            descriptor.setDescriptor(jsBoolean(true), ReadOnly | DontDelete | DontEnum);
294            return true;
295        }
296        entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName);
297        if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) {
298            PropertySlot slot;
299            slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
300            descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
301            return true;
302        }
303        descriptor.setUndefined();
304        return true;
305    }
306
307    entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName);
308    if (entry) {
309        PropertySlot slot;
310        slot.setCustom(this, entry->propertyGetter());
311        descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
312        return true;
313    }
314
315    // Check for child frames by name before built-in properties to
316    // match Mozilla. This does not match IE, but some sites end up
317    // naming frames things that conflict with window properties that
318    // are in Moz but not IE. Since we have some of these, we have to do
319    // it the Moz way.
320    if (impl()->frame()->tree()->child(identifierToAtomicString(propertyName))) {
321        PropertySlot slot;
322        slot.setCustom(this, childFrameGetter);
323        descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
324        return true;
325    }
326
327    bool ok;
328    unsigned i = propertyName.toArrayIndex(ok);
329    if (ok && i < impl()->frame()->tree()->childCount()) {
330        PropertySlot slot;
331        slot.setCustomIndex(this, i, indexGetter);
332        descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
333        return true;
334    }
335
336    // Allow shortcuts like 'Image1' instead of document.images.Image1
337    Document* document = impl()->frame()->document();
338    if (document->isHTMLDocument()) {
339        AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
340        if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) {
341            PropertySlot slot;
342            slot.setCustom(this, namedItemGetter);
343            descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
344            return true;
345        }
346    }
347
348    return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
349}
350
351void JSDOMWindow::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
352{
353    if (!impl()->frame())
354        return;
355
356    // Optimization: access JavaScript global variables directly before involving the DOM.
357    if (JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) {
358        if (allowsAccessFrom(exec))
359            JSGlobalObject::put(exec, propertyName, value, slot);
360        return;
361    }
362
363    if (lookupPut<JSDOMWindow>(exec, propertyName, value, s_info.propHashTable(exec), this))
364        return;
365
366    if (allowsAccessFrom(exec))
367        Base::put(exec, propertyName, value, slot);
368}
369
370bool JSDOMWindow::deleteProperty(ExecState* exec, const Identifier& propertyName)
371{
372    // Only allow deleting properties by frames in the same origin.
373    if (!allowsAccessFrom(exec))
374        return false;
375    return Base::deleteProperty(exec, propertyName);
376}
377
378void JSDOMWindow::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
379{
380    // Only allow the window to enumerated by frames in the same origin.
381    if (!allowsAccessFrom(exec))
382        return;
383    Base::getPropertyNames(exec, propertyNames, mode);
384}
385
386void JSDOMWindow::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
387{
388    // Only allow the window to enumerated by frames in the same origin.
389    if (!allowsAccessFrom(exec))
390        return;
391    Base::getOwnPropertyNames(exec, propertyNames, mode);
392}
393
394void JSDOMWindow::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes)
395{
396    // Only allow defining getters by frames in the same origin.
397    if (!allowsAccessFrom(exec))
398        return;
399
400    // Don't allow shadowing location using defineGetter.
401    if (propertyName == "location")
402        return;
403
404    Base::defineGetter(exec, propertyName, getterFunction, attributes);
405}
406
407void JSDOMWindow::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes)
408{
409    // Only allow defining setters by frames in the same origin.
410    if (!allowsAccessFrom(exec))
411        return;
412    Base::defineSetter(exec, propertyName, setterFunction, attributes);
413}
414
415bool JSDOMWindow::defineOwnProperty(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor, bool shouldThrow)
416{
417    // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
418    if (!allowsAccessFrom(exec))
419        return false;
420    return Base::defineOwnProperty(exec, propertyName, descriptor, shouldThrow);
421}
422
423JSValue JSDOMWindow::lookupGetter(ExecState* exec, const Identifier& propertyName)
424{
425    // Only allow looking-up getters by frames in the same origin.
426    if (!allowsAccessFrom(exec))
427        return jsUndefined();
428    return Base::lookupGetter(exec, propertyName);
429}
430
431JSValue JSDOMWindow::lookupSetter(ExecState* exec, const Identifier& propertyName)
432{
433    // Only allow looking-up setters by frames in the same origin.
434    if (!allowsAccessFrom(exec))
435        return jsUndefined();
436    return Base::lookupSetter(exec, propertyName);
437}
438
439// Custom Attributes
440
441JSValue JSDOMWindow::history(ExecState* exec) const
442{
443    History* history = impl()->history();
444    if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), history))
445        return wrapper;
446
447    JSDOMWindow* window = const_cast<JSDOMWindow*>(this);
448    JSHistory* jsHistory = new (exec) JSHistory(getDOMStructure<JSHistory>(exec, window), window, history);
449    cacheWrapper(currentWorld(exec), history, jsHistory);
450    return jsHistory;
451}
452
453JSValue JSDOMWindow::location(ExecState* exec) const
454{
455    Location* location = impl()->location();
456    if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), location))
457        return wrapper;
458
459    JSDOMWindow* window = const_cast<JSDOMWindow*>(this);
460    JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, window), window, location);
461    cacheWrapper(currentWorld(exec), location, jsLocation);
462    return jsLocation;
463}
464
465void JSDOMWindow::setLocation(ExecState* exec, JSValue value)
466{
467#if ENABLE(DASHBOARD_SUPPORT)
468    // To avoid breaking old widgets, make "var location =" in a top-level frame create
469    // a property named "location" instead of performing a navigation (<rdar://problem/5688039>).
470    if (Frame* activeFrame = activeDOMWindow(exec)->frame()) {
471        if (Settings* settings = activeFrame->settings()) {
472            if (settings->usesDashboardBackwardCompatibilityMode() && !activeFrame->tree()->parent()) {
473                if (allowsAccessFrom(exec))
474                    putDirect(exec->globalData(), Identifier(exec, "location"), value);
475                return;
476            }
477        }
478    }
479#endif
480
481    UString locationString = value.toString(exec);
482    if (exec->hadException())
483        return;
484
485    impl()->setLocation(ustringToString(locationString), activeDOMWindow(exec), firstDOMWindow(exec));
486}
487
488JSValue JSDOMWindow::event(ExecState* exec) const
489{
490    Event* event = currentEvent();
491    if (!event)
492        return jsUndefined();
493    return toJS(exec, event);
494}
495
496#if ENABLE(EVENTSOURCE)
497JSValue JSDOMWindow::eventSource(ExecState* exec) const
498{
499    return getDOMConstructor<JSEventSourceConstructor>(exec, this);
500}
501#endif
502
503JSValue JSDOMWindow::image(ExecState* exec) const
504{
505    return getDOMConstructor<JSImageConstructor>(exec, this);
506}
507
508JSValue JSDOMWindow::option(ExecState* exec) const
509{
510    return getDOMConstructor<JSOptionConstructor>(exec, this);
511}
512
513#if ENABLE(VIDEO)
514JSValue JSDOMWindow::audio(ExecState* exec) const
515{
516    if (!MediaPlayer::isAvailable())
517        return jsUndefined();
518    return getDOMConstructor<JSAudioConstructor>(exec, this);
519}
520#endif
521
522JSValue JSDOMWindow::webKitPoint(ExecState* exec) const
523{
524    return getDOMConstructor<JSWebKitPointConstructor>(exec, this);
525}
526
527JSValue JSDOMWindow::webKitCSSMatrix(ExecState* exec) const
528{
529    return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec, this);
530}
531
532JSValue JSDOMWindow::arrayBuffer(ExecState* exec) const
533{
534    return getDOMConstructor<JSArrayBufferConstructor>(exec, this);
535}
536
537JSValue JSDOMWindow::int8Array(ExecState* exec) const
538{
539    return getDOMConstructor<JSInt8ArrayConstructor>(exec, this);
540}
541
542JSValue JSDOMWindow::uint8Array(ExecState* exec) const
543{
544    return getDOMConstructor<JSUint8ArrayConstructor>(exec, this);
545}
546
547JSValue JSDOMWindow::int32Array(ExecState* exec) const
548{
549    return getDOMConstructor<JSInt32ArrayConstructor>(exec, this);
550}
551
552JSValue JSDOMWindow::uint32Array(ExecState* exec) const
553{
554    return getDOMConstructor<JSUint32ArrayConstructor>(exec, this);
555}
556
557JSValue JSDOMWindow::int16Array(ExecState* exec) const
558{
559    return getDOMConstructor<JSInt16ArrayConstructor>(exec, this);
560}
561
562JSValue JSDOMWindow::uint16Array(ExecState* exec) const
563{
564    return getDOMConstructor<JSUint16ArrayConstructor>(exec, this);
565}
566
567JSValue JSDOMWindow::float32Array(ExecState* exec) const
568{
569    return getDOMConstructor<JSFloat32ArrayConstructor>(exec, this);
570}
571
572JSValue JSDOMWindow::dataView(ExecState* exec) const
573{
574    return getDOMConstructor<JSDataViewConstructor>(exec, this);
575}
576
577JSValue JSDOMWindow::xmlHttpRequest(ExecState* exec) const
578{
579    return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, this);
580}
581
582#if ENABLE(XSLT)
583JSValue JSDOMWindow::xsltProcessor(ExecState* exec) const
584{
585    return getDOMConstructor<JSXSLTProcessorConstructor>(exec, this);
586}
587#endif
588
589#if ENABLE(CHANNEL_MESSAGING)
590JSValue JSDOMWindow::messageChannel(ExecState* exec) const
591{
592    return getDOMConstructor<JSMessageChannelConstructor>(exec, this);
593}
594#endif
595
596#if ENABLE(WORKERS)
597JSValue JSDOMWindow::worker(ExecState* exec) const
598{
599    return getDOMConstructor<JSWorkerConstructor>(exec, this);
600}
601#endif
602
603#if ENABLE(SHARED_WORKERS)
604JSValue JSDOMWindow::sharedWorker(ExecState* exec) const
605{
606    if (SharedWorkerRepository::isAvailable())
607        return getDOMConstructor<JSSharedWorkerConstructor>(exec, this);
608    return jsUndefined();
609}
610#endif
611
612#if ENABLE(WEB_AUDIO)
613JSValue JSDOMWindow::webkitAudioContext(ExecState* exec) const
614{
615    return getDOMConstructor<JSAudioContextConstructor>(exec, this);
616}
617#endif
618
619#if ENABLE(WEB_SOCKETS)
620JSValue JSDOMWindow::webSocket(ExecState* exec) const
621{
622    Frame* frame = impl()->frame();
623    if (!frame)
624        return jsUndefined();
625    Settings* settings = frame->settings();
626    if (!settings)
627        return jsUndefined();
628    return getDOMConstructor<JSWebSocketConstructor>(exec, this);
629}
630#endif
631
632// Custom functions
633
634JSValue JSDOMWindow::open(ExecState* exec)
635{
636    String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0));
637    if (exec->hadException())
638        return jsUndefined();
639    AtomicString frameName = exec->argument(1).isUndefinedOrNull() ? "_blank" : ustringToAtomicString(exec->argument(1).toString(exec));
640    if (exec->hadException())
641        return jsUndefined();
642    String windowFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2));
643    if (exec->hadException())
644        return jsUndefined();
645
646    RefPtr<DOMWindow> openedWindow = impl()->open(urlString, frameName, windowFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec));
647    if (!openedWindow)
648        return jsUndefined();
649    return toJS(exec, openedWindow.get());
650}
651
652class DialogHandler {
653public:
654    explicit DialogHandler(ExecState* exec)
655        : m_exec(exec)
656        , m_globalObject(0)
657    {
658    }
659
660    void dialogCreated(DOMWindow*);
661    JSValue returnValue() const;
662
663private:
664    ExecState* m_exec;
665    JSDOMWindow* m_globalObject;
666};
667
668inline void DialogHandler::dialogCreated(DOMWindow* dialog)
669{
670    // FIXME: This looks like a leak between the normal world and an isolated
671    //        world if dialogArguments comes from an isolated world.
672    m_globalObject = toJSDOMWindow(dialog->frame(), normalWorld(m_exec->globalData()));
673    if (JSValue dialogArguments = m_exec->argument(1))
674        m_globalObject->putDirect(m_exec->globalData(), Identifier(m_exec, "dialogArguments"), dialogArguments);
675}
676
677inline JSValue DialogHandler::returnValue() const
678{
679    if (!m_globalObject)
680        return jsUndefined();
681    Identifier identifier(m_exec, "returnValue");
682    PropertySlot slot;
683    if (!m_globalObject->JSGlobalObject::getOwnPropertySlot(m_exec, identifier, slot))
684        return jsUndefined();
685    return slot.getValue(m_exec, identifier);
686}
687
688static void setUpDialog(DOMWindow* dialog, void* handler)
689{
690    static_cast<DialogHandler*>(handler)->dialogCreated(dialog);
691}
692
693JSValue JSDOMWindow::showModalDialog(ExecState* exec)
694{
695    String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0));
696    if (exec->hadException())
697        return jsUndefined();
698    String dialogFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2));
699    if (exec->hadException())
700        return jsUndefined();
701
702    DialogHandler handler(exec);
703
704    impl()->showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec), setUpDialog, &handler);
705
706    return handler.returnValue();
707}
708
709JSValue JSDOMWindow::postMessage(ExecState* exec)
710{
711    PassRefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0));
712
713    if (exec->hadException())
714        return jsUndefined();
715
716    MessagePortArray messagePorts;
717    if (exec->argumentCount() > 2)
718        fillMessagePortArray(exec, exec->argument(1), messagePorts);
719    if (exec->hadException())
720        return jsUndefined();
721
722    String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, exec->argument((exec->argumentCount() == 2) ? 1 : 2));
723    if (exec->hadException())
724        return jsUndefined();
725
726    ExceptionCode ec = 0;
727    impl()->postMessage(message, &messagePorts, targetOrigin, activeDOMWindow(exec), ec);
728    setDOMException(exec, ec);
729
730    return jsUndefined();
731}
732
733JSValue JSDOMWindow::setTimeout(ExecState* exec)
734{
735    ContentSecurityPolicy* contentSecurityPolicy = impl()->document() ? impl()->document()->contentSecurityPolicy() : 0;
736    OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), contentSecurityPolicy);
737    if (exec->hadException())
738        return jsUndefined();
739
740    if (!action)
741        return jsNumber(0);
742
743    int delay = exec->argument(1).toInt32(exec);
744
745    ExceptionCode ec = 0;
746    int result = impl()->setTimeout(action.release(), delay, ec);
747    setDOMException(exec, ec);
748
749    return jsNumber(result);
750}
751
752JSValue JSDOMWindow::setInterval(ExecState* exec)
753{
754    ContentSecurityPolicy* contentSecurityPolicy = impl()->document() ? impl()->document()->contentSecurityPolicy() : 0;
755    OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), contentSecurityPolicy);
756    if (exec->hadException())
757        return jsUndefined();
758    int delay = exec->argument(1).toInt32(exec);
759
760    if (!action)
761        return jsNumber(0);
762
763    ExceptionCode ec = 0;
764    int result = impl()->setInterval(action.release(), delay, ec);
765    setDOMException(exec, ec);
766
767    return jsNumber(result);
768}
769
770JSValue JSDOMWindow::addEventListener(ExecState* exec)
771{
772    Frame* frame = impl()->frame();
773    if (!frame)
774        return jsUndefined();
775
776    JSValue listener = exec->argument(1);
777    if (!listener.isObject())
778        return jsUndefined();
779
780    impl()->addEventListener(ustringToAtomicString(exec->argument(0).toString(exec)), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), exec->argument(2).toBoolean(exec));
781    return jsUndefined();
782}
783
784JSValue JSDOMWindow::removeEventListener(ExecState* exec)
785{
786    Frame* frame = impl()->frame();
787    if (!frame)
788        return jsUndefined();
789
790    JSValue listener = exec->argument(1);
791    if (!listener.isObject())
792        return jsUndefined();
793
794    impl()->removeEventListener(ustringToAtomicString(exec->argument(0).toString(exec)), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), exec->argument(2).toBoolean(exec));
795    return jsUndefined();
796}
797
798DOMWindow* toDOMWindow(JSValue value)
799{
800    if (!value.isObject())
801        return 0;
802    JSObject* object = asObject(value);
803    if (object->inherits(&JSDOMWindow::s_info))
804        return static_cast<JSDOMWindow*>(object)->impl();
805    if (object->inherits(&JSDOMWindowShell::s_info))
806        return static_cast<JSDOMWindowShell*>(object)->impl();
807    return 0;
808}
809
810} // namespace WebCore
811