Home | History | Annotate | Download | only in js
      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