compositeeditcommand.cpp

来自「linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自Web」· C++ 代码 · 共 1,041 行 · 第 1/3 页

CPP
1,041
字号
void CompositeEditCommand::deleteSelection(const VisibleSelection &selection, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements){    if (selection.isRange())        applyCommandToComposite(DeleteSelectionCommand::create(selection, smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));}void CompositeEditCommand::removeCSSProperty(PassRefPtr<CSSMutableStyleDeclaration> style, CSSPropertyID property){    applyCommandToComposite(RemoveCSSPropertyCommand::create(document(), style, property));}void CompositeEditCommand::removeNodeAttribute(PassRefPtr<Element> element, const QualifiedName& attribute){    setNodeAttribute(element, attribute, AtomicString());}void CompositeEditCommand::setNodeAttribute(PassRefPtr<Element> element, const QualifiedName& attribute, const AtomicString& value){    applyCommandToComposite(SetNodeAttributeCommand::create(element, attribute, value));}static inline bool isWhitespace(UChar c){    return c == noBreakSpace || c == ' ' || c == '\n' || c == '\t';}// FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, cousins, etc).void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position){    Node* node = position.node();    if (!node || !node->isTextNode())        return;    Text* textNode = static_cast<Text*>(node);            if (textNode->length() == 0)        return;    RenderObject* renderer = textNode->renderer();    if (renderer && !renderer->style()->collapseWhiteSpace())        return;            String text = textNode->data();    ASSERT(!text.isEmpty());    int offset = position.offset();    // If neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.    if (!isWhitespace(text[offset])) {        offset--;        if (offset < 0 || !isWhitespace(text[offset]))            return;    }        // Set upstream and downstream to define the extent of the whitespace surrounding text[offset].    int upstream = offset;    while (upstream > 0 && isWhitespace(text[upstream - 1]))        upstream--;        int downstream = offset;    while ((unsigned)downstream + 1 < text.length() && isWhitespace(text[downstream + 1]))        downstream++;        int length = downstream - upstream + 1;    ASSERT(length > 0);        VisiblePosition visibleUpstreamPos(Position(position.node(), upstream));    VisiblePosition visibleDownstreamPos(Position(position.node(), downstream + 1));        String string = text.substring(upstream, length);    String rebalancedString = stringWithRebalancedWhitespace(string,    // FIXME: Because of the problem mentioned at the top of this function, we must also use nbsps at the start/end of the string because    // this function doesn't get all surrounding whitespace, just the whitespace in the current text node.                                                             isStartOfParagraph(visibleUpstreamPos) || upstream == 0,                                                              isEndOfParagraph(visibleDownstreamPos) || (unsigned)downstream == text.length() - 1);        if (string != rebalancedString)        replaceTextInNode(textNode, upstream, length, rebalancedString);}void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& position){    Node* node = position.node();    if (!node || !node->isTextNode())        return;    Text* textNode = static_cast<Text*>(node);            if (textNode->length() == 0)        return;    RenderObject* renderer = textNode->renderer();    if (renderer && !renderer->style()->collapseWhiteSpace())        return;    // Delete collapsed whitespace so that inserting nbsps doesn't uncollapse it.    Position upstreamPos = position.upstream();    deleteInsignificantText(position.upstream(), position.downstream());    position = upstreamPos.downstream();    VisiblePosition visiblePos(position);    VisiblePosition previousVisiblePos(visiblePos.previous());    Position previous(previousVisiblePos.deepEquivalent());        if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous.node()->isTextNode() && !previous.node()->hasTagName(brTag))        replaceTextInNode(static_cast<Text*>(previous.node()), previous.offset(), 1, nonBreakingSpaceString());    if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.node()->isTextNode() && !position.node()->hasTagName(brTag))        replaceTextInNode(static_cast<Text*>(position.node()), position.offset(), 1, nonBreakingSpaceString());}void CompositeEditCommand::rebalanceWhitespace(){    VisibleSelection selection = endingSelection();    if (selection.isNone())        return;            rebalanceWhitespaceAt(selection.start());    if (selection.isRange())        rebalanceWhitespaceAt(selection.end());}void CompositeEditCommand::deleteInsignificantText(PassRefPtr<Text> textNode, unsigned start, unsigned end){    if (!textNode || start >= end)        return;    RenderText* textRenderer = toRenderText(textNode->renderer());    if (!textRenderer)        return;    InlineTextBox* box = textRenderer->firstTextBox();    if (!box) {        // whole text node is empty        removeNode(textNode);        return;        }        unsigned length = textNode->length();    if (start >= length || end > length)        return;    unsigned removed = 0;    InlineTextBox* prevBox = 0;    String str;    // This loop structure works to process all gaps preceding a box,    // and also will look at the gap after the last box.    while (prevBox || box) {        unsigned gapStart = prevBox ? prevBox->start() + prevBox->len() : 0;        if (end < gapStart)            // No more chance for any intersections            break;        unsigned gapEnd = box ? box->start() : length;        bool indicesIntersect = start <= gapEnd && end >= gapStart;        int gapLen = gapEnd - gapStart;        if (indicesIntersect && gapLen > 0) {            gapStart = max(gapStart, start);            gapEnd = min(gapEnd, end);            if (str.isNull())                str = textNode->string()->substring(start, end - start);            // remove text in the gap            str.remove(gapStart - start - removed, gapLen);            removed += gapLen;        }                prevBox = box;        if (box)            box = box->nextTextBox();    }    if (!str.isNull()) {        // Replace the text between start and end with our pruned version.        if (!str.isEmpty())            replaceTextInNode(textNode, start, end - start, str);        else {            // Assert that we are not going to delete all of the text in the node.            // If we were, that should have been done above with the call to             // removeNode and return.            ASSERT(start > 0 || end - start < textNode->length());            deleteTextFromNode(textNode, start, end - start);        }    }}void CompositeEditCommand::deleteInsignificantText(const Position& start, const Position& end){    if (start.isNull() || end.isNull())        return;    if (Range::compareBoundaryPoints(start, end) >= 0)        return;    Node* next;    for (Node* node = start.node(); node; node = next) {        next = node->traverseNextNode();        if (node->isTextNode()) {            Text* textNode = static_cast<Text*>(node);            int startOffset = node == start.node() ? start.offset() : 0;            int endOffset = node == end.node() ? end.offset() : textNode->length();            deleteInsignificantText(textNode, startOffset, endOffset);        }        if (node == end.node())            break;    }}void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos){    Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivalent().downstream();    deleteInsignificantText(pos, end);}PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRefPtr<Element> container){    if (!container)        return 0;        // Should assert isBlockFlow || isInlineFlow when deletion improves. See 4244964.    ASSERT(container->renderer());    RefPtr<Node> placeholder = createBlockPlaceholderElement(document());    appendNode(placeholder, container);    return placeholder.release();}PassRefPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const Position& pos){    if (pos.isNull())        return 0;    // Should assert isBlockFlow || isInlineFlow when deletion improves.  See 4244964.    ASSERT(pos.node()->renderer());    RefPtr<Node> placeholder = createBlockPlaceholderElement(document());    insertNodeAt(placeholder, pos);    return placeholder.release();}PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Element* container){    if (!container)        return 0;    updateLayout();    RenderObject* renderer = container->renderer();    if (!renderer || !renderer->isBlockFlow())        return 0;        // append the placeholder to make sure it follows    // any unrendered blocks    RenderBlock* block = toRenderBlock(renderer);    if (block->height() == 0 || (block->isListItem() && block->isEmpty()))        return appendBlockPlaceholder(container);    return 0;}// Removes '\n's and brs that will collapse when content is inserted just before them.// FIXME: We shouldn't really have to remove placeholders, but removing them is a workaround for 9661.void CompositeEditCommand::removePlaceholderAt(const VisiblePosition& visiblePosition){    if (visiblePosition.isNull())        return;            Position p = visiblePosition.deepEquivalent().downstream();    // If a br or '\n' is at the end of a block and not at the start of a paragraph,    // then it is superfluous, so adding content before a br or '\n' that is at    // the start of a paragraph will render it superfluous.    // FIXME: This doesn't remove placeholders at the end of anonymous blocks.    if (isEndOfBlock(visiblePosition) && isStartOfParagraph(visiblePosition)) {        if (p.node()->hasTagName(brTag) && p.offset() == 0)            removeNode(p.node());        else if (lineBreakExistsAtPosition(visiblePosition))            deleteTextFromNode(static_cast<Text*>(p.node()), p.offset(), 1);    }}PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const Position& position){    RefPtr<Element> paragraphElement = createDefaultParagraphElement(document());    ExceptionCode ec;    paragraphElement->appendChild(createBreakElement(document()), ec);    insertNodeAt(paragraphElement, position);    return paragraphElement.release();}// If the paragraph is not entirely within it's own block, create one and move the paragraph into // it, and return that block.  Otherwise return 0.PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary(const Position& pos){    if (pos.isNull())        return 0;        updateLayout();        // It's strange that this function is responsible for verifying that pos has not been invalidated    // by an earlier call to this function.  The caller, applyBlockStyle, should do this.    VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);    VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos));    VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos);    VisiblePosition next = visibleParagraphEnd.next();    VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd;        Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream();    Position upstreamEnd = visibleEnd.deepEquivalent().upstream();    // If there are no VisiblePositions in the same block as pos then     // upstreamStart will be outside the paragraph    if (Range::compareBoundaryPoints(pos, upstreamStart) < 0)        return 0;    // Perform some checks to see if we need to perform work in this function.    if (isBlock(upstreamStart.node())) {        // If the block is the root editable element, always move content to a new block,        // since it is illegal to modify attributes on the root editable element for editing.        if (upstreamStart.node() == editableRootForPosition(upstreamStart)) {            // If the block is the root editable element and there is nothing insde of it, create a new            // block but don't try and move content into it, since there's nothing to move.            if (upstreamStart == upstreamEnd)                return insertNewDefaultParagraphElementAt(upstreamStart);        } else if (isBlock(upstreamEnd.node())) {            if (!upstreamEnd.node()->isDescendantOf(upstreamStart.node())) {                // If the paragraph end is a descendant of paragraph start, then we need to run                // the rest of this function. If not, we can bail here.                return 0;            }        }        else if (enclosingBlock(upstreamEnd.node()) != upstreamStart.node()) {            // The visibleEnd.  It must be an ancestor of the paragraph start.            // We can bail as we have a full block to work with.            ASSERT(upstreamStart.node()->isDescendantOf(enclosingBlock(upstreamEnd.node())));            return 0;        }        else if (isEndOfDocument(visibleEnd)) {            // At the end of the document. We can bail here as well.            return 0;        }    }    RefPtr<Node> newBlock = insertNewDefaultParagraphElementAt(upstreamStart);        moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(Position(newBlock.get(), 0)));        return newBlock.release();}void CompositeEditCommand::pushAnchorElementDown(Node* anchorNode){    if (!anchorNode)        return;

⌨️ 快捷键说明

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