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

📄 replaceselectioncommand.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 4 页
字号:
        RefPtr<CSSMutableStyleDeclaration> styleAtInsertionPos = rangeCompliantEquivalent(insertionPos).computedStyle()->copyInheritableProperties();    String styleText = styleAtInsertionPos->cssText();        if (styleText == static_cast<Element*>(sourceDocumentStyleSpan)->getAttribute(styleAttr)) {        fragment.removeNodePreservingChildren(sourceDocumentStyleSpan);        if (!isStyleSpan(copiedRangeStyleSpan.get()))            return true;    }            if (isStyleSpan(copiedRangeStyleSpan.get()) && styleText == static_cast<Element*>(copiedRangeStyleSpan.get())->getAttribute(styleAttr)) {        fragment.removeNodePreservingChildren(copiedRangeStyleSpan.get());        return true;    }        return false;}// At copy time, WebKit wraps copied content in a span that contains the source document's // default styles.  If the copied Range inherits any other styles from its ancestors, we put // those styles on a second span.// This function removes redundant styles from those spans, and removes the spans if all their // styles are redundant. // We should remove the Apple-style-span class when we're done, see <rdar://problem/5685600>.// We should remove styles from spans that are overridden by all of their children, either here// or at copy time.void ReplaceSelectionCommand::handleStyleSpans(){    Node* sourceDocumentStyleSpan = 0;    Node* copiedRangeStyleSpan = 0;    // The style span that contains the source document's default style should be at    // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Quotation),    // so search for the top level style span instead of assuming it's at the top.    for (Node* node = m_firstNodeInserted.get(); node; node = node->traverseNextNode()) {        if (isStyleSpan(node)) {            sourceDocumentStyleSpan = node;            // If the copied Range's common ancestor had user applied inheritable styles            // on it, they'll be on a second style span, just below the one that holds the             // document defaults.            if (isStyleSpan(node->firstChild()))                copiedRangeStyleSpan = node->firstChild();            break;        }    }        // There might not be any style spans if we're pasting from another application or if     // we are here because of a document.execCommand("InsertHTML", ...) call.    if (!sourceDocumentStyleSpan)        return;            RefPtr<CSSMutableStyleDeclaration> sourceDocumentStyle = static_cast<HTMLElement*>(sourceDocumentStyleSpan)->getInlineStyleDecl()->copy();    Node* context = sourceDocumentStyleSpan->parentNode();        // If Mail wraps the fragment with a Paste as Quotation blockquote, styles from that element are    // allowed to override those from the source document, see <rdar://problem/4930986>.    if (isMailPasteAsQuotationNode(context)) {        RefPtr<CSSMutableStyleDeclaration> blockquoteStyle = computedStyle(context)->copyInheritableProperties();        RefPtr<CSSMutableStyleDeclaration> parentStyle = computedStyle(context->parentNode())->copyInheritableProperties();        parentStyle->diff(blockquoteStyle.get());        CSSMutableStyleDeclaration::const_iterator end = blockquoteStyle->end();        for (CSSMutableStyleDeclaration::const_iterator it = blockquoteStyle->begin(); it != end; ++it) {            const CSSProperty& property = *it;            sourceDocumentStyle->removeProperty(property.id());        }                context = context->parentNode();    }        RefPtr<CSSMutableStyleDeclaration> contextStyle = computedStyle(context)->copyInheritableProperties();    contextStyle->diff(sourceDocumentStyle.get());        // Remove block properties in the span's style. This prevents properties that probably have no effect     // currently from affecting blocks later if the style is cloned for a new block element during a future     // editing operation.    // FIXME: They *can* have an effect currently if blocks beneath the style span aren't individually marked    // with block styles by the editing engine used to style them.  WebKit doesn't do this, but others might.    sourceDocumentStyle->removeBlockProperties();        // The styles on sourceDocumentStyleSpan are all redundant, and there is no copiedRangeStyleSpan    // to consider.  We're finished.    if (sourceDocumentStyle->length() == 0 && !copiedRangeStyleSpan) {        removeNodePreservingChildren(sourceDocumentStyleSpan);        return;    }        // There are non-redundant styles on sourceDocumentStyleSpan, but there is no    // copiedRangeStyleSpan.  Clear the redundant styles from sourceDocumentStyleSpan    // and return.    if (sourceDocumentStyle->length() > 0 && !copiedRangeStyleSpan) {        setNodeAttribute(static_cast<Element*>(sourceDocumentStyleSpan), styleAttr, sourceDocumentStyle->cssText());        return;    }        RefPtr<CSSMutableStyleDeclaration> copiedRangeStyle = static_cast<HTMLElement*>(copiedRangeStyleSpan)->getInlineStyleDecl()->copy();        // We're going to put sourceDocumentStyleSpan's non-redundant styles onto copiedRangeStyleSpan,    // as long as they aren't overridden by ones on copiedRangeStyleSpan.    sourceDocumentStyle->merge(copiedRangeStyle.get(), true);    copiedRangeStyle = sourceDocumentStyle;        removeNodePreservingChildren(sourceDocumentStyleSpan);        // Remove redundant styles.    context = copiedRangeStyleSpan->parentNode();    contextStyle = computedStyle(context)->copyInheritableProperties();    contextStyle->diff(copiedRangeStyle.get());        // See the comments above about removing block properties.    copiedRangeStyle->removeBlockProperties();    // All the styles on copiedRangeStyleSpan are redundant, remove it.    if (copiedRangeStyle->length() == 0) {        removeNodePreservingChildren(copiedRangeStyleSpan);        return;    }        // Clear the redundant styles from the span's style attribute.    // FIXME: If font-family:-webkit-monospace is non-redundant, then the font-size should stay, even if it    // appears redundant.    setNodeAttribute(static_cast<Element*>(copiedRangeStyleSpan), styleAttr, copiedRangeStyle->cssText());}void ReplaceSelectionCommand::mergeEndIfNeeded(){    if (!m_shouldMergeEnd)        return;    VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent());    VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent());        // Bail to avoid infinite recursion.    if (m_movingParagraph) {        ASSERT_NOT_REACHED();        return;    }        // Merging two paragraphs will destroy the moved one's block styles.  Always move the end of inserted forward     // to preserve the block style of the paragraph already in the document, unless the paragraph to move would     // include the what was the start of the selection that was pasted into, so that we preserve that paragraph's    // block styles.    bool mergeForward = !(inSameParagraph(startOfInsertedContent, endOfInsertedContent) && !isStartOfParagraph(startOfInsertedContent));        VisiblePosition destination = mergeForward ? endOfInsertedContent.next() : endOfInsertedContent;    VisiblePosition startOfParagraphToMove = mergeForward ? startOfParagraph(endOfInsertedContent) : endOfInsertedContent.next();    moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove), destination);    // Merging forward will remove m_lastLeafInserted from the document.    // FIXME: Maintain positions for the start and end of inserted content instead of keeping nodes.  The nodes are    // only ever used to create positions where inserted content starts/ends.    if (mergeForward) {        m_lastLeafInserted = destination.previous().deepEquivalent().node();        if (!m_firstNodeInserted->inDocument())            m_firstNodeInserted = endingSelection().visibleStart().deepEquivalent().node();    }}void ReplaceSelectionCommand::doApply(){    VisibleSelection selection = endingSelection();    ASSERT(selection.isCaretOrRange());    ASSERT(selection.start().node());    if (selection.isNone() || !selection.start().node())        return;        bool selectionIsPlainText = !selection.isContentRichlyEditable();        Element* currentRoot = selection.rootEditableElement();    ReplacementFragment fragment(document(), m_documentFragment.get(), m_matchStyle, selection);        if (m_matchStyle)        m_insertionStyle = styleAtPosition(selection.start());        VisiblePosition visibleStart = selection.visibleStart();    VisiblePosition visibleEnd = selection.visibleEnd();        bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd);    bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart);        Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().node());        Position insertionPos = selection.start();    bool startIsInsideMailBlockquote = nearestMailBlockquote(insertionPos.node());        if (selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !startIsInsideMailBlockquote ||        startBlock == currentRoot ||        startBlock && startBlock->renderer() && startBlock->renderer()->isListItem() ||        selectionIsPlainText)        m_preventNesting = false;        if (selection.isRange()) {        // When the end of the selection being pasted into is at the end of a paragraph, and that selection        // spans multiple blocks, not merging may leave an empty line.        // When the start of the selection being pasted into is at the start of a block, not merging         // will leave hanging block(s).        // Merge blocks if the start of the selection was in a Mail blockquote, since we handle          // that case specially to prevent nesting.         bool mergeBlocksAfterDelete = startIsInsideMailBlockquote || isEndOfParagraph(visibleEnd) || isStartOfBlock(visibleStart);        // FIXME: We should only expand to include fully selected special elements if we are copying a         // selection and pasting it on top of itself.        deleteSelection(false, mergeBlocksAfterDelete, true, false);        visibleStart = endingSelection().visibleStart();        if (fragment.hasInterchangeNewlineAtStart()) {            if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {                if (!isEndOfDocument(visibleStart))                    setEndingSelection(visibleStart.next());            } else                insertParagraphSeparator();        }        insertionPos = endingSelection().start();    } else {        ASSERT(selection.isCaret());        if (fragment.hasInterchangeNewlineAtStart()) {            VisiblePosition next = visibleStart.next(true);            if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart) && next.isNotNull())                setEndingSelection(next);            else                 insertParagraphSeparator();        }        // We split the current paragraph in two to avoid nesting the blocks from the fragment inside the current block.        // For example paste <div>foo</div><div>bar</div><div>baz</div> into <div>x^x</div>, where ^ is the caret.          // As long as the  div styles are the same, visually you'd expect: <div>xbar</div><div>bar</div><div>bazx</div>,         // not <div>xbar<div>bar</div><div>bazx</div></div>.        // Don't do this if the selection started in a Mail blockquote.        if (m_preventNesting && !startIsInsideMailBlockquote && !isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {            insertParagraphSeparator();            setEndingSelection(endingSelection().visibleStart().previous());        }        insertionPos = endingSelection().start();    }        if (startIsInsideMailBlockquote && m_preventNesting) {         // We don't want any of the pasted content to end up nested in a Mail blockquote, so first break         // out of any surrounding Mail blockquotes.         applyCommandToComposite(BreakBlockquoteCommand::create(document()));         // This will leave a br between the split.         Node* br = endingSelection().start().node();         ASSERT(br->hasTagName(brTag));         // Insert content between the two blockquotes, but remove the br (since it was just a placeholder).         insertionPos = positionBeforeNode(br);         removeNode(br);    }        // Inserting content could cause whitespace to collapse, e.g. inserting <div>foo</div> into hello^ world.    prepareWhitespaceAtPositionForSplit(insertionPos);        // NOTE: This would be an incorrect usage of downstream() if downstream() were changed to mean the last position after     // p that maps to the same visible position as p (since in the case where a br is at the end of a block and collapsed     // away, there are positions after the br which map to the same visible position as [br, 0]).      Node* endBR = insertionPos.downstream().node()->hasTagName(brTag) ? insertionPos.downstream().node() : 0;    VisiblePosition originalVisPosBeforeEndBR;    if (endBR)        originalVisPosBeforeEndBR = VisiblePosition(endBR, 0, DOWNSTREAM).previous();        startBlock = enclosingBlock(insertionPos.node());        // Adjust insertionPos to prevent nesting.    // If the start was in a Mail blockquote, we will have already handled adjusting insertionPos above.    if (m_preventNesting && startBlock && !startIsInsideMailBlockquote) {        ASSERT(startBlock != currentRoot);        VisiblePosition visibleInsertionPos(insertionPos);        if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInsertionPos) && fragment.hasInterchangeNewlineAtEnd()))            insertionPos = positionAfterNode(startBlock);        else if (isStartOfBlock(visibleInsertionPos))            insertionPos = positionBeforeNode(startBlock);    }    // Paste into run of tabs splits the tab span.    insertionPos = positionOutsideTabSpan(insertionPos);    

⌨️ 快捷键说明

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