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