1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/frame/EventHandlerRegistry.h"
7
8 #include "core/events/ThreadLocalEventNames.h"
9 #include "core/frame/LocalDOMWindow.h"
10 #include "core/frame/LocalFrame.h"
11 #include "core/html/HTMLFrameOwnerElement.h"
12 #include "core/page/Page.h"
13 #include "core/page/scrolling/ScrollingCoordinator.h"
14
15 namespace WebCore {
16
EventHandlerRegistry(FrameHost & frameHost)17 EventHandlerRegistry::EventHandlerRegistry(FrameHost& frameHost)
18 : m_frameHost(frameHost)
19 {
20 }
21
~EventHandlerRegistry()22 EventHandlerRegistry::~EventHandlerRegistry()
23 {
24 checkConsistency();
25 }
26
eventTypeToClass(const AtomicString & eventType,EventHandlerClass * result)27 bool EventHandlerRegistry::eventTypeToClass(const AtomicString& eventType, EventHandlerClass* result)
28 {
29 if (eventType == EventTypeNames::scroll) {
30 *result = ScrollEvent;
31 } else if (eventType == EventTypeNames::wheel || eventType == EventTypeNames::mousewheel) {
32 *result = WheelEvent;
33 #if ASSERT_ENABLED
34 } else if (eventType == EventTypeNames::load || eventType == EventTypeNames::mousemove || eventType == EventTypeNames::touchstart) {
35 *result = EventsForTesting;
36 #endif
37 } else {
38 return false;
39 }
40 return true;
41 }
42
eventHandlerTargets(EventHandlerClass handlerClass) const43 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClass handlerClass) const
44 {
45 checkConsistency();
46 return &m_targets[handlerClass];
47 }
48
hasEventHandlers(EventHandlerClass handlerClass) const49 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) const
50 {
51 return m_targets[handlerClass].size();
52 }
53
updateEventHandlerTargets(ChangeOperation op,EventHandlerClass handlerClass,EventTarget * target)54 bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
55 {
56 EventTargetSet* targets = &m_targets[handlerClass];
57 if (op == Add) {
58 if (!targets->add(target).isNewEntry) {
59 // Just incremented refcount, no real change.
60 return false;
61 }
62 } else {
63 ASSERT(op == Remove || op == RemoveAll);
64 ASSERT(op == RemoveAll || targets->contains(target));
65
66 if (op == RemoveAll) {
67 if (!targets->contains(target))
68 return false;
69 targets->removeAll(target);
70 } else {
71 if (!targets->remove(target)) {
72 // Just decremented refcount, no real update.
73 return false;
74 }
75 }
76 }
77 return true;
78 }
79
updateEventHandlerInternal(ChangeOperation op,EventHandlerClass handlerClass,EventTarget * target)80 void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
81 {
82 bool hadHandlers = hasEventHandlers(handlerClass);
83 updateEventHandlerTargets(op, handlerClass, target);
84 bool hasHandlers = hasEventHandlers(handlerClass);
85
86 if (hadHandlers != hasHandlers) {
87 notifyHasHandlersChanged(handlerClass, hasHandlers);
88 }
89 checkConsistency();
90 }
91
updateEventHandlerOfType(ChangeOperation op,const AtomicString & eventType,EventTarget * target)92 void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op, const AtomicString& eventType, EventTarget* target)
93 {
94 EventHandlerClass handlerClass;
95 if (!eventTypeToClass(eventType, &handlerClass))
96 return;
97 updateEventHandlerInternal(op, handlerClass, target);
98 }
99
didAddEventHandler(EventTarget & target,const AtomicString & eventType)100 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, const AtomicString& eventType)
101 {
102 updateEventHandlerOfType(Add, eventType, &target);
103 }
104
didRemoveEventHandler(EventTarget & target,const AtomicString & eventType)105 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, const AtomicString& eventType)
106 {
107 updateEventHandlerOfType(Remove, eventType, &target);
108 }
109
didAddEventHandler(EventTarget & target,EventHandlerClass handlerClass)110 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerClass handlerClass)
111 {
112 updateEventHandlerInternal(Add, handlerClass, &target);
113 }
114
didRemoveEventHandler(EventTarget & target,EventHandlerClass handlerClass)115 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandlerClass handlerClass)
116 {
117 updateEventHandlerInternal(Remove, handlerClass, &target);
118 }
119
didMoveIntoFrameHost(EventTarget & target)120 void EventHandlerRegistry::didMoveIntoFrameHost(EventTarget& target)
121 {
122 updateAllEventHandlers(Add, target);
123 }
124
didMoveOutOfFrameHost(EventTarget & target)125 void EventHandlerRegistry::didMoveOutOfFrameHost(EventTarget& target)
126 {
127 updateAllEventHandlers(RemoveAll, target);
128 }
129
didRemoveAllEventHandlers(EventTarget & target)130 void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget& target)
131 {
132 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
133 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
134 updateEventHandlerInternal(RemoveAll, handlerClass, &target);
135 }
136 }
137
updateAllEventHandlers(ChangeOperation op,EventTarget & target)138 void EventHandlerRegistry::updateAllEventHandlers(ChangeOperation op, EventTarget& target)
139 {
140 if (!target.hasEventListeners())
141 return;
142
143 Vector<AtomicString> eventTypes = target.eventTypes();
144 for (size_t i = 0; i < eventTypes.size(); ++i) {
145 EventHandlerClass handlerClass;
146 if (!eventTypeToClass(eventTypes[i], &handlerClass))
147 continue;
148 if (op == RemoveAll) {
149 updateEventHandlerInternal(op, handlerClass, &target);
150 continue;
151 }
152 for (unsigned count = target.getEventListeners(eventTypes[i]).size(); count > 0; --count)
153 updateEventHandlerInternal(op, handlerClass, &target);
154 }
155 }
156
notifyHasHandlersChanged(EventHandlerClass handlerClass,bool hasActiveHandlers)157 void EventHandlerRegistry::notifyHasHandlersChanged(EventHandlerClass handlerClass, bool hasActiveHandlers)
158 {
159 ScrollingCoordinator* scrollingCoordinator = m_frameHost.page().scrollingCoordinator();
160
161 switch (handlerClass) {
162 case ScrollEvent:
163 if (scrollingCoordinator)
164 scrollingCoordinator->updateHaveScrollEventHandlers();
165 break;
166 case WheelEvent:
167 if (scrollingCoordinator)
168 scrollingCoordinator->updateHaveWheelEventHandlers();
169 break;
170 #if ASSERT_ENABLED
171 case EventsForTesting:
172 break;
173 #endif
174 default:
175 ASSERT_NOT_REACHED();
176 break;
177 }
178 }
179
trace(Visitor * visitor)180 void EventHandlerRegistry::trace(Visitor* visitor)
181 {
182 visitor->registerWeakMembers<EventHandlerRegistry, &EventHandlerRegistry::clearWeakMembers>(this);
183 }
184
clearWeakMembers(Visitor * visitor)185 void EventHandlerRegistry::clearWeakMembers(Visitor* visitor)
186 {
187 Vector<EventTarget*> deadTargets;
188 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
189 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
190 const EventTargetSet* targets = &m_targets[handlerClass];
191 for (EventTargetSet::const_iterator it = targets->begin(); it != targets->end(); ++it) {
192 Node* node = it->key->toNode();
193 LocalDOMWindow* window = it->key->toDOMWindow();
194 if (node && !visitor->isAlive(node)) {
195 deadTargets.append(node);
196 } else if (window && !visitor->isAlive(window)) {
197 deadTargets.append(window);
198 }
199 }
200 }
201 for (size_t i = 0; i < deadTargets.size(); ++i)
202 didRemoveAllEventHandlers(*deadTargets[i]);
203 }
204
documentDetached(Document & document)205 void EventHandlerRegistry::documentDetached(Document& document)
206 {
207 // Remove all event targets under the detached document.
208 for (size_t handlerClassIndex = 0; handlerClassIndex < EventHandlerClassCount; ++handlerClassIndex) {
209 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(handlerClassIndex);
210 Vector<EventTarget*> targetsToRemove;
211 const EventTargetSet* targets = &m_targets[handlerClass];
212 for (EventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
213 if (Node* node = iter->key->toNode()) {
214 for (Document* doc = &node->document(); doc; doc = doc->ownerElement() ? &doc->ownerElement()->document() : 0) {
215 if (doc == &document) {
216 targetsToRemove.append(iter->key);
217 break;
218 }
219 }
220 } else if (iter->key->toDOMWindow()) {
221 // DOMWindows may outlive their documents, so we shouldn't remove their handlers
222 // here.
223 } else {
224 ASSERT_NOT_REACHED();
225 }
226 }
227 for (size_t i = 0; i < targetsToRemove.size(); ++i)
228 updateEventHandlerInternal(RemoveAll, handlerClass, targetsToRemove[i]);
229 }
230 }
231
checkConsistency() const232 void EventHandlerRegistry::checkConsistency() const
233 {
234 #if ASSERT_ENABLED
235 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
236 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
237 const EventTargetSet* targets = &m_targets[handlerClass];
238 for (EventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
239 if (Node* node = iter->key->toNode()) {
240 // See the comment for |documentDetached| if either of these assertions fails.
241 ASSERT(node->document().frameHost());
242 ASSERT(node->document().frameHost() == &m_frameHost);
243 } else if (LocalDOMWindow* window = iter->key->toDOMWindow()) {
244 // If any of these assertions fail, LocalDOMWindow failed to unregister its handlers
245 // properly.
246 ASSERT(window->frame());
247 ASSERT(window->frame()->host());
248 ASSERT(window->frame()->host() == &m_frameHost);
249 }
250 }
251 }
252 #endif // ASSERT_ENABLED
253 }
254
255 } // namespace WebCore
256