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 "EventNames.h"
31 #include "RuntimeEnabledFeatures.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"
47 // SVG1.1 specified that the <use> instance tree would expose the target
48 // element for events. This has been deprecated and will be removed.
49 // See: crbug.com/313438
50 static bool usesDeprecatedSVGUseTreeEventRules(Node* node)
52 return node->isSVGElement() && toSVGElement(node)->inUseShadowTree();
55 EventTarget* EventPath::eventTargetRespectingTargetRules(Node* referenceNode)
57 ASSERT(referenceNode);
59 if (referenceNode->isPseudoElement())
60 return referenceNode->parentNode();
62 if (!usesDeprecatedSVGUseTreeEventRules(referenceNode))
65 // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
66 // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects.
67 Node& rootNode = referenceNode->treeScope().rootNode();
68 Element* shadowHostElement = rootNode.isShadowRoot() ? toShadowRoot(rootNode).host() : 0;
69 // At this time, SVG nodes are not supported in non-<use> shadow trees.
70 if (!isSVGUseElement(shadowHostElement))
72 SVGUseElement& useElement = toSVGUseElement(*shadowHostElement);
73 if (SVGElementInstance* instance = useElement.instanceForShadowTreeElement(referenceNode))
79 static inline bool inTheSameScope(ShadowRoot* shadowRoot, EventTarget* target)
81 return target->toNode() && target->toNode()->treeScope().rootNode() == shadowRoot;
84 static inline EventDispatchBehavior determineDispatchBehavior(Event* event, ShadowRoot* shadowRoot, EventTarget* target)
86 // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
87 // Changing this breaks existing sites.
88 // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
89 const AtomicString eventType = event->type();
90 if (inTheSameScope(shadowRoot, target)
91 && (eventType == EventTypeNames::abort
92 || eventType == EventTypeNames::change
93 || eventType == EventTypeNames::error
94 || eventType == EventTypeNames::load
95 || eventType == EventTypeNames::reset
96 || eventType == EventTypeNames::resize
97 || eventType == EventTypeNames::scroll
98 || eventType == EventTypeNames::select
99 || eventType == EventTypeNames::selectstart))
100 return StayInsideShadowDOM;
102 return RetargetEvent;
105 EventPath::EventPath(Event* event)
111 EventPath::EventPath(Node* node)
118 void EventPath::resetWith(Node* node)
122 m_nodeEventContexts.clear();
123 m_treeScopeEventContexts.clear();
125 calculateAdjustedTargets();
126 if (!usesDeprecatedSVGUseTreeEventRules(node))
127 calculateTreeScopePrePostOrderNumbers();
130 void EventPath::addNodeEventContext(Node* node)
132 m_nodeEventContexts.append(NodeEventContext(node, eventTargetRespectingTargetRules(node)));
135 void EventPath::calculatePath()
138 ASSERT(m_nodeEventContexts.isEmpty());
139 m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node));
141 Node* current = m_node;
142 addNodeEventContext(current);
143 if (!m_node->inDocument())
146 if (current->isShadowRoot() && m_event && determineDispatchBehavior(m_event, toShadowRoot(current), m_node) == StayInsideShadowDOM)
148 Vector<InsertionPoint*, 8> insertionPoints;
149 collectDestinationInsertionPoints(*current, insertionPoints);
150 if (!insertionPoints.isEmpty()) {
151 for (size_t i = 0; i < insertionPoints.size(); ++i) {
152 InsertionPoint* insertionPoint = insertionPoints[i];
153 if (insertionPoint->isShadowInsertionPoint()) {
154 ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot();
155 ASSERT(containingShadowRoot);
156 if (!containingShadowRoot->isOldest())
157 addNodeEventContext(containingShadowRoot->olderShadowRoot());
159 addNodeEventContext(insertionPoint);
161 current = insertionPoints.last();
164 if (current->isShadowRoot()) {
165 current = current->shadowHost();
166 addNodeEventContext(current);
168 current = current->parentNode();
170 addNodeEventContext(current);
175 void EventPath::calculateTreeScopePrePostOrderNumbers()
178 // - TreeScopes in m_treeScopeEventContexts must be *connected* in the same tree of trees.
179 // - The root tree must be included.
180 HashMap<const TreeScope*, TreeScopeEventContext*> treeScopeEventContextMap;
181 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i)
182 treeScopeEventContextMap.add(&m_treeScopeEventContexts[i]->treeScope(), m_treeScopeEventContexts[i].get());
183 TreeScopeEventContext* rootTree = 0;
184 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
185 TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
186 // Use olderShadowRootOrParentTreeScope here for parent-child relationships.
187 // See the definition of trees of trees in the Shado DOM spec: http://w3c.github.io/webcomponents/spec/shadow/
188 TreeScope* parent = treeScopeEventContext->treeScope().olderShadowRootOrParentTreeScope();
191 rootTree = treeScopeEventContext;
194 ASSERT(treeScopeEventContextMap.find(parent) != treeScopeEventContextMap.end());
195 treeScopeEventContextMap.find(parent)->value->addChild(*treeScopeEventContext);
198 rootTree->calculatePrePostOrderNumber(0);
201 TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap)
205 TreeScopeEventContext* treeScopeEventContext;
208 TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(treeScope, nullptr);
209 if ((isNewEntry = addResult.isNewEntry))
210 addResult.storedValue->value = TreeScopeEventContext::create(*treeScope);
211 treeScopeEventContext = addResult.storedValue->value.get();
214 TreeScopeEventContext* parentTreeScopeEventContext = ensureTreeScopeEventContext(0, treeScope->olderShadowRootOrParentTreeScope(), treeScopeEventContextMap);
215 if (parentTreeScopeEventContext && parentTreeScopeEventContext->target()) {
216 treeScopeEventContext->setTarget(parentTreeScopeEventContext->target());
217 } else if (currentTarget) {
218 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
220 } else if (!treeScopeEventContext->target() && currentTarget) {
221 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
223 return treeScopeEventContext;
226 void EventPath::calculateAdjustedTargets()
228 const TreeScope* lastTreeScope = 0;
229 bool useDeprecatedSVGUseTreeEventRules = usesDeprecatedSVGUseTreeEventRules(at(0).node());
231 TreeScopeEventContextMap treeScopeEventContextMap;
232 TreeScopeEventContext* lastTreeScopeEventContext = 0;
234 for (size_t i = 0; i < size(); ++i) {
235 Node* currentNode = at(i).node();
236 TreeScope& currentTreeScope = currentNode->treeScope();
237 if (lastTreeScope != ¤tTreeScope) {
238 if (!useDeprecatedSVGUseTreeEventRules) {
239 lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, ¤tTreeScope, treeScopeEventContextMap);
241 TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(¤tTreeScope, TreeScopeEventContext::create(currentTreeScope));
242 lastTreeScopeEventContext = addResult.storedValue->value.get();
243 if (addResult.isNewEntry) {
244 // Don't adjust an event target for SVG.
245 lastTreeScopeEventContext->setTarget(eventTargetRespectingTargetRules(at(0).node()));
249 ASSERT(lastTreeScopeEventContext);
250 at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
251 lastTreeScope = ¤tTreeScope;
253 m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
256 void EventPath::buildRelatedNodeMap(const Node* relatedNode, RelatedTargetMap& relatedTargetMap)
258 EventPath relatedTargetEventPath(const_cast<Node*>(relatedNode));
259 for (size_t i = 0; i < relatedTargetEventPath.m_treeScopeEventContexts.size(); ++i) {
260 TreeScopeEventContext* treeScopeEventContext = relatedTargetEventPath.m_treeScopeEventContexts[i].get();
261 relatedTargetMap.add(&treeScopeEventContext->treeScope(), treeScopeEventContext->target());
265 EventTarget* EventPath::findRelatedNode(TreeScope* scope, RelatedTargetMap& relatedTargetMap)
267 Vector<TreeScope*, 32> parentTreeScopes;
268 EventTarget* relatedNode = 0;
270 parentTreeScopes.append(scope);
271 RelatedTargetMap::const_iterator iter = relatedTargetMap.find(scope);
272 if (iter != relatedTargetMap.end() && iter->value) {
273 relatedNode = iter->value;
276 scope = scope->olderShadowRootOrParentTreeScope();
279 for (Vector<TreeScope*, 32>::iterator iter = parentTreeScopes.begin(); iter < parentTreeScopes.end(); ++iter)
280 relatedTargetMap.add(*iter, relatedNode);
284 void EventPath::adjustForRelatedTarget(Node* target, EventTarget* relatedTarget)
290 Node* relatedNode = relatedTarget->toNode();
293 if (target->document() != relatedNode->document())
295 if (!target->inDocument() || !relatedNode->inDocument())
298 RelatedTargetMap relatedNodeMap;
299 buildRelatedNodeMap(relatedNode, relatedNodeMap);
301 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
302 TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
303 EventTarget* adjustedRelatedTarget = findRelatedNode(&treeScopeEventContext->treeScope(), relatedNodeMap);
304 ASSERT(adjustedRelatedTarget);
305 treeScopeEventContext->setRelatedTarget(adjustedRelatedTarget);
308 shrinkIfNeeded(target, relatedTarget);
311 void EventPath::shrinkIfNeeded(const Node* target, const EventTarget* relatedTarget)
313 // Synthetic mouse events can have a relatedTarget which is identical to the target.
314 bool targetIsIdenticalToToRelatedTarget = (target == relatedTarget);
316 for (size_t i = 0; i < size(); ++i) {
317 if (targetIsIdenticalToToRelatedTarget) {
318 if (target->treeScope().rootNode() == at(i).node()) {
322 } else if (at(i).target() == at(i).relatedTarget()) {
323 // Event dispatching should be stopped here.
330 void EventPath::adjustForTouchEvent(Node* node, TouchEvent& touchEvent)
332 WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouches;
333 WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTargetTouches;
334 WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedChangedTouches;
335 Vector<TreeScope*> treeScopes;
337 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
338 TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->ensureTouchEventContext();
339 adjustedTouches.append(&touchEventContext->touches());
340 adjustedTargetTouches.append(&touchEventContext->targetTouches());
341 adjustedChangedTouches.append(&touchEventContext->changedTouches());
342 treeScopes.append(&m_treeScopeEventContexts[i]->treeScope());
345 adjustTouchList(node, touchEvent.touches(), adjustedTouches, treeScopes);
346 adjustTouchList(node, touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
347 adjustTouchList(node, touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);
350 for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
351 TreeScope& treeScope = m_treeScopeEventContexts[i]->treeScope();
352 TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->touchEventContext();
353 checkReachability(treeScope, touchEventContext->touches());
354 checkReachability(treeScope, touchEventContext->targetTouches());
355 checkReachability(treeScope, touchEventContext->changedTouches());
360 void EventPath::adjustTouchList(const Node* node, const TouchList* touchList, WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouchList, const Vector<TreeScope*>& treeScopes)
364 for (size_t i = 0; i < touchList->length(); ++i) {
365 const Touch& touch = *touchList->item(i);
366 RelatedTargetMap relatedNodeMap;
367 buildRelatedNodeMap(touch.target()->toNode(), relatedNodeMap);
368 for (size_t j = 0; j < treeScopes.size(); ++j) {
369 adjustedTouchList[j]->append(touch.cloneWithNewTarget(findRelatedNode(treeScopes[j], relatedNodeMap)));
375 void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList)
377 for (size_t i = 0; i < touchList.length(); ++i)
378 ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope));
382 void EventPath::trace(Visitor* visitor)
384 visitor->trace(m_event);