2 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
3 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All Rights Reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "JSEventListener.h"
26 #include "JSEventTarget.h"
27 #include "JSMainThreadExecState.h"
28 #include <runtime/JSLock.h>
29 #include <wtf/RefCountedLeakCounter.h>
35 JSEventListener::JSEventListener(JSObject* function, JSObject* wrapper, bool isAttribute, DOMWrapperWorld* isolatedWorld)
36 : EventListener(JSEventListenerType)
37 , m_wrapper(*isolatedWorld->globalData(), wrapper)
38 , m_isAttribute(isAttribute)
39 , m_isolatedWorld(isolatedWorld)
41 m_jsFunction.set(*m_isolatedWorld->globalData(), wrapper, function);
44 JSEventListener::~JSEventListener()
48 JSObject* JSEventListener::initializeJSFunction(ScriptExecutionContext*) const
54 void JSEventListener::markJSFunction(MarkStack& markStack)
57 markStack.append(&m_jsFunction);
60 void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
62 ASSERT(scriptExecutionContext);
63 if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionTerminated())
66 JSLock lock(SilenceAssertionsOnly);
68 JSObject* jsFunction = this->jsFunction(scriptExecutionContext);
72 JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get());
76 if (scriptExecutionContext->isDocument()) {
77 JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject);
78 Frame* frame = window->impl()->frame();
81 // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>.
82 // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in.
83 if (frame->domWindow() != window->impl())
85 // FIXME: Is this check needed for other contexts?
86 ScriptController* script = frame->script();
87 if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused())
91 ExecState* exec = globalObject->globalExec();
92 JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent"));
95 CallType callType = getCallData(handleEventFunction, callData);
96 if (callType == CallTypeNone) {
97 handleEventFunction = JSValue();
98 callType = jsFunction->getCallData(callData);
101 if (callType != CallTypeNone) {
104 MarkedArgumentBuffer args;
105 args.append(toJS(exec, globalObject, event));
107 Event* savedEvent = globalObject->currentEvent();
108 globalObject->setCurrentEvent(event);
110 JSGlobalData& globalData = globalObject->globalData();
111 DynamicGlobalObjectScope globalObjectScope(globalData, globalData.dynamicGlobalObject ? globalData.dynamicGlobalObject : globalObject);
113 globalData.timeoutChecker.start();
115 if (handleEventFunction) {
116 retval = scriptExecutionContext->isDocument()
117 ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, jsFunction, args)
118 : JSC::call(exec, handleEventFunction, callType, callData, jsFunction, args);
120 JSValue currentTarget = toJS(exec, globalObject, event->currentTarget());
121 retval = scriptExecutionContext->isDocument()
122 ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, currentTarget, args)
123 : JSC::call(exec, jsFunction, callType, callData, currentTarget, args);
125 globalData.timeoutChecker.stop();
127 globalObject->setCurrentEvent(savedEvent);
129 if (exec->hadException()) {
130 event->target()->uncaughtExceptionInEventHandler();
131 reportCurrentException(exec);
133 if (!retval.isUndefinedOrNull() && event->storesResultAsString())
134 event->storeResult(ustringToString(retval.toString(exec)));
137 if (retval.getBoolean(retvalbool) && !retvalbool)
138 event->preventDefault();
146 bool JSEventListener::virtualisAttribute() const
148 return m_isAttribute;
151 bool JSEventListener::operator==(const EventListener& listener)
153 if (const JSEventListener* jsEventListener = JSEventListener::cast(&listener))
154 return m_jsFunction == jsEventListener->m_jsFunction && m_isAttribute == jsEventListener->m_isAttribute;
158 } // namespace WebCore