Rename AtomicString to AtomString
[WebKit-https.git] / Source / WebCore / bindings / js / JSEventListener.h
1 /*
2  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
3  *  Copyright (C) 2003-2018 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 #pragma once
21
22 #include "DOMWrapperWorld.h"
23 #include "EventListener.h"
24 #include <JavaScriptCore/StrongInlines.h>
25 #include <JavaScriptCore/Weak.h>
26 #include <JavaScriptCore/WeakInlines.h>
27 #include <wtf/Ref.h>
28 #include <wtf/TypeCasts.h>
29 #include <wtf/text/TextPosition.h>
30 #include <wtf/text/WTFString.h>
31
32 namespace WebCore {
33
34 class DOMWindow;
35 class Document;
36 class EventTarget;
37 class HTMLElement;
38
39 class JSEventListener : public EventListener {
40 public:
41     static Ref<JSEventListener> create(JSC::JSObject* listener, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld&);
42     static RefPtr<JSEventListener> create(JSC::JSValue listener, JSC::JSObject& wrapper, bool isAttribute, DOMWrapperWorld&);
43
44     virtual ~JSEventListener();
45
46     bool operator==(const EventListener&) const final;
47
48     // Returns true if this event listener was created for an event handler attribute, like "onload" or "onclick".
49     bool isAttribute() const final { return m_isAttribute; }
50
51     JSC::JSObject* jsFunction(ScriptExecutionContext&) const;
52     DOMWrapperWorld& isolatedWorld() const { return m_isolatedWorld; }
53
54     JSC::JSObject* wrapper() const { return m_wrapper.get(); }
55     void setWrapper(JSC::VM&, JSC::JSObject* wrapper) const { m_wrapper = JSC::Weak<JSC::JSObject>(wrapper); }
56
57     virtual String sourceURL() const { return String(); }
58     virtual TextPosition sourcePosition() const { return TextPosition(); }
59
60 private:
61     virtual JSC::JSObject* initializeJSFunction(ScriptExecutionContext&) const;
62     void visitJSFunction(JSC::SlotVisitor&) final;
63
64 protected:
65     JSEventListener(JSC::JSObject* function, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld&);
66     void handleEvent(ScriptExecutionContext&, Event&) override;
67
68 private:
69     mutable JSC::Weak<JSC::JSObject> m_jsFunction;
70     mutable JSC::Weak<JSC::JSObject> m_wrapper;
71
72     bool m_isAttribute;
73     Ref<DOMWrapperWorld> m_isolatedWorld;
74 };
75
76 // For "onxxx" attributes that automatically set up JavaScript event listeners.
77 JSC::JSValue eventHandlerAttribute(EventTarget&, const AtomString& eventType, DOMWrapperWorld&);
78 void setEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, EventTarget&, const AtomString& eventType, JSC::JSValue);
79
80 // Like the functions above, but for attributes that forward event handlers to the window object rather than setting them on the target.
81 JSC::JSValue windowEventHandlerAttribute(HTMLElement&, const AtomString& eventType, DOMWrapperWorld&);
82 void setWindowEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, HTMLElement&, const AtomString& eventType, JSC::JSValue);
83 JSC::JSValue windowEventHandlerAttribute(DOMWindow&, const AtomString& eventType, DOMWrapperWorld&);
84 void setWindowEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, DOMWindow&, const AtomString& eventType, JSC::JSValue);
85
86 // Like the functions above, but for attributes that forward event handlers to the document rather than setting them on the target.
87 JSC::JSValue documentEventHandlerAttribute(HTMLElement&, const AtomString& eventType, DOMWrapperWorld&);
88 void setDocumentEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, HTMLElement&, const AtomString& eventType, JSC::JSValue);
89 JSC::JSValue documentEventHandlerAttribute(Document&, const AtomString& eventType, DOMWrapperWorld&);
90 void setDocumentEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, Document&, const AtomString& eventType, JSC::JSValue);
91
92 inline JSC::JSObject* JSEventListener::jsFunction(ScriptExecutionContext& scriptExecutionContext) const
93 {
94     // initializeJSFunction can trigger code that deletes this event listener
95     // before we're done. It should always return null in this case.
96     auto protect = makeRef(const_cast<JSEventListener&>(*this));
97     JSC::Strong<JSC::JSObject> wrapper(m_isolatedWorld->vm(), m_wrapper.get());
98
99     if (!m_jsFunction) {
100         auto* function = initializeJSFunction(scriptExecutionContext);
101         if (auto* wrapper = m_wrapper.get())
102             JSC::Heap::heap(wrapper)->writeBarrier(wrapper, function);
103         m_jsFunction = JSC::Weak<JSC::JSObject>(function);
104     }
105
106     // Verify that we have a valid wrapper protecting our function from
107     // garbage collection. That is except for when we're not in the normal
108     // world and can have zombie m_jsFunctions.
109     ASSERT(!m_isolatedWorld->isNormal() || m_wrapper || !m_jsFunction);
110
111     // If m_wrapper is null, then m_jsFunction is zombied, and should never be accessed.
112     if (!m_wrapper)
113         return nullptr;
114
115     // Try to verify that m_jsFunction wasn't recycled. (Not exact, since an
116     // event listener can be almost anything, but this makes test-writing easier).
117     ASSERT(!m_jsFunction || static_cast<JSC::JSCell*>(m_jsFunction.get())->isObject());
118
119     return m_jsFunction.get();
120 }
121
122 } // namespace WebCore
123
124 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::JSEventListener)
125 static bool isType(const WebCore::EventListener& input) { return input.type() == WebCore::JSEventListener::JSEventListenerType; }
126 SPECIALIZE_TYPE_TRAITS_END()