1/* 2 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 3 * Copyright (C) 2003, 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#ifndef JSEventListener_h 21#define JSEventListener_h 22 23#include "DOMWrapperWorld.h" 24#include "EventListener.h" 25#include <heap/StrongInlines.h> 26#include <heap/Weak.h> 27#include <heap/WeakInlines.h> 28#include <wtf/Ref.h> 29 30namespace WebCore { 31 32 class JSDOMGlobalObject; 33 34 class JSEventListener : public EventListener { 35 public: 36 static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld& world) 37 { 38 return adoptRef(new JSEventListener(listener, wrapper, isAttribute, world)); 39 } 40 41 static const JSEventListener* cast(const EventListener* listener) 42 { 43 return listener->type() == JSEventListenerType 44 ? static_cast<const JSEventListener*>(listener) 45 : 0; 46 } 47 48 virtual ~JSEventListener(); 49 50 virtual bool operator==(const EventListener& other) override; 51 52 // Returns true if this event listener was created for an event handler attribute, like "onload" or "onclick". 53 bool isAttribute() const { return m_isAttribute; } 54 55 JSC::JSObject* jsFunction(ScriptExecutionContext*) const; 56 DOMWrapperWorld& isolatedWorld() const { return *m_isolatedWorld; } 57 58 JSC::JSObject* wrapper() const { return m_wrapper.get(); } 59 void setWrapper(JSC::VM&, JSC::JSObject* wrapper) const { m_wrapper = JSC::Weak<JSC::JSObject>(wrapper); } 60 61 private: 62 virtual JSC::JSObject* initializeJSFunction(ScriptExecutionContext*) const; 63 virtual void visitJSFunction(JSC::SlotVisitor&) override; 64 virtual bool virtualisAttribute() const override; 65 66 protected: 67 JSEventListener(JSC::JSObject* function, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld&); 68 virtual void handleEvent(ScriptExecutionContext*, Event*) override; 69 70 private: 71 mutable JSC::Weak<JSC::JSObject> m_jsFunction; 72 mutable JSC::Weak<JSC::JSObject> m_wrapper; 73 74 bool m_isAttribute; 75 RefPtr<DOMWrapperWorld> m_isolatedWorld; 76 }; 77 78 inline JSC::JSObject* JSEventListener::jsFunction(ScriptExecutionContext* scriptExecutionContext) const 79 { 80 // initializeJSFunction can trigger code that deletes this event listener 81 // before we're done. It should always return 0 in this case. 82 Ref<JSEventListener> protect(const_cast<JSEventListener&>(*this)); 83 JSC::Strong<JSC::JSObject> wrapper(m_isolatedWorld->vm(), m_wrapper.get()); 84 85 if (!m_jsFunction) { 86 JSC::JSObject* function = initializeJSFunction(scriptExecutionContext); 87 JSC::JSObject* wrapper = m_wrapper.get(); 88 if (wrapper) 89 JSC::Heap::heap(wrapper)->writeBarrier(wrapper, function); 90 m_jsFunction = JSC::Weak<JSC::JSObject>(function); 91 } 92 93 // Verify that we have a valid wrapper protecting our function from 94 // garbage collection. That is except for when we're not in the normal 95 // world and can have zombie m_jsFunctions. 96 ASSERT(!m_isolatedWorld->isNormal() || m_wrapper || !m_jsFunction); 97 98 // If m_wrapper is 0, then m_jsFunction is zombied, and should never be accessed. 99 if (!m_wrapper) 100 return 0; 101 102 // Try to verify that m_jsFunction wasn't recycled. (Not exact, since an 103 // event listener can be almost anything, but this makes test-writing easier). 104 ASSERT(!m_jsFunction || static_cast<JSC::JSCell*>(m_jsFunction.get())->isObject()); 105 106 return m_jsFunction.get(); 107 } 108 109 // Creates a JS EventListener for an "onXXX" event attribute. 110 inline PassRefPtr<JSEventListener> createJSAttributeEventListener(JSC::ExecState* exec, JSC::JSValue listener, JSC::JSObject* wrapper) 111 { 112 if (!listener.isObject()) 113 return 0; 114 115 return JSEventListener::create(asObject(listener), wrapper, true, currentWorld(exec)); 116 } 117 118 119} // namespace WebCore 120 121#endif // JSEventListener_h 122