⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 compositeeditcommand.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        ASSERT(anchorNode->isLink());        setEndingSelection(VisibleSelection::selectionFromContentsOfNode(anchorNode));    applyStyledElement(static_cast<Element*>(anchorNode));    // Clones of anchorNode have been pushed down, now remove it.    if (anchorNode->inDocument())        removeNodePreservingChildren(anchorNode);}// We must push partially selected anchors down before creating or removing// links from a selection to create fully selected chunks that can be removed.// ApplyStyleCommand doesn't do this for us because styles can be nested.// Anchors cannot be nested.void CompositeEditCommand::pushPartiallySelectedAnchorElementsDown(){    VisibleSelection originalSelection = endingSelection();    VisiblePosition visibleStart(originalSelection.start());    VisiblePosition visibleEnd(originalSelection.end());        Node* startAnchor = enclosingAnchorElement(originalSelection.start());    VisiblePosition startOfStartAnchor(Position(startAnchor, 0));    if (startAnchor && startOfStartAnchor != visibleStart)        pushAnchorElementDown(startAnchor);    Node* endAnchor = enclosingAnchorElement(originalSelection.end());    VisiblePosition endOfEndAnchor(Position(endAnchor, 0));    if (endAnchor && endOfEndAnchor != visibleEnd)        pushAnchorElementDown(endAnchor);    ASSERT(originalSelection.start().node()->inDocument() && originalSelection.end().node()->inDocument());    setEndingSelection(originalSelection);}// This moves a paragraph preserving its style.void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle){    ASSERT(isStartOfParagraph(startOfParagraphToMove));    ASSERT(isEndOfParagraph(endOfParagraphToMove));    moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, preserveSelection, preserveStyle);}void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle){    if (startOfParagraphToMove == destination)        return;        int startIndex = -1;    int endIndex = -1;    int destinationIndex = -1;    if (preserveSelection && !endingSelection().isNone()) {        VisiblePosition visibleStart = endingSelection().visibleStart();        VisiblePosition visibleEnd = endingSelection().visibleEnd();                bool startAfterParagraph = Range::compareBoundaryPoints(visibleStart.deepEquivalent(), endOfParagraphToMove.deepEquivalent()) > 0;        bool endBeforeParagraph = Range::compareBoundaryPoints(visibleEnd.deepEquivalent(), startOfParagraphToMove.deepEquivalent()) < 0;                if (!startAfterParagraph && !endBeforeParagraph) {            bool startInParagraph = Range::compareBoundaryPoints(visibleStart.deepEquivalent(), startOfParagraphToMove.deepEquivalent()) >= 0;            bool endInParagraph = Range::compareBoundaryPoints(visibleEnd.deepEquivalent(), endOfParagraphToMove.deepEquivalent()) <= 0;                        startIndex = 0;            if (startInParagraph) {                RefPtr<Range> startRange = Range::create(document(), rangeCompliantEquivalent(startOfParagraphToMove.deepEquivalent()), rangeCompliantEquivalent(visibleStart.deepEquivalent()));                startIndex = TextIterator::rangeLength(startRange.get(), true);            }            endIndex = 0;            if (endInParagraph) {                RefPtr<Range> endRange = Range::create(document(), rangeCompliantEquivalent(startOfParagraphToMove.deepEquivalent()), rangeCompliantEquivalent(visibleEnd.deepEquivalent()));                endIndex = TextIterator::rangeLength(endRange.get(), true);            }        }    }        VisiblePosition beforeParagraph = startOfParagraphToMove.previous();    VisiblePosition afterParagraph(endOfParagraphToMove.next());    // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.    // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.        Position start = startOfParagraphToMove.deepEquivalent().downstream();    Position end = endOfParagraphToMove.deepEquivalent().upstream();        // start and end can't be used directly to create a Range; they are "editing positions"    Position startRangeCompliant = rangeCompliantEquivalent(start);    Position endRangeCompliant = rangeCompliantEquivalent(end);    RefPtr<Range> range = Range::create(document(), startRangeCompliant.node(), startRangeCompliant.offset(), endRangeCompliant.node(), endRangeCompliant.offset());    // FIXME: This is an inefficient way to preserve style on nodes in the paragraph to move.  It     // shouldn't matter though, since moved paragraphs will usually be quite small.    RefPtr<DocumentFragment> fragment = startOfParagraphToMove != endOfParagraphToMove ? createFragmentFromMarkup(document(), createMarkup(range.get(), 0, DoNotAnnotateForInterchange, true), "") : 0;        // A non-empty paragraph's style is moved when we copy and move it.  We don't move     // anything if we're given an empty paragraph, but an empty paragraph can have style    // too, <div><b><br></b></div> for example.  Save it so that we can preserve it later.    RefPtr<CSSMutableStyleDeclaration> styleInEmptyParagraph;    if (startOfParagraphToMove == endOfParagraphToMove && preserveStyle) {        styleInEmptyParagraph = styleAtPosition(startOfParagraphToMove.deepEquivalent());        // The moved paragraph should assume the block style of the destination.        styleInEmptyParagraph->removeBlockProperties();    }        // FIXME (5098931): We should add a new insert action "WebViewInsertActionMoved" and call shouldInsertFragment here.        setEndingSelection(VisibleSelection(start, end, DOWNSTREAM));    deleteSelection(false, false, false, false);    ASSERT(destination.deepEquivalent().node()->inDocument());        // There are bugs in deletion when it removes a fully selected table/list.      // It expands and removes the entire table/list, but will let content    // before and after the table/list collapse onto one line.        // Deleting a paragraph will leave a placeholder.  Remove it (and prune    // empty or unrendered parents).    VisiblePosition caretAfterDelete = endingSelection().visibleStart();    if (isStartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) {        // Note: We want the rightmost candidate.        Position position = caretAfterDelete.deepEquivalent().downstream();        Node* node = position.node();        // Normally deletion will leave a br as a placeholder.        if (node->hasTagName(brTag))            removeNodeAndPruneAncestors(node);        // If the selection to move was empty and in an empty block that         // doesn't require a placeholder to prop itself open (like a bordered         // div or an li), remove it during the move (the list removal code         // expects this behavior).        else if (isBlock(node))            removeNodeAndPruneAncestors(node);        else if (lineBreakExistsAtPosition(caretAfterDelete)) {            // There is a preserved '\n' at caretAfterDelete.            Text* textNode = static_cast<Text*>(node);            if (textNode->length() == 1)                removeNodeAndPruneAncestors(node);            else                 deleteTextFromNode(textNode, position.offset(), 1);        }    }    // Add a br if pruning an empty block level element caused a collapse.  For example:    // foo^    // <div>bar</div>    // baz    // Imagine moving 'bar' to ^.  'bar' will be deleted and its div pruned.  That would    // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br.    // Must recononicalize these two VisiblePositions after the pruning above.    beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());    afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());    if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || beforeParagraph == afterParagraph)) {        // FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.        insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquivalent());        // Need an updateLayout here in case inserting the br has split a text node.        updateLayout();    }            RefPtr<Range> startToDestinationRange(Range::create(document(), Position(document(), 0), rangeCompliantEquivalent(destination.deepEquivalent())));    destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(), true);        setEndingSelection(destination);    applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment, true, false, !preserveStyle, false, true));    // Restore styles from an empty paragraph to the new empty paragraph.    if (styleInEmptyParagraph)        applyStyle(styleInEmptyParagraph.get());        if (preserveSelection && startIndex != -1) {        // Fragment creation (using createMarkup) incorrectly uses regular        // spaces instead of nbsps for some spaces that were rendered (11475), which        // causes spaces to be collapsed during the move operation.  This results        // in a call to rangeFromLocationAndLength with a location past the end        // of the document (which will return null).        RefPtr<Range> start = TextIterator::rangeFromLocationAndLength(document()->documentElement(), destinationIndex + startIndex, 0, true);        RefPtr<Range> end = TextIterator::rangeFromLocationAndLength(document()->documentElement(), destinationIndex + endIndex, 0, true);        if (start && end)            setEndingSelection(VisibleSelection(start->startPosition(), end->startPosition(), DOWNSTREAM));    }}// FIXME: Send an appropriate shouldDeleteRange call.bool CompositeEditCommand::breakOutOfEmptyListItem(){    Node* emptyListItem = enclosingEmptyListItem(endingSelection().visibleStart());    if (!emptyListItem)        return false;            RefPtr<CSSMutableStyleDeclaration> style = styleAtPosition(endingSelection().start());    Node* listNode = emptyListItem->parentNode();        if (!listNode->isContentEditable())        return false;        RefPtr<Element> newBlock = isListElement(listNode->parentNode()) ? createListItemElement(document()) : createDefaultParagraphElement(document());        if (emptyListItem->renderer()->nextSibling()) {        if (emptyListItem->renderer()->previousSibling())            splitElement(static_cast<Element*>(listNode), emptyListItem);        insertNodeBefore(newBlock, listNode);        removeNode(emptyListItem);    } else {        insertNodeAfter(newBlock, listNode);        removeNode(emptyListItem->renderer()->previousSibling() ? emptyListItem : listNode);    }        appendBlockPlaceholder(newBlock);    setEndingSelection(VisibleSelection(Position(newBlock.get(), 0), DOWNSTREAM));        computedStyle(endingSelection().start().node())->diff(style.get());    if (style->length() > 0)        applyStyle(style.get());        return true;}// If the caret is in an empty quoted paragraph, and either there is nothing before that// paragraph, or what is before is unquoted, and the user presses delete, unquote that paragraph.bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph(){    if (!endingSelection().isCaret())        return false;            VisiblePosition caret(endingSelection().visibleStart());    Node* highestBlockquote = highestEnclosingNodeOfType(caret.deepEquivalent(), &isMailBlockquote);    if (!highestBlockquote)        return false;            if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret))        return false;        VisiblePosition previous(caret.previous(true));    // Only move forward if there's nothing before the caret, or if there's unquoted content before it.    if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote))        return false;        RefPtr<Node> br = createBreakElement(document());    // We want to replace this quoted paragraph with an unquoted one, so insert a br    // to hold the caret before the highest blockquote.    insertNodeBefore(br, highestBlockquote);    VisiblePosition atBR(Position(br.get(), 0));    // If the br we inserted collapsed, for example foo<br><blockquote>...</blockquote>, insert     // a second one.    if (!isStartOfParagraph(atBR))        insertNodeBefore(createBreakElement(document()), br);    setEndingSelection(VisibleSelection(atBR));        // If this is an empty paragraph there must be a line break here.    if (!lineBreakExistsAtPosition(caret))        return false;        Position caretPos(caret.deepEquivalent());    // A line break is either a br or a preserved newline.    ASSERT(caretPos.node()->hasTagName(brTag) || caretPos.node()->isTextNode() && caretPos.node()->renderer()->style()->preserveNewline());        if (caretPos.node()->hasTagName(brTag)) {        Position beforeBR(positionBeforeNode(caretPos.node()));        removeNode(caretPos.node());        prune(beforeBR.node());    } else {        ASSERT(caretPos.offset() == 0);        Text* textNode = static_cast<Text*>(caretPos.node());        Node* parentNode = textNode->parentNode();        // The preserved newline must be the first thing in the node, since otherwise the previous        // paragraph would be quoted, and we verified that it wasn't above.        deleteTextFromNode(textNode, 0, 1);        prune(parentNode);    }        return true;}// Operations use this function to avoid inserting content into an anchor when at the start or the end of // that anchor, as in NSTextView.// FIXME: This is only an approximation of NSTextViews insertion behavior, which varies depending on how// the caret was made. Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Position& original){    if (original.isNull())        return original;            VisiblePosition visiblePos(original);    Node* enclosingAnchor = enclosingAnchorElement(original);    Position result = original;    // Don't avoid block level anchors, because that would insert content into the wrong paragraph.    if (enclosingAnchor && !isBlock(enclosingAnchor)) {        VisiblePosition firstInAnchor(Position(enclosingAnchor, 0));        VisiblePosition lastInAnchor(Position(enclosingAnchor, maxDeepOffset(enclosingAnchor)));        // If visually just after the anchor, insert *inside* the anchor unless it's the last         // VisiblePosition in the document, to match NSTextView.        if (visiblePos == lastInAnchor) {            // Make sure anchors are pushed down before avoiding them so that we don't            // also avoid structural elements like lists and blocks (5142012).            if (original.node() != enclosingAnchor && original.node()->parentNode() != enclosingAnchor) {                pushAnchorElementDown(enclosingAnchor);                enclosingAnchor = enclosingAnchorElement(original);                if (!enclosingAnchor)                    return original;            }            // Don't insert outside an anchor if doing so would skip over a line break.  It would            // probably be safe to move the line break so that we could still avoid the anchor here.            Position downstream(visiblePos.deepEquivalent().downstream());            if (lineBreakExistsAtPosition(visiblePos) && downstream.node()->isDescendantOf(enclosingAnchor))                return original;                        result = positionAfterNode(enclosingAnchor);        }        // If visually just before an anchor, insert *outside* the anchor unless it's the first        // VisiblePosition in a paragraph, to match NSTextView.        if (visiblePos == firstInAnchor) {            // Make sure anchors are pushed down before avoiding them so that we don't            // also avoid structural elements like lists and blocks (5142012).            if (original.node() != enclosingAnchor && original.node()->parentNode() != enclosingAnchor) {                pushAnchorElementDown(enclosingAnchor);                enclosingAnchor = enclosingAnchorElement(original);            }            result = positionBeforeNode(enclosingAnchor);        }    }            if (result.isNull() || !editableRootForPosition(result))        result = original;        return result;}// Splits the tree parent by parent until we reach the specified ancestor. We use VisiblePositions// to determine if the split is necessary. Returns the last split node.PassRefPtr<Node> CompositeEditCommand::splitTreeToNode(Node* start, Node* end, bool splitAncestor){    RefPtr<Node> node;    for (node = start; node && node->parent() != end; node = node->parent()) {        VisiblePosition positionInParent(Position(node->parent(), 0), DOWNSTREAM);        VisiblePosition positionInNode(Position(node, 0), DOWNSTREAM);        if (positionInParent != positionInNode)            applyCommandToComposite(SplitElementCommand::create(static_cast<Element*>(node->parent()), node));    }    if (splitAncestor)        return splitTreeToNode(end, end->parent());    return node.release();}PassRefPtr<Element> createBlockPlaceholderElement(Document* document){    RefPtr<Element> breakNode = document->createElement(brTag, false);    return breakNode.release();}} // namespace WebCore

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -