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 "core/editing/CompositeEditCommand.h"
     28 
     29 #include "HTMLNames.h"
     30 #include "bindings/v8/ExceptionStatePlaceholder.h"
     31 #include "core/dom/Document.h"
     32 #include "core/dom/DocumentFragment.h"
     33 #include "core/dom/DocumentMarkerController.h"
     34 #include "core/dom/NodeTraversal.h"
     35 #include "core/dom/Range.h"
     36 #include "core/events/ScopedEventQueue.h"
     37 #include "core/dom/Text.h"
     38 #include "core/editing/AppendNodeCommand.h"
     39 #include "core/editing/ApplyStyleCommand.h"
     40 #include "core/editing/DeleteFromTextNodeCommand.h"
     41 #include "core/editing/DeleteSelectionCommand.h"
     42 #include "core/editing/Editor.h"
     43 #include "core/editing/InsertIntoTextNodeCommand.h"
     44 #include "core/editing/InsertLineBreakCommand.h"
     45 #include "core/editing/InsertNodeBeforeCommand.h"
     46 #include "core/editing/InsertParagraphSeparatorCommand.h"
     47 #include "core/editing/MergeIdenticalElementsCommand.h"
     48 #include "core/editing/PlainTextRange.h"
     49 #include "core/editing/RemoveCSSPropertyCommand.h"
     50 #include "core/editing/RemoveNodeCommand.h"
     51 #include "core/editing/RemoveNodePreservingChildrenCommand.h"
     52 #include "core/editing/ReplaceNodeWithSpanCommand.h"
     53 #include "core/editing/ReplaceSelectionCommand.h"
     54 #include "core/editing/SetNodeAttributeCommand.h"
     55 #include "core/editing/SpellChecker.h"
     56 #include "core/editing/SplitElementCommand.h"
     57 #include "core/editing/SplitTextNodeCommand.h"
     58 #include "core/editing/SplitTextNodeContainingElementCommand.h"
     59 #include "core/editing/TextIterator.h"
     60 #include "core/editing/VisibleUnits.h"
     61 #include "core/editing/WrapContentsInDummySpanCommand.h"
     62 #include "core/editing/htmlediting.h"
     63 #include "core/editing/markup.h"
     64 #include "core/html/HTMLElement.h"
     65 #include "core/frame/Frame.h"
     66 #include "core/rendering/InlineTextBox.h"
     67 #include "core/rendering/RenderBlock.h"
     68 #include "core/rendering/RenderText.h"
     69 
     70 using namespace std;
     71 
     72 namespace WebCore {
     73 
     74 using namespace HTMLNames;
     75 
     76 namespace {
     77 class ReentrancyGuard {
     78 public:
     79     static bool isRecursiveCall() { return s_nestingCounter; }
     80 
     81     class Scope {
     82     public:
     83         Scope() { ++s_nestingCounter; }
     84         ~Scope() { --s_nestingCounter; }
     85     };
     86     friend class Scope;
     87 
     88 private:
     89     static int s_nestingCounter;
     90 };
     91 int ReentrancyGuard::s_nestingCounter;
     92 }
     93 
     94 PassRefPtr<EditCommandComposition> EditCommandComposition::create(Document* document,
     95     const VisibleSelection& startingSelection, const VisibleSelection& endingSelection, EditAction editAction)
     96 {
     97     return adoptRef(new EditCommandComposition(document, startingSelection, endingSelection, editAction));
     98 }
     99 
    100 EditCommandComposition::EditCommandComposition(Document* document, const VisibleSelection& startingSelection, const VisibleSelection& endingSelection, EditAction editAction)
    101     : m_document(document)
    102     , m_startingSelection(startingSelection)
    103     , m_endingSelection(endingSelection)
    104     , m_startingRootEditableElement(startingSelection.rootEditableElement())
    105     , m_endingRootEditableElement(endingSelection.rootEditableElement())
    106     , m_editAction(editAction)
    107 {
    108 }
    109 
    110 bool EditCommandComposition::belongsTo(const Frame& frame) const
    111 {
    112     ASSERT(m_document);
    113     return m_document->frame() == &frame;
    114 }
    115 
    116 void EditCommandComposition::unapply()
    117 {
    118     ASSERT(m_document);
    119     RefPtr<Frame> frame = m_document->frame();
    120     ASSERT(frame);
    121 
    122     // Changes to the document may have been made since the last editing operation that require a layout, as in <rdar://problem/5658603>.
    123     // Low level operations, like RemoveNodeCommand, don't require a layout because the high level operations that use them perform one
    124     // if one is necessary (like for the creation of VisiblePositions).
    125     m_document->updateLayoutIgnorePendingStylesheets();
    126 
    127     {
    128         size_t size = m_commands.size();
    129         for (size_t i = size; i; --i)
    130             m_commands[i - 1]->doUnapply();
    131     }
    132 
    133     frame->editor().unappliedEditing(this);
    134 }
    135 
    136 void EditCommandComposition::reapply()
    137 {
    138     ASSERT(m_document);
    139     RefPtr<Frame> frame = m_document->frame();
    140     ASSERT(frame);
    141 
    142     // Changes to the document may have been made since the last editing operation that require a layout, as in <rdar://problem/5658603>.
    143     // Low level operations, like RemoveNodeCommand, don't require a layout because the high level operations that use them perform one
    144     // if one is necessary (like for the creation of VisiblePositions).
    145     m_document->updateLayoutIgnorePendingStylesheets();
    146 
    147     {
    148         size_t size = m_commands.size();
    149         for (size_t i = 0; i != size; ++i)
    150             m_commands[i]->doReapply();
    151     }
    152 
    153     frame->editor().reappliedEditing(this);
    154 }
    155 
    156 void EditCommandComposition::append(SimpleEditCommand* command)
    157 {
    158     m_commands.append(command);
    159 }
    160 
    161 void EditCommandComposition::setStartingSelection(const VisibleSelection& selection)
    162 {
    163     m_startingSelection = selection;
    164     m_startingRootEditableElement = selection.rootEditableElement();
    165 }
    166 
    167 void EditCommandComposition::setEndingSelection(const VisibleSelection& selection)
    168 {
    169     m_endingSelection = selection;
    170     m_endingRootEditableElement = selection.rootEditableElement();
    171 }
    172 
    173 CompositeEditCommand::CompositeEditCommand(Document& document)
    174     : EditCommand(document)
    175 {
    176 }
    177 
    178 CompositeEditCommand::~CompositeEditCommand()
    179 {
    180     ASSERT(isTopLevelCommand() || !m_composition);
    181 }
    182 
    183 void CompositeEditCommand::apply()
    184 {
    185     // We don't allow recusrive |apply()| to protect against attack code.
    186     // Recursive call of |apply()| could be happened by moving iframe
    187     // with script triggered by insertion, e.g. <iframe src="javascript:...">
    188     // <iframe onload="...">. This usage is valid as of the specification
    189     // although, it isn't common use case, rather it is used as attack code.
    190     if (ReentrancyGuard::isRecursiveCall())
    191         return;
    192 
    193     if (!endingSelection().isContentRichlyEditable()) {
    194         switch (editingAction()) {
    195         case EditActionTyping:
    196         case EditActionPaste:
    197         case EditActionDrag:
    198         case EditActionSetWritingDirection:
    199         case EditActionCut:
    200         case EditActionUnspecified:
    201             break;
    202         default:
    203             ASSERT_NOT_REACHED();
    204             return;
    205         }
    206     }
    207     ensureComposition();
    208 
    209     // Changes to the document may have been made since the last editing operation that require a layout, as in <rdar://problem/5658603>.
    210     // Low level operations, like RemoveNodeCommand, don't require a layout because the high level operations that use them perform one
    211     // if one is necessary (like for the creation of VisiblePositions).
    212     document().updateLayoutIgnorePendingStylesheets();
    213 
    214     Frame* frame = document().frame();
    215     ASSERT(frame);
    216     {
    217         EventQueueScope eventQueueScope;
    218         ReentrancyGuard::Scope reentrancyGuardScope;
    219         doApply();
    220     }
    221 
    222     // Only need to call appliedEditing for top-level commands,
    223     // and TypingCommands do it on their own (see TypingCommand::typingAddedToOpenCommand).
    224     if (!isTypingCommand())
    225         frame->editor().appliedEditing(this);
    226     setShouldRetainAutocorrectionIndicator(false);
    227 }
    228 
    229 EditCommandComposition* CompositeEditCommand::ensureComposition()
    230 {
    231     CompositeEditCommand* command = this;
    232     while (command && command->parent())
    233         command = command->parent();
    234     if (!command->m_composition)
    235         command->m_composition = EditCommandComposition::create(&document(), startingSelection(), endingSelection(), editingAction());
    236     return command->m_composition.get();
    237 }
    238 
    239 bool CompositeEditCommand::isCreateLinkCommand() const
    240 {
    241     return false;
    242 }
    243 
    244 bool CompositeEditCommand::preservesTypingStyle() const
    245 {
    246     return false;
    247 }
    248 
    249 bool CompositeEditCommand::isTypingCommand() const
    250 {
    251     return false;
    252 }
    253 
    254 bool CompositeEditCommand::shouldRetainAutocorrectionIndicator() const
    255 {
    256     return false;
    257 }
    258 
    259 void CompositeEditCommand::setShouldRetainAutocorrectionIndicator(bool)
    260 {
    261 }
    262 
    263 //
    264 // sugary-sweet convenience functions to help create and apply edit commands in composite commands
    265 //
    266 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<EditCommand> prpCommand)
    267 {
    268     RefPtr<EditCommand> command = prpCommand;
    269     command->setParent(this);
    270     command->doApply();
    271     if (command->isSimpleEditCommand()) {
    272         command->setParent(0);
    273         ensureComposition()->append(toSimpleEditCommand(command.get()));
    274     }
    275     m_commands.append(command.release());
    276 }
    277 
    278 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<CompositeEditCommand> command, const VisibleSelection& selection)
    279 {
    280     command->setParent(this);
    281     if (selection != command->endingSelection()) {
    282         command->setStartingSelection(selection);
    283         command->setEndingSelection(selection);
    284     }
    285     command->doApply();
    286     m_commands.append(command);
    287 }
    288 
    289 void CompositeEditCommand::applyStyle(const EditingStyle* style, EditAction editingAction)
    290 {
    291     applyCommandToComposite(ApplyStyleCommand::create(document(), style, editingAction));
    292 }
    293 
    294 void CompositeEditCommand::applyStyle(const EditingStyle* style, const Position& start, const Position& end, EditAction editingAction)
    295 {
    296     applyCommandToComposite(ApplyStyleCommand::create(document(), style, start, end, editingAction));
    297 }
    298 
    299 void CompositeEditCommand::applyStyledElement(PassRefPtr<Element> element)
    300 {
    301     applyCommandToComposite(ApplyStyleCommand::create(element, false));
    302 }
    303 
    304 void CompositeEditCommand::removeStyledElement(PassRefPtr<Element> element)
    305 {
    306     applyCommandToComposite(ApplyStyleCommand::create(element, true));
    307 }
    308 
    309 void CompositeEditCommand::insertParagraphSeparator(bool useDefaultParagraphElement, bool pasteBlockqutoeIntoUnquotedArea)
    310 {
    311     applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(), useDefaultParagraphElement, pasteBlockqutoeIntoUnquotedArea));
    312 }
    313 
    314 void CompositeEditCommand::insertLineBreak()
    315 {
    316     applyCommandToComposite(InsertLineBreakCommand::create(document()));
    317 }
    318 
    319 bool CompositeEditCommand::isRemovableBlock(const Node* node)
    320 {
    321     if (!node->hasTagName(divTag))
    322         return false;
    323 
    324     Node* parentNode = node->parentNode();
    325     if (parentNode && parentNode->firstChild() != parentNode->lastChild())
    326         return false;
    327 
    328     if (!toElement(node)->hasAttributes())
    329         return true;
    330 
    331     return false;
    332 }
    333 
    334 void CompositeEditCommand::insertNodeBefore(PassRefPtr<Node> insertChild, PassRefPtr<Node> refChild, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAlwaysEditable)
    335 {
    336     ASSERT(!refChild->hasTagName(bodyTag));
    337     applyCommandToComposite(InsertNodeBeforeCommand::create(insertChild, refChild, shouldAssumeContentIsAlwaysEditable));
    338 }
    339 
    340 void CompositeEditCommand::insertNodeAfter(PassRefPtr<Node> insertChild, PassRefPtr<Node> refChild)
    341 {
    342     ASSERT(insertChild);
    343     ASSERT(refChild);
    344     ASSERT(!refChild->hasTagName(bodyTag));
    345     ContainerNode* parent = refChild->parentNode();
    346     ASSERT(parent);
    347     ASSERT(!parent->isShadowRoot());
    348     if (parent->lastChild() == refChild)
    349         appendNode(insertChild, parent);
    350     else {
    351         ASSERT(refChild->nextSibling());
    352         insertNodeBefore(insertChild, refChild->nextSibling());
    353     }
    354 }
    355 
    356 void CompositeEditCommand::insertNodeAt(PassRefPtr<Node> insertChild, const Position& editingPosition)
    357 {
    358     ASSERT(isEditablePosition(editingPosition));
    359     // For editing positions like [table, 0], insert before the table,
    360     // likewise for replaced elements, brs, etc.
    361     Position p = editingPosition.parentAnchoredEquivalent();
    362     Node* refChild = p.deprecatedNode();
    363     int offset = p.deprecatedEditingOffset();
    364 
    365     if (canHaveChildrenForEditing(refChild)) {
    366         Node* child = refChild->firstChild();
    367         for (int i = 0; child && i < offset; i++)
    368             child = child->nextSibling();
    369         if (child)
    370             insertNodeBefore(insertChild, child);
    371         else
    372             appendNode(insertChild, toContainerNode(refChild));
    373     } else if (caretMinOffset(refChild) >= offset)
    374         insertNodeBefore(insertChild, refChild);
    375     else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) {
    376         splitTextNode(toText(refChild), offset);
    377 
    378         // Mutation events (bug 22634) from the text node insertion may have removed the refChild
    379         if (!refChild->inDocument())
    380             return;
    381         insertNodeBefore(insertChild, refChild);
    382     } else
    383         insertNodeAfter(insertChild, refChild);
    384 }
    385 
    386 void CompositeEditCommand::appendNode(PassRefPtr<Node> node, PassRefPtr<ContainerNode> parent)
    387 {
    388     ASSERT(canHaveChildrenForEditing(parent.get()));
    389     applyCommandToComposite(AppendNodeCommand::create(parent, node));
    390 }
    391 
    392 void CompositeEditCommand::removeChildrenInRange(PassRefPtr<Node> node, unsigned from, unsigned to)
    393 {
    394     Vector<RefPtr<Node> > children;
    395     Node* child = node->childNode(from);
    396     for (unsigned i = from; child && i < to; i++, child = child->nextSibling())
    397         children.append(child);
    398 
    399     size_t size = children.size();
    400     for (size_t i = 0; i < size; ++i)
    401         removeNode(children[i].release());
    402 }
    403 
    404 void CompositeEditCommand::removeNode(PassRefPtr<Node> node, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAlwaysEditable)
    405 {
    406     if (!node || !node->nonShadowBoundaryParentNode())
    407         return;
    408     applyCommandToComposite(RemoveNodeCommand::create(node, shouldAssumeContentIsAlwaysEditable));
    409 }
    410 
    411 void CompositeEditCommand::removeNodePreservingChildren(PassRefPtr<Node> node, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAlwaysEditable)
    412 {
    413     applyCommandToComposite(RemoveNodePreservingChildrenCommand::create(node, shouldAssumeContentIsAlwaysEditable));
    414 }
    415 
    416 void CompositeEditCommand::removeNodeAndPruneAncestors(PassRefPtr<Node> node, Node* excludeNode)
    417 {
    418     ASSERT(node.get() != excludeNode);
    419     RefPtr<ContainerNode> parent = node->parentNode();
    420     removeNode(node);
    421     prune(parent.release(), excludeNode);
    422 }
    423 
    424 void CompositeEditCommand::moveRemainingSiblingsToNewParent(Node* node, Node* pastLastNodeToMove, PassRefPtr<Element> prpNewParent)
    425 {
    426     NodeVector nodesToRemove;
    427     RefPtr<Element> newParent = prpNewParent;
    428 
    429     for (; node && node != pastLastNodeToMove; node = node->nextSibling())
    430         nodesToRemove.append(node);
    431 
    432     for (unsigned i = 0; i < nodesToRemove.size(); i++) {
    433         removeNode(nodesToRemove[i]);
    434         appendNode(nodesToRemove[i], newParent);
    435     }
    436 }
    437 
    438 void CompositeEditCommand::updatePositionForNodeRemovalPreservingChildren(Position& position, Node* node)
    439 {
    440     int offset = (position.anchorType() == Position::PositionIsOffsetInAnchor) ? position.offsetInContainerNode() : 0;
    441     updatePositionForNodeRemoval(position, node);
    442     if (offset)
    443         position.moveToOffset(offset);
    444 }
    445 
    446 HTMLElement* CompositeEditCommand::replaceElementWithSpanPreservingChildrenAndAttributes(PassRefPtr<HTMLElement> node)
    447 {
    448     // It would also be possible to implement all of ReplaceNodeWithSpanCommand
    449     // as a series of existing smaller edit commands.  Someone who wanted to
    450     // reduce the number of edit commands could do so here.
    451     RefPtr<ReplaceNodeWithSpanCommand> command = ReplaceNodeWithSpanCommand::create(node);
    452     applyCommandToComposite(command);
    453     // Returning a raw pointer here is OK because the command is retained by
    454     // applyCommandToComposite (thus retaining the span), and the span is also
    455     // in the DOM tree, and thus alive whie it has a parent.
    456     ASSERT(command->spanElement()->inDocument());
    457     return command->spanElement();
    458 }
    459 
    460 void CompositeEditCommand::prune(PassRefPtr<Node> node, Node* excludeNode)
    461 {
    462     if (RefPtr<Node> highestNodeToRemove = highestNodeToRemoveInPruning(node.get(), excludeNode))
    463         removeNode(highestNodeToRemove.release());
    464 }
    465 
    466 void CompositeEditCommand::splitTextNode(PassRefPtr<Text> node, unsigned offset)
    467 {
    468     applyCommandToComposite(SplitTextNodeCommand::create(node, offset));
    469 }
    470 
    471 void CompositeEditCommand::splitElement(PassRefPtr<Element> element, PassRefPtr<Node> atChild)
    472 {
    473     applyCommandToComposite(SplitElementCommand::create(element, atChild));
    474 }
    475 
    476 void CompositeEditCommand::mergeIdenticalElements(PassRefPtr<Element> prpFirst, PassRefPtr<Element> prpSecond)
    477 {
    478     RefPtr<Element> first = prpFirst;
    479     RefPtr<Element> second = prpSecond;
    480     ASSERT(!first->isDescendantOf(second.get()) && second != first);
    481     if (first->nextSibling() != second) {
    482         removeNode(second);
    483         insertNodeAfter(second, first);
    484     }
    485     applyCommandToComposite(MergeIdenticalElementsCommand::create(first, second));
    486 }
    487 
    488 void CompositeEditCommand::wrapContentsInDummySpan(PassRefPtr<Element> element)
    489 {
    490     applyCommandToComposite(WrapContentsInDummySpanCommand::create(element));
    491 }
    492 
    493 void CompositeEditCommand::splitTextNodeContainingElement(PassRefPtr<Text> text, unsigned offset)
    494 {
    495     applyCommandToComposite(SplitTextNodeContainingElementCommand::create(text, offset));
    496 }
    497 
    498 void CompositeEditCommand::insertTextIntoNode(PassRefPtr<Text> node, unsigned offset, const String& text)
    499 {
    500     if (!text.isEmpty())
    501         applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset, text));
    502 }
    503 
    504 void CompositeEditCommand::deleteTextFromNode(PassRefPtr<Text> node, unsigned offset, unsigned count)
    505 {
    506     applyCommandToComposite(DeleteFromTextNodeCommand::create(node, offset, count));
    507 }
    508 
    509 void CompositeEditCommand::replaceTextInNode(PassRefPtr<Text> prpNode, unsigned offset, unsigned count, const String& replacementText)
    510 {
    511     RefPtr<Text> node(prpNode);
    512     applyCommandToComposite(DeleteFromTextNodeCommand::create(node, offset, count));
    513     if (!replacementText.isEmpty())
    514         applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset, replacementText));
    515 }
    516 
    517 Position CompositeEditCommand::replaceSelectedTextInNode(const String& text)
    518 {
    519     Position start = endingSelection().start();
    520     Position end = endingSelection().end();
    521     if (start.containerNode() != end.containerNode() || !start.containerNode()->isTextNode() || isTabSpanTextNode(start.containerNode()))
    522         return Position();
    523 
    524     RefPtr<Text> textNode = start.containerText();
    525     replaceTextInNode(textNode, start.offsetInContainerNode(), end.offsetInContainerNode() - start.offsetInContainerNode(), text);
    526 
    527     return Position(textNode.release(), start.offsetInContainerNode() + text.length());
    528 }
    529 
    530 static void copyMarkers(const Vector<DocumentMarker*>& markerPointers, Vector<DocumentMarker>& markers)
    531 {
    532     size_t arraySize = markerPointers.size();
    533     markers.reserveCapacity(arraySize);
    534     for (size_t i = 0; i < arraySize; ++i)
    535         markers.append(*markerPointers[i]);
    536 }
    537 
    538 void CompositeEditCommand::replaceTextInNodePreservingMarkers(PassRefPtr<Text> prpNode, unsigned offset, unsigned count, const String& replacementText)
    539 {
    540     RefPtr<Text> node(prpNode);
    541     DocumentMarkerController* markerController = document().markers();
    542     Vector<DocumentMarker> markers;
    543     copyMarkers(markerController->markersInRange(Range::create(document(), node.get(), offset, node.get(), offset + count).get(), DocumentMarker::AllMarkers()), markers);
    544     replaceTextInNode(node, offset, count, replacementText);
    545     RefPtr<Range> newRange = Range::create(document(), node.get(), offset, node.get(), offset + replacementText.length());
    546     for (size_t i = 0; i < markers.size(); ++i)
    547         markerController->addMarker(newRange.get(), markers[i].type(), markers[i].description());
    548 }
    549 
    550 Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos)
    551 {
    552     if (!isTabSpanTextNode(pos.anchorNode()))
    553         return pos;
    554 
    555     switch (pos.anchorType()) {
    556     case Position::PositionIsBeforeChildren:
    557     case Position::PositionIsAfterChildren:
    558         ASSERT_NOT_REACHED();
    559         return pos;
    560     case Position::PositionIsOffsetInAnchor:
    561         break;
    562     case Position::PositionIsBeforeAnchor:
    563         return positionInParentBeforeNode(pos.anchorNode());
    564     case Position::PositionIsAfterAnchor:
    565         return positionInParentAfterNode(pos.anchorNode());
    566     }
    567 
    568     Node* tabSpan = tabSpanNode(pos.containerNode());
    569 
    570     if (pos.offsetInContainerNode() <= caretMinOffset(pos.containerNode()))
    571         return positionInParentBeforeNode(tabSpan);
    572 
    573     if (pos.offsetInContainerNode() >= caretMaxOffset(pos.containerNode()))
    574         return positionInParentAfterNode(tabSpan);
    575 
    576     splitTextNodeContainingElement(toText(pos.containerNode()), pos.offsetInContainerNode());
    577     return positionInParentBeforeNode(tabSpan);
    578 }
    579 
    580 void CompositeEditCommand::insertNodeAtTabSpanPosition(PassRefPtr<Node> node, const Position& pos)
    581 {
    582     // insert node before, after, or at split of tab span
    583     insertNodeAt(node, positionOutsideTabSpan(pos));
    584 }
    585 
    586 void CompositeEditCommand::deleteSelection(bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements, bool sanitizeMarkup)
    587 {
    588     if (endingSelection().isRange())
    589         applyCommandToComposite(DeleteSelectionCommand::create(document(), smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements, sanitizeMarkup));
    590 }
    591 
    592 void CompositeEditCommand::deleteSelection(const VisibleSelection &selection, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements, bool sanitizeMarkup)
    593 {
    594     if (selection.isRange())
    595         applyCommandToComposite(DeleteSelectionCommand::create(selection, smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements, sanitizeMarkup));
    596 }
    597 
    598 void CompositeEditCommand::removeCSSProperty(PassRefPtr<Element> element, CSSPropertyID property)
    599 {
    600     applyCommandToComposite(RemoveCSSPropertyCommand::create(document(), element, property));
    601 }
    602 
    603 void CompositeEditCommand::removeNodeAttribute(PassRefPtr<Element> element, const QualifiedName& attribute)
    604 {
    605     setNodeAttribute(element, attribute, AtomicString());
    606 }
    607 
    608 void CompositeEditCommand::setNodeAttribute(PassRefPtr<Element> element, const QualifiedName& attribute, const AtomicString& value)
    609 {
    610     applyCommandToComposite(SetNodeAttributeCommand::create(element, attribute, value));
    611 }
    612 
    613 static inline bool containsOnlyWhitespace(const String& text)
    614 {
    615     for (unsigned i = 0; i < text.length(); ++i) {
    616         if (!isWhitespace(text[i]))
    617             return false;
    618     }
    619 
    620     return true;
    621 }
    622 
    623 bool CompositeEditCommand::shouldRebalanceLeadingWhitespaceFor(const String& text) const
    624 {
    625     return containsOnlyWhitespace(text);
    626 }
    627 
    628 bool CompositeEditCommand::canRebalance(const Position& position) const
    629 {
    630     Node* node = position.containerNode();
    631     if (position.anchorType() != Position::PositionIsOffsetInAnchor || !node || !node->isTextNode())
    632         return false;
    633 
    634     Text* textNode = toText(node);
    635     if (textNode->length() == 0)
    636         return false;
    637 
    638     RenderObject* renderer = textNode->renderer();
    639     if (renderer && !renderer->style()->collapseWhiteSpace())
    640         return false;
    641 
    642     return true;
    643 }
    644 
    645 // FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, cousins, etc).
    646 void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position)
    647 {
    648     Node* node = position.containerNode();
    649     if (!canRebalance(position))
    650         return;
    651 
    652     // If the rebalance is for the single offset, and neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.
    653     int offset = position.deprecatedEditingOffset();
    654     String text = toText(node)->data();
    655     if (!isWhitespace(text[offset])) {
    656         offset--;
    657         if (offset < 0 || !isWhitespace(text[offset]))
    658             return;
    659     }
    660 
    661     rebalanceWhitespaceOnTextSubstring(toText(node), position.offsetInContainerNode(), position.offsetInContainerNode());
    662 }
    663 
    664 void CompositeEditCommand::rebalanceWhitespaceOnTextSubstring(PassRefPtr<Text> prpTextNode, int startOffset, int endOffset)
    665 {
    666     RefPtr<Text> textNode = prpTextNode;
    667 
    668     String text = textNode->data();
    669     ASSERT(!text.isEmpty());
    670 
    671     // Set upstream and downstream to define the extent of the whitespace surrounding text[offset].
    672     int upstream = startOffset;
    673     while (upstream > 0 && isWhitespace(text[upstream - 1]))
    674         upstream--;
    675 
    676     int downstream = endOffset;
    677     while ((unsigned)downstream < text.length() && isWhitespace(text[downstream]))
    678         downstream++;
    679 
    680     int length = downstream - upstream;
    681     if (!length)
    682         return;
    683 
    684     VisiblePosition visibleUpstreamPos(Position(textNode, upstream));
    685     VisiblePosition visibleDownstreamPos(Position(textNode, downstream));
    686 
    687     String string = text.substring(upstream, length);
    688     String rebalancedString = stringWithRebalancedWhitespace(string,
    689     // 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
    690     // this function doesn't get all surrounding whitespace, just the whitespace in the current text node.
    691                                                              isStartOfParagraph(visibleUpstreamPos) || upstream == 0,
    692                                                              isEndOfParagraph(visibleDownstreamPos) || (unsigned)downstream == text.length());
    693 
    694     if (string != rebalancedString)
    695         replaceTextInNodePreservingMarkers(textNode.release(), upstream, length, rebalancedString);
    696 }
    697 
    698 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& position)
    699 {
    700     Node* node = position.deprecatedNode();
    701     if (!node || !node->isTextNode())
    702         return;
    703     Text* textNode = toText(node);
    704 
    705     if (textNode->length() == 0)
    706         return;
    707     RenderObject* renderer = textNode->renderer();
    708     if (renderer && !renderer->style()->collapseWhiteSpace())
    709         return;
    710 
    711     // Delete collapsed whitespace so that inserting nbsps doesn't uncollapse it.
    712     Position upstreamPos = position.upstream();
    713     deleteInsignificantText(upstreamPos, position.downstream());
    714     position = upstreamPos.downstream();
    715 
    716     VisiblePosition visiblePos(position);
    717     VisiblePosition previousVisiblePos(visiblePos.previous());
    718     replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(previousVisiblePos);
    719     replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(visiblePos);
    720 }
    721 
    722 void CompositeEditCommand::replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(const VisiblePosition& visiblePosition)
    723 {
    724     if (!isCollapsibleWhitespace(visiblePosition.characterAfter()))
    725         return;
    726     Position pos = visiblePosition.deepEquivalent().downstream();
    727     if (!pos.containerNode() || !pos.containerNode()->isTextNode() || pos.containerNode()->hasTagName(brTag))
    728         return;
    729     replaceTextInNodePreservingMarkers(pos.containerText(), pos.offsetInContainerNode(), 1, nonBreakingSpaceString());
    730 }
    731 
    732 void CompositeEditCommand::rebalanceWhitespace()
    733 {
    734     VisibleSelection selection = endingSelection();
    735     if (selection.isNone())
    736         return;
    737 
    738     rebalanceWhitespaceAt(selection.start());
    739     if (selection.isRange())
    740         rebalanceWhitespaceAt(selection.end());
    741 }
    742 
    743 void CompositeEditCommand::deleteInsignificantText(PassRefPtr<Text> textNode, unsigned start, unsigned end)
    744 {
    745     if (!textNode || start >= end)
    746         return;
    747 
    748     document().updateLayout();
    749 
    750     RenderText* textRenderer = toRenderText(textNode->renderer());
    751     if (!textRenderer)
    752         return;
    753 
    754     Vector<InlineTextBox*> sortedTextBoxes;
    755     size_t sortedTextBoxesPosition = 0;
    756 
    757     for (InlineTextBox* textBox = textRenderer->firstTextBox(); textBox; textBox = textBox->nextTextBox())
    758         sortedTextBoxes.append(textBox);
    759 
    760     // If there is mixed directionality text, the boxes can be out of order,
    761     // (like Arabic with embedded LTR), so sort them first.
    762     if (textRenderer->containsReversedText())
    763         std::sort(sortedTextBoxes.begin(), sortedTextBoxes.end(), InlineTextBox::compareByStart);
    764     InlineTextBox* box = sortedTextBoxes.isEmpty() ? 0 : sortedTextBoxes[sortedTextBoxesPosition];
    765 
    766     if (!box) {
    767         // whole text node is empty
    768         removeNode(textNode);
    769         return;
    770     }
    771 
    772     unsigned length = textNode->length();
    773     if (start >= length || end > length)
    774         return;
    775 
    776     unsigned removed = 0;
    777     InlineTextBox* prevBox = 0;
    778     String str;
    779 
    780     // This loop structure works to process all gaps preceding a box,
    781     // and also will look at the gap after the last box.
    782     while (prevBox || box) {
    783         unsigned gapStart = prevBox ? prevBox->start() + prevBox->len() : 0;
    784         if (end < gapStart)
    785             // No more chance for any intersections
    786             break;
    787 
    788         unsigned gapEnd = box ? box->start() : length;
    789         bool indicesIntersect = start <= gapEnd && end >= gapStart;
    790         int gapLen = gapEnd - gapStart;
    791         if (indicesIntersect && gapLen > 0) {
    792             gapStart = max(gapStart, start);
    793             gapEnd = min(gapEnd, end);
    794             if (str.isNull())
    795                 str = textNode->data().substring(start, end - start);
    796             // remove text in the gap
    797             str.remove(gapStart - start - removed, gapLen);
    798             removed += gapLen;
    799         }
    800 
    801         prevBox = box;
    802         if (box) {
    803             if (++sortedTextBoxesPosition < sortedTextBoxes.size())
    804                 box = sortedTextBoxes[sortedTextBoxesPosition];
    805             else
    806                 box = 0;
    807         }
    808     }
    809 
    810     if (!str.isNull()) {
    811         // Replace the text between start and end with our pruned version.
    812         if (!str.isEmpty())
    813             replaceTextInNode(textNode, start, end - start, str);
    814         else {
    815             // Assert that we are not going to delete all of the text in the node.
    816             // If we were, that should have been done above with the call to
    817             // removeNode and return.
    818             ASSERT(start > 0 || end - start < textNode->length());
    819             deleteTextFromNode(textNode, start, end - start);
    820         }
    821     }
    822 }
    823 
    824 void CompositeEditCommand::deleteInsignificantText(const Position& start, const Position& end)
    825 {
    826     if (start.isNull() || end.isNull())
    827         return;
    828 
    829     if (comparePositions(start, end) >= 0)
    830         return;
    831 
    832     Vector<RefPtr<Text> > nodes;
    833     for (Node* node = start.deprecatedNode(); node; node = NodeTraversal::next(*node)) {
    834         if (node->isTextNode())
    835             nodes.append(toText(node));
    836         if (node == end.deprecatedNode())
    837             break;
    838     }
    839 
    840     for (size_t i = 0; i < nodes.size(); ++i) {
    841         Text* textNode = nodes[i].get();
    842         int startOffset = textNode == start.deprecatedNode() ? start.deprecatedEditingOffset() : 0;
    843         int endOffset = textNode == end.deprecatedNode() ? end.deprecatedEditingOffset() : static_cast<int>(textNode->length());
    844         deleteInsignificantText(textNode, startOffset, endOffset);
    845     }
    846 }
    847 
    848 void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos)
    849 {
    850     Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivalent().downstream();
    851     deleteInsignificantText(pos, end);
    852 }
    853 
    854 PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRefPtr<Element> container)
    855 {
    856     if (!container)
    857         return 0;
    858 
    859     document().updateLayoutIgnorePendingStylesheets();
    860 
    861     // Should assert isRenderBlockFlow || isInlineFlow when deletion improves. See 4244964.
    862     ASSERT(container->renderer());
    863 
    864     RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
    865     appendNode(placeholder, container);
    866     return placeholder.release();
    867 }
    868 
    869 PassRefPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const Position& pos)
    870 {
    871     if (pos.isNull())
    872         return 0;
    873 
    874     // Should assert isRenderBlockFlow || isInlineFlow when deletion improves. See 4244964.
    875     ASSERT(pos.deprecatedNode()->renderer());
    876 
    877     RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
    878     insertNodeAt(placeholder, pos);
    879     return placeholder.release();
    880 }
    881 
    882 PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Element* container)
    883 {
    884     if (!container)
    885         return 0;
    886 
    887     document().updateLayoutIgnorePendingStylesheets();
    888 
    889     RenderObject* renderer = container->renderer();
    890     if (!renderer || !renderer->isRenderBlockFlow())
    891         return 0;
    892 
    893     // append the placeholder to make sure it follows
    894     // any unrendered blocks
    895     RenderBlock* block = toRenderBlock(renderer);
    896     if (block->height() == 0 || (block->isListItem() && block->isEmpty()))
    897         return appendBlockPlaceholder(container);
    898 
    899     return 0;
    900 }
    901 
    902 // Assumes that the position is at a placeholder and does the removal without much checking.
    903 void CompositeEditCommand::removePlaceholderAt(const Position& p)
    904 {
    905     ASSERT(lineBreakExistsAtPosition(p));
    906 
    907     // We are certain that the position is at a line break, but it may be a br or a preserved newline.
    908     if (p.anchorNode()->hasTagName(brTag)) {
    909         removeNode(p.anchorNode());
    910         return;
    911     }
    912 
    913     deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1);
    914 }
    915 
    916 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const Position& position)
    917 {
    918     RefPtr<Element> paragraphElement = createDefaultParagraphElement(document());
    919     paragraphElement->appendChild(createBreakElement(document()));
    920     insertNodeAt(paragraphElement, position);
    921     return paragraphElement.release();
    922 }
    923 
    924 // If the paragraph is not entirely within it's own block, create one and move the paragraph into
    925 // it, and return that block.  Otherwise return 0.
    926 PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary(const Position& pos)
    927 {
    928     if (pos.isNull())
    929         return 0;
    930 
    931     document().updateLayoutIgnorePendingStylesheets();
    932 
    933     // It's strange that this function is responsible for verifying that pos has not been invalidated
    934     // by an earlier call to this function.  The caller, applyBlockStyle, should do this.
    935     VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
    936     VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos));
    937     VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos);
    938     VisiblePosition next = visibleParagraphEnd.next();
    939     VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd;
    940 
    941     Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream();
    942     Position upstreamEnd = visibleEnd.deepEquivalent().upstream();
    943 
    944     // If there are no VisiblePositions in the same block as pos then
    945     // upstreamStart will be outside the paragraph
    946     if (comparePositions(pos, upstreamStart) < 0)
    947         return 0;
    948 
    949     // Perform some checks to see if we need to perform work in this function.
    950     if (isBlock(upstreamStart.deprecatedNode())) {
    951         // If the block is the root editable element, always move content to a new block,
    952         // since it is illegal to modify attributes on the root editable element for editing.
    953         if (upstreamStart.deprecatedNode() == editableRootForPosition(upstreamStart)) {
    954             // If the block is the root editable element and it contains no visible content, create a new
    955             // block but don't try and move content into it, since there's nothing for moveParagraphs to move.
    956             if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(upstreamStart.deprecatedNode()->renderer()))
    957                 return insertNewDefaultParagraphElementAt(upstreamStart);
    958         } else if (isBlock(upstreamEnd.deprecatedNode())) {
    959             if (!upstreamEnd.deprecatedNode()->isDescendantOf(upstreamStart.deprecatedNode())) {
    960                 // If the paragraph end is a descendant of paragraph start, then we need to run
    961                 // the rest of this function. If not, we can bail here.
    962                 return 0;
    963             }
    964         } else if (enclosingBlock(upstreamEnd.deprecatedNode()) != upstreamStart.deprecatedNode()) {
    965             // The visibleEnd.  It must be an ancestor of the paragraph start.
    966             // We can bail as we have a full block to work with.
    967             ASSERT(upstreamStart.deprecatedNode()->isDescendantOf(enclosingBlock(upstreamEnd.deprecatedNode())));
    968             return 0;
    969         } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) {
    970             // At the end of the editable region. We can bail here as well.
    971             return 0;
    972         }
    973     }
    974 
    975     RefPtr<Node> newBlock = insertNewDefaultParagraphElementAt(upstreamStart);
    976 
    977     bool endWasBr = visibleParagraphEnd.deepEquivalent().deprecatedNode()->hasTagName(brTag);
    978 
    979     moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(firstPositionInNode(newBlock.get())));
    980 
    981     if (newBlock->lastChild() && newBlock->lastChild()->hasTagName(brTag) && !endWasBr)
    982         removeNode(newBlock->lastChild());
    983 
    984     return newBlock.release();
    985 }
    986 
    987 void CompositeEditCommand::pushAnchorElementDown(Node* anchorNode)
    988 {
    989     if (!anchorNode)
    990         return;
    991 
    992     ASSERT(anchorNode->isLink());
    993 
    994     setEndingSelection(VisibleSelection::selectionFromContentsOfNode(anchorNode));
    995     applyStyledElement(toElement(anchorNode));
    996     // Clones of anchorNode have been pushed down, now remove it.
    997     if (anchorNode->inDocument())
    998         removeNodePreservingChildren(anchorNode);
    999 }
   1000 
   1001 // Clone the paragraph between start and end under blockElement,
   1002 // preserving the hierarchy up to outerNode.
   1003 
   1004 void CompositeEditCommand::cloneParagraphUnderNewElement(Position& start, Position& end, Node* passedOuterNode, Element* blockElement)
   1005 {
   1006     // First we clone the outerNode
   1007     RefPtr<Node> lastNode;
   1008     RefPtr<Node> outerNode = passedOuterNode;
   1009 
   1010     if (outerNode->isRootEditableElement()) {
   1011         lastNode = blockElement;
   1012     } else {
   1013         lastNode = outerNode->cloneNode(isTableElement(outerNode.get()));
   1014         appendNode(lastNode, blockElement);
   1015     }
   1016 
   1017     if (start.anchorNode() != outerNode && lastNode->isElementNode() && start.anchorNode()->isDescendantOf(outerNode.get())) {
   1018         Vector<RefPtr<Node> > ancestors;
   1019 
   1020         // Insert each node from innerNode to outerNode (excluded) in a list.
   1021         for (Node* n = start.deprecatedNode(); n && n != outerNode; n = n->parentNode())
   1022             ancestors.append(n);
   1023 
   1024         // Clone every node between start.deprecatedNode() and outerBlock.
   1025 
   1026         for (size_t i = ancestors.size(); i != 0; --i) {
   1027             Node* item = ancestors[i - 1].get();
   1028             RefPtr<Node> child = item->cloneNode(isTableElement(item));
   1029             appendNode(child, toElement(lastNode));
   1030             lastNode = child.release();
   1031         }
   1032     }
   1033 
   1034     // Scripts specified in javascript protocol may remove |outerNode|
   1035     // during insertion, e.g. <iframe src="javascript:...">
   1036     if (!outerNode->inDocument())
   1037         return;
   1038 
   1039     // Handle the case of paragraphs with more than one node,
   1040     // cloning all the siblings until end.deprecatedNode() is reached.
   1041 
   1042     if (start.deprecatedNode() != end.deprecatedNode() && !start.deprecatedNode()->isDescendantOf(end.deprecatedNode())) {
   1043         // If end is not a descendant of outerNode we need to
   1044         // find the first common ancestor to increase the scope
   1045         // of our nextSibling traversal.
   1046         while (!end.deprecatedNode()->isDescendantOf(outerNode.get())) {
   1047             outerNode = outerNode->parentNode();
   1048         }
   1049 
   1050         RefPtr<Node> startNode = start.deprecatedNode();
   1051         for (RefPtr<Node> node = NodeTraversal::nextSkippingChildren(*startNode, outerNode.get()); node; node = NodeTraversal::nextSkippingChildren(*node, outerNode.get())) {
   1052             // Move lastNode up in the tree as much as node was moved up in the
   1053             // tree by NodeTraversal::nextSkippingChildren, so that the relative depth between
   1054             // node and the original start node is maintained in the clone.
   1055             while (startNode->parentNode() != node->parentNode()) {
   1056                 startNode = startNode->parentNode();
   1057                 lastNode = lastNode->parentNode();
   1058             }
   1059 
   1060             RefPtr<Node> clonedNode = node->cloneNode(true);
   1061             insertNodeAfter(clonedNode, lastNode);
   1062             lastNode = clonedNode.release();
   1063             if (node == end.deprecatedNode() || end.deprecatedNode()->isDescendantOf(node.get()))
   1064                 break;
   1065         }
   1066     }
   1067 }
   1068 
   1069 
   1070 // There are bugs in deletion when it removes a fully selected table/list.
   1071 // It expands and removes the entire table/list, but will let content
   1072 // before and after the table/list collapse onto one line.
   1073 // Deleting a paragraph will leave a placeholder. Remove it (and prune
   1074 // empty or unrendered parents).
   1075 
   1076 void CompositeEditCommand::cleanupAfterDeletion(VisiblePosition destination)
   1077 {
   1078     VisiblePosition caretAfterDelete = endingSelection().visibleStart();
   1079     Node* destinationNode = destination.deepEquivalent().anchorNode();
   1080     if (caretAfterDelete != destination && isStartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) {
   1081         // Note: We want the rightmost candidate.
   1082         Position position = caretAfterDelete.deepEquivalent().downstream();
   1083         Node* node = position.deprecatedNode();
   1084 
   1085         // Bail if we'd remove an ancestor of our destination.
   1086         if (destinationNode && destinationNode->isDescendantOf(node))
   1087             return;
   1088 
   1089         // Normally deletion will leave a br as a placeholder.
   1090         if (node->hasTagName(brTag)) {
   1091             removeNodeAndPruneAncestors(node, destinationNode);
   1092 
   1093             // If the selection to move was empty and in an empty block that
   1094             // doesn't require a placeholder to prop itself open (like a bordered
   1095             // div or an li), remove it during the move (the list removal code
   1096             // expects this behavior).
   1097         } else if (isBlock(node)) {
   1098             // If caret position after deletion and destination position coincides,
   1099             // node should not be removed.
   1100             if (!position.rendersInDifferentPosition(destination.deepEquivalent())) {
   1101                 prune(node, destinationNode);
   1102                 return;
   1103             }
   1104             removeNodeAndPruneAncestors(node, destinationNode);
   1105         }
   1106         else if (lineBreakExistsAtPosition(position)) {
   1107             // There is a preserved '\n' at caretAfterDelete.
   1108             // We can safely assume this is a text node.
   1109             Text* textNode = toText(node);
   1110             if (textNode->length() == 1)
   1111                 removeNodeAndPruneAncestors(node, destinationNode);
   1112             else
   1113                 deleteTextFromNode(textNode, position.deprecatedEditingOffset(), 1);
   1114         }
   1115     }
   1116 }
   1117 
   1118 // This is a version of moveParagraph that preserves style by keeping the original markup
   1119 // It is currently used only by IndentOutdentCommand but it is meant to be used in the
   1120 // future by several other commands such as InsertList and the align commands.
   1121 // The blockElement parameter is the element to move the paragraph to,
   1122 // outerNode is the top element of the paragraph hierarchy.
   1123 
   1124 void CompositeEditCommand::moveParagraphWithClones(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, Element* blockElement, Node* outerNode)
   1125 {
   1126     ASSERT(outerNode);
   1127     ASSERT(blockElement);
   1128 
   1129     VisiblePosition beforeParagraph = startOfParagraphToMove.previous();
   1130     VisiblePosition afterParagraph(endOfParagraphToMove.next());
   1131 
   1132     // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
   1133     // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.
   1134     Position start = startOfParagraphToMove.deepEquivalent().downstream();
   1135     Position end = endOfParagraphToMove.deepEquivalent().upstream();
   1136 
   1137     cloneParagraphUnderNewElement(start, end, outerNode, blockElement);
   1138 
   1139     setEndingSelection(VisibleSelection(start, end, DOWNSTREAM));
   1140     deleteSelection(false, false, false, false);
   1141 
   1142     // There are bugs in deletion when it removes a fully selected table/list.
   1143     // It expands and removes the entire table/list, but will let content
   1144     // before and after the table/list collapse onto one line.
   1145 
   1146     cleanupAfterDeletion();
   1147 
   1148     // Add a br if pruning an empty block level element caused a collapse.  For example:
   1149     // foo^
   1150     // <div>bar</div>
   1151     // baz
   1152     // Imagine moving 'bar' to ^.  'bar' will be deleted and its div pruned.  That would
   1153     // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br.
   1154     // Must recononicalize these two VisiblePositions after the pruning above.
   1155     beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
   1156     afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
   1157 
   1158     if (beforeParagraph.isNotNull() && !isRenderedTable(beforeParagraph.deepEquivalent().deprecatedNode())
   1159         && ((!isEndOfParagraph(beforeParagraph) && !isStartOfParagraph(beforeParagraph)) || beforeParagraph == afterParagraph)) {
   1160         // FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.
   1161         insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquivalent());
   1162     }
   1163 }
   1164 
   1165 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor)
   1166 {
   1167     ASSERT(isStartOfParagraph(startOfParagraphToMove));
   1168     ASSERT(isEndOfParagraph(endOfParagraphToMove));
   1169     moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, preserveSelection, preserveStyle, constrainingAncestor);
   1170 }
   1171 
   1172 void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor)
   1173 {
   1174     if (startOfParagraphToMove == destination)
   1175         return;
   1176 
   1177     int startIndex = -1;
   1178     int endIndex = -1;
   1179     int destinationIndex = -1;
   1180     bool originalIsDirectional = endingSelection().isDirectional();
   1181     if (preserveSelection && !endingSelection().isNone()) {
   1182         VisiblePosition visibleStart = endingSelection().visibleStart();
   1183         VisiblePosition visibleEnd = endingSelection().visibleEnd();
   1184 
   1185         bool startAfterParagraph = comparePositions(visibleStart, endOfParagraphToMove) > 0;
   1186         bool endBeforeParagraph = comparePositions(visibleEnd, startOfParagraphToMove) < 0;
   1187 
   1188         if (!startAfterParagraph && !endBeforeParagraph) {
   1189             bool startInParagraph = comparePositions(visibleStart, startOfParagraphToMove) >= 0;
   1190             bool endInParagraph = comparePositions(visibleEnd, endOfParagraphToMove) <= 0;
   1191 
   1192             startIndex = 0;
   1193             if (startInParagraph) {
   1194                 RefPtr<Range> startRange = Range::create(document(), startOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleStart.deepEquivalent().parentAnchoredEquivalent());
   1195                 startIndex = TextIterator::rangeLength(startRange.get(), true);
   1196             }
   1197 
   1198             endIndex = 0;
   1199             if (endInParagraph) {
   1200                 RefPtr<Range> endRange = Range::create(document(), startOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleEnd.deepEquivalent().parentAnchoredEquivalent());
   1201                 endIndex = TextIterator::rangeLength(endRange.get(), true);
   1202             }
   1203         }
   1204     }
   1205 
   1206     VisiblePosition beforeParagraph = startOfParagraphToMove.previous(CannotCrossEditingBoundary);
   1207     VisiblePosition afterParagraph(endOfParagraphToMove.next(CannotCrossEditingBoundary));
   1208 
   1209     // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
   1210     // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.
   1211     Position start = startOfParagraphToMove.deepEquivalent().downstream();
   1212     Position end = endOfParagraphToMove.deepEquivalent().upstream();
   1213 
   1214     // start and end can't be used directly to create a Range; they are "editing positions"
   1215     Position startRangeCompliant = start.parentAnchoredEquivalent();
   1216     Position endRangeCompliant = end.parentAnchoredEquivalent();
   1217     RefPtr<Range> range = Range::create(document(), startRangeCompliant.deprecatedNode(), startRangeCompliant.deprecatedEditingOffset(), endRangeCompliant.deprecatedNode(), endRangeCompliant.deprecatedEditingOffset());
   1218 
   1219     // FIXME: This is an inefficient way to preserve style on nodes in the paragraph to move. It
   1220     // shouldn't matter though, since moved paragraphs will usually be quite small.
   1221     RefPtr<DocumentFragment> fragment = startOfParagraphToMove != endOfParagraphToMove ?
   1222         createFragmentFromMarkup(document(), createMarkup(range.get(), 0, DoNotAnnotateForInterchange, true, DoNotResolveURLs, constrainingAncestor), "") : 0;
   1223 
   1224     // A non-empty paragraph's style is moved when we copy and move it.  We don't move
   1225     // anything if we're given an empty paragraph, but an empty paragraph can have style
   1226     // too, <div><b><br></b></div> for example.  Save it so that we can preserve it later.
   1227     RefPtr<EditingStyle> styleInEmptyParagraph;
   1228     if (startOfParagraphToMove == endOfParagraphToMove && preserveStyle) {
   1229         styleInEmptyParagraph = EditingStyle::create(startOfParagraphToMove.deepEquivalent());
   1230         styleInEmptyParagraph->mergeTypingStyle(&document());
   1231         // The moved paragraph should assume the block style of the destination.
   1232         styleInEmptyParagraph->removeBlockProperties();
   1233     }
   1234 
   1235     // FIXME (5098931): We should add a new insert action "WebViewInsertActionMoved" and call shouldInsertFragment here.
   1236 
   1237     setEndingSelection(VisibleSelection(start, end, DOWNSTREAM));
   1238     document().frame()->spellChecker().clearMisspellingsAndBadGrammar(endingSelection());
   1239     deleteSelection(false, false, false, false);
   1240 
   1241     ASSERT(destination.deepEquivalent().inDocument());
   1242     cleanupAfterDeletion(destination);
   1243     ASSERT(destination.deepEquivalent().inDocument());
   1244 
   1245     // Add a br if pruning an empty block level element caused a collapse. For example:
   1246     // foo^
   1247     // <div>bar</div>
   1248     // baz
   1249     // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That would
   1250     // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br.
   1251     // Must recononicalize these two VisiblePositions after the pruning above.
   1252     beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
   1253     afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
   1254     if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || beforeParagraph == afterParagraph)) {
   1255         // FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.
   1256         insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquivalent());
   1257         // Need an updateLayout here in case inserting the br has split a text node.
   1258         document().updateLayoutIgnorePendingStylesheets();
   1259     }
   1260 
   1261     RefPtr<Range> startToDestinationRange(Range::create(document(), firstPositionInNode(document().documentElement()), destination.deepEquivalent().parentAnchoredEquivalent()));
   1262     destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(), true);
   1263 
   1264     setEndingSelection(VisibleSelection(destination, originalIsDirectional));
   1265     ASSERT(endingSelection().isCaretOrRange());
   1266     ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MovingParagraph;
   1267     if (!preserveStyle)
   1268         options |= ReplaceSelectionCommand::MatchStyle;
   1269     applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment, options));
   1270 
   1271     document().frame()->spellChecker().markMisspellingsAndBadGrammar(endingSelection());
   1272 
   1273     // If the selection is in an empty paragraph, restore styles from the old empty paragraph to the new empty paragraph.
   1274     bool selectionIsEmptyParagraph = endingSelection().isCaret() && isStartOfParagraph(endingSelection().visibleStart()) && isEndOfParagraph(endingSelection().visibleStart());
   1275     if (styleInEmptyParagraph && selectionIsEmptyParagraph)
   1276         applyStyle(styleInEmptyParagraph.get());
   1277 
   1278     if (preserveSelection && startIndex != -1) {
   1279         // Fragment creation (using createMarkup) incorrectly uses regular
   1280         // spaces instead of nbsps for some spaces that were rendered (11475), which
   1281         // causes spaces to be collapsed during the move operation.  This results
   1282         // in a call to rangeFromLocationAndLength with a location past the end
   1283         // of the document (which will return null).
   1284         RefPtr<Range> start = PlainTextRange(destinationIndex + startIndex).createRangeForSelection(*document().documentElement());
   1285         RefPtr<Range> end = PlainTextRange(destinationIndex + endIndex).createRangeForSelection(*document().documentElement());
   1286         if (start && end)
   1287             setEndingSelection(VisibleSelection(start->startPosition(), end->startPosition(), DOWNSTREAM, originalIsDirectional));
   1288     }
   1289 }
   1290 
   1291 // FIXME: Send an appropriate shouldDeleteRange call.
   1292 bool CompositeEditCommand::breakOutOfEmptyListItem()
   1293 {
   1294     RefPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelection().visibleStart());
   1295     if (!emptyListItem)
   1296         return false;
   1297 
   1298     RefPtr<EditingStyle> style = EditingStyle::create(endingSelection().start());
   1299     style->mergeTypingStyle(&document());
   1300 
   1301     RefPtr<ContainerNode> listNode = emptyListItem->parentNode();
   1302     // FIXME: Can't we do something better when the immediate parent wasn't a list node?
   1303     if (!listNode
   1304         || (!listNode->hasTagName(ulTag) && !listNode->hasTagName(olTag))
   1305         || !listNode->rendererIsEditable()
   1306         || listNode == emptyListItem->rootEditableElement())
   1307         return false;
   1308 
   1309     RefPtr<Element> newBlock = 0;
   1310     if (ContainerNode* blockEnclosingList = listNode->parentNode()) {
   1311         if (blockEnclosingList->hasTagName(liTag)) { // listNode is inside another list item
   1312             if (visiblePositionAfterNode(blockEnclosingList) == visiblePositionAfterNode(listNode.get())) {
   1313                 // If listNode appears at the end of the outer list item, then move listNode outside of this list item
   1314                 // 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
   1315                 // If listNode does NOT appear at the end, then we should consider it as a regular paragraph.
   1316                 // 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
   1317                 splitElement(toElement(blockEnclosingList), listNode);
   1318                 removeNodePreservingChildren(listNode->parentNode());
   1319                 newBlock = createListItemElement(document());
   1320             }
   1321             // If listNode does NOT appear at the end of the outer list item, then behave as if in a regular paragraph.
   1322         } else if (blockEnclosingList->hasTagName(olTag) || blockEnclosingList->hasTagName(ulTag)) {
   1323             newBlock = createListItemElement(document());
   1324         }
   1325     }
   1326     if (!newBlock)
   1327         newBlock = createDefaultParagraphElement(document());
   1328 
   1329     RefPtr<Node> previousListNode = emptyListItem->isElementNode() ? toElement(emptyListItem)->previousElementSibling(): emptyListItem->previousSibling();
   1330     RefPtr<Node> nextListNode = emptyListItem->isElementNode() ? toElement(emptyListItem)->nextElementSibling(): emptyListItem->nextSibling();
   1331     if (isListItem(nextListNode.get()) || isListElement(nextListNode.get())) {
   1332         // If emptyListItem follows another list item or nested list, split the list node.
   1333         if (isListItem(previousListNode.get()) || isListElement(previousListNode.get()))
   1334             splitElement(toElement(listNode), emptyListItem);
   1335 
   1336         // If emptyListItem is followed by other list item or nested list, then insert newBlock before the list node.
   1337         // Because we have splitted the element, emptyListItem is the first element in the list node.
   1338         // i.e. insert newBlock before ul or ol whose first element is emptyListItem
   1339         insertNodeBefore(newBlock, listNode);
   1340         removeNode(emptyListItem);
   1341     } else {
   1342         // When emptyListItem does not follow any list item or nested list, insert newBlock after the enclosing list node.
   1343         // Remove the enclosing node if emptyListItem is the only child; otherwise just remove emptyListItem.
   1344         insertNodeAfter(newBlock, listNode);
   1345         removeNode(isListItem(previousListNode.get()) || isListElement(previousListNode.get()) ? emptyListItem.get() : listNode.get());
   1346     }
   1347 
   1348     appendBlockPlaceholder(newBlock);
   1349     setEndingSelection(VisibleSelection(firstPositionInNode(newBlock.get()), DOWNSTREAM, endingSelection().isDirectional()));
   1350 
   1351     style->prepareToApplyAt(endingSelection().start());
   1352     if (!style->isEmpty())
   1353         applyStyle(style.get());
   1354 
   1355     return true;
   1356 }
   1357 
   1358 // If the caret is in an empty quoted paragraph, and either there is nothing before that
   1359 // paragraph, or what is before is unquoted, and the user presses delete, unquote that paragraph.
   1360 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph()
   1361 {
   1362     if (!endingSelection().isCaret())
   1363         return false;
   1364 
   1365     VisiblePosition caret(endingSelection().visibleStart());
   1366     Node* highestBlockquote = highestEnclosingNodeOfType(caret.deepEquivalent(), &isMailBlockquote);
   1367     if (!highestBlockquote)
   1368         return false;
   1369 
   1370     if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret))
   1371         return false;
   1372 
   1373     VisiblePosition previous(caret.previous(CannotCrossEditingBoundary));
   1374     // Only move forward if there's nothing before the caret, or if there's unquoted content before it.
   1375     if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote))
   1376         return false;
   1377 
   1378     RefPtr<Node> br = createBreakElement(document());
   1379     // We want to replace this quoted paragraph with an unquoted one, so insert a br
   1380     // to hold the caret before the highest blockquote.
   1381     insertNodeBefore(br, highestBlockquote);
   1382     VisiblePosition atBR(positionBeforeNode(br.get()));
   1383     // If the br we inserted collapsed, for example foo<br><blockquote>...</blockquote>, insert
   1384     // a second one.
   1385     if (!isStartOfParagraph(atBR))
   1386         insertNodeBefore(createBreakElement(document()), br);
   1387     setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional()));
   1388 
   1389     // If this is an empty paragraph there must be a line break here.
   1390     if (!lineBreakExistsAtVisiblePosition(caret))
   1391         return false;
   1392 
   1393     Position caretPos(caret.deepEquivalent().downstream());
   1394     // A line break is either a br or a preserved newline.
   1395     ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedNode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveNewline()));
   1396 
   1397     if (caretPos.deprecatedNode()->hasTagName(brTag))
   1398         removeNodeAndPruneAncestors(caretPos.deprecatedNode());
   1399     else if (caretPos.deprecatedNode()->isTextNode()) {
   1400         ASSERT(caretPos.deprecatedEditingOffset() == 0);
   1401         Text* textNode = toText(caretPos.deprecatedNode());
   1402         ContainerNode* parentNode = textNode->parentNode();
   1403         // The preserved newline must be the first thing in the node, since otherwise the previous
   1404         // paragraph would be quoted, and we verified that it wasn't above.
   1405         deleteTextFromNode(textNode, 0, 1);
   1406         prune(parentNode);
   1407     }
   1408 
   1409     return true;
   1410 }
   1411 
   1412 // Operations use this function to avoid inserting content into an anchor when at the start or the end of
   1413 // that anchor, as in NSTextView.
   1414 // FIXME: This is only an approximation of NSTextViews insertion behavior, which varies depending on how
   1415 // the caret was made.
   1416 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Position& original)
   1417 {
   1418     if (original.isNull())
   1419         return original;
   1420 
   1421     VisiblePosition visiblePos(original);
   1422     Node* enclosingAnchor = enclosingAnchorElement(original);
   1423     Position result = original;
   1424 
   1425     if (!enclosingAnchor)
   1426         return result;
   1427 
   1428     // Don't avoid block level anchors, because that would insert content into the wrong paragraph.
   1429     if (enclosingAnchor && !isBlock(enclosingAnchor)) {
   1430         VisiblePosition firstInAnchor(firstPositionInNode(enclosingAnchor));
   1431         VisiblePosition lastInAnchor(lastPositionInNode(enclosingAnchor));
   1432         // If visually just after the anchor, insert *inside* the anchor unless it's the last
   1433         // VisiblePosition in the document, to match NSTextView.
   1434         if (visiblePos == lastInAnchor) {
   1435             // Make sure anchors are pushed down before avoiding them so that we don't
   1436             // also avoid structural elements like lists and blocks (5142012).
   1437             if (original.deprecatedNode() != enclosingAnchor && original.deprecatedNode()->parentNode() != enclosingAnchor) {
   1438                 pushAnchorElementDown(enclosingAnchor);
   1439                 enclosingAnchor = enclosingAnchorElement(original);
   1440                 if (!enclosingAnchor)
   1441                     return original;
   1442             }
   1443             // Don't insert outside an anchor if doing so would skip over a line break.  It would
   1444             // probably be safe to move the line break so that we could still avoid the anchor here.
   1445             Position downstream(visiblePos.deepEquivalent().downstream());
   1446             if (lineBreakExistsAtVisiblePosition(visiblePos) && downstream.deprecatedNode()->isDescendantOf(enclosingAnchor))
   1447                 return original;
   1448 
   1449             result = positionInParentAfterNode(enclosingAnchor);
   1450         }
   1451         // If visually just before an anchor, insert *outside* the anchor unless it's the first
   1452         // VisiblePosition in a paragraph, to match NSTextView.
   1453         if (visiblePos == firstInAnchor) {
   1454             // Make sure anchors are pushed down before avoiding them so that we don't
   1455             // also avoid structural elements like lists and blocks (5142012).
   1456             if (original.deprecatedNode() != enclosingAnchor && original.deprecatedNode()->parentNode() != enclosingAnchor) {
   1457                 pushAnchorElementDown(enclosingAnchor);
   1458                 enclosingAnchor = enclosingAnchorElement(original);
   1459             }
   1460             if (!enclosingAnchor)
   1461                 return original;
   1462 
   1463             result = positionInParentBeforeNode(enclosingAnchor);
   1464         }
   1465     }
   1466 
   1467     if (result.isNull() || !editableRootForPosition(result))
   1468         result = original;
   1469 
   1470     return result;
   1471 }
   1472 
   1473 // Splits the tree parent by parent until we reach the specified ancestor. We use VisiblePositions
   1474 // to determine if the split is necessary. Returns the last split node.
   1475 PassRefPtr<Node> CompositeEditCommand::splitTreeToNode(Node* start, Node* end, bool shouldSplitAncestor)
   1476 {
   1477     ASSERT(start);
   1478     ASSERT(end);
   1479     ASSERT(start != end);
   1480 
   1481     RefPtr<Node> node;
   1482     if (shouldSplitAncestor && end->parentNode())
   1483         end = end->parentNode();
   1484 
   1485     RefPtr<Node> endNode = end;
   1486     for (node = start; node && node->parentNode() != endNode; node = node->parentNode()) {
   1487         if (!node->parentNode()->isElementNode())
   1488             break;
   1489         // Do not split a node when doing so introduces an empty node.
   1490         VisiblePosition positionInParent = firstPositionInNode(node->parentNode());
   1491         VisiblePosition positionInNode = firstPositionInOrBeforeNode(node.get());
   1492         if (positionInParent != positionInNode)
   1493             splitElement(toElement(node->parentNode()), node);
   1494     }
   1495 
   1496     return node.release();
   1497 }
   1498 
   1499 PassRefPtr<Element> createBlockPlaceholderElement(Document& document)
   1500 {
   1501     RefPtr<Element> breakNode = document.createElement(brTag, false);
   1502     return breakNode.release();
   1503 }
   1504 
   1505 } // namespace WebCore
   1506