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