18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Element.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "InsertListCommand.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "DocumentFragment.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "htmlediting.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLElement.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLNames.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "TextIterator.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "visible_units.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace HTMLNames;
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
40e8b154fd68f9b33be40a3590e58347f353835f5cSteve Blockstatic Node* enclosingListChild(Node* node, Node* listNode)
41e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{
42e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    Node* listChild = enclosingListChild(node);
43e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    while (listChild && enclosingList(listChild) != listNode)
44e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        listChild = enclosingListChild(listChild->parentNode());
45e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    return listChild;
46e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block}
47e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
48635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectPassRefPtr<HTMLElement> InsertListCommand::insertList(Document* document, Type type)
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    RefPtr<InsertListCommand> insertCommand = create(document, type);
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    insertCommand->apply();
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return insertCommand->m_listElement;
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
55635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHTMLElement* InsertListCommand::fixOrphanedListChild(Node* node)
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
57635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    RefPtr<HTMLElement> listElement = createUnorderedListElement(document());
58635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    insertNodeBefore(listElement, node);
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    removeNode(node);
60635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    appendNode(node, listElement);
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_listElement = listElement;
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return listElement.get();
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
65db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve BlockPassRefPtr<HTMLElement> InsertListCommand::mergeWithNeighboringLists(PassRefPtr<HTMLElement> passedList)
66db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block{
67db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    RefPtr<HTMLElement> list = passedList;
68db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    Element* previousList = list->previousElementSibling();
69db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (canMergeLists(previousList, list.get()))
70db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        mergeIdenticalElements(previousList, list);
71db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
72db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (!list || !list->nextElementSibling() || !list->nextElementSibling()->isHTMLElement())
73db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        return list.release();
74db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    RefPtr<HTMLElement> nextList = toHTMLElement(list->nextElementSibling());
76db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (canMergeLists(list.get(), nextList.get())) {
77db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        mergeIdenticalElements(list, nextList);
78db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        return nextList.release();
79db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    }
80db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    return list.release();
81db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block}
82db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
83db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockbool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection, const QualifiedName& listTag)
84db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block{
85db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    VisiblePosition start = selection.visibleStart();
86db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
8781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!enclosingList(start.deepEquivalent().deprecatedNode()))
88db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        return false;
89db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
90db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    VisiblePosition end = selection.visibleEnd();
91db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    while (start.isNotNull() && start != end) {
9281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        Element* listNode = enclosingList(start.deepEquivalent().deprecatedNode());
93db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        if (!listNode || !listNode->hasTagName(listTag))
94db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            return false;
95db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        start = startOfNextParagraph(start);
96db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    }
97db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
98db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    return true;
99db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block}
100db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
1018f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng QianInsertListCommand::InsertListCommand(Document* document, Type type)
102967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    : CompositeEditCommand(document), m_type(type)
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid InsertListCommand::doApply()
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
108e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!endingSelection().isNonOrphanedCaretOrRange())
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
110e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!endingSelection().rootEditableElement())
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition visibleEnd = endingSelection().visibleEnd();
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition visibleStart = endingSelection().visibleStart();
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // When a selection ends at the start of a paragraph, we rarely paint
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // the selection gap before that paragraph, because there often is no gap.
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // In a case like this, it's not obvious to the user that the selection
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // ends "inside" that paragraph, so it would be confusing if InsertUn{Ordered}List
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // operated on that paragraph.
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: We paint the gap before some paragraphs that are indented with left
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // margin/padding, but not others.  We should make the gap painting more consistent and
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // then use a left margin/padding rule here.
1242bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd, CanSkipOverEditingBoundary))
1252bde8e466a4451c7319e3a072d118917957d6554Steve Block        setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(CannotCrossEditingBoundary)));
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
127db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    const QualifiedName& listTag = (m_type == OrderedList) ? olTag : ulTag;
128967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (endingSelection().isRange()) {
129967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        VisibleSelection selection = selectionForParagraphIteration(endingSelection());
130967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        ASSERT(selection.isRange());
131967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        VisiblePosition startOfSelection = selection.visibleStart();
132967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        VisiblePosition endOfSelection = selection.visibleEnd();
1332bde8e466a4451c7319e3a072d118917957d6554Steve Block        VisiblePosition startOfLastParagraph = startOfParagraph(endOfSelection, CanSkipOverEditingBoundary);
134967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
1352bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (startOfParagraph(startOfSelection, CanSkipOverEditingBoundary) != startOfLastParagraph) {
136db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            bool forceCreateList = !selectionHasListOfType(selection, listTag);
137967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
138db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            RefPtr<Range> currentSelection = endingSelection().firstRange();
139967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            VisiblePosition startOfCurrentParagraph = startOfSelection;
1402bde8e466a4451c7319e3a072d118917957d6554Steve Block            while (!inSameParagraph(startOfCurrentParagraph, startOfLastParagraph, CanCrossEditingBoundary)) {
141967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                // doApply() may operate on and remove the last paragraph of the selection from the document
142967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                // if it's in the same list item as startOfCurrentParagraph.  Return early to avoid an
143967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                // infinite loop and because there is no more work to be done.
144967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                // FIXME(<rdar://problem/5983974>): The endingSelection() may be incorrect here.  Compute
145967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                // the new location of endOfSelection and use it as the end of the new selection.
14681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                if (!startOfLastParagraph.deepEquivalent().anchorNode()->inDocument())
147967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                    return;
148967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                setEndingSelection(startOfCurrentParagraph);
149e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
150e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                // Save and restore endOfSelection and startOfLastParagraph when necessary
151e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                // since moveParagraph and movePragraphWithClones can remove nodes.
152e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                // FIXME: This is an inefficient way to keep selection alive because indexForVisiblePosition walks from
153e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                // the beginning of the document to the endOfSelection everytime this code is executed.
154e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                // But not using index is hard because there are so many ways we can lose selection inside doApplyForSingleParagraph.
155e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                int indexForEndOfSelection = indexForVisiblePosition(endOfSelection);
156db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block                doApplyForSingleParagraph(forceCreateList, listTag, currentSelection.get());
157e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                if (endOfSelection.isNull() || endOfSelection.isOrphan() || startOfLastParagraph.isNull() || startOfLastParagraph.isOrphan()) {
158e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                    RefPtr<Range> lastSelectionRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), indexForEndOfSelection, 0, true);
1594a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch                    // If lastSelectionRange is null, then some contents have been deleted from the document.
1604a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch                    // This should never happen and if it did, exit early immediately because we've lost the loop invariant.
1614a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch                    ASSERT(lastSelectionRange);
1624a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch                    if (!lastSelectionRange)
1634a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch                        return;
164e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                    endOfSelection = lastSelectionRange->startPosition();
1652bde8e466a4451c7319e3a072d118917957d6554Steve Block                    startOfLastParagraph = startOfParagraph(endOfSelection, CanSkipOverEditingBoundary);
166e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                }
167967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
168967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                // Fetch the start of the selection after moving the first paragraph,
169967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                // because moving the paragraph will invalidate the original start.
170967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                // We'll use the new start to restore the original selection after
171967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                // we modified all selected paragraphs.
172967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                if (startOfCurrentParagraph == startOfSelection)
173967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                    startOfSelection = endingSelection().visibleStart();
174967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
175967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch                startOfCurrentParagraph = startOfNextParagraph(endingSelection().visibleStart());
176967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            }
177967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            setEndingSelection(endOfSelection);
178db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            doApplyForSingleParagraph(forceCreateList, listTag, currentSelection.get());
179967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            // Fetch the end of the selection, for the reason mentioned above.
180967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            endOfSelection = endingSelection().visibleEnd();
181967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            setEndingSelection(VisibleSelection(startOfSelection, endOfSelection));
182967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch            return;
183967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        }
184967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    }
185967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
186db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    doApplyForSingleParagraph(false, listTag, endingSelection().firstRange().get());
187967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
188967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
189db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockvoid InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const QualifiedName& listTag, Range* currentSelection)
190967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: This will produce unexpected results for a selection that starts just before a
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // table and ends inside the first cell, selectionForParagraphIteration should probably
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // be renamed and deployed inside setEndingSelection().
19481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    Node* selectionNode = endingSelection().start().deprecatedNode();
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* listChildNode = enclosingListChild(selectionNode);
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool switchListType = false;
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (listChildNode) {
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Remove the list chlild.
199db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        RefPtr<HTMLElement> listNode = enclosingList(listChildNode);
200db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        if (!listNode) {
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            listNode = fixOrphanedListChild(listChildNode);
202db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            listNode = mergeWithNeighboringLists(listNode);
203db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        }
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!listNode->hasTagName(listTag))
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // listChildNode will be removed from the list and a list of type m_type will be created.
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            switchListType = true;
207545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
208db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        // If the list is of the desired type, and we are not removing the list, then exit early.
209db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        if (!switchListType && forceCreateList)
210db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            return;
211db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
212db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        // If the entire list is selected, then convert the whole list.
213db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        if (switchListType && isNodeVisiblyContainedWithin(listNode.get(), currentSelection)) {
214e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            bool rangeStartIsInList = visiblePositionBeforeNode(listNode.get()) == currentSelection->startPosition();
215e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            bool rangeEndIsInList = visiblePositionAfterNode(listNode.get()) == currentSelection->endPosition();
216e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
217db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            RefPtr<HTMLElement> newList = createHTMLElement(document(), listTag);
218db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            insertNodeBefore(newList, listNode);
219e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
22081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            Node* firstChildInList = enclosingListChild(VisiblePosition(firstPositionInNode(listNode.get())).deepEquivalent().deprecatedNode(), listNode.get());
221e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            Node* outerBlock = firstChildInList->isBlockFlow() ? firstChildInList : listNode.get();
222e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
223db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            moveParagraphWithClones(firstPositionInNode(listNode.get()), lastPositionInNode(listNode.get()), newList.get(), outerBlock);
224e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
225e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            // Manually remove listNode because moveParagraphWithClones sometimes leaves it behind in the document.
226e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            // See the bug 33668 and editing/execCommand/insert-list-orphaned-item-with-nested-lists.html.
227e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            // FIXME: This might be a bug in moveParagraphWithClones or deleteSelection.
228e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            if (listNode && listNode->inDocument())
229e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                removeNode(listNode);
230e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
231db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            newList = mergeWithNeighboringLists(newList);
232e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
233e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            // Restore the start and the end of current selection if they started inside listNode
234e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            // because moveParagraphWithClones could have removed them.
235e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            ExceptionCode ec;
236e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            if (rangeStartIsInList && newList)
237e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                currentSelection->setStart(newList, 0, ec);
238e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            if (rangeEndIsInList && newList)
239e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                currentSelection->setEnd(newList, lastOffsetInNode(newList.get()), ec);
240e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
241db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            setEndingSelection(VisiblePosition(firstPositionInNode(newList.get())));
242e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
243db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block            return;
244db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        }
245db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
246db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        unlistifyParagraph(endingSelection().visibleStart(), listNode.get(), listChildNode);
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
249967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (!listChildNode || switchListType || forceCreateList)
250545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        m_listElement = listifyParagraph(endingSelection().visibleStart(), listTag);
251545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch}
252545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
253545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochvoid InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart, HTMLElement* listNode, Node* listChildNode)
254545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch{
255545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    Node* nextListChild;
256545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    Node* previousListChild;
257545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    VisiblePosition start;
258545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    VisiblePosition end;
259545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    if (listChildNode->hasTagName(liTag)) {
2602bde8e466a4451c7319e3a072d118917957d6554Steve Block        start = firstPositionInNode(listChildNode);
2612bde8e466a4451c7319e3a072d118917957d6554Steve Block        end = lastPositionInNode(listChildNode);
262545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        nextListChild = listChildNode->nextSibling();
263545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        previousListChild = listChildNode->previousSibling();
264545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    } else {
265545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // A paragraph is visually a list item minus a list marker.  The paragraph will be moved.
2662bde8e466a4451c7319e3a072d118917957d6554Steve Block        start = startOfParagraph(originalStart, CanSkipOverEditingBoundary);
2672bde8e466a4451c7319e3a072d118917957d6554Steve Block        end = endOfParagraph(start, CanSkipOverEditingBoundary);
26881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        nextListChild = enclosingListChild(end.next().deepEquivalent().deprecatedNode(), listNode);
269545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        ASSERT(nextListChild != listChildNode);
27081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        previousListChild = enclosingListChild(start.previous().deepEquivalent().deprecatedNode(), listNode);
271545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        ASSERT(previousListChild != listChildNode);
272545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    }
273545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    // When removing a list, we must always create a placeholder to act as a point of insertion
274545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    // for the list content being removed.
275545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    RefPtr<Element> placeholder = createBreakElement(document());
276545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    RefPtr<Element> nodeToInsert = placeholder;
277545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    // If the content of the list item will be moved into another list, put it in a list item
278545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    // so that we don't create an orphaned list child.
279545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    if (enclosingList(listNode)) {
280545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        nodeToInsert = createListItemElement(document());
281545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        appendNode(placeholder, nodeToInsert);
282545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    }
283545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
284545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    if (nextListChild && previousListChild) {
285545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // We want to pull listChildNode out of listNode, and place it before nextListChild
286545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // and after previousListChild, so we split listNode and insert it between the two lists.
287545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // But to split listNode, we must first split ancestors of listChildNode between it and listNode,
288545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // if any exist.
289545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // FIXME: We appear to split at nextListChild as opposed to listChildNode so that when we remove
290545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // listChildNode below in moveParagraphs, previousListChild will be removed along with it if it is
291545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // unrendered. But we ought to remove nextListChild too, if it is unrendered.
292545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        splitElement(listNode, splitTreeToNode(nextListChild, listNode));
293545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        insertNodeBefore(nodeToInsert, listNode);
294545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    } else if (nextListChild || listChildNode->parentNode() != listNode) {
295545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // Just because listChildNode has no previousListChild doesn't mean there isn't any content
296545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // in listNode that comes before listChildNode, as listChildNode could have ancestors
297545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // between it and listNode. So, we split up to listNode before inserting the placeholder
298545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // where we're about to move listChildNode to.
299545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        if (listChildNode->parentNode() != listNode)
300545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            splitElement(listNode, splitTreeToNode(listChildNode, listNode).get());
301545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        insertNodeBefore(nodeToInsert, listNode);
302545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    } else
303545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        insertNodeAfter(nodeToInsert, listNode);
304545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
305ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    VisiblePosition insertionPoint = VisiblePosition(positionBeforeNode(placeholder.get()));
306545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    moveParagraphs(start, end, insertionPoint, true);
307545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch}
3085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
3090617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsenstatic Element* adjacentEnclosingList(const VisiblePosition& pos, const VisiblePosition& adjacentPos, const QualifiedName& listTag)
3100617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen{
31181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    Element* listNode = outermostEnclosingList(adjacentPos.deepEquivalent().deprecatedNode());
3120617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
3130617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (!listNode)
3140617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        return 0;
3150617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
3160617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    Node* previousCell = enclosingTableCell(pos.deepEquivalent());
3170617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    Node* currentCell = enclosingTableCell(adjacentPos.deepEquivalent());
3180617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
3190617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (!listNode->hasTagName(listTag)
32081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        || listNode->contains(pos.deepEquivalent().deprecatedNode())
321e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        || previousCell != currentCell
32281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        || enclosingList(listNode) != enclosingList(pos.deepEquivalent().deprecatedNode()))
3230617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen        return 0;
3240617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
3250617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    return listNode;
3260617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen}
3270617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
328545e470e52f0ac6a3a072bf559c796b42c6066b6Ben MurdochPassRefPtr<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePosition& originalStart, const QualifiedName& listTag)
329545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch{
3302bde8e466a4451c7319e3a072d118917957d6554Steve Block    VisiblePosition start = startOfParagraph(originalStart, CanSkipOverEditingBoundary);
3312bde8e466a4451c7319e3a072d118917957d6554Steve Block    VisiblePosition end = endOfParagraph(start, CanSkipOverEditingBoundary);
332e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
333e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (start.isNull() || end.isNull())
334e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return 0;
335545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
336545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    // Check for adjoining lists.
337545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    RefPtr<HTMLElement> listItemElement = createListItemElement(document());
338545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    RefPtr<HTMLElement> placeholder = createBreakElement(document());
339545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    appendNode(placeholder, listItemElement);
3400617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
341545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    // Place list item into adjoining lists.
3422bde8e466a4451c7319e3a072d118917957d6554Steve Block    Element* previousList = adjacentEnclosingList(start.deepEquivalent(), start.previous(CannotCrossEditingBoundary), listTag);
3432bde8e466a4451c7319e3a072d118917957d6554Steve Block    Element* nextList = adjacentEnclosingList(start.deepEquivalent(), end.next(CannotCrossEditingBoundary), listTag);
344545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    RefPtr<HTMLElement> listElement;
345545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    if (previousList)
346545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        appendNode(listItemElement, previousList);
347545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    else if (nextList)
348ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        insertNodeAt(listItemElement, positionBeforeNode(nextList));
349545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    else {
350545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // Create the list.
351545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        listElement = createHTMLElement(document(), listTag);
352545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        appendNode(listItemElement, listElement);
353545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
35481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (start == end && isBlock(start.deepEquivalent().deprecatedNode())) {
355545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            // Inserting the list into an empty paragraph that isn't held open
356545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            // by a br or a '\n', will invalidate start and end.  Insert
357545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            // a placeholder and then recompute start and end.
358545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            RefPtr<Node> placeholder = insertBlockPlaceholder(start.deepEquivalent());
359ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            start = positionBeforeNode(placeholder.get());
360545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            end = start;
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
362545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
363545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // Insert the list at a position visually equivalent to start of the
364545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // paragraph that is being moved into the list.
365545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // Try to avoid inserting it somewhere where it will be surrounded by
366545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // inline ancestors of start, since it is easier for editing to produce
367545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // clean markup when inline elements are pushed down as far as possible.
368545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        Position insertionPos(start.deepEquivalent().upstream());
369545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // Also avoid the containing list item.
37081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        Node* listChild = enclosingListChild(insertionPos.deprecatedNode());
371545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        if (listChild && listChild->hasTagName(liTag))
372545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            insertionPos = positionInParentBeforeNode(listChild);
373545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
374545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        insertNodeAt(listElement, insertionPos);
375545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
376545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // We inserted the list at the start of the content we're about to move
377545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        // Update the start of content, so we don't try to move the list into itself.  bug 19066
3782bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Layout is necessary since start's node's inline renderers may have been destroyed by the insertion
3792bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (insertionPos == start.deepEquivalent()) {
3802bde8e466a4451c7319e3a072d118917957d6554Steve Block            listElement->document()->updateLayoutIgnorePendingStylesheets();
3812bde8e466a4451c7319e3a072d118917957d6554Steve Block            start = startOfParagraph(originalStart, CanSkipOverEditingBoundary);
3822bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
384545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
385ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    moveParagraph(start, end, positionBeforeNode(placeholder.get()), true);
386545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
387db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (listElement)
388db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        return mergeWithNeighboringLists(listElement);
389db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block
390db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (canMergeLists(previousList, nextList))
391545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        mergeIdenticalElements(previousList, nextList);
392545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
393545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    return listElement;
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
397