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