Home | History | Annotate | Download | only in js
      1 /*
      2  * Copyright (C) 2007, 2008, 2009 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 "AtomicString.h"
     24 #include "Base64.h"
     25 #include "Chrome.h"
     26 #include "DOMWindow.h"
     27 #include "Document.h"
     28 #include "ExceptionCode.h"
     29 #include "FloatRect.h"
     30 #include "Frame.h"
     31 #include "FrameLoadRequest.h"
     32 #include "FrameLoader.h"
     33 #include "FrameTree.h"
     34 #include "FrameView.h"
     35 #include "HTMLCollection.h"
     36 #include "HTMLDocument.h"
     37 #include "History.h"
     38 #include "JSAudioConstructor.h"
     39 #include "JSDOMWindowShell.h"
     40 #include "JSEvent.h"
     41 #include "JSEventListener.h"
     42 #include "JSEventSourceConstructor.h"
     43 #include "JSHTMLCollection.h"
     44 #include "JSHistory.h"
     45 #include "JSImageConstructor.h"
     46 #include "JSLocation.h"
     47 #include "JSMessageChannelConstructor.h"
     48 #include "JSMessagePort.h"
     49 #include "JSMessagePortCustom.h"
     50 #include "JSOptionConstructor.h"
     51 
     52 #if ENABLE(SHARED_WORKERS)
     53 #include "JSSharedWorkerConstructor.h"
     54 #endif
     55 
     56 #if ENABLE(3D_CANVAS)
     57 #include "JSWebGLArrayBufferConstructor.h"
     58 #include "JSWebGLByteArrayConstructor.h"
     59 #include "JSWebGLUnsignedByteArrayConstructor.h"
     60 #include "JSWebGLIntArrayConstructor.h"
     61 #include "JSWebGLUnsignedIntArrayConstructor.h"
     62 #include "JSWebGLShortArrayConstructor.h"
     63 #include "JSWebGLUnsignedShortArrayConstructor.h"
     64 #include "JSWebGLFloatArrayConstructor.h"
     65 #endif
     66 #include "JSWebKitCSSMatrixConstructor.h"
     67 #include "JSWebKitPointConstructor.h"
     68 #if ENABLE(WEB_SOCKETS)
     69 #include "JSWebSocketConstructor.h"
     70 #endif
     71 #include "JSWorkerConstructor.h"
     72 #include "JSXMLHttpRequestConstructor.h"
     73 #include "JSXSLTProcessorConstructor.h"
     74 #include "Location.h"
     75 #include "MediaPlayer.h"
     76 #include "MessagePort.h"
     77 #include "NotificationCenter.h"
     78 #include "Page.h"
     79 #include "PlatformScreen.h"
     80 #include "RegisteredEventListener.h"
     81 #include "ScheduledAction.h"
     82 #include "ScriptController.h"
     83 #include "SerializedScriptValue.h"
     84 #include "Settings.h"
     85 #include "SharedWorkerRepository.h"
     86 #include "WindowFeatures.h"
     87 #include <runtime/Error.h>
     88 #include <runtime/JSFunction.h>
     89 #include <runtime/JSObject.h>
     90 #include <runtime/PrototypeFunction.h>
     91 
     92 using namespace JSC;
     93 
     94 namespace WebCore {
     95 
     96 void JSDOMWindow::markChildren(MarkStack& markStack)
     97 {
     98     Base::markChildren(markStack);
     99 
    100     impl()->markJSEventListeners(markStack);
    101 
    102     JSGlobalData& globalData = *Heap::heap(this)->globalData();
    103 
    104     markDOMObjectWrapper(markStack, globalData, impl()->optionalConsole());
    105     markDOMObjectWrapper(markStack, globalData, impl()->optionalHistory());
    106     markDOMObjectWrapper(markStack, globalData, impl()->optionalLocationbar());
    107     markDOMObjectWrapper(markStack, globalData, impl()->optionalMenubar());
    108     markDOMObjectWrapper(markStack, globalData, impl()->optionalNavigator());
    109     markDOMObjectWrapper(markStack, globalData, impl()->optionalPersonalbar());
    110     markDOMObjectWrapper(markStack, globalData, impl()->optionalScreen());
    111     markDOMObjectWrapper(markStack, globalData, impl()->optionalScrollbars());
    112     markDOMObjectWrapper(markStack, globalData, impl()->optionalSelection());
    113     markDOMObjectWrapper(markStack, globalData, impl()->optionalStatusbar());
    114     markDOMObjectWrapper(markStack, globalData, impl()->optionalToolbar());
    115     markDOMObjectWrapper(markStack, globalData, impl()->optionalLocation());
    116     markDOMObjectWrapper(markStack, globalData, impl()->optionalMedia());
    117 #if ENABLE(DOM_STORAGE)
    118     markDOMObjectWrapper(markStack, globalData, impl()->optionalSessionStorage());
    119     markDOMObjectWrapper(markStack, globalData, impl()->optionalLocalStorage());
    120 #endif
    121 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
    122     markDOMObjectWrapper(markStack, globalData, impl()->optionalApplicationCache());
    123 #endif
    124 }
    125 
    126 template<NativeFunction nativeFunction, int length>
    127 JSValue nonCachingStaticFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot&)
    128 {
    129     return new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), length, propertyName, nativeFunction);
    130 }
    131 
    132 static JSValue childFrameGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
    133 {
    134     return toJS(exec, static_cast<JSDOMWindow*>(asObject(slot.slotBase()))->impl()->frame()->tree()->child(AtomicString(propertyName))->domWindow());
    135 }
    136 
    137 static JSValue indexGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)
    138 {
    139     return toJS(exec, static_cast<JSDOMWindow*>(asObject(slot.slotBase()))->impl()->frame()->tree()->child(slot.index())->domWindow());
    140 }
    141 
    142 static JSValue namedItemGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
    143 {
    144     JSDOMWindowBase* thisObj = static_cast<JSDOMWindow*>(asObject(slot.slotBase()));
    145     Document* document = thisObj->impl()->frame()->document();
    146 
    147     ASSERT(thisObj->allowsAccessFrom(exec));
    148     ASSERT(document);
    149     ASSERT(document->isHTMLDocument());
    150 
    151     RefPtr<HTMLCollection> collection = document->windowNamedItems(propertyName);
    152     if (collection->length() == 1)
    153         return toJS(exec, collection->firstItem());
    154     return toJS(exec, collection.get());
    155 }
    156 
    157 bool JSDOMWindow::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    158 {
    159     // When accessing a Window cross-domain, functions are always the native built-in ones, and they
    160     // are not affected by properties changed on the Window or anything in its prototype chain.
    161     // This is consistent with the behavior of Firefox.
    162 
    163     const HashEntry* entry;
    164 
    165     // We don't want any properties other than "close" and "closed" on a closed window.
    166     if (!impl()->frame()) {
    167         // The following code is safe for cross-domain and same domain use.
    168         // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype).
    169         entry = s_info.propHashTable(exec)->entry(exec, propertyName);
    170         if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) {
    171             slot.setCustom(this, entry->propertyGetter());
    172             return true;
    173         }
    174         entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName);
    175         if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) {
    176             slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
    177             return true;
    178         }
    179 
    180         // FIXME: We should have a message here that explains why the property access/function call was
    181         // not allowed.
    182         slot.setUndefined();
    183         return true;
    184     }
    185 
    186     // We need to check for cross-domain access here without printing the generic warning message
    187     // because we always allow access to some function, just different ones depending whether access
    188     // is allowed.
    189     String errorMessage;
    190     bool allowsAccess = allowsAccessFrom(exec, errorMessage);
    191 
    192     // Look for overrides before looking at any of our own properties, but ignore overrides completely
    193     // if this is cross-domain access.
    194     if (allowsAccess && JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot))
    195         return true;
    196 
    197     // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the
    198     // prototype due to the blanket same origin (allowsAccessFrom) check at the end of getOwnPropertySlot.
    199     // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of
    200     // what prototype is actually set on this object.
    201     entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName);
    202     if (entry) {
    203         if (entry->attributes() & Function) {
    204             if (entry->function() == jsDOMWindowPrototypeFunctionBlur) {
    205                 if (!allowsAccess) {
    206                     slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>);
    207                     return true;
    208                 }
    209             } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) {
    210                 if (!allowsAccess) {
    211                     slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
    212                     return true;
    213                 }
    214             } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) {
    215                 if (!allowsAccess) {
    216                     slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>);
    217                     return true;
    218                 }
    219             } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) {
    220                 if (!allowsAccess) {
    221                     slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>);
    222                     return true;
    223                 }
    224             } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) {
    225                 if (!DOMWindow::canShowModalDialog(impl()->frame())) {
    226                     slot.setUndefined();
    227                     return true;
    228                 }
    229             }
    230         }
    231     } else {
    232         // Allow access to toString() cross-domain, but always Object.prototype.toString.
    233         if (propertyName == exec->propertyNames().toString) {
    234             if (!allowsAccess) {
    235                 slot.setCustom(this, objectToStringFunctionGetter);
    236                 return true;
    237             }
    238         }
    239     }
    240 
    241     entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName);
    242     if (entry) {
    243         slot.setCustom(this, entry->propertyGetter());
    244         return true;
    245     }
    246 
    247     // Check for child frames by name before built-in properties to
    248     // match Mozilla. This does not match IE, but some sites end up
    249     // naming frames things that conflict with window properties that
    250     // are in Moz but not IE. Since we have some of these, we have to do
    251     // it the Moz way.
    252     if (impl()->frame()->tree()->child(propertyName)) {
    253         slot.setCustom(this, childFrameGetter);
    254         return true;
    255     }
    256 
    257     // Do prototype lookup early so that functions and attributes in the prototype can have
    258     // precedence over the index and name getters.
    259     JSValue proto = prototype();
    260     if (proto.isObject()) {
    261         if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) {
    262             if (!allowsAccess) {
    263                 printErrorMessage(errorMessage);
    264                 slot.setUndefined();
    265             }
    266             return true;
    267         }
    268     }
    269 
    270     // FIXME: Search the whole frame hierarchy somewhere around here.
    271     // We need to test the correct priority order.
    272 
    273     // allow window[1] or parent[1] etc. (#56983)
    274     bool ok;
    275     unsigned i = propertyName.toArrayIndex(&ok);
    276     if (ok && i < impl()->frame()->tree()->childCount()) {
    277         slot.setCustomIndex(this, i, indexGetter);
    278         return true;
    279     }
    280 
    281     if (!allowsAccess) {
    282         printErrorMessage(errorMessage);
    283         slot.setUndefined();
    284         return true;
    285     }
    286 
    287     // Allow shortcuts like 'Image1' instead of document.images.Image1
    288     Document* document = impl()->frame()->document();
    289     if (document->isHTMLDocument()) {
    290         AtomicStringImpl* atomicPropertyName = AtomicString::find(propertyName);
    291         if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) {
    292             slot.setCustom(this, namedItemGetter);
    293             return true;
    294         }
    295     }
    296 
    297     return Base::getOwnPropertySlot(exec, propertyName, slot);
    298 }
    299 
    300 bool JSDOMWindow::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
    301 {
    302     // Never allow cross-domain getOwnPropertyDescriptor
    303     if (!allowsAccessFrom(exec))
    304         return false;
    305 
    306     const HashEntry* entry;
    307 
    308     // We don't want any properties other than "close" and "closed" on a closed window.
    309     if (!impl()->frame()) {
    310         // The following code is safe for cross-domain and same domain use.
    311         // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype).
    312         entry = s_info.propHashTable(exec)->entry(exec, propertyName);
    313         if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) {
    314             descriptor.setDescriptor(jsBoolean(true), ReadOnly | DontDelete | DontEnum);
    315             return true;
    316         }
    317         entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName);
    318         if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) {
    319             PropertySlot slot;
    320             slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
    321             descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
    322             return true;
    323         }
    324         descriptor.setUndefined();
    325         return true;
    326     }
    327 
    328     entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName);
    329     if (entry) {
    330         PropertySlot slot;
    331         slot.setCustom(this, entry->propertyGetter());
    332         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
    333         return true;
    334     }
    335 
    336     // Check for child frames by name before built-in properties to
    337     // match Mozilla. This does not match IE, but some sites end up
    338     // naming frames things that conflict with window properties that
    339     // are in Moz but not IE. Since we have some of these, we have to do
    340     // it the Moz way.
    341     if (impl()->frame()->tree()->child(propertyName)) {
    342         PropertySlot slot;
    343         slot.setCustom(this, childFrameGetter);
    344         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
    345         return true;
    346     }
    347 
    348     bool ok;
    349     unsigned i = propertyName.toArrayIndex(&ok);
    350     if (ok && i < impl()->frame()->tree()->childCount()) {
    351         PropertySlot slot;
    352         slot.setCustomIndex(this, i, indexGetter);
    353         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
    354         return true;
    355     }
    356 
    357     // Allow shortcuts like 'Image1' instead of document.images.Image1
    358     Document* document = impl()->frame()->document();
    359     if (document->isHTMLDocument()) {
    360         AtomicStringImpl* atomicPropertyName = AtomicString::find(propertyName);
    361         if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) {
    362             PropertySlot slot;
    363             slot.setCustom(this, namedItemGetter);
    364             descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
    365             return true;
    366         }
    367     }
    368 
    369     return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
    370 }
    371 
    372 void JSDOMWindow::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    373 {
    374     if (!impl()->frame())
    375         return;
    376 
    377     // Optimization: access JavaScript global variables directly before involving the DOM.
    378     if (JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) {
    379         if (allowsAccessFrom(exec))
    380             JSGlobalObject::put(exec, propertyName, value, slot);
    381         return;
    382     }
    383 
    384     if (lookupPut<JSDOMWindow>(exec, propertyName, value, s_info.propHashTable(exec), this))
    385         return;
    386 
    387     if (allowsAccessFrom(exec))
    388         Base::put(exec, propertyName, value, slot);
    389 }
    390 
    391 bool JSDOMWindow::deleteProperty(ExecState* exec, const Identifier& propertyName)
    392 {
    393     // Only allow deleting properties by frames in the same origin.
    394     if (!allowsAccessFrom(exec))
    395         return false;
    396     return Base::deleteProperty(exec, propertyName);
    397 }
    398 
    399 void JSDOMWindow::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
    400 {
    401     // Only allow the window to enumerated by frames in the same origin.
    402     if (!allowsAccessFrom(exec))
    403         return;
    404     Base::getPropertyNames(exec, propertyNames, mode);
    405 }
    406 
    407 void JSDOMWindow::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
    408 {
    409     // Only allow the window to enumerated by frames in the same origin.
    410     if (!allowsAccessFrom(exec))
    411         return;
    412     Base::getOwnPropertyNames(exec, propertyNames, mode);
    413 }
    414 
    415 void JSDOMWindow::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes)
    416 {
    417     // Only allow defining getters by frames in the same origin.
    418     if (!allowsAccessFrom(exec))
    419         return;
    420 
    421     // Don't allow shadowing location using defineGetter.
    422     if (propertyName == "location")
    423         return;
    424 
    425     Base::defineGetter(exec, propertyName, getterFunction, attributes);
    426 }
    427 
    428 void JSDOMWindow::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes)
    429 {
    430     // Only allow defining setters by frames in the same origin.
    431     if (!allowsAccessFrom(exec))
    432         return;
    433     Base::defineSetter(exec, propertyName, setterFunction, attributes);
    434 }
    435 
    436 bool JSDOMWindow::defineOwnProperty(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor, bool shouldThrow)
    437 {
    438     // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
    439     if (!allowsAccessFrom(exec))
    440         return false;
    441     return Base::defineOwnProperty(exec, propertyName, descriptor, shouldThrow);
    442 }
    443 
    444 JSValue JSDOMWindow::lookupGetter(ExecState* exec, const Identifier& propertyName)
    445 {
    446     // Only allow looking-up getters by frames in the same origin.
    447     if (!allowsAccessFrom(exec))
    448         return jsUndefined();
    449     return Base::lookupGetter(exec, propertyName);
    450 }
    451 
    452 JSValue JSDOMWindow::lookupSetter(ExecState* exec, const Identifier& propertyName)
    453 {
    454     // Only allow looking-up setters by frames in the same origin.
    455     if (!allowsAccessFrom(exec))
    456         return jsUndefined();
    457     return Base::lookupSetter(exec, propertyName);
    458 }
    459 
    460 // Custom Attributes
    461 
    462 JSValue JSDOMWindow::history(ExecState* exec) const
    463 {
    464     History* history = impl()->history();
    465     if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, history))
    466         return wrapper;
    467 
    468     JSDOMWindow* window = const_cast<JSDOMWindow*>(this);
    469     JSHistory* jsHistory = new (exec) JSHistory(getDOMStructure<JSHistory>(exec, window), window, history);
    470     cacheDOMObjectWrapper(exec, history, jsHistory);
    471     return jsHistory;
    472 }
    473 
    474 JSValue JSDOMWindow::location(ExecState* exec) const
    475 {
    476     Location* location = impl()->location();
    477     if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, location))
    478         return wrapper;
    479 
    480     JSDOMWindow* window = const_cast<JSDOMWindow*>(this);
    481     JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, window), window, location);
    482     cacheDOMObjectWrapper(exec, location, jsLocation);
    483     return jsLocation;
    484 }
    485 
    486 void JSDOMWindow::setLocation(ExecState* exec, JSValue value)
    487 {
    488     Frame* lexicalFrame = toLexicalFrame(exec);
    489     if (!lexicalFrame)
    490         return;
    491 
    492 #if ENABLE(DASHBOARD_SUPPORT)
    493     // To avoid breaking old widgets, make "var location =" in a top-level frame create
    494     // a property named "location" instead of performing a navigation (<rdar://problem/5688039>).
    495     if (Settings* settings = lexicalFrame->settings()) {
    496         if (settings->usesDashboardBackwardCompatibilityMode() && !lexicalFrame->tree()->parent()) {
    497             if (allowsAccessFrom(exec))
    498                 putDirect(Identifier(exec, "location"), value);
    499             return;
    500         }
    501     }
    502 #endif
    503 
    504     Frame* frame = impl()->frame();
    505     ASSERT(frame);
    506 
    507     KURL url = completeURL(exec, value.toString(exec));
    508     if (url.isNull())
    509         return;
    510 
    511     if (!shouldAllowNavigation(exec, frame))
    512         return;
    513 
    514     if (!protocolIsJavaScript(url) || allowsAccessFrom(exec)) {
    515         // We want a new history item if this JS was called via a user gesture
    516         frame->redirectScheduler()->scheduleLocationChange(url, lexicalFrame->loader()->outgoingReferrer(), !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, processingUserGesture(exec));
    517     }
    518 }
    519 
    520 JSValue JSDOMWindow::crypto(ExecState*) const
    521 {
    522     return jsUndefined();
    523 }
    524 
    525 JSValue JSDOMWindow::event(ExecState* exec) const
    526 {
    527     Event* event = currentEvent();
    528     if (!event)
    529         return jsUndefined();
    530     return toJS(exec, event);
    531 }
    532 
    533 #if ENABLE(EVENTSOURCE)
    534 JSValue JSDOMWindow::eventSource(ExecState* exec) const
    535 {
    536     return getDOMConstructor<JSEventSourceConstructor>(exec, this);
    537 }
    538 #endif
    539 
    540 JSValue JSDOMWindow::image(ExecState* exec) const
    541 {
    542     return getDOMConstructor<JSImageConstructor>(exec, this);
    543 }
    544 
    545 JSValue JSDOMWindow::option(ExecState* exec) const
    546 {
    547     return getDOMConstructor<JSOptionConstructor>(exec, this);
    548 }
    549 
    550 #if ENABLE(VIDEO)
    551 JSValue JSDOMWindow::audio(ExecState* exec) const
    552 {
    553     if (!MediaPlayer::isAvailable())
    554         return jsUndefined();
    555     return getDOMConstructor<JSAudioConstructor>(exec, this);
    556 }
    557 #endif
    558 
    559 JSValue JSDOMWindow::webKitPoint(ExecState* exec) const
    560 {
    561     return getDOMConstructor<JSWebKitPointConstructor>(exec, this);
    562 }
    563 
    564 JSValue JSDOMWindow::webKitCSSMatrix(ExecState* exec) const
    565 {
    566     return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec, this);
    567 }
    568 
    569 #if ENABLE(3D_CANVAS)
    570 JSValue JSDOMWindow::webGLArrayBuffer(ExecState* exec) const
    571 {
    572     return getDOMConstructor<JSWebGLArrayBufferConstructor>(exec, this);
    573 }
    574 
    575 JSValue JSDOMWindow::webGLByteArray(ExecState* exec) const
    576 {
    577     return getDOMConstructor<JSWebGLByteArrayConstructor>(exec, this);
    578 }
    579 
    580 JSValue JSDOMWindow::webGLUnsignedByteArray(ExecState* exec) const
    581 {
    582     return getDOMConstructor<JSWebGLUnsignedByteArrayConstructor>(exec, this);
    583 }
    584 
    585 JSValue JSDOMWindow::webGLIntArray(ExecState* exec) const
    586 {
    587     return getDOMConstructor<JSWebGLIntArrayConstructor>(exec, this);
    588 }
    589 
    590 JSValue JSDOMWindow::webGLUnsignedIntArray(ExecState* exec) const
    591 {
    592     return getDOMConstructor<JSWebGLUnsignedIntArrayConstructor>(exec, this);
    593 }
    594 
    595 JSValue JSDOMWindow::webGLShortArray(ExecState* exec) const
    596 {
    597     return getDOMConstructor<JSWebGLShortArrayConstructor>(exec, this);
    598 }
    599 
    600 JSValue JSDOMWindow::webGLUnsignedShortArray(ExecState* exec) const
    601 {
    602     return getDOMConstructor<JSWebGLUnsignedShortArrayConstructor>(exec, this);
    603 }
    604 
    605 JSValue JSDOMWindow::webGLFloatArray(ExecState* exec) const
    606 {
    607     return getDOMConstructor<JSWebGLFloatArrayConstructor>(exec, this);
    608 }
    609 #endif
    610 
    611 JSValue JSDOMWindow::xmlHttpRequest(ExecState* exec) const
    612 {
    613     return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, this);
    614 }
    615 
    616 #if ENABLE(XSLT)
    617 JSValue JSDOMWindow::xsltProcessor(ExecState* exec) const
    618 {
    619     return getDOMConstructor<JSXSLTProcessorConstructor>(exec, this);
    620 }
    621 #endif
    622 
    623 #if ENABLE(CHANNEL_MESSAGING)
    624 JSValue JSDOMWindow::messageChannel(ExecState* exec) const
    625 {
    626     return getDOMConstructor<JSMessageChannelConstructor>(exec, this);
    627 }
    628 #endif
    629 
    630 #if ENABLE(WORKERS)
    631 JSValue JSDOMWindow::worker(ExecState* exec) const
    632 {
    633     return getDOMConstructor<JSWorkerConstructor>(exec, this);
    634 }
    635 #endif
    636 
    637 #if ENABLE(SHARED_WORKERS)
    638 JSValue JSDOMWindow::sharedWorker(ExecState* exec) const
    639 {
    640     if (SharedWorkerRepository::isAvailable())
    641         return getDOMConstructor<JSSharedWorkerConstructor>(exec, this);
    642     return jsUndefined();
    643 }
    644 #endif
    645 
    646 #if ENABLE(WEB_SOCKETS)
    647 JSValue JSDOMWindow::webSocket(ExecState* exec) const
    648 {
    649     Frame* frame = impl()->frame();
    650     if (!frame)
    651         return jsUndefined();
    652     Settings* settings = frame->settings();
    653     if (!settings)
    654         return jsUndefined();
    655     return getDOMConstructor<JSWebSocketConstructor>(exec, this);
    656 }
    657 #endif
    658 
    659 // Custom functions
    660 
    661 // Helper for window.open() and window.showModalDialog()
    662 static Frame* createWindow(ExecState* exec, Frame* lexicalFrame, Frame* dynamicFrame,
    663                            Frame* openerFrame, const String& url, const String& frameName,
    664                            const WindowFeatures& windowFeatures, JSValue dialogArgs)
    665 {
    666     ASSERT(lexicalFrame);
    667     ASSERT(dynamicFrame);
    668 
    669     if (Document* lexicalDocument = lexicalFrame->document()) {
    670         // Sandboxed iframes cannot open new auxiliary browsing contexts.
    671         if (lexicalDocument->securityOrigin()->isSandboxed(SandboxNavigation))
    672             return 0;
    673     }
    674 
    675     ResourceRequest request;
    676 
    677     // For whatever reason, Firefox uses the dynamicGlobalObject to determine
    678     // the outgoingReferrer.  We replicate that behavior here.
    679     String referrer = dynamicFrame->loader()->outgoingReferrer();
    680     request.setHTTPReferrer(referrer);
    681     FrameLoader::addHTTPOriginIfNeeded(request, dynamicFrame->loader()->outgoingOrigin());
    682     FrameLoadRequest frameRequest(request, frameName);
    683 
    684     // FIXME: It's much better for client API if a new window starts with a URL, here where we
    685     // know what URL we are going to open. Unfortunately, this code passes the empty string
    686     // for the URL, but there's a reason for that. Before loading we have to set up the opener,
    687     // openedByDOM, and dialogArguments values. Also, to decide whether to use the URL we currently
    688     // do an allowsAccessFrom call using the window we create, which can't be done before creating it.
    689     // We'd have to resolve all those issues to pass the URL instead of "".
    690 
    691     bool created;
    692     // We pass in the opener frame here so it can be used for looking up the frame name, in case the active frame
    693     // is different from the opener frame, and the name references a frame relative to the opener frame, for example
    694     // "_self" or "_parent".
    695     Frame* newFrame = lexicalFrame->loader()->createWindow(openerFrame->loader(), frameRequest, windowFeatures, created);
    696     if (!newFrame)
    697         return 0;
    698 
    699     newFrame->loader()->setOpener(openerFrame);
    700     newFrame->page()->setOpenedByDOM();
    701 
    702     // FIXME: If a window is created from an isolated world, what are the consequences of this? 'dialogArguments' only appears back in the normal world?
    703     JSDOMWindow* newWindow = toJSDOMWindow(newFrame, normalWorld(exec->globalData()));
    704 
    705     if (dialogArgs)
    706         newWindow->putDirect(Identifier(exec, "dialogArguments"), dialogArgs);
    707 
    708     if (!protocolIsJavaScript(url) || newWindow->allowsAccessFrom(exec)) {
    709         KURL completedURL = url.isEmpty() ? KURL(ParsedURLString, "") : completeURL(exec, url);
    710         bool userGesture = processingUserGesture(exec);
    711 
    712         if (created)
    713             newFrame->loader()->changeLocation(completedURL, referrer, false, false, userGesture);
    714         else if (!url.isEmpty())
    715             newFrame->redirectScheduler()->scheduleLocationChange(completedURL.string(), referrer, !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture);
    716     }
    717 
    718     return newFrame;
    719 }
    720 
    721 static bool domWindowAllowPopUp(Frame* activeFrame, ExecState* exec)
    722 {
    723     ASSERT(activeFrame);
    724     if (activeFrame->script()->processingUserGesture(currentWorld(exec)))
    725         return true;
    726     return DOMWindow::allowPopUp(activeFrame);
    727 }
    728 
    729 JSValue JSDOMWindow::open(ExecState* exec, const ArgList& args)
    730 {
    731     String urlString = valueToStringWithUndefinedOrNullCheck(exec, args.at(0));
    732     AtomicString frameName = args.at(1).isUndefinedOrNull() ? "_blank" : AtomicString(args.at(1).toString(exec));
    733     WindowFeatures windowFeatures(valueToStringWithUndefinedOrNullCheck(exec, args.at(2)));
    734 
    735     Frame* frame = impl()->frame();
    736     if (!frame)
    737         return jsUndefined();
    738     Frame* lexicalFrame = toLexicalFrame(exec);
    739     if (!lexicalFrame)
    740         return jsUndefined();
    741     Frame* dynamicFrame = toDynamicFrame(exec);
    742     if (!dynamicFrame)
    743         return jsUndefined();
    744 
    745     Page* page = frame->page();
    746 
    747     // Because FrameTree::find() returns true for empty strings, we must check for empty framenames.
    748     // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
    749     if (!domWindowAllowPopUp(dynamicFrame, exec) && (frameName.isEmpty() || !frame->tree()->find(frameName)))
    750         return jsUndefined();
    751 
    752     // Get the target frame for the special cases of _top and _parent.  In those
    753     // cases, we can schedule a location change right now and return early.
    754     bool topOrParent = false;
    755     if (frameName == "_top") {
    756         frame = frame->tree()->top();
    757         topOrParent = true;
    758     } else if (frameName == "_parent") {
    759         if (Frame* parent = frame->tree()->parent())
    760             frame = parent;
    761         topOrParent = true;
    762     }
    763     if (topOrParent) {
    764         String completedURL;
    765         if (!urlString.isEmpty())
    766             completedURL = completeURL(exec, urlString).string();
    767 
    768         if (!shouldAllowNavigation(exec, frame))
    769             return jsUndefined();
    770 
    771         const JSDOMWindow* targetedWindow = toJSDOMWindow(frame, currentWorld(exec));
    772         if (!completedURL.isEmpty() && (!protocolIsJavaScript(completedURL) || (targetedWindow && targetedWindow->allowsAccessFrom(exec)))) {
    773             bool userGesture = processingUserGesture(exec);
    774 
    775             // For whatever reason, Firefox uses the dynamicGlobalObject to
    776             // determine the outgoingReferrer.  We replicate that behavior
    777             // here.
    778             String referrer = dynamicFrame->loader()->outgoingReferrer();
    779 
    780             frame->redirectScheduler()->scheduleLocationChange(completedURL, referrer, !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture);
    781         }
    782         return toJS(exec, frame->domWindow());
    783     }
    784 
    785     // In the case of a named frame or a new window, we'll use the createWindow() helper
    786     FloatRect windowRect(windowFeatures.xSet ? windowFeatures.x : 0, windowFeatures.ySet ? windowFeatures.y : 0,
    787                          windowFeatures.widthSet ? windowFeatures.width : 0, windowFeatures.heightSet ? windowFeatures.height : 0);
    788     DOMWindow::adjustWindowRect(screenAvailableRect(page ? page->mainFrame()->view() : 0), windowRect, windowRect);
    789 
    790     windowFeatures.x = windowRect.x();
    791     windowFeatures.y = windowRect.y();
    792     windowFeatures.height = windowRect.height();
    793     windowFeatures.width = windowRect.width();
    794 
    795     frame = createWindow(exec, lexicalFrame, dynamicFrame, frame, urlString, frameName, windowFeatures, JSValue());
    796 
    797     if (!frame)
    798         return jsUndefined();
    799 
    800     return toJS(exec, frame->domWindow());
    801 }
    802 
    803 JSValue JSDOMWindow::showModalDialog(ExecState* exec, const ArgList& args)
    804 {
    805     String url = valueToStringWithUndefinedOrNullCheck(exec, args.at(0));
    806     JSValue dialogArgs = args.at(1);
    807     String featureArgs = valueToStringWithUndefinedOrNullCheck(exec, args.at(2));
    808 
    809     Frame* frame = impl()->frame();
    810     if (!frame)
    811         return jsUndefined();
    812     Frame* lexicalFrame = toLexicalFrame(exec);
    813     if (!lexicalFrame)
    814         return jsUndefined();
    815     Frame* dynamicFrame = toDynamicFrame(exec);
    816     if (!dynamicFrame)
    817         return jsUndefined();
    818 
    819     if (!DOMWindow::canShowModalDialogNow(frame) || !domWindowAllowPopUp(dynamicFrame, exec))
    820         return jsUndefined();
    821 
    822     HashMap<String, String> features;
    823     DOMWindow::parseModalDialogFeatures(featureArgs, features);
    824 
    825     const bool trusted = false;
    826 
    827     // The following features from Microsoft's documentation are not implemented:
    828     // - default font settings
    829     // - width, height, left, and top specified in units other than "px"
    830     // - edge (sunken or raised, default is raised)
    831     // - dialogHide: trusted && boolFeature(features, "dialoghide"), makes dialog hide when you print
    832     // - help: boolFeature(features, "help", true), makes help icon appear in dialog (what does it do on Windows?)
    833     // - unadorned: trusted && boolFeature(features, "unadorned");
    834 
    835     FloatRect screenRect = screenAvailableRect(frame->view());
    836 
    837     WindowFeatures wargs;
    838     wargs.width = WindowFeatures::floatFeature(features, "dialogwidth", 100, screenRect.width(), 620); // default here came from frame size of dialog in MacIE
    839     wargs.widthSet = true;
    840     wargs.height = WindowFeatures::floatFeature(features, "dialogheight", 100, screenRect.height(), 450); // default here came from frame size of dialog in MacIE
    841     wargs.heightSet = true;
    842 
    843     wargs.x = WindowFeatures::floatFeature(features, "dialogleft", screenRect.x(), screenRect.right() - wargs.width, -1);
    844     wargs.xSet = wargs.x > 0;
    845     wargs.y = WindowFeatures::floatFeature(features, "dialogtop", screenRect.y(), screenRect.bottom() - wargs.height, -1);
    846     wargs.ySet = wargs.y > 0;
    847 
    848     if (WindowFeatures::boolFeature(features, "center", true)) {
    849         if (!wargs.xSet) {
    850             wargs.x = screenRect.x() + (screenRect.width() - wargs.width) / 2;
    851             wargs.xSet = true;
    852         }
    853         if (!wargs.ySet) {
    854             wargs.y = screenRect.y() + (screenRect.height() - wargs.height) / 2;
    855             wargs.ySet = true;
    856         }
    857     }
    858 
    859     wargs.dialog = true;
    860     wargs.resizable = WindowFeatures::boolFeature(features, "resizable");
    861     wargs.scrollbarsVisible = WindowFeatures::boolFeature(features, "scroll", true);
    862     wargs.statusBarVisible = WindowFeatures::boolFeature(features, "status", !trusted);
    863     wargs.menuBarVisible = false;
    864     wargs.toolBarVisible = false;
    865     wargs.locationBarVisible = false;
    866     wargs.fullscreen = false;
    867 
    868     Frame* dialogFrame = createWindow(exec, lexicalFrame, dynamicFrame, frame, url, "", wargs, dialogArgs);
    869     if (!dialogFrame)
    870         return jsUndefined();
    871 
    872     JSDOMWindow* dialogWindow = toJSDOMWindow(dialogFrame, currentWorld(exec));
    873     dialogFrame->page()->chrome()->runModal();
    874 
    875     Identifier returnValue(exec, "returnValue");
    876     if (dialogWindow->allowsAccessFromNoErrorMessage(exec)) {
    877         PropertySlot slot;
    878         // This is safe, we have already performed the origin security check and we are
    879         // not interested in any of the DOM properties of the window.
    880         if (dialogWindow->JSGlobalObject::getOwnPropertySlot(exec, returnValue, slot))
    881             return slot.getValue(exec, returnValue);
    882     }
    883     return jsUndefined();
    884 }
    885 
    886 JSValue JSDOMWindow::postMessage(ExecState* exec, const ArgList& args)
    887 {
    888     DOMWindow* window = impl();
    889 
    890     DOMWindow* source = asJSDOMWindow(exec->lexicalGlobalObject())->impl();
    891     PassRefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, args.at(0));
    892 
    893     if (exec->hadException())
    894         return jsUndefined();
    895 
    896     MessagePortArray messagePorts;
    897     if (args.size() > 2)
    898         fillMessagePortArray(exec, args.at(1), messagePorts);
    899     if (exec->hadException())
    900         return jsUndefined();
    901 
    902     String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, args.at((args.size() == 2) ? 1 : 2));
    903     if (exec->hadException())
    904         return jsUndefined();
    905 
    906     ExceptionCode ec = 0;
    907     window->postMessage(message, &messagePorts, targetOrigin, source, ec);
    908     setDOMException(exec, ec);
    909 
    910     return jsUndefined();
    911 }
    912 
    913 JSValue JSDOMWindow::setTimeout(ExecState* exec, const ArgList& args)
    914 {
    915     ScheduledAction* action = ScheduledAction::create(exec, args, currentWorld(exec));
    916     if (exec->hadException())
    917         return jsUndefined();
    918     int delay = args.at(1).toInt32(exec);
    919 
    920     ExceptionCode ec = 0;
    921     int result = impl()->setTimeout(action, delay, ec);
    922     setDOMException(exec, ec);
    923 
    924     return jsNumber(exec, result);
    925 }
    926 
    927 JSValue JSDOMWindow::setInterval(ExecState* exec, const ArgList& args)
    928 {
    929     ScheduledAction* action = ScheduledAction::create(exec, args, currentWorld(exec));
    930     if (exec->hadException())
    931         return jsUndefined();
    932     int delay = args.at(1).toInt32(exec);
    933 
    934     ExceptionCode ec = 0;
    935     int result = impl()->setInterval(action, delay, ec);
    936     setDOMException(exec, ec);
    937 
    938     return jsNumber(exec, result);
    939 }
    940 
    941 JSValue JSDOMWindow::atob(ExecState* exec, const ArgList& args)
    942 {
    943     if (args.size() < 1)
    944         return throwError(exec, SyntaxError, "Not enough arguments");
    945 
    946     JSValue v = args.at(0);
    947     if (v.isNull())
    948         return jsEmptyString(exec);
    949 
    950     UString s = v.toString(exec);
    951     if (!s.is8Bit()) {
    952         setDOMException(exec, INVALID_CHARACTER_ERR);
    953         return jsUndefined();
    954     }
    955 
    956     Vector<char> in(s.size());
    957     for (int i = 0; i < s.size(); ++i)
    958         in[i] = static_cast<char>(s.data()[i]);
    959     Vector<char> out;
    960 
    961     if (!base64Decode(in, out))
    962         return throwError(exec, GeneralError, "Cannot decode base64");
    963 
    964     return jsString(exec, String(out.data(), out.size()));
    965 }
    966 
    967 JSValue JSDOMWindow::btoa(ExecState* exec, const ArgList& args)
    968 {
    969     if (args.size() < 1)
    970         return throwError(exec, SyntaxError, "Not enough arguments");
    971 
    972     JSValue v = args.at(0);
    973     if (v.isNull())
    974         return jsEmptyString(exec);
    975 
    976     UString s = v.toString(exec);
    977     if (!s.is8Bit()) {
    978         setDOMException(exec, INVALID_CHARACTER_ERR);
    979         return jsUndefined();
    980     }
    981 
    982     Vector<char> in(s.size());
    983     for (int i = 0; i < s.size(); ++i)
    984         in[i] = static_cast<char>(s.data()[i]);
    985     Vector<char> out;
    986 
    987     base64Encode(in, out);
    988 
    989     return jsString(exec, String(out.data(), out.size()));
    990 }
    991 
    992 JSValue JSDOMWindow::addEventListener(ExecState* exec, const ArgList& args)
    993 {
    994     Frame* frame = impl()->frame();
    995     if (!frame)
    996         return jsUndefined();
    997 
    998     JSValue listener = args.at(1);
    999     if (!listener.isObject())
   1000         return jsUndefined();
   1001 
   1002     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
   1003     return jsUndefined();
   1004 }
   1005 
   1006 JSValue JSDOMWindow::removeEventListener(ExecState* exec, const ArgList& args)
   1007 {
   1008     Frame* frame = impl()->frame();
   1009     if (!frame)
   1010         return jsUndefined();
   1011 
   1012     JSValue listener = args.at(1);
   1013     if (!listener.isObject())
   1014         return jsUndefined();
   1015 
   1016     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
   1017     return jsUndefined();
   1018 }
   1019 
   1020 DOMWindow* toDOMWindow(JSValue value)
   1021 {
   1022     if (!value.isObject())
   1023         return 0;
   1024     JSObject* object = asObject(value);
   1025     if (object->inherits(&JSDOMWindow::s_info))
   1026         return static_cast<JSDOMWindow*>(object)->impl();
   1027     if (object->inherits(&JSDOMWindowShell::s_info))
   1028         return static_cast<JSDOMWindowShell*>(object)->impl();
   1029     return 0;
   1030 }
   1031 
   1032 } // namespace WebCore
   1033