JSDOMWindowCustom.cpp [plain text]
#include "config.h"
#include "JSDOMWindowCustom.h"
#include "AtomicString.h"
#include "Base64.h"
#include "DOMWindow.h"
#include "Document.h"
#include "ExceptionCode.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameTree.h"
#include "History.h"
#include "JSDOMWindowShell.h"
#include "JSEventListener.h"
#include "JSHistory.h"
#include "JSLocation.h"
#include "JSMessagePort.h"
#include "Location.h"
#include "MessagePort.h"
#include "ScriptController.h"
#include "Settings.h"
#include <runtime/JSObject.h>
#include <runtime/PrototypeFunction.h>
#include "ChromeClient.h"
#include "Page.h"
#include "WKContentObservation.h"
using namespace JSC;
namespace WebCore {
void JSDOMWindow::mark()
{
Base::mark();
if (Frame* frame = impl()->frame()) {
if (Document* document = frame->document())
document->markWindowEventListeners();
}
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());
#if ENABLE(DOM_STORAGE)
markDOMObjectWrapper(globalData, impl()->optionalSessionStorage());
markDOMObjectWrapper(globalData, impl()->optionalLocalStorage());
#endif
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
markDOMObjectWrapper(globalData, impl()->optionalApplicationCache());
#endif
}
bool JSDOMWindow::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
if (!allowsAccessFrom(exec))
return false;
return Base::deleteProperty(exec, propertyName);
}
bool JSDOMWindow::customGetPropertyNames(ExecState* exec, PropertyNameArray&)
{
if (!allowsAccessFrom(exec))
return true;
return false;
}
bool JSDOMWindow::getPropertyAttributes(JSC::ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
{
if (!allowsAccessFrom(exec))
return false;
return Base::getPropertyAttributes(exec, propertyName, attributes);
}
void JSDOMWindow::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction)
{
if (!allowsAccessFrom(exec))
return;
Base::defineGetter(exec, propertyName, getterFunction);
}
void JSDOMWindow::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction)
{
if (!allowsAccessFrom(exec))
return;
Base::defineSetter(exec, propertyName, setterFunction);
}
JSValuePtr JSDOMWindow::lookupGetter(ExecState* exec, const Identifier& propertyName)
{
if (!allowsAccessFrom(exec))
return jsUndefined();
return Base::lookupGetter(exec, propertyName);
}
JSValuePtr JSDOMWindow::lookupSetter(ExecState* exec, const Identifier& propertyName)
{
if (!allowsAccessFrom(exec))
return jsUndefined();
return Base::lookupSetter(exec, propertyName);
}
JSValuePtr JSDOMWindow::history(ExecState* exec) const
{
History* history = impl()->history();
if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec->globalData(), history))
return wrapper;
JSHistory* jsHistory = new (exec) JSHistory(getDOMStructure<JSHistory>(exec, const_cast<JSDOMWindow*>(this)), history);
cacheDOMObjectWrapper(exec->globalData(), history, jsHistory);
return jsHistory;
}
JSValuePtr JSDOMWindow::location(ExecState* exec) const
{
Location* location = impl()->location();
if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec->globalData(), location))
return wrapper;
JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, const_cast<JSDOMWindow*>(this)), location);
cacheDOMObjectWrapper(exec->globalData(), location, jsLocation);
return jsLocation;
}
void JSDOMWindow::setLocation(ExecState* exec, JSValuePtr value)
{
Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame();
if (!activeFrame)
return;
#if ENABLE(DASHBOARD_SUPPORT)
if (Settings* settings = activeFrame->settings()) {
if (settings->usesDashboardBackwardCompatibilityMode() && !activeFrame->tree()->parent()) {
if (allowsAccessFrom(exec))
putDirect(Identifier(exec, "location"), value);
return;
}
}
#endif
if (!activeFrame->loader()->shouldAllowNavigation(impl()->frame()))
return;
String dstUrl = activeFrame->loader()->completeURL(value.toString(exec)).string();
if (!protocolIs(dstUrl, "javascript") || allowsAccessFrom(exec)) {
bool userGesture = activeFrame->script()->processingUserGesture();
impl()->frame()->loader()->scheduleLocationChange(dstUrl, activeFrame->loader()->outgoingReferrer(), !activeFrame->script()->anyPageIsProcessingUserGesture(), false, userGesture);
}
}
JSValuePtr JSDOMWindow::postMessage(ExecState* exec, const ArgList& args)
{
DOMWindow* window = impl();
DOMWindow* source = asJSDOMWindow(exec->lexicalGlobalObject())->impl();
String message = args.at(exec, 0).toString(exec);
if (exec->hadException())
return jsUndefined();
MessagePort* messagePort = (args.size() == 2) ? 0 : toMessagePort(args.at(exec, 1));
String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, (args.size() == 2) ? 1 : 2));
if (exec->hadException())
return jsUndefined();
ExceptionCode ec = 0;
window->postMessage(message, messagePort, targetOrigin, source, ec);
setDOMException(exec, ec);
return jsUndefined();
}
static JSValuePtr setTimeoutOrInterval(ExecState* exec, JSDOMWindow* window, const ArgList& args, bool timeout)
{
JSValuePtr v = args.at(exec, 0);
int delay = args.at(exec, 1).toInt32(exec);
if (v.isString())
return jsNumber(exec, window->installTimeout(asString(v)->value(), delay, timeout));
CallData callData;
if (v.getCallData(callData) == CallTypeNone)
return jsUndefined();
ArgList argsTail;
args.getSlice(2, argsTail);
return jsNumber(exec, window->installTimeout(exec, v, argsTail, delay, timeout));
}
JSValuePtr JSDOMWindow::setTimeout(ExecState* exec, const ArgList& args)
{
return setTimeoutOrInterval(exec, this, args, true);
}
JSValuePtr JSDOMWindow::clearTimeout(ExecState* exec, const ArgList& args)
{
int timeoutId = args.at(exec, 0).toInt32(exec);
if (Frame *frame = impl()->frame()) {
if (timeoutId > 0 && frame->document()) {
DOMTimer *timer = frame->document()->findTimeout(timeoutId);
if (timer && WebThreadContainsObservedContentModifier(timer)) {
WebThreadRemoveObservedContentModifier(timer);
if (WebThreadCountOfObservedContentModifiers() == 0)
if (frame->page())
frame->page()->chrome()->client()->observedContentChange(impl()->frame());
}
}
}
removeTimeout(timeoutId);
return jsUndefined();
}
JSValuePtr JSDOMWindow::setInterval(ExecState* exec, const ArgList& args)
{
return setTimeoutOrInterval(exec, this, args, false);
}
JSValuePtr JSDOMWindow::clearInterval(ExecState* exec, const ArgList& args)
{
removeTimeout(args.at(exec, 0).toInt32(exec));
return jsUndefined();
}
JSValuePtr JSDOMWindow::atob(ExecState* exec, const ArgList& args)
{
if (args.size() < 1)
return throwError(exec, SyntaxError, "Not enough arguments");
JSValuePtr v = args.at(exec, 0);
if (v.isNull())
return jsEmptyString(exec);
UString s = v.toString(exec);
if (!s.is8Bit()) {
setDOMException(exec, INVALID_CHARACTER_ERR);
return jsUndefined();
}
Vector<char> in(s.size());
for (int i = 0; i < s.size(); ++i)
in[i] = static_cast<char>(s.data()[i]);
Vector<char> out;
if (!base64Decode(in, out))
return throwError(exec, GeneralError, "Cannot decode base64");
return jsString(exec, String(out.data(), out.size()));
}
JSValuePtr JSDOMWindow::btoa(ExecState* exec, const ArgList& args)
{
if (args.size() < 1)
return throwError(exec, SyntaxError, "Not enough arguments");
JSValuePtr v = args.at(exec, 0);
if (v.isNull())
return jsEmptyString(exec);
UString s = v.toString(exec);
if (!s.is8Bit()) {
setDOMException(exec, INVALID_CHARACTER_ERR);
return jsUndefined();
}
Vector<char> in(s.size());
for (int i = 0; i < s.size(); ++i)
in[i] = static_cast<char>(s.data()[i]);
Vector<char> out;
base64Encode(in, out);
return jsString(exec, String(out.data(), out.size()));
}
JSValuePtr JSDOMWindow::addEventListener(ExecState* exec, const ArgList& args)
{
Frame* frame = impl()->frame();
if (!frame)
return jsUndefined();
if (RefPtr<JSProtectedEventListener> listener = findOrCreateJSProtectedEventListener(args.at(exec, 1))) {
if (Document* doc = frame->document())
doc->addWindowEventListener(AtomicString(args.at(exec, 0).toString(exec)), listener.release(), args.at(exec, 2).toBoolean(exec));
}
return jsUndefined();
}
JSValuePtr JSDOMWindow::removeEventListener(ExecState* exec, const ArgList& args)
{
Frame* frame = impl()->frame();
if (!frame)
return jsUndefined();
if (JSProtectedEventListener* listener = findJSProtectedEventListener(args.at(exec, 1))) {
if (Document* doc = frame->document())
doc->removeWindowEventListener(AtomicString(args.at(exec, 0).toString(exec)), listener, args.at(exec, 2).toBoolean(exec));
}
return jsUndefined();
}
DOMWindow* toDOMWindow(JSValuePtr value)
{
if (!value.isObject())
return 0;
JSObject* object = asObject(value);
if (object->inherits(&JSDOMWindow::s_info))
return static_cast<JSDOMWindow*>(object)->impl();
if (object->inherits(&JSDOMWindowShell::s_info))
return static_cast<JSDOMWindowShell*>(object)->impl();
return 0;
}
JSValuePtr nonCachingStaticCloseFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot&)
{
return new (exec) PrototypeFunction(exec, 0, propertyName, jsDOMWindowPrototypeFunctionClose);
}
JSValuePtr nonCachingStaticBlurFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot&)
{
return new (exec) PrototypeFunction(exec, 0, propertyName, jsDOMWindowPrototypeFunctionBlur);
}
JSValuePtr nonCachingStaticFocusFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot&)
{
return new (exec) PrototypeFunction(exec, 0, propertyName, jsDOMWindowPrototypeFunctionFocus);
}
JSValuePtr nonCachingStaticPostMessageFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot&)
{
return new (exec) PrototypeFunction(exec, 2, propertyName, jsDOMWindowPrototypeFunctionPostMessage);
}
}