a03955371bf1cf3cca8000a246b4b666a89e2a95
[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 #include <wtf/text/TextPosition.h>
30 #include <wtf/text/WTFString.h>
31
32 namespace WebCore {
33
34 class DOMWindow;
35 class EventTarget;
36 class HTMLElement;
37 class JSDOMGlobalObject;
38
39 class JSEventListener : public EventListener {
40 public:
41     static Ref<JSEventListener> create(JSC::JSObject* listener, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld& world)
42     {
43         return adoptRef(*new JSEventListener(listener, wrapper, isAttribute, world));
44     }
45
46     static const JSEventListener* cast(const EventListener* listener)
47     {
48         return listener->type() == JSEventListenerType
49             ? static_cast<const JSEventListener*>(listener)
50             : 0;
51     }
52
53     virtual ~JSEventListener();
54
55     bool operator==(const EventListener& other) override;
56
57     // Returns true if this event listener was created for an event handler attribute, like "onload" or "onclick".
58     bool isAttribute() const { return m_isAttribute; }
59
60     JSC::JSObject* jsFunction(ScriptExecutionContext*) const;
61     DOMWrapperWorld& isolatedWorld() const { return *m_isolatedWorld; }
62
63     JSC::JSObject* wrapper() const { return m_wrapper.get(); }
64     void setWrapper(JSC::VM&, JSC::JSObject* wrapper) const { m_wrapper = JSC::Weak<JSC::JSObject>(wrapper); }
65
66     virtual String sourceURL() const { return String(); }
67     virtual TextPosition sourcePosition() const { return TextPosition::minimumPosition(); }
68
69 private:
70     virtual JSC::JSObject* initializeJSFunction(ScriptExecutionContext*) const;
71     void visitJSFunction(JSC::SlotVisitor&) override;
72     bool virtualisAttribute() const override;
73
74 protected:
75     JSEventListener(JSC::JSObject* function, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld&);
76     void handleEvent(ScriptExecutionContext*, Event*) override;
77
78 private:
79     mutable JSC::Weak<JSC::JSObject> m_jsFunction;
80     mutable JSC::Weak<JSC::JSObject> m_wrapper;
81
82     bool m_isAttribute;
83     RefPtr<DOMWrapperWorld> m_isolatedWorld;
84 };
85
86 // For "onxxx" attributes that automatically set up JavaScript event listeners.
87 JSC::JSValue eventHandlerAttribute(EventTarget&, const AtomicString& eventType);
88 void setEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, EventTarget&, const AtomicString& eventType, JSC::JSValue);
89
90 // Like the functions above, but for attributes that forward event handlers to the window object rather than setting them on the target.
91 JSC::JSValue windowEventHandlerAttribute(HTMLElement&, const AtomicString& eventType);
92 void setWindowEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, HTMLElement&, const AtomicString& eventType, JSC::JSValue);
93 JSC::JSValue windowEventHandlerAttribute(DOMWindow&, const AtomicString& eventType);
94 void setWindowEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, DOMWindow&, const AtomicString& eventType, JSC::JSValue);
95
96 // Like the functions above, but for attributes that forward event handlers to the document rather than setting them on the target.
97 JSC::JSValue documentEventHandlerAttribute(HTMLElement&, const AtomicString& eventType);
98 void setDocumentEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, HTMLElement&, const AtomicString& eventType, JSC::JSValue);
99 JSC::JSValue documentEventHandlerAttribute(Document&, const AtomicString& eventType);
100 void setDocumentEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, Document&, const AtomicString& eventType, JSC::JSValue);
101
102 Ref<JSEventListener> createJSEventListenerForAdd(JSC::ExecState&, JSC::JSObject& listener, JSC::JSObject& wrapper);
103 Ref<JSEventListener> createJSEventListenerForRemove(JSC::ExecState&, JSC::JSObject& listener, JSC::JSObject& wrapper);
104
105 inline JSC::JSObject* JSEventListener::jsFunction(ScriptExecutionContext* scriptExecutionContext) const
106 {
107     // initializeJSFunction can trigger code that deletes this event listener
108     // before we're done. It should always return 0 in this case.
109     Ref<JSEventListener> protect(const_cast<JSEventListener&>(*this));
110     JSC::Strong<JSC::JSObject> wrapper(m_isolatedWorld->vm(), m_wrapper.get());
111
112     if (!m_jsFunction) {
113         JSC::JSObject* function = initializeJSFunction(scriptExecutionContext);
114         JSC::JSObject* wrapper = m_wrapper.get();
115         if (wrapper)
116             JSC::Heap::heap(wrapper)->writeBarrier(wrapper, function);
117         m_jsFunction = JSC::Weak<JSC::JSObject>(function);
118     }
119
120     // Verify that we have a valid wrapper protecting our function from
121     // garbage collection. That is except for when we're not in the normal
122     // world and can have zombie m_jsFunctions.
123     ASSERT(!m_isolatedWorld->isNormal() || m_wrapper || !m_jsFunction);
124
125     // If m_wrapper is 0, then m_jsFunction is zombied, and should never be accessed.
126     if (!m_wrapper)
127         return 0;
128
129     // Try to verify that m_jsFunction wasn't recycled. (Not exact, since an
130     // event listener can be almost anything, but this makes test-writing easier).
131     ASSERT(!m_jsFunction || static_cast<JSC::JSCell*>(m_jsFunction.get())->isObject());
132
133     return m_jsFunction.get();
134 }
135
136 inline Ref<JSEventListener> createJSEventListenerForRemove(JSC::ExecState& state, JSC::JSObject& listener, JSC::JSObject& wrapper)
137 {
138     return createJSEventListenerForAdd(state, listener, wrapper);
139 }
140
141 } // namespace WebCore
142
143 #endif // JSEventListener_h