0e7840722fe535100dd23f4da337eed3bbde300c
[WebKit-https.git] / Source / WebCore / bindings / js / JSEventListener.h
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 "EventListener.h"
24 #include "JSDOMWindow.h"
25 #include <heap/StrongInlines.h>
26 #include <heap/Weak.h>
27 #include <heap/WeakInlines.h>
28 #include <wtf/Ref.h>
29
30 namespace 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* isolatedWorld)
37         {
38             return adoptRef(new JSEventListener(listener, wrapper, isAttribute, isolatedWorld));
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);
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.get(); }
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&);
64         virtual bool virtualisAttribute() const;
65
66     protected:
67         JSEventListener(JSC::JSObject* function, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld* isolatedWorld);
68         virtual void handleEvent(ScriptExecutionContext*, Event*);
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::Heap::writeBarrier(m_wrapper.get(), function);
88             m_jsFunction = JSC::Weak<JSC::JSObject>(function);
89         }
90
91         // Verify that we have a valid wrapper protecting our function from
92         // garbage collection. That is except for when we're not in the normal
93         // world and can have zombie m_jsFunctions.
94         ASSERT(!m_isolatedWorld->isNormal() || m_wrapper || !m_jsFunction);
95
96         // If m_wrapper is 0, then m_jsFunction is zombied, and should never be accessed.
97         if (!m_wrapper)
98             return 0;
99
100         // Try to verify that m_jsFunction wasn't recycled. (Not exact, since an
101         // event listener can be almost anything, but this makes test-writing easier).
102         ASSERT(!m_jsFunction || static_cast<JSC::JSCell*>(m_jsFunction.get())->isObject());
103
104         return m_jsFunction.get();
105     }
106
107     // Creates a JS EventListener for an "onXXX" event attribute.
108     inline PassRefPtr<JSEventListener> createJSAttributeEventListener(JSC::ExecState* exec, JSC::JSValue listener, JSC::JSObject* wrapper)
109     {
110         if (!listener.isObject())
111             return 0;
112
113         return JSEventListener::create(asObject(listener), wrapper, true, currentWorld(exec));
114     }
115
116
117 } // namespace WebCore
118
119 #endif // JSEventListener_h