static ContainerNode* traverseParent(const Node* node, ShadowRootCrossing shadowRootCrossing)
{
    if (node->isPseudoElement())
        return toPseudoElement(node)->hostElement();

    if (shadowRootCrossing == DontCrossShadowRoot  && node->isShadowRoot())
        return 0;

    if (nodeCanBeDistributed(node)) {
        if (InsertionPoint* insertionPoint = findInsertionPointOf(node))
            return traverseParent(insertionPoint, shadowRootCrossing);
        return nullptr;
    }
    ContainerNode* parent = node->parentNode();
    if (!parent)
        return nullptr;

    if (parent->isShadowRoot())
        return shadowRootCrossing == CrossShadowRoot ? toShadowRoot(parent)->hostElement() : parent;

    if (parent->isInsertionPoint()) {
        const InsertionPoint* insertionPoint = toInsertionPoint(parent);
        if (insertionPoint->hasDistribution())
            return nullptr;
        if (insertionPoint->isActive())
            return traverseParent(parent, shadowRootCrossing);
    }
    return parent;
}
Пример #2
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 ContentDistributor::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
{
    ContentDistribution distribution;
    for (Node* node = containerNode->firstChild(); node; node = node->nextSibling()) {
        if (isActiveInsertionPoint(node)) {
            InsertionPoint* innerInsertionPoint = toInsertionPoint(node);
            if (innerInsertionPoint->hasDistribution()) {
                for (size_t i = 0; i < innerInsertionPoint->size(); ++i) {
                    distribution.append(innerInsertionPoint->at(i));
                    if (!m_nodeToInsertionPoint.contains(innerInsertionPoint->at(i)))
                        m_nodeToInsertionPoint.add(innerInsertionPoint->at(i), insertionPoint);
                }
            } else {
                for (Node* child = innerInsertionPoint->firstChild(); child; child = child->nextSibling()) {
                    distribution.append(child);
                    m_nodeToInsertionPoint.add(child, insertionPoint);
                }
            }
        } else {
            distribution.append(node);
            if (!m_nodeToInsertionPoint.contains(node))
                m_nodeToInsertionPoint.add(node, insertionPoint);
        }
    }

    insertionPoint->setDistribution(distribution);
}
inline Node* ComposedShadowTreeWalker::traverseNodeEscapingFallbackContents(const Node* node, ParentTraversalDetails* details) const
{
    ASSERT(node);
    if (!node->isInsertionPoint())
        return const_cast<Node*>(node);
    const InsertionPoint* insertionPoint = toInsertionPoint(node);
    return insertionPoint->hasDistribution() ? 0 :
        insertionPoint->isActive() ? traverseParent(node, details) : const_cast<Node*>(node);
}
Пример #5
0
bool Internals::isValidContentSelect(Element* insertionPoint, ExceptionCode& ec)
{
    if (!insertionPoint || !isInsertionPoint(insertionPoint)) {
        ec = INVALID_ACCESS_ERR;
        return false;
    }

    return toInsertionPoint(insertionPoint)->isSelectValid();
}
static Node* findLastEnteringInsertionPoints(const Node* node)
{
    ASSERT(node);
    if (!isActiveInsertionPoint(node))
        return const_cast<Node*>(node);
    const InsertionPoint* insertionPoint = toInsertionPoint(node);
    if (Node* found = findLastFromDistributedNode(insertionPoint->lastDistributed(), insertionPoint))
        return found;
    return findLastSiblingEnteringInsertionPoints(node->lastChild());
}
Node* ComposedShadowTreeWalker::traverseNode(const Node* node, TraversalDirection direction)
{
    ASSERT(node);
    if (!isActiveInsertionPoint(node))
        return const_cast<Node*>(node);
    const InsertionPoint* insertionPoint = toInsertionPoint(node);
    if (Node* found = traverseDistributedNodes(direction == TraversalDirectionForward ? insertionPoint->first() : insertionPoint->last(), insertionPoint, direction))
        return found;
    return traverseLightChildren(node, direction);
}
Node* ComposedTreeWalker::traverseNode(const Node* node, TraversalDirection direction)
{
    ASSERT(node);
    if (!isActiveInsertionPoint(*node))
        return const_cast<Node*>(node);
    const InsertionPoint* insertionPoint = toInsertionPoint(node);
    if (Node* found = traverseDistributedNodes(direction == TraversalDirectionForward ? insertionPoint->first() : insertionPoint->last(), insertionPoint, direction))
        return found;
    ASSERT(node->hasTagName(HTMLNames::shadowTag) || (node->hasTagName(HTMLNames::contentTag) && !node->hasChildNodes()));
    return 0;
}
Пример #9
0
Node* ComposedShadowTreeWalker::traverseNode(const Node* node, TraversalDirection direction)
{
    ASSERT(node);
    if (!isInsertionPoint(node))
        return const_cast<Node*>(node);
    const InsertionPoint* insertionPoint = toInsertionPoint(node);
    if (!insertionPoint->isActive())
        return const_cast<Node*>(node);
    if (Node* next = (direction == TraversalDirectionForward ? insertionPoint->first() : insertionPoint->last()))
        return traverseNode(next, direction);
    return traverseLightChildren(node, direction);
}
Node* FlatTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, TraversalDirection direction)
{
    DCHECK(!isHTMLSlotElement(node));
    for (const Node* sibling = &node; sibling; sibling = (direction == TraversalDirectionForward ? sibling->nextSibling() : sibling->previousSibling())) {
        if (!isActiveInsertionPoint(*sibling))
            return const_cast<Node*>(sibling);
        const InsertionPoint& insertionPoint = toInsertionPoint(*sibling);
        if (Node* found = (direction == TraversalDirectionForward ? insertionPoint.firstDistributedNode() : insertionPoint.lastDistributedNode()))
            return found;
        DCHECK(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(insertionPoint) && !insertionPoint.hasChildren()));
    }
    return nullptr;
}
Пример #11
0
void ContentDistributor::distribute(Element* host)
{
    ASSERT(needsDistribution());
    ASSERT(m_nodeToInsertionPoint.isEmpty());

    m_validity = Valid;

    ContentDistribution pool;
    for (Node* node = host->firstChild(); node; node = node->nextSibling())
        populate(node, pool);

    Vector<bool> distributed(pool.size());
    distributed.fill(false);

    Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints;
    for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
        HTMLShadowElement* firstActiveShadowInsertionPoint = 0;

        for (Node* node = root; node; node = node->traverseNextNode(root)) {
            if (!isActiveInsertionPoint(node))
                continue;
            InsertionPoint* point = toInsertionPoint(node);

            if (isHTMLShadowElement(node)) {
                if (!firstActiveShadowInsertionPoint)
                    firstActiveShadowInsertionPoint = toHTMLShadowElement(node);
            } else {
                distributeSelectionsTo(point, pool, distributed);
                if (ElementShadow* shadow = node->parentNode()->isElementNode() ? toElement(node->parentNode())->shadow() : 0)
                    shadow->invalidateDistribution();
            }
        }

        if (firstActiveShadowInsertionPoint)
            activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint);
    }

    for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) {
        HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1];
        ShadowRoot* root = shadowElement->shadowRoot();
        ASSERT(root);
        if (root->olderShadowRoot()) {
            distributeNodeChildrenTo(shadowElement, root->olderShadowRoot());
            root->olderShadowRoot()->setAssignedTo(shadowElement);
        } else {
            distributeSelectionsTo(shadowElement, pool, distributed);
            if (ElementShadow* shadow = shadowElement->parentNode()->isElementNode() ? toElement(shadowElement->parentNode())->shadow() : 0)
                shadow->invalidateDistribution();
        }
    }
}
Пример #12
0
inline void DistributionPool::populateChildren(const ContainerNode* parent)
{
    for (Node* child = parent->firstChild(); child; child = child->nextSibling()) {
        if (isActiveInsertionPoint(*child)) {
            InsertionPoint* insertionPoint = toInsertionPoint(child);
            for (size_t i = 0; i < insertionPoint->size(); ++i)
                m_nodes.append(insertionPoint->at(i));
        } else {
            m_nodes.append(child);
        }
    }
    m_distributed.resize(m_nodes.size());
    m_distributed.fill(false);
}
Пример #13
0
const Vector<RefPtr<InsertionPoint> >& ContentDistributor::ensureInsertionPointList(ShadowRoot* shadowRoot)
{
    if (m_insertionPointListIsValid)
        return m_insertionPointList;

    m_insertionPointListIsValid = true;
    ASSERT(m_insertionPointList.isEmpty());

    for (Element* element = ElementTraversal::firstWithin(shadowRoot); element; element = ElementTraversal::next(element, shadowRoot)) {
        if (element->isInsertionPoint())
            m_insertionPointList.append(toInsertionPoint(element));
    }

    return m_insertionPointList;
}
Пример #14
0
const Vector<RefPtr<InsertionPoint>>& ContentDistributor::ensureInsertionPointList(ShadowRoot* shadowRoot)
{
    if (m_insertionPointListIsValid)
        return m_insertionPointList;

    m_insertionPointListIsValid = true;
    ASSERT(m_insertionPointList.isEmpty());

    for (auto& element : descendantsOfType<Element>(*shadowRoot)) {
        if (element.isInsertionPoint())
            m_insertionPointList.append(toInsertionPoint(&element));
    }

    return m_insertionPointList;
}
Пример #15
0
void ContentDistributor::populate(Node* node, ContentDistribution& pool)
{
    if (!isActiveInsertionPoint(node)) {
        pool.append(node);
        return;
    }

    InsertionPoint* insertionPoint = toInsertionPoint(node);
    if (insertionPoint->hasDistribution()) {
        for (size_t i = 0; i < insertionPoint->size(); ++i)
            populate(insertionPoint->at(i), pool);
    } else {
        for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling())
            pool.append(fallbackNode);
    }
}
const Vector<InsertionPoint*>& ShadowRootContentDistributionData::ensureInsertionPointList(ShadowRoot* shadowRoot)
{
    if (m_insertionPointListIsValid)
        return m_insertionPointList;

    m_insertionPointListIsValid = true;
    ASSERT(m_insertionPointList.isEmpty());

    if (!shadowRoot->hasInsertionPoint())
        return m_insertionPointList;

    for (Node* node = shadowRoot; node; node = node->traverseNextNode(shadowRoot)) {
        if (node->isInsertionPoint())
            m_insertionPointList.append(toInsertionPoint(node));
    }

    return m_insertionPointList;
}
Пример #17
0
inline void DistributionPool::populateChildren(const ContainerNode& parent) {
  clear();
  for (Node* child = parent.firstChild(); child; child = child->nextSibling()) {
    if (isHTMLSlotElement(child)) {
      // TODO(hayato): Support re-distribution across v0 and v1 shadow trees
      continue;
    }
    if (isActiveInsertionPoint(*child)) {
      InsertionPoint* insertionPoint = toInsertionPoint(child);
      for (size_t i = 0; i < insertionPoint->distributedNodesSize(); ++i)
        m_nodes.append(insertionPoint->distributedNodeAt(i));
    } else {
      m_nodes.append(child);
    }
  }
  m_distributed.resize(m_nodes.size());
  m_distributed.fill(false);
}
Пример #18
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;
        }
    }
}
Пример #19
0
bool ContentDistributor::invalidate(Element* host)
{
    ASSERT(needsInvalidation());
    bool needsReattach = (m_validity == Undetermined) || !m_nodeToInsertionPoint.isEmpty();

    for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
        root->setAssignedTo(0);

        for (Node* node = root; node; node = node->traverseNextNode(root)) {
            if (!isInsertionPoint(node))
                continue;
            needsReattach = needsReattach || true;
            InsertionPoint* point = toInsertionPoint(node);
            point->clearDistribution();
        }
    }

    m_validity = Invalidating;
    m_nodeToInsertionPoint.clear();
    return needsReattach;
}
Пример #20
0
const Vector<RefPtr<InsertionPoint> >& ShadowRoot::descendantInsertionPoints()
{
    DEFINE_STATIC_LOCAL(const Vector<RefPtr<InsertionPoint> >, emptyList, ());

    if (m_shadowRootRareData && m_descendantInsertionPointsIsValid)
        return m_shadowRootRareData->descendantInsertionPoints();

    m_descendantInsertionPointsIsValid = true;

    if (!containsInsertionPoints())
        return emptyList;

    Vector<RefPtr<InsertionPoint> > insertionPoints;
    for (Element* element = ElementTraversal::firstWithin(*this); element; element = ElementTraversal::next(*element, this)) {
        if (element->isInsertionPoint())
            insertionPoints.append(toInsertionPoint(element));
    }

    ensureShadowRootRareData()->setDescendantInsertionPoints(insertionPoints);

    return m_shadowRootRareData->descendantInsertionPoints();
}