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