Home | History | Annotate | Download | only in editing
      1 /*
      2  * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "CompositeEditCommand.h"
     28 
     29 #include "AppendNodeCommand.h"
     30 #include "ApplyStyleCommand.h"
     31 #include "CSSComputedStyleDeclaration.h"
     32 #include "CSSMutableStyleDeclaration.h"
     33 #include "CharacterNames.h"
     34 #include "DeleteFromTextNodeCommand.h"
     35 #include "DeleteSelectionCommand.h"
     36 #include "Document.h"
     37 #include "DocumentFragment.h"
     38 #include "EditorInsertAction.h"
     39 #include "HTMLElement.h"
     40 #include "HTMLNames.h"
     41 #include "InlineTextBox.h"
     42 #include "InsertIntoTextNodeCommand.h"
     43 #include "InsertLineBreakCommand.h"
     44 #include "InsertNodeBeforeCommand.h"
     45 #include "InsertParagraphSeparatorCommand.h"
     46 #include "InsertTextCommand.h"
     47 #include "JoinTextNodesCommand.h"
     48 #include "MergeIdenticalElementsCommand.h"
     49 #include "Range.h"
     50 #include "RemoveCSSPropertyCommand.h"
     51 #include "RemoveNodeCommand.h"
     52 #include "RemoveNodePreservingChildrenCommand.h"
     53 #include "ReplaceNodeWithSpanCommand.h"
     54 #include "ReplaceSelectionCommand.h"
     55 #include "RenderBlock.h"
     56 #include "RenderText.h"
     57 #include "SetNodeAttributeCommand.h"
     58 #include "SplitElementCommand.h"
     59 #include "SplitTextNodeCommand.h"
     60 #include "SplitTextNodeContainingElementCommand.h"
     61 #include "Text.h"
     62 #include "TextIterator.h"
     63 #include "WrapContentsInDummySpanCommand.h"
     64 #include "htmlediting.h"
     65 #include "markup.h"
     66 #include "visible_units.h"
     67 
     68 using namespace std;
     69 
     70 namespace WebCore {
     71 
     72 using namespace HTMLNames;
     73 
     74 CompositeEditCommand::CompositeEditCommand(Document *document)
     75     : EditCommand(document)
     76 {
     77 }
     78 
     79 void CompositeEditCommand::doUnapply()
     80 {
     81     size_t size = m_commands.size();
     82     for (size_t i = size; i != 0; --i)
     83         m_commands[i - 1]->unapply();
     84 }
     85 
     86 void CompositeEditCommand::doReapply()
     87 {
     88     size_t size = m_commands.size();
     89     for (size_t i = 0; i != size; ++i)
     90         m_commands[i]->reapply();
     91 }
     92 
     93 //
     94 // sugary-sweet convenience functions to help create and apply edit commands in composite commands
     95 //
     96 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<EditCommand> cmd)
     97 {
     98     cmd->setParent(this);
     99     cmd->apply();
    100     m_commands.append(cmd);
    101 }
    102 
    103 void CompositeEditCommand::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
    104 {
    105     applyCommandToComposite(ApplyStyleCommand::create(document(), style, editingAction));
    106 }
    107 
    108 void CompositeEditCommand::applyStyle(CSSStyleDeclaration* style, const Position& start, const Position& end, EditAction editingAction)
    109 {
    110     applyCommandToComposite(ApplyStyleCommand::create(document(), style, start, end, editingAction));
    111 }
    112 
    113 void CompositeEditCommand::applyStyledElement(PassRefPtr<Element> element)
    114 {
    115     applyCommandToComposite(ApplyStyleCommand::create(element, false));
    116 }
    117 
    118 void CompositeEditCommand::removeStyledElement(PassRefPtr<Element> element)
    119 {
    120     applyCommandToComposite(ApplyStyleCommand::create(element, true));
    121 }
    122 
    123 void CompositeEditCommand::insertParagraphSeparator(bool useDefaultParagraphElement)
    124 {
    125     applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(), useDefaultParagraphElement));
    126 }
    127 
    128 void CompositeEditCommand::insertLineBreak()
    129 {
    130     applyCommandToComposite(InsertLineBreakCommand::create(document()));
    131 }
    132 
    133 void CompositeEditCommand::insertNodeBefore(PassRefPtr<Node> insertChild, PassRefPtr<Node> refChild)
    134 {
    135     ASSERT(!refChild->hasTagName(bodyTag));
    136     applyCommandToComposite(InsertNodeBeforeCommand::create(insertChild, refChild));
    137 }
    138 
    139 void CompositeEditCommand::insertNodeAfter(PassRefPtr<Node> insertChild, PassRefPtr<Node> refChild)
    140 {
    141     ASSERT(insertChild);
    142     ASSERT(refChild);
    143     ASSERT(!refChild->hasTagName(bodyTag));
    144     Element* parent = refChild->parentElement();
    145     ASSERT(parent);
    146     if (parent->lastChild() == refChild)
    147         appendNode(insertChild, parent);
    148     else {
    149         ASSERT(refChild->nextSibling());
    150         insertNodeBefore(insertChild, refChild->nextSibling());
    151     }
    152 }
    153 
    154 void CompositeEditCommand::insertNodeAt(PassRefPtr<Node> insertChild, const Position& editingPosition)
    155 {
    156     ASSERT(isEditablePosition(editingPosition));
    157     // For editing positions like [table, 0], insert before the table,
    158     // likewise for replaced elements, brs, etc.
    159     Position p = rangeCompliantEquivalent(editingPosition);
    160     Node* refChild = p.node();
    161     int offset = p.deprecatedEditingOffset();
    162 
    163     if (canHaveChildrenForEditing(refChild)) {
    164         Node* child = refChild->firstChild();
    165         for (int i = 0; child && i < offset; i++)
    166             child = child->nextSibling();
    167         if (child)
    168             insertNodeBefore(insertChild, child);
    169         else
    170             appendNode(insertChild, static_cast<Element*>(refChild));
    171     } else if (caretMinOffset(refChild) >= offset)
    172         insertNodeBefore(insertChild, refChild);
    173     else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) {
    174         splitTextNode(static_cast<Text *>(refChild), offset);
    175 
    176         // Mutation events (bug 22634) from the text node insertion may have removed the refChild
    177         if (!refChild->inDocument())
    178             return;
    179         insertNodeBefore(insertChild, refChild);
    180     } else
    181         insertNodeAfter(insertChild, refChild);
    182 }
    183 
    184 void CompositeEditCommand::appendNode(PassRefPtr<Node> node, PassRefPtr<Element> parent)
    185 {
    186     ASSERT(canHaveChildrenForEditing(parent.get()));
    187     applyCommandToComposite(AppendNodeCommand::create(parent, node));
    188 }
    189 
    190 void CompositeEditCommand::removeChildrenInRange(PassRefPtr<Node> node, unsigned from, unsigned to)
    191 {
    192     Vector<RefPtr<Node> > children;
    193     Node* child = node->childNode(from);
    194     for (unsigned i = from; child && i < to; i++, child = child->nextSibling())
    195         children.append(child);
    196 
    197     size_t size = children.size();
    198     for (size_t i = 0; i < size; ++i)
    199         removeNode(children[i].release());
    200 }
    201 
    202 void CompositeEditCommand::removeNode(PassRefPtr<Node> node)
    203 {
    204     applyCommandToComposite(RemoveNodeCommand::create(node));
    205 }
    206 
    207 void CompositeEditCommand::removeNodePreservingChildren(PassRefPtr<Node> node)
    208 {
    209     applyCommandToComposite(RemoveNodePreservingChildrenCommand::create(node));
    210 }
    211 
    212 void CompositeEditCommand::removeNodeAndPruneAncestors(PassRefPtr<Node> node)
    213 {
    214     RefPtr<Node> parent = node->parentNode();
    215     removeNode(node);
    216     prune(parent.release());
    217 }
    218 
    219 HTMLElement* CompositeEditCommand::replaceNodeWithSpanPreservingChildrenAndAttributes(PassRefPtr<Node> node)
    220 {
    221     // It would also be possible to implement all of ReplaceNodeWithSpanCommand
    222     // as a series of existing smaller edit commands.  Someone who wanted to
    223     // reduce the number of edit commands could do so here.
    224     RefPtr<ReplaceNodeWithSpanCommand> command = ReplaceNodeWithSpanCommand::create(node);
    225     applyCommandToComposite(command);
    226     // Returning a raw pointer here is OK because the command is retained by
    227     // applyCommandToComposite (thus retaining the span), and the span is also
    228     // in the DOM tree, and thus alive whie it has a parent.
    229     ASSERT(command->spanElement()->inDocument());
    230     return command->spanElement();
    231 }
    232 
    233 static bool hasARenderedDescendant(Node* node)
    234 {
    235     Node* n = node->firstChild();
    236     while (n) {
    237         if (n->renderer())
    238             return true;
    239         n = n->traverseNextNode(node);
    240     }
    241     return false;
    242 }
    243 
    244 void CompositeEditCommand::prune(PassRefPtr<Node> node)
    245 {
    246     while (node) {
    247         // If you change this rule you may have to add an updateLayout() here.
    248         RenderObject* renderer = node->renderer();
    249         if (renderer && (!renderer->canHaveChildren() || hasARenderedDescendant(node.get()) || node->rootEditableElement() == node))
    250             return;
    251 
    252         RefPtr<Node> next = node->parentNode();
    253         removeNode(node);
    254         node = next;
    255     }
    256 }
    257 
    258 void CompositeEditCommand::splitTextNode(PassRefPtr<Text> node, unsigned offset)
    259 {
    260     applyCommandToComposite(SplitTextNodeCommand::create(node, offset));
    261 }
    262 
    263 void CompositeEditCommand::splitElement(PassRefPtr<Element> element, PassRefPtr<Node> atChild)
    264 {
    265     applyCommandToComposite(SplitElementCommand::create(element, atChild));
    266 }
    267 
    268 void CompositeEditCommand::mergeIdenticalElements(PassRefPtr<Element> prpFirst, PassRefPtr<Element> prpSecond)
    269 {
    270     RefPtr<Element> first = prpFirst;
    271     RefPtr<Element> second = prpSecond;
    272     ASSERT(!first->isDescendantOf(second.get()) && second != first);
    273     if (first->nextSibling() != second) {
    274         removeNode(second);
    275         insertNodeAfter(second, first);
    276     }
    277     applyCommandToComposite(MergeIdenticalElementsCommand::create(first, second));
    278 }
    279 
    280 void CompositeEditCommand::wrapContentsInDummySpan(PassRefPtr<Element> element)
    281 {
    282     applyCommandToComposite(WrapContentsInDummySpanCommand::create(element));
    283 }
    284 
    285 void CompositeEditCommand::splitTextNodeContainingElement(PassRefPtr<Text> text, unsigned offset)
    286 {
    287     applyCommandToComposite(SplitTextNodeContainingElementCommand::create(text, offset));
    288 }
    289 
    290 void CompositeEditCommand::joinTextNodes(PassRefPtr<Text> text1, PassRefPtr<Text> text2)
    291 {
    292     applyCommandToComposite(JoinTextNodesCommand::create(text1, text2));
    293 }
    294 
    295 void CompositeEditCommand::inputText(const String& text, bool selectInsertedText)
    296 {
    297     int offset = 0;
    298     int length = text.length();
    299     RefPtr<Range> startRange = Range::create(document(), Position(document()->documentElement(), 0), endingSelection().start());
    300     int startIndex = TextIterator::rangeLength(startRange.get());
    301     int newline;
    302     do {
    303         newline = text.find('\n', offset);
    304         if (newline != offset) {
    305             RefPtr<InsertTextCommand> command = InsertTextCommand::create(document());
    306             applyCommandToComposite(command);
    307             int substringLength = newline == -1 ? length - offset : newline - offset;
    308             command->input(text.substring(offset, substringLength), false);
    309         }
    310         if (newline != -1)
    311             insertLineBreak();
    312 
    313         offset = newline + 1;
    314     } while (newline != -1 && offset != length);
    315 
    316     if (selectInsertedText) {
    317         RefPtr<Range> selectedRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), startIndex, length);
    318         setEndingSelection(VisibleSelection(selectedRange.get()));
    319     }
    320 }
    321 
    322 void CompositeEditCommand::insertTextIntoNode(PassRefPtr<Text> node, unsigned offset, const String& text)
    323 {
    324     applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset, text));
    325 }
    326 
    327 void CompositeEditCommand::deleteTextFromNode(PassRefPtr<Text> node, unsigned offset, unsigned count)
    328 {
    329     applyCommandToComposite(DeleteFromTextNodeCommand::create(node, offset, count));
    330 }
    331 
    332 void CompositeEditCommand::replaceTextInNode(PassRefPtr<Text> node, unsigned offset, unsigned count, const String& replacementText)
    333 {
    334     applyCommandToComposite(DeleteFromTextNodeCommand::create(node.get(), offset, count));
    335     applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset, replacementText));
    336 }
    337 
    338 Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos)
    339 {
    340     if (!isTabSpanTextNode(pos.node()))
    341         return pos;
    342 
    343     Node* tabSpan = tabSpanNode(pos.node());
    344 
    345     if (pos.deprecatedEditingOffset() <= caretMinOffset(pos.node()))
    346         return positionInParentBeforeNode(tabSpan);
    347 
    348     if (pos.deprecatedEditingOffset() >= caretMaxOffset(pos.node()))
    349         return positionInParentAfterNode(tabSpan);
    350 
    351     splitTextNodeContainingElement(static_cast<Text *>(pos.node()), pos.deprecatedEditingOffset());
    352     return positionInParentBeforeNode(tabSpan);
    353 }
    354 
    355 void CompositeEditCommand::insertNodeAtTabSpanPosition(PassRefPtr<Node> node, const Position& pos)
    356 {
    357     // insert node before, after, or at split of tab span
    358     insertNodeAt(node, positionOutsideTabSpan(pos));
    359 }
    360 
    361 void CompositeEditCommand::deleteSelection(bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
    362 {
    363     if (endingSelection().isRange())
    364         applyCommandToComposite(DeleteSelectionCommand::create(document(), smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));
    365 }
    366 
    367 void CompositeEditCommand::deleteSelection(const VisibleSelection &selection, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
    368 {
    369     if (selection.isRange())
    370         applyCommandToComposite(DeleteSelectionCommand::create(selection, smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));
    371 }
    372 
    373 void CompositeEditCommand::removeCSSProperty(PassRefPtr<CSSMutableStyleDeclaration> style, CSSPropertyID property)
    374 {
    375     applyCommandToComposite(RemoveCSSPropertyCommand::create(document(), style, property));
    376 }
    377 
    378 void CompositeEditCommand::removeNodeAttribute(PassRefPtr<Element> element, const QualifiedName& attribute)
    379 {
    380     setNodeAttribute(element, attribute, AtomicString());
    381 }
    382 
    383 void CompositeEditCommand::setNodeAttribute(PassRefPtr<Element> element, const QualifiedName& attribute, const AtomicString& value)
    384 {
    385     applyCommandToComposite(SetNodeAttributeCommand::create(element, attribute, value));
    386 }
    387 
    388 static inline bool isWhitespace(UChar c)
    389 {
    390     return c == noBreakSpace || c == ' ' || c == '\n' || c == '\t';
    391 }
    392 
    393 // FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, cousins, etc).
    394 void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position)
    395 {
    396     Node* node = position.node();
    397     if (!node || !node->isTextNode())
    398         return;
    399     Text* textNode = static_cast<Text*>(node);
    400 
    401     if (textNode->length() == 0)
    402         return;
    403     RenderObject* renderer = textNode->renderer();
    404     if (renderer && !renderer->style()->collapseWhiteSpace())
    405         return;
    406 
    407     String text = textNode->data();
    408     ASSERT(!text.isEmpty());
    409 
    410     int offset = position.deprecatedEditingOffset();
    411     // If neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.
    412     if (!isWhitespace(text[offset])) {
    413         offset--;
    414         if (offset < 0 || !isWhitespace(text[offset]))
    415             return;
    416     }
    417 
    418     // Set upstream and downstream to define the extent of the whitespace surrounding text[offset].
    419     int upstream = offset;
    420     while (upstream > 0 && isWhitespace(text[upstream - 1]))
    421         upstream--;
    422 
    423     int downstream = offset;
    424     while ((unsigned)downstream + 1 < text.length() && isWhitespace(text[downstream + 1]))
    425         downstream++;
    426 
    427     int length = downstream - upstream + 1;
    428     ASSERT(length > 0);
    429 
    430     VisiblePosition visibleUpstreamPos(Position(position.node(), upstream));
    431     VisiblePosition visibleDownstreamPos(Position(position.node(), downstream + 1));
    432 
    433     String string = text.substring(upstream, length);
    434     String rebalancedString = stringWithRebalancedWhitespace(string,
    435     // 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
    436     // this function doesn't get all surrounding whitespace, just the whitespace in the current text node.
    437                                                              isStartOfParagraph(visibleUpstreamPos) || upstream == 0,
    438                                                              isEndOfParagraph(visibleDownstreamPos) || (unsigned)downstream == text.length() - 1);
    439 
    440     if (string != rebalancedString)
    441         replaceTextInNode(textNode, upstream, length, rebalancedString);
    442 }
    443 
    444 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& position)
    445 {
    446     Node* node = position.node();
    447     if (!node || !node->isTextNode())
    448         return;
    449     Text* textNode = static_cast<Text*>(node);
    450 
    451     if (textNode->length() == 0)
    452         return;
    453     RenderObject* renderer = textNode->renderer();
    454     if (renderer && !renderer->style()->collapseWhiteSpace())
    455         return;
    456 
    457     // Delete collapsed whitespace so that inserting nbsps doesn't uncollapse it.
    458     Position upstreamPos = position.upstream();
    459     deleteInsignificantText(position.upstream(), position.downstream());
    460     position = upstreamPos.downstream();
    461 
    462     VisiblePosition visiblePos(position);
    463     VisiblePosition previousVisiblePos(visiblePos.previous());
    464     Position previous(previousVisiblePos.deepEquivalent());
    465 
    466     if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous.node()->isTextNode() && !previous.node()->hasTagName(brTag))
    467         replaceTextInNode(static_cast<Text*>(previous.node()), previous.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
    468     if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.node()->isTextNode() && !position.node()->hasTagName(brTag))
    469         replaceTextInNode(static_cast<Text*>(position.node()), position.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
    470 }
    471 
    472 void CompositeEditCommand::rebalanceWhitespace()
    473 {
    474     VisibleSelection selection = endingSelection();
    475     if (selection.isNone())
    476         return;
    477 
    478     rebalanceWhitespaceAt(selection.start());
    479     if (selection.isRange())
    480         rebalanceWhitespaceAt(selection.end());
    481 }
    482 
    483 void CompositeEditCommand::deleteInsignificantText(PassRefPtr<Text> textNode, unsigned start, unsigned end)
    484 {
    485     if (!textNode || start >= end)
    486         return;
    487 
    488     RenderText* textRenderer = toRenderText(textNode->renderer());
    489     if (!textRenderer)
    490         return;
    491 
    492     InlineTextBox* box = textRenderer->firstTextBox();
    493     if (!box) {
    494         // whole text node is empty
    495         removeNode(textNode);
    496         return;
    497     }
    498 
    499     unsigned length = textNode->length();
    500     if (start >= length || end > length)
    501         return;
    502 
    503     unsigned removed = 0;
    504     InlineTextBox* prevBox = 0;
    505     String str;
    506 
    507     // This loop structure works to process all gaps preceding a box,
    508     // and also will look at the gap after the last box.
    509     while (prevBox || box) {
    510         unsigned gapStart = prevBox ? prevBox->start() + prevBox->len() : 0;
    511         if (end < gapStart)
    512             // No more chance for any intersections
    513             break;
    514 
    515         unsigned gapEnd = box ? box->start() : length;
    516         bool indicesIntersect = start <= gapEnd && end >= gapStart;
    517         int gapLen = gapEnd - gapStart;
    518         if (indicesIntersect && gapLen > 0) {
    519             gapStart = max(gapStart, start);
    520             gapEnd = min(gapEnd, end);
    521             if (str.isNull())
    522                 str = textNode->data().substring(start, end - start);
    523             // remove text in the gap
    524             str.remove(gapStart - start - removed, gapLen);
    525             removed += gapLen;
    526         }
    527 
    528         prevBox = box;
    529         if (box)
    530             box = box->nextTextBox();
    531     }
    532 
    533     if (!str.isNull()) {
    534         // Replace the text between start and end with our pruned version.
    535         if (!str.isEmpty())
    536             replaceTextInNode(textNode, start, end - start, str);
    537         else {
    538             // Assert that we are not going to delete all of the text in the node.
    539             // If we were, that should have been done above with the call to
    540             // removeNode and return.
    541             ASSERT(start > 0 || end - start < textNode->length());
    542             deleteTextFromNode(textNode, start, end - start);
    543         }
    544     }
    545 }
    546 
    547 void CompositeEditCommand::deleteInsignificantText(const Position& start, const Position& end)
    548 {
    549     if (start.isNull() || end.isNull())
    550         return;
    551 
    552     if (comparePositions(start, end) >= 0)
    553         return;
    554 
    555     Node* next;
    556     for (Node* node = start.node(); node; node = next) {
    557         next = node->traverseNextNode();
    558         if (node->isTextNode()) {
    559             Text* textNode = static_cast<Text*>(node);
    560             int startOffset = node == start.node() ? start.deprecatedEditingOffset() : 0;
    561             int endOffset = node == end.node() ? end.deprecatedEditingOffset() : textNode->length();
    562             deleteInsignificantText(textNode, startOffset, endOffset);
    563         }
    564         if (node == end.node())
    565             break;
    566     }
    567 }
    568 
    569 void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos)
    570 {
    571     Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivalent().downstream();
    572     deleteInsignificantText(pos, end);
    573 }
    574 
    575 PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRefPtr<Element> container)
    576 {
    577     if (!container)
    578         return 0;
    579 
    580     // Should assert isBlockFlow || isInlineFlow when deletion improves. See 4244964.
    581     ASSERT(container->renderer());
    582 
    583     RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
    584     appendNode(placeholder, container);
    585     return placeholder.release();
    586 }
    587 
    588 PassRefPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const Position& pos)
    589 {
    590     if (pos.isNull())
    591         return 0;
    592 
    593     // Should assert isBlockFlow || isInlineFlow when deletion improves.  See 4244964.
    594     ASSERT(pos.node()->renderer());
    595 
    596     RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
    597     insertNodeAt(placeholder, pos);
    598     return placeholder.release();
    599 }
    600 
    601 PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Element* container)
    602 {
    603     if (!container)
    604         return 0;
    605 
    606     updateLayout();
    607 
    608     RenderObject* renderer = container->renderer();
    609     if (!renderer || !renderer->isBlockFlow())
    610         return 0;
    611 
    612     // append the placeholder to make sure it follows
    613     // any unrendered blocks
    614     RenderBlock* block = toRenderBlock(renderer);
    615     if (block->height() == 0 || (block->isListItem() && block->isEmpty()))
    616         return appendBlockPlaceholder(container);
    617 
    618     return 0;
    619 }
    620 
    621 // Assumes that the position is at a placeholder and does the removal without much checking.
    622 void CompositeEditCommand::removePlaceholderAt(const Position& p)
    623 {
    624     ASSERT(lineBreakExistsAtPosition(p));
    625 
    626     // We are certain that the position is at a line break, but it may be a br or a preserved newline.
    627     if (p.anchorNode()->hasTagName(brTag)) {
    628         removeNode(p.anchorNode());
    629         return;
    630     }
    631 
    632     deleteTextFromNode(static_cast<Text*>(p.anchorNode()), p.offsetInContainerNode(), 1);
    633 }
    634 
    635 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const Position& position)
    636 {
    637     RefPtr<Element> paragraphElement = createDefaultParagraphElement(document());
    638     ExceptionCode ec;
    639     paragraphElement->appendChild(createBreakElement(document()), ec);
    640     insertNodeAt(paragraphElement, position);
    641     return paragraphElement.release();
    642 }
    643 
    644 // If the paragraph is not entirely within it's own block, create one and move the paragraph into
    645 // it, and return that block.  Otherwise return 0.
    646 PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary(const Position& pos)
    647 {
    648     if (pos.isNull())
    649         return 0;
    650 
    651     updateLayout();
    652 
    653     // It's strange that this function is responsible for verifying that pos has not been invalidated
    654     // by an earlier call to this function.  The caller, applyBlockStyle, should do this.
    655     VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
    656     VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos));
    657     VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos);
    658     VisiblePosition next = visibleParagraphEnd.next();
    659     VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd;
    660 
    661     Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream();
    662     Position upstreamEnd = visibleEnd.deepEquivalent().upstream();
    663 
    664     // If there are no VisiblePositions in the same block as pos then
    665     // upstreamStart will be outside the paragraph
    666     if (comparePositions(pos, upstreamStart) < 0)
    667         return 0;
    668 
    669     // Perform some checks to see if we need to perform work in this function.
    670     if (isBlock(upstreamStart.node())) {
    671         // If the block is the root editable element, always move content to a new block,
    672         // since it is illegal to modify attributes on the root editable element for editing.
    673         if (upstreamStart.node() == editableRootForPosition(upstreamStart)) {
    674             // If the block is the root editable element and it contains no visible content, create a new
    675             // block but don't try and move content into it, since there's nothing for moveParagraphs to move.
    676             if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(upstreamStart.node()->renderer()))
    677                 return insertNewDefaultParagraphElementAt(upstreamStart);
    678         } else if (isBlock(upstreamEnd.node())) {
    679             if (!upstreamEnd.node()->isDescendantOf(upstreamStart.node())) {
    680                 // If the paragraph end is a descendant of paragraph start, then we need to run
    681                 // the rest of this function. If not, we can bail here.
    682                 return 0;
    683             }
    684         }
    685         else if (enclosingBlock(upstreamEnd.node()) != upstreamStart.node()) {
    686             // The visibleEnd.  It must be an ancestor of the paragraph start.
    687             // We can bail as we have a full block to work with.
    688             ASSERT(upstreamStart.node()->isDescendantOf(enclosingBlock(upstreamEnd.node())));
    689             return 0;
    690         }
    691         else if (isEndOfDocument(visibleEnd)) {
    692             // At the end of the document. We can bail here as well.
    693             return 0;
    694         }
    695     }
    696 
    697     RefPtr<Node> newBlock = insertNewDefaultParagraphElementAt(upstreamStart);
    698 
    699     moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(Position(newBlock.get(), 0)));
    700 
    701     return newBlock.release();
    702 }
    703 
    704 void CompositeEditCommand::pushAnchorElementDown(Node* anchorNode)
    705 {
    706     if (!anchorNode)
    707         return;
    708 
    709     ASSERT(anchorNode->isLink());
    710 
    711     setEndingSelection(VisibleSelection::selectionFromContentsOfNode(anchorNode));
    712     applyStyledElement(static_cast<Element*>(anchorNode));
    713     // Clones of anchorNode have been pushed down, now remove it.
    714     if (anchorNode->inDocument())
    715         removeNodePreservingChildren(anchorNode);
    716 }
    717 
    718 // We must push partially selected anchors down before creating or removing
    719 // links from a selection to create fully selected chunks that can be removed.
    720 // ApplyStyleCommand doesn't do this for us because styles can be nested.
    721 // Anchors cannot be nested.
    722 void CompositeEditCommand::pushPartiallySelectedAnchorElementsDown()
    723 {
    724     VisibleSelection originalSelection = endingSelection();
    725     VisiblePosition visibleStart(originalSelection.start());
    726     VisiblePosition visibleEnd(originalSelection.end());
    727 
    728     Node* startAnchor = enclosingAnchorElement(originalSelection.start());
    729     VisiblePosition startOfStartAnchor(Position(startAnchor, 0));
    730     if (startAnchor && startOfStartAnchor != visibleStart)
    731         pushAnchorElementDown(startAnchor);
    732 
    733     Node* endAnchor = enclosingAnchorElement(originalSelection.end());
    734     VisiblePosition endOfEndAnchor(Position(endAnchor, 0));
    735     if (endAnchor && endOfEndAnchor != visibleEnd)
    736         pushAnchorElementDown(endAnchor);
    737 
    738     ASSERT(originalSelection.start().node()->inDocument() && originalSelection.end().node()->inDocument());
    739     setEndingSelection(originalSelection);
    740 }
    741 
    742 // Clone the paragraph between start and end under blockElement,
    743 // preserving the hierarchy up to outerNode.
    744 
    745 void CompositeEditCommand::cloneParagraphUnderNewElement(Position& start, Position& end, Node* outerNode, Element* blockElement)
    746 {
    747     // First we clone the outerNode
    748 
    749     RefPtr<Node> topNode = outerNode->cloneNode(isTableElement(outerNode));
    750     appendNode(topNode, blockElement);
    751     RefPtr<Node> lastNode = topNode;
    752 
    753     if (start.node() != outerNode) {
    754         Vector<RefPtr<Node> > ancestors;
    755 
    756         // Insert each node from innerNode to outerNode (excluded) in a list.
    757         for (Node* n = start.node(); n && n != outerNode; n = n->parentNode())
    758             ancestors.append(n);
    759 
    760         // Clone every node between start.node() and outerBlock.
    761 
    762         for (size_t i = ancestors.size(); i != 0; --i) {
    763             Node* item = ancestors[i - 1].get();
    764             RefPtr<Node> child = item->cloneNode(isTableElement(item));
    765             appendNode(child, static_cast<Element *>(lastNode.get()));
    766             lastNode = child.release();
    767         }
    768     }
    769 
    770     // Handle the case of paragraphs with more than one node,
    771     // cloning all the siblings until end.node() is reached.
    772 
    773     if (start.node() != end.node() && !start.node()->isDescendantOf(end.node())) {
    774         // If end is not a descendant of outerNode we need to
    775         // find the first common ancestor and adjust the insertion
    776         // point accordingly.
    777         while (!end.node()->isDescendantOf(outerNode)) {
    778             outerNode = outerNode->parentNode();
    779             topNode = topNode->parentNode();
    780         }
    781 
    782         for (Node* n = start.node()->traverseNextSibling(outerNode); n; n = n->nextSibling()) {
    783             if (n->parentNode() != start.node()->parentNode())
    784                 lastNode = topNode->lastChild();
    785 
    786             RefPtr<Node> clonedNode = n->cloneNode(true);
    787             insertNodeAfter(clonedNode, lastNode);
    788             lastNode = clonedNode.release();
    789             if (n == end.node() || end.node()->isDescendantOf(n))
    790                 break;
    791         }
    792     }
    793 }
    794 
    795 
    796 // There are bugs in deletion when it removes a fully selected table/list.
    797 // It expands and removes the entire table/list, but will let content
    798 // before and after the table/list collapse onto one line.
    799 // Deleting a paragraph will leave a placeholder. Remove it (and prune
    800 // empty or unrendered parents).
    801 
    802 void CompositeEditCommand::cleanupAfterDeletion()
    803 {
    804     VisiblePosition caretAfterDelete = endingSelection().visibleStart();
    805     if (isStartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) {
    806         // Note: We want the rightmost candidate.
    807         Position position = caretAfterDelete.deepEquivalent().downstream();
    808         Node* node = position.node();
    809         // Normally deletion will leave a br as a placeholder.
    810         if (node->hasTagName(brTag))
    811             removeNodeAndPruneAncestors(node);
    812         // If the selection to move was empty and in an empty block that
    813         // doesn't require a placeholder to prop itself open (like a bordered
    814         // div or an li), remove it during the move (the list removal code
    815         // expects this behavior).
    816         else if (isBlock(node))
    817             removeNodeAndPruneAncestors(node);
    818         else if (lineBreakExistsAtPosition(position)) {
    819             // There is a preserved '\n' at caretAfterDelete.
    820             // We can safely assume this is a text node.
    821             Text* textNode = static_cast<Text*>(node);
    822             if (textNode->length() == 1)
    823                 removeNodeAndPruneAncestors(node);
    824             else
    825                 deleteTextFromNode(textNode, position.deprecatedEditingOffset(), 1);
    826         }
    827     }
    828 }
    829 
    830 // This is a version of moveParagraph that preserves style by keeping the original markup
    831 // It is currently used only by IndentOutdentCommand but it is meant to be used in the
    832 // future by several other commands such as InsertList and the align commands.
    833 // The blockElement parameter is the element to move the paragraph to,
    834 // outerNode is the top element of the paragraph hierarchy.
    835 
    836 void CompositeEditCommand::moveParagraphWithClones(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, Element* blockElement, Node* outerNode)
    837 {
    838     ASSERT(outerNode);
    839     ASSERT(blockElement);
    840 
    841     VisiblePosition beforeParagraph = startOfParagraphToMove.previous();
    842     VisiblePosition afterParagraph(endOfParagraphToMove.next());
    843 
    844     // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
    845     // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.
    846     Position start = startOfParagraphToMove.deepEquivalent().downstream();
    847     Position end = endOfParagraphToMove.deepEquivalent().upstream();
    848 
    849     cloneParagraphUnderNewElement(start, end, outerNode, blockElement);
    850 
    851     setEndingSelection(VisibleSelection(start, end, DOWNSTREAM));
    852     deleteSelection(false, false, false, false);
    853 
    854     // There are bugs in deletion when it removes a fully selected table/list.
    855     // It expands and removes the entire table/list, but will let content
    856     // before and after the table/list collapse onto one line.
    857 
    858     cleanupAfterDeletion();
    859 
    860     // Add a br if pruning an empty block level element caused a collapse.  For example:
    861     // foo^
    862     // <div>bar</div>
    863     // baz
    864     // Imagine moving 'bar' to ^.  'bar' will be deleted and its div pruned.  That would
    865     // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br.
    866     // Must recononicalize these two VisiblePositions after the pruning above.
    867     beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
    868     afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
    869 
    870     if (beforeParagraph.isNotNull() && !isTableElement(beforeParagraph.deepEquivalent().node()) && (!isEndOfParagraph(beforeParagraph) || beforeParagraph == afterParagraph)) {
    871         // FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.
    872         insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquivalent());
    873     }
    874 }
    875 
    876 
    877 // This moves a paragraph preserving its style.
    878 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
    879 {
    880     ASSERT(isStartOfParagraph(startOfParagraphToMove));
    881     ASSERT(isEndOfParagraph(endOfParagraphToMove));
    882     moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, preserveSelection, preserveStyle);
    883 }
    884 
    885 void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
    886 {
    887     if (startOfParagraphToMove == destination)
    888         return;
    889 
    890     int startIndex = -1;
    891     int endIndex = -1;
    892     int destinationIndex = -1;
    893     if (preserveSelection && !endingSelection().isNone()) {
    894         VisiblePosition visibleStart = endingSelection().visibleStart();
    895         VisiblePosition visibleEnd = endingSelection().visibleEnd();
    896 
    897         bool startAfterParagraph = comparePositions(visibleStart, endOfParagraphToMove) > 0;
    898         bool endBeforeParagraph = comparePositions(visibleEnd, startOfParagraphToMove) < 0;
    899 
    900         if (!startAfterParagraph && !endBeforeParagraph) {
    901             bool startInParagraph = comparePositions(visibleStart, startOfParagraphToMove) >= 0;
    902             bool endInParagraph = comparePositions(visibleEnd, endOfParagraphToMove) <= 0;
    903 
    904             startIndex = 0;
    905             if (startInParagraph) {
    906                 RefPtr<Range> startRange = Range::create(document(), rangeCompliantEquivalent(startOfParagraphToMove.deepEquivalent()), rangeCompliantEquivalent(visibleStart.deepEquivalent()));
    907                 startIndex = TextIterator::rangeLength(startRange.get(), true);
    908             }
    909 
    910             endIndex = 0;
    911             if (endInParagraph) {
    912                 RefPtr<Range> endRange = Range::create(document(), rangeCompliantEquivalent(startOfParagraphToMove.deepEquivalent()), rangeCompliantEquivalent(visibleEnd.deepEquivalent()));
    913                 endIndex = TextIterator::rangeLength(endRange.get(), true);
    914             }
    915         }
    916     }
    917 
    918     VisiblePosition beforeParagraph = startOfParagraphToMove.previous();
    919     VisiblePosition afterParagraph(endOfParagraphToMove.next());
    920 
    921     // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
    922     // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.
    923     Position start = startOfParagraphToMove.deepEquivalent().downstream();
    924     Position end = endOfParagraphToMove.deepEquivalent().upstream();
    925 
    926     // start and end can't be used directly to create a Range; they are "editing positions"
    927     Position startRangeCompliant = rangeCompliantEquivalent(start);
    928     Position endRangeCompliant = rangeCompliantEquivalent(end);
    929     RefPtr<Range> range = Range::create(document(), startRangeCompliant.node(), startRangeCompliant.deprecatedEditingOffset(), endRangeCompliant.node(), endRangeCompliant.deprecatedEditingOffset());
    930 
    931     // FIXME: This is an inefficient way to preserve style on nodes in the paragraph to move. It
    932     // shouldn't matter though, since moved paragraphs will usually be quite small.
    933     RefPtr<DocumentFragment> fragment = startOfParagraphToMove != endOfParagraphToMove ? createFragmentFromMarkup(document(), createMarkup(range.get(), 0, DoNotAnnotateForInterchange, true), "") : 0;
    934 
    935     // A non-empty paragraph's style is moved when we copy and move it.  We don't move
    936     // anything if we're given an empty paragraph, but an empty paragraph can have style
    937     // too, <div><b><br></b></div> for example.  Save it so that we can preserve it later.
    938     RefPtr<CSSMutableStyleDeclaration> styleInEmptyParagraph;
    939     if (startOfParagraphToMove == endOfParagraphToMove && preserveStyle) {
    940         styleInEmptyParagraph = editingStyleAtPosition(startOfParagraphToMove.deepEquivalent(), IncludeTypingStyle);
    941         // The moved paragraph should assume the block style of the destination.
    942         styleInEmptyParagraph->removeBlockProperties();
    943     }
    944 
    945     // FIXME (5098931): We should add a new insert action "WebViewInsertActionMoved" and call shouldInsertFragment here.
    946 
    947     setEndingSelection(VisibleSelection(start, end, DOWNSTREAM));
    948     deleteSelection(false, false, false, false);
    949 
    950     ASSERT(destination.deepEquivalent().node()->inDocument());
    951 
    952     cleanupAfterDeletion();
    953 
    954     // Add a br if pruning an empty block level element caused a collapse. For example:
    955     // foo^
    956     // <div>bar</div>
    957     // baz
    958     // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That would
    959     // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br.
    960     // Must recononicalize these two VisiblePositions after the pruning above.
    961     beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
    962     afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
    963     if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || beforeParagraph == afterParagraph)) {
    964         // FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.
    965         insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquivalent());
    966         // Need an updateLayout here in case inserting the br has split a text node.
    967         updateLayout();
    968     }
    969 
    970     RefPtr<Range> startToDestinationRange(Range::create(document(), Position(document(), 0), rangeCompliantEquivalent(destination.deepEquivalent())));
    971     destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(), true);
    972 
    973     setEndingSelection(destination);
    974     applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment, true, false, !preserveStyle, false, true));
    975 
    976     // If the selection is in an empty paragraph, restore styles from the old empty paragraph to the new empty paragraph.
    977     bool selectionIsEmptyParagraph = endingSelection().isCaret() && isStartOfParagraph(endingSelection().visibleStart()) && isEndOfParagraph(endingSelection().visibleStart());
    978     if (styleInEmptyParagraph && selectionIsEmptyParagraph)
    979         applyStyle(styleInEmptyParagraph.get());
    980 
    981     if (preserveSelection && startIndex != -1) {
    982         // Fragment creation (using createMarkup) incorrectly uses regular
    983         // spaces instead of nbsps for some spaces that were rendered (11475), which
    984         // causes spaces to be collapsed during the move operation.  This results
    985         // in a call to rangeFromLocationAndLength with a location past the end
    986         // of the document (which will return null).
    987         RefPtr<Range> start = TextIterator::rangeFromLocationAndLength(document()->documentElement(), destinationIndex + startIndex, 0, true);
    988         RefPtr<Range> end = TextIterator::rangeFromLocationAndLength(document()->documentElement(), destinationIndex + endIndex, 0, true);
    989         if (start && end)
    990             setEndingSelection(VisibleSelection(start->startPosition(), end->startPosition(), DOWNSTREAM));
    991     }
    992 }
    993 
    994 // FIXME: Send an appropriate shouldDeleteRange call.
    995 bool CompositeEditCommand::breakOutOfEmptyListItem()
    996 {
    997     Node* emptyListItem = enclosingEmptyListItem(endingSelection().visibleStart());
    998     if (!emptyListItem)
    999         return false;
   1000 
   1001     RefPtr<CSSMutableStyleDeclaration> style = editingStyleAtPosition(endingSelection().start(), IncludeTypingStyle);
   1002 
   1003     Node* listNode = emptyListItem->parentNode();
   1004     // FIXME: Can't we do something better when the immediate parent wasn't a list node?
   1005     if (!listNode
   1006         || (!listNode->hasTagName(ulTag) && !listNode->hasTagName(olTag))
   1007         || !listNode->isContentEditable())
   1008         return false;
   1009 
   1010     RefPtr<Element> newBlock = 0;
   1011     if (Node* blockEnclosingList = listNode->parentNode()) {
   1012         if (blockEnclosingList->hasTagName(liTag)) { // listNode is inside another list item
   1013             if (visiblePositionAfterNode(blockEnclosingList) == visiblePositionAfterNode(listNode)) {
   1014                 // If listNode appears at the end of the outer list item, then move listNode outside of this list item
   1015                 // e.g. <ul><li>hello <ul><li><br></li></ul> </li></ul> should become <ul><li>hello</li> <ul><li><br></li></ul> </ul> after this section
   1016                 // If listNode does NOT appear at the end, then we should consider it as a regular paragraph.
   1017                 // e.g. <ul><li> <ul><li><br></li></ul> hello</li></ul> should become <ul><li> <div><br></div> hello</li></ul> at the end
   1018                 splitElement(static_cast<Element*>(blockEnclosingList), listNode);
   1019                 removeNodePreservingChildren(listNode->parentNode());
   1020                 newBlock = createListItemElement(document());
   1021             }
   1022             // If listNode does NOT appear at the end of the outer list item, then behave as if in a regular paragraph.
   1023         } else if (blockEnclosingList->hasTagName(olTag) || blockEnclosingList->hasTagName(ulTag))
   1024             newBlock = createListItemElement(document());
   1025     }
   1026     if (!newBlock)
   1027         newBlock = createDefaultParagraphElement(document());
   1028 
   1029     if (emptyListItem->renderer()->nextSibling()) {
   1030         // If emptyListItem follows another list item, split the list node.
   1031         if (emptyListItem->renderer()->previousSibling())
   1032             splitElement(static_cast<Element*>(listNode), emptyListItem);
   1033 
   1034         // If emptyListItem is followed by other list item, then insert newBlock before the list node.
   1035         // Because we have splitted the element, emptyListItem is the first element in the list node.
   1036         // i.e. insert newBlock before ul or ol whose first element is emptyListItem
   1037         insertNodeBefore(newBlock, listNode);
   1038         removeNode(emptyListItem);
   1039     } else {
   1040         // When emptyListItem does not follow any list item, insert newBlock after the enclosing list node.
   1041         // Remove the enclosing node if emptyListItem is the only child; otherwise just remove emptyListItem.
   1042         insertNodeAfter(newBlock, listNode);
   1043         removeNode(emptyListItem->renderer()->previousSibling() ? emptyListItem : listNode);
   1044     }
   1045 
   1046     appendBlockPlaceholder(newBlock);
   1047     setEndingSelection(VisibleSelection(Position(newBlock.get(), 0), DOWNSTREAM));
   1048 
   1049     prepareEditingStyleToApplyAt(style.get(), endingSelection().start());
   1050     if (style->length())
   1051         applyStyle(style.get());
   1052 
   1053     return true;
   1054 }
   1055 
   1056 // If the caret is in an empty quoted paragraph, and either there is nothing before that
   1057 // paragraph, or what is before is unquoted, and the user presses delete, unquote that paragraph.
   1058 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph()
   1059 {
   1060     if (!endingSelection().isCaret())
   1061         return false;
   1062 
   1063     VisiblePosition caret(endingSelection().visibleStart());
   1064     Node* highestBlockquote = highestEnclosingNodeOfType(caret.deepEquivalent(), &isMailBlockquote);
   1065     if (!highestBlockquote)
   1066         return false;
   1067 
   1068     if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret))
   1069         return false;
   1070 
   1071     VisiblePosition previous(caret.previous(true));
   1072     // Only move forward if there's nothing before the caret, or if there's unquoted content before it.
   1073     if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote))
   1074         return false;
   1075 
   1076     RefPtr<Node> br = createBreakElement(document());
   1077     // We want to replace this quoted paragraph with an unquoted one, so insert a br
   1078     // to hold the caret before the highest blockquote.
   1079     insertNodeBefore(br, highestBlockquote);
   1080     VisiblePosition atBR(Position(br.get(), 0));
   1081     // If the br we inserted collapsed, for example foo<br><blockquote>...</blockquote>, insert
   1082     // a second one.
   1083     if (!isStartOfParagraph(atBR))
   1084         insertNodeBefore(createBreakElement(document()), br);
   1085     setEndingSelection(VisibleSelection(atBR));
   1086 
   1087     // If this is an empty paragraph there must be a line break here.
   1088     if (!lineBreakExistsAtVisiblePosition(caret))
   1089         return false;
   1090 
   1091     Position caretPos(caret.deepEquivalent());
   1092     // A line break is either a br or a preserved newline.
   1093     ASSERT(caretPos.node()->hasTagName(brTag) || (caretPos.node()->isTextNode() && caretPos.node()->renderer()->style()->preserveNewline()));
   1094 
   1095     if (caretPos.node()->hasTagName(brTag)) {
   1096         Position beforeBR(positionInParentBeforeNode(caretPos.node()));
   1097         removeNode(caretPos.node());
   1098         prune(beforeBR.node());
   1099     } else {
   1100         ASSERT(caretPos.deprecatedEditingOffset() == 0);
   1101         Text* textNode = static_cast<Text*>(caretPos.node());
   1102         Node* parentNode = textNode->parentNode();
   1103         // The preserved newline must be the first thing in the node, since otherwise the previous
   1104         // paragraph would be quoted, and we verified that it wasn't above.
   1105         deleteTextFromNode(textNode, 0, 1);
   1106         prune(parentNode);
   1107     }
   1108 
   1109     return true;
   1110 }
   1111 
   1112 // Operations use this function to avoid inserting content into an anchor when at the start or the end of
   1113 // that anchor, as in NSTextView.
   1114 // FIXME: This is only an approximation of NSTextViews insertion behavior, which varies depending on how
   1115 // the caret was made.
   1116 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Position& original)
   1117 {
   1118     if (original.isNull())
   1119         return original;
   1120 
   1121     VisiblePosition visiblePos(original);
   1122     Node* enclosingAnchor = enclosingAnchorElement(original);
   1123     Position result = original;
   1124 
   1125     if (!enclosingAnchor)
   1126         return result;
   1127 
   1128     // Don't avoid block level anchors, because that would insert content into the wrong paragraph.
   1129     if (enclosingAnchor && !isBlock(enclosingAnchor)) {
   1130         VisiblePosition firstInAnchor(firstDeepEditingPositionForNode(enclosingAnchor));
   1131         VisiblePosition lastInAnchor(lastDeepEditingPositionForNode(enclosingAnchor));
   1132         // If visually just after the anchor, insert *inside* the anchor unless it's the last
   1133         // VisiblePosition in the document, to match NSTextView.
   1134         if (visiblePos == lastInAnchor) {
   1135             // Make sure anchors are pushed down before avoiding them so that we don't
   1136             // also avoid structural elements like lists and blocks (5142012).
   1137             if (original.node() != enclosingAnchor && original.node()->parentNode() != enclosingAnchor) {
   1138                 pushAnchorElementDown(enclosingAnchor);
   1139                 enclosingAnchor = enclosingAnchorElement(original);
   1140                 if (!enclosingAnchor)
   1141                     return original;
   1142             }
   1143             // Don't insert outside an anchor if doing so would skip over a line break.  It would
   1144             // probably be safe to move the line break so that we could still avoid the anchor here.
   1145             Position downstream(visiblePos.deepEquivalent().downstream());
   1146             if (lineBreakExistsAtVisiblePosition(visiblePos) && downstream.node()->isDescendantOf(enclosingAnchor))
   1147                 return original;
   1148 
   1149             result = positionInParentAfterNode(enclosingAnchor);
   1150         }
   1151         // If visually just before an anchor, insert *outside* the anchor unless it's the first
   1152         // VisiblePosition in a paragraph, to match NSTextView.
   1153         if (visiblePos == firstInAnchor) {
   1154             // Make sure anchors are pushed down before avoiding them so that we don't
   1155             // also avoid structural elements like lists and blocks (5142012).
   1156             if (original.node() != enclosingAnchor && original.node()->parentNode() != enclosingAnchor) {
   1157                 pushAnchorElementDown(enclosingAnchor);
   1158                 enclosingAnchor = enclosingAnchorElement(original);
   1159             }
   1160             if (!enclosingAnchor)
   1161                 return original;
   1162 
   1163             result = positionInParentBeforeNode(enclosingAnchor);
   1164         }
   1165     }
   1166 
   1167     if (result.isNull() || !editableRootForPosition(result))
   1168         result = original;
   1169 
   1170     return result;
   1171 }
   1172 
   1173 // Splits the tree parent by parent until we reach the specified ancestor. We use VisiblePositions
   1174 // to determine if the split is necessary. Returns the last split node.
   1175 PassRefPtr<Node> CompositeEditCommand::splitTreeToNode(Node* start, Node* end, bool splitAncestor)
   1176 {
   1177     ASSERT(start != end);
   1178 
   1179     RefPtr<Node> node;
   1180     for (node = start; node && node->parent() != end; node = node->parent()) {
   1181         VisiblePosition positionInParent(Position(node->parent(), 0), DOWNSTREAM);
   1182         VisiblePosition positionInNode(Position(node, 0), DOWNSTREAM);
   1183         if (positionInParent != positionInNode)
   1184             applyCommandToComposite(SplitElementCommand::create(static_cast<Element*>(node->parent()), node));
   1185     }
   1186     if (splitAncestor) {
   1187         splitElement(static_cast<Element*>(end), node);
   1188         return node->parent();
   1189     }
   1190     return node.release();
   1191 }
   1192 
   1193 PassRefPtr<Element> createBlockPlaceholderElement(Document* document)
   1194 {
   1195     RefPtr<Element> breakNode = document->createElement(brTag, false);
   1196     return breakNode.release();
   1197 }
   1198 
   1199 } // namespace WebCore
   1200