This source file includes following definitions.
- eventTargetRespectingTargetRules
- inTheSameScope
- determineDispatchBehavior
- m_event
- m_event
- resetWith
- addNodeEventContext
- calculatePath
- calculateTreeScopePrePostOrderNumbers
- ensureTreeScopeEventContext
- calculateAdjustedTargets
- buildRelatedNodeMap
- findRelatedNode
- adjustForRelatedTarget
- shrinkIfNeeded
- adjustForTouchEvent
- adjustTouchList
- checkReachability
- trace
#include "config.h"
#include "core/events/EventPath.h"
#include "EventNames.h"
#include "RuntimeEnabledFeatures.h"
#include "SVGNames.h"
#include "core/dom/FullscreenElementStack.h"
#include "core/dom/Touch.h"
#include "core/dom/TouchList.h"
#include "core/dom/shadow/InsertionPoint.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/events/FocusEvent.h"
#include "core/events/MouseEvent.h"
#include "core/events/TouchEvent.h"
#include "core/events/TouchEventContext.h"
#include "core/svg/SVGElementInstance.h"
#include "core/svg/SVGUseElement.h"
namespace WebCore {
EventTarget* EventPath::eventTargetRespectingTargetRules(Node* referenceNode)
{
ASSERT(referenceNode);
if (referenceNode->isPseudoElement())
return referenceNode->parentNode();
if (!referenceNode->isSVGElement() || !referenceNode->isInShadowTree())
return referenceNode;
Node& rootNode = referenceNode->treeScope().rootNode();
Element* shadowHostElement = rootNode.isShadowRoot() ? toShadowRoot(rootNode).host() : 0;
if (!isSVGUseElement(shadowHostElement))
return referenceNode;
SVGUseElement& useElement = toSVGUseElement(*shadowHostElement);
if (SVGElementInstance* instance = useElement.instanceForShadowTreeElement(referenceNode))
return instance;
return referenceNode;
}
static inline bool inTheSameScope(ShadowRoot* shadowRoot, EventTarget* target)
{
return target->toNode() && target->toNode()->treeScope().rootNode() == shadowRoot;
}
static inline EventDispatchBehavior determineDispatchBehavior(Event* event, ShadowRoot* shadowRoot, EventTarget* target)
{
const AtomicString eventType = event->type();
if (inTheSameScope(shadowRoot, target)
&& (eventType == EventTypeNames::abort
|| eventType == EventTypeNames::change
|| eventType == EventTypeNames::error
|| eventType == EventTypeNames::load
|| eventType == EventTypeNames::reset
|| eventType == EventTypeNames::resize
|| eventType == EventTypeNames::scroll
|| eventType == EventTypeNames::select
|| eventType == EventTypeNames::selectstart))
return StayInsideShadowDOM;
return RetargetEvent;
}
EventPath::EventPath(Event* event)
: m_node(0)
, m_event(event)
{
}
EventPath::EventPath(Node* node)
: m_node(node)
, m_event(nullptr)
{
resetWith(node);
}
void EventPath::resetWith(Node* node)
{
ASSERT(node);
m_node = node;
m_nodeEventContexts.clear();
m_treeScopeEventContexts.clear();
calculatePath();
calculateAdjustedTargets();
if (!node->isSVGElement())
calculateTreeScopePrePostOrderNumbers();
}
void EventPath::addNodeEventContext(Node* node)
{
m_nodeEventContexts.append(NodeEventContext(node, eventTargetRespectingTargetRules(node)));
}
void EventPath::calculatePath()
{
ASSERT(m_node);
ASSERT(m_nodeEventContexts.isEmpty());
m_node->document().updateDistributionForNodeIfNeeded(const_cast<Node*>(m_node));
Node* current = m_node;
addNodeEventContext(current);
if (!m_node->inDocument())
return;
while (current) {
if (current->isShadowRoot() && m_event && determineDispatchBehavior(m_event, toShadowRoot(current), m_node) == StayInsideShadowDOM)
break;
Vector<InsertionPoint*, 8> insertionPoints;
collectDestinationInsertionPoints(*current, insertionPoints);
if (!insertionPoints.isEmpty()) {
for (size_t i = 0; i < insertionPoints.size(); ++i) {
InsertionPoint* insertionPoint = insertionPoints[i];
if (insertionPoint->isShadowInsertionPoint()) {
ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot();
ASSERT(containingShadowRoot);
if (!containingShadowRoot->isOldest())
addNodeEventContext(containingShadowRoot->olderShadowRoot());
}
addNodeEventContext(insertionPoint);
}
current = insertionPoints.last();
continue;
}
if (current->isShadowRoot()) {
current = current->shadowHost();
addNodeEventContext(current);
} else {
current = current->parentNode();
if (current)
addNodeEventContext(current);
}
}
}
void EventPath::calculateTreeScopePrePostOrderNumbers()
{
HashMap<const TreeScope*, TreeScopeEventContext*> treeScopeEventContextMap;
for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i)
treeScopeEventContextMap.add(&m_treeScopeEventContexts[i]->treeScope(), m_treeScopeEventContexts[i].get());
TreeScopeEventContext* rootTree = 0;
for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
TreeScope* parent = treeScopeEventContext->treeScope().olderShadowRootOrParentTreeScope();
if (!parent) {
ASSERT(!rootTree);
rootTree = treeScopeEventContext;
continue;
}
ASSERT(treeScopeEventContextMap.find(parent) != treeScopeEventContextMap.end());
treeScopeEventContextMap.find(parent)->value->addChild(*treeScopeEventContext);
}
ASSERT(rootTree);
rootTree->calculatePrePostOrderNumber(0);
}
TreeScopeEventContext* EventPath::ensureTreeScopeEventContext(Node* currentTarget, TreeScope* treeScope, TreeScopeEventContextMap& treeScopeEventContextMap)
{
if (!treeScope)
return 0;
TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(treeScope, TreeScopeEventContext::create(*treeScope));
TreeScopeEventContext* treeScopeEventContext = addResult.storedValue->value.get();
if (addResult.isNewEntry) {
TreeScopeEventContext* parentTreeScopeEventContext = ensureTreeScopeEventContext(0, treeScope->olderShadowRootOrParentTreeScope(), treeScopeEventContextMap);
if (parentTreeScopeEventContext && parentTreeScopeEventContext->target()) {
treeScopeEventContext->setTarget(parentTreeScopeEventContext->target());
} else if (currentTarget) {
treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
}
} else if (!treeScopeEventContext->target() && currentTarget) {
treeScopeEventContext->setTarget(eventTargetRespectingTargetRules(currentTarget));
}
return treeScopeEventContext;
}
void EventPath::calculateAdjustedTargets()
{
const TreeScope* lastTreeScope = 0;
bool isSVGElement = at(0).node()->isSVGElement();
TreeScopeEventContextMap treeScopeEventContextMap;
TreeScopeEventContext* lastTreeScopeEventContext = 0;
for (size_t i = 0; i < size(); ++i) {
Node* currentNode = at(i).node();
TreeScope& currentTreeScope = currentNode->treeScope();
if (lastTreeScope != ¤tTreeScope) {
if (!isSVGElement) {
lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, ¤tTreeScope, treeScopeEventContextMap);
} else {
TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(¤tTreeScope, TreeScopeEventContext::create(currentTreeScope));
lastTreeScopeEventContext = addResult.storedValue->value.get();
if (addResult.isNewEntry) {
lastTreeScopeEventContext->setTarget(eventTargetRespectingTargetRules(at(0).node()));
}
}
}
ASSERT(lastTreeScopeEventContext);
at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
lastTreeScope = ¤tTreeScope;
}
m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
}
void EventPath::buildRelatedNodeMap(const Node* relatedNode, RelatedTargetMap& relatedTargetMap)
{
EventPath relatedTargetEventPath(const_cast<Node*>(relatedNode));
for (size_t i = 0; i < relatedTargetEventPath.m_treeScopeEventContexts.size(); ++i) {
TreeScopeEventContext* treeScopeEventContext = relatedTargetEventPath.m_treeScopeEventContexts[i].get();
relatedTargetMap.add(&treeScopeEventContext->treeScope(), treeScopeEventContext->target());
}
}
EventTarget* EventPath::findRelatedNode(TreeScope* scope, RelatedTargetMap& relatedTargetMap)
{
Vector<TreeScope*, 32> parentTreeScopes;
EventTarget* relatedNode = 0;
while (scope) {
parentTreeScopes.append(scope);
RelatedTargetMap::const_iterator iter = relatedTargetMap.find(scope);
if (iter != relatedTargetMap.end() && iter->value) {
relatedNode = iter->value;
break;
}
scope = scope->olderShadowRootOrParentTreeScope();
}
ASSERT(relatedNode);
for (Vector<TreeScope*, 32>::iterator iter = parentTreeScopes.begin(); iter < parentTreeScopes.end(); ++iter)
relatedTargetMap.add(*iter, relatedNode);
return relatedNode;
}
void EventPath::adjustForRelatedTarget(Node* target, EventTarget* relatedTarget)
{
if (!target)
return;
if (!relatedTarget)
return;
Node* relatedNode = relatedTarget->toNode();
if (!relatedNode)
return;
if (target->document() != relatedNode->document())
return;
if (!target->inDocument() || !relatedNode->inDocument())
return;
RelatedTargetMap relatedNodeMap;
buildRelatedNodeMap(relatedNode, relatedNodeMap);
for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
TreeScopeEventContext* treeScopeEventContext = m_treeScopeEventContexts[i].get();
EventTarget* adjustedRelatedTarget = findRelatedNode(&treeScopeEventContext->treeScope(), relatedNodeMap);
ASSERT(adjustedRelatedTarget);
treeScopeEventContext->setRelatedTarget(adjustedRelatedTarget);
}
shrinkIfNeeded(target, relatedTarget);
}
void EventPath::shrinkIfNeeded(const Node* target, const EventTarget* relatedTarget)
{
bool targetIsIdenticalToToRelatedTarget = (target == relatedTarget);
for (size_t i = 0; i < size(); ++i) {
if (targetIsIdenticalToToRelatedTarget) {
if (target->treeScope().rootNode() == at(i).node()) {
shrink(i + 1);
break;
}
} else if (at(i).target() == at(i).relatedTarget()) {
shrink(i);
break;
}
}
}
void EventPath::adjustForTouchEvent(Node* node, TouchEvent& touchEvent)
{
WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouches;
WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTargetTouches;
WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedChangedTouches;
Vector<TreeScope*> treeScopes;
for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->ensureTouchEventContext();
adjustedTouches.append(&touchEventContext->touches());
adjustedTargetTouches.append(&touchEventContext->targetTouches());
adjustedChangedTouches.append(&touchEventContext->changedTouches());
treeScopes.append(&m_treeScopeEventContexts[i]->treeScope());
}
adjustTouchList(node, touchEvent.touches(), adjustedTouches, treeScopes);
adjustTouchList(node, touchEvent.targetTouches(), adjustedTargetTouches, treeScopes);
adjustTouchList(node, touchEvent.changedTouches(), adjustedChangedTouches, treeScopes);
#ifndef NDEBUG
for (size_t i = 0; i < m_treeScopeEventContexts.size(); ++i) {
TreeScope& treeScope = m_treeScopeEventContexts[i]->treeScope();
TouchEventContext* touchEventContext = m_treeScopeEventContexts[i]->touchEventContext();
checkReachability(treeScope, touchEventContext->touches());
checkReachability(treeScope, touchEventContext->targetTouches());
checkReachability(treeScope, touchEventContext->changedTouches());
}
#endif
}
void EventPath::adjustTouchList(const Node* node, const TouchList* touchList, WillBeHeapVector<RawPtrWillBeMember<TouchList> > adjustedTouchList, const Vector<TreeScope*>& treeScopes)
{
if (!touchList)
return;
for (size_t i = 0; i < touchList->length(); ++i) {
const Touch& touch = *touchList->item(i);
RelatedTargetMap relatedNodeMap;
buildRelatedNodeMap(touch.target()->toNode(), relatedNodeMap);
for (size_t j = 0; j < treeScopes.size(); ++j) {
adjustedTouchList[j]->append(touch.cloneWithNewTarget(findRelatedNode(treeScopes[j], relatedNodeMap)));
}
}
}
#ifndef NDEBUG
void EventPath::checkReachability(TreeScope& treeScope, TouchList& touchList)
{
for (size_t i = 0; i < touchList.length(); ++i)
ASSERT(touchList.item(i)->target()->toNode()->treeScope().isInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(treeScope));
}
#endif
void EventPath::trace(Visitor* visitor)
{
visitor->trace(m_event);
}
}