Home | History | Annotate | Download | only in events
      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 != &currentTreeScope) {
    203             lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, &currentTreeScope, treeScopeEventContextMap);
    204         }
    205         ASSERT(lastTreeScopeEventContext);
    206         at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
    207         lastTreeScope = &currentTreeScope;
    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