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/frame/LocalDOMWindow.h"
9 #include "core/frame/LocalFrame.h"
10 #include "core/html/HTMLFrameOwnerElement.h"
11 #include "core/page/ChromeClient.h"
12 #include "core/page/Page.h"
13 #include "core/page/scrolling/ScrollingCoordinator.h"
19 inline bool isTouchEventType(const AtomicString
& eventType
)
21 return eventType
== EventTypeNames::touchstart
22 || eventType
== EventTypeNames::touchmove
23 || eventType
== EventTypeNames::touchend
24 || eventType
== EventTypeNames::touchcancel
;
27 inline bool isPointerEventType(const AtomicString
& eventType
)
29 return eventType
== EventTypeNames::gotpointercapture
30 || eventType
== EventTypeNames::lostpointercapture
31 || eventType
== EventTypeNames::pointercancel
32 || eventType
== EventTypeNames::pointerdown
33 || eventType
== EventTypeNames::pointerenter
34 || eventType
== EventTypeNames::pointerleave
35 || eventType
== EventTypeNames::pointermove
36 || eventType
== EventTypeNames::pointerout
37 || eventType
== EventTypeNames::pointerover
38 || eventType
== EventTypeNames::pointerup
;
43 EventHandlerRegistry::EventHandlerRegistry(FrameHost
& frameHost
)
44 : m_frameHost(&frameHost
)
48 EventHandlerRegistry::~EventHandlerRegistry()
53 bool EventHandlerRegistry::eventTypeToClass(const AtomicString
& eventType
, EventHandlerClass
* result
)
55 if (eventType
== EventTypeNames::scroll
) {
56 *result
= ScrollEvent
;
57 } else if (eventType
== EventTypeNames::wheel
|| eventType
== EventTypeNames::mousewheel
) {
59 } else if (isTouchEventType(eventType
)) {
61 } else if (isPointerEventType(eventType
)) {
62 // The EventHandlerClass is still TouchEvent below since we are firing PointerEvents only from
63 // EventHandler::handleTouchEvent for now. See crbug.com/476565.
66 } else if (eventType
== EventTypeNames::load
|| eventType
== EventTypeNames::mousemove
|| eventType
== EventTypeNames::touchstart
) {
67 *result
= EventsForTesting
;
75 const EventTargetSet
* EventHandlerRegistry::eventHandlerTargets(EventHandlerClass handlerClass
) const
78 return &m_targets
[handlerClass
];
81 bool EventHandlerRegistry::hasEventHandlers(EventHandlerClass handlerClass
) const
84 return m_targets
[handlerClass
].size();
87 bool EventHandlerRegistry::updateEventHandlerTargets(ChangeOperation op
, EventHandlerClass handlerClass
, EventTarget
* target
)
89 EventTargetSet
* targets
= &m_targets
[handlerClass
];
91 if (!targets
->add(target
).isNewEntry
) {
92 // Just incremented refcount, no real change.
96 ASSERT(op
== Remove
|| op
== RemoveAll
);
97 ASSERT(op
== RemoveAll
|| targets
->contains(target
));
99 if (op
== RemoveAll
) {
100 if (!targets
->contains(target
))
102 targets
->removeAll(target
);
104 if (!targets
->remove(target
)) {
105 // Just decremented refcount, no real update.
113 void EventHandlerRegistry::updateEventHandlerInternal(ChangeOperation op
, EventHandlerClass handlerClass
, EventTarget
* target
)
115 bool hadHandlers
= m_targets
[handlerClass
].size();
116 bool targetSetChanged
= updateEventHandlerTargets(op
, handlerClass
, target
);
117 bool hasHandlers
= m_targets
[handlerClass
].size();
119 if (hadHandlers
!= hasHandlers
)
120 notifyHasHandlersChanged(handlerClass
, hasHandlers
);
122 if (targetSetChanged
)
123 notifyDidAddOrRemoveEventHandlerTarget(handlerClass
);
126 void EventHandlerRegistry::updateEventHandlerOfType(ChangeOperation op
, const AtomicString
& eventType
, EventTarget
* target
)
128 EventHandlerClass handlerClass
;
129 if (!eventTypeToClass(eventType
, &handlerClass
))
131 updateEventHandlerInternal(op
, handlerClass
, target
);
134 void EventHandlerRegistry::didAddEventHandler(EventTarget
& target
, const AtomicString
& eventType
)
136 updateEventHandlerOfType(Add
, eventType
, &target
);
139 void EventHandlerRegistry::didRemoveEventHandler(EventTarget
& target
, const AtomicString
& eventType
)
141 updateEventHandlerOfType(Remove
, eventType
, &target
);
144 void EventHandlerRegistry::didAddEventHandler(EventTarget
& target
, EventHandlerClass handlerClass
)
146 updateEventHandlerInternal(Add
, handlerClass
, &target
);
149 void EventHandlerRegistry::didRemoveEventHandler(EventTarget
& target
, EventHandlerClass handlerClass
)
151 updateEventHandlerInternal(Remove
, handlerClass
, &target
);
154 void EventHandlerRegistry::didMoveIntoFrameHost(EventTarget
& target
)
156 if (!target
.hasEventListeners())
159 Vector
<AtomicString
> eventTypes
= target
.eventTypes();
160 for (size_t i
= 0; i
< eventTypes
.size(); ++i
) {
161 EventHandlerClass handlerClass
;
162 if (!eventTypeToClass(eventTypes
[i
], &handlerClass
))
164 EventListenerVector
* listeners
= target
.getEventListeners(eventTypes
[i
]);
167 for (unsigned count
= listeners
->size(); count
> 0; --count
)
168 didAddEventHandler(target
, handlerClass
);
172 void EventHandlerRegistry::didMoveOutOfFrameHost(EventTarget
& target
)
174 didRemoveAllEventHandlers(target
);
177 void EventHandlerRegistry::didMoveBetweenFrameHosts(EventTarget
& target
, FrameHost
* oldFrameHost
, FrameHost
* newFrameHost
)
179 ASSERT(newFrameHost
!= oldFrameHost
);
180 for (size_t i
= 0; i
< EventHandlerClassCount
; ++i
) {
181 EventHandlerClass handlerClass
= static_cast<EventHandlerClass
>(i
);
182 const EventTargetSet
* targets
= &oldFrameHost
->eventHandlerRegistry().m_targets
[handlerClass
];
183 for (unsigned count
= targets
->count(&target
); count
> 0; --count
)
184 newFrameHost
->eventHandlerRegistry().didAddEventHandler(target
, handlerClass
);
185 oldFrameHost
->eventHandlerRegistry().didRemoveAllEventHandlers(target
);
189 void EventHandlerRegistry::didRemoveAllEventHandlers(EventTarget
& target
)
191 for (size_t i
= 0; i
< EventHandlerClassCount
; ++i
) {
192 EventHandlerClass handlerClass
= static_cast<EventHandlerClass
>(i
);
193 updateEventHandlerInternal(RemoveAll
, handlerClass
, &target
);
197 void EventHandlerRegistry::notifyHasHandlersChanged(EventHandlerClass handlerClass
, bool hasActiveHandlers
)
199 ScrollingCoordinator
* scrollingCoordinator
= m_frameHost
->page().scrollingCoordinator();
201 switch (handlerClass
) {
203 if (scrollingCoordinator
)
204 scrollingCoordinator
->updateHaveScrollEventHandlers();
207 if (scrollingCoordinator
)
208 scrollingCoordinator
->updateHaveWheelEventHandlers();
211 m_frameHost
->chromeClient().needTouchEvents(hasActiveHandlers
);
214 case EventsForTesting
:
218 ASSERT_NOT_REACHED();
223 void EventHandlerRegistry::notifyDidAddOrRemoveEventHandlerTarget(EventHandlerClass handlerClass
)
225 ScrollingCoordinator
* scrollingCoordinator
= m_frameHost
->page().scrollingCoordinator();
226 if (scrollingCoordinator
&& handlerClass
== TouchEvent
)
227 scrollingCoordinator
->touchEventTargetRectsDidChange();
230 DEFINE_TRACE(EventHandlerRegistry
)
232 visitor
->trace(m_frameHost
);
233 visitor
->template registerWeakMembers
<EventHandlerRegistry
, &EventHandlerRegistry::clearWeakMembers
>(this);
236 void EventHandlerRegistry::clearWeakMembers(Visitor
* visitor
)
238 Vector
<EventTarget
*> deadTargets
;
239 for (size_t i
= 0; i
< EventHandlerClassCount
; ++i
) {
240 EventHandlerClass handlerClass
= static_cast<EventHandlerClass
>(i
);
241 const EventTargetSet
* targets
= &m_targets
[handlerClass
];
242 for (const auto& eventTarget
: *targets
) {
243 Node
* node
= eventTarget
.key
->toNode();
244 LocalDOMWindow
* window
= eventTarget
.key
->toDOMWindow();
245 if (node
&& !Heap::isHeapObjectAlive(node
)) {
246 deadTargets
.append(node
);
247 } else if (window
&& !Heap::isHeapObjectAlive(window
)) {
248 deadTargets
.append(window
);
252 for (size_t i
= 0; i
< deadTargets
.size(); ++i
)
253 didRemoveAllEventHandlers(*deadTargets
[i
]);
256 void EventHandlerRegistry::documentDetached(Document
& document
)
258 // Remove all event targets under the detached document.
259 for (size_t handlerClassIndex
= 0; handlerClassIndex
< EventHandlerClassCount
; ++handlerClassIndex
) {
260 EventHandlerClass handlerClass
= static_cast<EventHandlerClass
>(handlerClassIndex
);
261 Vector
<EventTarget
*> targetsToRemove
;
262 const EventTargetSet
* targets
= &m_targets
[handlerClass
];
263 for (const auto& eventTarget
: *targets
) {
264 if (Node
* node
= eventTarget
.key
->toNode()) {
265 for (Document
* doc
= &node
->document(); doc
; doc
= doc
->ownerElement() ? &doc
->ownerElement()->document() : 0) {
266 if (doc
== &document
) {
267 targetsToRemove
.append(eventTarget
.key
);
271 } else if (eventTarget
.key
->toDOMWindow()) {
272 // DOMWindows may outlive their documents, so we shouldn't remove their handlers
275 ASSERT_NOT_REACHED();
278 for (size_t i
= 0; i
< targetsToRemove
.size(); ++i
)
279 updateEventHandlerInternal(RemoveAll
, handlerClass
, targetsToRemove
[i
]);
283 void EventHandlerRegistry::checkConsistency() const
286 for (size_t i
= 0; i
< EventHandlerClassCount
; ++i
) {
287 EventHandlerClass handlerClass
= static_cast<EventHandlerClass
>(i
);
288 const EventTargetSet
* targets
= &m_targets
[handlerClass
];
289 for (const auto& eventTarget
: *targets
) {
290 if (Node
* node
= eventTarget
.key
->toNode()) {
291 // See the comment for |documentDetached| if either of these assertions fails.
292 ASSERT(node
->document().frameHost());
293 ASSERT(node
->document().frameHost() == m_frameHost
);
294 } else if (LocalDOMWindow
* window
= eventTarget
.key
->toDOMWindow()) {
295 // If any of these assertions fail, LocalDOMWindow failed to unregister its handlers
297 ASSERT(window
->frame());
298 ASSERT(window
->frame()->host());
299 ASSERT(window
->frame()->host() == m_frameHost
);
303 #endif // ENABLE(ASSERT)