| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/input/PointerEventManager.h" | 5 #include "core/input/PointerEventManager.h" |
| 6 | 6 |
| 7 #include "core/dom/ElementTraversal.h" | 7 #include "core/dom/ElementTraversal.h" |
| 8 #include "core/dom/shadow/FlatTreeTraversal.h" | 8 #include "core/dom/shadow/FlatTreeTraversal.h" |
| 9 #include "core/events/MouseEvent.h" | 9 #include "core/events/MouseEvent.h" |
| 10 #include "core/html/HTMLCanvasElement.h" | 10 #include "core/html/HTMLCanvasElement.h" |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 HTMLCanvasElement* canvas = Traversal<HTMLCanvasElement>::firstAncestorOrSel
f(*element); | 72 HTMLCanvasElement* canvas = Traversal<HTMLCanvasElement>::firstAncestorOrSel
f(*element); |
| 73 // In this case, the event target is canvas and mouse rerouting doesn't happ
en. | 73 // In this case, the event target is canvas and mouse rerouting doesn't happ
en. |
| 74 if (canvas == element) | 74 if (canvas == element) |
| 75 return mouseEvent; | 75 return mouseEvent; |
| 76 String region = canvas->getIdFromControl(element); | 76 String region = canvas->getIdFromControl(element); |
| 77 PlatformMouseEvent newMouseEvent = mouseEvent; | 77 PlatformMouseEvent newMouseEvent = mouseEvent; |
| 78 newMouseEvent.setRegion(region); | 78 newMouseEvent.setRegion(region); |
| 79 return newMouseEvent; | 79 return newMouseEvent; |
| 80 } | 80 } |
| 81 | 81 |
| 82 void buildAncestorChainsAndFindCommonAncestors( |
| 83 EventTarget* exitedTarget, EventTarget* enteredTarget, |
| 84 HeapVector<Member<Node>, 20>* exitedAncestorsOut, |
| 85 HeapVector<Member<Node>, 20>* enteredAncestorsOut, |
| 86 size_t* exitedAncestorsCommonParentIndexOut, |
| 87 size_t* enteredAncestorsCommonParentIndexOut) |
| 88 { |
| 89 DCHECK(exitedAncestorsOut); |
| 90 DCHECK(enteredAncestorsOut); |
| 91 DCHECK(exitedAncestorsCommonParentIndexOut); |
| 92 DCHECK(enteredAncestorsCommonParentIndexOut); |
| 93 |
| 94 // Index 0 element in the ancestors arrays will be the corresponding |
| 95 // target. So the root of their document will be their last element. |
| 96 |
| 97 if (isInDocument(exitedTarget)) { |
| 98 Node* exitedNode = exitedTarget->toNode(); |
| 99 DCHECK(exitedNode); |
| 100 exitedNode->updateDistribution(); |
| 101 for (Node* node = exitedNode; node; node = FlatTreeTraversal::parent(*no
de)) |
| 102 exitedAncestorsOut->append(node); |
| 103 } |
| 104 |
| 105 if (isInDocument(enteredTarget)) { |
| 106 Node* enteredNode = enteredTarget->toNode(); |
| 107 DCHECK(enteredNode); |
| 108 enteredNode->updateDistribution(); |
| 109 for (Node* node = enteredNode; node; node = FlatTreeTraversal::parent(*n
ode)) |
| 110 enteredAncestorsOut->append(node); |
| 111 } |
| 112 |
| 113 *exitedAncestorsCommonParentIndexOut = exitedAncestorsOut->size(); |
| 114 *enteredAncestorsCommonParentIndexOut = enteredAncestorsOut->size(); |
| 115 while (*exitedAncestorsCommonParentIndexOut > 0 |
| 116 && *enteredAncestorsCommonParentIndexOut > 0) { |
| 117 if ((*exitedAncestorsOut)[(*exitedAncestorsCommonParentIndexOut)-1] |
| 118 != (*enteredAncestorsOut)[(*enteredAncestorsCommonParentIndexOut)-1]
) |
| 119 break; |
| 120 (*exitedAncestorsCommonParentIndexOut)--; |
| 121 (*enteredAncestorsCommonParentIndexOut)--; |
| 122 } |
| 123 } |
| 124 |
| 82 } // namespace | 125 } // namespace |
| 83 | 126 |
| 84 WebInputEventResult PointerEventManager::dispatchPointerEvent( | 127 WebInputEventResult PointerEventManager::dispatchPointerEvent( |
| 85 EventTarget* target, | 128 EventTarget* target, |
| 86 PointerEvent* pointerEvent, | 129 PointerEvent* pointerEvent, |
| 87 bool checkForListener) | 130 bool checkForListener) |
| 88 { | 131 { |
| 89 if (!target) | 132 if (!target) |
| 90 return WebInputEventResult::NotHandled; | 133 return WebInputEventResult::NotHandled; |
| 91 | 134 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 pointerEvent, EventTypeNames::pointerout, enteredTarget)); | 216 pointerEvent, EventTypeNames::pointerout, enteredTarget)); |
| 174 } else { | 217 } else { |
| 175 dispatchMouseEvent(exitedTarget, | 218 dispatchMouseEvent(exitedTarget, |
| 176 EventTypeNames::mouseout, | 219 EventTypeNames::mouseout, |
| 177 mouseEventWithRegion(exitedTarget->toNode(), mouseEvent), | 220 mouseEventWithRegion(exitedTarget->toNode(), mouseEvent), |
| 178 enteredTarget); | 221 enteredTarget); |
| 179 } | 222 } |
| 180 } | 223 } |
| 181 | 224 |
| 182 // Create lists of all exited/entered ancestors, locate the common ancestor | 225 // Create lists of all exited/entered ancestors, locate the common ancestor |
| 183 HeapVector<Member<Node>, 32> exitedAncestors; | 226 // Based on httparchive, in more than 97% cases the depth of DOM is less |
| 184 HeapVector<Member<Node>, 32> enteredAncestors; | 227 // than 20. |
| 185 if (isInDocument(exitedTarget)) { | 228 HeapVector<Member<Node>, 20> exitedAncestors; |
| 186 Node* exitedNode = exitedTarget->toNode(); | 229 HeapVector<Member<Node>, 20> enteredAncestors; |
| 187 exitedNode->updateDistribution(); | 230 size_t exitedAncestorsCommonParentIndex = 0; |
| 188 for (Node* node = exitedNode; node; node = FlatTreeTraversal::parent(*no
de)) | 231 size_t enteredAncestorsCommonParentIndex = 0; |
| 189 exitedAncestors.append(node); | |
| 190 } | |
| 191 | |
| 192 if (isInDocument(enteredTarget)) { | |
| 193 Node* enteredNode = enteredTarget->toNode(); | |
| 194 enteredNode->updateDistribution(); | |
| 195 for (Node* node = enteredNode; node; node = FlatTreeTraversal::parent(*n
ode)) | |
| 196 enteredAncestors.append(node); | |
| 197 } | |
| 198 | 232 |
| 199 // A note on mouseenter and mouseleave: These are non-bubbling events, and t
hey are dispatched if there | 233 // A note on mouseenter and mouseleave: These are non-bubbling events, and t
hey are dispatched if there |
| 200 // is a capturing event handler on an ancestor or a normal event handler on
the element itself. This special | 234 // is a capturing event handler on an ancestor or a normal event handler on
the element itself. This special |
| 201 // handling is necessary to avoid O(n^2) capturing event handler checks. | 235 // handling is necessary to avoid O(n^2) capturing event handler checks. |
| 202 // | 236 // |
| 203 // Note, however, that this optimization can possibly cause some unanswere
d/missing/redundant mouseenter or | 237 // Note, however, that this optimization can possibly cause some unanswere
d/missing/redundant mouseenter or |
| 204 // mouseleave events in certain contrived eventhandling scenarios, e.g., whe
n: | 238 // mouseleave events in certain contrived eventhandling scenarios, e.g., whe
n: |
| 205 // - the mouseleave handler for a node sets the only capturing-mouseleave-li
stener in its ancestor, or | 239 // - the mouseleave handler for a node sets the only capturing-mouseleave-li
stener in its ancestor, or |
| 206 // - DOM mods in any mouseenter/mouseleave handler changes the common ancest
or of exited & entered nodes, etc. | 240 // - DOM mods in any mouseenter/mouseleave handler changes the common ancest
or of exited & entered nodes, etc. |
| 207 // We think the spec specifies a "frozen" state to avoid such corner cases (
check the discussion on "candidate event | 241 // We think the spec specifies a "frozen" state to avoid such corner cases (
check the discussion on "candidate event |
| 208 // listeners" at http://www.w3.org/TR/uievents), but our code below preserve
s one such behavior from past only to | 242 // listeners" at http://www.w3.org/TR/uievents), but our code below preserve
s one such behavior from past only to |
| 209 // match Firefox and IE behavior. | 243 // match Firefox and IE behavior. |
| 210 // | 244 // |
| 211 // TODO(mustaq): Confirm spec conformance, double-check with other browsers. | 245 // TODO(mustaq): Confirm spec conformance, double-check with other browsers. |
| 212 | 246 |
| 213 size_t numExitedAncestors = exitedAncestors.size(); | 247 buildAncestorChainsAndFindCommonAncestors( |
| 214 size_t numEnteredAncestors = enteredAncestors.size(); | 248 exitedTarget, enteredTarget, |
| 215 | 249 &exitedAncestors, &enteredAncestors, |
| 216 size_t exitedAncestorIndex = numExitedAncestors; | 250 &exitedAncestorsCommonParentIndex, &enteredAncestorsCommonParentIndex); |
| 217 size_t enteredAncestorIndex = numEnteredAncestors; | |
| 218 for (size_t i = 0; i < numExitedAncestors; i++) { | |
| 219 for (size_t j = 0; j < numEnteredAncestors; j++) { | |
| 220 if (exitedAncestors[i] == enteredAncestors[j]) { | |
| 221 exitedAncestorIndex = i; | |
| 222 enteredAncestorIndex = j; | |
| 223 break; | |
| 224 } | |
| 225 } | |
| 226 if (exitedAncestorIndex < exitedAncestors.size()) | |
| 227 break; | |
| 228 } | |
| 229 | 251 |
| 230 bool exitedNodeHasCapturingAncestor = false; | 252 bool exitedNodeHasCapturingAncestor = false; |
| 231 for (size_t j = 0; j < exitedAncestors.size(); j++) { | 253 for (size_t j = 0; j < exitedAncestors.size(); j++) { |
| 232 if (exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::mouse
leave) | 254 if (exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::mouse
leave) |
| 233 || (RuntimeEnabledFeatures::pointerEventEnabled() | 255 || (RuntimeEnabledFeatures::pointerEventEnabled() |
| 234 && exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::po
interleave))) | 256 && exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::po
interleave))) |
| 235 exitedNodeHasCapturingAncestor = true; | 257 exitedNodeHasCapturingAncestor = true; |
| 236 } | 258 } |
| 237 | 259 |
| 238 // Dispatch pointerleave/mouseleave events, in child-to-parent order. | 260 // Dispatch pointerleave/mouseleave events, in child-to-parent order. |
| 239 for (size_t j = 0; j < exitedAncestorIndex; j++) { | 261 for (size_t j = 0; j < exitedAncestorsCommonParentIndex; j++) { |
| 240 if (!sendMouseEvent) { | 262 if (!sendMouseEvent) { |
| 241 dispatchPointerEvent(exitedAncestors[j].get(), | 263 dispatchPointerEvent(exitedAncestors[j].get(), |
| 242 m_pointerEventFactory.createPointerTransitionEvent( | 264 m_pointerEventFactory.createPointerTransitionEvent( |
| 243 pointerEvent, EventTypeNames::pointerleave, enteredTarget), | 265 pointerEvent, EventTypeNames::pointerleave, enteredTarget), |
| 244 !exitedNodeHasCapturingAncestor); | 266 !exitedNodeHasCapturingAncestor); |
| 245 } else { | 267 } else { |
| 246 dispatchMouseEvent(exitedAncestors[j].get(), | 268 dispatchMouseEvent(exitedAncestors[j].get(), |
| 247 EventTypeNames::mouseleave, | 269 EventTypeNames::mouseleave, |
| 248 mouseEventWithRegion(exitedTarget->toNode(), mouseEvent), | 270 mouseEventWithRegion(exitedTarget->toNode(), mouseEvent), |
| 249 enteredTarget, 0, !exitedNodeHasCapturingAncestor); | 271 enteredTarget, 0, !exitedNodeHasCapturingAncestor); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 265 // the leave handlers might set a capturing enter handler. | 287 // the leave handlers might set a capturing enter handler. |
| 266 bool enteredNodeHasCapturingAncestor = false; | 288 bool enteredNodeHasCapturingAncestor = false; |
| 267 for (size_t i = 0; i < enteredAncestors.size(); i++) { | 289 for (size_t i = 0; i < enteredAncestors.size(); i++) { |
| 268 if (enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::mous
eenter) | 290 if (enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::mous
eenter) |
| 269 || (RuntimeEnabledFeatures::pointerEventEnabled() | 291 || (RuntimeEnabledFeatures::pointerEventEnabled() |
| 270 && enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::p
ointerenter))) | 292 && enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::p
ointerenter))) |
| 271 enteredNodeHasCapturingAncestor = true; | 293 enteredNodeHasCapturingAncestor = true; |
| 272 } | 294 } |
| 273 | 295 |
| 274 // Dispatch pointerenter/mouseenter events, in parent-to-child order. | 296 // Dispatch pointerenter/mouseenter events, in parent-to-child order. |
| 275 for (size_t i = enteredAncestorIndex; i > 0; i--) { | 297 for (size_t i = enteredAncestorsCommonParentIndex; i > 0; i--) { |
| 276 if (!sendMouseEvent) { | 298 if (!sendMouseEvent) { |
| 277 dispatchPointerEvent(enteredAncestors[i-1].get(), | 299 dispatchPointerEvent(enteredAncestors[i-1].get(), |
| 278 m_pointerEventFactory.createPointerTransitionEvent( | 300 m_pointerEventFactory.createPointerTransitionEvent( |
| 279 pointerEvent, EventTypeNames::pointerenter, exitedTarget), | 301 pointerEvent, EventTypeNames::pointerenter, exitedTarget), |
| 280 !enteredNodeHasCapturingAncestor); | 302 !enteredNodeHasCapturingAncestor); |
| 281 } else { | 303 } else { |
| 282 dispatchMouseEvent(enteredAncestors[i-1].get(), | 304 dispatchMouseEvent(enteredAncestors[i-1].get(), |
| 283 EventTypeNames::mouseenter, mouseEvent, exitedTarget, | 305 EventTypeNames::mouseenter, mouseEvent, exitedTarget, |
| 284 0, !enteredNodeHasCapturingAncestor); | 306 0, !enteredNodeHasCapturingAncestor); |
| 285 } | 307 } |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 | 654 |
| 633 DEFINE_TRACE(PointerEventManager) | 655 DEFINE_TRACE(PointerEventManager) |
| 634 { | 656 { |
| 635 visitor->trace(m_nodeUnderPointer); | 657 visitor->trace(m_nodeUnderPointer); |
| 636 visitor->trace(m_pointerCaptureTarget); | 658 visitor->trace(m_pointerCaptureTarget); |
| 637 visitor->trace(m_pendingPointerCaptureTarget); | 659 visitor->trace(m_pendingPointerCaptureTarget); |
| 638 } | 660 } |
| 639 | 661 |
| 640 | 662 |
| 641 } // namespace blink | 663 } // namespace blink |
| OLD | NEW |