18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2005 Apple Computer, 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 "DeleteSelectionCommand.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Document.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "DocumentFragment.h"
314576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang#include "EditingBoundary.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Editor.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "EditorClient.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Element.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Frame.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "htmlediting.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLInputElement.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLNames.h"
39635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "RenderTableCell.h"
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Text.h"
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "visible_units.h"
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace HTMLNames;
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic bool isTableRow(const Node* node)
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return node && node->hasTagName(trTag);
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic bool isTableCellEmpty(Node* cell)
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isTableCell(cell));
552bde8e466a4451c7319e3a072d118917957d6554Steve Block    return VisiblePosition(firstPositionInNode(cell)) == VisiblePosition(lastPositionInNode(cell));
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic bool isTableRowEmpty(Node* row)
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!isTableRow(row))
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (Node* child = row->firstChild(); child; child = child->nextSibling())
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isTableCell(child) && !isTableCellEmpty(child))
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectDeleteSelectionCommand::DeleteSelectionCommand(Document *document, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    : CompositeEditCommand(document),
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_hasSelectionToDelete(false),
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_smartDelete(smartDelete),
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
752bde8e466a4451c7319e3a072d118917957d6554Steve Block      m_needPlaceholder(false),
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_replace(replace),
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_expandForSpecialElements(expandForSpecialElements),
78635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project      m_pruneStartBlockIfNecessary(false),
795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian      m_startsAtEmptyLine(false),
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_startBlock(0),
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_endBlock(0),
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_typingStyle(0),
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_deleteIntoBlockquoteStyle(0)
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
878f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng QianDeleteSelectionCommand::DeleteSelectionCommand(const VisibleSelection& selection, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
8881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    : CompositeEditCommand(selection.start().anchorNode()->document()),
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_hasSelectionToDelete(true),
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_smartDelete(smartDelete),
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
922bde8e466a4451c7319e3a072d118917957d6554Steve Block      m_needPlaceholder(false),
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_replace(replace),
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_expandForSpecialElements(expandForSpecialElements),
95635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project      m_pruneStartBlockIfNecessary(false),
965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian      m_startsAtEmptyLine(false),
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_selectionToDelete(selection),
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_startBlock(0),
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_endBlock(0),
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_typingStyle(0),
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      m_deleteIntoBlockquoteStyle(0)
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::initializeStartEnd(Position& start, Position& end)
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* startSpecialContainer = 0;
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* endSpecialContainer = 0;
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    start = m_selectionToDelete.start();
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    end = m_selectionToDelete.end();
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // For HRs, we'll get a position at (HR,1) when hitting delete from the beginning of the previous line, or (HR,0) when forward deleting,
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // but in these cases, we want to delete it, so manually expand the selection
11581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (start.deprecatedNode()->hasTagName(hrTag))
11681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        start = positionBeforeNode(start.deprecatedNode());
11781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    else if (end.deprecatedNode()->hasTagName(hrTag))
11881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        end = positionAfterNode(end.deprecatedNode());
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
120d0825bca7fe65beaee391d30da42e937db621564Steve Block    // FIXME: This is only used so that moveParagraphs can avoid the bugs in special element expansion.
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_expandForSpecialElements)
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (1) {
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startSpecialContainer = 0;
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endSpecialContainer = 0;
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Position s = positionBeforeContainingSpecialElement(start, &startSpecialContainer);
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Position e = positionAfterContainingSpecialElement(end, &endSpecialContainer);
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!startSpecialContainer && !endSpecialContainer)
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (VisiblePosition(start) != m_selectionToDelete.visibleStart() || VisiblePosition(end) != m_selectionToDelete.visibleEnd())
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
1365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
137231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        // If we're going to expand to include the startSpecialContainer, it must be fully selected.
138231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (startSpecialContainer && !endSpecialContainer && comparePositions(positionInParentAfterNode(startSpecialContainer), end) > -1)
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // If we're going to expand to include the endSpecialContainer, it must be fully selected.
142231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (endSpecialContainer && !startSpecialContainer && comparePositions(start, positionInParentBeforeNode(endSpecialContainer)) > -1)
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
144231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (startSpecialContainer && startSpecialContainer->isDescendantOf(endSpecialContainer))
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Don't adjust the end yet, it is the end of a special element that contains the start
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // special element (which may or may not be fully selected).
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            start = s;
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else if (endSpecialContainer && endSpecialContainer->isDescendantOf(startSpecialContainer))
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Don't adjust the start yet, it is the start of a special element that contains the end
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // special element (which may or may not be fully selected).
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            end = e;
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else {
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            start = s;
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            end = e;
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
160dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid DeleteSelectionCommand::setStartingSelectionOnSmartDelete(const Position& start, const Position& end)
161dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
162dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    VisiblePosition newBase;
163dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    VisiblePosition newExtent;
164dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (startingSelection().isBaseFirst()) {
165dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        newBase = start;
166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        newExtent = end;
167dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    } else {
168dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        newBase = end;
169dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        newExtent = start;
170dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
171dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    setStartingSelection(VisibleSelection(newBase, newExtent));
172dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
173dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::initializePositionData()
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position start, end;
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    initializeStartEnd(start, end);
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_upstreamStart = start.upstream();
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_downstreamStart = start.downstream();
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_upstreamEnd = end.upstream();
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_downstreamEnd = end.downstream();
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_startRoot = editableRootForPosition(start);
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_endRoot = editableRootForPosition(end);
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_startTableRow = enclosingNodeOfType(start, &isTableRow);
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_endTableRow = enclosingNodeOfType(end, &isTableRow);
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Don't move content out of a table cell.
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If the cell is non-editable, enclosingNodeOfType won't return it by default, so
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // tell that function that we don't care if it returns non-editable nodes.
1932bde8e466a4451c7319e3a072d118917957d6554Steve Block    Node* startCell = enclosingNodeOfType(m_upstreamStart, &isTableCell, CanCrossEditingBoundary);
1942bde8e466a4451c7319e3a072d118917957d6554Steve Block    Node* endCell = enclosingNodeOfType(m_downstreamEnd, &isTableCell, CanCrossEditingBoundary);
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: This isn't right.  A borderless table with two rows and a single column would appear as two paragraphs.
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (endCell && endCell != startCell)
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_mergeBlocksAfterDelete = false;
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Usually the start and the end of the selection to delete are pulled together as a result of the deletion.
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Sometimes they aren't (like when no merge is requested), so we must choose one position to hold the caret
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // and receive the placeholder after deletion.
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition visibleEnd(m_downstreamEnd);
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_mergeBlocksAfterDelete && !isEndOfParagraph(visibleEnd))
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_endingPosition = m_downstreamEnd;
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_endingPosition = m_downstreamStart;
207635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
208635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We don't want to merge into a block if it will mean changing the quote level of content after deleting
209635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // selections that contain a whole number paragraphs plus a line break, since it is unclear to most users
210635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // that such a selection actually ends at the start of the next paragraph. This matches TextEdit behavior
211635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // for indented paragraphs.
2125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Only apply this rule if the endingSelection is a range selection.  If it is a caret, then other operations have created
2135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // the selection we're deleting (like the process of creating a selection to delete during a backspace), and the user isn't in the situation described above.
2145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end)
2155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            && isStartOfParagraph(visibleEnd) && isStartOfParagraph(VisiblePosition(start))
2165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            && endingSelection().isRange()) {
217635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_mergeBlocksAfterDelete = false;
218635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_pruneStartBlockIfNecessary = true;
219635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Handle leading and trailing whitespace, as well as smart delete adjustments to the selection
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition(m_selectionToDelete.affinity());
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY);
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_smartDelete) {
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // skip smart delete if the selection to delete already starts or ends with whitespace
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Position pos = VisiblePosition(m_upstreamStart, m_selectionToDelete.affinity()).deepEquivalent();
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        bool skipSmartDelete = pos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNotNull();
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!skipSmartDelete)
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            skipSmartDelete = m_downstreamEnd.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNotNull();
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // extend selection upstream if there is whitespace there
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        bool hasLeadingWhitespaceBeforeAdjustment = m_upstreamStart.leadingWhitespacePosition(m_selectionToDelete.affinity(), true).isNotNull();
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!skipSmartDelete && hasLeadingWhitespaceBeforeAdjustment) {
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            VisiblePosition visiblePos = VisiblePosition(m_upstreamStart, VP_DEFAULT_AFFINITY).previous();
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            pos = visiblePos.deepEquivalent();
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Expand out one character upstream for smart delete and recalculate
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // positions based on this change.
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_upstreamStart = pos.upstream();
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_downstreamStart = pos.downstream();
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition(visiblePos.affinity());
243dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
244dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            setStartingSelectionOnSmartDelete(m_upstreamStart, m_upstreamEnd);
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // trailing whitespace is only considered for smart delete if there is no leading
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // whitespace, as in the case where you double-click the first word of a paragraph.
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!skipSmartDelete && !hasLeadingWhitespaceBeforeAdjustment && m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNotNull()) {
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Expand out one character downstream for smart delete and recalculate
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // positions based on this change.
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            pos = VisiblePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY).next().deepEquivalent();
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_upstreamEnd = pos.upstream();
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_downstreamEnd = pos.downstream();
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY);
256dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
257dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            setStartingSelectionOnSmartDelete(m_downstreamStart, m_downstreamEnd);
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
261ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    // We must pass call parentAnchoredEquivalent on the positions since some editing positions
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // that appear inside their nodes aren't really inside them.  [hr, 0] is one example.
263ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    // FIXME: parentAnchoredEquivalent should eventually be moved into enclosing element getters
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // like the one below, since editing functions should obviously accept editing positions.
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Passing false to enclosingNodeOfType tells it that it's OK to return a non-editable
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // node.  This was done to match existing behavior, but it seems wrong.
2672bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_startBlock = enclosingNodeOfType(m_downstreamStart.parentAnchoredEquivalent(), &isBlock, CanCrossEditingBoundary);
2682bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_endBlock = enclosingNodeOfType(m_upstreamEnd.parentAnchoredEquivalent(), &isBlock, CanCrossEditingBoundary);
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::saveTypingStyleState()
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // A common case is deleting characters that are all from the same text node. In
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // that case, the style at the start of the selection before deletion will be the
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // same as the style at the start of the selection after deletion (since those
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // two positions will be identical). Therefore there is no need to save the
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // typing style at the start of the selection, nor is there a reason to
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // compute the style at the start of the selection after deletion (see the
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // early return in calculateTypingStyleAfterDelete).
28081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (m_upstreamStart.deprecatedNode() == m_downstreamEnd.deprecatedNode() && m_upstreamStart.deprecatedNode()->isTextNode())
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Figure out the typing style in effect before the delete is done.
2842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    m_typingStyle = EditingStyle::create(m_selectionToDelete.start());
28528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    m_typingStyle->removeStyleAddedByNode(enclosingAnchorElement(m_selectionToDelete.start()));
2860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If we're deleting into a Mail blockquote, save the style at end() instead of start()
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // We'll use this later in computeTypingStyleAfterDelete if we end up outside of a Mail blockquote
2892bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (enclosingNodeOfType(m_selectionToDelete.start(), isMailBlockquote))
29028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_deleteIntoBlockquoteStyle = EditingStyle::create(m_selectionToDelete.end());
2910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    else
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_deleteIntoBlockquoteStyle = 0;
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool DeleteSelectionCommand::handleSpecialCaseBRDelete()
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Check for special-case where the selection contains only a BR on a line by itself after another BR.
29881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    bool upstreamStartIsBR = m_upstreamStart.deprecatedNode()->hasTagName(brTag);
29981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    bool downstreamStartIsBR = m_downstreamStart.deprecatedNode()->hasTagName(brTag);
30081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && m_downstreamStart.deprecatedNode() == m_upstreamEnd.deprecatedNode();
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isBROnLineByItself) {
30281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        removeNode(m_downstreamStart.deprecatedNode());
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return true;
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Not a special-case delete per se, but we can detect that the merging of content between blocks
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // should not be done.
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (upstreamStartIsBR && downstreamStartIsBR) {
3095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        m_startsAtEmptyLine = true;
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_endingPosition = m_downstreamEnd;
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void updatePositionForNodeRemoval(Node* node, Position& position)
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (position.isNull())
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
320ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    switch (position.anchorType()) {
321ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    case Position::PositionIsOffsetInAnchor:
322ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        if (position.containerNode() == node->parentNode() && static_cast<unsigned>(position.offsetInContainerNode()) > node->nodeIndex())
323ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            position.moveToOffset(position.offsetInContainerNode() - 1);
324ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        else if (node->contains(position.containerNode()))
325ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            position = positionInParentBeforeNode(node);
326ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        break;
327ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    case Position::PositionIsAfterAnchor:
328ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        if (node->contains(position.anchorNode()))
329ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            position = positionInParentAfterNode(node);
330ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        break;
331ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    case Position::PositionIsBeforeAnchor:
332ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        if (node->contains(position.anchorNode()))
333ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            position = positionInParentBeforeNode(node);
334ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        break;
335ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    }
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic Position firstEditablePositionInNode(Node* node)
3392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
3402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    ASSERT(node);
3412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    Node* next = node;
3422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    while (next && !next->rendererIsEditable())
3432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        next = next->traverseNextNode(node);
3442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return next ? firstPositionInOrBeforeNode(next) : Position();
3452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
3462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
347635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid DeleteSelectionCommand::removeNode(PassRefPtr<Node> node)
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!node)
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_startRoot != m_endRoot && !(node->isDescendantOf(m_startRoot.get()) && node->isDescendantOf(m_endRoot.get()))) {
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // If a node is not in both the start and end editable roots, remove it only if its inside an editable region.
3542bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (!node->parentNode()->rendererIsEditable()) {
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Don't remove non-editable atomic nodes.
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (!node->firstChild())
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return;
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Search this non-editable region for editable regions to empty.
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            RefPtr<Node> child = node->firstChild();
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (child) {
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                RefPtr<Node> nextChild = child->nextSibling();
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                removeNode(child.get());
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // Bail if nextChild is no longer node's child.
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (nextChild && nextChild->parentNode() != node)
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return;
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                child = nextChild;
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Don't remove editable regions that are inside non-editable ones, just clear them.
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
374635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (isTableStructureNode(node.get()) || node == node->rootEditableElement()) {
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Do not remove an element of table structure; remove its contents.
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Likewise for the root editable element.
377635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        Node* child = node->firstChild();
3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (child) {
379635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            Node* remove = child;
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            child = child->nextSibling();
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            removeNode(remove);
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        // Make sure empty cell has some height, if a placeholder can be inserted.
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        updateLayout();
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        RenderObject *r = node->renderer();
3872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (r && r->isTableCell() && toRenderTableCell(r)->contentHeight() <= 0) {
3882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            Position firstEditablePosition = firstEditablePositionInNode(node.get());
3892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            if (firstEditablePosition.isNotNull())
3902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                insertBlockPlaceholder(firstEditablePosition);
3912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        }
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3952bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (node == m_startBlock && !isEndOfBlock(VisiblePosition(firstPositionInNode(m_startBlock.get())).previous()))
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_needPlaceholder = true;
3972bde8e466a4451c7319e3a072d118917957d6554Steve Block    else if (node == m_endBlock && !isStartOfBlock(VisiblePosition(lastPositionInNode(m_startBlock.get())).next()))
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_needPlaceholder = true;
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Update the endpoints of the range being deleted.
401635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    updatePositionForNodeRemoval(node.get(), m_endingPosition);
402635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    updatePositionForNodeRemoval(node.get(), m_leadingWhitespace);
403635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    updatePositionForNodeRemoval(node.get(), m_trailingWhitespace);
4048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CompositeEditCommand::removeNode(node);
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
408635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void updatePositionForTextRemoval(Node* node, int offset, int count, Position& position)
4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
410ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    if (position.anchorType() != Position::PositionIsOffsetInAnchor || position.containerNode() != node)
411ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        return;
412ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch
413ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    if (position.offsetInContainerNode() > offset + count)
414ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        position.moveToOffset(position.offsetInContainerNode() - count);
415ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    else if (position.offsetInContainerNode() > offset)
416ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch        position.moveToOffset(offset);
4178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
419635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid DeleteSelectionCommand::deleteTextFromNode(PassRefPtr<Text> node, unsigned offset, unsigned count)
4208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Update the endpoints of the range being deleted.
422635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    updatePositionForTextRemoval(node.get(), offset, count, m_endingPosition);
423635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    updatePositionForTextRemoval(node.get(), offset, count, m_leadingWhitespace);
424635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    updatePositionForTextRemoval(node.get(), offset, count, m_trailingWhitespace);
4255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    updatePositionForTextRemoval(node.get(), offset, count, m_downstreamEnd);
4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CompositeEditCommand::deleteTextFromNode(node, offset, count);
4288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::handleGeneralDelete()
4318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int startOffset = m_upstreamStart.deprecatedEditingOffset();
43381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    Node* startNode = m_upstreamStart.deprecatedNode();
4348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Never remove the start block unless it's a table, in which case we won't merge content in.
4368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (startNode == m_startBlock && startOffset == 0 && canHaveChildrenForEditing(startNode) && !startNode->hasTagName(tableTag)) {
4378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startOffset = 0;
4388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startNode = startNode->traverseNextNode();
4398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (startOffset >= caretMaxOffset(startNode) && startNode->isTextNode()) {
4428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Text *text = static_cast<Text *>(startNode);
4438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (text->length() > (unsigned)caretMaxOffset(startNode))
4448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            deleteTextFromNode(text, caretMaxOffset(startNode), text->length() - caretMaxOffset(startNode));
4458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4478f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (startOffset >= lastOffsetForEditing(startNode)) {
4488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startNode = startNode->traverseNextSibling();
4498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startOffset = 0;
4508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Done adjusting the start.  See if we're all done.
4538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!startNode)
4548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
45681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (startNode == m_downstreamEnd.deprecatedNode()) {
457bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        if (m_downstreamEnd.deprecatedEditingOffset() - startOffset > 0) {
4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (startNode->isTextNode()) {
4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // in a text node that needs to be trimmed
4608f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                Text* text = static_cast<Text*>(startNode);
4615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                deleteTextFromNode(text, startOffset, m_downstreamEnd.deprecatedEditingOffset() - startOffset);
4628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
4635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                removeChildrenInRange(startNode, startOffset, m_downstreamEnd.deprecatedEditingOffset());
4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                m_endingPosition = m_upstreamStart;
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
467bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen
468bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        // The selection to delete is all in one node.
469bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        if (!startNode->renderer() || (!startOffset && m_downstreamEnd.atLastEditingPositionForNode()))
470bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            removeNode(startNode);
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else {
47381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        bool startNodeWasDescendantOfEndNode = m_upstreamStart.deprecatedNode()->isDescendantOf(m_downstreamEnd.deprecatedNode());
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // The selection to delete spans more than one node.
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        RefPtr<Node> node(startNode);
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (startOffset > 0) {
4788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (startNode->isTextNode()) {
4798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // in a text node that needs to be trimmed
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                Text *text = static_cast<Text *>(node.get());
4818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                deleteTextFromNode(text, startOffset, text->length() - startOffset);
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                node = node->traverseNextNode();
4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                node = startNode->childNode(startOffset);
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
48681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        } else if (startNode == m_upstreamEnd.deprecatedNode() && startNode->isTextNode()) {
48781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            Text* text = static_cast<Text*>(m_upstreamEnd.deprecatedNode());
488bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            deleteTextFromNode(text, 0, m_upstreamEnd.deprecatedEditingOffset());
4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // handle deleting all nodes that are completely selected
49281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        while (node && node != m_downstreamEnd.deprecatedNode()) {
493ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            if (comparePositions(firstPositionInOrBeforeNode(node.get()), m_downstreamEnd) >= 0) {
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // traverseNextSibling just blew past the end position, so stop deleting
4958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                node = 0;
49681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            } else if (!m_downstreamEnd.deprecatedNode()->isDescendantOf(node.get())) {
4978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                RefPtr<Node> nextNode = node->traverseNextSibling();
4988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // if we just removed a node from the end container, update end position so the
4998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // check above will work
50081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                if (node->parentNode() == m_downstreamEnd.deprecatedNode()) {
501ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch                    ASSERT(m_downstreamEnd.deprecatedEditingOffset());
5025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    ASSERT(node->nodeIndex() < (unsigned)m_downstreamEnd.deprecatedEditingOffset());
503ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch                    m_downstreamEnd.moveToOffset(m_downstreamEnd.deprecatedEditingOffset() - 1);
5048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
5058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                removeNode(node.get());
5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                node = nextNode.get();
5078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
5088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                Node* n = node->lastDescendant();
50981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                if (m_downstreamEnd.deprecatedNode() == n && m_downstreamEnd.deprecatedEditingOffset() >= caretMaxOffset(n)) {
5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    removeNode(node.get());
5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    node = 0;
5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                } else
5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    node = node->traverseNextNode();
5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
51781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (m_downstreamEnd.deprecatedNode() != startNode && !m_upstreamStart.deprecatedNode()->isDescendantOf(m_downstreamEnd.deprecatedNode()) && m_downstreamEnd.anchorNode()->inDocument() && m_downstreamEnd.deprecatedEditingOffset() >= caretMinOffset(m_downstreamEnd.deprecatedNode())) {
51881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            if (m_downstreamEnd.atLastEditingPositionForNode() && !canHaveChildrenForEditing(m_downstreamEnd.deprecatedNode())) {
5198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // The node itself is fully selected, not just its contents.  Delete it.
52081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                removeNode(m_downstreamEnd.deprecatedNode());
5218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
52281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                if (m_downstreamEnd.deprecatedNode()->isTextNode()) {
5238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // in a text node that needs to be trimmed
52481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    Text* text = static_cast<Text*>(m_downstreamEnd.deprecatedNode());
5255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    if (m_downstreamEnd.deprecatedEditingOffset() > 0) {
5265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                        deleteTextFromNode(text, 0, m_downstreamEnd.deprecatedEditingOffset());
5278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    }
52881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                // Remove children of m_downstreamEnd.deprecatedNode() that come after m_upstreamStart.
52981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                // Don't try to remove children if m_upstreamStart was inside m_downstreamEnd.deprecatedNode()
5308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // and m_upstreamStart has been removed from the document, because then we don't
5318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // know how many children to remove.
5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // FIXME: Make m_upstreamStart a position we update as we remove content, then we can
5338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // always know which children to remove.
53481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                } else if (!(startNodeWasDescendantOfEndNode && !m_upstreamStart.anchorNode()->inDocument())) {
5358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    int offset = 0;
53681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    if (m_upstreamStart.deprecatedNode()->isDescendantOf(m_downstreamEnd.deprecatedNode())) {
53781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                        Node* n = m_upstreamStart.deprecatedNode();
53881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                        while (n && n->parentNode() != m_downstreamEnd.deprecatedNode())
5398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            n = n->parentNode();
5408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        if (n)
5418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            offset = n->nodeIndex() + 1;
5428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    }
54381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    removeChildrenInRange(m_downstreamEnd.deprecatedNode(), offset, m_downstreamEnd.deprecatedEditingOffset());
544ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch                    m_downstreamEnd.moveToOffset(offset);
5458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
5468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
5478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::fixupWhitespace()
5528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    updateLayout();
5548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: isRenderedCharacter should be removed, and we should use VisiblePosition::characterAfter and VisiblePosition::characterBefore
55581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (m_leadingWhitespace.isNotNull() && !m_leadingWhitespace.isRenderedCharacter() && m_leadingWhitespace.deprecatedNode()->isTextNode()) {
55681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        Text* textNode = static_cast<Text*>(m_leadingWhitespace.deprecatedNode());
5578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
5585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        replaceTextInNode(textNode, m_leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
5598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
56081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (m_trailingWhitespace.isNotNull() && !m_trailingWhitespace.isRenderedCharacter() && m_trailingWhitespace.deprecatedNode()->isTextNode()) {
56181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        Text* textNode = static_cast<Text*>(m_trailingWhitespace.deprecatedNode());
5628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(!textNode->renderer() ||textNode->renderer()->style()->collapseWhiteSpace());
5635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        replaceTextInNode(textNode, m_trailingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
5648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// If a selection starts in one block and ends in another, we have to merge to bring content before the
5688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// start together with content after the end.
5698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::mergeParagraphs()
5708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
571635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_mergeBlocksAfterDelete) {
572635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (m_pruneStartBlockIfNecessary) {
573635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // We aren't going to merge into the start block, so remove it if it's empty.
5745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            prune(m_startBlock);
575635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Removing the start block during a deletion is usually an indication that we need
576635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // a placeholder, but not in this case.
577635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_needPlaceholder = false;
578635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
5798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
580635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
581635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
582635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // It shouldn't have been asked to both try and merge content into the start block and prune it.
583635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(!m_pruneStartBlockIfNecessary);
5848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Deletion should adjust selection endpoints as it removes nodes so that we never get into this state (4099839).
58681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!m_downstreamEnd.anchorNode()->inDocument() || !m_upstreamStart.anchorNode()->inDocument())
5878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project         return;
5888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: The deletion algorithm shouldn't let this happen.
5905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (comparePositions(m_upstreamStart, m_downstreamEnd) > 0)
5918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
5928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // There's nothing to merge.
5945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (m_upstreamStart == m_downstreamEnd)
5958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
5968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition startOfParagraphToMove(m_downstreamEnd);
5988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition mergeDestination(m_upstreamStart);
5998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // m_downstreamEnd's block has been emptied out by deletion.  There is no content inside of it to
6018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // move, so just remove it.
60281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    Element* endBlock = static_cast<Element*>(enclosingBlock(m_downstreamEnd.deprecatedNode()));
60381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!startOfParagraphToMove.deepEquivalent().deprecatedNode() || !endBlock->contains(startOfParagraphToMove.deepEquivalent().deprecatedNode())) {
60481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        removeNode(enclosingBlock(m_downstreamEnd.deprecatedNode()));
6058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
6068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // We need to merge into m_upstreamStart's block, but it's been emptied out and collapsed by deletion.
6092bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!mergeDestination.deepEquivalent().deprecatedNode() || !mergeDestination.deepEquivalent().deprecatedNode()->isDescendantOf(enclosingBlock(m_upstreamStart.containerNode())) || m_startsAtEmptyLine) {
6108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        insertNodeAt(createBreakElement(document()).get(), m_upstreamStart);
6118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        mergeDestination = VisiblePosition(m_upstreamStart);
6128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (mergeDestination == startOfParagraphToMove)
6158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
6168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove);
6188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (mergeDestination == endOfParagraphToMove)
6208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
6218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // The rule for merging into an empty block is: only do so if its farther to the right.
6238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Consider RTL.
6245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && startOfParagraphToMove.absoluteCaretBounds().x() > mergeDestination.absoluteCaretBounds().x()) {
62581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (mergeDestination.deepEquivalent().downstream().deprecatedNode()->hasTagName(brTag)) {
62681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            removeNodeAndPruneAncestors(mergeDestination.deepEquivalent().downstream().deprecatedNode());
627d0825bca7fe65beaee391d30da42e937db621564Steve Block            m_endingPosition = startOfParagraphToMove.deepEquivalent();
628d0825bca7fe65beaee391d30da42e937db621564Steve Block            return;
629d0825bca7fe65beaee391d30da42e937db621564Steve Block        }
6308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
632643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Block images, tables and horizontal rules cannot be made inline with content at mergeDestination.  If there is
633643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // any (!isStartOfParagraph(mergeDestination)), don't merge, just move the caret to just before the selection we deleted.
634643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // See https://bugs.webkit.org/show_bug.cgi?id=25439
63581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalent().deprecatedNode()) && !isStartOfParagraph(mergeDestination)) {
636643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        m_endingPosition = m_upstreamStart;
637643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return;
638643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
639643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
640ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    RefPtr<Range> range = Range::create(document(), startOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent(), endOfParagraphToMove.deepEquivalent().parentAnchoredEquivalent());
641ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    RefPtr<Range> rangeToBeReplaced = Range::create(document(), mergeDestination.deepEquivalent().parentAnchoredEquivalent(), mergeDestination.deepEquivalent().parentAnchoredEquivalent());
6428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!document()->frame()->editor()->client()->shouldMoveRangeAfterDelete(range.get(), rangeToBeReplaced.get()))
6438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
6448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // moveParagraphs will insert placeholders if it removes blocks that would require their use, don't let block
6468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // removals that it does cause the insertion of *another* placeholder.
6478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool needPlaceholder = m_needPlaceholder;
648f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    bool paragraphToMergeIsEmpty = (startOfParagraphToMove == endOfParagraphToMove);
649f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    moveParagraph(startOfParagraphToMove, endOfParagraphToMove, mergeDestination, false, !paragraphToMergeIsEmpty);
6508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_needPlaceholder = needPlaceholder;
6518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // The endingPosition was likely clobbered by the move, so recompute it (moveParagraph selects the moved paragraph).
6528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_endingPosition = endingSelection().start();
6538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::removePreviouslySelectedEmptyTableRows()
6568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_startTableRow) {
6588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Node* row = m_endTableRow->previousSibling();
6598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (row && row != m_startTableRow) {
6608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            RefPtr<Node> previousRow = row->previousSibling();
6618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (isTableRowEmpty(row))
6628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // Use a raw removeNode, instead of DeleteSelectionCommand's, because
6638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // that won't remove rows, it only empties them in preparation for this function.
6648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                CompositeEditCommand::removeNode(row);
6658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            row = previousRow.get();
6668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
6678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Remove empty rows after the start row.
6708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_startTableRow && m_startTableRow->inDocument() && m_startTableRow != m_endTableRow) {
6718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Node* row = m_startTableRow->nextSibling();
6728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (row && row != m_endTableRow) {
6738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            RefPtr<Node> nextRow = row->nextSibling();
6748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (isTableRowEmpty(row))
6758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                CompositeEditCommand::removeNode(row);
6768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            row = nextRow.get();
6778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
6788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_startTableRow)
6818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isTableRowEmpty(m_endTableRow.get())) {
6828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Don't remove m_endTableRow if it's where we're putting the ending selection.
68381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            if (!m_endingPosition.deprecatedNode()->isDescendantOf(m_endTableRow.get())) {
6848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // FIXME: We probably shouldn't remove m_endTableRow unless it's fully selected, even if it is empty.
6858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // We'll need to start adjusting the selection endpoints during deletion to know whether or not m_endTableRow
6868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // was fully selected here.
6878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                CompositeEditCommand::removeNode(m_endTableRow.get());
6888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
6898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
6908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::calculateTypingStyleAfterDelete()
6938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_typingStyle)
6958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
6968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Compute the difference between the style before the delete and the style now
6988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // after the delete has been done. Set this style on the frame, so other editing
6998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // commands being composed with this one will work, and also cache it on the command,
7008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // so the Frame::appliedEditing can set it after the whole composite command
7018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // has completed.
7028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If we deleted into a blockquote, but are now no longer in a blockquote, use the alternate typing style
7042bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (m_deleteIntoBlockquoteStyle && !enclosingNodeOfType(m_endingPosition, isMailBlockquote, CanCrossEditingBoundary))
7058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_typingStyle = m_deleteIntoBlockquoteStyle;
7068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_deleteIntoBlockquoteStyle = 0;
7070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
70828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    m_typingStyle->prepareToApplyAt(m_endingPosition);
70928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (m_typingStyle->isEmpty())
7108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_typingStyle = 0;
7118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition visibleEnd(m_endingPosition);
7128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_typingStyle &&
7138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        isStartOfParagraph(visibleEnd) &&
7148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        isEndOfParagraph(visibleEnd) &&
7155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        lineBreakExistsAtVisiblePosition(visibleEnd)) {
7168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Apply style to the placeholder that is now holding open the empty paragraph.
7178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // This makes sure that the paragraph has the right height, and that the paragraph
7188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // takes on the right style and retains it even if you move the selection away and
7198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // then move it back (which will clear typing style).
7208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        setEndingSelection(visibleEnd);
722f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        applyStyle(m_typingStyle.get(), EditActionUnspecified);
7238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // applyStyle can destroy the placeholder that was at m_endingPosition if it needs to
7248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // move it, but it will set an endingSelection() at [movedPlaceholder, 0] if it does so.
7258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_endingPosition = endingSelection().start();
7268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_typingStyle = 0;
7278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // This is where we've deleted all traces of a style but not a whole paragraph (that's handled above).
7298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // In this case if we start typing, the new characters should have the same style as the just deleted ones,
7308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // but, if we change the selection, come back and start typing that style should be lost.  Also see
7318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // preserveTypingStyle() below.
73268513a70bcd92384395513322f1b801e7bf9c729Steve Block    document()->frame()->selection()->setTypingStyle(m_typingStyle);
7338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::clearTransientState()
7368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7378f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    m_selectionToDelete = VisibleSelection();
7388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_upstreamStart.clear();
7398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_downstreamStart.clear();
7408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_upstreamEnd.clear();
7418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_downstreamEnd.clear();
7428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_endingPosition.clear();
7438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_leadingWhitespace.clear();
7448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_trailingWhitespace.clear();
7458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DeleteSelectionCommand::doApply()
7488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If selection has not been set to a custom selection when the command was created,
7508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // use the current ending selection.
7518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_hasSelectionToDelete)
7528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_selectionToDelete = endingSelection();
753e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
754e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!m_selectionToDelete.isNonOrphanedRange())
7558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If the deletion is occurring in a text field, and we're not deleting to replace the selection, then let the frame call across the bridge to notify the form delegate.
7588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_replace) {
75981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        Node* startNode = m_selectionToDelete.start().deprecatedNode();
7608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Node* ancestorNode = startNode ? startNode->shadowAncestorNode() : 0;
7618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (ancestorNode && ancestorNode->hasTagName(inputTag)
7628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                && static_cast<HTMLInputElement*>(ancestorNode)->isTextField()
7638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                && ancestorNode->focused())
7645abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick            document()->frame()->editor()->textWillBeDeletedInTextField(static_cast<Element*>(ancestorNode));
7658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // save this to later make the selection with
7688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    EAffinity affinity = m_selectionToDelete.affinity();
7698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position downstreamEnd = m_selectionToDelete.end().downstream();
7714576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    m_needPlaceholder = isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditingBoundary)
7724576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang            && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBoundary)
773e14391e94c850b8bd03680c23b38978db68687a8John Reck            && !lineBreakExistsAtVisiblePosition(m_selectionToDelete.visibleEnd());
7748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_needPlaceholder) {
7758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Don't need a placeholder when deleting a selection that starts just before a table
7768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // and ends inside it (we do need placeholders to hold open empty cells, but that's
7778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // handled elsewhere).
7788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (Node* table = isLastPositionBeforeTable(m_selectionToDelete.visibleStart()))
77981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            if (m_selectionToDelete.end().deprecatedNode()->isDescendantOf(table))
7808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                m_needPlaceholder = false;
7818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // set up our state
7858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    initializePositionData();
7868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Delete any text that may hinder our ability to fixup whitespace after the delete
7888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    deleteInsignificantTextDownstream(m_trailingWhitespace);
7898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    saveTypingStyleState();
7918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // deleting just a BR is handled specially, at least because we do not
7938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // want to replace it with a placeholder BR!
7948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (handleSpecialCaseBRDelete()) {
7958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        calculateTypingStyleAfterDelete();
7968f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        setEndingSelection(VisibleSelection(m_endingPosition, affinity));
7978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        clearTransientState();
7988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        rebalanceWhitespace();
7998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    handleGeneralDelete();
8038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    fixupWhitespace();
8058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    mergeParagraphs();
8078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    removePreviouslySelectedEmptyTableRows();
8098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RefPtr<Node> placeholder = m_needPlaceholder ? createBreakElement(document()).get() : 0;
8118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (placeholder)
8138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        insertNodeAt(placeholder.get(), m_endingPosition);
8148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    rebalanceWhitespaceAt(m_endingPosition);
8168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    calculateTypingStyleAfterDelete();
8188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8198f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    setEndingSelection(VisibleSelection(m_endingPosition, affinity));
8208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    clearTransientState();
8218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectEditAction DeleteSelectionCommand::editingAction() const
8248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Note that DeleteSelectionCommand is also used when the user presses the Delete key,
8268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // but in that case there's a TypingCommand that supplies the editingAction(), so
8278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // the Undo menu correctly shows "Undo Typing"
8288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return EditActionCut;
8298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Normally deletion doesn't preserve the typing style that was present before it.  For example,
8328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// type a character, Bold, then delete the character and start typing.  The Bold typing style shouldn't
8338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// stick around.  Deletion should preserve a typing style that *it* sets, however.
8348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool DeleteSelectionCommand::preservesTypingStyle() const
8358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_typingStyle;
8378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace WebCore
840