22bbb33fc5315dec190abe639fd6d15a5e5e2a94
[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     for (auto& command : m_commands)
136         command->doReapply();
137
138     frame->editor().reappliedEditing(this);
139 }
140
141 void EditCommandComposition::append(SimpleEditCommand* command)
142 {
143     m_commands.append(command);
144 }
145
146 void EditCommandComposition::setStartingSelection(const VisibleSelection& selection)
147 {
148     m_startingSelection = selection;
149     m_startingRootEditableElement = selection.rootEditableElement();
150 }
151
152 void EditCommandComposition::setEndingSelection(const VisibleSelection& selection)
153 {
154     m_endingSelection = selection;
155     m_endingRootEditableElement = selection.rootEditableElement();
156 }
157
158 #ifndef NDEBUG
159 void EditCommandComposition::getNodesInCommand(HashSet<Node*>& nodes)
160 {
161     for (auto& command : m_commands)
162         command->getNodesInCommand(nodes);
163 }
164 #endif
165
166 AXTextEditType EditCommandComposition::unapplyEditType() const
167 {
168     switch (editingAction()) {
169     case EditActionCut:
170     case EditActionDelete:
171         return AXTextEditTypeInsert;
172     case EditActionDictation:
173     case EditActionInsert:
174     case EditActionPaste:
175     case EditActionTyping:
176         return AXTextEditTypeDelete;
177     // Include default case for unhandled EditAction cases.
178     default:
179         break;
180     }
181     return AXTextEditTypeUnknown;
182 }
183
184 void applyCommand(PassRefPtr<CompositeEditCommand> command)
185 {
186     command->apply();
187 }
188
189 CompositeEditCommand::CompositeEditCommand(Document& document, EditAction editingAction)
190     : EditCommand(document, editingAction)
191 {
192 }
193
194 CompositeEditCommand::~CompositeEditCommand()
195 {
196     ASSERT(isTopLevelCommand() || !m_composition);
197 }
198
199 void CompositeEditCommand::apply()
200 {
201     if (!endingSelection().isContentRichlyEditable()) {
202         switch (editingAction()) {
203         case EditActionTyping:
204         case EditActionPaste:
205         case EditActionDrag:
206         case EditActionSetWritingDirection:
207         case EditActionCut:
208         case EditActionUnspecified:
209         case EditActionInsert:
210         case EditActionDelete:
211         case EditActionDictation:
212             break;
213         default:
214             ASSERT_NOT_REACHED();
215             return;
216         }
217     }
218     ensureComposition();
219
220     // Changes to the document may have been made since the last editing operation that require a layout, as in <rdar://problem/5658603>.
221     // Low level operations, like RemoveNodeCommand, don't require a layout because the high level operations that use them perform one
222     // if one is necessary (like for the creation of VisiblePositions).
223     document().updateLayoutIgnorePendingStylesheets();
224
225     {
226         EventQueueScope eventQueueScope;
227         doApply();
228     }
229
230     // Only need to call appliedEditing for top-level commands,
231     // and TypingCommands do it on their own (see TypingCommand::typingAddedToOpenCommand).
232     if (!isTypingCommand())
233         frame().editor().appliedEditing(this);
234     setShouldRetainAutocorrectionIndicator(false);
235 }
236
237 EditCommandComposition* CompositeEditCommand::ensureComposition()
238 {
239     CompositeEditCommand* command = this;
240     while (command && command->parent())
241         command = command->parent();
242     if (!command->m_composition)
243         command->m_composition = EditCommandComposition::create(document(), startingSelection(), endingSelection(), editingAction());
244     return command->m_composition.get();
245 }
246
247 bool CompositeEditCommand::isCreateLinkCommand() const
248 {
249     return false;
250 }
251
252 bool CompositeEditCommand::preservesTypingStyle() const
253 {
254     return false;
255 }
256
257 bool CompositeEditCommand::isTypingCommand() const
258 {
259     return false;
260 }
261
262 bool CompositeEditCommand::shouldRetainAutocorrectionIndicator() const
263 {
264     return false;
265 }
266
267 void CompositeEditCommand::setShouldRetainAutocorrectionIndicator(bool)
268 {
269 }
270
271 //
272 // sugary-sweet convenience functions to help create and apply edit commands in composite commands
273 //
274 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<EditCommand> prpCommand)
275 {
276     RefPtr<EditCommand> command = prpCommand;
277     command->setParent(this);
278     command->doApply();
279     if (command->isSimpleEditCommand()) {
280         command->setParent(0);
281         ensureComposition()->append(toSimpleEditCommand(command.get()));
282     }
283     m_commands.append(command.release());
284 }
285
286 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<CompositeEditCommand> command, const VisibleSelection& selection)
287 {
288     command->setParent(this);
289     if (selection != command->endingSelection()) {
290         command->setStartingSelection(selection);
291         command->setEndingSelection(selection);
292     }
293     command->doApply();
294     m_commands.append(command);
295 }
296
297 void CompositeEditCommand::applyStyle(const EditingStyle* style, EditAction editingAction)
298 {
299     applyCommandToComposite(ApplyStyleCommand::create(document(), style, editingAction));
300 }
301
302 void CompositeEditCommand::applyStyle(const EditingStyle* style, const Position& start, const Position& end, EditAction editingAction)
303 {
304     applyCommandToComposite(ApplyStyleCommand::create(document(), style, start, end, editingAction));
305 }
306
307 void CompositeEditCommand::applyStyledElement(PassRefPtr<Element> element)
308 {
309     applyCommandToComposite(ApplyStyleCommand::create(element, false));
310 }
311
312 void CompositeEditCommand::removeStyledElement(PassRefPtr<Element> element)
313 {
314     applyCommandToComposite(ApplyStyleCommand::create(element, true));
315 }
316
317 void CompositeEditCommand::insertParagraphSeparator(bool useDefaultParagraphElement, bool pasteBlockqutoeIntoUnquotedArea)
318 {
319     applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(), useDefaultParagraphElement, pasteBlockqutoeIntoUnquotedArea, editingAction()));
320 }
321
322 void CompositeEditCommand::insertLineBreak()
323 {
324     applyCommandToComposite(InsertLineBreakCommand::create(document()));
325 }
326
327 bool CompositeEditCommand::isRemovableBlock(const Node* node)
328 {
329     ASSERT(node);
330     if (!is<HTMLDivElement>(*node))
331         return false;
332
333     Node* parentNode = node->parentNode();
334     if (parentNode && parentNode->firstChild() != parentNode->lastChild())
335         return false;
336
337     if (!downcast<HTMLDivElement>(*node).hasAttributes())
338         return true;
339
340     return false;
341 }
342
343 void CompositeEditCommand::insertNodeBefore(PassRefPtr<Node> insertChild, PassRefPtr<Node> refChild, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAlwaysEditable)
344 {
345     applyCommandToComposite(InsertNodeBeforeCommand::create(insertChild, refChild, shouldAssumeContentIsAlwaysEditable, editingAction()));
346 }
347
348 void CompositeEditCommand::insertNodeAfter(PassRefPtr<Node> insertChild, PassRefPtr<Node> refChild)
349 {
350     ASSERT(insertChild);
351     ASSERT(refChild);
352     ContainerNode* parent = refChild->parentNode();
353     if (!parent)
354         return;
355
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     for (auto& child : children)
410         removeNode(child.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 Vector<RenderedDocumentMarker> copyMarkers(const Vector<RenderedDocumentMarker*>& markerPointers)
581 {
582     Vector<RenderedDocumentMarker> markers;
583     markers.reserveInitialCapacity(markerPointers.size());
584     for (auto& markerPointer : markerPointers)
585         markers.uncheckedAppend(*markerPointer);
586
587     return markers;
588 }
589
590 void CompositeEditCommand::replaceTextInNodePreservingMarkers(PassRefPtr<Text> prpNode, unsigned offset, unsigned count, const String& replacementText)
591 {
592     RefPtr<Text> node(prpNode);
593     DocumentMarkerController& markerController = document().markers();
594     auto markers = copyMarkers(markerController.markersInRange(Range::create(document(), node, offset, node, offset + count).ptr(), DocumentMarker::AllMarkers()));
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 (auto& textNode : nodes) {
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     if (startOfParagraphToMove.isNull() || endOfParagraphToMove.isNull())
1165         return;
1166     
1167     ASSERT(outerNode);
1168     ASSERT(blockElement);
1169
1170     VisiblePosition beforeParagraph = startOfParagraphToMove.previous();
1171     VisiblePosition afterParagraph(endOfParagraphToMove.next());
1172     
1173     // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
1174     // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.
1175     Position start = startOfParagraphToMove.deepEquivalent().downstream();
1176     Position end = startOfParagraphToMove == endOfParagraphToMove ? start : endOfParagraphToMove.deepEquivalent().upstream();
1177
1178     cloneParagraphUnderNewElement(start, end, outerNode, blockElement);
1179       
1180     setEndingSelection(VisibleSelection(start, end, DOWNSTREAM));
1181     deleteSelection(false, false, false, false);
1182     
1183     // There are bugs in deletion when it removes a fully selected table/list.
1184     // It expands and removes the entire table/list, but will let content
1185     // before and after the table/list collapse onto one line.
1186        
1187     cleanupAfterDeletion();
1188     
1189     // Add a br if pruning an empty block level element caused a collapse.  For example:
1190     // foo^
1191     // <div>bar</div>
1192     // baz
1193     // Imagine moving 'bar' to ^.  'bar' will be deleted and its div pruned.  That would
1194     // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br.
1195     // Must recononicalize these two VisiblePositions after the pruning above.
1196     beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
1197     afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
1198
1199     if (beforeParagraph.isNotNull() && !isRenderedTable(beforeParagraph.deepEquivalent().deprecatedNode())
1200         && ((!isEndOfParagraph(beforeParagraph) && !isStartOfParagraph(beforeParagraph)) || beforeParagraph == afterParagraph)) {
1201         // FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.
1202         insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquivalent());
1203     }
1204 }
1205     
1206     
1207 // This moves a paragraph preserving its style.
1208 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
1209 {
1210     ASSERT(isStartOfParagraph(startOfParagraphToMove));
1211     ASSERT(isEndOfParagraph(endOfParagraphToMove));
1212     moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, preserveSelection, preserveStyle);
1213 }
1214
1215 void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
1216 {
1217     if (startOfParagraphToMove == destination)
1218         return;
1219     
1220     int startIndex = -1;
1221     int endIndex = -1;
1222     int destinationIndex = -1;
1223     bool originalIsDirectional = endingSelection().isDirectional();
1224     if (preserveSelection && !endingSelection().isNone()) {
1225         VisiblePosition visibleStart = endingSelection().visibleStart();
1226         VisiblePosition visibleEnd = endingSelection().visibleEnd();
1227         
1228         bool startAfterParagraph = comparePositions(visibleStart, endOfParagraphToMove) > 0;
1229         bool endBeforeParagraph = comparePositions(visibleEnd, startOfParagraphToMove) < 0;
1230         
1231         if (!startAfterParagraph && !endBeforeParagraph) {
1232             bool startInParagraph = comparePositions(visibleStart, startOfParagraphToMove) >= 0;
1233             bool endInParagraph = comparePositions(visibleEnd, endOfParagraphToMove) <= 0;
1234             
1235             startIndex = 0;
1236             if (startInParagraph) {
1237                 RefPtr<Range> startRange = Range::create(document(), startOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleStart.deepEquivalent().parentAnchoredEquivalent());
1238                 startIndex = TextIterator::rangeLength(startRange.get(), true);
1239             }
1240
1241             endIndex = 0;
1242             if (endInParagraph) {
1243                 RefPtr<Range> endRange = Range::create(document(), startOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleEnd.deepEquivalent().parentAnchoredEquivalent());
1244                 endIndex = TextIterator::rangeLength(endRange.get(), true);
1245             }
1246         }
1247     }
1248     
1249     VisiblePosition beforeParagraph = startOfParagraphToMove.previous(CannotCrossEditingBoundary);
1250     VisiblePosition afterParagraph(endOfParagraphToMove.next(CannotCrossEditingBoundary));
1251
1252     // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
1253     // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.
1254     Position start = startOfParagraphToMove.deepEquivalent().downstream();
1255     Position end = endOfParagraphToMove.deepEquivalent().upstream();
1256      
1257     // start and end can't be used directly to create a Range; they are "editing positions"
1258     Position startRangeCompliant = start.parentAnchoredEquivalent();
1259     Position endRangeCompliant = end.parentAnchoredEquivalent();
1260     RefPtr<Range> range = Range::create(document(), startRangeCompliant.deprecatedNode(), startRangeCompliant.deprecatedEditingOffset(), endRangeCompliant.deprecatedNode(), endRangeCompliant.deprecatedEditingOffset());
1261
1262     // FIXME: This is an inefficient way to preserve style on nodes in the paragraph to move. It
1263     // shouldn't matter though, since moved paragraphs will usually be quite small.
1264     RefPtr<DocumentFragment> fragment;
1265     // This used to use a ternary for initialization, but that confused some versions of GCC, see bug 37912
1266     if (startOfParagraphToMove != endOfParagraphToMove)
1267         fragment = createFragmentFromMarkup(document(), createMarkup(*range, 0, DoNotAnnotateForInterchange, true), "");
1268
1269     // A non-empty paragraph's style is moved when we copy and move it.  We don't move 
1270     // anything if we're given an empty paragraph, but an empty paragraph can have style
1271     // too, <div><b><br></b></div> for example.  Save it so that we can preserve it later.
1272     RefPtr<EditingStyle> styleInEmptyParagraph;
1273 #if !PLATFORM(IOS)
1274     if (startOfParagraphToMove == endOfParagraphToMove && preserveStyle) {
1275 #else
1276     if (startOfParagraphToMove == endOfParagraphToMove && preserveStyle && isRichlyEditablePosition(destination.deepEquivalent())) {
1277 #endif
1278         styleInEmptyParagraph = EditingStyle::create(startOfParagraphToMove.deepEquivalent());
1279         styleInEmptyParagraph->mergeTypingStyle(document());
1280         // The moved paragraph should assume the block style of the destination.
1281         styleInEmptyParagraph->removeBlockProperties();
1282     }
1283     
1284     // FIXME (5098931): We should add a new insert action "WebViewInsertActionMoved" and call shouldInsertFragment here.
1285     
1286     setEndingSelection(VisibleSelection(start, end, DOWNSTREAM));
1287     frame().editor().clearMisspellingsAndBadGrammar(endingSelection());
1288     deleteSelection(false, false, false, false);
1289
1290     ASSERT(destination.deepEquivalent().anchorNode()->inDocument());
1291     cleanupAfterDeletion(destination);
1292     ASSERT(destination.deepEquivalent().anchorNode()->inDocument());
1293
1294     // Add a br if pruning an empty block level element caused a collapse. For example:
1295     // foo^
1296     // <div>bar</div>
1297     // baz
1298     // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That would
1299     // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br.
1300     // Must recononicalize these two VisiblePositions after the pruning above.
1301     beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
1302     afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
1303     if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || beforeParagraph == afterParagraph)) {
1304         // FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.
1305         insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquivalent());
1306         // Need an updateLayout here in case inserting the br has split a text node.
1307         document().updateLayoutIgnorePendingStylesheets();
1308     }
1309
1310     RefPtr<Range> startToDestinationRange(Range::create(document(), firstPositionInNode(document().documentElement()), destination.deepEquivalent().parentAnchoredEquivalent()));
1311     destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(), true);
1312
1313     setEndingSelection(VisibleSelection(destination, originalIsDirectional));
1314     ASSERT(endingSelection().isCaretOrRange());
1315     ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MovingParagraph;
1316     if (!preserveStyle)
1317         options |= ReplaceSelectionCommand::MatchStyle;
1318     applyCommandToComposite(ReplaceSelectionCommand::create(document(), WTF::move(fragment), options));
1319
1320     frame().editor().markMisspellingsAndBadGrammar(endingSelection());
1321
1322     // If the selection is in an empty paragraph, restore styles from the old empty paragraph to the new empty paragraph.
1323     bool selectionIsEmptyParagraph = endingSelection().isCaret() && isStartOfParagraph(endingSelection().visibleStart()) && isEndOfParagraph(endingSelection().visibleStart());
1324     if (styleInEmptyParagraph && selectionIsEmptyParagraph)
1325         applyStyle(styleInEmptyParagraph.get());
1326
1327     if (preserveSelection && startIndex != -1) {
1328         // Fragment creation (using createMarkup) incorrectly uses regular
1329         // spaces instead of nbsps for some spaces that were rendered (11475), which
1330         // causes spaces to be collapsed during the move operation.  This results
1331         // in a call to rangeFromLocationAndLength with a location past the end
1332         // of the document (which will return null).
1333         RefPtr<Range> start = TextIterator::rangeFromLocationAndLength(document().documentElement(), destinationIndex + startIndex, 0, true);
1334         RefPtr<Range> end = TextIterator::rangeFromLocationAndLength(document().documentElement(), destinationIndex + endIndex, 0, true);
1335         if (start && end)
1336             setEndingSelection(VisibleSelection(start->startPosition(), end->startPosition(), DOWNSTREAM, originalIsDirectional));
1337     }
1338 }
1339
1340 // FIXME: Send an appropriate shouldDeleteRange call.
1341 bool CompositeEditCommand::breakOutOfEmptyListItem()
1342 {
1343     RefPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelection().visibleStart());
1344     if (!emptyListItem)
1345         return false;
1346
1347     RefPtr<EditingStyle> style = EditingStyle::create(endingSelection().start());
1348     style->mergeTypingStyle(document());
1349
1350     RefPtr<ContainerNode> listNode = emptyListItem->parentNode();
1351     // FIXME: Can't we do something better when the immediate parent wasn't a list node?
1352     if (!listNode
1353         || (!listNode->hasTagName(ulTag) && !listNode->hasTagName(olTag))
1354         || !listNode->hasEditableStyle()
1355         || listNode == emptyListItem->rootEditableElement())
1356         return false;
1357
1358     RefPtr<Element> newBlock;
1359     if (ContainerNode* blockEnclosingList = listNode->parentNode()) {
1360         if (is<HTMLLIElement>(*blockEnclosingList)) { // listNode is inside another list item
1361             if (visiblePositionAfterNode(blockEnclosingList) == visiblePositionAfterNode(listNode.get())) {
1362                 // If listNode appears at the end of the outer list item, then move listNode outside of this list item
1363                 // 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
1364                 // If listNode does NOT appear at the end, then we should consider it as a regular paragraph.
1365                 // 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
1366                 splitElement(downcast<HTMLLIElement>(blockEnclosingList), listNode);
1367                 removeNodePreservingChildren(listNode->parentNode());
1368                 newBlock = createListItemElement(document());
1369             }
1370             // If listNode does NOT appear at the end of the outer list item, then behave as if in a regular paragraph.
1371         } else if (blockEnclosingList->hasTagName(olTag) || blockEnclosingList->hasTagName(ulTag))
1372             newBlock = createListItemElement(document());
1373     }
1374     if (!newBlock)
1375         newBlock = createDefaultParagraphElement(document());
1376
1377     RefPtr<Node> previousListNode = emptyListItem->isElementNode() ? ElementTraversal::previousSibling(*emptyListItem): emptyListItem->previousSibling();
1378     RefPtr<Node> nextListNode = emptyListItem->isElementNode() ? ElementTraversal::nextSibling(*emptyListItem): emptyListItem->nextSibling();
1379     if (isListItem(nextListNode.get()) || isListElement(nextListNode.get())) {
1380         // If emptyListItem follows another list item or nested list, split the list node.
1381         if (isListItem(previousListNode.get()) || isListElement(previousListNode.get()))
1382             splitElement(downcast<Element>(listNode.get()), emptyListItem);
1383
1384         // If emptyListItem is followed by other list item or nested list, then insert newBlock before the list node.
1385         // Because we have splitted the element, emptyListItem is the first element in the list node.
1386         // i.e. insert newBlock before ul or ol whose first element is emptyListItem
1387         insertNodeBefore(newBlock, listNode);
1388         removeNode(emptyListItem);
1389     } else {
1390         // When emptyListItem does not follow any list item or nested list, insert newBlock after the enclosing list node.
1391         // Remove the enclosing node if emptyListItem is the only child; otherwise just remove emptyListItem.
1392         insertNodeAfter(newBlock, listNode);
1393         removeNode(isListItem(previousListNode.get()) || isListElement(previousListNode.get()) ? emptyListItem.get() : listNode.get());
1394     }
1395
1396     appendBlockPlaceholder(newBlock);
1397     setEndingSelection(VisibleSelection(firstPositionInNode(newBlock.get()), DOWNSTREAM, endingSelection().isDirectional()));
1398
1399     style->prepareToApplyAt(endingSelection().start());
1400     if (!style->isEmpty())
1401         applyStyle(style.get());
1402
1403     return true;
1404 }
1405
1406 // If the caret is in an empty quoted paragraph, and either there is nothing before that
1407 // paragraph, or what is before is unquoted, and the user presses delete, unquote that paragraph.
1408 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph()
1409 {
1410     if (!endingSelection().isCaret())
1411         return false;
1412         
1413     VisiblePosition caret(endingSelection().visibleStart());
1414     Node* highestBlockquote = highestEnclosingNodeOfType(caret.deepEquivalent(), &isMailBlockquote);
1415     if (!highestBlockquote)
1416         return false;
1417         
1418     if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret))
1419         return false;
1420     
1421     VisiblePosition previous(caret.previous(CannotCrossEditingBoundary));
1422     // Only move forward if there's nothing before the caret, or if there's unquoted content before it.
1423     if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote))
1424         return false;
1425     
1426     RefPtr<Node> br = createBreakElement(document());
1427     // We want to replace this quoted paragraph with an unquoted one, so insert a br
1428     // to hold the caret before the highest blockquote.
1429     insertNodeBefore(br, highestBlockquote);
1430     VisiblePosition atBR(positionBeforeNode(br.get()));
1431     // If the br we inserted collapsed, for example foo<br><blockquote>...</blockquote>, insert
1432     // a second one.
1433     if (!isStartOfParagraph(atBR))
1434         insertNodeBefore(createBreakElement(document()), br);
1435     setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional()));
1436     
1437     // If this is an empty paragraph there must be a line break here.
1438     if (!lineBreakExistsAtVisiblePosition(caret))
1439         return false;
1440
1441     Position caretPos(caret.deepEquivalent().downstream());
1442     // A line break is either a br or a preserved newline.
1443     ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedNode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style().preserveNewline()));
1444     
1445     if (caretPos.deprecatedNode()->hasTagName(brTag))
1446         removeNodeAndPruneAncestors(caretPos.deprecatedNode());
1447     else if (is<Text>(*caretPos.deprecatedNode())) {
1448         ASSERT(caretPos.deprecatedEditingOffset() == 0);
1449         Text& textNode = downcast<Text>(*caretPos.deprecatedNode());
1450         ContainerNode* parentNode = textNode.parentNode();
1451         // The preserved newline must be the first thing in the node, since otherwise the previous
1452         // paragraph would be quoted, and we verified that it wasn't above.
1453         deleteTextFromNode(&textNode, 0, 1);
1454         prune(parentNode);
1455     }
1456
1457     return true;
1458 }
1459
1460 // Operations use this function to avoid inserting content into an anchor when at the start or the end of
1461 // that anchor, as in NSTextView.
1462 // FIXME: This is only an approximation of NSTextViews insertion behavior, which varies depending on how
1463 // the caret was made. 
1464 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Position& original)
1465 {
1466     if (original.isNull())
1467         return original;
1468         
1469     VisiblePosition visiblePos(original);
1470     Element* enclosingAnchor = enclosingAnchorElement(original);
1471     Position result = original;
1472
1473     if (!enclosingAnchor)
1474         return result;
1475
1476     // Don't avoid block level anchors, because that would insert content into the wrong paragraph.
1477     if (enclosingAnchor && !isBlock(enclosingAnchor)) {
1478         VisiblePosition firstInAnchor(firstPositionInNode(enclosingAnchor));
1479         VisiblePosition lastInAnchor(lastPositionInNode(enclosingAnchor));
1480         // If visually just after the anchor, insert *inside* the anchor unless it's the last
1481         // VisiblePosition in the document, to match NSTextView.
1482         if (visiblePos == lastInAnchor) {
1483             // Make sure anchors are pushed down before avoiding them so that we don't
1484             // also avoid structural elements like lists and blocks (5142012).
1485             if (original.deprecatedNode() != enclosingAnchor && original.deprecatedNode()->parentNode() != enclosingAnchor) {
1486                 pushAnchorElementDown(*enclosingAnchor);
1487                 enclosingAnchor = enclosingAnchorElement(original);
1488                 if (!enclosingAnchor)
1489                     return original;
1490             }
1491             // Don't insert outside an anchor if doing so would skip over a line break.  It would
1492             // probably be safe to move the line break so that we could still avoid the anchor here.
1493             Position downstream(visiblePos.deepEquivalent().downstream());
1494             if (lineBreakExistsAtVisiblePosition(visiblePos) && downstream.deprecatedNode()->isDescendantOf(enclosingAnchor))
1495                 return original;
1496             
1497             result = positionInParentAfterNode(enclosingAnchor);
1498         }
1499         // If visually just before an anchor, insert *outside* the anchor unless it's the first
1500         // VisiblePosition in a paragraph, to match NSTextView.
1501         if (visiblePos == firstInAnchor) {
1502             // Make sure anchors are pushed down before avoiding them so that we don't
1503             // also avoid structural elements like lists and blocks (5142012).
1504             if (original.deprecatedNode() != enclosingAnchor && original.deprecatedNode()->parentNode() != enclosingAnchor) {
1505                 pushAnchorElementDown(*enclosingAnchor);
1506                 enclosingAnchor = enclosingAnchorElement(original);
1507             }
1508             if (!enclosingAnchor)
1509                 return original;
1510
1511             result = positionInParentBeforeNode(enclosingAnchor);
1512         }
1513     }
1514         
1515     if (result.isNull() || !editableRootForPosition(result))
1516         result = original;
1517     
1518     return result;
1519 }
1520
1521 // Splits the tree parent by parent until we reach the specified ancestor. We use VisiblePositions
1522 // to determine if the split is necessary. Returns the last split node.
1523 PassRefPtr<Node> CompositeEditCommand::splitTreeToNode(Node* start, Node* end, bool shouldSplitAncestor)
1524 {
1525     ASSERT(start);
1526     ASSERT(end);
1527     ASSERT(start != end);
1528
1529     RefPtr<Node> node;
1530     if (shouldSplitAncestor && end->parentNode())
1531         end = end->parentNode();
1532
1533     RefPtr<Node> endNode = end;
1534     for (node = start; node && node->parentNode() != endNode; node = node->parentNode()) {
1535         if (!is<Element>(*node->parentNode()))
1536             break;
1537         // Do not split a node when doing so introduces an empty node.
1538         VisiblePosition positionInParent = firstPositionInNode(node->parentNode());
1539         VisiblePosition positionInNode = firstPositionInOrBeforeNode(node.get());
1540         if (positionInParent != positionInNode)
1541             splitElement(downcast<Element>(node->parentNode()), node);
1542     }
1543
1544     return node.release();
1545 }
1546
1547 Ref<Element> createBlockPlaceholderElement(Document& document)
1548 {
1549     return document.createElement(brTag, false);
1550 }
1551
1552 } // namespace WebCore