2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Neither the name of Google Inc. nor the names of its
11 * contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "core/events/EventPath.h"
30 #include "core/EventNames.h"
31 #include "core/dom/Document.h"
32 #include "core/dom/Touch.h"
33 #include "core/dom/TouchList.h"
34 #include "core/dom/shadow/InsertionPoint.h"
35 #include "core/dom/shadow/ShadowRoot.h"
36 #include "core/events/TouchEvent.h"
37 #include "core/events/TouchEventContext.h"
41 EventTarget* EventPath::eventTargetRespectingTargetRules(Node* referenceNode)
43 ASSERT(referenceNode);
45 if (referenceNode->isPseudoElement())
46 return referenceNode->parentNode();
51 static inline bool shouldStopAtShadowRoot(Event& event, ShadowRoot& shadowRoot, EventTarget& target)
53 // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
54 // Changing this breaks existing sites.
55 // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
56 const AtomicString eventType = event.type();
57 return target.toNode() && target.toNode()->shadowHost() == shadowRoot.host()
58 && (eventType == EventTypeNames::abort
59 || eventType == EventTypeNames::change
60 || eventType == EventTypeNames::error
61 || eventType == EventTypeNames::load
62 || eventType == EventTypeNames::reset
63 || eventType == EventTypeNames::resize
64 || eventType == EventTypeNames::scroll
65 || eventType == EventTypeNames::select
66 || eventType == EventTypeNames::selectstart);
69 EventPath::EventPath(Event* event)
75 EventPath::EventPath(Node* node)
82 void EventPath::resetWith(Node* node)
86 m_nodeEventContexts.clear();
87 m_treeScopeEventContexts.clear();
89 calculateAdjustedTargets();
90 calculateTreeScopePrePostOrderNumbers();
93 void EventPath::addNodeEventContext(Node* node)
95 m_nodeEventContexts.append(NodeEventContext(node, eventTargetRespectingTargetRules(node)));
98 void EventPath::calculatePath()
101 ASSERT(m_nodeEventContexts.isEmpty());
102 m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node.get()));
104 Node* current = m_node;
105 addNodeEventContext(current);
106 if (!m_node->inDocument())
109 if (m_event && current->keepEventInNode(m_event))
111 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
112 collectDestinationInsertionPoints(*current, insertionPoints);
113 if (!insertionPoints.isEmpty()) {
114 for (const auto& insertionPoint : insertionPoints) {
115 if (insertionPoint->isShadowInsertionPoint()) {
116 ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot();
117 ASSERT(containingShadowRoot);
118 if (!containingShadowRoot->isOldest())
119 addNodeEventContext(containingShadowRoot->olderShadowRoot());
121 addNodeEventContext(insertionPoint);
123 current = insertionPoints.last();
126 if (current->isShadowRoot()) {
127 if (m_event && shouldStopAtShadowRoot(*m_event, *toShadowRoot(current), *m_node))
129 current = current->shadowHost();
130 addNodeEventContext(current);
132 current = current->parentNode();
134 addNodeEventContext(current);
139 void EventPath::calculateTreeScopePrePostOrderNumbers()
142 // - TreeScopes in m_treeScopeEventContexts must be *connected* in the same tree of trees.
143 // - The root tree must be included.
144 WillBeHeapHashMap<RawPtrWillBeMember<const TreeScope>, RawPtrWillBeMember<TreeScopeEventContext>> treeScopeEventContextMap;
145 for (const auto& treeScopeEventContext : m_treeScopeEventContexts)
146 treeScopeEventContextMap.add(&treeScopeEventContext->treeScope(), treeScopeEventContext.get());
147 TreeScopeEventContext* rootTree = 0;
148 for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
149 // Use olderShadowRootOrParentTreeScope here for parent-child relationships.
150 // See the definition of trees of trees in the Shado DOM spec: http://w3c.github.io/webcomponents/spec/shadow/
151 TreeScope* parent = treeScopeEventContext.get()->treeScope().olderShadowRootOrParentTreeScope();
154 rootTree = treeScopeEventContext.get();
157 ASSERT(treeScopeEventContextMap.find(parent) != treeScopeEventContextMap.end());
158 treeScopeEventContextMap.find(parent)->value->addChild(*treeScopeEventContext.get());
161 rootTree->calculatePrePostOrderNumber(0);
164 TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap)
168 TreeScopeEventContext* treeScopeEventContext;
171 TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(treeScope, nullptr);
172 isNewEntry = addResult.isNewEntry;
174 addResult.storedValue->value = TreeScopeEventContext::create(*treeScope);
175 treeScopeEventContext = addResult.storedValue->value.get();
178 TreeScopeEventContext* parentTreeScopeEventContext = ensureTreeScopeEventContext(0, treeScope->olderShadowRootOrParentTreeScope(), treeScopeEventContextMap);
179 if (parentTreeScopeEventContext && parentTreeScopeEventContext->target()) {
180 treeScopeEventContext->setTarget(parentTreeScopeEventContext->target());
181 } else if (currentTarget) {
182 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
184 } else if (!treeScopeEventContext->target() && currentTarget) {
185 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
187 return treeScopeEventContext;
190 void EventPath::calculateAdjustedTargets()
192 const TreeScope* lastTreeScope = 0;
194 TreeScopeEventContextMap treeScopeEventContextMap;
195 TreeScopeEventContext* lastTreeScopeEventContext = 0;
197 for (size_t i = 0; i < size(); ++i) {
198 Node* currentNode = at(i).node();
199 TreeScope& currentTreeScope = currentNode->treeScope();
200 if (lastTreeScope != ¤tTreeScope) {
201 lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, ¤tTreeScope, treeScopeEventContextMap);
203 ASSERT(lastTreeScopeEventContext);
204 at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
205 lastTreeScope = ¤tTreeScope;
207 m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
210 void EventPath::buildRelatedNodeMap(const Node* relatedNode, RelatedTargetMap& relatedTargetMap)
212 EventPath relatedTargetEventPath(const_cast<Node*>(relatedNode));
213 for (size_t i = 0; i < relatedTargetEventPath.m_treeScopeEventContexts.size(); ++i) {
214 TreeScopeEventContext* treeScopeEventContext = relatedTargetEventPath.m_treeScopeEventContexts[i].get();
215 relatedTargetMap.add(&treeScopeEventContext->treeScope(), treeScopeEventContext->target());
219 EventTarget* EventPath::findRelatedNode(TreeScope* scope, RelatedTargetMap& relatedTargetMap)
221 WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32> parentTreeScopes;
222 EventTarget* relatedNode = 0;
224 parentTreeScopes.append(scope);
225 RelatedTargetMap::const_iterator iter = relatedTargetMap.find(scope);
226 if (iter != relatedTargetMap.end() && iter->value) {
227 relatedNode = iter->value;
230 scope = scope->olderShadowRootOrParentTreeScope();
233 for (WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32>::iterator iter = parentTreeScopes.begin(); iter < parentTreeScopes.end(); ++iter)
234 relatedTargetMap.add(*iter, relatedNode);
238 void EventPath::adjustForRelatedTarget(Node* target, EventTarget* relatedTarget)
244 Node* relatedNode = relatedTarget->toNode();
247 if (target->document() != relatedNode->document())
249 if (!target->inDocument() || !relatedNode->inDocument())
252 RelatedTargetMap relatedNodeMap;
253 buildRelatedNodeMap(relatedNode, relatedNodeMap);
255 for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
256 EventTarget* adjustedRelatedTarget = findRelatedNode(&treeScopeEventContext.get()->treeScope(), relatedNodeMap);
257 ASSERT(adjustedRelatedTarget);
258 treeScopeEventContext.get()->setRelatedTarget(adjustedRelatedTarget);
261 shrinkIfNeeded(target, relatedTarget);
264 void EventPath::shrinkIfNeeded(const Node* target, const EventTarget* relatedTarget)
266 // Synthetic mouse events can have a relatedTarget which is identical to the target.
267 bool targetIsIdenticalToToRelatedTarget = (target == relatedTarget);
269 for (size_t i = 0; i < size(); ++i) {
270 if (targetIsIdenticalToToRelatedTarget) {
271 if (target->treeScope().rootNode() == at(i).node()) {
275 } else if (at(i).target() == at(i).relatedTarget()) {
276 // Event dispatching should be stopped here.
283 void EventPath::adjustForTouchEvent(Node* node, TouchEvent& touchEvent)
285 WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedTouches;
286 WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedTargetTouches;
287 WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedChangedTouches;
288 WillBeHeapVector<RawPtrWillBeMember<TreeScope>> treeScopes;
290 for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
291 TouchEventContext* touchEventContext = treeScopeEventContext->ensureTouchEventContext();
292 adjustedTouches.append(&touchEventContext->touches());
293 adjustedTargetTouches.append(&touchEventContext->targetTouches());
294 adjustedChangedTouches.append(&touchEventContext->changedTouches());
295 treeScopes.append(&treeScopeEventContext->treeScope());
298 adjustTouchList(node, touchEvent.touches(), adjustedTouches, treeScopes);
299 adjustTouchList(node, touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
300 adjustTouchList(node, touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);
303 for (const auto& treeScopeEventContext : m_treeScopeEventContexts) {
304 TreeScope& treeScope = treeScopeEventContext->treeScope();
305 TouchEventContext* touchEventContext = treeScopeEventContext->touchEventContext();
306 checkReachability(treeScope, touchEventContext->touches());
307 checkReachability(treeScope, touchEventContext->targetTouches());
308 checkReachability(treeScope, touchEventContext->changedTouches());
313 void EventPath::adjustTouchList(const Node* node, const TouchList* touchList, WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedTouchList, const WillBeHeapVector<RawPtrWillBeMember<TreeScope>>& treeScopes)
317 for (size_t i = 0; i < touchList->length(); ++i) {
318 const Touch& touch = *touchList->item(i);
319 RelatedTargetMap relatedNodeMap;
320 buildRelatedNodeMap(touch.target()->toNode(), relatedNodeMap);
321 for (size_t j = 0; j < treeScopes.size(); ++j) {
322 adjustedTouchList[j]->append(touch.cloneWithNewTarget(findRelatedNode(treeScopes[j], relatedNodeMap)));
328 void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList)
330 for (size_t i = 0; i < touchList.length(); ++i)
331 ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope));
335 void EventPath::trace(Visitor* visitor)
337 visitor->trace(m_nodeEventContexts);
338 visitor->trace(m_node);
339 visitor->trace(m_event);
340 visitor->trace(m_treeScopeEventContexts);