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