Ejemplo n.º 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(!isActiveInsertionPoint(*anchor));
        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 (isActiveInsertionPoint(*child)) {
            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 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::escapeFallbackContentElement(const Node* node, TraversalDirection direction)
{
    ASSERT(node);
    if (node->parentNode() && isActiveInsertionPoint(node->parentNode()))
        return traverseSiblingOrBackToInsertionPoint(node->parentNode(), direction);
    return 0;
}
Ejemplo n.º 4
0
Node* ComposedShadowTreeWalker::traverseNodeEscapingFallbackContents(const Node* node) const
{
    ASSERT(node);
    if (isActiveInsertionPoint(node))
        return traverseParent(node);
    return const_cast<Node*>(node);
}
Ejemplo n.º 5
0
void ContentDistribution::append(PassRefPtrWillBeRawPtr<Node> node)
{
    ASSERT(node);
    ASSERT(!isActiveInsertionPoint(*node));
    size_t size = m_nodes.size();
    m_indices.set(node.get(), size);
    m_nodes.append(node);
}
Ejemplo n.º 6
0
ContainerNode* parent(const Node* node, ParentDetails* details)
{
    ASSERT(node);
    ASSERT(!node->document().childNeedsDistributionRecalc());
    if (isActiveInsertionPoint(*node))
        return 0;
    ComposedTreeWalker walker(node, ComposedTreeWalker::CanStartFromShadowBoundary);
    return toContainerNode(walker.traverseParent(walker.get(), details));
}
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);
}
Ejemplo n.º 9
0
void SlotAssignment::resolveAssignment(const ShadowRoot& shadowRoot)
{
    m_assignment.clear();

    using Name2Slot = WillBeHeapHashMap<AtomicString, RefPtrWillBeMember<HTMLSlotElement>>;
    Name2Slot name2slot;
    HTMLSlotElement* defaultSlot = nullptr;
    WillBeHeapVector<RefPtrWillBeMember<HTMLSlotElement>> slots;

    // TODO(hayato): Cache slots elements so that we do not have to travese the shadow tree. See ShadowRoot::descendantInsertionPoints()
    for (HTMLSlotElement& slot : Traversal<HTMLSlotElement>::descendantsOf(shadowRoot)) {
        slot.clearDistribution();

        slots.append(&slot);

        AtomicString name = slot.fastGetAttribute(HTMLNames::nameAttr);
        if (name.isNull() || name.isEmpty()) {
            if (!defaultSlot)
                defaultSlot = &slot;
        } else {
            name2slot.add(name, &slot);
        }
    }

    for (Node& child : NodeTraversal::childrenOf(*shadowRoot.host())) {
        if (child.isElementNode()) {
            if (isActiveInsertionPoint(child)) {
                // TODO(hayato): Support re-distribution across v0 and v1 shadow trees
                detachNotAssignedNode(child);
                continue;
            }
            AtomicString slotName = toElement(child).fastGetAttribute(HTMLNames::slotAttr);
            if (slotName.isNull() || slotName.isEmpty()) {
                if (defaultSlot)
                    assign(child, *defaultSlot);
                else
                    detachNotAssignedNode(child);
            } else {
                HTMLSlotElement* slot = name2slot.get(slotName);
                if (slot)
                    assign(child, *slot);
                else
                    detachNotAssignedNode(child);
            }
        } else if (defaultSlot) {
            assign(child, *defaultSlot);
        } else {
            detachNotAssignedNode(child);
        }
    }

    // Update each slot's distribution in reverse tree order so that a child slot is visited before its parent slot.
    for (auto slot = slots.rbegin(); slot != slots.rend(); ++slot)
        (*slot)->updateDistributedNodesWithFallback();
}
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;
}
Ejemplo n.º 11
0
Node* previousInScope(const Node* node)
{
    ASSERT(!isActiveInsertionPoint(node));

    if (Node* current = traversePreviousSibling(node)) {
        while (Node* child = traverseLastChild(current, DontCrossShadowRoot))
            current = child;
        return current;
    }
    return traverseParent(node, DontCrossShadowRoot);
}
Ejemplo n.º 12
0
LayoutTreeBuilderForElement::LayoutTreeBuilderForElement(Element& element, ComputedStyle* style)
    : LayoutTreeBuilder(element, nullptr)
    , m_style(style)
{
    ASSERT(!isActiveInsertionPoint(element));
    if (element.isFirstLetterPseudoElement()) {
        if (LayoutObject* nextLayoutObject = FirstLetterPseudoElement::firstLetterTextLayoutObject(element))
            m_layoutObjectParent = nextLayoutObject->parent();
    } else if (ContainerNode* containerNode = LayoutTreeBuilderTraversal::parent(element)) {
        m_layoutObjectParent = containerNode->layoutObject();
    }
}
Ejemplo n.º 13
0
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;
}
Ejemplo n.º 14
0
Node* nextInScope(const Node* node)
{
    ASSERT(!isActiveInsertionPoint(node));

    if (Node* next = traverseFirstChild(node, DontCrossShadowRoot))
        return next;
    if (Node* next = traverseNextSibling(node))
        return next;
    const Node* current = node;
    while (current && !traverseNextSibling(current))
        current = traverseParent(current, DontCrossShadowRoot);
    return current ? traverseNextSibling(current) : 0;
}
Ejemplo n.º 15
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();
        }
    }
}
Ejemplo n.º 16
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);
}
Ejemplo n.º 17
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);
    }
}
Ejemplo n.º 18
0
ContainerNode* FlatTreeTraversal::traverseParentForV0(const Node& node, ParentTraversalDetails* details)
{
    if (shadowWhereNodeCanBeDistributed(node)) {
        if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) {
            if (details)
                details->didTraverseInsertionPoint(insertionPoint);
            // The node is distributed. But the distribution was stopped at this insertion point.
            if (shadowWhereNodeCanBeDistributed(*insertionPoint))
                return nullptr;
            return traverseParent(*insertionPoint);
        }
        return nullptr;
    }
    ContainerNode* parent = traverseParentOrHost(node);
    if (isActiveInsertionPoint(*parent))
        return nullptr;
    return parent;
}
Ejemplo n.º 19
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);
}
Ejemplo n.º 20
0
static Node* traversePreviousSibling(const Node* node)
{
    ASSERT(node);

    InsertionPoint* insertionPoint;
    if (nodeCanBeDistributed(node) && (insertionPoint = findInsertionPointOf(node))) {
        Node* found = findLastFromDistributedNode(insertionPoint->previousDistributedTo(node), insertionPoint);
        if (found)
            return found;
        return traversePreviousSibling(insertionPoint);
    }

    for (const Node* sibling = node->previousSibling(); sibling; sibling = sibling->previousSibling()) {
        if (Node* found = findLastEnteringInsertionPoints(sibling))
            return found;
    }
    if (node->parentNode() && isActiveInsertionPoint(node->parentNode()))
        return traversePreviousSibling(node->parentNode());

    return nullptr;
}
Ejemplo n.º 21
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;
    for (ComposedShadowTreeParentWalker walker(m_node.get()); walker.get(); walker.parentIncludingInsertionPointAndShadowRoot()) {
        Node* node = walker.get();
        if (isActiveInsertionPoint(node) || targetStack.isEmpty())
            targetStack.append(eventTargetRespectingSVGTargetRules(node));
        m_ancestors.append(EventContext(node, eventTargetRespectingSVGTargetRules(node), targetStack.last()));
        if (!inDocument)
            return;
        if (!node->isShadowRoot())
            continue;
        if (determineDispatchBehavior(event, toShadowRoot(node)) == StayInsideShadowDOM)
            return;
        if (!isSVGElement && !targetStack.isEmpty())
            targetStack.removeLast();
    }
}
Ejemplo n.º 22
0
Node* lastChildInScope(const Node* node)
{
    ASSERT(!isActiveInsertionPoint(node));

    return traverseLastChild(node, DontCrossShadowRoot);
}
Ejemplo n.º 23
0
Node* parentInScope(const Node* node)
{
    ASSERT(!isActiveInsertionPoint(node));

    return traverseParent(node, DontCrossShadowRoot);
}