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 Node* EventPath::parent(Node* node)
49 EventPath eventPath(node);
50 return eventPath.size() > 1 ? eventPath[1].node() : 0;
53 EventTarget* EventPath::eventTargetRespectingTargetRules(Node* referenceNode)
55 ASSERT(referenceNode);
57 if (referenceNode->isPseudoElement())
58 return referenceNode->parentNode();
60 if (!referenceNode->isSVGElement() || !referenceNode->isInShadowTree())
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))
70 SVGUseElement* useElement = toSVGUseElement(shadowHostElement);
71 if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(referenceNode))
77 static inline bool inTheSameScope(ShadowRoot* shadowRoot, EventTarget* target)
79 return target->toNode() && target->toNode()->treeScope().rootNode() == shadowRoot;
82 static inline EventDispatchBehavior determineDispatchBehavior(Event* event, ShadowRoot* shadowRoot, EventTarget* target)
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;
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;
109 return RetargetEvent;
112 EventPath::EventPath(Event* event)
118 EventPath::EventPath(Node* node)
125 void EventPath::resetWith(Node* node)
129 m_nodeEventContexts.clear();
130 m_treeScopeEventContexts.clear();
132 calculateAdjustedTargets();
133 calculateAdjustedEventPath();
136 void EventPath::addNodeEventContext(Node* node)
138 m_nodeEventContexts.append(NodeEventContext(node, eventTargetRespectingTargetRules(node)));
141 void EventPath::calculatePath()
144 ASSERT(m_nodeEventContexts.isEmpty());
145 m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node));
147 Node* current = m_node;
148 addNodeEventContext(current);
149 if (!m_node->inDocument())
152 if (current->isShadowRoot() && m_event && determineDispatchBehavior(m_event, toShadowRoot(current), m_node) == StayInsideShadowDOM)
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());
165 addNodeEventContext(insertionPoint);
167 current = insertionPoints.last();
170 if (current->isShadowRoot()) {
171 current = current->shadowHost();
172 addNodeEventContext(current);
174 current = current->parentNode();
176 addNodeEventContext(current);
181 void EventPath::calculateAdjustedEventPath()
183 if (!RuntimeEnabledFeatures::shadowDOMEnabled())
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());
198 treeScopeEventContext->adoptEventPath(nodes);
202 TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap)
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));
215 } else if (!treeScopeEventContext->target() && currentTarget) {
216 treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
218 return treeScopeEventContext;
221 void EventPath::calculateAdjustedTargets()
223 const TreeScope* lastTreeScope = 0;
224 bool isSVGElement = at(0).node()->isSVGElement();
226 TreeScopeEventContextMap treeScopeEventContextMap;
227 TreeScopeEventContext* lastTreeScopeEventContext = 0;
229 for (size_t i = 0; i < size(); ++i) {
230 Node* currentNode = at(i).node();
231 TreeScope& currentTreeScope = currentNode->treeScope();
232 if (lastTreeScope != ¤tTreeScope) {
234 lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, ¤tTreeScope, treeScopeEventContextMap);
236 TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(¤tTreeScope, 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()));
244 ASSERT(lastTreeScopeEventContext);
245 at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
246 lastTreeScope = ¤tTreeScope;
248 m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
251 void EventPath::buildRelatedNodeMap(const Node* relatedNode, RelatedTargetMap& relatedTargetMap)
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());
260 EventTarget* EventPath::findRelatedNode(TreeScope* scope, RelatedTargetMap& relatedTargetMap)
262 Vector<TreeScope*, 32> parentTreeScopes;
263 EventTarget* relatedNode = 0;
265 parentTreeScopes.append(scope);
266 RelatedTargetMap::const_iterator iter = relatedTargetMap.find(scope);
267 if (iter != relatedTargetMap.end() && iter->value) {
268 relatedNode = iter->value;
271 scope = scope->olderShadowRootOrParentTreeScope();
274 for (Vector<TreeScope*, 32>::iterator iter = parentTreeScopes.begin(); iter < parentTreeScopes.end(); ++iter)
275 relatedTargetMap.add(*iter, relatedNode);
279 void EventPath::adjustForRelatedTarget(Node* target, EventTarget* relatedTarget)
285 Node* relatedNode = relatedTarget->toNode();
288 if (target->document() != relatedNode->document())
290 if (!target->inDocument() || !relatedNode->inDocument())
293 RelatedTargetMap relatedNodeMap;
294 buildRelatedNodeMap(relatedNode, relatedNodeMap);
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);
303 shrinkIfNeeded(target, relatedTarget);
306 void EventPath::shrinkIfNeeded(const Node* target, const EventTarget* relatedTarget)
308 // Synthetic mouse events can have a relatedTarget which is identical to the target.
309 bool targetIsIdenticalToToRelatedTarget = (target == relatedTarget);
311 for (size_t i = 0; i < size(); ++i) {
312 if (targetIsIdenticalToToRelatedTarget) {
313 if (target->treeScope().rootNode() == at(i).node()) {
317 } else if (at(i).target() == at(i).relatedTarget()) {
318 // Event dispatching should be stopped here.
325 void EventPath::adjustForTouchEvent(Node* node, TouchEvent& touchEvent)
327 Vector<TouchList*> adjustedTouches;
328 Vector<TouchList*> adjustedTargetTouches;
329 Vector<TouchList*> adjustedChangedTouches;
330 Vector<TreeScope*> treeScopes;
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());
340 adjustTouchList(node, touchEvent.touches(), adjustedTouches, treeScopes);
341 adjustTouchList(node, touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
342 adjustTouchList(node, touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);
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());
355 void EventPath::adjustTouchList(const Node* node, const TouchList* touchList, Vector<TouchList*> adjustedTouchList, const Vector<TreeScope*>& treeScopes)
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)));
370 void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList)
372 for (size_t i = 0; i < touchList.length(); ++i)
373 ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope));