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