summaryrefslogtreecommitdiffstats
path: root/WebCore/bindings/js/JSDOMWindowCustom.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/bindings/js/JSDOMWindowCustom.cpp')
-rw-r--r--WebCore/bindings/js/JSDOMWindowCustom.cpp263
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