Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / events / EventPath.cpp
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
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
51 static inline bool inTheSameScope(ShadowRoot* shadowRoot, EventTarget* target)
52 {
53     return target->toNode() && target->toNode()->treeScope().rootNode() == shadowRoot;
54 }
55
56 static inline EventDispatchBehavior determineDispatchBehavior(Event* event, ShadowRoot* shadowRoot, EventTarget* target)
57 {
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;
73
74     return RetargetEvent;
75 }
76
77 EventPath::EventPath(Event* event)
78     : m_node(nullptr)
79     , m_event(event)
80 {
81 }
82
83 EventPath::EventPath(Node* node)
84     : m_node(node)
85     , m_event(nullptr)
86 {
87     resetWith(node);
88 }
89
90 void EventPath::resetWith(Node* node)
91 {
92     ASSERT(node);
93     m_node = node;
94     m_nodeEventContexts.clear();
95     m_treeScopeEventContexts.clear();
96     calculatePath();
97     calculateAdjustedTargets();
98     calculateTreeScopePrePostOrderNumbers();
99 }
100
101 void EventPath::addNodeEventContext(Node* node)
102 {
103     m_nodeEventContexts.append(NodeEventContext(node, eventTargetRespectingTargetRules(node)));
104 }
105
106 void EventPath::calculatePath()
107 {
108     ASSERT(m_node);
109     ASSERT(m_nodeEventContexts.isEmpty());
110     m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node.get()));
111
112     Node* current = m_node;
113     addNodeEventContext(current);
114     if (!m_node->inDocument())
115         return;
116     while (current) {
117         if (m_event && current->keepEventInNode(m_event))
118             break;
119         if (current->isShadowRoot() && m_event && determineDispatchBehavior(m_event, toShadowRoot(current), m_node) == StayInsideShadowDOM)
120             break;
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());
131                 }
132                 addNodeEventContext(insertionPoint);
133             }
134             current = insertionPoints.last();
135             continue;
136         }
137         if (current->isShadowRoot()) {
138             current = current->shadowHost();
139             addNodeEventContext(current);
140         } else {
141             current = current->parentNode();
142             if (current)
143                 addNodeEventContext(current);
144         }
145     }
146 }
147
148 void EventPath::calculateTreeScopePrePostOrderNumbers()
149 {
150     // Precondition:
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();
162         if (!parent) {
163             ASSERT(!rootTree);
164             rootTree = treeScopeEventContext;
165             continue;
166         }
167         ASSERT(treeScopeEventContextMap.find(parent) != treeScopeEventContextMap.end());
168         treeScopeEventContextMap.find(parent)->value->addChild(*treeScopeEventContext);
169     }
170     ASSERT(rootTree);
171     rootTree->calculatePrePostOrderNumber(0);
172 }
173
174 TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap)
175 {
176     if (!treeScope)
177         return 0;
178     TreeScopeEventContext* treeScopeEventContext;
179     bool isNewEntry;
180     {
181         TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(treeScope, nullptr);
182         isNewEntry = addResult.isNewEntry;
183         if (isNewEntry)
184             addResult.storedValue->value = TreeScopeEventContext::create(*treeScope);
185         treeScopeEventContext = addResult.storedValue->value.get();
186     }
187     if (isNewEntry) {
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));
193         }
194     } else if (!treeScopeEventContext->target() && currentTarget) {
195         treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
196     }
197     return treeScopeEventContext;
198 }
199
200 void EventPath::calculateAdjustedTargets()
201 {
202     const TreeScope* lastTreeScope = 0;
203
204     TreeScopeEventContextMap treeScopeEventContextMap;
205     TreeScopeEventContext* lastTreeScopeEventContext = 0;
206
207     for (size_t i = 0; i < size(); ++i) {
208         Node* currentNode = at(i).node();
209         TreeScope& currentTreeScope = currentNode->treeScope();
210         if (lastTreeScope != &currentTreeScope) {
211             lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, &currentTreeScope, treeScopeEventContextMap);
212         }
213         ASSERT(lastTreeScopeEventContext);
214         at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
215         lastTreeScope = &currentTreeScope;
216     }
217     m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
218 }
219
220 void EventPath::buildRelatedNodeMap(const Node* relatedNode, RelatedTargetMap& relatedTargetMap)
221 {
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());
226     }
227 }
228
229 EventTarget* EventPath::findRelatedNode(TreeScope* scope, RelatedTargetMap& relatedTargetMap)
230 {
231     WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32> parentTreeScopes;
232     EventTarget* relatedNode = 0;
233     while (scope) {
234         parentTreeScopes.append(scope);
235         RelatedTargetMap::const_iterator iter = relatedTargetMap.find(scope);
236         if (iter != relatedTargetMap.end() && iter->value) {
237             relatedNode = iter->value;
238             break;
239         }
240         scope = scope->olderShadowRootOrParentTreeScope();
241     }
242     ASSERT(relatedNode);
243     for (WillBeHeapVector<RawPtrWillBeMember<TreeScope>, 32>::iterator iter = parentTreeScopes.begin(); iter < parentTreeScopes.end(); ++iter)
244         relatedTargetMap.add(*iter, relatedNode);
245     return relatedNode;
246 }
247
248 void EventPath::adjustForRelatedTarget(Node* target, EventTarget* relatedTarget)
249 {
250     if (!target)
251         return;
252     if (!relatedTarget)
253         return;
254     Node* relatedNode = relatedTarget->toNode();
255     if (!relatedNode)
256         return;
257     if (target->document() != relatedNode->document())
258         return;
259     if (!target->inDocument() || !relatedNode->inDocument())
260         return;
261
262     RelatedTargetMap relatedNodeMap;
263     buildRelatedNodeMap(relatedNode, relatedNodeMap);
264
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);
270     }
271
272     shrinkIfNeeded(target, relatedTarget);
273 }
274
275 void EventPath::shrinkIfNeeded(const Node* target, const EventTarget* relatedTarget)
276 {
277     // Synthetic mouse events can have a relatedTarget which is identical to the target.
278     bool targetIsIdenticalToToRelatedTarget = (target == relatedTarget);
279
280     for (size_t i = 0; i < size(); ++i) {
281         if (targetIsIdenticalToToRelatedTarget) {
282             if (target->treeScope().rootNode() == at(i).node()) {
283                 shrink(i + 1);
284                 break;
285             }
286         } else if (at(i).target() == at(i).relatedTarget()) {
287             // Event dispatching should be stopped here.
288             shrink(i);
289             break;
290         }
291     }
292 }
293
294 void EventPath::adjustForTouchEvent(Node* node, TouchEvent& touchEvent)
295 {
296     WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouches;
297     WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTargetTouches;
298     WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedChangedTouches;
299     WillBeHeapVector<RawPtrWillBeMember<TreeScope> > treeScopes;
300
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());
307     }
308
309     adjustTouchList(node, touchEvent.touches(), adjustedTouches, treeScopes);
310     adjustTouchList(node, touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
311     adjustTouchList(node, touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);
312
313 #if ENABLE(ASSERT)
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());
320     }
321 #endif
322 }
323
324 void EventPath::adjustTouchList(const Node* node, const TouchList* touchList, WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouchList, const WillBeHeapVector<RawPtrWillBeMember<TreeScope> >& treeScopes)
325 {
326     if (!touchList)
327         return;
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)));
334         }
335     }
336 }
337
338 #if ENABLE(ASSERT)
339 void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList)
340 {
341     for (size_t i = 0; i < touchList.length(); ++i)
342         ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope));
343 }
344 #endif
345
346 void EventPath::trace(Visitor* visitor)
347 {
348     visitor->trace(m_nodeEventContexts);
349     visitor->trace(m_node);
350     visitor->trace(m_event);
351     visitor->trace(m_treeScopeEventContexts);
352 }
353
354 } // namespace