Chromium Code Reviews| 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, | |
|
bokan
2016/04/21 21:38:29
Seems like these can't be null? If that's true, ma
Navid Zolghadr
2016/04/21 23:40:14
No. They can be null. The isInDocument checks for
bokan
2016/04/22 00:52:54
Got it, ok, fine as they are (if possible though,
Navid Zolghadr
2016/04/22 17:04:12
This turned out to be harder than I thought. Marki
bokan
2016/04/22 17:30:52
Nah, if it's more trouble lgtm as-is. Our code is
| |
| 84 HeapVector<Member<Node>, 20> &exitedAncestors, | |
| 85 HeapVector<Member<Node>, 20> &enteredAncestors, | |
| 86 size_t& exitedAncestorsCommonParentIndex, | |
| 87 size_t& enteredAncestorsCommonParentIndex) | |
|
bokan
2016/04/21 21:38:28
Output parameters should be passed by pointer.
Navid Zolghadr
2016/04/21 23:40:14
You mean like size_t* and HeapVector<Member<Node>
bokan
2016/04/22 00:52:54
Yup, see the bit about output params here: https:/
Navid Zolghadr
2016/04/22 17:04:12
Done.
| |
| 88 { | |
| 89 // Index 0 element in the ancestors arrays will be the corresponding | |
| 90 // target. So the root of their document will be their last element. | |
| 91 | |
|
bokan
2016/04/21 21:38:29
I see you check if exitedTarget == enteredTarget b
Navid Zolghadr
2016/04/21 23:40:14
I don't think that is needed. This function doesn'
bokan
2016/04/22 00:52:54
Whoops, yah, you're right. That's fine.
| |
| 92 if (isInDocument(exitedTarget)) { | |
| 93 Node* exitedNode = exitedTarget->toNode(); | |
|
bokan
2016/04/21 21:38:28
Either DCHECK that exitedNode != nullptr (if indee
Navid Zolghadr
2016/04/21 23:40:14
Neither the DCHECK nor the behavior of handling wh
bokan
2016/04/22 00:52:54
Acknowledged.
Navid Zolghadr
2016/04/22 17:04:12
Done.
| |
| 94 exitedNode->updateDistribution(); | |
| 95 for (Node* node = exitedNode; node; node = FlatTreeTraversal::parent(*no de)) | |
| 96 exitedAncestors.append(node); | |
| 97 } | |
| 98 | |
| 99 if (isInDocument(enteredTarget)) { | |
| 100 Node* enteredNode = enteredTarget->toNode(); | |
| 101 enteredNode->updateDistribution(); | |
|
bokan
2016/04/21 21:38:29
Question: what does updateDistribution do?
Navid Zolghadr
2016/04/21 23:40:14
To be honest with you, I'm not sure myself. From t
bokan
2016/04/22 00:52:54
Hmm, I've never seen it before. But I can see it w
| |
| 102 for (Node* node = enteredNode; node; node = FlatTreeTraversal::parent(*n ode)) | |
| 103 enteredAncestors.append(node); | |
| 104 } | |
| 105 | |
| 106 exitedAncestorsCommonParentIndex = exitedAncestors.size(); | |
| 107 enteredAncestorsCommonParentIndex = enteredAncestors.size(); | |
|
bokan
2016/04/21 21:38:29
One more suggested DCHECK here :), exitedAncestors
Navid Zolghadr
2016/04/21 23:40:14
That's not right. They might be from different doc
bokan
2016/04/22 00:52:54
That's what I'm getting at, you have no way of dis
Navid Zolghadr
2016/04/22 01:46:13
No. That is not the case. Here is an example
if we
bokan
2016/04/22 01:50:47
Bah, I'm not having a good day...you're totally ri
| |
| 108 while (exitedAncestorsCommonParentIndex > 0 | |
| 109 && enteredAncestorsCommonParentIndex > 0) { | |
| 110 if (exitedAncestors[exitedAncestorsCommonParentIndex-1] | |
| 111 != enteredAncestors[enteredAncestorsCommonParentIndex-1]) | |
| 112 break; | |
| 113 exitedAncestorsCommonParentIndex--; | |
| 114 enteredAncestorsCommonParentIndex--; | |
| 115 } | |
| 116 } | |
| 117 | |
| 82 } // namespace | 118 } // namespace |
| 83 | 119 |
| 84 WebInputEventResult PointerEventManager::dispatchPointerEvent( | 120 WebInputEventResult PointerEventManager::dispatchPointerEvent( |
| 85 EventTarget* target, | 121 EventTarget* target, |
| 86 PointerEvent* pointerEvent, | 122 PointerEvent* pointerEvent, |
| 87 bool checkForListener) | 123 bool checkForListener) |
| 88 { | 124 { |
| 89 if (!target) | 125 if (!target) |
| 90 return WebInputEventResult::NotHandled; | 126 return WebInputEventResult::NotHandled; |
| 91 | 127 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 pointerEvent, EventTypeNames::pointerout, enteredTarget)); | 209 pointerEvent, EventTypeNames::pointerout, enteredTarget)); |
| 174 } else { | 210 } else { |
| 175 dispatchMouseEvent(exitedTarget, | 211 dispatchMouseEvent(exitedTarget, |
| 176 EventTypeNames::mouseout, | 212 EventTypeNames::mouseout, |
| 177 mouseEventWithRegion(exitedTarget->toNode(), mouseEvent), | 213 mouseEventWithRegion(exitedTarget->toNode(), mouseEvent), |
| 178 enteredTarget); | 214 enteredTarget); |
| 179 } | 215 } |
| 180 } | 216 } |
| 181 | 217 |
| 182 // Create lists of all exited/entered ancestors, locate the common ancestor | 218 // Create lists of all exited/entered ancestors, locate the common ancestor |
| 183 HeapVector<Member<Node>, 32> exitedAncestors; | 219 // Based on httparchive, in more than 97% cases the depth of DOM is less |
|
bokan
2016/04/21 21:38:29
Doesn't this mean that in 3% of cases we'll incur
Navid Zolghadr
2016/04/21 23:40:14
I don't have a strong answer here.
I had it at 32.
bokan
2016/04/22 00:52:54
Heap allocations can be fairly expensive and unpre
| |
| 184 HeapVector<Member<Node>, 32> enteredAncestors; | 220 // than 20. |
| 185 if (isInDocument(exitedTarget)) { | 221 HeapVector<Member<Node>, 20> exitedAncestors; |
| 186 Node* exitedNode = exitedTarget->toNode(); | 222 HeapVector<Member<Node>, 20> enteredAncestors; |
| 187 exitedNode->updateDistribution(); | 223 size_t exitedAncestorsCommonParentIndex = 0; |
| 188 for (Node* node = exitedNode; node; node = FlatTreeTraversal::parent(*no de)) | 224 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 | 225 |
| 199 // A note on mouseenter and mouseleave: These are non-bubbling events, and t hey are dispatched if there | 226 // 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 | 227 // 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. | 228 // handling is necessary to avoid O(n^2) capturing event handler checks. |
| 202 // | 229 // |
| 203 // Note, however, that this optimization can possibly cause some unanswere d/missing/redundant mouseenter or | 230 // 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: | 231 // 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 | 232 // - 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. | 233 // - 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 | 234 // 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 | 235 // 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. | 236 // match Firefox and IE behavior. |
| 210 // | 237 // |
| 211 // TODO(mustaq): Confirm spec conformance, double-check with other browsers. | 238 // TODO(mustaq): Confirm spec conformance, double-check with other browsers. |
| 212 | 239 |
| 213 size_t numExitedAncestors = exitedAncestors.size(); | 240 buildAncestorChainsAndFindCommonAncestors( |
| 214 size_t numEnteredAncestors = enteredAncestors.size(); | 241 exitedTarget, enteredTarget, |
| 215 | 242 exitedAncestors, enteredAncestors, |
| 216 size_t exitedAncestorIndex = numExitedAncestors; | 243 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 | 244 |
| 230 bool exitedNodeHasCapturingAncestor = false; | 245 bool exitedNodeHasCapturingAncestor = false; |
| 231 for (size_t j = 0; j < exitedAncestors.size(); j++) { | 246 for (size_t j = 0; j < exitedAncestors.size(); j++) { |
| 232 if (exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::mouse leave) | 247 if (exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::mouse leave) |
| 233 || (RuntimeEnabledFeatures::pointerEventEnabled() | 248 || (RuntimeEnabledFeatures::pointerEventEnabled() |
| 234 && exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::po interleave))) | 249 && exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::po interleave))) |
| 235 exitedNodeHasCapturingAncestor = true; | 250 exitedNodeHasCapturingAncestor = true; |
| 236 } | 251 } |
| 237 | 252 |
| 238 // Dispatch pointerleave/mouseleave events, in child-to-parent order. | 253 // Dispatch pointerleave/mouseleave events, in child-to-parent order. |
| 239 for (size_t j = 0; j < exitedAncestorIndex; j++) { | 254 for (size_t j = 0; j < exitedAncestorsCommonParentIndex; j++) { |
| 240 if (!sendMouseEvent) { | 255 if (!sendMouseEvent) { |
| 241 dispatchPointerEvent(exitedAncestors[j].get(), | 256 dispatchPointerEvent(exitedAncestors[j].get(), |
| 242 m_pointerEventFactory.createPointerTransitionEvent( | 257 m_pointerEventFactory.createPointerTransitionEvent( |
| 243 pointerEvent, EventTypeNames::pointerleave, enteredTarget), | 258 pointerEvent, EventTypeNames::pointerleave, enteredTarget), |
| 244 !exitedNodeHasCapturingAncestor); | 259 !exitedNodeHasCapturingAncestor); |
| 245 } else { | 260 } else { |
| 246 dispatchMouseEvent(exitedAncestors[j].get(), | 261 dispatchMouseEvent(exitedAncestors[j].get(), |
| 247 EventTypeNames::mouseleave, | 262 EventTypeNames::mouseleave, |
| 248 mouseEventWithRegion(exitedTarget->toNode(), mouseEvent), | 263 mouseEventWithRegion(exitedTarget->toNode(), mouseEvent), |
| 249 enteredTarget, 0, !exitedNodeHasCapturingAncestor); | 264 enteredTarget, 0, !exitedNodeHasCapturingAncestor); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 265 // the leave handlers might set a capturing enter handler. | 280 // the leave handlers might set a capturing enter handler. |
| 266 bool enteredNodeHasCapturingAncestor = false; | 281 bool enteredNodeHasCapturingAncestor = false; |
| 267 for (size_t i = 0; i < enteredAncestors.size(); i++) { | 282 for (size_t i = 0; i < enteredAncestors.size(); i++) { |
| 268 if (enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::mous eenter) | 283 if (enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::mous eenter) |
| 269 || (RuntimeEnabledFeatures::pointerEventEnabled() | 284 || (RuntimeEnabledFeatures::pointerEventEnabled() |
| 270 && enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::p ointerenter))) | 285 && enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::p ointerenter))) |
| 271 enteredNodeHasCapturingAncestor = true; | 286 enteredNodeHasCapturingAncestor = true; |
| 272 } | 287 } |
| 273 | 288 |
| 274 // Dispatch pointerenter/mouseenter events, in parent-to-child order. | 289 // Dispatch pointerenter/mouseenter events, in parent-to-child order. |
| 275 for (size_t i = enteredAncestorIndex; i > 0; i--) { | 290 for (size_t i = enteredAncestorsCommonParentIndex; i > 0; i--) { |
| 276 if (!sendMouseEvent) { | 291 if (!sendMouseEvent) { |
| 277 dispatchPointerEvent(enteredAncestors[i-1].get(), | 292 dispatchPointerEvent(enteredAncestors[i-1].get(), |
| 278 m_pointerEventFactory.createPointerTransitionEvent( | 293 m_pointerEventFactory.createPointerTransitionEvent( |
| 279 pointerEvent, EventTypeNames::pointerenter, exitedTarget), | 294 pointerEvent, EventTypeNames::pointerenter, exitedTarget), |
| 280 !enteredNodeHasCapturingAncestor); | 295 !enteredNodeHasCapturingAncestor); |
| 281 } else { | 296 } else { |
| 282 dispatchMouseEvent(enteredAncestors[i-1].get(), | 297 dispatchMouseEvent(enteredAncestors[i-1].get(), |
| 283 EventTypeNames::mouseenter, mouseEvent, exitedTarget, | 298 EventTypeNames::mouseenter, mouseEvent, exitedTarget, |
| 284 0, !enteredNodeHasCapturingAncestor); | 299 0, !enteredNodeHasCapturingAncestor); |
| 285 } | 300 } |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 632 | 647 |
| 633 DEFINE_TRACE(PointerEventManager) | 648 DEFINE_TRACE(PointerEventManager) |
| 634 { | 649 { |
| 635 visitor->trace(m_nodeUnderPointer); | 650 visitor->trace(m_nodeUnderPointer); |
| 636 visitor->trace(m_pointerCaptureTarget); | 651 visitor->trace(m_pointerCaptureTarget); |
| 637 visitor->trace(m_pendingPointerCaptureTarget); | 652 visitor->trace(m_pendingPointerCaptureTarget); |
| 638 } | 653 } |
| 639 | 654 |
| 640 | 655 |
| 641 } // namespace blink | 656 } // namespace blink |
| OLD | NEW |