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