Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: third_party/WebKit/Source/core/input/PointerEventManager.cpp

Issue 1670073004: Send node transition events for touch events (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add the tests Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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 "core/input/PointerEventManager.h"
6
7 #include "core/dom/shadow/FlatTreeTraversal.h"
8 #include "core/events/MouseEvent.h"
9 #include "core/input/EventHandler.h"
10
11 namespace blink {
12
13 namespace {
14
15 const AtomicString& pointerEventNameForTouchPointState(PlatformTouchPoint::State state)
16 {
17 switch (state) {
18 case PlatformTouchPoint::TouchReleased:
19 return EventTypeNames::pointerup;
20 case PlatformTouchPoint::TouchCancelled:
21 return EventTypeNames::pointercancel;
22 case PlatformTouchPoint::TouchPressed:
23 return EventTypeNames::pointerdown;
24 case PlatformTouchPoint::TouchMoved:
25 return EventTypeNames::pointermove;
26 case PlatformTouchPoint::TouchStationary:
27 // Fall through to default
28 default:
29 ASSERT_NOT_REACHED();
30 return emptyAtom;
31 }
32 }
33
34 const AtomicString& pointerEventNameForMouseEventName(const AtomicString& mouseE ventName)
35 {
36 #define RETURN_CORRESPONDING_PE_NAME(eventSuffix) \
37 if (mouseEventName == EventTypeNames::mouse##eventSuffix) {\
38 return EventTypeNames::pointer##eventSuffix;\
39 }
40
41 RETURN_CORRESPONDING_PE_NAME(down);
42 RETURN_CORRESPONDING_PE_NAME(enter);
43 RETURN_CORRESPONDING_PE_NAME(leave);
44 RETURN_CORRESPONDING_PE_NAME(move);
45 RETURN_CORRESPONDING_PE_NAME(out);
46 RETURN_CORRESPONDING_PE_NAME(over);
47 RETURN_CORRESPONDING_PE_NAME(up);
48
49 #undef RETURN_CORRESPONDING_PE_NAME
50
51 ASSERT_NOT_REACHED();
52 return emptyAtom;
53 }
54
55 bool isInDocument(PassRefPtrWillBeRawPtr<EventTarget> n)
56 {
57 return n && n->toNode() && n->toNode()->inDocument();
58 }
59
60 WebInputEventResult dispatchPointerEvent(
61 PassRefPtrWillBeRawPtr<EventTarget> target,
62 PassRefPtrWillBeRawPtr<PointerEvent> pointerevent,
63 bool checkForListener = false)
64 {
65 if (!RuntimeEnabledFeatures::pointerEventEnabled())
66 return WebInputEventResult::NotHandled;
67 if (!checkForListener || target->hasEventListeners(pointerevent->type())) {
68 bool dispatchResult = target->dispatchEvent(pointerevent);
69 return EventHandler::eventToEventResult(pointerevent, dispatchResult);
70 }
71 return WebInputEventResult::NotHandled;
72 }
73
74 WebInputEventResult dispatchMouseEvent(
75 PassRefPtrWillBeRawPtr<EventTarget> target,
76 const AtomicString& mouseEventType,
77 const PlatformMouseEvent& mouseEvent,
78 PassRefPtrWillBeRawPtr<EventTarget> relatedTarget,
79 int detail = 0,
80 bool checkForListener = false)
81 {
82 if (target->toNode()
83 && (!checkForListener || target->hasEventListeners(mouseEventType))) {
84 RefPtrWillBeRawPtr<Node> targetNode = target->toNode();
85 RefPtrWillBeRawPtr<MouseEvent> event = MouseEvent::create(mouseEventType ,
86 targetNode->document().domWindow(), mouseEvent, detail,
87 relatedTarget ? relatedTarget->toNode() : nullptr);
88 bool res = target->dispatchEvent(event);
89 return EventHandler::eventToEventResult(event, res);
90 }
91 return WebInputEventResult::NotHandled;
92 }
93
94 } // namespace
95
96 PassRefPtrWillBeRawPtr<Node> PointerEventManager::getEffectiveTargetForPointerEv ent(
97 PassRefPtrWillBeRawPtr<Node> target,
98 PassRefPtrWillBeRawPtr<PointerEvent> pointerEvent)
99 {
100 // TODO(nzolghadr): Add APIs to set the capturing nodes and return the corre ct node here
101 (void) pointerEvent;
102 return target;
103 }
104
105 // Sends node transition events (pointer|mouse)(out|leave|over|enter) to the cor responding targets
106 void PointerEventManager::sendNodeTransitionEvents(
107 PassRefPtrWillBeRawPtr<Node> exitedNode,
108 PassRefPtrWillBeRawPtr<Node> enteredNode,
109 const PlatformMouseEvent& mouseEvent,
110 PassRefPtrWillBeRawPtr<AbstractView> view)
111 {
112 // Pointer event type does not matter as it will be overridden in the sendNo deTransitionEvents
113 sendNodeTransitionEvents(exitedNode, enteredNode,
114 m_pointerEventFactory.create(EventTypeNames::pointerout, mouseEvent, nul lptr, view),
115 mouseEvent, true);
116 }
117
118 void PointerEventManager::sendNodeTransitionEvents(
119 PassRefPtrWillBeRawPtr<EventTarget> exitedTarget,
120 PassRefPtrWillBeRawPtr<EventTarget> enteredTarget,
121 PassRefPtrWillBeRawPtr<PointerEvent> pointerEvent,
122 const PlatformMouseEvent& mouseEvent, bool sendMouseEvent)
123 {
124 if (exitedTarget == enteredTarget)
125 return;
126
127 // Dispatch pointerout/mouseout events
128 if (isInDocument(exitedTarget)) {
129 dispatchPointerEvent(exitedTarget, m_pointerEventFactory.create(
130 pointerEvent, EventTypeNames::pointerout, enteredTarget));
131 if (sendMouseEvent) {
132 dispatchMouseEvent(exitedTarget,
133 EventTypeNames::mouseout, mouseEvent, enteredTarget);
134 }
135 }
136
137 // Create lists of all exited/entered ancestors, locate the common ancestor
138 WillBeHeapVector<RefPtrWillBeMember<Node>, 32> exitedAncestors;
139 WillBeHeapVector<RefPtrWillBeMember<Node>, 32> enteredAncestors;
140 if (isInDocument(exitedTarget)) {
141 RefPtrWillBeRawPtr<Node> exitedNode = exitedTarget->toNode();
142 exitedNode->updateDistribution();
143 for (RefPtrWillBeRawPtr<Node> node = exitedNode; node; node = FlatTreeTr aversal::parent(*node))
144 exitedAncestors.append(node);
145 }
146
147 if (isInDocument(enteredTarget)) {
148 RefPtrWillBeRawPtr<Node> enteredNode = enteredTarget->toNode();
149 enteredNode->updateDistribution();
150 for (RefPtrWillBeRawPtr<Node> node = enteredNode; node; node = FlatTreeT raversal::parent(*node))
151 enteredAncestors.append(node);
152 }
153
154 // A note on mouseenter and mouseleave: These are non-bubbling events, and t hey are dispatched if there
155 // is a capturing event handler on an ancestor or a normal event handler on the element itself. This special
156 // handling is necessary to avoid O(n^2) capturing event handler checks.
157 //
158 // Note, however, that this optimization can possibly cause some unanswere d/missing/redundant mouseenter or
159 // mouseleave events in certain contrived eventhandling scenarios, e.g., whe n:
160 // - the mouseleave handler for a node sets the only capturing-mouseleave-li stener in its ancestor, or
161 // - DOM mods in any mouseenter/mouseleave handler changes the common ancest or of exited & entered nodes, etc.
162 // We think the spec specifies a "frozen" state to avoid such corner cases ( check the discussion on "candidate event
163 // listeners" at http://www.w3.org/TR/uievents), but our code below preserve s one such behavior from past only to
164 // match Firefox and IE behavior.
165 //
166 // TODO(mustaq): Confirm spec conformance, double-check with other browsers.
167
168 size_t numExitedAncestors = exitedAncestors.size();
169 size_t numEnteredAncestors = enteredAncestors.size();
170
171 size_t exitedAncestorIndex = numExitedAncestors;
172 size_t enteredAncestorIndex = numEnteredAncestors;
173 for (size_t i = 0; i < numExitedAncestors; i++) {
174 for (size_t j = 0; j < numEnteredAncestors; j++) {
175 if (exitedAncestors[i] == enteredAncestors[j]) {
176 exitedAncestorIndex = i;
177 enteredAncestorIndex = j;
178 break;
179 }
180 }
181 if (exitedAncestorIndex < exitedAncestors.size())
182 break;
183 }
184
185 bool exitedNodeHasCapturingAncestor = false;
186 for (size_t j = 0; j < exitedAncestors.size(); j++) {
187 if (exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::mouse leave)
188 || (RuntimeEnabledFeatures::pointerEventEnabled()
189 && exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::po interleave)))
190 exitedNodeHasCapturingAncestor = true;
191 }
192
193 // Dispatch pointerleave/mouseleave events, in child-to-parent order.
194 for (size_t j = 0; j < exitedAncestorIndex; j++) {
195 dispatchPointerEvent(exitedAncestors[j].get(),
196 m_pointerEventFactory.create(
197 pointerEvent, EventTypeNames::pointerleave, enteredTarget),
198 !exitedNodeHasCapturingAncestor);
199 if (sendMouseEvent) {
200 dispatchMouseEvent(exitedAncestors[j].get(),
201 EventTypeNames::mouseleave, mouseEvent, enteredTarget,
202 0, !exitedNodeHasCapturingAncestor);
203 }
204 }
205
206 // Dispatch pointerover/mouseover.
207 if (isInDocument(enteredTarget)) {
208 dispatchPointerEvent(enteredTarget, m_pointerEventFactory.create(
209 pointerEvent, EventTypeNames::pointerover, exitedTarget));
210 if (sendMouseEvent) {
211 dispatchMouseEvent(enteredTarget,
212 EventTypeNames::mouseover, mouseEvent, exitedTarget);
213 }
214 }
215
216 // Defer locating capturing pointeenter/mouseenter listener until /after/ di spatching the leave events because
217 // the leave handlers might set a capturing enter handler.
218 bool enteredNodeHasCapturingAncestor = false;
219 for (size_t i = 0; i < enteredAncestors.size(); i++) {
220 if (enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::mous eenter)
221 || (RuntimeEnabledFeatures::pointerEventEnabled()
222 && enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::p ointerenter)))
223 enteredNodeHasCapturingAncestor = true;
224 }
225
226 // Dispatch pointerenter/mouseenter events, in parent-to-child order.
227 for (size_t i = enteredAncestorIndex; i > 0; i--) {
228 dispatchPointerEvent(enteredAncestors[i-1].get(),
229 m_pointerEventFactory.create(
230 pointerEvent, EventTypeNames::pointerenter, exitedTarget),
231 !enteredNodeHasCapturingAncestor);
232 if (sendMouseEvent) {
233 dispatchMouseEvent(enteredAncestors[i-1].get(),
234 EventTypeNames::mouseenter, mouseEvent, exitedTarget,
235 0, !enteredNodeHasCapturingAncestor);
236 }
237 }
238 }
239
240 void PointerEventManager::setNodeUnderPointer(
241 PassRefPtrWillBeRawPtr<PointerEvent> pointerevent,
242 PassRefPtrWillBeRawPtr<EventTarget> target)
243 {
244 if (m_nodeUnderPointer.contains(pointerevent->pointerId())) {
245 sendNodeTransitionEvents(m_nodeUnderPointer.get(
246 pointerevent->pointerId()), target, pointerevent);
247 if (!target)
248 m_nodeUnderPointer.remove(pointerevent->pointerId());
249 else
250 m_nodeUnderPointer.set(pointerevent->pointerId(), target);
251 } else if (target) {
252 sendNodeTransitionEvents(nullptr, target, pointerevent);
253 m_nodeUnderPointer.add(pointerevent->pointerId(), target);
254 }
255 }
256
257 void PointerEventManager::sendTouchCancelPointerEvent(PassRefPtrWillBeRawPtr<Eve ntTarget> target,
258 const PlatformTouchPoint& point)
259 {
260 RefPtrWillBeRawPtr<PointerEvent> pointerEvent =
261 m_pointerEventFactory.createPointerCancel(point);
262
263 // TODO(nzolghadr): crbug.com/579553 dealing with implicit touch capturing v s pointer event capturing
264 target->dispatchEvent(pointerEvent.get());
265
266 m_pointerEventFactory.remove(pointerEvent);
267 setNodeUnderPointer(pointerEvent, nullptr);
268 }
269
270 WebInputEventResult PointerEventManager::sendTouchPointerEvent(
271 PassRefPtrWillBeRawPtr<EventTarget> target,
272 const PlatformTouchPoint& touchPoint, PlatformEvent::Modifiers modifiers,
273 const double width, const double height,
274 const double clientX, const double clientY)
275 {
276 RefPtrWillBeRawPtr<PointerEvent> pointerEvent =
277 m_pointerEventFactory.create(
278 pointerEventNameForTouchPointState(touchPoint.state()),
279 touchPoint, modifiers, width, height, clientX, clientY);
280
281 setNodeUnderPointer(pointerEvent, target);
282
283 // TODO(nzolghadr): crbug.com/579553 dealing with implicit touch capturing v s pointer event capturing
284 WebInputEventResult result = dispatchPointerEvent(target, pointerEvent.get() );
285
286 if (touchPoint.state() == PlatformTouchPoint::TouchReleased
287 || touchPoint.state() == PlatformTouchPoint::TouchCancelled) {
288 m_pointerEventFactory.remove(pointerEvent);
289 setNodeUnderPointer(pointerEvent, nullptr);
290 }
291
292 return result;
293 }
294
295 WebInputEventResult PointerEventManager::sendMousePointerEvent(
296 PassRefPtrWillBeRawPtr<Node> target, const AtomicString& mouseEventType,
297 int clickCount, const PlatformMouseEvent& mouseEvent,
298 PassRefPtrWillBeRawPtr<Node> relatedTarget,
299 PassRefPtrWillBeRawPtr<AbstractView> view)
300 {
301 AtomicString pointerEventType =
302 pointerEventNameForMouseEventName(mouseEventType);
303 unsigned short pointerButtonsPressed =
304 MouseEvent::platformModifiersToButtons(mouseEvent.modifiers());
305
306 // Make sure chorded buttons fire pointermove instead of pointerup/pointerdo wn.
307 if ((pointerEventType == EventTypeNames::pointerdown && (pointerButtonsPress ed & ~MouseEvent::buttonToButtons(mouseEvent.button())) != 0)
308 || (pointerEventType == EventTypeNames::pointerup && pointerButtonsPress ed != 0))
309 pointerEventType = EventTypeNames::pointermove;
310
311 RefPtrWillBeRawPtr<PointerEvent> pointerEvent =
312 m_pointerEventFactory.create(pointerEventType, mouseEvent,
313 relatedTarget, view);
314
315 RefPtrWillBeRawPtr<Node> effectiveTarget =
316 getEffectiveTargetForPointerEvent(target, pointerEvent);
317
318 WebInputEventResult result =
319 dispatchPointerEvent(effectiveTarget, pointerEvent);
320
321 if (result != WebInputEventResult::NotHandled
322 && pointerEventType == EventTypeNames::pointerdown)
323 m_preventMouseEventForPointerTypeMouse = true;
324
325 if (!m_preventMouseEventForPointerTypeMouse) {
326 result = EventHandler::mergeEventResult(result,
327 dispatchMouseEvent(effectiveTarget, mouseEventType, mouseEvent,
328 nullptr, clickCount));
329 }
330
331 return result;
332 }
333
334 PointerEventManager::PointerEventManager()
335 {
336 clear();
337 }
338
339 PointerEventManager::~PointerEventManager()
340 {
341 }
342 void PointerEventManager::clearPreventMouseEventForPointerTypeMouse()
343 {
344 m_preventMouseEventForPointerTypeMouse = false;
345 }
346 void PointerEventManager::clear()
347 {
348 m_preventMouseEventForPointerTypeMouse = false;
349 m_pointerEventFactory.clear();
350 m_nodeUnderPointer.clear();
351 }
352
353 DEFINE_TRACE(PointerEventManager)
354 {
355 visitor->trace(m_nodeUnderPointer);
356 }
357
358
359 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698