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 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 69 EventPath::EventPath(Event* event) 70 : m_node(nullptr) 71 , m_event(event) 72 { 73 } 74 75 EventPath::EventPath(Node* node) 76 : m_node(node) 77 , m_event(nullptr) 78 { 79 resetWith(node); 80 } 81 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 93 void EventPath::addNodeEventContext(Node* node) 94 { 95 m_nodeEventContexts.append(NodeEventContext(node, eventTargetRespectingTargetRules(node))); 96 } 97 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 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 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 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 != ¤tTreeScope) { 203 lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, ¤tTreeScope, treeScopeEventContextMap); 204 } 205 ASSERT(lastTreeScopeEventContext); 206 at(i).setTreeScopeEventContext(lastTreeScopeEventContext); 207 lastTreeScope = ¤tTreeScope; 208 } 209 m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end()); 210 } 211 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 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 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 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 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 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) 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 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