Example #1
0
PositionInComposedTree toPositionInComposedTree(const Position& pos)
{
    if (pos.isNull())
        return PositionInComposedTree();

    if (pos.isOffsetInAnchor()) {
        Node* anchor = pos.anchorNode();
        if (anchor->offsetInCharacters())
            return PositionInComposedTree(anchor, pos.computeOffsetInContainerNode());
        ASSERT(!anchor->isSlotOrActiveInsertionPoint());
        int offset = pos.computeOffsetInContainerNode();
        Node* child = NodeTraversal::childAt(*anchor, offset);
        if (!child) {
            if (anchor->isShadowRoot())
                return PositionInComposedTree(anchor->shadowHost(), PositionAnchorType::AfterChildren);
            return PositionInComposedTree(anchor, PositionAnchorType::AfterChildren);
        }
        child->updateDistribution();
        if (child->isSlotOrActiveInsertionPoint()) {
            if (anchor->isShadowRoot())
                return PositionInComposedTree(anchor->shadowHost(), offset);
            return PositionInComposedTree(anchor, offset);
        }
        if (Node* parent = ComposedTreeTraversal::parent(*child))
            return PositionInComposedTree(parent, ComposedTreeTraversal::index(*child));
        // When |pos| isn't appeared in composed tree, we map |pos| to after
        // children of shadow host.
        // e.g. "foo",0 in <progress>foo</progress>
        if (anchor->isShadowRoot())
            return PositionInComposedTree(anchor->shadowHost(), PositionAnchorType::AfterChildren);
        return PositionInComposedTree(anchor, PositionAnchorType::AfterChildren);
    }

    return PositionInComposedTree(pos.anchorNode(), pos.anchorType());
}
void EventDispatcher::getEventAncestors(EventTarget* originalTarget, EventDispatchBehavior behavior)
{
    if (!m_node->inDocument())
        return;

    if (ancestorsInitialized())
        return;

    EventTarget* target = originalTarget;
    Node* ancestor = m_node.get();
    bool shouldSkipNextAncestor = false;
    while (true) {
        if (ancestor->isShadowRoot()) {
            if (behavior == StayInsideShadowDOM)
                return;
            ancestor = ancestor->shadowHost();
            if (!shouldSkipNextAncestor)
                target = ancestor;
        } else
            ancestor = ancestor->parentNodeGuaranteedHostFree();

        if (!ancestor)
            return;

#if ENABLE(SVG)
        // Skip SVGShadowTreeRootElement.
        shouldSkipNextAncestor = ancestor->isSVGElement() && ancestor->isShadowRoot();
        if (shouldSkipNextAncestor)
            continue;
#endif
        // FIXME: Unroll the extra loop inside eventTargetRespectingSVGTargetRules into this loop.
        m_ancestors.append(EventContext(ancestor, eventTargetRespectingSVGTargetRules(ancestor), target));
    }
}
bool InspectorOverlay::handleMouseMove(const PlatformMouseEvent& event)
{
    if (!shouldSearchForNode())
        return false;

    LocalFrame* frame = m_webViewImpl->mainFrameImpl()->frame();
    if (!frame->view() || !frame->contentLayoutObject())
        return false;
    Node* node = hoveredNodeForEvent(frame, event, event.shiftKey());

    // Do not highlight within user agent shadow root unless requested.
    if (m_inspectMode != InspectorDOMAgent::SearchingForUAShadow) {
        ShadowRoot* shadowRoot = InspectorDOMAgent::userAgentShadowRoot(node);
        if (shadowRoot)
            node = shadowRoot->host();
    }

    // Shadow roots don't have boxes - use host element instead.
    if (node && node->isShadowRoot())
        node = node->parentOrShadowHostNode();

    if (!node)
        return true;

    Node* eventTarget = event.shiftKey() ? hoveredNodeForEvent(m_webViewImpl->mainFrameImpl()->frame(), event, false) : nullptr;
    if (eventTarget == node)
        eventTarget = nullptr;

    if (node && m_inspectModeHighlightConfig) {
        m_hoveredNodeForInspectMode = node;
        m_domAgent->nodeHighlightedInOverlay(node);
        highlightNode(node, eventTarget, *m_inspectModeHighlightConfig, event.ctrlKey() || event.metaKey());
    }
    return true;
}
Example #4
0
EventPath::EventPath(Node& targetNode, Event& event)
{
    bool inDocument = targetNode.inDocument();
    bool isSVGElement = targetNode.isSVGElement();
    bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent();
#if ENABLE(TOUCH_EVENTS)
    bool isTouchEvent = event.isTouchEvent();
#endif
    EventTarget* target = 0;

    Node* node = nodeOrHostIfPseudoElement(&targetNode);
    while (node) {
        if (!target || !isSVGElement) // FIXME: This code doesn't make sense once we've climbed out of the SVG subtree in a HTML document.
            target = &eventTargetRespectingTargetRules(*node);
        for (; node; node = node->parentNode()) {
            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 (!inDocument)
                return;
            if (node->isShadowRoot())
                break;
        }
        if (!node || !shouldEventCrossShadowBoundary(event, *toShadowRoot(node), *target))
            return;
        node = toShadowRoot(node)->hostElement();
    }
}
Example #5
0
static String nodePosition(Node* node)
{
    String result;

    Element* body = node->document()->body();
    Node* parent;
    for (Node* n = node; n; n = parent) {
        parent = n->parentOrHostNode();
        if (n != node)
            result += " of ";
        if (parent) {
            if (body && n == body) {
                // We don't care what offset body may be in the document.
                result += "body";
                break;
            }
            if (n->isShadowRoot())
                result += "{" + getTagName(n) + "}";
            else
                result += "child " + String::number(n->nodeIndex()) + " {" + getTagName(n) + "}";
        } else
            result += "document";
    }

    return result;
}
Example #6
0
static String nodePosition(Node* node)
{
    StringBuilder result;

    Element* body = node->document()->body();
    Node* parent;
    for (Node* n = node; n; n = parent) {
        parent = n->parentOrHostNode();
        if (n != node)
            result.appendLiteral(" of ");
        if (parent) {
            if (body && n == body) {
                // We don't care what offset body may be in the document.
                result.appendLiteral("body");
                break;
            }
            if (n->isShadowRoot()) {
                result.append('{');
                result.append(getTagName(n));
                result.append('}');
            } else {
                result.appendLiteral("child ");
                result.appendNumber(n->nodeIndex());
                result.appendLiteral(" {");
                result.append(getTagName(n));
                result.append('}');
            }
        } else
            result.appendLiteral("document");
    }

    return result.toString();
}
Example #7
0
inline void TreeScopeAdopter::moveNodeToNewDocument(
    Node& node,
    Document& oldDocument,
    Document& newDocument) const {
  DCHECK_NE(oldDocument, newDocument);

  if (node.hasRareData()) {
    NodeRareData* rareData = node.rareData();
    if (rareData->nodeLists())
      rareData->nodeLists()->adoptDocument(oldDocument, newDocument);
  }

  oldDocument.moveNodeIteratorsToNewDocument(node, newDocument);

  if (node.getCustomElementState() == CustomElementState::Custom) {
    Element& element = toElement(node);
    CustomElement::enqueueAdoptedCallback(&element, &oldDocument, &newDocument);
  }

  if (node.isShadowRoot())
    toShadowRoot(node).setDocument(newDocument);

#if DCHECK_IS_ON()
  didMoveToNewDocumentWasCalled = false;
  oldDocumentDidMoveToNewDocumentWasCalledWith = &oldDocument;
#endif

  node.didMoveToNewDocument(oldDocument);
#if DCHECK_IS_ON()
  DCHECK(didMoveToNewDocumentWasCalled);
#endif
}
Example #8
0
void EventRetargeter::calculateEventPath(Node* targetNode, Event* event, EventPath& eventPath)
{
    bool inDocument = targetNode->inDocument();
    bool isSVGElement = targetNode->isSVGElement();
    bool isMouseOrFocusEvent = event->isMouseEvent() || event->isFocusEvent();
#if ENABLE(TOUCH_EVENTS)
    bool isTouchEvent = event->isTouchEvent();
#endif
    Vector<EventTarget*, 32> targetStack;

    for (Node* node = nodeOrHostIfPseudoElement(targetNode); node; node = node->parentOrShadowHostNode()) {
        if (targetStack.isEmpty())
            targetStack.append(eventTargetRespectingTargetRules(node));
        if (isMouseOrFocusEvent)
            eventPath.append(adoptPtr(new MouseOrFocusEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
#if ENABLE(TOUCH_EVENTS)
        else if (isTouchEvent)
            eventPath.append(adoptPtr(new TouchEventContext(node, eventTargetRespectingTargetRules(node), targetStack.last())));
#endif
        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();
        }
    }
}
Example #9
0
void EventDispatcher::ensureEventAncestors(Event* event)
{
    if (m_ancestorsInitialized)
        return;
    m_ancestorsInitialized = true;
    bool inDocument = m_node->inDocument();
    bool isSVGElement = m_node->isSVGElement();
    Vector<EventTarget*> targetStack;
    Node* last = 0;
    for (ComposedShadowTreeParentWalker walker(m_node.get()); walker.get(); walker.parentIncludingInsertionPointAndShadowRoot()) {
        Node* node = walker.get();
        if (targetStack.isEmpty())
            targetStack.append(eventTargetRespectingSVGTargetRules(node));
        else if (isInsertionPoint(node) && toInsertionPoint(node)->contains(last))
            targetStack.append(targetStack.last());
        m_ancestors.append(EventContext(node, eventTargetRespectingSVGTargetRules(node), targetStack.last()));
        if (!inDocument)
            return;
        last = node;
        if (!node->isShadowRoot())
            continue;
        if (determineDispatchBehavior(event, toShadowRoot(node), targetStack.last()) == StayInsideShadowDOM)
            return;
        if (!isSVGElement) {
            ASSERT(!targetStack.isEmpty());
            targetStack.removeLast();
        }
    }
}
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();
        }
    }
}
Example #11
0
Element* TreeScope::adjustedFocusedElement()
{
    Document& document = rootNode()->document();
    Element* element = document.focusedElement();
    if (!element && document.page())
        element = focusedFrameOwnerElement(document.page()->focusController().focusedFrame(), document.frame());
    if (!element)
        return 0;
    Vector<Node*> targetStack;
    for (EventPathWalker walker(element); walker.node(); walker.moveToParent()) {
        Node* node = walker.node();
        if (targetStack.isEmpty())
            targetStack.append(node);
        else if (walker.isVisitingInsertionPointInReprojection())
            targetStack.append(targetStack.last());
        if (node == rootNode()) {
            // targetStack.last() is one of the followings:
            // - InsertionPoint
            // - shadow host
            // - Document::focusedElement()
            // So, it's safe to do toElement().
            return toElement(targetStack.last());
        }
        if (node->isShadowRoot()) {
            ASSERT(!targetStack.isEmpty());
            targetStack.removeLast();
        }
    }
    return 0;
}
Example #12
0
inline EventTarget& eventTargetRespectingTargetRules(Node& referenceNode)
{
    if (referenceNode.isPseudoElement()) {
        EventTarget* hostElement = toPseudoElement(referenceNode).hostElement();
        ASSERT(hostElement);
        return *hostElement;
    }

#if ENABLE(SVG)
    if (!referenceNode.isSVGElement() || !referenceNode.isInShadowTree())
        return referenceNode;

    // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
    // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects
    Node* rootNode = referenceNode.treeScope().rootNode();
    Element* shadowHostElement = rootNode->isShadowRoot() ? toShadowRoot(rootNode)->hostElement() : 0;
    // At this time, SVG nodes are not supported in non-<use> shadow trees.
    if (!shadowHostElement || !shadowHostElement->hasTagName(SVGNames::useTag))
        return referenceNode;
    SVGUseElement* useElement = toSVGUseElement(shadowHostElement);
    if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(&referenceNode))
        return *instance;
