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 inTheSameScope(ShadowRoot* shadowRoot, EventTarget* target)
53 return target->toNode() && target->toNode()->treeScope().rootNode() == shadowRoot;
56 static inline EventDispatchBehavior determineDispatchBehavior(Event* event, ShadowRoot* shadowRoot, EventTarget* target)
58 // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
59 // Changing this breaks existing sites.
60 // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
61 const AtomicString eventType = event->type();
62 if (inTheSameScope(shadowRoot, target)
63 && (eventType == EventTypeNames::abort
64 || eventType == EventTypeNames::change
65 || eventType == EventTypeNames::error
66 || eventType == EventTypeNames::load
67 || eventType == EventTypeNames::reset
68 || eventType == EventTypeNames::resize
69 || eventType == EventTypeNames::scroll
70 || eventType == EventTypeNames::select
71 || eventType == EventTypeNames::selectstart))
72 return StayInsideShadowDOM;
77 EventPath::EventPath(Event* event)
83 EventPath::EventPath(Node* node)
90 void EventPath::resetWith(Node* node)
94 m_nodeEventContexts.clear();
95 m_treeScopeEventContexts.clear();
97 calculateAdjustedTargets();
98 calculateTreeScopePrePostOrderNumbers();
101 void EventPath::addNodeEventContext(Node* node)
103 m_nodeEventContexts.append(NodeEventContext(node, eventTargetRespectingTargetRules(node)));
106 void EventPath::calculatePath()
109 ASSERT(m_nodeEventContexts.isEmpty());
110 m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node.get()));
112 Node* current = m_node;
113 addNodeEventContext(current);
114 if (!m_node->inDocument())
117 if (m_event && current->keepEventInNode(m_event))
119 if (current->isShadowRoot() && m_event && determineDispatchBehavior(m_event, toShadowRoot(current), m_node) == StayInsideShadowDOM)
121 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
122 collectDestinationInsertionPoints(*current, insertionPoints);
123 if (!insertionPoints.isEmpty()) {
124 for (size_t i = 0; i < insertionPoints.size(); ++i) {
125 InsertionPoint* insertionPoint = insertionPoints[i];
126 if (insertionPoint->isShadowInsertionPoint()) {
127 ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot();
128 ASSERT(containingShadowRoot);
129 if (!containingShadowRoot->isOldest())
130 addNodeEventContext(containingShadowRoot->olderShadowRoot());
132 addNodeEventContext(insertionPoint);
134 current = insertionPoints.last();
137 if (current->isShadowRoot()) {
138 current = current->shadowHost();
139 addNodeEventContext(current);
141 current = current->parentNode();
143 addNodeEventContext(current);
148 void EventPath::calculateTreeScopePrePostOrderNumbers()
151 // - TreeScopes in m_treeScopeEventContexts must be *connected* in the same tree of trees.
152 // - The root tree must be included.
153 WillBeHeapHashMap<RawPtrWillBeMember<const TreeScope>, RawPtrWillBeMember<TreeScopeEventContext> > treeScopeEventContextMap;
154 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i)
155 treeScopeEventContextMap.add(&m_treeScopeEventContexts[i]->treeScope(), m_treeScopeEventContexts[i].get());
156 TreeScopeEventContext* rootTree = 0;
157 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
158 TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
159 // Use olderShadowRootOrParentTreeScope here for parent-child relationships.
160 // See the definition of trees of trees in the Shado DOM spec: http://w3c.github.io/webcomponents/spec/shadow/
161 TreeScope* parent = treeScopeEventContext->treeScope().olderShadowRootOrParentTreeScope();
164 rootTree = treeScopeEventContext;
167 ASSERT(treeScopeEventContextMap.find(parent) != treeScopeEventContextMap.end());
168 treeScopeEventContextMap.find(parent)->value->addChild(*treeScopeEventContext);
171 rootTree->calculatePrePostOrderNumber(0);
174 TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap)
178 TreeScopeEventContext* treeScopeEventContext;
181 TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(treeScope, nullptr);
182 isNewEntry = addResult.isNewEntry;
184 addResult.storedValue->value = TreeScopeEventContext::create(*treeScope);
185 treeScopeEventContext = addResult.storedValue->value.get();
188 TreeScopeEventContext* parentTreeScopeEventContext = ensureTreeScopeEventContext(0, treeScope->olderShadowRootOrParentTreeScope(), treeScopeEventContextMap);
189 if (parentTreeScopeEventContext && parentTreeScopeEventContext->target()) {
190 treeScopeEventContext->setTarget(parentTreeScopeEventContext->target());
191 } else if (currentTarget) {
192 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
194 } else if (!treeScopeEventContext->target() && currentTarget) {
195 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
197 return treeScopeEventContext;
200 void EventPath::calculateAdjustedTargets()
202 const TreeScope* lastTreeScope = 0;
204 TreeScopeEventContextMap treeScopeEventContextMap;
205 TreeScopeEventContext* lastTreeScopeEventContext = 0;
207 for (size_t i = 0; i < size(); ++i) {
208 Node* currentNode = at(i).node();
209 TreeScope& currentTreeScope = currentNode->treeScope();
210 if (lastTreeScope != ¤tTreeScope) {
211 lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, ¤tTreeScope, treeScopeEventContextMap);
213 ASSERT(lastTreeScopeEventContext);
214 at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
215 lastTreeScope = ¤tTreeScope;
217 m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
220 void EventPath::buildRelatedNodeMap(const Node* relatedNode, RelatedTargetMap& relatedTargetMap)
222 EventPath relatedTargetEventPath(const_cast<Node*>(relatedNode));
223 for (size_t i = 0; i < relatedTargetEventPath.m_treeScopeEventContexts.size(); ++i) {
224 TreeScopeEventContext* treeScopeEventContext = relatedTargetEventPath.m_treeScopeEventContexts[i].get();
225 relatedTargetMap.add(&treeScopeEventContext->treeScope(), treeScopeEventContext->target());
229 EventTarget* EventPath::findRelatedNode(TreeScope* scope, RelatedTargetMap& relatedTargetMap)
231 WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32> parentTreeScopes;
232 EventTarget* relatedNode = 0;
234 parentTreeScopes.append(scope);
235 RelatedTargetMap::const_iterator iter = relatedTargetMap.find(scope);
236 if (iter != relatedTargetMap.end() && iter->value) {
237 relatedNode = iter->value;
240 scope = scope->olderShadowRootOrParentTreeScope();
243 for (WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32>::iterator iter = parentTreeScopes.begin(); iter < parentTreeScopes.end(); ++iter)
244 relatedTargetMap.add(*iter, relatedNode);
248 void EventPath::adjustForRelatedTarget(Node* target, EventTarget* relatedTarget)
254 Node* relatedNode = relatedTarget->toNode();
257 if (target->document() != relatedNode->document())
259 if (!target->inDocument() || !relatedNode->inDocument())
262 RelatedTargetMap relatedNodeMap;
263 buildRelatedNodeMap(relatedNode, relatedNodeMap);
265 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
266 TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
267 EventTarget* adjustedRelatedTarget = findRelatedNode(&treeScopeEventContext->treeScope(), relatedNodeMap);
268 ASSERT(adjustedRelatedTarget);
269 treeScopeEventContext->setRelatedTarget(adjustedRelatedTarget);
272 shrinkIfNeeded(target, relatedTarget);
275 void EventPath::shrinkIfNeeded(const Node* target, const EventTarget* relatedTarget)
277 // Synthetic mouse events can have a relatedTarget which is identical to the target.
278 bool targetIsIdenticalToToRelatedTarget = (target == relatedTarget);
280 for (size_t i = 0; i < size(); ++i) {
281 if (targetIsIdenticalToToRelatedTarget) {
282 if (target->treeScope().rootNode() == at(i).node()) {
286 } else if (at(i).target() == at(i).relatedTarget()) {
287 // Event dispatching should be stopped here.
294 void EventPath::adjustForTouchEvent(Node* node, TouchEvent& touchEvent)
296 WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouches;
297 WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTargetTouches;
298 WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedChangedTouches;
299 WillBeHeapVector<RawPtrWillBeMember<TreeScope> > treeScopes;
301 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
302 TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->ensureTouchEventContext();
303 adjustedTouches.append(&touchEventContext->touches());
304 adjustedTargetTouches.append(&touchEventContext->targetTouches());
305 adjustedChangedTouches.append(&touchEventContext->changedTouches());
306 treeScopes.append(&m_treeScopeEventContexts[i]->treeScope());
309 adjustTouchList(node, touchEvent.touches(), adjustedTouches, treeScopes);
310 adjustTouchList(node, touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
311 adjustTouchList(node, touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);
314 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
315 TreeScope& treeScope = m_treeScopeEventContexts[i]->treeScope();
316 TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->touchEventContext();
317 checkReachability(treeScope, touchEventContext->touches());
318 checkReachability(treeScope, touchEventContext->targetTouches());
319 checkReachability(treeScope, touchEventContext->changedTouches());
324 void EventPath::adjustTouchList(const Node* node, const TouchList* touchList, WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouchList, const WillBeHeapVector<RawPtrWillBeMember<TreeScope> >& treeScopes)
328 for (size_t i = 0; i < touchList->length(); ++i) {
329 const Touch& touch = *touchList->item(i);
330 RelatedTargetMap relatedNodeMap;
331 buildRelatedNodeMap(touch.target()->toNode(), relatedNodeMap);
332 for (size_t j = 0; j < treeScopes.size(); ++j) {
333 adjustedTouchList[j]->append(touch.cloneWithNewTarget(findRelatedNode(treeScopes[j], relatedNodeMap)));
339 void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList)
341 for (size_t i = 0; i < touchList.length(); ++i)
342 ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope));
346 void EventPath::trace(Visitor* visitor)
348 visitor->trace(m_nodeEventContexts);
349 visitor->trace(m_node);
350 visitor->trace(m_event);
351 visitor->trace(m_treeScopeEventContexts);