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 17 EventHandlerRegistry::EventHandlerRegistry(FrameHost& frameHost) 18 : m_frameHost(frameHost) 19 { 20 } 21 22 EventHandlerRegistry::~EventHandlerRegistry() 23 { 24 checkConsistency(); 25 } 26 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 43 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClass handlerClass) const 44 { 45 checkConsistency(); 46 return &m_targets[handlerClass]; 47 } 48 49 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) const 50 { 51 return m_targets[handlerClass].size(); 52 } 53 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 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 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 100 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, const AtomicString& eventType) 101 { 102 updateEventHandlerOfType(Add, eventType, &target); 103 } 104 105 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, const AtomicString& eventType) 106 { 107 updateEventHandlerOfType(Remove, eventType, &target); 108 } 109 110 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerClass handlerClass) 111 { 112 updateEventHandlerInternal(Add, handlerClass, &target); 113 } 114 115 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandlerClass handlerClass) 116 { 117 updateEventHandlerInternal(Remove, handlerClass, &target); 118 } 119 120 void EventHandlerRegistry::didMoveIntoFrameHost(EventTarget& target) 121 { 122 updateAllEventHandlers(Add, target); 123 } 124 125 void EventHandlerRegistry::didMoveOutOfFrameHost(EventTarget& target) 126 { 127 updateAllEventHandlers(RemoveAll, target); 128 } 129 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 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 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 180 void EventHandlerRegistry::trace(Visitor* visitor) 181 { 182 visitor->registerWeakMembers<EventHandlerRegistry, &EventHandlerRegistry::clearWeakMembers>(this); 183 } 184 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 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 232 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