RawPtr<Node> Text::mergeNextSiblingNodesIfPossible()
{
    RawPtr<Node> protect(this);

    // Remove empty text nodes.
    if (!length()) {
        // Care must be taken to get the next node before removing the current node.
        RawPtr<Node> nextNode(NodeTraversal::nextPostOrder(*this));
        remove(IGNORE_EXCEPTION);
        return nextNode.release();
    }

    // Merge text nodes.
    while (Node* nextSibling = this->nextSibling()) {
        if (nextSibling->getNodeType() != TEXT_NODE)
            break;

        RawPtr<Text> nextText = toText(nextSibling);

        // Remove empty text nodes.
        if (!nextText->length()) {
            nextText->remove(IGNORE_EXCEPTION);
            continue;
        }

        // Both non-empty text nodes. Merge them.
        unsigned offset = length();
        String nextTextData = nextText->data();
        String oldTextData = data();
        setDataWithoutUpdate(data() + nextTextData);
        updateTextLayoutObject(oldTextData.length(), 0);

        // Empty nextText for layout update.
        nextText->setDataWithoutUpdate(emptyString());
        nextText->updateTextLayoutObject(0, nextTextData.length());

        document().didMergeTextNodes(*nextText, offset);

        // Restore nextText for mutation event.
        nextText->setDataWithoutUpdate(nextTextData);
        nextText->updateTextLayoutObject(0, 0);

        document().incDOMTreeVersion();
        didModifyData(oldTextData, CharacterData::UpdateFromNonParser);
        nextText->remove(IGNORE_EXCEPTION);
    }

    return NodeTraversal::nextPostOrder(*this);
}