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.
6 #include "core/frame/EventHandlerRegistry.h"
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"
17 EventHandlerRegistry::EventHandlerRegistry(FrameHost& frameHost)
18 : m_frameHost(frameHost)
22 EventHandlerRegistry::~EventHandlerRegistry()
27 bool EventHandlerRegistry::eventTypeToClass(const AtomicString& eventType, EventHandlerClass* result)
29 if (eventType == EventTypeNames::scroll) {
30 *result = ScrollEvent;
31 } else if (eventType == EventTypeNames::wheel || eventType == EventTypeNames::mousewheel) {
34 } else if (eventType == EventTypeNames::load || eventType == EventTypeNames::mousemove || eventType == EventTypeNames::touchstart) {
35 *result = EventsForTesting;
43 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClass handlerClass) const
46 return &m_targets[handlerClass];
49 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) const
51 return m_targets[handlerClass].size();
54 bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
56 EventTargetSet* targets = &m_targets[handlerClass];
58 if (!targets->add(target).isNewEntry) {
59 // Just incremented refcount, no real change.
63 ASSERT(op == Remove || op == RemoveAll);
64 ASSERT(op == RemoveAll || targets->contains(target));
66 if (op == RemoveAll) {
67 if (!targets->contains(target))
69 targets->removeAll(target);
71 if (!targets->remove(target)) {
72 // Just decremented refcount, no real update.
80 void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
82 bool hadHandlers = hasEventHandlers(handlerClass);
83 updateEventHandlerTargets(op, handlerClass, target);
84 bool hasHandlers = hasEventHandlers(handlerClass);
86 if (hadHandlers != hasHandlers) {
87 notifyHasHandlersChanged(handlerClass, hasHandlers);
92 void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op, const AtomicString& eventType, EventTarget* target)
94 EventHandlerClass handlerClass;
95 if (!eventTypeToClass(eventType, &handlerClass))
97 updateEventHandlerInternal(op, handlerClass, target);
100 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, const AtomicString& eventType)
102 updateEventHandlerOfType(Add, eventType, &target);
105 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, const AtomicString& eventType)
107 updateEventHandlerOfType(Remove, eventType, &target);
110 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerClass handlerClass)
112 updateEventHandlerInternal(Add, handlerClass, &target);
115 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandlerClass handlerClass)
117 updateEventHandlerInternal(Remove, handlerClass, &target);
120 void EventHandlerRegistry::didMoveIntoFrameHost(EventTarget& target)
122 updateAllEventHandlers(Add, target);
125 void EventHandlerRegistry::didMoveOutOfFrameHost(EventTarget& target)
127 updateAllEventHandlers(RemoveAll, target);
130 void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget& target)
132 for (size_t i = 0; i < EventHandlerClassCount; ++i) {
133 EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
134 updateEventHandlerInternal(RemoveAll, handlerClass, &target);
138 void EventHandlerRegistry::updateAllEventHandlers(ChangeOperation op, EventTarget& target)
140 if (!target.hasEventListeners())
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))
148 if (op == RemoveAll) {
149 updateEventHandlerInternal(op, handlerClass, &target);
152 for (unsigned count = target.getEventListeners(eventTypes[i]).size(); count > 0; --count)
153 updateEventHandlerInternal(op, handlerClass, &target);
157 void EventHandlerRegistry::notifyHasHandlersChanged(EventHandlerClass handlerClass, bool hasActiveHandlers)
159 ScrollingCoordinator* scrollingCoordinator = m_frameHost.page().scrollingCoordinator();
161 switch (handlerClass) {
163 if (scrollingCoordinator)
164 scrollingCoordinator->updateHaveScrollEventHandlers();
167 if (scrollingCoordinator)
168 scrollingCoordinator->updateHaveWheelEventHandlers();
171 case EventsForTesting:
175 ASSERT_NOT_REACHED();
180 void EventHandlerRegistry::trace(Visitor* visitor)
182 visitor->registerWeakMembers<EventHandlerRegistry, &EventHandlerRegistry::clearWeakMembers>(this);
185 void EventHandlerRegistry::clearWeakMembers(Visitor* visitor)
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);
201 for (size_t i = 0; i < deadTargets.size(); ++i)
202 didRemoveAllEventHandlers(*deadTargets[i]);
205 void EventHandlerRegistry::documentDetached(Document& document)
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);
220 } else if (iter->key->toDOMWindow()) {
221 // DOMWindows may outlive their documents, so we shouldn't remove their handlers
224 ASSERT_NOT_REACHED();
227 for (size_t i = 0; i < targetsToRemove.size(); ++i)
228 updateEventHandlerInternal(RemoveAll, handlerClass, targetsToRemove[i]);
232 void EventHandlerRegistry::checkConsistency() const
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
246 ASSERT(window->frame());
247 ASSERT(window->frame()->host());
248 ASSERT(window->frame()->host() == &m_frameHost);
252 #endif // ASSERT_ENABLED
255 } // namespace WebCore