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