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
31 using namespace JSC;
32
33 namespace WebCore {
34
35 #ifndef NDEBUG
36 static WTF::RefCountedLeakCounter eventListenerCounter("JSLazyEventListener");
37 #endif
38
JSLazyEventListener(const String & functionName,const String & eventParameterName,const String & code,Node * node,const String & sourceURL,int lineNumber,JSObject * wrapper,DOMWrapperWorld * isolatedWorld)39 JSLazyEventListener::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
~JSLazyEventListener()64 JSLazyEventListener::~JSLazyEventListener()
65 {
66 #ifndef NDEBUG
67 eventListenerCounter.decrement();
68 #endif
69 }
70
initializeJSFunction(ScriptExecutionContext * executionContext) const71 JSObject* 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