Home | History | Annotate | Download | only in js
      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 
     71 using namespace JSC;
     72 
     73 namespace WebCore {
     74 
     75 void 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 
    105 template<NativeFunction nativeFunction, int length>
    106 JSValue nonCachingStaticFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName)
    107 {
    108     return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), length, propertyName, nativeFunction);
    109 }
    110 
    111 static 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 
    116 static 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 
    121 static 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 
    136 bool 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 
    279 bool 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 
    351 void 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 
    370 bool 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 
    378 void 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 
    386 void 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 
    394 void 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 
    407 void 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 
    415 bool 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 
    423 JSValue 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 
    431 JSValue 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 
    441 JSValue 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 
    453 JSValue 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 
    465 void 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 
    488 JSValue 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)
    497 JSValue JSDOMWindow::eventSource(ExecState* exec) const
    498 {
    499     return getDOMConstructor<JSEventSourceConstructor>(exec, this);
    500 }
    501 #endif
    502 
    503 JSValue JSDOMWindow::image(ExecState* exec) const
    504 {
    505     return getDOMConstructor<JSImageConstructor>(exec, this);
    506 }
    507 
    508 JSValue JSDOMWindow::option(ExecState* exec) const
    509 {
    510     return getDOMConstructor<JSOptionConstructor>(exec, this);
    511 }
    512 
    513 #if ENABLE(VIDEO)
    514 JSValue JSDOMWindow::audio(ExecState* exec) const
    515 {
    516     if (!MediaPlayer::isAvailable())
    517         return jsUndefined();
    518     return getDOMConstructor<JSAudioConstructor>(exec, this);
    519 }
    520 #endif
    521 
    522 JSValue JSDOMWindow::webKitPoint(ExecState* exec) const
    523 {
    524     return getDOMConstructor<JSWebKitPointConstructor>(exec, this);
    525 }
    526 
    527 JSValue JSDOMWindow::webKitCSSMatrix(ExecState* exec) const
    528 {
    529     return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec, this);
    530 }
    531 
    532 JSValue JSDOMWindow::arrayBuffer(ExecState* exec) const
    533 {
    534     return getDOMConstructor<JSArrayBufferConstructor>(exec, this);
    535 }
    536 
    537 JSValue JSDOMWindow::int8Array(ExecState* exec) const
    538 {
    539     return getDOMConstructor<JSInt8ArrayConstructor>(exec, this);
    540 }
    541 
    542 JSValue JSDOMWindow::uint8Array(ExecState* exec) const
    543 {
    544     return getDOMConstructor<JSUint8ArrayConstructor>(exec, this);
    545 }
    546 
    547 JSValue JSDOMWindow::int32Array(ExecState* exec) const
    548 {
    549     return getDOMConstructor<JSInt32ArrayConstructor>(exec, this);
    550 }
    551 
    552 JSValue JSDOMWindow::uint32Array(ExecState* exec) const
    553 {
    554     return getDOMConstructor<JSUint32ArrayConstructor>(exec, this);
    555 }
    556 
    557 JSValue JSDOMWindow::int16Array(ExecState* exec) const
    558 {
    559     return getDOMConstructor<JSInt16ArrayConstructor>(exec, this);
    560 }
    561 
    562 JSValue JSDOMWindow::uint16Array(ExecState* exec) const
    563 {
    564     return getDOMConstructor<JSUint16ArrayConstructor>(exec, this);
    565 }
    566 
    567 JSValue JSDOMWindow::float32Array(ExecState* exec) const
    568 {
    569     return getDOMConstructor<JSFloat32ArrayConstructor>(exec, this);
    570 }
    571 
    572 JSValue JSDOMWindow::dataView(ExecState* exec) const
    573 {
    574     return getDOMConstructor<JSDataViewConstructor>(exec, this);
    575 }
    576 
    577 JSValue JSDOMWindow::xmlHttpRequest(ExecState* exec) const
    578 {
    579     return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, this);
    580 }
    581 
    582 #if ENABLE(XSLT)
    583 JSValue JSDOMWindow::xsltProcessor(ExecState* exec) const
    584 {
    585     return getDOMConstructor<JSXSLTProcessorConstructor>(exec, this);
    586 }
    587 #endif
    588 
    589 #if ENABLE(CHANNEL_MESSAGING)
    590 JSValue JSDOMWindow::messageChannel(ExecState* exec) const
    591 {
    592     return getDOMConstructor<JSMessageChannelConstructor>(exec, this);
    593 }
    594 #endif
    595 
    596 #if ENABLE(WORKERS)
    597 JSValue JSDOMWindow::worker(ExecState* exec) const
    598 {
    599     return getDOMConstructor<JSWorkerConstructor>(exec, this);
    600 }
    601 #endif
    602 
    603 #if ENABLE(SHARED_WORKERS)
    604 JSValue 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)
    613 JSValue JSDOMWindow::webkitAudioContext(ExecState* exec) const
    614 {
    615     return getDOMConstructor<JSAudioContextConstructor>(exec, this);
    616 }
    617 #endif
    618 
    619 #if ENABLE(WEB_SOCKETS)
    620 JSValue 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 
    634 JSValue 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 
    652 class DialogHandler {
    653 public:
    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 
    663 private:
    664     ExecState* m_exec;
    665     JSDOMWindow* m_globalObject;
    666 };
    667 
    668 inline 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 
    677 inline 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 
    688 static void setUpDialog(DOMWindow* dialog, void* handler)
    689 {
    690     static_cast<DialogHandler*>(handler)->dialogCreated(dialog);
    691 }
    692 
    693 JSValue 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 
    709 JSValue 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 
    733 JSValue 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 
    752 JSValue 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 
    770 JSValue 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 
    784 JSValue 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 
    798 DOMWindow* 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