/* * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include "JSEventListener.h" #include "Event.h" #include "Frame.h" #include "JSEvent.h" #include "JSEventTarget.h" #include "JSMainThreadExecState.h" #include #include using namespace JSC; namespace WebCore { JSEventListener::JSEventListener(JSObject* function, JSObject* wrapper, bool isAttribute, DOMWrapperWorld* isolatedWorld) : EventListener(JSEventListenerType) , m_wrapper(*isolatedWorld->globalData(), wrapper) , m_isAttribute(isAttribute) , m_isolatedWorld(isolatedWorld) { m_jsFunction.set(*m_isolatedWorld->globalData(), wrapper, function); } JSEventListener::~JSEventListener() { } JSObject* JSEventListener::initializeJSFunction(ScriptExecutionContext*) const { ASSERT_NOT_REACHED(); return 0; } void JSEventListener::markJSFunction(MarkStack& markStack) { if (m_jsFunction) markStack.append(&m_jsFunction); } void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionTerminated()) return; JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get()); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // The window must still be active in its frame. See . // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in. if (frame->domWindow() != window->impl()) return; // FIXME: Is this check needed for other contexts? ScriptController* script = frame->script(); if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = getCallData(handleEventFunction, callData); if (callType == CallTypeNone) { handleEventFunction = JSValue(); callType = jsFunction->getCallData(callData); } if (callType != CallTypeNone) { ref(); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); JSGlobalData& globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData.dynamicGlobalObject ? globalData.dynamicGlobalObject : globalObject); globalData.timeoutChecker.start(); JSValue retval; if (handleEventFunction) { retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, jsFunction, args) : JSC::call(exec, handleEventFunction, callType, callData, jsFunction, args); } else { JSValue currentTarget = toJS(exec, globalObject, event->currentTarget()); retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, currentTarget, args) : JSC::call(exec, jsFunction, callType, callData, currentTarget, args); } globalData.timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); if (exec->hadException()) { event->target()->uncaughtExceptionInEventHandler(); reportCurrentException(exec); } else { if (!retval.isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(ustringToString(retval.toString(exec))); if (m_isAttribute) { bool retvalbool; if (retval.getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } deref(); } } bool JSEventListener::virtualisAttribute() const { return m_isAttribute; } bool JSEventListener::operator==(const EventListener& listener) { if (const JSEventListener* jsEventListener = JSEventListener::cast(&listener)) return m_jsFunction == jsEventListener->m_jsFunction && m_isAttribute == jsEventListener->m_isAttribute; return false; } } // namespace WebCore