Upstream version 5.34.104.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 "EventNames.h"
31 #include "RuntimeEnabledFeatures.h"
32 #include "SVGNames.h"
33 #include "core/dom/FullscreenElementStack.h"
34 #include "core/dom/Touch.h"
35 #include "core/dom/TouchList.h"
36 #include "core/dom/shadow/InsertionPoint.h"
37 #include "core/dom/shadow/ShadowRoot.h"
38 #include "core/events/FocusEvent.h"
39 #include "core/events/MouseEvent.h"
40 #include "core/events/TouchEvent.h"
41 #include "core/events/TouchEventContext.h"
42 #include "core/svg/SVGElementInstance.h"
43 #include "core/svg/SVGUseElement.h"
44
45 namespace WebCore {
46
47 Node* EventPath::parent(Node* node)
48 {
49     EventPath eventPath(node);
50     return eventPath.size() > 1 ? eventPath[1].node() : 0;
51 }
52
53 EventTarget* EventPath::eventTargetRespectingTargetRules(Node* referenceNode)
54 {
55     ASSERT(referenceNode);
56
57     if (referenceNode->isPseudoElement())
58         return referenceNode->parentNode();
59
60     if (!referenceNode->isSVGElement() || !referenceNode->isInShadowTree())
61         return referenceNode;
62
63     // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
64     // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects.
65     Node& rootNode = referenceNode->treeScope().rootNode();
66     Element* shadowHostElement = rootNode.isShadowRoot() ? toShadowRoot(rootNode).host() : 0;
67     // At this time, SVG nodes are not supported in non-<use> shadow trees.
68     if (!shadowHostElement || !shadowHostElement->hasTagName(SVGNames::useTag))
69         return referenceNode;
70     SVGUseElement* useElement = toSVGUseElement(shadowHostElement);
71     if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(referenceNode))
72         return instance;
73
74     return referenceNode;
75 }
76
77 static inline bool inTheSameScope(ShadowRoot* shadowRoot, EventTarget* target)
78 {
79     return target->toNode() && target->toNode()->treeScope().rootNode() == shadowRoot;
80 }
81
82 static inline EventDispatchBehavior determineDispatchBehavior(Event* event, ShadowRoot* shadowRoot, EventTarget* target)
83 {
84     // Video-only full screen is a mode where we use the shadow DOM as an implementation
85     // detail that should not be detectable by the web content.
86     if (Element* element = FullscreenElementStack::currentFullScreenElementFrom(&target->toNode()->document())) {
87         // FIXME: We assume that if the full screen element is a media element that it's
88         // the video-only full screen. Both here and elsewhere. But that is probably wrong.
89         if (element->isMediaElement() && shadowRoot && shadowRoot->host() == element)
90             return StayInsideShadowDOM;
91     }
92
93     // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
94     // Changing this breaks existing sites.
95     // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
96     const AtomicString eventType = event->type();
97     if (inTheSameScope(shadowRoot, target)
98         && (eventType == EventTypeNames::abort
99             || eventType == EventTypeNames::change
100             || eventType == EventTypeNames::error
101             || eventType == EventTypeNames::load
102             || eventType == EventTypeNames::reset
103             || eventType == EventTypeNames::resize
104             || eventType == EventTypeNames::scroll
105             || eventType == EventTypeNames::select
106             || eventType == EventTypeNames::selectstart))
107         return StayInsideShadowDOM;
108
109     return RetargetEvent;
110 }
111
112 EventPath::EventPath(Event* event)
113     : m_node(0)
114     , m_event(event)
115 {
116 }
117
118 EventPath::EventPath(Node* node)
119     : m_node(node)
120     , m_event(0)
121 {
122     resetWith(node);
123 }
124
125 void EventPath::resetWith(Node* node)
126 {
127     ASSERT(node);
128     m_node = node;
129     m_nodeEventContexts.clear();
130     m_treeScopeEventContexts.clear();
131     calculatePath();
132     calculateAdjustedTargets();
133     calculateAdjustedEventPath();
134 }
135
136 void EventPath::addNodeEventContext(Node* node)
137 {
138     m_nodeEventContexts.append(NodeEventContext(node, eventTargetRespectingTargetRules(node)));
139 }
140
141 void EventPath::calculatePath()
142 {
143     ASSERT(m_node);
144     ASSERT(m_nodeEventContexts.isEmpty());
145     m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node));
146
147     Node* current = m_node;
148     addNodeEventContext(current);
149     if (!m_node->inDocument())
150         return;
151     while (current) {
152         if (current->isShadowRoot() && m_event && determineDispatchBehavior(m_event, toShadowRoot(current), m_node) == StayInsideShadowDOM)
153             break;
154         Vector<InsertionPoint*, 8> insertionPoints;
155         collectDestinationInsertionPoints(*current, insertionPoints);
156         if (!insertionPoints.isEmpty()) {
157             for (size_t i = 0; i < insertionPoints.size(); ++i) {
158                 InsertionPoint* insertionPoint = insertionPoints[i];
159                 if (insertionPoint->isShadowInsertionPoint()) {
160                     ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot();
161                     ASSERT(containingShadowRoot);
162                     if (!containingShadowRoot->isOldest())
163                         addNodeEventContext(containingShadowRoot->olderShadowRoot());
164                 }
165                 addNodeEventContext(insertionPoint);
166             }
167             current = insertionPoints.last();
168             continue;
169         }
170         if (current->isShadowRoot()) {
171             current = current->shadowHost();
172             addNodeEventContext(current);
173         } else {
174             current = current->parentNode();
175             if (current)
176                 addNodeEventContext(current);
177         }
178     }
179 }
180
181 void EventPath::calculateAdjustedEventPath()
182 {
183     if (!RuntimeEnabledFeatures::shadowDOMEnabled())
184         return;
185     for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
186         TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
187         Vector<RefPtr<Node> > nodes;
188         nodes.reserveInitialCapacity(size());
189         for (size_t i = 0; i < size(); ++i) {
190             if (at(i).node()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScopeEventContext->treeScope())) {
191                 ASSERT(!at(i).node()->containingShadowRoot()
192                     || at(i).node()->treeScope() == treeScopeEventContext->treeScope()
193                     || toShadowRoot(treeScopeEventContext->treeScope().rootNode()).type() == ShadowRoot::UserAgentShadowRoot
194                     || at(i).node()->containingShadowRoot()->type() != ShadowRoot::UserAgentShadowRoot);
195                 nodes.append(at(i).node());
196             }
197         }
198         treeScopeEventContext->adoptEventPath(nodes);
199     }
200 }
201
202 TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap)
203 {
204     if (!treeScope)
205         return 0;
206     TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(treeScope, TreeScopeEventContext::create(*treeScope));
207     TreeScopeEventContext* treeScopeEventContext = addResult.storedValue->value.get();
208     if (addResult.isNewEntry) {
209         TreeScopeEventContext* parentTreeScopeEventContext = ensureTreeScopeEventContext(0, treeScope->olderShadowRootOrParentTreeScope(), treeScopeEventContextMap);
210         if (parentTreeScopeEventContext && parentTreeScopeEventContext->target()) {
211             treeScopeEventContext->setTarget(parentTreeScopeEventContext->target());
212         } else if (currentTarget) {
213             treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
214         }
215     } else if (!treeScopeEventContext->target() && currentTarget) {
216         treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
217     }
218     return treeScopeEventContext;
219 }
220
221 void EventPath::calculateAdjustedTargets()
222 {
223     const TreeScope* lastTreeScope = 0;
224     bool isSVGElement = at(0).node()->isSVGElement();
225
226     TreeScopeEventContextMap treeScopeEventContextMap;
227     TreeScopeEventContext* lastTreeScopeEventContext = 0;
228
229     for (size_t i = 0; i < size(); ++i) {
230         Node* currentNode = at(i).node();
231         TreeScope& currentTreeScope = currentNode->treeScope();
232         if (lastTreeScope != &currentTreeScope) {
233             if (!isSVGElement) {
234                 lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, &currentTreeScope, treeScopeEventContextMap);
235             } else {
236                 TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(&currentTreeScope, TreeScopeEventContext::create(currentTreeScope));
237                 lastTreeScopeEventContext = addResult.storedValue->value.get();
238                 if (addResult.isNewEntry) {
239                     // Don't adjust an event target for SVG.
240                     lastTreeScopeEventContext->setTarget(eventTargetRespectingTargetRules(at(0).node()));
241                 }
242             }
243         }
244         ASSERT(lastTreeScopeEventContext);
245         at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
246         lastTreeScope = &currentTreeScope;
247     }
248     m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
249 }
250
251 void EventPath::buildRelatedNodeMap(const Node* relatedNode, RelatedTargetMap& relatedTargetMap)
252 {
253     EventPath relatedTargetEventPath(const_cast<Node*>(relatedNode));
254     for (size_t i = 0; i < relatedTargetEventPath.m_treeScopeEventContexts.size(); ++i) {
255         TreeScopeEventContext* treeScopeEventContext = relatedTargetEventPath.m_treeScopeEventContexts[i].get();
256         relatedTargetMap.add(&treeScopeEventContext->treeScope(), treeScopeEventContext->target());
257     }
258 }
259
260 EventTarget* EventPath::findRelatedNode(TreeScope* scope, RelatedTargetMap& relatedTargetMap)
261 {
262     Vector<TreeScope*, 32> parentTreeScopes;
263     EventTarget* relatedNode = 0;
264     while (scope) {
265         parentTreeScopes.append(scope);
266         RelatedTargetMap::const_iterator iter = relatedTargetMap.find(scope);
267         if (iter != relatedTargetMap.end() && iter->value) {
268             relatedNode = iter->value;
269             break;
270         }
271         scope = scope->olderShadowRootOrParentTreeScope();
272     }
273     ASSERT(relatedNode);
274     for (Vector<TreeScope*, 32>::iterator iter = parentTreeScopes.begin(); iter < parentTreeScopes.end(); ++iter)
275         relatedTargetMap.add(*iter, relatedNode);
276     return relatedNode;
277 }
278
279 void EventPath::adjustForRelatedTarget(Node* target, EventTarget* relatedTarget)
280 {
281     if (!target)
282         return;
283     if (!relatedTarget)
284         return;
285     Node* relatedNode = relatedTarget->toNode();
286     if (!relatedNode)
287         return;
288     if (target->document() != relatedNode->document())
289         return;
290     if (!target->inDocument() || !relatedNode->inDocument())
291         return;
292
293     RelatedTargetMap relatedNodeMap;
294     buildRelatedNodeMap(relatedNode, relatedNodeMap);
295
296     for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
297         TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
298         EventTarget* adjustedRelatedTarget = findRelatedNode(&treeScopeEventContext->treeScope(), relatedNodeMap);
299         ASSERT(adjustedRelatedTarget);
300         treeScopeEventContext->setRelatedTarget(adjustedRelatedTarget);
301     }
302
303     shrinkIfNeeded(target, relatedTarget);
304 }
305
306 void EventPath::shrinkIfNeeded(const Node* target, const EventTarget* relatedTarget)
307 {
308     // Synthetic mouse events can have a relatedTarget which is identical to the target.
309     bool targetIsIdenticalToToRelatedTarget = (target == relatedTarget);
310
311     for (size_t i = 0; i < size(); ++i) {
312         if (targetIsIdenticalToToRelatedTarget) {
313             if (target->treeScope().rootNode() == at(i).node()) {
314                 shrink(i + 1);
315                 break;
316             }
317         } else if (at(i).target() == at(i).relatedTarget()) {
318             // Event dispatching should be stopped here.
319             shrink(i);
320             break;
321         }
322     }
323 }
324
325 void EventPath::adjustForTouchEvent(Node* node, TouchEvent& touchEvent)
326 {
327     Vector<TouchList*> adjustedTouches;
328     Vector<TouchList*> adjustedTargetTouches;
329     Vector<TouchList*> adjustedChangedTouches;
330     Vector<TreeScope*> treeScopes;
331
332     for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
333         TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->ensureTouchEventContext();
334         adjustedTouches.append(&touchEventContext->touches());
335         adjustedTargetTouches.append(&touchEventContext->targetTouches());
336         adjustedChangedTouches.append(&touchEventContext->changedTouches());
337         treeScopes.append(&m_treeScopeEventContexts[i]->treeScope());
338     }
339
340     adjustTouchList(node, touchEvent.touches(), adjustedTouches, treeScopes);
341     adjustTouchList(node, touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
342     adjustTouchList(node, touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);
343
344 #ifndef NDEBUG
345     for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
346         TreeScope& treeScope = m_treeScopeEventContexts[i]->treeScope();
347         TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->touchEventContext();
348         checkReachability(treeScope, touchEventContext->touches());
349         checkReachability(treeScope, touchEventContext->targetTouches());
350         checkReachability(treeScope, touchEventContext->changedTouches());
351     }
352 #endif
353 }
354
355 void EventPath::adjustTouchList(const Node* node, const TouchList* touchList, Vector<TouchList*> adjustedTouchList, const Vector<TreeScope*>& treeScopes)
356 {
357     if (!touchList)
358         return;
359     for (size_t i = 0; i < touchList->length(); ++i) {
360         const Touch& touch = *touchList->item(i);
361         RelatedTargetMap relatedNodeMap;
362         buildRelatedNodeMap(touch.target()->toNode(), relatedNodeMap);
363         for (size_t j = 0; j < treeScopes.size(); ++j) {
364             adjustedTouchList[j]->append(touch.cloneWithNewTarget(findRelatedNode(treeScopes[j], relatedNodeMap)));
365         }
366     }
367 }
368
369 #ifndef NDEBUG
370 void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList)
371 {
372     for (size_t i = 0; i < touchList.length(); ++i)
373         ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope));
374 }
375 #endif
376
377 } // namespace