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