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