build.webkit.org/dashboard: OS X EWS is now on Mavericks
[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 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