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

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

Issue 1904453003: Change finding common ancestor from O(n^2) to O(n) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased Created 4 years, 7 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698