LayoutTests:
[WebKit-https.git] / WebCore / editing / CompositeEditCommand.cpp
1 /*
2  * Copyright (C) 2005, 2006 Apple Computer, 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 "CSSComputedStyleDeclaration.h"
32 #include "CSSMutableStyleDeclaration.h"
33 #include "CharacterNames.h"
34 #include "DeleteFromTextNodeCommand.h"
35 #include "DeleteSelectionCommand.h"
36 #include "Document.h"
37 #include "DocumentFragment.h"
38 #include "EditorInsertAction.h"
39 #include "Element.h"
40 #include "HTMLNames.h"
41 #include "InlineTextBox.h"
42 #include "InsertIntoTextNodeCommand.h"
43 #include "InsertNodeBeforeCommand.h"
44 #include "InsertParagraphSeparatorCommand.h"
45 #include "InsertTextCommand.h"
46 #include "JoinTextNodesCommand.h"
47 #include "MergeIdenticalElementsCommand.h"
48 #include "Range.h"
49 #include "RemoveCSSPropertyCommand.h"
50 #include "RemoveNodeAttributeCommand.h"
51 #include "RemoveNodeCommand.h"
52 #include "RemoveNodePreservingChildrenCommand.h"
53 #include "ReplaceSelectionCommand.h"
54 #include "SetNodeAttributeCommand.h"
55 #include "SplitElementCommand.h"
56 #include "SplitTextNodeCommand.h"
57 #include "SplitTextNodeContainingElementCommand.h"
58 #include "Text.h"
59 #include "TextIterator.h"
60 #include "WrapContentsInDummySpanCommand.h"
61 #include "htmlediting.h"
62 #include "markup.h"
63 #include "visible_units.h"
64
65 using namespace std;
66
67 namespace WebCore {
68
69 using namespace HTMLNames;
70
71 CompositeEditCommand::CompositeEditCommand(Document *document) 
72     : EditCommand(document)
73 {
74 }
75
76 void CompositeEditCommand::doUnapply()
77 {
78     size_t size = m_commands.size();
79     for (size_t i = size; i != 0; --i)
80         m_commands[i - 1]->unapply();
81 }
82
83 void CompositeEditCommand::doReapply()
84 {
85     size_t size = m_commands.size();
86     for (size_t i = 0; i != size; ++i)
87         m_commands[i]->reapply();
88 }
89
90 //
91 // sugary-sweet convenience functions to help create and apply edit commands in composite commands
92 //
93 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<EditCommand> cmd)
94 {
95     cmd->setParent(this);
96     cmd->apply();
97     m_commands.append(cmd);
98 }
99
100 void CompositeEditCommand::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
101 {
102     applyCommandToComposite(new ApplyStyleCommand(document(), style, editingAction));
103 }
104
105 void CompositeEditCommand::applyStyle(CSSStyleDeclaration* style, const Position& start, const Position& end, EditAction editingAction)
106 {
107     applyCommandToComposite(new ApplyStyleCommand(document(), style, start, end, editingAction));
108 }
109
110 void CompositeEditCommand::applyStyledElement(Element* element)
111 {
112     applyCommandToComposite(new ApplyStyleCommand(element, false));
113 }
114
115 void CompositeEditCommand::removeStyledElement(Element* element)
116 {
117     applyCommandToComposite(new ApplyStyleCommand(element, true));
118 }
119
120 void CompositeEditCommand::insertParagraphSeparator()
121 {
122     applyCommandToComposite(new InsertParagraphSeparatorCommand(document()));
123 }
124
125 void CompositeEditCommand::insertNodeBefore(Node* insertChild, Node* refChild)
126 {
127     ASSERT(!refChild->hasTagName(bodyTag));
128     applyCommandToComposite(new InsertNodeBeforeCommand(insertChild, refChild));
129 }
130
131 void CompositeEditCommand::insertNodeAfter(Node* insertChild, Node* refChild)
132 {
133     ASSERT(!refChild->hasTagName(bodyTag));
134     if (refChild->parentNode()->lastChild() == refChild)
135         appendNode(insertChild, refChild->parentNode());
136     else {
137         ASSERT(refChild->nextSibling());
138         insertNodeBefore(insertChild, refChild->nextSibling());
139     }
140 }
141
142 void CompositeEditCommand::insertNodeAt(Node* insertChild, const Position& editingPosition)
143 {
144     ASSERT(isEditablePosition(editingPosition));
145     // For editing positions like [table, 0], insert before the table,
146     // likewise for replaced elements, brs, etc.
147     Position p = rangeCompliantEquivalent(editingPosition);
148     Node* refChild = p.node();
149     int offset = p.offset();
150     
151     if (canHaveChildrenForEditing(refChild)) {
152         Node* child = refChild->firstChild();
153         for (int i = 0; child && i < offset; i++)
154             child = child->nextSibling();
155         if (child)
156             insertNodeBefore(insertChild, child);
157         else
158             appendNode(insertChild, refChild);
159     } else if (refChild->caretMinOffset() >= offset) {
160         insertNodeBefore(insertChild, refChild);
161     } else if (refChild->isTextNode() && refChild->caretMaxOffset() > offset) {
162         splitTextNode(static_cast<Text *>(refChild), offset);
163         insertNodeBefore(insertChild, refChild);
164     } else {
165         insertNodeAfter(insertChild, refChild);
166     }
167 }
168
169 void CompositeEditCommand::appendNode(Node* newChild, Node* parent)
170 {
171     ASSERT(canHaveChildrenForEditing(parent));
172     applyCommandToComposite(new AppendNodeCommand(parent, newChild));
173 }
174
175 void CompositeEditCommand::removeChildrenInRange(Node* node, int from, int to)
176 {
177     Node* nodeToRemove = node->childNode(from);
178     for (int i = from; i < to; i++) {
179         ASSERT(nodeToRemove);
180         Node* next = nodeToRemove->nextSibling();
181         removeNode(nodeToRemove);
182         nodeToRemove = next;
183     }
184 }
185
186 void CompositeEditCommand::removeNode(Node* removeChild)
187 {
188     applyCommandToComposite(new RemoveNodeCommand(removeChild));
189 }
190
191 void CompositeEditCommand::removeNodePreservingChildren(Node* removeChild)
192 {
193     applyCommandToComposite(new RemoveNodePreservingChildrenCommand(removeChild));
194 }
195
196 void CompositeEditCommand::removeNodeAndPruneAncestors(Node* node)
197 {
198     RefPtr<Node> parent = node->parentNode();
199     removeNode(node);
200     prune(parent);
201 }
202
203 bool hasARenderedDescendant(Node* node)
204 {
205     Node* n = node->firstChild();
206     while (n) {
207         if (n->renderer())
208             return true;
209         n = n->traverseNextNode(node);
210     }
211     return false;
212 }
213
214 void CompositeEditCommand::prune(PassRefPtr<Node> node)
215 {
216     while (node) {
217         // If you change this rule you may have to add an updateLayout() here.
218         RenderObject* renderer = node->renderer();
219         if (renderer && (!renderer->canHaveChildren() || hasARenderedDescendant(node.get()) || node->rootEditableElement() == node))
220             return;
221             
222         RefPtr<Node> next = node->parentNode();
223         removeNode(node.get());
224         node = next;
225     }
226 }
227
228 void CompositeEditCommand::splitTextNode(Text *text, int offset)
229 {
230     applyCommandToComposite(new SplitTextNodeCommand(text, offset));
231 }
232
233 void CompositeEditCommand::splitElement(Element* element, Node* atChild)
234 {
235     applyCommandToComposite(new SplitElementCommand(element, atChild));
236 }
237
238 void CompositeEditCommand::mergeIdenticalElements(Element* first, Element* second)
239 {
240     ASSERT(!first->isDescendantOf(second) && second != first);
241     if (first->nextSibling() != second) {
242         removeNode(second);
243         insertNodeAfter(second, first);
244     }
245     applyCommandToComposite(new MergeIdenticalElementsCommand(first, second));
246 }
247
248 void CompositeEditCommand::wrapContentsInDummySpan(Element* element)
249 {
250     applyCommandToComposite(new WrapContentsInDummySpanCommand(element));
251 }
252
253 void CompositeEditCommand::splitTextNodeContainingElement(Text *text, int offset)
254 {
255     applyCommandToComposite(new SplitTextNodeContainingElementCommand(text, offset));
256 }
257
258 void CompositeEditCommand::joinTextNodes(Text *text1, Text *text2)
259 {
260     applyCommandToComposite(new JoinTextNodesCommand(text1, text2));
261 }
262
263 void CompositeEditCommand::inputText(const String &text, bool selectInsertedText)
264 {
265     RefPtr<InsertTextCommand> command = new InsertTextCommand(document());
266     applyCommandToComposite(command);
267     command->input(text, selectInsertedText);
268 }
269
270 void CompositeEditCommand::insertTextIntoNode(Text *node, int offset, const String &text)
271 {
272     applyCommandToComposite(new InsertIntoTextNodeCommand(node, offset, text));
273 }
274
275 void CompositeEditCommand::deleteTextFromNode(Text *node, int offset, int count)
276 {
277     applyCommandToComposite(new DeleteFromTextNodeCommand(node, offset, count));
278 }
279
280 void CompositeEditCommand::replaceTextInNode(Text *node, int offset, int count, const String &replacementText)
281 {
282     applyCommandToComposite(new DeleteFromTextNodeCommand(node, offset, count));
283     applyCommandToComposite(new InsertIntoTextNodeCommand(node, offset, replacementText));
284 }
285
286 Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos)
287 {
288     if (!isTabSpanTextNode(pos.node()))
289         return pos;
290     
291     Node* tabSpan = tabSpanNode(pos.node());
292     
293     if (pos.offset() <= pos.node()->caretMinOffset())
294         return positionBeforeNode(tabSpan);
295         
296     if (pos.offset() >= pos.node()->caretMaxOffset())
297         return positionAfterNode(tabSpan);
298
299     splitTextNodeContainingElement(static_cast<Text *>(pos.node()), pos.offset());
300     return positionBeforeNode(tabSpan);
301 }
302
303 void CompositeEditCommand::insertNodeAtTabSpanPosition(Node* node, const Position& pos)
304 {
305     // insert node before, after, or at split of tab span
306     Position insertPos = positionOutsideTabSpan(pos);
307     insertNodeAt(node, insertPos);
308 }
309
310 void CompositeEditCommand::deleteSelection(bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
311 {
312     if (endingSelection().isRange())
313         applyCommandToComposite(new DeleteSelectionCommand(document(), smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));
314 }
315
316 void CompositeEditCommand::deleteSelection(const Selection &selection, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
317 {
318     if (selection.isRange())
319         applyCommandToComposite(new DeleteSelectionCommand(selection, smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));
320 }
321
322 void CompositeEditCommand::removeCSSProperty(CSSStyleDeclaration *decl, int property)
323 {
324     applyCommandToComposite(new RemoveCSSPropertyCommand(document(), decl, property));
325 }
326
327 void CompositeEditCommand::removeNodeAttribute(Element* element, const QualifiedName& attribute)
328 {
329     if (element->getAttribute(attribute).isNull())
330         return;
331     applyCommandToComposite(new RemoveNodeAttributeCommand(element, attribute));
332 }
333
334 void CompositeEditCommand::setNodeAttribute(Element* element, const QualifiedName& attribute, const String &value)
335 {
336     applyCommandToComposite(new SetNodeAttributeCommand(element, attribute, value));
337 }
338
339 static inline bool isWhitespace(UChar c)
340 {
341     return c == noBreakSpace || c == ' ' || c == '\n' || c == '\t';
342 }
343
344 // FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, cousins, etc).
345 void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position)
346 {
347     Node* node = position.node();
348     if (!node || !node->isTextNode())
349         return;
350     Text* textNode = static_cast<Text*>(node);    
351     
352     if (textNode->length() == 0)
353         return;
354     RenderObject* renderer = textNode->renderer();
355     if (renderer && !renderer->style()->collapseWhiteSpace())
356         return;
357         
358     String text = textNode->data();
359     ASSERT(!text.isEmpty());
360
361     int offset = position.offset();
362     // If neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.
363     if (!isWhitespace(text[offset])) {
364         offset--;
365         if (offset < 0 || !isWhitespace(text[offset]))
366             return;
367     }
368     
369     // Set upstream and downstream to define the extent of the whitespace surrounding text[offset].
370     int upstream = offset;
371     while (upstream > 0 && isWhitespace(text[upstream - 1]))
372         upstream--;
373     
374     int downstream = offset;
375     while ((unsigned)downstream + 1 < text.length() && isWhitespace(text[downstream + 1]))
376         downstream++;
377     
378     int length = downstream - upstream + 1;
379     ASSERT(length > 0);
380     
381     VisiblePosition visibleUpstreamPos(Position(position.node(), upstream));
382     VisiblePosition visibleDownstreamPos(Position(position.node(), downstream + 1));
383     
384     String string = text.substring(upstream, length);
385     String rebalancedString = stringWithRebalancedWhitespace(string,
386     // 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
387     // this function doesn't get all surrounding whitespace, just the whitespace in the current text node.
388                                                              isStartOfParagraph(visibleUpstreamPos) || upstream == 0, 
389                                                              isEndOfParagraph(visibleDownstreamPos) || (unsigned)downstream == text.length() - 1);
390     
391     if (string != rebalancedString)
392         replaceTextInNode(textNode, upstream, length, rebalancedString);
393 }
394
395 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& position)
396 {
397     Node* node = position.node();
398     if (!node || !node->isTextNode())
399         return;
400     Text* textNode = static_cast<Text*>(node);    
401     
402     if (textNode->length() == 0)
403         return;
404     RenderObject* renderer = textNode->renderer();
405     if (renderer && !renderer->style()->collapseWhiteSpace())
406         return;
407
408     // Delete collapsed whitespace so that inserting nbsps doesn't uncollapse it.
409     Position upstreamPos = position.upstream();
410     deleteInsignificantText(position.upstream(), position.downstream());
411     position = upstreamPos.downstream();
412
413     VisiblePosition visiblePos(position);
414     VisiblePosition previousVisiblePos(visiblePos.next());
415     Position previous(previousVisiblePos.deepEquivalent());
416     
417     if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous.node()->isTextNode() && !previous.node()->hasTagName(brTag))
418         replaceTextInNode(static_cast<Text*>(previous.node()), previous.offset(), 1, nonBreakingSpaceString());
419     if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.node()->isTextNode() && !position.node()->hasTagName(brTag))
420         replaceTextInNode(static_cast<Text*>(position.node()), position.offset(), 1, nonBreakingSpaceString());
421 }
422
423 void CompositeEditCommand::rebalanceWhitespace()
424 {
425     Selection selection = endingSelection();
426     if (selection.isNone())
427         return;
428         
429     rebalanceWhitespaceAt(selection.start());
430     if (selection.isRange())
431         rebalanceWhitespaceAt(selection.end());
432 }
433
434 void CompositeEditCommand::deleteInsignificantText(Text* textNode, int start, int end)
435 {
436     if (!textNode || !textNode->renderer() || start >= end)
437         return;
438
439     RenderText* textRenderer = static_cast<RenderText*>(textNode->renderer());
440     InlineTextBox* box = textRenderer->firstTextBox();
441     if (!box) {
442         // whole text node is empty
443         removeNode(textNode);
444         return;    
445     }
446     
447     int length = textNode->length();
448     if (start >= length || end > length)
449         return;
450
451     int removed = 0;
452     InlineTextBox* prevBox = 0;
453     RefPtr<StringImpl> str;
454
455     // This loop structure works to process all gaps preceding a box,
456     // and also will look at the gap after the last box.
457     while (prevBox || box) {
458         int gapStart = prevBox ? prevBox->m_start + prevBox->m_len : 0;
459         if (end < gapStart)
460             // No more chance for any intersections
461             break;
462
463         int gapEnd = box ? box->m_start : length;
464         bool indicesIntersect = start <= gapEnd && end >= gapStart;
465         int gapLen = gapEnd - gapStart;
466         if (indicesIntersect && gapLen > 0) {
467             gapStart = max(gapStart, start);
468             gapEnd = min(gapEnd, end);
469             if (!str)
470                 str = textNode->string()->substring(start, end - start);
471             // remove text in the gap
472             str->remove(gapStart - start - removed, gapLen);
473             removed += gapLen;
474         }
475         
476         prevBox = box;
477         if (box)
478             box = box->nextTextBox();
479     }
480
481     if (str) {
482         // Replace the text between start and end with our pruned version.
483         if (str->length() > 0) {
484             replaceTextInNode(textNode, start, end - start, str.get());
485         } else {
486             // Assert that we are not going to delete all of the text in the node.
487             // If we were, that should have been done above with the call to 
488             // removeNode and return.
489             ASSERT(start > 0 || (unsigned)end - start < textNode->length());
490             deleteTextFromNode(textNode, start, end - start);
491         }
492     }
493 }
494
495 void CompositeEditCommand::deleteInsignificantText(const Position& start, const Position& end)
496 {
497     if (start.isNull() || end.isNull())
498         return;
499
500     if (Range::compareBoundaryPoints(start, end) >= 0)
501         return;
502
503     Node* next;
504     for (Node* node = start.node(); node; node = next) {
505         next = node->traverseNextNode();
506         if (node->isTextNode()) {
507             Text* textNode = static_cast<Text*>(node);
508             int startOffset = node == start.node() ? start.offset() : 0;
509             int endOffset = node == end.node() ? end.offset() : textNode->length();
510             deleteInsignificantText(textNode, startOffset, endOffset);
511         }
512         if (node == end.node())
513             break;
514     }
515 }
516
517 void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos)
518 {
519     Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivalent().downstream();
520     deleteInsignificantText(pos, end);
521 }
522
523 Node* CompositeEditCommand::appendBlockPlaceholder(Node* node)
524 {
525     if (!node)
526         return 0;
527     
528     // Should assert isBlockFlow || isInlineFlow when deletion improves.  See 4244964.
529     ASSERT(node->renderer());
530
531     RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
532     appendNode(placeholder.get(), node);
533     return placeholder.get();
534 }
535
536 Node* CompositeEditCommand::insertBlockPlaceholder(const Position& pos)
537 {
538     if (pos.isNull())
539         return 0;
540
541     // Should assert isBlockFlow || isInlineFlow when deletion improves.  See 4244964.
542     ASSERT(pos.node()->renderer());
543
544     RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
545     insertNodeAt(placeholder.get(), pos);
546     return placeholder.get();
547 }
548
549 Node* CompositeEditCommand::addBlockPlaceholderIfNeeded(Node* node)
550 {
551     if (!node)
552         return 0;
553
554     updateLayout();
555
556     RenderObject *renderer = node->renderer();
557     if (!renderer || !renderer->isBlockFlow())
558         return 0;
559     
560     // append the placeholder to make sure it follows
561     // any unrendered blocks
562     if (renderer->height() == 0 || (renderer->isListItem() && renderer->isEmpty()))
563         return appendBlockPlaceholder(node);
564
565     return 0;
566 }
567
568 // Removes '\n's and brs that will collapse when content is inserted just before them.
569 // FIXME: We shouldn't really have to remove placeholders, but removing them is a workaround for 9661.
570 void CompositeEditCommand::removePlaceholderAt(const VisiblePosition& visiblePosition)
571 {
572     if (visiblePosition.isNull())
573         return;
574         
575     Position p = visiblePosition.deepEquivalent().downstream();
576     // If a br or '\n' is at the end of a block and not at the start of a paragraph,
577     // then it is superfluous, so adding content before a br or '\n' that is at
578     // the start of a paragraph will render it superfluous.
579     // FIXME: This doesn't remove placeholders at the end of anonymous blocks.
580     if (isEndOfBlock(visiblePosition) && isStartOfParagraph(visiblePosition)) {
581         if (p.node()->hasTagName(brTag) && p.offset() == 0)
582             removeNode(p.node());
583         else if (lineBreakExistsAtPosition(visiblePosition))
584             deleteTextFromNode(static_cast<Text*>(p.node()), p.offset(), 1);
585     }
586 }
587
588 Node* CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary(const Position& pos)
589 {
590     if (pos.isNull())
591         return 0;
592     
593     updateLayout();
594     
595     VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
596     VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos));
597     VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos);
598     VisiblePosition next = visibleParagraphEnd.next();
599     VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd;
600     
601     Position paragraphStart = visibleParagraphStart.deepEquivalent().upstream();
602     Position end = visibleEnd.deepEquivalent().upstream();
603
604     // If there are no VisiblePositions in the same block as pos then 
605     // paragraphStart will be outside the paragraph
606     if (Range::compareBoundaryPoints(pos, paragraphStart) < 0)
607         return 0;
608
609     // Perform some checks to see if we need to perform work in this function.
610     if (isBlock(paragraphStart.node())) {
611         if (isBlock(end.node())) {
612             if (!end.node()->isDescendantOf(paragraphStart.node())) {
613                 // If the paragraph end is a descendant of paragraph start, then we need to run
614                 // the rest of this function. If not, we can bail here.
615                 return 0;
616             }
617         }
618         else if (enclosingBlock(end.node()) != paragraphStart.node()) {
619             // The visibleEnd.  It must be an ancestor of the paragraph start.
620             // We can bail as we have a full block to work with.
621             ASSERT(paragraphStart.node()->isDescendantOf(enclosingBlock(end.node())));
622             return 0;
623         }
624         else if (isEndOfDocument(visibleEnd)) {
625             // At the end of the document. We can bail here as well.
626             return 0;
627         }
628     }
629
630     RefPtr<Node> newBlock = createDefaultParagraphElement(document());
631     appendNode(createBreakElement(document()).get(), newBlock.get());
632     insertNodeAt(newBlock.get(), paragraphStart);
633     
634     moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(Position(newBlock.get(), 0)));
635     
636     return newBlock.get();
637 }
638
639 void CompositeEditCommand::pushAnchorElementDown(Node* anchorNode)
640 {
641     if (!anchorNode)
642         return;
643     
644     ASSERT(anchorNode->isLink());
645     
646     setEndingSelection(Selection::selectionFromContentsOfNode(anchorNode));
647     applyStyledElement(static_cast<Element*>(anchorNode));
648     // Clones of anchorNode have been pushed down, now remove it.
649     if (anchorNode->inDocument())
650         removeNodePreservingChildren(anchorNode);
651 }
652
653 // We must push partially selected anchors down before creating or removing
654 // links from a selection to create fully selected chunks that can be removed.
655 // ApplyStyleCommand doesn't do this for us because styles can be nested.
656 // Anchors cannot be nested.
657 void CompositeEditCommand::pushPartiallySelectedAnchorElementsDown()
658 {
659     Selection originalSelection = endingSelection();
660     VisiblePosition visibleStart(originalSelection.start());
661     VisiblePosition visibleEnd(originalSelection.end());
662     
663     Node* startAnchor = enclosingAnchorElement(originalSelection.start());
664     VisiblePosition startOfStartAnchor(Position(startAnchor, 0));
665     if (startAnchor && startOfStartAnchor != visibleStart)
666         pushAnchorElementDown(startAnchor);
667
668     Node* endAnchor = enclosingAnchorElement(originalSelection.end());
669     VisiblePosition endOfEndAnchor(Position(endAnchor, 0));
670     if (endAnchor && endOfEndAnchor != visibleEnd)
671         pushAnchorElementDown(endAnchor);
672
673     ASSERT(originalSelection.start().node()->inDocument() && originalSelection.end().node()->inDocument());
674     setEndingSelection(originalSelection);
675 }
676
677 // This moves a paragraph preserving its style.
678 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
679 {
680     ASSERT(isStartOfParagraph(startOfParagraphToMove));
681     ASSERT(isEndOfParagraph(endOfParagraphToMove));
682     moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, preserveSelection, preserveStyle);
683 }
684
685 void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
686 {
687     if (startOfParagraphToMove == destination)
688         return;
689     
690     int startIndex = -1;
691     int endIndex = -1;
692     int destinationIndex = -1;
693     if (preserveSelection && !endingSelection().isNone()) {
694         VisiblePosition visibleStart = endingSelection().visibleStart();
695         VisiblePosition visibleEnd = endingSelection().visibleEnd();
696         
697         bool startAfterParagraph = Range::compareBoundaryPoints(visibleStart.deepEquivalent(), endOfParagraphToMove.deepEquivalent()) > 0;
698         bool endBeforeParagraph = Range::compareBoundaryPoints(visibleEnd.deepEquivalent(), startOfParagraphToMove.deepEquivalent()) < 0;
699         
700         if (!startAfterParagraph && !endBeforeParagraph) {
701             bool startInParagraph = Range::compareBoundaryPoints(visibleStart.deepEquivalent(), startOfParagraphToMove.deepEquivalent()) >= 0;
702             bool endInParagraph = Range::compareBoundaryPoints(visibleEnd.deepEquivalent(), endOfParagraphToMove.deepEquivalent()) <= 0;
703             
704             startIndex = 0;
705             if (startInParagraph) {
706                 RefPtr<Range> startRange = new Range(document(), startOfParagraphToMove.deepEquivalent(), visibleStart.deepEquivalent());
707                 startIndex = TextIterator::rangeLength(startRange.get(), true);
708             }
709
710             endIndex = 0;
711             if (endInParagraph) {
712                 RefPtr<Range> endRange = new Range(document(), startOfParagraphToMove.deepEquivalent(), visibleEnd.deepEquivalent());
713                 endIndex = TextIterator::rangeLength(endRange.get(), true);
714             }
715         }
716     }
717     
718     VisiblePosition beforeParagraph = startOfParagraphToMove.previous();
719     VisiblePosition afterParagraph(endOfParagraphToMove.next());
720
721     // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
722     // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.    
723     Position start = startOfParagraphToMove.deepEquivalent().downstream();
724     Position end = endOfParagraphToMove.deepEquivalent().upstream();
725     
726     // start and end can't be used directly to create a Range; they are "editing positions"
727     Position startRangeCompliant = rangeCompliantEquivalent(start);
728     Position endRangeCompliant = rangeCompliantEquivalent(end);
729     RefPtr<Range> range = new Range(document(), startRangeCompliant.node(), startRangeCompliant.offset(), endRangeCompliant.node(), endRangeCompliant.offset());
730
731     // FIXME: This is an inefficient way to preserve style on nodes in the paragraph to move.  It 
732     // shouldn't matter though, since moved paragraphs will usually be quite small.
733     RefPtr<DocumentFragment> fragment = startOfParagraphToMove != endOfParagraphToMove ? createFragmentFromMarkup(document(), createMarkup(range.get(), 0, DoNotAnnotateForInterchange, true), "") : 0;
734     
735     // FIXME (5098931): We should add a new insert action "WebViewInsertActionMoved" and call shouldInsertFragment here.
736     
737     setEndingSelection(Selection(start, end, DOWNSTREAM));
738     deleteSelection(false, false, false, false);
739
740     ASSERT(destination.deepEquivalent().node()->inDocument());
741     
742     // There are bugs in deletion when it removes a fully selected table/list.  
743     // It expands and removes the entire table/list, but will let content
744     // before and after the table/list collapse onto one line.
745     
746     // Deleting a paragraph will leave a placeholder.  Remove it (and prune
747     // empty or unrendered parents).
748     VisiblePosition caretAfterDelete = endingSelection().visibleStart();
749     if (isStartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) {
750         // Note: We want the rightmost candidate.
751         Position position = caretAfterDelete.deepEquivalent().downstream();
752         Node* node = position.node();
753         // Normally deletion will leave a br as a placeholder.
754         if (node->hasTagName(brTag))
755             removeNodeAndPruneAncestors(node);
756         // If the selection to move was empty and in an empty block that 
757         // doesn't require a placeholder to prop itself open (like a bordered 
758         // div or an li), remove it during the move (the list removal code 
759         // expects this behavior).
760         else if (isBlock(node))
761             removeNodeAndPruneAncestors(node);
762         else if (lineBreakExistsAtPosition(caretAfterDelete))
763             deleteTextFromNode(static_cast<Text*>(node), position.offset(), 1);
764     }
765
766     // Add a br if pruning an empty block level element caused a collapse.  For example:
767     // foo^
768     // <div>bar</div>
769     // baz
770     // Imagine moving 'bar' to ^.  'bar' will be deleted and its div pruned.  That would
771     // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br.
772     // Must recononicalize these two VisiblePositions after the pruning above.
773     beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
774     afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
775     if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || beforeParagraph == afterParagraph)) {
776         // FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.
777         insertNodeAt(createBreakElement(document()).get(), beforeParagraph.deepEquivalent());
778         // Need an updateLayout here in case inserting the br has split a text node.
779         updateLayout();
780     }
781         
782     RefPtr<Range> startToDestinationRange(new Range(document(), Position(document(), 0), rangeCompliantEquivalent(destination.deepEquivalent())));
783     destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(), true);
784     
785     setEndingSelection(destination);
786     applyCommandToComposite(new ReplaceSelectionCommand(document(), fragment.get(), true, false, !preserveStyle, false));
787     
788     if (preserveSelection && startIndex != -1) {
789         // Fragment creation (using createMarkup) incorrectly uses regular
790         // spaces instead of nbsps for some spaces that were rendered (11475), which
791         // causes spaces to be collapsed during the move operation.  This results
792         // in a call to rangeFromLocationAndLength with a location past the end
793         // of the document (which will return null).
794         RefPtr<Range> start = TextIterator::rangeFromLocationAndLength(document()->documentElement(), destinationIndex + startIndex, 0, true);
795         RefPtr<Range> end = TextIterator::rangeFromLocationAndLength(document()->documentElement(), destinationIndex + endIndex, 0, true);
796         if (start && end)
797             setEndingSelection(Selection(start->startPosition(), end->startPosition(), DOWNSTREAM));
798     }
799 }
800
801 // FIXME: Send an appropriate shouldDeleteRange call.
802 bool CompositeEditCommand::breakOutOfEmptyListItem()
803 {
804     Node* emptyListItem = enclosingEmptyListItem(endingSelection().visibleStart());
805     if (!emptyListItem)
806         return false;
807         
808     RefPtr<CSSMutableStyleDeclaration> style = styleAtPosition(endingSelection().start());
809
810     Node* listNode = emptyListItem->parentNode();
811     RefPtr<Node> newBlock = isListElement(listNode->parentNode()) ? createListItemElement(document()) : createDefaultParagraphElement(document());
812     
813     if (emptyListItem->renderer()->nextSibling()) {
814         if (emptyListItem->renderer()->previousSibling())
815             splitElement(static_cast<Element*>(listNode), emptyListItem);
816         insertNodeBefore(newBlock.get(), listNode);
817         removeNode(emptyListItem);
818     } else {
819         insertNodeAfter(newBlock.get(), listNode);
820         removeNode(emptyListItem->renderer()->previousSibling() ? emptyListItem : listNode);
821     }
822     
823     appendBlockPlaceholder(newBlock.get());
824     setEndingSelection(Selection(Position(newBlock.get(), 0), DOWNSTREAM));
825     
826     CSSComputedStyleDeclaration endingStyle(endingSelection().start().node());
827     endingStyle.diff(style.get());
828     if (style->length() > 0)
829         applyStyle(style.get());
830     
831     return true;
832 }
833
834 // Operations use this function to avoid inserting content into an anchor when at the start or the end of 
835 // that anchor, as in NSTextView.
836 // FIXME: This is only an approximation of NSTextViews insertion behavior, which varies depending on how
837 // the caret was made. 
838 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Position& p, bool alwaysAvoidAnchors)
839 {
840     if (p.isNull())
841         return p;
842         
843     VisiblePosition visiblePos(p);
844     Node* enclosingAnchor = enclosingAnchorElement(p);
845     Position result = p;
846     // Don't avoid block level anchors, because that would insert content into the wrong paragraph.
847     if (enclosingAnchor && !isBlock(enclosingAnchor)) {
848         VisiblePosition firstInAnchor(Position(enclosingAnchor, 0));
849         VisiblePosition lastInAnchor(Position(enclosingAnchor, maxDeepOffset(enclosingAnchor)));
850         // If visually just after the anchor, insert *inside* the anchor unless it's the last 
851         // VisiblePosition in the document, to match NSTextView.
852         if (visiblePos == lastInAnchor && (isEndOfDocument(visiblePos) || alwaysAvoidAnchors)) {
853             // Make sure anchors are pushed down before avoiding them so that we don't
854             // also avoid structural elements like lists and blocks (5142012).
855             if (Node* anchor = enclosingAnchorElement(p))
856                 if (p.node() != anchor && p.node()->parentNode() != anchor) {
857                     pushAnchorElementDown(anchor);
858                     enclosingAnchor = enclosingAnchorElement(p);
859                 }
860             result = positionAfterNode(enclosingAnchor);
861         }
862         // If visually just before an anchor, insert *outside* the anchor unless it's the first
863         // VisiblePosition in a paragraph, to match NSTextView.
864         if (visiblePos == firstInAnchor && (!isStartOfParagraph(visiblePos) || alwaysAvoidAnchors)) {
865             // Make sure anchors are pushed down before avoiding them so that we don't
866             // also avoid structural elements like lists and blocks (5142012).
867             if (Node* anchor = enclosingAnchorElement(p))
868                 if (p.node() != anchor && p.node()->parentNode() != anchor) {
869                     pushAnchorElementDown(anchor);
870                     enclosingAnchor = enclosingAnchorElement(p);
871                 }
872             result = positionBeforeNode(enclosingAnchor);
873         }
874     }
875         
876     if (result.isNull() || !editableRootForPosition(result))
877         result = p;
878     
879     return result;
880 }
881
882 PassRefPtr<Element> createBlockPlaceholderElement(Document* document)
883 {
884     ExceptionCode ec = 0;
885     RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "br", ec);
886     ASSERT(ec == 0);
887     static String classString = "webkit-block-placeholder";
888     breakNode->setAttribute(classAttr, classString);
889     return breakNode.release();
890 }
891
892 } // namespace WebCore