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

📄 deleteselectioncommand.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 3 页
字号:
{    if (!m_mergeBlocksAfterDelete) {        if (m_pruneStartBlockIfNecessary) {            // Make sure that the ending position isn't inside the block we're about to prune.            m_endingPosition = m_downstreamEnd;            // We aren't going to merge into the start block, so remove it if it's empty.            prune(m_upstreamStart.node());            // Removing the start block during a deletion is usually an indication that we need            // a placeholder, but not in this case.            m_needPlaceholder = false;        }        return;    }        // It shouldn't have been asked to both try and merge content into the start block and prune it.    ASSERT(!m_pruneStartBlockIfNecessary);    // FIXME: Deletion should adjust selection endpoints as it removes nodes so that we never get into this state (4099839).    if (!m_downstreamEnd.node()->inDocument() || !m_upstreamStart.node()->inDocument())         return;             // FIXME: The deletion algorithm shouldn't let this happen.    if (Range::compareBoundaryPoints(m_upstreamStart, m_downstreamEnd) > 0)        return;            // FIXME: Merging will always be unnecessary in this case, but we really bail here because this is a case where    // deletion commonly fails to adjust its endpoints, which would cause the visible position comparison below to false negative.    if (m_endBlock == m_startBlock)        return;            VisiblePosition startOfParagraphToMove(m_downstreamEnd);    VisiblePosition mergeDestination(m_upstreamStart);        // m_downstreamEnd's block has been emptied out by deletion.  There is no content inside of it to    // move, so just remove it.    Element* endBlock = static_cast<Element*>(enclosingBlock(m_downstreamEnd.node()));    if (!startOfParagraphToMove.deepEquivalent().node() || !endBlock->contains(startOfParagraphToMove.deepEquivalent().node())) {        removeNode(enclosingBlock(m_downstreamEnd.node()));        return;    }        // We need to merge into m_upstreamStart's block, but it's been emptied out and collapsed by deletion.    if (!mergeDestination.deepEquivalent().node() || !mergeDestination.deepEquivalent().node()->isDescendantOf(m_upstreamStart.node()->enclosingBlockFlowElement())) {        insertNodeAt(createBreakElement(document()).get(), m_upstreamStart);        mergeDestination = VisiblePosition(m_upstreamStart);    }        if (mergeDestination == startOfParagraphToMove)        return;            VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove);        if (mergeDestination == endOfParagraphToMove)        return;        // The rule for merging into an empty block is: only do so if its farther to the right.    // FIXME: Consider RTL.    // FIXME: handleSpecialCaseBRDelete prevents us from getting here in a case like <ul><li>foo<br><br></li></ul>^foo    if (isStartOfParagraph(mergeDestination) && startOfParagraphToMove.absoluteCaretBounds().x() > mergeDestination.absoluteCaretBounds().x()) {        ASSERT(mergeDestination.deepEquivalent().downstream().node()->hasTagName(brTag));        removeNodeAndPruneAncestors(mergeDestination.deepEquivalent().downstream().node());        m_endingPosition = startOfParagraphToMove.deepEquivalent();        return;    }        RefPtr<Range> range = Range::create(document(), rangeCompliantEquivalent(startOfParagraphToMove.deepEquivalent()), rangeCompliantEquivalent(endOfParagraphToMove.deepEquivalent()));    RefPtr<Range> rangeToBeReplaced = Range::create(document(), rangeCompliantEquivalent(mergeDestination.deepEquivalent()), rangeCompliantEquivalent(mergeDestination.deepEquivalent()));    if (!document()->frame()->editor()->client()->shouldMoveRangeAfterDelete(range.get(), rangeToBeReplaced.get()))        return;        // moveParagraphs will insert placeholders if it removes blocks that would require their use, don't let block    // removals that it does cause the insertion of *another* placeholder.    bool needPlaceholder = m_needPlaceholder;    moveParagraph(startOfParagraphToMove, endOfParagraphToMove, mergeDestination);    m_needPlaceholder = needPlaceholder;    // The endingPosition was likely clobbered by the move, so recompute it (moveParagraph selects the moved paragraph).    m_endingPosition = endingSelection().start();}void DeleteSelectionCommand::removePreviouslySelectedEmptyTableRows(){    if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_startTableRow) {        Node* row = m_endTableRow->previousSibling();        while (row && row != m_startTableRow) {            RefPtr<Node> previousRow = row->previousSibling();            if (isTableRowEmpty(row))                // Use a raw removeNode, instead of DeleteSelectionCommand's, because                // that won't remove rows, it only empties them in preparation for this function.                CompositeEditCommand::removeNode(row);            row = previousRow.get();        }    }        // Remove empty rows after the start row.    if (m_startTableRow && m_startTableRow->inDocument() && m_startTableRow != m_endTableRow) {        Node* row = m_startTableRow->nextSibling();        while (row && row != m_endTableRow) {            RefPtr<Node> nextRow = row->nextSibling();            if (isTableRowEmpty(row))                CompositeEditCommand::removeNode(row);            row = nextRow.get();        }    }        if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_startTableRow)        if (isTableRowEmpty(m_endTableRow.get())) {            // Don't remove m_endTableRow if it's where we're putting the ending selection.            if (!m_endingPosition.node()->isDescendantOf(m_endTableRow.get())) {                // FIXME: We probably shouldn't remove m_endTableRow unless it's fully selected, even if it is empty.                // We'll need to start adjusting the selection endpoints during deletion to know whether or not m_endTableRow                // was fully selected here.                CompositeEditCommand::removeNode(m_endTableRow.get());            }        }}void DeleteSelectionCommand::calculateTypingStyleAfterDelete(){    if (!m_typingStyle)        return;            // Compute the difference between the style before the delete and the style now    // after the delete has been done. Set this style on the frame, so other editing    // commands being composed with this one will work, and also cache it on the command,    // so the Frame::appliedEditing can set it after the whole composite command     // has completed.        // If we deleted into a blockquote, but are now no longer in a blockquote, use the alternate typing style    if (m_deleteIntoBlockquoteStyle && !nearestMailBlockquote(m_endingPosition.node()))        m_typingStyle = m_deleteIntoBlockquoteStyle;    m_deleteIntoBlockquoteStyle = 0;        RefPtr<CSSComputedStyleDeclaration> endingStyle = computedStyle(m_endingPosition.node());    endingStyle->diff(m_typingStyle.get());    if (!m_typingStyle->length())        m_typingStyle = 0;    VisiblePosition visibleEnd(m_endingPosition);    if (m_typingStyle &&         isStartOfParagraph(visibleEnd) &&        isEndOfParagraph(visibleEnd) &&        lineBreakExistsAtPosition(visibleEnd)) {        // Apply style to the placeholder that is now holding open the empty paragraph.         // This makes sure that the paragraph has the right height, and that the paragraph         // takes on the right style and retains it even if you move the selection away and        // then move it back (which will clear typing style).        setEndingSelection(visibleEnd);        applyStyle(m_typingStyle.get(), EditActionUnspecified);        // applyStyle can destroy the placeholder that was at m_endingPosition if it needs to         // move it, but it will set an endingSelection() at [movedPlaceholder, 0] if it does so.        m_endingPosition = endingSelection().start();        m_typingStyle = 0;    }    // This is where we've deleted all traces of a style but not a whole paragraph (that's handled above).    // In this case if we start typing, the new characters should have the same style as the just deleted ones,    // but, if we change the selection, come back and start typing that style should be lost.  Also see     // preserveTypingStyle() below.    document()->frame()->setTypingStyle(m_typingStyle.get());}void DeleteSelectionCommand::clearTransientState(){    m_selectionToDelete = VisibleSelection();    m_upstreamStart.clear();    m_downstreamStart.clear();    m_upstreamEnd.clear();    m_downstreamEnd.clear();    m_endingPosition.clear();    m_leadingWhitespace.clear();    m_trailingWhitespace.clear();}void DeleteSelectionCommand::doApply(){    // If selection has not been set to a custom selection when the command was created,    // use the current ending selection.    if (!m_hasSelectionToDelete)        m_selectionToDelete = endingSelection();        if (!m_selectionToDelete.isRange())        return;    // If the deletion is occurring in a text field, and we're not deleting to replace the selection, then let the frame call across the bridge to notify the form delegate.     if (!m_replace) {        Node* startNode = m_selectionToDelete.start().node();        Node* ancestorNode = startNode ? startNode->shadowAncestorNode() : 0;        if (ancestorNode && ancestorNode->hasTagName(inputTag)                && static_cast<HTMLInputElement*>(ancestorNode)->isTextField()                && ancestorNode->focused())            document()->frame()->textWillBeDeletedInTextField(static_cast<Element*>(ancestorNode));    }    // save this to later make the selection with    EAffinity affinity = m_selectionToDelete.affinity();        Position downstreamEnd = m_selectionToDelete.end().downstream();    m_needPlaceholder = isStartOfParagraph(m_selectionToDelete.visibleStart()) &&                        isEndOfParagraph(m_selectionToDelete.visibleEnd()) &&                        !lineBreakExistsAtPosition(m_selectionToDelete.visibleEnd());    if (m_needPlaceholder) {        // Don't need a placeholder when deleting a selection that starts just before a table        // and ends inside it (we do need placeholders to hold open empty cells, but that's        // handled elsewhere).        if (Node* table = isLastPositionBeforeTable(m_selectionToDelete.visibleStart()))            if (m_selectionToDelete.end().node()->isDescendantOf(table))                m_needPlaceholder = false;    }                // set up our state    initializePositionData();    // Delete any text that may hinder our ability to fixup whitespace after the delete    deleteInsignificantTextDownstream(m_trailingWhitespace);        saveTypingStyleState();        // deleting just a BR is handled specially, at least because we do not    // want to replace it with a placeholder BR!    if (handleSpecialCaseBRDelete()) {        calculateTypingStyleAfterDelete();        setEndingSelection(VisibleSelection(m_endingPosition, affinity));        clearTransientState();        rebalanceWhitespace();        return;    }        handleGeneralDelete();        fixupWhitespace();        mergeParagraphs();        removePreviouslySelectedEmptyTableRows();        RefPtr<Node> placeholder = m_needPlaceholder ? createBreakElement(document()).get() : 0;        if (placeholder)        insertNodeAt(placeholder.get(), m_endingPosition);    rebalanceWhitespaceAt(m_endingPosition);    calculateTypingStyleAfterDelete();        setEndingSelection(VisibleSelection(m_endingPosition, affinity));    clearTransientState();}EditAction DeleteSelectionCommand::editingAction() const{    // Note that DeleteSelectionCommand is also used when the user presses the Delete key,    // but in that case there's a TypingCommand that supplies the editingAction(), so    // the Undo menu correctly shows "Undo Typing"    return EditActionCut;}// Normally deletion doesn't preserve the typing style that was present before it.  For example,// type a character, Bold, then delete the character and start typing.  The Bold typing style shouldn't// stick around.  Deletion should preserve a typing style that *it* sets, however.bool DeleteSelectionCommand::preservesTypingStyle() const{    return m_typingStyle;}} // namespace WebCore

⌨️ 快捷键说明

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