18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
38f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All Rights Reserved.
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is free software; you can redistribute it and/or
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  modify it under the terms of the GNU Lesser General Public
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  License as published by the Free Software Foundation; either
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  version 2 of the License, or (at your option) any later version.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is distributed in the hope that it will be useful,
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  but WITHOUT ANY WARRANTY; without even the implied warranty of
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Lesser General Public License for more details.
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  You should have received a copy of the GNU Lesser General Public
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  License along with this library; if not, write to the Free Software
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSEventListener.h"
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Event.h"
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Frame.h"
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSEvent.h"
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSEventTarget.h"
27e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include "JSMainThreadExecState.h"
282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "WorkerContext.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <runtime/JSLock.h>
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/RefCountedLeakCounter.h>
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace JSC;
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
368a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve BlockJSEventListener::JSEventListener(JSObject* function, JSObject* wrapper, bool isAttribute, DOMWrapperWorld* isolatedWorld)
37231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    : EventListener(JSEventListenerType)
3881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    , m_wrapper(*isolatedWorld->globalData(), wrapper)
395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_isAttribute(isAttribute)
40cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    , m_isolatedWorld(isolatedWorld)
415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (wrapper)
432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        m_jsFunction.set(*m_isolatedWorld->globalData(), wrapper, function);
442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    else
452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        ASSERT(!function);
462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
495f1ab04193ad0130ca8204aadaceae083aca9881Feng QianJSEventListener::~JSEventListener()
505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
538a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve BlockJSObject* JSEventListener::initializeJSFunction(ScriptExecutionContext*) const
545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
558a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    ASSERT_NOT_REACHED();
568a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    return 0;
575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid JSEventListener::markJSFunction(MarkStack& markStack)
605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (m_jsFunction)
622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        markStack.append(&m_jsFunction);
635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
65231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event)
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
67231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ASSERT(scriptExecutionContext);
682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden())
69231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return;
70231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    JSLock lock(SilenceAssertionsOnly);
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
73231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    JSObject* jsFunction = this->jsFunction(scriptExecutionContext);
745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!jsFunction)
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
77cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get());
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!globalObject)
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (scriptExecutionContext->isDocument()) {
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject);
83635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        Frame* frame = window->impl()->frame();
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!frame)
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>.
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in.
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (frame->domWindow() != window->impl())
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // FIXME: Is this check needed for other contexts?
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ScriptController* script = frame->script();
92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused())
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ExecState* exec = globalObject->globalExec();
97643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent"));
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CallData callData;
100545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    CallType callType = getCallData(handleEventFunction, callData);
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (callType == CallTypeNone) {
1025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        handleEventFunction = JSValue();
1035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        callType = jsFunction->getCallData(callData);
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (callType != CallTypeNone) {
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ref();
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        MarkedArgumentBuffer args;
1100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        args.append(toJS(exec, globalObject, event));
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Event* savedEvent = globalObject->currentEvent();
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        globalObject->setCurrentEvent(event);
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
115e14391e94c850b8bd03680c23b38978db68687a8John Reck        JSGlobalData& globalData = globalObject->globalData();
1162bde8e466a4451c7319e3a072d118917957d6554Steve Block        DynamicGlobalObjectScope globalObjectScope(globalData, globalData.dynamicGlobalObject ? globalData.dynamicGlobalObject : globalObject);
117635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
118e14391e94c850b8bd03680c23b38978db68687a8John Reck        globalData.timeoutChecker.start();
119e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        JSValue retval;
120e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        if (handleEventFunction) {
121e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block            retval = scriptExecutionContext->isDocument()
122e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block                ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, jsFunction, args)
123e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block                : JSC::call(exec, handleEventFunction, callType, callData, jsFunction, args);
124e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        } else {
125e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block            JSValue currentTarget = toJS(exec, globalObject, event->currentTarget());
126e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block            retval = scriptExecutionContext->isDocument()
127e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block                ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, currentTarget, args)
128e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block                : JSC::call(exec, jsFunction, callType, callData, currentTarget, args);
129e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block        }
130e14391e94c850b8bd03680c23b38978db68687a8John Reck        globalData.timeoutChecker.stop();
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        globalObject->setCurrentEvent(savedEvent);
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if ENABLE(WORKERS)
1352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (scriptExecutionContext->isWorkerContext()) {
1362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            bool terminatorCausedException = (exec->hadException() && exec->exception().isObject() && asObject(exec->exception())->exceptionType() == Terminated);
1372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if (terminatorCausedException || globalData.terminator.shouldTerminate())
1382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                static_cast<WorkerContext*>(scriptExecutionContext)->script()->forbidExecution();
1392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        }
1402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#endif
1412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
14281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (exec->hadException()) {
14381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            event->target()->uncaughtExceptionInEventHandler();
144635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            reportCurrentException(exec);
14581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        } else {
146635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (!retval.isUndefinedOrNull() && event->storesResultAsString())
147dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                event->storeResult(ustringToString(retval.toString(exec)));
1485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            if (m_isAttribute) {
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                bool retvalbool;
150635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                if (retval.getBoolean(retvalbool) && !retvalbool)
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    event->preventDefault();
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        deref();
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianbool JSEventListener::virtualisAttribute() const
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return m_isAttribute;
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
164231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockbool JSEventListener::operator==(const EventListener& listener)
165231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
166231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (const JSEventListener* jsEventListener = JSEventListener::cast(&listener))
167231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return m_jsFunction == jsEventListener->m_jsFunction && m_isAttribute == jsEventListener->m_isAttribute;
168231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return false;
169231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
170231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace WebCore
172