PageRenderTime 309ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/core/frame/EventHandlerRegistry.cpp

https://gitlab.com/bjwbell/b2
C++ | 304 lines | 255 code | 34 blank | 15 comment | 87 complexity | 60dc06577940f8b6c59b4585f867e988 MD5 | raw file
  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. #include "core/frame/EventHandlerRegistry.h"
  5. #include "core/events/EventListenerOptions.h"
  6. #include "core/events/EventUtil.h"
  7. #include "core/frame/LocalDOMWindow.h"
  8. #include "core/frame/LocalFrame.h"
  9. #include "core/html/HTMLFrameOwnerElement.h"
  10. #include "core/page/ChromeClient.h"
  11. #include "core/page/Page.h"
  12. #include "core/page/scrolling/ScrollingCoordinator.h"
  13. namespace blink {
  14. namespace {
  15. WebEventListenerProperties webEventListenerProperties(bool hasBlocking, bool hasPassive)
  16. {
  17. if (hasBlocking && hasPassive)
  18. return WebEventListenerProperties::BlockingAndPassive;
  19. if (hasBlocking)
  20. return WebEventListenerProperties::Blocking;
  21. if (hasPassive)
  22. return WebEventListenerProperties::Passive;
  23. return WebEventListenerProperties::Nothing;
  24. }
  25. } // namespace
  26. EventHandlerRegistry::EventHandlerRegistry(FrameHost& frameHost)
  27. : m_frameHost(&frameHost)
  28. {
  29. }
  30. EventHandlerRegistry::~EventHandlerRegistry()
  31. {
  32. checkConsistency();
  33. }
  34. bool EventHandlerRegistry::eventTypeToClass(const AtomicString& eventType, const AddEventListenerOptions& options, EventHandlerClass* result)
  35. {
  36. if (eventType == EventTypeNames::scroll) {
  37. *result = ScrollEvent;
  38. } else if (eventType == EventTypeNames::wheel || eventType == EventTypeNames::mousewheel) {
  39. *result = options.passive() ? WheelEventPassive : WheelEventBlocking;
  40. } else if (eventType == EventTypeNames::touchend || eventType == EventTypeNames::touchcancel) {
  41. *result = options.passive() ? TouchEndOrCancelEventPassive : TouchEndOrCancelEventBlocking;
  42. } else if (eventType == EventTypeNames::touchstart || eventType == EventTypeNames::touchmove) {
  43. *result = options.passive() ? TouchStartOrMoveEventPassive : TouchStartOrMoveEventBlocking;
  44. } else if (EventUtil::isPointerEventType(eventType)) {
  45. // The EventHandlerClass is TouchStartOrMoveEventPassive since
  46. // the pointer events never block scrolling and the compositor
  47. // only needs to know about the touch listeners.
  48. *result = TouchStartOrMoveEventPassive;
  49. #if ENABLE(ASSERT)
  50. } else if (eventType == EventTypeNames::load || eventType == EventTypeNames::mousemove || eventType == EventTypeNames::touchstart) {
  51. *result = EventsForTesting;
  52. #endif
  53. } else {
  54. return false;
  55. }
  56. return true;
  57. }
  58. const EventTargetSet* EventHandlerRegistry::eventHandlerTargets(EventHandlerClass handlerClass) const
  59. {
  60. checkConsistency();
  61. return &m_targets[handlerClass];
  62. }
  63. bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass) const
  64. {
  65. checkConsistency();
  66. return m_targets[handlerClass].size();
  67. }
  68. bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
  69. {
  70. EventTargetSet* targets = &m_targets[handlerClass];
  71. if (op == Add) {
  72. if (!targets->add(target).isNewEntry) {
  73. // Just incremented refcount, no real change.
  74. return false;
  75. }
  76. } else {
  77. ASSERT(op == Remove || op == RemoveAll);
  78. ASSERT(op == RemoveAll || targets->contains(target));
  79. if (op == RemoveAll) {
  80. if (!targets->contains(target))
  81. return false;
  82. targets->removeAll(target);
  83. } else {
  84. if (!targets->remove(target)) {
  85. // Just decremented refcount, no real update.
  86. return false;
  87. }
  88. }
  89. }
  90. return true;
  91. }
  92. void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op, EventHandlerClass handlerClass, EventTarget* target)
  93. {
  94. bool hadHandlers = m_targets[handlerClass].size();
  95. bool targetSetChanged = updateEventHandlerTargets(op, handlerClass, target);
  96. bool hasHandlers = m_targets[handlerClass].size();
  97. if (hadHandlers != hasHandlers)
  98. notifyHasHandlersChanged(handlerClass, hasHandlers);
  99. if (targetSetChanged)
  100. notifyDidAddOrRemoveEventHandlerTarget(handlerClass);
  101. }
  102. void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op, const AtomicString& eventType, const AddEventListenerOptions& options, EventTarget* target)
  103. {
  104. EventHandlerClass handlerClass;
  105. if (!eventTypeToClass(eventType, options, &handlerClass))
  106. return;
  107. updateEventHandlerInternal(op, handlerClass, target);
  108. }
  109. void EventHandlerRegistry::didAddEventHandler(EventTarget& target, const AtomicString& eventType, const AddEventListenerOptions& options)
  110. {
  111. updateEventHandlerOfType(Add, eventType, options, &target);
  112. }
  113. void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, const AtomicString& eventType, const AddEventListenerOptions& options)
  114. {
  115. updateEventHandlerOfType(Remove, eventType, options, &target);
  116. }
  117. void EventHandlerRegistry::didAddEventHandler(EventTarget& target, EventHandlerClass handlerClass)
  118. {
  119. updateEventHandlerInternal(Add, handlerClass, &target);
  120. }
  121. void EventHandlerRegistry::didRemoveEventHandler(EventTarget& target, EventHandlerClass handlerClass)
  122. {
  123. updateEventHandlerInternal(Remove, handlerClass, &target);
  124. }
  125. void EventHandlerRegistry::didMoveIntoFrameHost(EventTarget& target)
  126. {
  127. if (!target.hasEventListeners())
  128. return;
  129. // This code is not efficient at all.
  130. Vector<AtomicString> eventTypes = target.eventTypes();
  131. for (size_t i = 0; i < eventTypes.size(); ++i) {
  132. EventListenerVector* listeners = target.getEventListeners(eventTypes[i]);
  133. if (!listeners)
  134. continue;
  135. for (unsigned count = listeners->size(); count > 0; --count) {
  136. EventHandlerClass handlerClass;
  137. if (!eventTypeToClass(eventTypes[i], (*listeners)[count - 1].options(), &handlerClass))
  138. continue;
  139. didAddEventHandler(target, handlerClass);
  140. }
  141. }
  142. }
  143. void EventHandlerRegistry::didMoveOutOfFrameHost(EventTarget& target)
  144. {
  145. didRemoveAllEventHandlers(target);
  146. }
  147. void EventHandlerRegistry::didMoveBetweenFrameHosts(EventTarget& target, FrameHost* oldFrameHost, FrameHost* newFrameHost)
  148. {
  149. ASSERT(newFrameHost != oldFrameHost);
  150. for (size_t i = 0; i < EventHandlerClassCount; ++i) {
  151. EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
  152. const EventTargetSet* targets = &oldFrameHost->eventHandlerRegistry().m_targets[handlerClass];
  153. for (unsigned count = targets->count(&target); count > 0; --count)
  154. newFrameHost->eventHandlerRegistry().didAddEventHandler(target, handlerClass);
  155. oldFrameHost->eventHandlerRegistry().didRemoveAllEventHandlers(target);
  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. void EventHandlerRegistry::notifyHasHandlersChanged(EventHandlerClass handlerClass, bool hasActiveHandlers)
  166. {
  167. switch (handlerClass) {
  168. case ScrollEvent:
  169. m_frameHost->chromeClient().setHasScrollEventHandlers(hasActiveHandlers);
  170. break;
  171. case WheelEventBlocking:
  172. case WheelEventPassive:
  173. m_frameHost->chromeClient().setEventListenerProperties(WebEventListenerClass::MouseWheel, webEventListenerProperties(hasEventHandlers(WheelEventBlocking), hasEventHandlers(WheelEventPassive)));
  174. break;
  175. case TouchStartOrMoveEventBlocking:
  176. case TouchStartOrMoveEventPassive:
  177. m_frameHost->chromeClient().setEventListenerProperties(WebEventListenerClass::TouchStartOrMove, webEventListenerProperties(hasEventHandlers(TouchStartOrMoveEventBlocking), hasEventHandlers(TouchStartOrMoveEventPassive)));
  178. break;
  179. case TouchEndOrCancelEventBlocking:
  180. case TouchEndOrCancelEventPassive:
  181. m_frameHost->chromeClient().setEventListenerProperties(WebEventListenerClass::TouchEndOrCancel, webEventListenerProperties(hasEventHandlers(TouchEndOrCancelEventBlocking), hasEventHandlers(TouchEndOrCancelEventPassive)));
  182. break;
  183. #if ENABLE(ASSERT)
  184. case EventsForTesting:
  185. break;
  186. #endif
  187. default:
  188. ASSERT_NOT_REACHED();
  189. break;
  190. }
  191. }
  192. void EventHandlerRegistry::notifyDidAddOrRemoveEventHandlerTarget(EventHandlerClass handlerClass)
  193. {
  194. ScrollingCoordinator* scrollingCoordinator = m_frameHost->page().scrollingCoordinator();
  195. if (scrollingCoordinator && handlerClass == TouchStartOrMoveEventBlocking)
  196. scrollingCoordinator->touchEventTargetRectsDidChange();
  197. }
  198. DEFINE_TRACE(EventHandlerRegistry)
  199. {
  200. visitor->trace(m_frameHost);
  201. visitor->template registerWeakMembers<EventHandlerRegistry, &EventHandlerRegistry::clearWeakMembers>(this);
  202. }
  203. void EventHandlerRegistry::clearWeakMembers(Visitor* visitor)
  204. {
  205. Vector<UntracedMember<EventTarget>> deadTargets;
  206. for (size_t i = 0; i < EventHandlerClassCount; ++i) {
  207. EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
  208. const EventTargetSet* targets = &m_targets[handlerClass];
  209. for (const auto& eventTarget : *targets) {
  210. Node* node = eventTarget.key->toNode();
  211. LocalDOMWindow* window = eventTarget.key->toLocalDOMWindow();
  212. if (node && !ThreadHeap::isHeapObjectAlive(node)) {
  213. deadTargets.append(node);
  214. } else if (window && !ThreadHeap::isHeapObjectAlive(window)) {
  215. deadTargets.append(window);
  216. }
  217. }
  218. }
  219. for (size_t i = 0; i < deadTargets.size(); ++i)
  220. didRemoveAllEventHandlers(*deadTargets[i]);
  221. }
  222. void EventHandlerRegistry::documentDetached(Document& document)
  223. {
  224. // Remove all event targets under the detached document.
  225. for (size_t handlerClassIndex = 0; handlerClassIndex < EventHandlerClassCount; ++handlerClassIndex) {
  226. EventHandlerClass handlerClass = static_cast<EventHandlerClass>(handlerClassIndex);
  227. Vector<UntracedMember<EventTarget>> targetsToRemove;
  228. const EventTargetSet* targets = &m_targets[handlerClass];
  229. for (const auto& eventTarget : *targets) {
  230. if (Node* node = eventTarget.key->toNode()) {
  231. for (Document* doc = &node->document(); doc; doc = doc->localOwner() ? &doc->localOwner()->document() : 0) {
  232. if (doc == &document) {
  233. targetsToRemove.append(eventTarget.key);
  234. break;
  235. }
  236. }
  237. } else if (eventTarget.key->toLocalDOMWindow()) {
  238. // DOMWindows may outlive their documents, so we shouldn't remove their handlers
  239. // here.
  240. } else {
  241. ASSERT_NOT_REACHED();
  242. }
  243. }
  244. for (size_t i = 0; i < targetsToRemove.size(); ++i)
  245. updateEventHandlerInternal(RemoveAll, handlerClass, targetsToRemove[i]);
  246. }
  247. }
  248. void EventHandlerRegistry::checkConsistency() const
  249. {
  250. #if ENABLE(ASSERT)
  251. for (size_t i = 0; i < EventHandlerClassCount; ++i) {
  252. EventHandlerClass handlerClass = static_cast<EventHandlerClass>(i);
  253. const EventTargetSet* targets = &m_targets[handlerClass];
  254. for (const auto& eventTarget : *targets) {
  255. if (Node* node = eventTarget.key->toNode()) {
  256. // See the comment for |documentDetached| if either of these assertions fails.
  257. ASSERT(node->document().frameHost());
  258. ASSERT(node->document().frameHost() == m_frameHost);
  259. } else if (LocalDOMWindow* window = eventTarget.key->toLocalDOMWindow()) {
  260. // If any of these assertions fail, LocalDOMWindow failed to unregister its handlers
  261. // properly.
  262. ASSERT(window->frame());
  263. ASSERT(window->frame()->host());
  264. ASSERT(window->frame()->host() == m_frameHost);
  265. }
  266. }
  267. }
  268. #endif // ENABLE(ASSERT)
  269. }
  270. } // namespace blink