예제 #1
0
const TreeScope* TreeScope::commonAncestorTreeScope(const TreeScope& other) const
{
    HeapVector<Member<const TreeScope>, 16> thisChain;
    for (const TreeScope* tree = this; tree; tree = tree->parentTreeScope())
        thisChain.append(tree);

    HeapVector<Member<const TreeScope>, 16> otherChain;
    for (const TreeScope* tree = &other; tree; tree = tree->parentTreeScope())
        otherChain.append(tree);

    // Keep popping out the last elements of these chains until a mismatched pair is found. If |this| and |other|
    // belong to different documents, null will be returned.
    const TreeScope* lastAncestor = nullptr;
    while (!thisChain.isEmpty() && !otherChain.isEmpty() && thisChain.last() == otherChain.last()) {
        lastAncestor = thisChain.last();
        thisChain.removeLast();
        otherChain.removeLast();
    }
    return lastAncestor;
}
Node* StyledMarkupTraverser<Strategy>::traverse(Node* startNode, Node* pastEnd)
{
    HeapVector<Member<ContainerNode>> ancestorsToClose;
    Node* next;
    Node* lastClosed = nullptr;
    for (Node* n = startNode; n && n != pastEnd; n = next) {
        // If |n| is a selection boundary such as <input>, traverse the child
        // nodes in the DOM tree instead of the flat tree.
        if (handleSelectionBoundary<Strategy>(*n)) {
            lastClosed = StyledMarkupTraverser<EditingStrategy>(m_accumulator, m_lastClosed.get()).traverse(n, EditingStrategy::nextSkippingChildren(*n));
            next = EditingInFlatTreeStrategy::nextSkippingChildren(*n);
        } else {
            next = Strategy::next(*n);
            if (isEnclosingBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd) {
                // Don't write out empty block containers that aren't fully selected.
                continue;
            }

            if (!n->layoutObject() && !enclosingElementWithTag(firstPositionInOrBeforeNode(n), selectTag)) {
                next = Strategy::nextSkippingChildren(*n);
                // Don't skip over pastEnd.
                if (pastEnd && Strategy::isDescendantOf(*pastEnd, *n))
                    next = pastEnd;
            } else {
                // Add the node to the markup if we're not skipping the descendants
                appendStartMarkup(*n);

                // If node has no children, close the tag now.
                if (Strategy::hasChildren(*n)) {
                    ancestorsToClose.append(toContainerNode(n));
                    continue;
                }
                appendEndMarkup(*n);
                lastClosed = n;
            }
        }

        // If we didn't insert open tag and there's no more siblings or we're at the end of the traversal, take care of ancestors.
        // FIXME: What happens if we just inserted open tag and reached the end?
        if (Strategy::nextSibling(*n) && next != pastEnd)
            continue;

        // Close up the ancestors.
        while (!ancestorsToClose.isEmpty()) {
            ContainerNode* ancestor = ancestorsToClose.last();
            ASSERT(ancestor);
            if (next && next != pastEnd && Strategy::isDescendantOf(*next, *ancestor))
                break;
            // Not at the end of the range, close ancestors up to sibling of next node.
            appendEndMarkup(*ancestor);
            lastClosed = ancestor;
            ancestorsToClose.removeLast();
        }

        // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors.
        ContainerNode* nextParent = next ? Strategy::parent(*next) : nullptr;
        if (next == pastEnd || n == nextParent)
            continue;

        ASSERT(n);
        Node* lastAncestorClosedOrSelf = (lastClosed && Strategy::isDescendantOf(*n, *lastClosed)) ? lastClosed : n;
        for (ContainerNode* parent = Strategy::parent(*lastAncestorClosedOrSelf); parent && parent != nextParent; parent = Strategy::parent(*parent)) {
            // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered:
            if (!parent->layoutObject())
                continue;
            // or b) ancestors that we never encountered during a pre-order traversal starting at startNode:
            ASSERT(startNode);
            ASSERT(Strategy::isDescendantOf(*startNode, *parent));
            RawPtr<EditingStyle> style = createInlineStyleIfNeeded(*parent);
            wrapWithNode(*parent, style);
            lastClosed = parent;
        }
    }

    return lastClosed;
}