1/* 2 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 3 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All Rights Reserved. 4 * 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. 9 * 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. 14 * 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 18 */ 19 20#include "config.h" 21#include "JSLazyEventListener.h" 22 23#include "ContentSecurityPolicy.h" 24#include "Frame.h" 25#include "JSNode.h" 26#include <runtime/FunctionConstructor.h> 27#include <runtime/JSFunction.h> 28#include <runtime/JSLock.h> 29#include <wtf/RefCountedLeakCounter.h> 30 31using namespace JSC; 32 33namespace WebCore { 34 35#ifndef NDEBUG 36static WTF::RefCountedLeakCounter eventListenerCounter("JSLazyEventListener"); 37#endif 38 39JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber, JSObject* wrapper, DOMWrapperWorld* isolatedWorld) 40 : JSEventListener(0, wrapper, true, isolatedWorld) 41 , m_functionName(functionName) 42 , m_eventParameterName(eventParameterName) 43 , m_code(code) 44 , m_sourceURL(sourceURL) 45 , m_lineNumber(lineNumber) 46 , m_originalNode(node) 47{ 48 // We don't retain the original node because we assume it 49 // will stay alive as long as this handler object is around 50 // and we need to avoid a reference cycle. If JS transfers 51 // this handler to another node, initializeJSFunction will 52 // be called and then originalNode is no longer needed. 53 54 // A JSLazyEventListener can be created with a line number of zero when it is created with 55 // a setAttribute call from JavaScript, so make the line number 1 in that case. 56 if (m_lineNumber == 0) 57 m_lineNumber = 1; 58 59#ifndef NDEBUG 60 eventListenerCounter.increment(); 61#endif 62} 63 64JSLazyEventListener::~JSLazyEventListener() 65{ 66#ifndef NDEBUG 67 eventListenerCounter.decrement(); 68#endif 69} 70 71JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const 72{ 73 ASSERT(executionContext); 74 ASSERT(executionContext->isDocument()); 75 if (!executionContext) 76 return 0; 77 78 Document* document = static_cast<Document*>(executionContext); 79 80 if (!document->frame()) 81 return 0; 82 83 if (!document->contentSecurityPolicy()->allowInlineEventHandlers()) 84 return 0; 85 86 ScriptController* script = document->frame()->script(); 87 if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) 88 return 0; 89 90 JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld()); 91 if (!globalObject) 92 return 0; 93 94 ExecState* exec = globalObject->globalExec(); 95 96 MarkedArgumentBuffer args; 97 args.append(jsNontrivialString(exec, stringToUString(m_eventParameterName))); 98 args.append(jsString(exec, m_code)); 99 100 JSObject* jsFunction = constructFunction(exec, exec->lexicalGlobalObject(), args, Identifier(exec, stringToUString(m_functionName)), stringToUString(m_sourceURL), m_lineNumber); // FIXME: is globalExec ok? 101 if (exec->hadException()) { 102 exec->clearException(); 103 return 0; 104 } 105 106 JSFunction* listenerAsFunction = static_cast<JSFunction*>(jsFunction); 107 if (m_originalNode) { 108 if (!wrapper()) { 109 // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. 110 JSLock lock(SilenceAssertionsOnly); 111 // FIXME: Should pass the global object associated with the node 112 setWrapper(exec->globalData(), asObject(toJS(exec, globalObject, m_originalNode))); 113 } 114 115 // Add the event's home element to the scope 116 // (and the document, and the form - see JSHTMLElement::eventHandlerScope) 117 listenerAsFunction->setScope(exec->globalData(), static_cast<JSNode*>(wrapper())->pushEventHandlerScope(exec, listenerAsFunction->scope())); 118 } 119 120 // Since we only parse once, there's no need to keep data used for parsing around anymore. 121 m_functionName = String(); 122 m_code = String(); 123 m_eventParameterName = String(); 124 m_sourceURL = String(); 125 return jsFunction; 126} 127 128} // namespace WebCore 129