/* | |
* 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 "JSLazyEventListener.h" | |
#include "Frame.h" | |
#include "JSNode.h" | |
#include <runtime/FunctionConstructor.h> | |
#include <runtime/JSFunction.h> | |
#include <runtime/JSLock.h> | |
#include <wtf/RefCountedLeakCounter.h> | |
using namespace JSC; | |
namespace WebCore { | |
#ifndef NDEBUG | |
static WTF::RefCountedLeakCounter eventListenerCounter("JSLazyEventListener"); | |
#endif | |
JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber, JSObject* wrapper, DOMWrapperWorld* isolatedWorld) | |
: JSEventListener(0, wrapper, true, isolatedWorld) | |
, m_functionName(functionName) | |
, m_eventParameterName(eventParameterName) | |
, m_code(code) | |
, m_sourceURL(sourceURL) | |
, m_lineNumber(lineNumber) | |
, m_originalNode(node) | |
{ | |
// 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, initializeJSFunction 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; | |
#ifndef NDEBUG | |
eventListenerCounter.increment(); | |
#endif | |
} | |
JSLazyEventListener::~JSLazyEventListener() | |
{ | |
#ifndef NDEBUG | |
eventListenerCounter.decrement(); | |
#endif | |
} | |
JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const | |
{ | |
ASSERT(executionContext); | |
ASSERT(executionContext->isDocument()); | |
if (!executionContext) | |
return 0; | |
Frame* frame = static_cast<Document*>(executionContext)->frame(); | |
if (!frame) | |
return 0; | |
ScriptController* scriptController = frame->script(); | |
if (!scriptController->canExecuteScripts(AboutToExecuteScript)) | |
return 0; | |
JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld()); | |
if (!globalObject) | |
return 0; | |
if (executionContext->isDocument()) { | |
JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); | |
Frame* frame = window->impl()->frame(); | |
if (!frame) | |
return 0; | |
// FIXME: Is this check needed for non-Document contexts? | |
ScriptController* script = frame->script(); | |
if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) | |
return 0; | |
} | |
ExecState* exec = globalObject->globalExec(); | |
MarkedArgumentBuffer args; | |
args.append(jsNontrivialString(exec, m_eventParameterName)); | |
args.append(jsString(exec, m_code)); | |
JSObject* jsFunction = constructFunction(exec, args, Identifier(exec, m_functionName), m_sourceURL, m_lineNumber); // FIXME: is globalExec ok? | |
if (exec->hadException()) { | |
exec->clearException(); | |
return 0; | |
} | |
JSFunction* listenerAsFunction = static_cast<JSFunction*>(jsFunction); | |
if (m_originalNode) { | |
if (!wrapper()) { | |
// Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. | |
JSLock lock(SilenceAssertionsOnly); | |
// FIXME: Should pass the global object associated with the node | |
setWrapper(asObject(toJS(globalObject->globalExec(), globalObject, m_originalNode))); | |
} | |
// Add the event's home element to the scope | |
// (and the document, and the form - see JSHTMLElement::eventHandlerScope) | |
ScopeChain scope = listenerAsFunction->scope(); | |
static_cast<JSNode*>(wrapper())->pushEventHandlerScope(exec, scope); | |
listenerAsFunction->setScope(scope); | |
} | |
// Since we only parse once, there's no need to keep data used for parsing around anymore. | |
m_functionName = String(); | |
m_code = String(); | |
m_eventParameterName = String(); | |
m_sourceURL = String(); | |
return jsFunction; | |
} | |
} // namespace WebCore |