1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
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.
13 *
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.
25 */
26
27 #include "config.h"
28 #include "core/events/EventPath.h"
29
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"
38
39 namespace blink {
40
eventTargetRespectingTargetRules(Node * referenceNode)41 EventTarget* EventPath::eventTargetRespectingTargetRules(Node* referenceNode)
42 {
43 ASSERT(referenceNode);
44
45 if (referenceNode->isPseudoElement())
46 return referenceNode->parentNode();
47
48 return referenceNode;
49 }
50
shouldStopAtShadowRoot(Event & event,ShadowRoot & shadowRoot,EventTarget & target)51 static inline bool shouldStopAtShadowRoot(Event& event, ShadowRoot& shadowRoot, EventTarget& target)
52 {
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);
67 }
68
EventPath(Event * event)69 EventPath::EventPath(Event* event)
70 : m_node(nullptr)
71 , m_event(event)
72 {
73 }
74
EventPath(Node * node)75 EventPath::EventPath(Node* node)
76 : m_node(node)
77 , m_event(nullptr)
78 {
79 resetWith(node);
80 }
81
resetWith(Node * node)82 void EventPath::resetWith(Node* node)
83 {
84 ASSERT(node);
85 m_node = node;
86 m_nodeEventContexts.clear();
87 m_treeScopeEventContexts.clear();
88 calculatePath();
89 calculateAdjustedTargets();
90 calculateTreeScopePrePostOrderNumbers();
91 }
92
addNodeEventContext(Node * node)93 void EventPath::addNodeEventContext(Node* node)
94 {
95 m_nodeEventContexts.append(NodeEventContext(node, eventTargetRespectingTargetRules(node)));
96 }
97
calculatePath()98 void EventPath::calculatePath()
99 {
100 ASSERT(m_node);
101 ASSERT(m_nodeEventContexts.isEmpty());
102 m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node.get()));
103
104 Node* current = m_node;
105 addNodeEventContext(current);
106 if (!m_node->inDocument())
107 return;
108 while (current) {
109 if (m_event && current->keepEventInNode(m_event))
110 break;
111 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
112 collectDestinationInsertionPoints(*current, insertionPoints);
113 if (!insertionPoints.isEmpty()) {
114 for (size_t i = 0; i < insertionPoints.size(); ++i) {
115 InsertionPoint* insertionPoint = insertionPoints[i];
116 if (insertionPoint->isShadowInsertionPoint()) {
117 ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot();
118 ASSERT(containingShadowRoot);
119 if (!containingShadowRoot->isOldest())
120 addNodeEventContext(containingShadowRoot->olderShadowRoot());
121 }
122 addNodeEventContext(insertionPoint);
123 }
124 current = insertionPoints.last();
125 continue;
126 }
127 if (current->isShadowRoot()) {
128 if (m_event && shouldStopAtShadowRoot(*m_event, *toShadowRoot(current), *m_node))
129 break;
130 current = current->shadowHost();
131 addNodeEventContext(current);
132 } else {
133 current = current->parentNode();
134 if (current)
135 addNodeEventContext(current);
136 }
137 }
138 }
139
calculateTreeScopePrePostOrderNumbers()140 void EventPath::calculateTreeScopePrePostOrderNumbers()
141 {
142 // Precondition:
143 // - TreeScopes in m_treeScopeEventContexts must be *connected* in the same tree of trees.
144 // - The root tree must be included.
145 WillBeHeapHashMap<RawPtrWillBeMember<const TreeScope>, RawPtrWillBeMember<TreeScopeEventContext> > treeScopeEventContextMap;
146 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i)
147 treeScopeEventContextMap.add(&m_treeScopeEventContexts[i]->treeScope(), m_treeScopeEventContexts[i].get());
148 TreeScopeEventContext* rootTree = 0;
149 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
150 TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
151 // Use olderShadowRootOrParentTreeScope here for parent-child relationships.
152 // See the definition of trees of trees in the Shado DOM spec: http://w3c.github.io/webcomponents/spec/shadow/
153 TreeScope* parent = treeScopeEventContext->treeScope().olderShadowRootOrParentTreeScope();
154 if (!parent) {
155 ASSERT(!rootTree);
156 rootTree = treeScopeEventContext;
157 continue;
158 }
159 ASSERT(treeScopeEventContextMap.find(parent) != treeScopeEventContextMap.end());
160 treeScopeEventContextMap.find(parent)->value->addChild(*treeScopeEventContext);
161 }
162 ASSERT(rootTree);
163 rootTree->calculatePrePostOrderNumber(0);
164 }
165
ensureTreeScopeEventContext(Node * currentTarget,TreeScope * treeScope,TreeScopeEventContextMap & treeScopeEventContextMap)166 TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap)
167 {
168 if (!treeScope)
169 return 0;
170 TreeScopeEventContext* treeScopeEventContext;
171 bool isNewEntry;
172 {
173 TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(treeScope, nullptr);
174 isNewEntry = addResult.isNewEntry;
175 if (isNewEntry)
176 addResult.storedValue->value = TreeScopeEventContext::create(*treeScope);
177 treeScopeEventContext = addResult.storedValue->value.get();
178 }
179 if (isNewEntry) {
180 TreeScopeEventContext* parentTreeScopeEventContext = ensureTreeScopeEventContext(0, treeScope->olderShadowRootOrParentTreeScope(), treeScopeEventContextMap);
181 if (parentTreeScopeEventContext && parentTreeScopeEventContext->target()) {
182 treeScopeEventContext->setTarget(parentTreeScopeEventContext->target());
183 } else if (currentTarget) {
184 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
185 }
186 } else if (!treeScopeEventContext->target() && currentTarget) {
187 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
188 }
189 return treeScopeEventContext;
190 }
191
calculateAdjustedTargets()192 void EventPath::calculateAdjustedTargets()
193 {
194 const TreeScope* lastTreeScope = 0;
195
196 TreeScopeEventContextMap treeScopeEventContextMap;
197 TreeScopeEventContext* lastTreeScopeEventContext = 0;
198
199 for (size_t i = 0; i < size(); ++i) {
200 Node* currentNode = at(i).node();
201 TreeScope& currentTreeScope = currentNode->treeScope();
202 if (lastTreeScope != ¤tTreeScope) {
203 lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, ¤tTreeScope, treeScopeEventContextMap);
204 }
205 ASSERT(lastTreeScopeEventContext);
206 at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
207 lastTreeScope = ¤tTreeScope;
208 }
209 m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
210 }
211
buildRelatedNodeMap(const Node * relatedNode,RelatedTargetMap & relatedTargetMap)212 void EventPath::buildRelatedNodeMap(const Node* relatedNode, RelatedTargetMap& relatedTargetMap)
213 {
214 EventPath relatedTargetEventPath(const_cast<Node*>(relatedNode));
215 for (size_t i = 0; i < relatedTargetEventPath.m_treeScopeEventContexts.size(); ++i) {
216 TreeScopeEventContext* treeScopeEventContext = relatedTargetEventPath.m_treeScopeEventContexts[i].get();
217 relatedTargetMap.add(&treeScopeEventContext->treeScope(), treeScopeEventContext->target());
218 }
219 }
220
findRelatedNode(TreeScope * scope,RelatedTargetMap & relatedTargetMap)221 EventTarget* EventPath::findRelatedNode(TreeScope* scope, RelatedTargetMap& relatedTargetMap)
222 {
223 WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32> parentTreeScopes;
224 EventTarget* relatedNode = 0;
225 while (scope) {
226 parentTreeScopes.append(scope);
227 RelatedTargetMap::const_iterator iter = relatedTargetMap.find(scope);
228 if (iter != relatedTargetMap.end() && iter->value) {
229 relatedNode = iter->value;
230 break;
231 }
232 scope = scope->olderShadowRootOrParentTreeScope();
233 }
234 ASSERT(relatedNode);
235 for (WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32>::iterator iter = parentTreeScopes.begin(); iter < parentTreeScopes.end(); ++iter)
236 relatedTargetMap.add(*iter, relatedNode);
237 return relatedNode;
238 }
239
adjustForRelatedTarget(Node * target,EventTarget * relatedTarget)240 void EventPath::adjustForRelatedTarget(Node* target, EventTarget* relatedTarget)
241 {
242 if (!target)
243 return;
244 if (!relatedTarget)
245 return;
246 Node* relatedNode = relatedTarget->toNode();
247 if (!relatedNode)
248 return;
249 if (target->document() != relatedNode->document())
250 return;
251 if (!target->inDocument() || !relatedNode->inDocument())
252 return;
253
254 RelatedTargetMap relatedNodeMap;
255 buildRelatedNodeMap(relatedNode, relatedNodeMap);
256
257 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
258 TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
259 EventTarget* adjustedRelatedTarget = findRelatedNode(&treeScopeEventContext->treeScope(), relatedNodeMap);
260 ASSERT(adjustedRelatedTarget);
261 treeScopeEventContext->setRelatedTarget(adjustedRelatedTarget);
262 }
263
264 shrinkIfNeeded(target, relatedTarget);
265 }
266
shrinkIfNeeded(const Node * target,const EventTarget * relatedTarget)267 void EventPath::shrinkIfNeeded(const Node* target, const EventTarget* relatedTarget)
268 {
269 // Synthetic mouse events can have a relatedTarget which is identical to the target.
270 bool targetIsIdenticalToToRelatedTarget = (target == relatedTarget);
271
272 for (size_t i = 0; i < size(); ++i) {
273 if (targetIsIdenticalToToRelatedTarget) {
274 if (target->treeScope().rootNode() == at(i).node()) {
275 shrink(i + 1);
276 break;
277 }
278 } else if (at(i).target() == at(i).relatedTarget()) {
279 // Event dispatching should be stopped here.
280 shrink(i);
281 break;
282 }
283 }
284 }
285
adjustForTouchEvent(Node * node,TouchEvent & touchEvent)286 void EventPath::adjustForTouchEvent(Node* node, TouchEvent& touchEvent)
287 {
288 WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouches;
289 WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTargetTouches;
290 WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedChangedTouches;
291 WillBeHeapVector<RawPtrWillBeMember<TreeScope> > treeScopes;
292
293 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
294 TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->ensureTouchEventContext();
295 adjustedTouches.append(&touchEventContext->touches());
296 adjustedTargetTouches.append(&touchEventContext->targetTouches());
297 adjustedChangedTouches.append(&touchEventContext->changedTouches());
298 treeScopes.append(&m_treeScopeEventContexts[i]->treeScope());
299 }
300
301 adjustTouchList(node, touchEvent.touches(), adjustedTouches, treeScopes);
302 adjustTouchList(node, touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
303 adjustTouchList(node, touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);
304
305 #if ENABLE(ASSERT)
306 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
307 TreeScope& treeScope = m_treeScopeEventContexts[i]->treeScope();
308 TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->touchEventContext();
309 checkReachability(treeScope, touchEventContext->touches());
310 checkReachability(treeScope, touchEventContext->targetTouches());
311 checkReachability(treeScope, touchEventContext->changedTouches());
312 }
313 #endif
314 }
315
adjustTouchList(const Node * node,const TouchList * touchList,WillBeHeapVector<RawPtrWillBeMember<TouchList>> adjustedTouchList,const WillBeHeapVector<RawPtrWillBeMember<TreeScope>> & treeScopes)316 void EventPath::adjustTouchList(const Node* node, const TouchList* touchList, WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouchList, const WillBeHeapVector<RawPtrWillBeMember<TreeScope> >& treeScopes)
317 {
318 if (!touchList)
319 return;
320 for (size_t i = 0; i < touchList->length(); ++i) {
321 const Touch& touch = *touchList->item(i);
322 RelatedTargetMap relatedNodeMap;
323 buildRelatedNodeMap(touch.target()->toNode(), relatedNodeMap);
324 for (size_t j = 0; j < treeScopes.size(); ++j) {
325 adjustedTouchList[j]->append(touch.cloneWithNewTarget(findRelatedNode(treeScopes[j], relatedNodeMap)));
326 }
327 }
328 }
329
330 #if ENABLE(ASSERT)
checkReachability(TreeScope & treeScope,TouchList & touchList)331 void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList)
332 {
333 for (size_t i = 0; i < touchList.length(); ++i)
334 ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope));
335 }
336 #endif
337
trace(Visitor * visitor)338 void EventPath::trace(Visitor* visitor)
339 {
340 visitor->trace(m_nodeEventContexts);
341 visitor->trace(m_node);
342 visitor->trace(m_event);
343 visitor->trace(m_treeScopeEventContexts);
344 }
345
346 } // namespace
347