341847fd380288f300e0d83b6b043dabe5217495
[WebKit-https.git] / Source / WebCore / dom / EventDispatcher.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2015 Apple Inc. All rights reserved.
6  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7  * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8  * Copyright (C) 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #include "config.h"
27 #include "EventDispatcher.h"
28
29 #include "EventContext.h"
30 #include "FocusEvent.h"
31 #include "FrameView.h"
32 #include "HTMLInputElement.h"
33 #include "HTMLMediaElement.h"
34 #include "HTMLSlotElement.h"
35 #include "MouseEvent.h"
36 #include "PseudoElement.h"
37 #include "ScopedEventQueue.h"
38 #include "ShadowRoot.h"
39 #include "SVGNames.h"
40 #include "SVGUseElement.h"
41 #include "TouchEvent.h"
42
43 namespace WebCore {
44
45 class WindowEventContext {
46 public:
47     WindowEventContext(PassRefPtr<Node>, const EventContext*);
48
49     DOMWindow* window() const { return m_window.get(); }
50     EventTarget* target() const { return m_target.get(); }
51     bool handleLocalEvents(Event&);
52
53 private:
54     RefPtr<DOMWindow> m_window;
55     RefPtr<EventTarget> m_target;
56 };
57
58 WindowEventContext::WindowEventContext(PassRefPtr<Node> node, const EventContext* topEventContext)
59 {
60     Node* topLevelContainer = topEventContext ? topEventContext->node() : node.get();
61     if (!is<Document>(*topLevelContainer))
62         return;
63
64     m_window = downcast<Document>(*topLevelContainer).domWindow();
65     m_target = topEventContext ? topEventContext->target() : node.get();
66 }
67
68 bool WindowEventContext::handleLocalEvents(Event& event)
69 {
70     if (!m_window)
71         return false;
72
73     event.setTarget(m_target.copyRef());
74     event.setCurrentTarget(m_window.get());
75     m_window->fireEventListeners(event);
76     return true;
77 }
78
79 class EventPath {
80 public:
81     EventPath(Node& origin, Event&);
82
83     bool isEmpty() const { return m_path.isEmpty(); }
84     size_t size() const { return m_path.size(); }
85     const EventContext& contextAt(size_t i) const { return *m_path[i]; }
86     EventContext& contextAt(size_t i) { return *m_path[i]; }
87
88 #if ENABLE(TOUCH_EVENTS)
89     bool updateTouchLists(const TouchEvent&);
90 #endif
91     void setRelatedTarget(Node& origin, EventTarget&);
92
93     bool hasEventListeners(const AtomicString& eventType) const;
94
95     EventContext* lastContextIfExists() { return m_path.isEmpty() ? nullptr : m_path.last().get(); }
96
97 private:
98 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
99     void updateTouchListsInEventPath(const TouchList*, TouchEventContext::TouchListType);
100 #endif
101
102     Event& m_event;
103     Vector<std::unique_ptr<EventContext>, 32> m_path;
104 };
105
106 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
107 // FIXME: Use RelatedNodeRetargeter instead.
108 class EventRelatedNodeResolver {
109 public:
110     EventRelatedNodeResolver(Touch& touch, TouchEventContext::TouchListType touchListType)
111         : m_relatedNode(*touch.target()->toNode())
112         , m_relatedNodeTreeScope(m_relatedNode.treeScope())
113         , m_relatedNodeInCurrentTreeScope(nullptr)
114         , m_currentTreeScope(nullptr)
115         , m_touch(&touch)
116         , m_touchListType(touchListType)
117     {
118         ASSERT(touch.target()->toNode());
119     }
120
121     Touch* touch() const { return m_touch; }
122     TouchEventContext::TouchListType touchListType() const { return m_touchListType; }
123
124     Node* moveToParentOrShadowHost(Node& newTarget)
125     {
126         TreeScope& newTreeScope = newTarget.treeScope();
127         if (&newTreeScope == m_currentTreeScope)
128             return m_relatedNodeInCurrentTreeScope;
129
130         if (m_currentTreeScope) {
131             ASSERT(is<ShadowRoot>(m_currentTreeScope->rootNode()));
132             ASSERT(&newTarget == downcast<ShadowRoot>(m_currentTreeScope->rootNode()).host());
133             ASSERT(m_currentTreeScope->parentTreeScope() == &newTreeScope);
134         }
135
136         if (&newTreeScope == &m_relatedNodeTreeScope)
137             m_relatedNodeInCurrentTreeScope = &m_relatedNode;
138         else if (m_relatedNodeInCurrentTreeScope) {
139             ASSERT(m_currentTreeScope);
140             m_relatedNodeInCurrentTreeScope = &newTarget;
141         } else {
142             if (!m_currentTreeScope) {
143                 TreeScope* newTreeScopeAncestor = &newTreeScope;
144                 do {
145                     m_relatedNodeInCurrentTreeScope = findHostOfTreeScopeInTargetTreeScope(m_relatedNodeTreeScope, *newTreeScopeAncestor);
146                     newTreeScopeAncestor = newTreeScopeAncestor->parentTreeScope();
147                     if (newTreeScopeAncestor == &m_relatedNodeTreeScope) {
148                         m_relatedNodeInCurrentTreeScope = &m_relatedNode;
149                         break;
150                     }
151                 } while (newTreeScopeAncestor && !m_relatedNodeInCurrentTreeScope);
152             }
153             ASSERT(m_relatedNodeInCurrentTreeScope || findHostOfTreeScopeInTargetTreeScope(newTreeScope, m_relatedNodeTreeScope)
154                 || &newTreeScope.documentScope() != &m_relatedNodeTreeScope.documentScope());
155         }
156
157         m_currentTreeScope = &newTreeScope;
158
159         return m_relatedNodeInCurrentTreeScope;
160     }
161
162     static Node* findHostOfTreeScopeInTargetTreeScope(const TreeScope& startingTreeScope, const TreeScope& targetScope)
163     {
164         ASSERT(&targetScope != &startingTreeScope);
165         Node* previousHost = nullptr;
166         for (const TreeScope* scope = &startingTreeScope; scope; scope = scope->parentTreeScope()) {
167             if (scope == &targetScope) {
168                 ASSERT(previousHost);
169                 ASSERT_WITH_SECURITY_IMPLICATION(&previousHost->treeScope() == &targetScope);
170                 return previousHost;
171             }
172             if (is<ShadowRoot>(scope->rootNode()))
173                 previousHost = downcast<ShadowRoot>(scope->rootNode()).host();
174             else
175                 ASSERT_WITH_SECURITY_IMPLICATION(!scope->parentTreeScope());
176         }
177         return nullptr;
178     }
179
180 private:
181     Node& m_relatedNode;
182     const TreeScope& m_relatedNodeTreeScope;
183     Node* m_relatedNodeInCurrentTreeScope;
184     TreeScope* m_currentTreeScope;
185     Touch* m_touch;
186     TouchEventContext::TouchListType m_touchListType;
187 };
188 #endif
189
190 inline EventTarget* eventTargetRespectingTargetRules(Node& referenceNode)
191 {
192     if (is<PseudoElement>(referenceNode))
193         return downcast<PseudoElement>(referenceNode).hostElement();
194
195     // Events sent to elements inside an SVG use element's shadow tree go to the use element.
196     if (is<SVGElement>(referenceNode)) {
197         if (auto* useElement = downcast<SVGElement>(referenceNode).correspondingUseElement())
198             return useElement;
199     }
200
201     return &referenceNode;
202 }
203
204 void EventDispatcher::dispatchScopedEvent(Node& node, Event& event)
205 {
206     // We need to set the target here because it can go away by the time we actually fire the event.
207     event.setTarget(eventTargetRespectingTargetRules(node));
208     ScopedEventQueue::singleton().enqueueEvent(event);
209 }
210
211 void EventDispatcher::dispatchSimulatedClick(Element* element, Event* underlyingEvent, SimulatedClickMouseEventOptions mouseEventOptions, SimulatedClickVisualOptions visualOptions)
212 {
213     if (element->isDisabledFormControl())
214         return;
215
216     DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<Element*>, elementsDispatchingSimulatedClicks, ());
217     if (!elementsDispatchingSimulatedClicks.add(element).isNewEntry)
218         return;
219
220     if (mouseEventOptions == SendMouseOverUpDownEvents)
221         dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mouseoverEvent, element->document().defaultView(), underlyingEvent, element));
222
223     if (mouseEventOptions != SendNoEvents)
224         dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mousedownEvent, element->document().defaultView(), underlyingEvent, element));
225     element->setActive(true, visualOptions == ShowPressedLook);
226     if (mouseEventOptions != SendNoEvents)
227         dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mouseupEvent, element->document().defaultView(), underlyingEvent, element));
228     element->setActive(false);
229
230     // always send click
231     dispatchEvent(element, SimulatedMouseEvent::create(eventNames().clickEvent, element->document().defaultView(), underlyingEvent, element));
232
233     elementsDispatchingSimulatedClicks.remove(element);
234 }
235
236 static void callDefaultEventHandlersInTheBubblingOrder(Event& event, const EventPath& path)
237 {
238     if (path.isEmpty())
239         return;
240
241     // Non-bubbling events call only one default event handler, the one for the target.
242     path.contextAt(0).node()->defaultEventHandler(&event);
243     ASSERT(!event.defaultPrevented());
244
245     if (event.defaultHandled() || !event.bubbles())
246         return;
247
248     size_t size = path.size();
249     for (size_t i = 1; i < size; ++i) {
250         path.contextAt(i).node()->defaultEventHandler(&event);
251         ASSERT(!event.defaultPrevented());
252         if (event.defaultHandled())
253             return;
254     }
255 }
256
257 static void dispatchEventInDOM(Event& event, const EventPath& path, WindowEventContext& windowEventContext)
258 {
259     // Trigger capturing event handlers, starting at the top and working our way down.
260     event.setEventPhase(Event::CAPTURING_PHASE);
261
262     // We don't dispatch load events to the window. This quirk was originally
263     // added because Mozilla doesn't propagate load events to the window object.
264     bool shouldFireEventAtWindow = event.type() != eventNames().loadEvent;
265     if (shouldFireEventAtWindow && windowEventContext.handleLocalEvents(event) && event.propagationStopped())
266         return;
267
268     for (size_t i = path.size() - 1; i > 0; --i) {
269         const EventContext& eventContext = path.contextAt(i);
270         if (eventContext.currentTargetSameAsTarget())
271             continue;
272         eventContext.handleLocalEvents(event);
273         if (event.propagationStopped())
274             return;
275     }
276
277     event.setEventPhase(Event::AT_TARGET);
278     path.contextAt(0).handleLocalEvents(event);
279     if (event.propagationStopped())
280         return;
281
282     // Trigger bubbling event handlers, starting at the bottom and working our way up.
283     size_t size = path.size();
284     for (size_t i = 1; i < size; ++i) {
285         const EventContext& eventContext = path.contextAt(i);
286         if (eventContext.currentTargetSameAsTarget())
287             event.setEventPhase(Event::AT_TARGET);
288         else if (event.bubbles() && !event.cancelBubble())
289             event.setEventPhase(Event::BUBBLING_PHASE);
290         else
291             continue;
292         eventContext.handleLocalEvents(event);
293         if (event.propagationStopped())
294             return;
295     }
296     if (event.bubbles() && !event.cancelBubble()) {
297         event.setEventPhase(Event::BUBBLING_PHASE);
298         if (shouldFireEventAtWindow)
299             windowEventContext.handleLocalEvents(event);
300     }
301 }
302
303 bool EventDispatcher::dispatchEvent(Node* origin, Event& event)
304 {
305     ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
306     ASSERT(origin);
307     RefPtr<Node> node(origin);
308     RefPtr<FrameView> view = node->document().view();
309     EventPath eventPath(*node, event);
310
311     if (EventTarget* relatedTarget = event.relatedTarget())
312         eventPath.setRelatedTarget(*node, *relatedTarget);
313 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
314     if (is<TouchEvent>(event)) {
315         if (!eventPath.updateTouchLists(downcast<TouchEvent>(event)))
316             return true;
317     }
318 #endif
319
320     ChildNodesLazySnapshot::takeChildNodesLazySnapshot();
321
322     EventTarget* target = eventTargetRespectingTargetRules(*node);
323     event.setTarget(target);
324     if (!event.target())
325         return true;
326
327     ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
328
329     WindowEventContext windowEventContext(node.get(), eventPath.lastContextIfExists());
330
331     InputElementClickState clickHandlingState;
332     if (is<HTMLInputElement>(*node))
333         downcast<HTMLInputElement>(*node).willDispatchEvent(event, clickHandlingState);
334
335     if (!event.propagationStopped() && !eventPath.isEmpty())
336         dispatchEventInDOM(event, eventPath, windowEventContext);
337
338     event.setTarget(eventTargetRespectingTargetRules(*node));
339     event.setCurrentTarget(nullptr);
340     event.setEventPhase(0);
341
342     if (clickHandlingState.stateful)
343         downcast<HTMLInputElement>(*node).didDispatchClickEvent(event, clickHandlingState);
344
345     // Call default event handlers. While the DOM does have a concept of preventing
346     // default handling, the detail of which handlers are called is an internal
347     // implementation detail and not part of the DOM.
348     if (!event.defaultPrevented() && !event.defaultHandled())
349         callDefaultEventHandlersInTheBubblingOrder(event, eventPath);
350
351     // Ensure that after event dispatch, the event's target object is the
352     // outermost shadow DOM boundary.
353     event.setTarget(windowEventContext.target());
354     event.setCurrentTarget(nullptr);
355
356     return !event.defaultPrevented();
357 }
358
359 static inline bool shouldEventCrossShadowBoundary(Event& event, ShadowRoot& shadowRoot, EventTarget& target)
360 {
361     Node* targetNode = target.toNode();
362 #if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
363     // Video-only full screen is a mode where we use the shadow DOM as an implementation
364     // detail that should not be detectable by the web content.
365     if (targetNode) {
366         if (Element* element = targetNode->document().webkitCurrentFullScreenElement()) {
367             // FIXME: We assume that if the full screen element is a media element that it's
368             // the video-only full screen. Both here and elsewhere. But that is probably wrong.
369             if (element->isMediaElement() && shadowRoot.host() == element)
370                 return false;
371         }
372     }
373 #endif
374
375     // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
376     // Changing this breaks existing sites.
377     // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
378     const AtomicString& eventType = event.type();
379     bool targetIsInShadowRoot = targetNode && &targetNode->treeScope().rootNode() == &shadowRoot;
380     return !targetIsInShadowRoot
381         || !(eventType == eventNames().abortEvent
382             || eventType == eventNames().changeEvent
383             || eventType == eventNames().errorEvent
384             || eventType == eventNames().loadEvent
385             || eventType == eventNames().resetEvent
386             || eventType == eventNames().resizeEvent
387             || eventType == eventNames().scrollEvent
388             || eventType == eventNames().selectEvent
389             || eventType == eventNames().selectstartEvent);
390 }
391
392 static Node* nodeOrHostIfPseudoElement(Node* node)
393 {
394     return is<PseudoElement>(*node) ? downcast<PseudoElement>(*node).hostElement() : node;
395 }
396
397 EventPath::EventPath(Node& originalTarget, Event& event)
398     : m_event(event)
399 {
400 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
401     Vector<EventTarget*, 16> targetStack;
402 #endif
403
404     bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent();
405 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
406     bool isTouchEvent = event.isTouchEvent();
407 #endif
408     EventTarget* target = nullptr;
409
410     Node* node = nodeOrHostIfPseudoElement(&originalTarget);
411     while (node) {
412         if (!target)
413             target = eventTargetRespectingTargetRules(*node);
414         ContainerNode* parent;
415         for (; node; node = parent) {
416             EventTarget* currentTarget = eventTargetRespectingTargetRules(*node);
417             if (isMouseOrFocusEvent)
418                 m_path.append(std::make_unique<MouseOrFocusEventContext>(node, currentTarget, target));
419 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
420             else if (isTouchEvent)
421                 m_path.append(std::make_unique<TouchEventContext>(node, currentTarget, target));
422 #endif
423             else
424                 m_path.append(std::make_unique<EventContext>(node, currentTarget, target));
425             if (is<ShadowRoot>(*node))
426                 break;
427             parent = node->parentNode();
428             if (!parent)
429                 return;
430 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
431             if (ShadowRoot* shadowRootOfParent = parent->shadowRoot()) {
432                 if (auto* assignedSlot = shadowRootOfParent->findAssignedSlot(*node)) {
433                     // node is assigned to a slot. Continue dispatching the event at this slot.
434                     targetStack.append(target);
435                     parent = assignedSlot;
436                     target = assignedSlot;
437                 }
438             }
439 #endif
440             node = parent;
441         }
442
443         ShadowRoot& shadowRoot = downcast<ShadowRoot>(*node);
444         // At a shadow root. Continue dispatching the event at the shadow host.
445 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
446         if (!targetStack.isEmpty()) {
447             // Move target back to a descendant of the shadow host if the event did not originate in this shadow tree or its inner shadow trees.
448             target = targetStack.last();
449             targetStack.removeLast();
450             ASSERT(shadowRoot.host()->contains(target->toNode()));
451         } else
452 #endif
453             target = nullptr;
454
455         if (!shouldEventCrossShadowBoundary(event, shadowRoot, originalTarget))
456             return;
457         node = shadowRoot.host();
458     }
459 }
460
461 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
462 static void addRelatedNodeResolversForTouchList(Vector<EventRelatedNodeResolver, 16>& touchTargetResolvers, TouchList* touchList, TouchEventContext::TouchListType type)
463 {
464     const size_t touchListSize = touchList->length();
465     for (size_t i = 0; i < touchListSize; ++i)
466         touchTargetResolvers.append(EventRelatedNodeResolver(*touchList->item(i), type));
467 }
468
469 bool EventPath::updateTouchLists(const TouchEvent& touchEvent)
470 {
471     if (!touchEvent.touches() || !touchEvent.targetTouches() || !touchEvent.changedTouches())
472         return false;
473     
474     Vector<EventRelatedNodeResolver, 16> touchTargetResolvers;
475     const size_t touchNodeCount = touchEvent.touches()->length() + touchEvent.targetTouches()->length() + touchEvent.changedTouches()->length();
476     touchTargetResolvers.reserveInitialCapacity(touchNodeCount);
477
478     addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.touches(), TouchEventContext::Touches);
479     addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.targetTouches(), TouchEventContext::TargetTouches);
480     addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.changedTouches(), TouchEventContext::ChangedTouches);
481
482     ASSERT(touchTargetResolvers.size() == touchNodeCount);
483     for (auto& eventPath : m_path) {
484         TouchEventContext& context = toTouchEventContext(*eventPath);
485         Node& nodeToMoveTo = *context.node();
486         for (size_t resolverIndex = 0; resolverIndex < touchNodeCount; ++resolverIndex) {
487             EventRelatedNodeResolver& currentResolver = touchTargetResolvers[resolverIndex];
488             Node* nodeInCurrentTreeScope = currentResolver.moveToParentOrShadowHost(nodeToMoveTo);
489             ASSERT(currentResolver.touch());
490             context.touchList(currentResolver.touchListType())->append(currentResolver.touch()->cloneWithNewTarget(nodeInCurrentTreeScope));
491         }
492     }
493     return true;
494 }
495 #endif
496
497 class RelatedNodeRetargeter {
498 public:
499     RelatedNodeRetargeter(Node& relatedNode, TreeScope& targetTreeScope)
500         : m_relatedNode(relatedNode)
501         , m_retargetedRelatedNode(&relatedNode)
502     {
503         TreeScope* currentTreeScope = &m_relatedNode.treeScope();
504         if (LIKELY(currentTreeScope == &targetTreeScope))
505             return;
506
507         if (&currentTreeScope->documentScope() != &targetTreeScope.documentScope()) {
508             m_hasDifferentTreeRoot = true;
509             m_retargetedRelatedNode = nullptr;
510             return;
511         }
512         if (relatedNode.inDocument() != targetTreeScope.rootNode().inDocument()) {
513             m_hasDifferentTreeRoot = true;
514             while (m_retargetedRelatedNode->isInShadowTree())
515                 m_retargetedRelatedNode = downcast<ShadowRoot>(m_retargetedRelatedNode->treeScope().rootNode()).host();
516             return;
517         }
518
519         collectTreeScopes();
520
521         // FIXME: We should collect this while constructing the event path.
522         Vector<TreeScope*, 8> targetTreeScopeAncestors;
523         for (TreeScope* currentTreeScope = &targetTreeScope; currentTreeScope; currentTreeScope = currentTreeScope->parentTreeScope())
524             targetTreeScopeAncestors.append(currentTreeScope);
525         ASSERT_WITH_SECURITY_IMPLICATION(!targetTreeScopeAncestors.isEmpty());
526
527         unsigned i = m_ancestorTreeScopes.size();
528         unsigned j = targetTreeScopeAncestors.size();
529         ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.last() == targetTreeScopeAncestors.last());
530         while (m_ancestorTreeScopes[i - 1] == targetTreeScopeAncestors[j - 1]) {
531             i--;
532             j--;
533             if (!i || !j)
534                 break;
535         }
536
537         m_lowestCommonAncestorIndex = i;
538         m_retargetedRelatedNode = nodeInLowestCommonAncestor();
539     }
540
541     Node* currentNode(TreeScope& currentTreeScope)
542     {
543         checkConsistency(currentTreeScope);
544         return m_retargetedRelatedNode;
545     }
546
547     void moveToNewTreeScope(TreeScope* previousTreeScope, TreeScope& newTreeScope)
548     {
549         if (m_hasDifferentTreeRoot)
550             return;
551
552         auto& currentRelatedNodeScope = m_retargetedRelatedNode->treeScope();
553         if (previousTreeScope != &currentRelatedNodeScope) {
554             // currentRelatedNode is still outside our shadow tree. New tree scope may contain currentRelatedNode
555             // but there is no need to re-target it. Moving into a slot (thereby a deeper shadow tree) doesn't matter.
556             return;
557         }
558
559         bool enteredSlot = newTreeScope.parentTreeScope() == previousTreeScope;
560         if (enteredSlot) {
561             if (m_lowestCommonAncestorIndex) {
562                 if (m_ancestorTreeScopes.isEmpty())
563                     collectTreeScopes();
564                 bool relatedNodeIsInSlot = m_ancestorTreeScopes[m_lowestCommonAncestorIndex - 1] == &newTreeScope;
565                 if (relatedNodeIsInSlot) {
566                     m_lowestCommonAncestorIndex--;
567                     m_retargetedRelatedNode = nodeInLowestCommonAncestor();
568                     ASSERT(&newTreeScope == &m_retargetedRelatedNode->treeScope());
569                 }
570             } else
571                 ASSERT(m_retargetedRelatedNode == &m_relatedNode);
572         } else {
573             ASSERT(previousTreeScope->parentTreeScope() == &newTreeScope);
574             m_lowestCommonAncestorIndex++;
575             ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.isEmpty() || m_lowestCommonAncestorIndex < m_ancestorTreeScopes.size());
576             m_retargetedRelatedNode = downcast<ShadowRoot>(currentRelatedNodeScope.rootNode()).host();
577             ASSERT(&newTreeScope == &m_retargetedRelatedNode->treeScope());
578         }
579     }
580
581     void checkConsistency(TreeScope& currentTreeScope)
582     {
583 #if !ASSERT_DISABLED
584         for (auto* relatedNodeScope = &m_relatedNode.treeScope(); relatedNodeScope; relatedNodeScope = relatedNodeScope->parentTreeScope()) {
585             for (auto* targetScope = &currentTreeScope; targetScope; targetScope = targetScope->parentTreeScope()) {
586                 if (targetScope == relatedNodeScope) {
587                     ASSERT(&m_retargetedRelatedNode->treeScope() == relatedNodeScope);
588                     return;
589                 }
590             }
591         }
592         ASSERT(!m_retargetedRelatedNode);
593 #else
594         UNUSED_PARAM(currentTreeScope);
595 #endif
596     }
597
598 private:
599     Node* nodeInLowestCommonAncestor()
600     {
601         if (!m_lowestCommonAncestorIndex)
602             return &m_relatedNode;
603         auto& rootNode = m_ancestorTreeScopes[m_lowestCommonAncestorIndex - 1]->rootNode();
604         return downcast<ShadowRoot>(rootNode).host();
605     }
606
607     void collectTreeScopes()
608     {
609         ASSERT(m_ancestorTreeScopes.isEmpty());
610         for (TreeScope* currentTreeScope = &m_relatedNode.treeScope(); currentTreeScope; currentTreeScope = currentTreeScope->parentTreeScope())
611             m_ancestorTreeScopes.append(currentTreeScope);
612         ASSERT_WITH_SECURITY_IMPLICATION(!m_ancestorTreeScopes.isEmpty());
613     }
614
615     Node& m_relatedNode;
616     Node* m_retargetedRelatedNode;
617     Vector<TreeScope*, 8> m_ancestorTreeScopes;
618     unsigned m_lowestCommonAncestorIndex { 0 };
619     bool m_hasDifferentTreeRoot { false };
620 };
621
622 void EventPath::setRelatedTarget(Node& origin, EventTarget& relatedTarget)
623 {
624     UNUSED_PARAM(origin);
625     Node* relatedNode = relatedTarget.toNode();
626     if (!relatedNode || m_path.isEmpty())
627         return;
628
629     RelatedNodeRetargeter retargeter(*relatedNode, downcast<MouseOrFocusEventContext>(*m_path[0]).node()->treeScope());
630
631     bool originIsRelatedTarget = &origin == relatedNode;
632     // FIXME: We should add a new flag on Event instead.
633     bool shouldTrimEventPath = m_event.type() == eventNames().mouseoverEvent
634         || m_event.type() == eventNames().mousemoveEvent
635         || m_event.type() == eventNames().mouseoutEvent;
636     Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode();
637     TreeScope* previousTreeScope = nullptr;
638     size_t originalEventPathSize = m_path.size();
639     for (unsigned contextIndex = 0; contextIndex < originalEventPathSize; contextIndex++) {
640         auto& context = downcast<MouseOrFocusEventContext>(*m_path[contextIndex]);
641
642         TreeScope& currentTreeScope = context.node()->treeScope();
643         if (UNLIKELY(previousTreeScope && &currentTreeScope != previousTreeScope))
644             retargeter.moveToNewTreeScope(previousTreeScope, currentTreeScope);
645
646         Node* currentRelatedNode = retargeter.currentNode(currentTreeScope);
647         if (UNLIKELY(shouldTrimEventPath && !originIsRelatedTarget && context.target() == currentRelatedNode)) {
648             m_path.shrink(contextIndex);
649             break;
650         }
651
652         context.setRelatedTarget(currentRelatedNode);
653
654         if (UNLIKELY(shouldTrimEventPath && originIsRelatedTarget && context.node() == &rootNodeInOriginTreeScope)) {
655             m_path.shrink(contextIndex + 1);
656             break;
657         }
658
659         previousTreeScope = &currentTreeScope;
660     }
661 }
662
663 bool EventPath::hasEventListeners(const AtomicString& eventType) const
664 {
665     for (auto& eventPath : m_path) {
666         if (eventPath->node()->hasEventListeners(eventType))
667             return true;
668     }
669
670     return false;
671 }
672
673 }