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