void EventPath::calculatePath()
{
    ASSERT(m_node);
    ASSERT(m_nodeEventContexts.isEmpty());
    m_node->updateDistribution();

    // For performance and memory usage reasons we want to store the
    // path using as few bytes as possible and with as few allocations
    // as possible which is why we gather the data on the stack before
    // storing it in a perfectly sized m_nodeEventContexts Vector.
    WillBeHeapVector<RawPtrWillBeMember<Node>, 64> nodesInPath;
    Node* current = m_node;
    nodesInPath.append(current);
    while (current) {
        if (m_event && current->keepEventInNode(m_event))
            break;
        WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints;
        collectDestinationInsertionPoints(*current, insertionPoints);
        if (!insertionPoints.isEmpty()) {
            for (const auto& insertionPoint : insertionPoints) {
                if (insertionPoint->isShadowInsertionPoint()) {
                    ShadowRoot* containingShadowRoot = insertionPoint->containingShadowRoot();
                    ASSERT(containingShadowRoot);
                    if (!containingShadowRoot->isOldest())
                        nodesInPath.append(containingShadowRoot->olderShadowRoot());
                }
                nodesInPath.append(insertionPoint);
            }
            current = insertionPoints.last();
            continue;
        }
        if (current->isShadowRoot()) {
            if (m_event && shouldStopAtShadowRoot(*m_event, *toShadowRoot(current), *m_node))
                break;
            current = current->shadowHost();
#if !ENABLE(OILPAN)
            // TODO(kochi): crbug.com/507413 This check is necessary when some asynchronous event
            // is queued while its shadow host is removed and the shadow root gets the event
            // immediately after it.  When Oilpan is enabled, this situation does not happen.
            // Except this case, shadow root's host is assumed to be non-null.
            if (current)
                nodesInPath.append(current);
#else
            nodesInPath.append(current);
#endif
        } else {
            current = current->parentNode();
            if (current)
                nodesInPath.append(current);
        }
    }

    m_nodeEventContexts.reserveCapacity(nodesInPath.size());
    for (Node* nodeInPath : nodesInPath) {
        m_nodeEventContexts.append(NodeEventContext(nodeInPath, eventTargetRespectingTargetRules(*nodeInPath)));
    }
}
Example #2
0
void EventPath::addNodeEventContext(Node& node)
{
    m_nodeEventContexts.append(NodeEventContext(&node, eventTargetRespectingTargetRules(node)));
}