Fix build.
[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 "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
30 namespace WebCore {
31
32     class JSDOMGlobalObject;
33
34     class JSEventListener : public EventListener {
35     public:
36         static Ref<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     // For "onXXX" event attributes.
79     RefPtr<JSEventListener> createJSEventListenerForAttribute(JSC::ExecState&, JSC::JSValue listener, JSC::JSObject& wrapper);
80
81     Ref<JSEventListener> createJSEventListenerForAdd(JSC::ExecState&, JSC::JSObject& listener, JSC::JSObject& wrapper);
82     Ref<JSEventListener> createJSEventListenerForRemove(JSC::ExecState&, JSC::JSObject& listener, JSC::JSObject& wrapper);
83
84     inline JSC::JSObject* JSEventListener::jsFunction(ScriptExecutionContext* scriptExecutionContext) const
85     {
86         // initializeJSFunction can trigger code that deletes this event listener
87         // before we're done. It should always return 0 in this case.
88         Ref<JSEventListener> protect(const_cast<JSEventListener&>(*this));
89         JSC::Strong<JSC::JSObject> wrapper(m_isolatedWorld->vm(), m_wrapper.get());
90
91         if (!m_jsFunction) {
92             JSC::JSObject* function = initializeJSFunction(scriptExecutionContext);
93             JSC::JSObject* wrapper = m_wrapper.get();
94             if (wrapper)
95                 JSC::Heap::heap(wrapper)->writeBarrier(wrapper, function);
96             m_jsFunction = JSC::Weak<JSC::JSObject>(function);
97         }
98
99         // Verify that we have a valid wrapper protecting our function from
100         // garbage collection. That is except for when we're not in the normal
101         // world and can have zombie m_jsFunctions.
102         ASSERT(!m_isolatedWorld->isNormal() || m_wrapper || !m_jsFunction);
103
104         // If m_wrapper is 0, then m_jsFunction is zombied, and should never be accessed.
105         if (!m_wrapper)
106             return 0;
107
108         // Try to verify that m_jsFunction wasn't recycled. (Not exact, since an
109         // event listener can be almost anything, but this makes test-writing easier).
110         ASSERT(!m_jsFunction || static_cast<JSC::JSCell*>(m_jsFunction.get())->isObject());
111
112         return m_jsFunction.get();
113     }
114
115     inline RefPtr<JSEventListener> createJSEventListenerForAttribute(JSC::ExecState& state, JSC::JSValue listener, JSC::JSObject& wrapper)
116     {
117         if (!listener.isObject())
118             return nullptr;
119         return JSEventListener::create(asObject(listener), &wrapper, true, currentWorld(&state));
120     }
121
122     inline Ref<JSEventListener> createJSEventListenerForRemove(JSC::ExecState& state, JSC::JSObject& listener, JSC::JSObject& wrapper)
123     {
124         return createJSEventListenerForAdd(state, listener, wrapper);
125     }
126
127 } // namespace WebCore
128
129 #endif // JSEventListener_h