diff options
Diffstat (limited to 'WebCore/bindings/js/JSDOMWindowCustom.cpp')
-rw-r--r-- | WebCore/bindings/js/JSDOMWindowCustom.cpp | 263 |
1 files changed, 235 insertions, 28 deletions
diff --git a/WebCore/bindings/js/JSDOMWindowCustom.cpp b/WebCore/bindings/js/JSDOMWindowCustom.cpp index b8c30c7..9798972 100644 --- a/WebCore/bindings/js/JSDOMWindowCustom.cpp +++ b/WebCore/bindings/js/JSDOMWindowCustom.cpp @@ -31,17 +31,21 @@ #include "FrameLoader.h" #include "FrameTree.h" #include "FrameView.h" +#include "HTMLCollection.h" +#include "HTMLDocument.h" #include "History.h" #include "JSAudioConstructor.h" #include "JSDOMWindowShell.h" #include "JSEvent.h" #include "JSEventListener.h" +#include "JSHTMLCollection.h" #include "JSHistory.h" #include "JSImageConstructor.h" #include "JSLocation.h" #include "JSMessageChannelConstructor.h" #include "JSMessagePort.h" #include "JSOptionConstructor.h" +#include "JSSharedWorkerConstructor.h" #include "JSWebKitCSSMatrixConstructor.h" #include "JSWebKitPointConstructor.h" #include "JSWorkerConstructor.h" @@ -58,40 +62,234 @@ #include "Settings.h" #include "WindowFeatures.h" #include <runtime/JSObject.h> +#include <runtime/PrototypeFunction.h> using namespace JSC; namespace WebCore { -void JSDOMWindow::mark() +void JSDOMWindow::markChildren(MarkStack& markStack) { - Base::mark(); + Base::markChildren(markStack); - markEventListeners(impl()->eventListeners()); + markEventListeners(markStack, impl()->eventListeners()); JSGlobalData& globalData = *Heap::heap(this)->globalData(); - markDOMObjectWrapper(globalData, impl()->optionalConsole()); - markDOMObjectWrapper(globalData, impl()->optionalHistory()); - markDOMObjectWrapper(globalData, impl()->optionalLocationbar()); - markDOMObjectWrapper(globalData, impl()->optionalMenubar()); - markDOMObjectWrapper(globalData, impl()->optionalNavigator()); - markDOMObjectWrapper(globalData, impl()->optionalPersonalbar()); - markDOMObjectWrapper(globalData, impl()->optionalScreen()); - markDOMObjectWrapper(globalData, impl()->optionalScrollbars()); - markDOMObjectWrapper(globalData, impl()->optionalSelection()); - markDOMObjectWrapper(globalData, impl()->optionalStatusbar()); - markDOMObjectWrapper(globalData, impl()->optionalToolbar()); - markDOMObjectWrapper(globalData, impl()->optionalLocation()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalConsole()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalHistory()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalLocationbar()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalMenubar()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalNavigator()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalPersonalbar()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalScreen()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalScrollbars()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalSelection()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalStatusbar()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalToolbar()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalLocation()); #if ENABLE(DOM_STORAGE) - markDOMObjectWrapper(globalData, impl()->optionalSessionStorage()); - markDOMObjectWrapper(globalData, impl()->optionalLocalStorage()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalSessionStorage()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalLocalStorage()); #endif #if ENABLE(OFFLINE_WEB_APPLICATIONS) - markDOMObjectWrapper(globalData, impl()->optionalApplicationCache()); + markDOMObjectWrapper(markStack, globalData, impl()->optionalApplicationCache()); #endif } +template<NativeFunction nativeFunction, int length> +JSValue nonCachingStaticFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot&) +{ + return new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), length, propertyName, nativeFunction); +} + +static JSValue childFrameGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot) +{ + return toJS(exec, static_cast<JSDOMWindow*>(asObject(slot.slotBase()))->impl()->frame()->tree()->child(AtomicString(propertyName))->domWindow()); +} + +static JSValue indexGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) +{ + return toJS(exec, static_cast<JSDOMWindow*>(asObject(slot.slotBase()))->impl()->frame()->tree()->child(slot.index())->domWindow()); +} + +static JSValue namedItemGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot) +{ + JSDOMWindowBase* thisObj = static_cast<JSDOMWindow*>(asObject(slot.slotBase())); + Document* document = thisObj->impl()->frame()->document(); + + ASSERT(thisObj->allowsAccessFrom(exec)); + ASSERT(document); + ASSERT(document->isHTMLDocument()); + + RefPtr<HTMLCollection> collection = document->windowNamedItems(propertyName); + if (collection->length() == 1) + return toJS(exec, collection->firstItem()); + return toJS(exec, collection.get()); +} + +bool JSDOMWindow::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +{ + // When accessing a Window cross-domain, functions are always the native built-in ones, and they + // are not affected by properties changed on the Window or anything in its prototype chain. + // This is consistent with the behavior of Firefox. + + const HashEntry* entry; + + // We don't want any properties other than "close" and "closed" on a closed window. + if (!impl()->frame()) { + // The following code is safe for cross-domain and same domain use. + // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype). + entry = s_info.propHashTable(exec)->entry(exec, propertyName); + if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) { + slot.setCustom(this, entry->propertyGetter()); + return true; + } + entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); + if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) { + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); + return true; + } + + // FIXME: We should have a message here that explains why the property access/function call was + // not allowed. + slot.setUndefined(); + return true; + } + + // We need to check for cross-domain access here without printing the generic warning message + // because we always allow access to some function, just different ones depending whether access + // is allowed. + String errorMessage; + bool allowsAccess = allowsAccessFrom(exec, errorMessage); + + // Look for overrides before looking at any of our own properties, but ignore overrides completely + // if this is cross-domain access. + if (allowsAccess && JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot)) + return true; + + // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the + // prototype due to the blanket same origin (allowsAccessFrom) check at the end of getOwnPropertySlot. + // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of + // what prototype is actually set on this object. + entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); + if (entry) { + if (entry->attributes() & Function) { + if (entry->function() == jsDOMWindowPrototypeFunctionBlur) { + if (!allowsAccess) { + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>); + return true; + } + } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) { + if (!allowsAccess) { + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); + return true; + } + } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) { + if (!allowsAccess) { + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>); + return true; + } + } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) { + if (!allowsAccess) { + slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>); + return true; + } + } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) { + if (!DOMWindow::canShowModalDialog(impl()->frame())) { + slot.setUndefined(); + return true; + } + } + } + } else { + // Allow access to toString() cross-domain, but always Object.prototype.toString. + if (propertyName == exec->propertyNames().toString) { + if (!allowsAccess) { + slot.setCustom(this, objectToStringFunctionGetter); + return true; + } + } + } + + entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName); + if (entry) { + slot.setCustom(this, entry->propertyGetter()); + return true; + } + + // Check for child frames by name before built-in properties to + // match Mozilla. This does not match IE, but some sites end up + // naming frames things that conflict with window properties that + // are in Moz but not IE. Since we have some of these, we have to do + // it the Moz way. + if (impl()->frame()->tree()->child(propertyName)) { + slot.setCustom(this, childFrameGetter); + return true; + } + + // Do prototype lookup early so that functions and attributes in the prototype can have + // precedence over the index and name getters. + JSValue proto = prototype(); + if (proto.isObject()) { + if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) { + if (!allowsAccess) { + printErrorMessage(errorMessage); + slot.setUndefined(); + } + return true; + } + } + + // FIXME: Search the whole frame hierachy somewhere around here. + // We need to test the correct priority order. + + // allow window[1] or parent[1] etc. (#56983) + bool ok; + unsigned i = propertyName.toArrayIndex(&ok); + if (ok && i < impl()->frame()->tree()->childCount()) { + slot.setCustomIndex(this, i, indexGetter); + return true; + } + + if (!allowsAccess) { + printErrorMessage(errorMessage); + slot.setUndefined(); + return true; + } + + // Allow shortcuts like 'Image1' instead of document.images.Image1 + Document* document = impl()->frame()->document(); + if (document->isHTMLDocument()) { + AtomicStringImpl* atomicPropertyName = AtomicString::find(propertyName); + if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) { + slot.setCustom(this, namedItemGetter); + return true; + } + } + + return Base::getOwnPropertySlot(exec, propertyName, slot); +} + +void JSDOMWindow::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + if (!impl()->frame()) + return; + + // Optimization: access JavaScript global variables directly before involving the DOM. + if (JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) { + if (allowsAccessFrom(exec)) + JSGlobalObject::put(exec, propertyName, value, slot); + return; + } + + if (lookupPut<JSDOMWindow>(exec, propertyName, value, s_info.propHashTable(exec), this)) + return; + + if (allowsAccessFrom(exec)) + Base::put(exec, propertyName, value, slot); +} + bool JSDOMWindow::deleteProperty(ExecState* exec, const Identifier& propertyName) { // Only allow deleting properties by frames in the same origin. @@ -100,15 +298,15 @@ bool JSDOMWindow::deleteProperty(ExecState* exec, const Identifier& propertyName return Base::deleteProperty(exec, propertyName); } -bool JSDOMWindow::customGetPropertyNames(ExecState* exec, PropertyNameArray&) +void JSDOMWindow::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { // Only allow the window to enumerated by frames in the same origin. if (!allowsAccessFrom(exec)) - return true; - return false; + return; + Base::getPropertyNames(exec, propertyNames); } -bool JSDOMWindow::getPropertyAttributes(JSC::ExecState* exec, const Identifier& propertyName, unsigned& attributes) const +bool JSDOMWindow::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const { // Only allow getting property attributes properties by frames in the same origin. if (!allowsAccessFrom(exec)) @@ -161,7 +359,8 @@ JSValue JSDOMWindow::history(ExecState* exec) const if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec->globalData(), history)) return wrapper; - JSHistory* jsHistory = new (exec) JSHistory(getDOMStructure<JSHistory>(exec, const_cast<JSDOMWindow*>(this)), history); + JSDOMWindow* window = const_cast<JSDOMWindow*>(this); + JSHistory* jsHistory = new (exec) JSHistory(getDOMStructure<JSHistory>(exec, window), window, history); cacheDOMObjectWrapper(exec->globalData(), history, jsHistory); return jsHistory; } @@ -172,7 +371,8 @@ JSValue JSDOMWindow::location(ExecState* exec) const if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec->globalData(), location)) return wrapper; - JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, const_cast<JSDOMWindow*>(this)), location); + JSDOMWindow* window = const_cast<JSDOMWindow*>(this); + JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, window), window, location); cacheDOMObjectWrapper(exec->globalData(), location, jsLocation); return jsLocation; } @@ -245,12 +445,12 @@ JSValue JSDOMWindow::audio(ExecState* exec) const JSValue JSDOMWindow::webKitPoint(ExecState* exec) const { - return getDOMConstructor<JSWebKitPointConstructor>(exec); + return getDOMConstructor<JSWebKitPointConstructor>(exec, this); } JSValue JSDOMWindow::webKitCSSMatrix(ExecState* exec) const { - return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec); + return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec, this); } JSValue JSDOMWindow::xmlHttpRequest(ExecState* exec) const @@ -261,7 +461,7 @@ JSValue JSDOMWindow::xmlHttpRequest(ExecState* exec) const #if ENABLE(XSLT) JSValue JSDOMWindow::xsltProcessor(ExecState* exec) const { - return getDOMConstructor<JSXSLTProcessorConstructor>(exec); + return getDOMConstructor<JSXSLTProcessorConstructor>(exec, this); } #endif @@ -275,7 +475,14 @@ JSValue JSDOMWindow::messageChannel(ExecState* exec) const #if ENABLE(WORKERS) JSValue JSDOMWindow::worker(ExecState* exec) const { - return getDOMConstructor<JSWorkerConstructor>(exec); + return getDOMConstructor<JSWorkerConstructor>(exec, this); +} +#endif + +#if ENABLE(SHARED_WORKERS) +JSValue JSDOMWindow::sharedWorker(ExecState* exec) const +{ + return getDOMConstructor<JSSharedWorkerConstructor>(exec, this); } #endif |