#endif

    return referenceNode;
}
Example #13
0
void EventDispatcher::ensureEventAncestors(Event* event)
{
    if (m_ancestorsInitialized)
        return;
    m_ancestorsInitialized = true;
    bool inDocument = m_node->inDocument();
    bool isSVGElement = m_node->isSVGElement();
    Vector<EventTarget*, 32> targetStack;
    for (AncestorChainWalker walker(m_node.get()); walker.get(); walker.parent()) {
        Node* node = walker.get();
        if (targetStack.isEmpty())
            targetStack.append(eventTargetRespectingTargetRules(node));
        else if (walker.crossingInsertionPoint())
            targetStack.append(targetStack.last());
        m_ancestors.append(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();
        }
    }
}
Example #14
0
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)));
    }
}
// FIXME: Once https://bugs.webkit.org/show_bug.cgi?id=52963 lands, this should
// be greatly improved. See https://bugs.webkit.org/show_bug.cgi?id=54025.
static Node* pullOutOfShadow(Node* node)
{
    Node* outermostShadowBoundary = node;
    for (Node* n = node; n; n = n->parentOrHostNode()) {
        if (n->isShadowRoot())
            outermostShadowBoundary = n->parentOrHostNode();
    }
    return outermostShadowBoundary;
}
Example #16
0
Element* FocusNavigationScope::owner() const
{
    Node* root = rootNode();
    if (root->isShadowRoot()) {
        ShadowRoot* shadowRoot = toShadowRoot(root);
        return shadowRoot->host();
    }
    return 0;
}
Example #17
0
Element* FocusNavigationScope::owner() const
{
    Node* root = rootNode();
    if (root->isShadowRoot())
        return toShadowRoot(root)->host();
    if (Frame* frame = root->document()->frame())
        return frame->ownerElement();
    return 0;
}
Example #18
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 #19
0
ShadowRoot* InsertionPoint::assignedFrom() const
{
    Node* treeScopeRoot = treeScope()->rootNode();
    if (!treeScopeRoot->isShadowRoot())
        return 0;

    ShadowRoot* olderShadowRoot = toShadowRoot(treeScopeRoot)->olderShadowRoot();
    if (olderShadowRoot && olderShadowRoot->assignedTo() == this)
        return olderShadowRoot;
    return 0;
}
Example #20
0
Element* TreeScope::elementFromPoint(int x, int y) const
{
    Node* node = nodeFromPoint(&rootNode()->document(), x, y);
    if (node && node->isTextNode())
        node = node->parentNode();
    ASSERT(!node || node->isElementNode() || node->isShadowRoot());
    node = ancestorInThisScope(node);
    if (!node || !node->isElementNode())
        return 0;
    return toElement(node);
}
Node* DOMPatchSupport::patchNode(Node* node, const String& markup, ExceptionState& exceptionState)
{
    // Don't parse <html> as a fragment.
    if (node->isDocumentNode() || (node->parentNode() && node->parentNode()->isDocumentNode())) {
        patchDocument(markup);
        return 0;
    }

    Node* previousSibling = node->previousSibling();
    RefPtrWillBeRawPtr<DocumentFragment> fragment = DocumentFragment::create(m_document);
    Node* targetNode = node->parentElementOrShadowRoot() ? node->parentElementOrShadowRoot() : m_document.documentElement();

    // Use the document BODY as the context element when editing immediate shadow root children,
    // as it provides an equivalent parsing context.
    if (targetNode->isShadowRoot())
        targetNode = m_document.body();
    Element* targetElement = toElement(targetNode);

    // FIXME: This code should use one of createFragment* in markup.h
    if (m_document.isHTMLDocument())
        fragment->parseHTML(markup, targetElement);
    else
        fragment->parseXML(markup, targetElement);

    // Compose the old list.
    ContainerNode* parentNode = node->parentNode();
    Vector<OwnPtr<Digest> > oldList;
    for (Node* child = parentNode->firstChild(); child; child = child->nextSibling())
        oldList.append(createDigest(child, 0));

    // Compose the new list.
    String markupCopy = markup.lower();
    Vector<OwnPtr<Digest> > newList;
    for (Node* child = parentNode->firstChild(); child != node; child = child->nextSibling())
        newList.append(createDigest(child, 0));
    for (Node* child = fragment->firstChild(); child; child = child->nextSibling()) {
        if (isHTMLHeadElement(*child) && !child->firstChild() && markupCopy.find("</head>") == kNotFound)
            continue; // HTML5 parser inserts empty <head> tag whenever it parses <body>
        if (isHTMLBodyElement(*child) && !child->firstChild() && markupCopy.find("</body>") == kNotFound)
            continue; // HTML5 parser inserts empty <body> tag whenever it parses </head>
        newList.append(createDigest(child, &m_unusedNodesMap));
    }
    for (Node* child = node->nextSibling(); child; child = child->nextSibling())
        newList.append(createDigest(child, 0));

    if (!innerPatchChildren(parentNode, oldList, newList, exceptionState)) {
        // Fall back to total replace.
        if (!m_domEditor->replaceChild(parentNode, fragment.release(), node, exceptionState))
            return 0;
    }
    return previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
}
inline Node* ComposedTreeWalker::traverseParentOrHost(const Node* node) const
{
    Node* parent = node->parentNode();
    if (!parent)
        return 0;
    if (!parent->isShadowRoot())
        return parent;
    ShadowRoot* shadowRoot = toShadowRoot(parent);
    ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot());
    if (!shadowRoot->isYoungest())
        return 0;
    return shadowRoot->host();
}
Example #23
0
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);
        }
    }
}
Element* TreeScope::hitTestPoint(int x, int y, const HitTestRequest& request) const
{
    HitTestResult result = hitTestInDocument(&rootNode().document(), x, y, request);
    Node* node = result.innerNode();
    if (!node || node->isDocumentNode())
        return 0;
    if (node->isPseudoElement() || node->isTextNode())
        node = node->parentOrShadowHostNode();
    ASSERT(!node || node->isElementNode() || node->isShadowRoot());
    node = ancestorInThisScope(node);
    if (!node || !node->isElementNode())
        return 0;
    return toElement(node);
}
static inline bool nodeCanBeDistributed(const Node* node)
{
    ASSERT(node);
    Node* parent = parentNodeForDistribution(node);
    if (!parent)
        return false;

    if (ShadowRoot* shadowRoot = parent->isShadowRoot() ? toShadowRoot(parent) : 0)
        return ScopeContentDistribution::assignedTo(shadowRoot);

    if (parent->isElementNode() && toElement(parent)->shadow())
        return true;

    return false;
}
Example #26
0
inline void TreeScopeAdopter::moveNodeToNewDocument(Node& node, Document& oldDocument, Document& newDocument) const
{
    ASSERT(oldDocument != newDocument);

    if (node.isShadowRoot())
        toShadowRoot(node).setDocument(newDocument);

#if ENABLE(ASSERT)
    didMoveToNewDocumentWasCalled = false;
    oldDocumentDidMoveToNewDocumentWasCalledWith = &oldDocument;
#endif

    node.didMoveToNewDocument(oldDocument);
    ASSERT(didMoveToNewDocumentWasCalled);
}
static inline bool nodeCanBeDistributed(const Node* node)
{
    ASSERT(node);
    Node* parent = parentNodeForDistribution(node);
    if (!parent)
        return false;

    if (ShadowRoot* shadowRoot = parent->isShadowRoot() ? toShadowRoot(parent) : 0)
        return shadowRoot->insertionPoint();

    if (parent->isElementNode() && toElement(parent)->shadow())
        return true;

    return false;
}
Example #28
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 #29
0
Node* DOMSelection::shadowAdjustedNode(const Position& position) const {
    if (position.isNull())
        return 0;

    Node* containerNode = position.computeContainerNode();
    Node* adjustedNode = m_treeScope->ancestorInThisScope(containerNode);

    if (!adjustedNode)
        return 0;

    if (containerNode == adjustedNode)
        return containerNode;

    DCHECK(!adjustedNode->isShadowRoot()) << adjustedNode;
    return adjustedNode->parentOrShadowHostNode();
}
String SVGStyledElement::title() const
{
    // According to spec, we should not return titles when hovering over root <svg> elements (those
    // <title> elements are the title of the document, not a tooltip) so we instantly return.
    if (hasTagName(SVGNames::svgTag)) {
        const SVGSVGElement* svg = static_cast<const SVGSVGElement*>(this);
        if (svg->isOutermostSVG())
            return String();
    }
    
    // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.
    Node* parent = const_cast<SVGStyledElement*>(this);
    while (parent) {
        if (!parent->isShadowRoot()) {
            parent = parent->parentNodeGuaranteedHostFree();
            continue;
        }
        
        // Get the <use> element.
        Element* shadowParent = parent->shadowHost();
        if (shadowParent && shadowParent->isSVGElement() && shadowParent->hasTagName(SVGNames::useTag)) {
            SVGUseElement* useElement = static_cast<SVGUseElement*>(shadowParent);
            // If the <use> title is not empty we found the title to use.
            String useTitle(useElement->title());
            if (useTitle.isEmpty())
                break;
            return useTitle;
        }
        parent = parent->parentNode();
    }
    
    // If we aren't an instance in a <use> or the <use> title was not found, then find the first
    // <title> child of this element.
    Element* titleElement = firstElementChild();
    for (; titleElement; titleElement = titleElement->nextElementSibling()) {
        if (titleElement->hasTagName(SVGNames::titleTag) && titleElement->isSVGElement())
            break;
    }

    // If a title child was found, return the text contents.
    if (titleElement)
        return titleElement->innerText();
    
    // Otherwise return a null/empty string.
    return String();
}