• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 != &currentTreeScope) {
203             lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, &currentTreeScope, treeScopeEventContextMap);
204         }
205         ASSERT(lastTreeScopeEventContext);
206         at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
207         lastTreeScope = &currentTreeScope;
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