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 19 EventHandlerRegistry::EventHandlerRegistry(FrameHost& frameHost) 20 : m_frameHost(frameHost) 21 { 22 } 23 24 EventHandlerRegistry::~EventHandlerRegistry() 25 { 26 checkConsistency(); 27 } 28 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 47 const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClass handlerClass) const 48 { 49 checkConsistency(); 50 return &m_targets[handlerClass]; 51 } 52 53 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) const 54 { 55 checkConsistency(); 56 return m_targets[handlerClass].size(); 57 } 58 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 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 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 106 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, const AtomicString& eventType) 107 { 108 updateEventHandlerOfType(Add, eventType, &target); 109 } 110 111 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, const AtomicString& eventType) 112 { 113 updateEventHandlerOfType(Remove, eventType, &target); 114 } 115 116 void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerClass handlerClass) 117 { 118 updateEventHandlerInternal(Add, handlerClass, &target); 119 } 120 121 void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandlerClass handlerClass) 122 { 123 updateEventHandlerInternal(Remove, handlerClass, &target); 124 } 125 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 141 void EventHandlerRegistry::didMoveOutOfFrameHost(EventTarget& target) 142 { 143 didRemoveAllEventHandlers(target); 144 } 145 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 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 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 192 void EventHandlerRegistry::notifyDidAddOrRemoveEventHandlerTarget(EventHandlerClass handlerClass) 193 { 194 ScrollingCoordinator* scrollingCoordinator = m_frameHost.page().scrollingCoordinator(); 195 if (scrollingCoordinator && handlerClass == TouchEvent) 196 scrollingCoordinator->touchEventTargetRectsDidChange(); 197 } 198 199 void EventHandlerRegistry::trace(Visitor* visitor) 200 { 201 visitor->registerWeakMembers<EventHandlerRegistry, &EventHandlerRegistry::clearWeakMembers>(this); 202 } 203 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 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 251 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