⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jseventlistener.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
字号:
/* *  Copyright (C) 2001 Peter Kelly (pmk@post.com) *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 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 "CString.h"#include "Console.h"#include "DOMWindow.h"#include "Document.h"#include "Event.h"#include "Frame.h"#include "FrameLoader.h"#include "JSDOMWindow.h"#include "JSEvent.h"#include "JSEventTarget.h"#include "JSNode.h"#include "ScriptController.h"#include <runtime/FunctionConstructor.h>#include <runtime/JSLock.h>#include <wtf/RefCountedLeakCounter.h>using namespace JSC;namespace WebCore {ASSERT_CLASS_FITS_IN_CELL(JSAbstractEventListener)void JSAbstractEventListener::handleEvent(Event* event, bool isWindowEvent){    JSLock lock(false);    JSObject* listener = listenerObj();    if (!listener)        return;    JSDOMGlobalObject* globalObject = this->globalObject();    // Null check as clearGlobalObject() can clear this and we still get called back by    // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275    // FIXME: Is this check still necessary? Requests are supposed to be stopped before clearGlobalObject() is called.    if (!globalObject)        return;    ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();    if (!scriptExecutionContext)        return;    if (scriptExecutionContext->isDocument()) {        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject);        Frame* frame = window->impl()->frame();        if (!frame)            return;        // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>.        // 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->isEnabled() || script->isPaused())            return;    }    ExecState* exec = globalObject->globalExec();    JSValuePtr handleEventFunction = listener->get(exec, Identifier(exec, "handleEvent"));    CallData callData;    CallType callType = handleEventFunction.getCallData(callData);    if (callType == CallTypeNone) {        handleEventFunction = noValue();        callType = listener->getCallData(callData);    }    if (callType != CallTypeNone) {        ref();        ArgList args;        args.append(toJS(exec, event));        Event* savedEvent = globalObject->currentEvent();        globalObject->setCurrentEvent(event);        // If this event handler is the first JavaScript to execute, then the        // dynamic global object should be set to the global object of the        // window in which the event occurred.        JSGlobalData* globalData = globalObject->globalData();        DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject);        JSValuePtr retval;        if (handleEventFunction) {            globalObject->globalData()->timeoutChecker.start();            retval = call(exec, handleEventFunction, callType, callData, listener, args);        } else {            JSValuePtr thisValue;            if (isWindowEvent)                thisValue = globalObject->toThisObject(exec);            else                thisValue = toJS(exec, event->currentTarget());            globalObject->globalData()->timeoutChecker.start();            retval = call(exec, listener, callType, callData, thisValue, args);        }        globalObject->globalData()->timeoutChecker.stop();        globalObject->setCurrentEvent(savedEvent);        if (exec->hadException())            reportCurrentException(exec);        else {            if (!retval.isUndefinedOrNull() && event->storesResultAsString())                event->storeResult(retval.toString(exec));            if (m_isInline) {                bool retvalbool;                if (retval.getBoolean(retvalbool) && !retvalbool)                    event->preventDefault();            }        }        if (scriptExecutionContext->isDocument())            Document::updateDocumentsRendering();        deref();    }}bool JSAbstractEventListener::isInline() const{    return m_isInline;}// -------------------------------------------------------------------------JSUnprotectedEventListener::JSUnprotectedEventListener(JSObject* listener, JSDOMGlobalObject* globalObject, bool isInline)    : JSAbstractEventListener(isInline)    , m_listener(listener)    , m_globalObject(globalObject){    if (m_listener) {        JSDOMWindow::UnprotectedListenersMap& listeners = isInline            ? globalObject->jsUnprotectedInlineEventListeners() : globalObject->jsUnprotectedEventListeners();        listeners.set(m_listener, this);    }}JSUnprotectedEventListener::~JSUnprotectedEventListener(){    if (m_listener && m_globalObject) {        JSDOMWindow::UnprotectedListenersMap& listeners = isInline()            ? m_globalObject->jsUnprotectedInlineEventListeners() : m_globalObject->jsUnprotectedEventListeners();        listeners.remove(m_listener);    }}JSObject* JSUnprotectedEventListener::listenerObj() const{    return m_listener;}JSDOMGlobalObject* JSUnprotectedEventListener::globalObject() const{    return m_globalObject;}void JSUnprotectedEventListener::clearGlobalObject(){    m_globalObject = 0;}void JSUnprotectedEventListener::mark(){    if (m_listener && !m_listener->marked())        m_listener->mark();}#ifndef NDEBUGstatic WTF::RefCountedLeakCounter eventListenerCounter("EventListener");#endif// -------------------------------------------------------------------------JSEventListener::JSEventListener(JSObject* listener, JSDOMGlobalObject* globalObject, bool isInline)    : JSAbstractEventListener(isInline)    , m_listener(listener)    , m_globalObject(globalObject){    if (m_listener) {        JSDOMWindow::ListenersMap& listeners = isInline            ? m_globalObject->jsInlineEventListeners() : m_globalObject->jsEventListeners();        listeners.set(m_listener, this);    }#ifndef NDEBUG    eventListenerCounter.increment();#endif}JSEventListener::~JSEventListener(){    if (m_listener && m_globalObject) {        JSDOMWindow::ListenersMap& listeners = isInline()            ? m_globalObject->jsInlineEventListeners() : m_globalObject->jsEventListeners();        listeners.remove(m_listener);    }#ifndef NDEBUG    eventListenerCounter.decrement();#endif}JSObject* JSEventListener::listenerObj() const{    return m_listener;}JSDOMGlobalObject* JSEventListener::globalObject() const{    return m_globalObject;}void JSEventListener::clearGlobalObject(){    m_globalObject = 0;}// -------------------------------------------------------------------------JSLazyEventListener::JSLazyEventListener(LazyEventListenerType type, const String& functionName, const String& code, JSDOMGlobalObject* globalObject, Node* node, int lineNumber)    : JSEventListener(0, globalObject, true)    , m_functionName(functionName)    , m_code(code)    , m_parsed(false)    , m_lineNumber(lineNumber)    , m_originalNode(node)    , m_type(type){    // We don't retain the original node because we assume it    // will stay alive as long as this handler object is around    // and we need to avoid a reference cycle. If JS transfers    // this handler to another node, parseCode will be called and    // then originalNode is no longer needed.    // A JSLazyEventListener can be created with a line number of zero when it is created with    // a setAttribute call from JavaScript, so make the line number 1 in that case.    if (m_lineNumber == 0)        m_lineNumber = 1;}JSObject* JSLazyEventListener::listenerObj() const{    parseCode();    return m_listener;}// Helper functioninline JSValuePtr eventParameterName(JSLazyEventListener::LazyEventListenerType type, ExecState* exec){    switch (type) {    case JSLazyEventListener::HTMLLazyEventListener:        return jsNontrivialString(exec, "event");#if ENABLE(SVG)    case JSLazyEventListener::SVGLazyEventListener:        return jsNontrivialString(exec, "evt");#endif    default:        ASSERT_NOT_REACHED();        return jsUndefined();    }}void JSLazyEventListener::parseCode() const{    if (m_parsed)        return;    if (globalObject()->scriptExecutionContext()->isDocument()) {        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject());        Frame* frame = window->impl()->frame();        if (!frame)            return;        // FIXME: Is this check needed for non-Document contexts?        ScriptController* script = frame->script();        if (!script->isEnabled() || script->isPaused())            return;    }    m_parsed = true;    ExecState* exec = globalObject()->globalExec();    ArgList args;    UString sourceURL(globalObject()->scriptExecutionContext()->url().string());    args.append(eventParameterName(m_type, exec));    args.append(jsString(exec, m_code));    // FIXME: Passing the document's URL to construct is not always correct, since this event listener might    // have been added with setAttribute from a script, and we should pass String() in that case.    m_listener = constructFunction(exec, args, Identifier(exec, m_functionName), sourceURL, m_lineNumber); // FIXME: is globalExec ok?    JSFunction* listenerAsFunction = static_cast<JSFunction*>(m_listener.get());    if (exec->hadException()) {        exec->clearException();        // failed to parse, so let's just make this listener a no-op        m_listener = 0;    } else if (m_originalNode) {        // Add the event's home element to the scope        // (and the document, and the form - see JSHTMLElement::eventHandlerScope)        ScopeChain scope = listenerAsFunction->scope();        JSValuePtr thisObj = toJS(exec, m_originalNode);        if (thisObj.isObject()) {            static_cast<JSNode*>(asObject(thisObj))->pushEventHandlerScope(exec, scope);            listenerAsFunction->setScope(scope);        }    }    // no more need to keep the unparsed code around    m_functionName = String();    m_code = String();    if (m_listener) {        ASSERT(isInline());        JSDOMWindow::ListenersMap& listeners = globalObject()->jsInlineEventListeners();        listeners.set(m_listener, const_cast<JSLazyEventListener*>(this));    }}} // namespace WebCore

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -