Example #1
0
void RelatedNodeRetargeter::moveToNewTreeScope(TreeScope* previousTreeScope, TreeScope& newTreeScope)
{
    if (m_hasDifferentTreeRoot)
        return;

    auto& currentRelatedNodeScope = m_retargetedRelatedNode->treeScope();
    if (previousTreeScope != &currentRelatedNodeScope) {
        // currentRelatedNode is still outside our shadow tree. New tree scope may contain currentRelatedNode
        // but there is no need to re-target it. Moving into a slot (thereby a deeper shadow tree) doesn't matter.
        return;
    }

    bool enteredSlot = newTreeScope.parentTreeScope() == previousTreeScope;
    if (enteredSlot) {
        if (m_lowestCommonAncestorIndex) {
            if (m_ancestorTreeScopes.isEmpty())
                collectTreeScopes();
            bool relatedNodeIsInSlot = m_ancestorTreeScopes[m_lowestCommonAncestorIndex - 1] == &newTreeScope;
            if (relatedNodeIsInSlot) {
                m_lowestCommonAncestorIndex--;
                m_retargetedRelatedNode = nodeInLowestCommonAncestor();
                ASSERT(&newTreeScope == &m_retargetedRelatedNode->treeScope());
            }
        } else
            ASSERT(m_retargetedRelatedNode == &m_relatedNode);
    } else {
        ASSERT(previousTreeScope->parentTreeScope() == &newTreeScope);
        m_lowestCommonAncestorIndex++;
        ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.isEmpty() || m_lowestCommonAncestorIndex < m_ancestorTreeScopes.size());
        m_retargetedRelatedNode = downcast<ShadowRoot>(currentRelatedNodeScope.rootNode()).host();
        ASSERT(&newTreeScope == &m_retargetedRelatedNode->treeScope());
    }
}
Example #2
0
Node* FocusController::findFocusableNodeAcrossTreeScope(FocusDirection direction, TreeScope* scope, Node* currentNode, KeyboardEvent* event)
{
    Node* node = findFocusableNode(direction, scope, currentNode, event);
    // If there's no focusable node to advance to, move up the tree scopes until we find one.
    while (!node && scope) {
        Node* owner = ownerOfTreeScope(scope);
        if (!owner)
            break;
        node = findFocusableNode(direction, owner->treeScope(), owner, event);
        scope = owner->treeScope();
    }
    node = deepFocusableNode(direction, node, event);
    return node;
}
Example #3
0
EventPath::EventPath(Node& originalTarget, Event& event)
    : m_event(event)
{
    bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent();
#if ENABLE(TOUCH_EVENTS)
    bool isTouchEvent = event.isTouchEvent();
#endif
    Node* node = nodeOrHostIfPseudoElement(&originalTarget);
    Node* target = node ? eventTargetRespectingTargetRules(*node) : nullptr;
    while (node) {
        while (node) {
            EventTarget* currentTarget = eventTargetRespectingTargetRules(*node);

            if (isMouseOrFocusEvent)
                m_path.append(std::make_unique<MouseOrFocusEventContext>(node, currentTarget, target));
#if ENABLE(TOUCH_EVENTS)
            else if (isTouchEvent)
                m_path.append(std::make_unique<TouchEventContext>(node, currentTarget, target));
#endif
            else
                m_path.append(std::make_unique<EventContext>(node, currentTarget, target));

            if (is<ShadowRoot>(*node))
                break;

            ContainerNode* parent = node->parentNode();
            if (!parent)
                return;

#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
            if (ShadowRoot* shadowRootOfParent = parent->shadowRoot()) {
                if (auto* assignedSlot = shadowRootOfParent->findAssignedSlot(*node)) {
                    // node is assigned to a slot. Continue dispatching the event at this slot.
                    parent = assignedSlot;
                }
            }
#endif
            node = parent;
        }

        bool exitingShadowTreeOfTarget = &target->treeScope() == &node->treeScope();
        ShadowRoot& shadowRoot = downcast<ShadowRoot>(*node);
        if (!shouldEventCrossShadowBoundary(event, shadowRoot, originalTarget))
            return;
        node = shadowRoot.host();
        if (exitingShadowTreeOfTarget)
            target = eventTargetRespectingTargetRules(*node);

    }
}
Example #4
0
void EventPath::calculateAdjustedTargets()
{
    const TreeScope* lastTreeScope = 0;
    bool useDeprecatedSVGUseTreeEventRules = usesDeprecatedSVGUseTreeEventRules(at(0).node());

    TreeScopeEventContextMap treeScopeEventContextMap;
    TreeScopeEventContext* lastTreeScopeEventContext = 0;

    for (size_t i = 0; i < size(); ++i) {
        Node* currentNode = at(i).node();
        TreeScope& currentTreeScope = currentNode->treeScope();
        if (lastTreeScope != &currentTreeScope) {
            if (!useDeprecatedSVGUseTreeEventRules) {
                lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, &currentTreeScope, treeScopeEventContextMap);
            } else {
                TreeScopeEventContextMap::AddResult addResult = treeScopeEventContextMap.add(&currentTreeScope, TreeScopeEventContext::create(currentTreeScope));
                lastTreeScopeEventContext = addResult.storedValue->value.get();
                if (addResult.isNewEntry) {
                    // Don't adjust an event target for SVG.
                    lastTreeScopeEventContext->setTarget(eventTargetRespectingTargetRules(at(0).node()));
                }
            }
        }
        ASSERT(lastTreeScopeEventContext);
        at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
        lastTreeScope = &currentTreeScope;
    }
    m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
}
Example #5
0
static inline bool shouldEventCrossShadowBoundary(Event& event, ShadowRoot& shadowRoot, EventTarget& target)
{
    Node* targetNode = target.toNode();
#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
    // Video-only full screen is a mode where we use the shadow DOM as an implementation
    // detail that should not be detectable by the web content.
    if (targetNode) {
        if (Element* element = targetNode->document().webkitCurrentFullScreenElement()) {
            // FIXME: We assume that if the full screen element is a media element that it's
            // the video-only full screen. Both here and elsewhere. But that is probably wrong.
            if (element->isMediaElement() && shadowRoot.hostElement() == element)
                return false;
        }
    }
#endif

    // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
    // Changing this breaks existing sites.
    // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
    const AtomicString& eventType = event.type();
    bool targetIsInShadowRoot = targetNode && targetNode->treeScope().rootNode() == &shadowRoot;
    return !targetIsInShadowRoot
        || !(eventType == eventNames().abortEvent
            || eventType == eventNames().changeEvent
            || eventType == eventNames().errorEvent
            || eventType == eventNames().loadEvent
            || eventType == eventNames().resetEvent
            || eventType == eventNames().resizeEvent
            || eventType == eventNames().scrollEvent
            || eventType == eventNames().selectEvent
            || eventType == eventNames().selectstartEvent);
}
Example #6
0
static Node* moveOutOfAllShadowRoots(Node& startingNode)
{
    Node* node = &startingNode;
    while (node->isInShadowTree())
        node = downcast<ShadowRoot>(node->treeScope().rootNode()).host();
    return node;
}
Example #7
0
Node* LiveNodeList::namedItem(const AtomicString& elementId) const
{
    Node* rootNode = this->rootNode();

    if (rootNode->inDocument()) {
#if ENABLE(MICRODATA)
        if (type() == PropertyNodeListType)
            static_cast<const PropertyNodeList*>(this)->updateRefElements();
#endif

        Element* element = rootNode->treeScope()->getElementById(elementId);
        if (element && nodeMatches(element) && element->isDescendantOf(rootNode))
            return element;
        if (!element)
            return 0;
        // In the case of multiple nodes with the same name, just fall through.
    }

    unsigned length = this->length();
    for (unsigned i = 0; i < length; i++) {
        Node* node = item(i);
        // FIXME: This should probably be using getIdAttribute instead of idForStyleResolution.
        if (node->hasID() && toElement(node)->idForStyleResolution() == elementId)
            return node;
    }

    return 0;
}
Example #8
0
void EventPath::setRelatedTarget(Node& origin, EventTarget& relatedTarget)
{
    Node* relatedNode = relatedTarget.toNode();
    if (!relatedNode)
        return;

    EventRelatedNodeResolver resolver(*relatedNode);

    bool originIsRelatedTarget = &origin == relatedNode;
    Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode();

    size_t eventPathSize = m_path.size();
    size_t i = 0;
    while (i < eventPathSize) {
        Node* contextNode = m_path[i]->node();
        Node* currentRelatedNode = resolver.moveToParentOrShadowHost(*contextNode);
        if (!originIsRelatedTarget && m_path[i]->target() == currentRelatedNode)
            break;
        toMouseOrFocusEventContext(*m_path[i]).setRelatedTarget(currentRelatedNode);
        i++;
        if (originIsRelatedTarget && &rootNodeInOriginTreeScope == contextNode)
            break;
    }
    m_path.shrink(i);
}
Example #9
0
Node* LiveNodeList::namedItem(const AtomicString& elementId) const
{
    Node* rootNode = this->rootNode();

    if (rootNode->inDocument()) {
        Element* element = rootNode->treeScope()->getElementById(elementId);
        if (element && nodeMatches(element) && element->isDescendantOf(rootNode))
            return element;
        if (!element)
            return 0;
        // In the case of multiple nodes with the same name, just fall through.
    }

    unsigned length = this->length();
    for (unsigned i = 0; i < length; i++) {
        Node* node = item(i);
        if (!node->isElementNode())
            continue;
        Element* element = toElement(node);
        // FIXME: This should probably be using getIdAttribute instead of idForStyleResolution.
        if (element->hasID() && element->idForStyleResolution() == elementId)
            return node;
    }

    return 0;
}
void SelectorDataList::executeQueryAll(Node& rootNode, Vector<RefPtr<Node> >& matchedElements) const
{
    if (!canUseFastQuery(rootNode))
        return executeSlowQueryAll(rootNode, matchedElements);

    ASSERT(m_selectors.size() == 1);
    ASSERT(m_selectors[0].selector);

    const CSSSelector* firstSelector = m_selectors[0].selector;

    if (!firstSelector->tagHistory()) {
        // Fast path for querySelectorAll('#id'), querySelectorAl('.foo'), and querySelectorAll('div').
        switch (firstSelector->m_match) {
        case CSSSelector::Id:
            {
                if (rootNode.document().containsMultipleElementsWithId(firstSelector->value()))
                    break;

                // Just the same as getElementById.
                Element* element = rootNode.treeScope().getElementById(firstSelector->value());
                if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
                    matchedElements.append(element);
                return;
            }
        case CSSSelector::Class:
            return collectElementsByClassName(rootNode, firstSelector->value(), matchedElements);
        case CSSSelector::Tag:
            return collectElementsByTagName(rootNode, firstSelector->tagQName(), matchedElements);
        default:
            break; // If we need another fast path, add here.
        }
    }

    bool matchTraverseRoots;
    OwnPtr<SimpleNodeList> traverseRoots = findTraverseRoots(&rootNode, matchTraverseRoots);
    if (traverseRoots->isEmpty())
        return;

    const SelectorData& selector = m_selectors[0];
    if (matchTraverseRoots) {
        while (!traverseRoots->isEmpty()) {
            Node& node = *traverseRoots->next();
            Element& element = toElement(node);
            if (selectorMatches(selector, element, rootNode))
                matchedElements.append(&element);
        }
        return;
    }

    while (!traverseRoots->isEmpty()) {
        Node* traverseRoot = traverseRoots->next();
        for (Element* element = ElementTraversal::firstWithin(traverseRoot); element; element = ElementTraversal::next(element, traverseRoot)) {
            if (selectorMatches(selector, *element, rootNode))
                matchedElements.append(element);
        }
    }
}
Example #11
0
FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(Node* node)
{
    ASSERT(node);
    Node* root = node;
    for (Node* n = node; n; n = n->parentNode())
        root = n;
    // The result is not always a ShadowRoot nor a DocumentNode since
    // a starting node is in an orphaned tree in composed shadow tree.
    return FocusNavigationScope(&root->treeScope());
}
Example #12
0
inline void TreeScopeAdopter::updateTreeScope(Node& node) const
{
    ASSERT(!node.isTreeScope());
    ASSERT(node.treeScope() == oldScope());
#if !ENABLE(OILPAN)
    newScope().guardRef();
    oldScope().guardDeref();
#endif
    node.setTreeScope(m_newScope);
}
Example #13
0
void EventRetargeter::calculateEventPath(Node* node, Event* event)
{
    EventPath& eventPath = event->eventPath();
    eventPath.clear();
    bool inDocument = node->inDocument();
    bool isSVGElement = node->isSVGElement();
    bool isMouseOrFocusEvent = event->isMouseEvent() || event->isFocusEvent();
    bool isTouchEvent = event->isTouchEvent();
    Vector<EventTarget*, 32> targetStack;
    for (EventPathWalker walker(node); walker.node(); walker.moveToParent()) {
        Node* node = walker.node();
        if (targetStack.isEmpty())
            targetStack.append(eventTargetRespectingTargetRules(node));
        else if (walker.isVisitingInsertionPointInReprojection())
            targetStack.append(targetStack.last());
        if (isMouseOrFocusEvent)
            eventPath.append(adoptPtr(new MouseOrFocusEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
        else if (isTouchEvent)
            eventPath.append(adoptPtr(new TouchEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
        else
            eventPath.append(adoptPtr(new EventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
        if (!inDocument)
            return;
        if (!node->isShadowRoot())
            continue;
        if (determineDispatchBehavior(event, toShadowRoot(node), targetStack.last()) == StayInsideShadowDOM)
            return;
        if (!isSVGElement) {
            ASSERT(!targetStack.isEmpty());
            targetStack.removeLast();
        }
    }

    // Calculates eventPath for each node for Event.path() API.
    if (!RuntimeEnabledFeatures::experimentalShadowDOMEnabled())
        return;
    TreeScope* lastScope = 0;
    size_t eventPathSize = eventPath.size();
    for (size_t i = 0; i < eventPathSize; ++i) {
        TreeScope* currentScope = eventPath[i]->node()->treeScope();
        if (currentScope == lastScope) {
            // Fast path.
            eventPath[i]->setEventPath(eventPath[i - 1]->eventPath());
            continue;
        }
        lastScope = currentScope;
        Vector<RefPtr<Node> > nodes;
        for (size_t j = 0; j < eventPathSize; ++j) {
            Node* node = eventPath[j]->node();
            if (node->treeScope()->isInclusiveAncestorOf(currentScope))
                nodes.append(node);
        }
        eventPath[i]->adoptEventPath(nodes);
    }
}
Example #14
0
    EventRelatedNodeResolver(Node& relatedNode)
        : m_relatedNode(relatedNode)
        , m_relatedNodeTreeScope(relatedNode.treeScope())
        , m_relatedNodeInCurrentTreeScope(nullptr)
        , m_currentTreeScope(nullptr)
#if ENABLE(TOUCH_EVENTS)
        , m_touch(0)
        , m_touchListType(TouchEventContext::NotTouchList)
#endif
    {
    }
Example #15
0
RelatedNodeRetargeter::RelatedNodeRetargeter(Node& relatedNode, Node& target)
    : m_relatedNode(relatedNode)
    , m_retargetedRelatedNode(&relatedNode)
{
    auto& targetTreeScope = target.treeScope();
    TreeScope* currentTreeScope = &m_relatedNode.treeScope();
    if (LIKELY(currentTreeScope == &targetTreeScope && target.inDocument() && m_relatedNode.inDocument()))
        return;

    if (&currentTreeScope->documentScope() != &targetTreeScope.documentScope()) {
        m_hasDifferentTreeRoot = true;
        m_retargetedRelatedNode = nullptr;
        return;
    }
    if (relatedNode.inDocument() != target.inDocument()) {
        m_hasDifferentTreeRoot = true;
        m_retargetedRelatedNode = moveOutOfAllShadowRoots(relatedNode);
        return;
    }

    collectTreeScopes();

    // FIXME: We should collect this while constructing the event path.
    Vector<TreeScope*, 8> targetTreeScopeAncestors;
    for (TreeScope* currentTreeScope = &targetTreeScope; currentTreeScope; currentTreeScope = currentTreeScope->parentTreeScope())
        targetTreeScopeAncestors.append(currentTreeScope);
    ASSERT_WITH_SECURITY_IMPLICATION(!targetTreeScopeAncestors.isEmpty());

    unsigned i = m_ancestorTreeScopes.size();
    unsigned j = targetTreeScopeAncestors.size();
    ASSERT_WITH_SECURITY_IMPLICATION(m_ancestorTreeScopes.last() == targetTreeScopeAncestors.last());
    while (m_ancestorTreeScopes[i - 1] == targetTreeScopeAncestors[j - 1]) {
        i--;
        j--;
        if (!i || !j)
            break;
    }

    bool lowestCommonAncestorIsDocumentScope = i + 1 == m_ancestorTreeScopes.size();
    if (lowestCommonAncestorIsDocumentScope && !relatedNode.inDocument() && !target.inDocument()) {
        Node& targetAncestorInDocumentScope = i ? *downcast<ShadowRoot>(m_ancestorTreeScopes[i - 1]->rootNode()).shadowHost() : target;
        Node& relatedNodeAncestorInDocumentScope = j ? *downcast<ShadowRoot>(targetTreeScopeAncestors[j - 1]->rootNode()).shadowHost() : relatedNode;
        if (targetAncestorInDocumentScope.rootNode() != relatedNodeAncestorInDocumentScope.rootNode()) {
            m_hasDifferentTreeRoot = true;
            m_retargetedRelatedNode = moveOutOfAllShadowRoots(relatedNode);
            return;
        }
    }

    m_lowestCommonAncestorIndex = i;
    m_retargetedRelatedNode = nodeInLowestCommonAncestor();
}
Example #16
0
FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(Node* node)
{
    ASSERT(node);
    ComposedShadowTreeWalker walker(node, ComposedShadowTreeWalker::DoNotCrossUpperBoundary);
    Node* root = node;
    while (walker.get()) {
        root = walker.get();
        walker.parent();
    }
    // The result is not always a ShadowRoot nor a DocumentNode since
    // a starting node is in an orphaned tree in composed shadow tree.
    return FocusNavigationScope(root->treeScope());
}
Example #17
0
void StyleEngine::modifiedStyleSheet(StyleSheet* sheet)
{
    if (!sheet)
        return;

    Node* node = sheet->ownerNode();
    if (!node || !node->inDocument())
        return;

    TreeScope& treeScope = node->hasTagName(styleTag) ? node->treeScope() : m_document;
    ASSERT(node->hasTagName(styleTag) || treeScope == m_document);

    markTreeScopeDirty(treeScope);
}
Example #18
0
void StyleEngine::modifiedStyleSheet(StyleSheet* sheet)
{
    if (!sheet)
        return;

    Node* node = sheet->ownerNode();
    if (!node || !node->inDocument())
        return;

    TreeScope& treeScope = isHTMLStyleElement(*node) ? node->treeScope() : *m_document;
    ASSERT(isHTMLStyleElement(node) || treeScope == m_document);

    markTreeScopeDirty(treeScope);
}
Example #19
0
void EventRelatedTargetAdjuster::adjust(Vector<EventContext, 32>& ancestors)
{
    // Synthetic mouse events can have a relatedTarget which is identical to the target.
    bool targetIsIdenticalToToRelatedTarget = (m_node.get() == m_relatedTarget.get());

    Vector<EventTarget*, 32> relatedTargetStack;
    TreeScope* lastTreeScope = 0;
    for (AncestorChainWalker walker(m_relatedTarget.get()); walker.get(); walker.parent()) {
        Node* node = walker.get();
        if (relatedTargetStack.isEmpty())
            relatedTargetStack.append(node);
        else if (walker.crossingInsertionPoint())
            relatedTargetStack.append(relatedTargetStack.last());
        TreeScope* scope = node->treeScope();
        // Skips adding a node to the map if treeScope does not change. Just for the performance optimization.
        if (scope != lastTreeScope)
            m_relatedTargetMap.add(scope, relatedTargetStack.last());
        lastTreeScope = scope;
        if (node->isShadowRoot()) {
            ASSERT(!relatedTargetStack.isEmpty());
            relatedTargetStack.removeLast();
        }
    }

    lastTreeScope = 0;
    EventTarget* adjustedRelatedTarget = 0;
    for (Vector<EventContext, 32>::iterator iter = ancestors.begin(); iter < ancestors.end(); ++iter) {
        TreeScope* scope = iter->node()->treeScope();
        if (scope == lastTreeScope) {
            // Re-use the previous adjustedRelatedTarget if treeScope does not change. Just for the performance optimization.
            iter->setRelatedTarget(adjustedRelatedTarget);
        } else {
            adjustedRelatedTarget = findRelatedTarget(scope);
            iter->setRelatedTarget(adjustedRelatedTarget);
        }
        lastTreeScope = scope;
        if (targetIsIdenticalToToRelatedTarget) {
            if (m_node->treeScope()->rootNode() == iter->node()) {
                ancestors.shrink(iter + 1 - ancestors.begin());
                break;
            }
        } else if (iter->target() == adjustedRelatedTarget) {
            // Event dispatching should be stopped here.
            ancestors.shrink(iter - ancestors.begin());
            break;
        }
    }
}
Example #20
0
Element* HTMLDocument::activeElement()
{
    Node* node = focusedNode();
    if (!node && page())
        node = focusedFrameOwnerElement(page()->focusController()->focusedFrame(), frame());
    if (!node)
        return body();
    ASSERT(node->document() == this);
    while (node->treeScope() != this) {
        node = node->parentOrHostNode();
        ASSERT(node);
    }
    if (node->isElementNode())
        return toElement(node);
    return body();
}
Example #21
0
 static Node* findHostOfTreeScopeInTargetTreeScope(const TreeScope& startingTreeScope, const TreeScope& targetScope)
 {
     ASSERT(&targetScope != &startingTreeScope);
     Node* previousHost = nullptr;
     for (const TreeScope* scope = &startingTreeScope; scope; scope = scope->parentTreeScope()) {
         if (scope == &targetScope) {
             ASSERT(previousHost);
             ASSERT_WITH_SECURITY_IMPLICATION(&previousHost->treeScope() == &targetScope);
             return previousHost;
         }
         if (is<ShadowRoot>(scope->rootNode()))
             previousHost = downcast<ShadowRoot>(scope->rootNode()).host();
         else
             ASSERT_WITH_SECURITY_IMPLICATION(!scope->parentTreeScope());
     }
     return nullptr;
 }
Example #22
0
void EventRetargeter::buildRelatedNodeMap(const Node* relatedNode, RelatedNodeMap& relatedNodeMap)
{
    Vector<Node*, 32> relatedNodeStack;
    TreeScope* lastTreeScope = 0;
    for (Node* node = nodeOrHostIfPseudoElement(const_cast<Node*>(relatedNode)); node; node = node->parentOrShadowHostNode()) {
        if (relatedNodeStack.isEmpty())
            relatedNodeStack.append(node);
        TreeScope* scope = node->treeScope();
        // Skips adding a node to the map if treeScope does not change. Just for the performance optimization.
        if (scope != lastTreeScope)
            relatedNodeMap.add(scope, relatedNodeStack.last());
        lastTreeScope = scope;
        if (node->isShadowRoot()) {
            ASSERT(!relatedNodeStack.isEmpty());
            relatedNodeStack.removeLast();
        }
    }
}
Example #23
0
void EventPath::shrinkIfNeeded(const Node& target, const EventTarget& relatedTarget)
{
    // Synthetic mouse events can have a relatedTarget which is identical to the target.
    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()) {
            // Event dispatching should be stopped here.
            shrink(i);
            break;
        }
    }
}
Example #24
0
void EventPath::calculateAdjustedTargets()
{
    const TreeScope* lastTreeScope = 0;

    TreeScopeEventContextMap treeScopeEventContextMap;
    TreeScopeEventContext* lastTreeScopeEventContext = 0;

    for (size_t i = 0; i < size(); ++i) {
        Node* currentNode = at(i).node();
        TreeScope& currentTreeScope = currentNode->treeScope();
        if (lastTreeScope != &currentTreeScope) {
            lastTreeScopeEventContext = ensureTreeScopeEventContext(currentNode, &currentTreeScope, treeScopeEventContextMap);
        }
        ASSERT(lastTreeScopeEventContext);
        at(i).setTreeScopeEventContext(lastTreeScopeEventContext);
        lastTreeScope = &currentTreeScope;
    }
    m_treeScopeEventContexts.appendRange(treeScopeEventContextMap.values().begin(), treeScopeEventContextMap.values().end());
}
Example #25
0
void EventRelatedTargetAdjuster::adjust(Vector<EventContext>& ancestors)
{
    Vector<EventTarget*> relatedTargetStack;
    TreeScope* lastTreeScope = 0;
    Node* lastNode = 0;
    for (ComposedShadowTreeParentWalker walker(m_relatedTarget.get()); walker.get(); walker.parentIncludingInsertionPointAndShadowRoot()) {
        Node* node = walker.get();
        if (relatedTargetStack.isEmpty())
            relatedTargetStack.append(node);
        else if (isInsertionPoint(node) && toInsertionPoint(node)->contains(lastNode))
            relatedTargetStack.append(relatedTargetStack.last());
        TreeScope* scope = node->treeScope();
        // Skips adding a node to the map if treeScope does not change. Just for the performance optimization.
        if (scope != lastTreeScope)
            m_relatedTargetMap.add(scope, relatedTargetStack.last());
        lastTreeScope = scope;
        lastNode = node;
        if (node->isShadowRoot()) {
            ASSERT(!relatedTargetStack.isEmpty());
            relatedTargetStack.removeLast();
        }
    }

    lastTreeScope = 0;
    EventTarget* adjustedRelatedTarget = 0;
    for (Vector<EventContext>::iterator iter = ancestors.begin(); iter < ancestors.end(); ++iter) {
        TreeScope* scope = iter->node()->treeScope();
        if (scope == lastTreeScope) {
            // Re-use the previous adjustedRelatedTarget if treeScope does not change. Just for the performance optimization.
            iter->setRelatedTarget(adjustedRelatedTarget);
        } else {
            adjustedRelatedTarget = findRelatedTarget(scope);
            iter->setRelatedTarget(adjustedRelatedTarget);
        }
        lastTreeScope = scope;
        if (iter->target() == adjustedRelatedTarget) {
            // Event dispatching should be stopped here.
            ancestors.shrink(iter - ancestors.begin());
            break;
        }
    }
}
Example #26
0
static inline bool shouldEventCrossShadowBoundary(Event& event, ShadowRoot& shadowRoot, EventTarget& target)
{
    Node* targetNode = target.toNode();

#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
    // Video-only full screen is a mode where we use the shadow DOM as an implementation
    // detail that should not be detectable by the web content.
    if (targetNode) {
        if (Element* element = targetNode->document().webkitCurrentFullScreenElement()) {
            // FIXME: We assume that if the full screen element is a media element that it's
            // the video-only full screen. Both here and elsewhere. But that is probably wrong.
            if (element->isMediaElement() && shadowRoot.host() == element)
                return false;
        }
    }
#endif

    bool targetIsInShadowRoot = targetNode && &targetNode->treeScope().rootNode() == &shadowRoot;
    return !targetIsInShadowRoot || !event.scoped();
}
void EventRetargeter::buildRelatedNodeMap(const Node* relatedNode, RelatedNodeMap& relatedNodeMap)
{
    Vector<Node*, 32> relatedNodeStack;
    TreeScope* lastTreeScope = 0;
    for (EventPathWalker walker(relatedNode); walker.node(); walker.moveToParent()) {
        Node* node = walker.node();
        if (relatedNodeStack.isEmpty())
            relatedNodeStack.append(node);
        else if (walker.isVisitingInsertionPointInReprojection())
            relatedNodeStack.append(relatedNodeStack.last());
        TreeScope* scope = node->treeScope();
        // Skips adding a node to the map if treeScope does not change. Just for the performance optimization.
        if (scope != lastTreeScope)
            relatedNodeMap.add(scope, relatedNodeStack.last());
        lastTreeScope = scope;
        if (node->isShadowRoot()) {
            ASSERT(!relatedNodeStack.isEmpty());
            relatedNodeStack.removeLast();
        }
    }
}
Example #28
0
void EventPath::setRelatedTarget(Node& origin, EventTarget& relatedTarget)
{
    UNUSED_PARAM(origin);
    Node* relatedNode = relatedTarget.toNode();
    if (!relatedNode || m_path.isEmpty())
        return;

    RelatedNodeRetargeter retargeter(*relatedNode, downcast<MouseOrFocusEventContext>(*m_path[0]).node()->treeScope());

    bool originIsRelatedTarget = &origin == relatedNode;
    // FIXME: We should add a new flag on Event instead.
    bool shouldTrimEventPath = m_event.type() == eventNames().mouseoverEvent
        || m_event.type() == eventNames().mousemoveEvent
        || m_event.type() == eventNames().mouseoutEvent;
    Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode();
    TreeScope* previousTreeScope = nullptr;
    size_t originalEventPathSize = m_path.size();
    for (unsigned contextIndex = 0; contextIndex < originalEventPathSize; contextIndex++) {
        auto& context = downcast<MouseOrFocusEventContext>(*m_path[contextIndex]);

        TreeScope& currentTreeScope = context.node()->treeScope();
        if (UNLIKELY(previousTreeScope && &currentTreeScope != previousTreeScope))
            retargeter.moveToNewTreeScope(previousTreeScope, currentTreeScope);

        Node* currentRelatedNode = retargeter.currentNode(currentTreeScope);
        if (UNLIKELY(shouldTrimEventPath && !originIsRelatedTarget && context.target() == currentRelatedNode)) {
            m_path.shrink(contextIndex);
            break;
        }

        context.setRelatedTarget(currentRelatedNode);

        if (UNLIKELY(shouldTrimEventPath && originIsRelatedTarget && context.node() == &rootNodeInOriginTreeScope)) {
            m_path.shrink(contextIndex + 1);
            break;
        }

        previousTreeScope = &currentTreeScope;
    }
}
Example #29
0
void EventPath::setRelatedTarget(Node& origin, EventTarget& relatedTarget)
{
    Node* relatedNode = relatedTarget.toNode();
    if (!relatedNode || m_path.isEmpty())
        return;

    RelatedNodeRetargeter retargeter(*relatedNode, *m_path[0]->node());

    bool originIsRelatedTarget = &origin == relatedNode;
    bool relatedTargetScoped = m_event.relatedTargetScoped();
    Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode();
    TreeScope* previousTreeScope = nullptr;
    size_t originalEventPathSize = m_path.size();
    for (unsigned contextIndex = 0; contextIndex < originalEventPathSize; contextIndex++) {
        auto& context = downcast<MouseOrFocusEventContext>(*m_path[contextIndex]);

        Node& currentTarget = *context.node();
        TreeScope& currentTreeScope = currentTarget.treeScope();
        if (UNLIKELY(previousTreeScope && &currentTreeScope != previousTreeScope))
            retargeter.moveToNewTreeScope(previousTreeScope, currentTreeScope);

        Node* currentRelatedNode = retargeter.currentNode(currentTarget);
        if (UNLIKELY(relatedTargetScoped && !originIsRelatedTarget && context.target() == currentRelatedNode)) {
            m_path.shrink(contextIndex);
            break;
        }

        context.setRelatedTarget(currentRelatedNode);

        if (UNLIKELY(relatedTargetScoped && originIsRelatedTarget && context.node() == &rootNodeInOriginTreeScope)) {
            m_path.shrink(contextIndex + 1);
            break;
        }

        previousTreeScope = &currentTreeScope;
    }
}
bool ValidationMessage::shadowTreeContains(const Node& node) const
{
    if (validationMessageClient() || !m_bubble)
        return false;
    return &m_bubble->treeScope() == &node.treeScope();
}