| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. | 2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| 11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
| 12 * | 12 * |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "config.h" | 26 #include "config.h" |
| 27 #include "core/editing/DeleteSelectionCommand.h" | 27 #include "core/editing/commands/DeleteSelectionCommand.h" |
| 28 | 28 |
| 29 #include "core/HTMLNames.h" | 29 #include "core/HTMLNames.h" |
| 30 #include "core/dom/Document.h" | 30 #include "core/dom/Document.h" |
| 31 #include "core/dom/Element.h" | 31 #include "core/dom/Element.h" |
| 32 #include "core/dom/NodeTraversal.h" | 32 #include "core/dom/NodeTraversal.h" |
| 33 #include "core/dom/Text.h" | 33 #include "core/dom/Text.h" |
| 34 #include "core/editing/EditingBoundary.h" | 34 #include "core/editing/EditingBoundary.h" |
| 35 #include "core/editing/EditingUtilities.h" | 35 #include "core/editing/EditingUtilities.h" |
| 36 #include "core/editing/Editor.h" | 36 #include "core/editing/Editor.h" |
| 37 #include "core/editing/VisibleUnits.h" | 37 #include "core/editing/VisibleUnits.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 51 { | 51 { |
| 52 ASSERT(isTableCell(cell)); | 52 ASSERT(isTableCell(cell)); |
| 53 return VisiblePosition(firstPositionInNode(cell)).deepEquivalent() == Visibl
ePosition(lastPositionInNode(cell)).deepEquivalent(); | 53 return VisiblePosition(firstPositionInNode(cell)).deepEquivalent() == Visibl
ePosition(lastPositionInNode(cell)).deepEquivalent(); |
| 54 } | 54 } |
| 55 | 55 |
| 56 static bool isTableRowEmpty(Node* row) | 56 static bool isTableRowEmpty(Node* row) |
| 57 { | 57 { |
| 58 if (!isHTMLTableRowElement(row)) | 58 if (!isHTMLTableRowElement(row)) |
| 59 return false; | 59 return false; |
| 60 | 60 |
| 61 for (Node* child = row->firstChild(); child; child = child->nextSibling()) | 61 for (Node* child = row->firstChild(); child; child = child->nextSibling()) { |
| 62 if (isTableCell(child) && !isTableCellEmpty(child)) | 62 if (isTableCell(child) && !isTableCellEmpty(child)) |
| 63 return false; | 63 return false; |
| 64 | 64 } |
| 65 return true; | 65 return true; |
| 66 } | 66 } |
| 67 | 67 |
| 68 DeleteSelectionCommand::DeleteSelectionCommand(Document& document, bool smartDel
ete, bool mergeBlocksAfterDelete, bool expandForSpecialElements, bool sanitizeMa
rkup) | 68 DeleteSelectionCommand::DeleteSelectionCommand(Document& document, bool smartDel
ete, bool mergeBlocksAfterDelete, bool expandForSpecialElements, bool sanitizeMa
rkup) |
| 69 : CompositeEditCommand(document) | 69 : CompositeEditCommand(document) |
| 70 , m_hasSelectionToDelete(false) | 70 , m_hasSelectionToDelete(false) |
| 71 , m_smartDelete(smartDelete) | 71 , m_smartDelete(smartDelete) |
| 72 , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete) | 72 , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete) |
| 73 , m_needPlaceholder(false) | 73 , m_needPlaceholder(false) |
| 74 , m_expandForSpecialElements(expandForSpecialElements) | 74 , m_expandForSpecialElements(expandForSpecialElements) |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 break; | 133 break; |
| 134 | 134 |
| 135 // If we're going to expand to include the startSpecialContainer, it mus
t be fully selected. | 135 // If we're going to expand to include the startSpecialContainer, it mus
t be fully selected. |
| 136 if (startSpecialContainer && !endSpecialContainer && comparePositions(po
sitionInParentAfterNode(*startSpecialContainer), end) > -1) | 136 if (startSpecialContainer && !endSpecialContainer && comparePositions(po
sitionInParentAfterNode(*startSpecialContainer), end) > -1) |
| 137 break; | 137 break; |
| 138 | 138 |
| 139 // If we're going to expand to include the endSpecialContainer, it must
be fully selected. | 139 // If we're going to expand to include the endSpecialContainer, it must
be fully selected. |
| 140 if (endSpecialContainer && !startSpecialContainer && comparePositions(st
art, positionInParentBeforeNode(*endSpecialContainer)) > -1) | 140 if (endSpecialContainer && !startSpecialContainer && comparePositions(st
art, positionInParentBeforeNode(*endSpecialContainer)) > -1) |
| 141 break; | 141 break; |
| 142 | 142 |
| 143 if (startSpecialContainer && startSpecialContainer->isDescendantOf(endSp
ecialContainer)) | 143 if (startSpecialContainer && startSpecialContainer->isDescendantOf(endSp
ecialContainer)) { |
| 144 // Don't adjust the end yet, it is the end of a special element that
contains the start | 144 // Don't adjust the end yet, it is the end of a special element that
contains the start |
| 145 // special element (which may or may not be fully selected). | 145 // special element (which may or may not be fully selected). |
| 146 start = s; | 146 start = s; |
| 147 else if (endSpecialContainer && endSpecialContainer->isDescendantOf(star
tSpecialContainer)) | 147 } else if (endSpecialContainer && endSpecialContainer->isDescendantOf(st
artSpecialContainer)) { |
| 148 // Don't adjust the start yet, it is the start of a special element
that contains the end | 148 // Don't adjust the start yet, it is the start of a special element
that contains the end |
| 149 // special element (which may or may not be fully selected). | 149 // special element (which may or may not be fully selected). |
| 150 end = e; | 150 end = e; |
| 151 else { | 151 } else { |
| 152 start = s; | 152 start = s; |
| 153 end = e; | 153 end = e; |
| 154 } | 154 } |
| 155 } | 155 } |
| 156 } | 156 } |
| 157 | 157 |
| 158 void DeleteSelectionCommand::setStartingSelectionOnSmartDelete(const Position& s
tart, const Position& end) | 158 void DeleteSelectionCommand::setStartingSelectionOnSmartDelete(const Position& s
tart, const Position& end) |
| 159 { | 159 { |
| 160 bool isBaseFirst = startingSelection().isBaseFirst(); | 160 bool isBaseFirst = startingSelection().isBaseFirst(); |
| 161 VisiblePosition newBase(isBaseFirst ? start : end); | 161 VisiblePosition newBase(isBaseFirst ? start : end); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 else | 201 else |
| 202 m_endingPosition = m_downstreamStart; | 202 m_endingPosition = m_downstreamStart; |
| 203 | 203 |
| 204 // We don't want to merge into a block if it will mean changing the quote le
vel of content after deleting | 204 // We don't want to merge into a block if it will mean changing the quote le
vel of content after deleting |
| 205 // selections that contain a whole number paragraphs plus a line break, sinc
e it is unclear to most users | 205 // selections that contain a whole number paragraphs plus a line break, sinc
e it is unclear to most users |
| 206 // that such a selection actually ends at the start of the next paragraph. T
his matches TextEdit behavior | 206 // that such a selection actually ends at the start of the next paragraph. T
his matches TextEdit behavior |
| 207 // for indented paragraphs. | 207 // for indented paragraphs. |
| 208 // Only apply this rule if the endingSelection is a range selection. If it
is a caret, then other operations have created | 208 // Only apply this rule if the endingSelection is a range selection. If it
is a caret, then other operations have created |
| 209 // 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
. | 209 // 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
. |
| 210 if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end) | 210 if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end) |
| 211 && isStartOfParagraph(visibleEnd) && isStartOfParagraph(VisiblePosit
ion(start)) | 211 && isStartOfParagraph(visibleEnd) |
| 212 && endingSelection().isRange()) { | 212 && isStartOfParagraph(VisiblePosition(start)) |
| 213 && endingSelection().isRange()) { |
| 213 m_mergeBlocksAfterDelete = false; | 214 m_mergeBlocksAfterDelete = false; |
| 214 m_pruneStartBlockIfNecessary = true; | 215 m_pruneStartBlockIfNecessary = true; |
| 215 } | 216 } |
| 216 | 217 |
| 217 // Handle leading and trailing whitespace, as well as smart delete adjustmen
ts to the selection | 218 // Handle leading and trailing whitespace, as well as smart delete adjustmen
ts to the selection |
| 218 m_leadingWhitespace = leadingWhitespacePosition(m_upstreamStart, m_selection
ToDelete.affinity()); | 219 m_leadingWhitespace = leadingWhitespacePosition(m_upstreamStart, m_selection
ToDelete.affinity()); |
| 219 m_trailingWhitespace = trailingWhitespacePosition(m_downstreamEnd, VP_DEFAUL
T_AFFINITY); | 220 m_trailingWhitespace = trailingWhitespacePosition(m_downstreamEnd, VP_DEFAUL
T_AFFINITY); |
| 220 | 221 |
| 221 if (m_smartDelete) { | 222 if (m_smartDelete) { |
| 222 | 223 |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 deleteTextFromNode(text, startOffset, m_downstreamEnd.computeOff
setInContainerNode() - startOffset); | 485 deleteTextFromNode(text, startOffset, m_downstreamEnd.computeOff
setInContainerNode() - startOffset); |
| 485 } else { | 486 } else { |
| 486 removeChildrenInRange(startNode, startOffset, m_downstreamEnd.co
mputeEditingOffset()); | 487 removeChildrenInRange(startNode, startOffset, m_downstreamEnd.co
mputeEditingOffset()); |
| 487 m_endingPosition = m_upstreamStart; | 488 m_endingPosition = m_upstreamStart; |
| 488 } | 489 } |
| 489 } | 490 } |
| 490 | 491 |
| 491 // The selection to delete is all in one node. | 492 // The selection to delete is all in one node. |
| 492 if (!startNode->layoutObject() || (!startOffset && m_downstreamEnd.atLas
tEditingPositionForNode())) | 493 if (!startNode->layoutObject() || (!startOffset && m_downstreamEnd.atLas
tEditingPositionForNode())) |
| 493 removeNode(startNode); | 494 removeNode(startNode); |
| 494 } | 495 } else { |
| 495 else { | |
| 496 bool startNodeWasDescendantOfEndNode = m_upstreamStart.anchorNode()->isD
escendantOf(m_downstreamEnd.anchorNode()); | 496 bool startNodeWasDescendantOfEndNode = m_upstreamStart.anchorNode()->isD
escendantOf(m_downstreamEnd.anchorNode()); |
| 497 // The selection to delete spans more than one node. | 497 // The selection to delete spans more than one node. |
| 498 RefPtrWillBeRawPtr<Node> node(startNode); | 498 RefPtrWillBeRawPtr<Node> node(startNode); |
| 499 | 499 |
| 500 if (startOffset > 0) { | 500 if (startOffset > 0) { |
| 501 if (startNode->isTextNode()) { | 501 if (startNode->isTextNode()) { |
| 502 // in a text node that needs to be trimmed | 502 // in a text node that needs to be trimmed |
| 503 Text* text = toText(node); | 503 Text* text = toText(node); |
| 504 deleteTextFromNode(text, startOffset, text->length() - startOffs
et); | 504 deleteTextFromNode(text, startOffset, text->length() - startOffs
et); |
| 505 node = NodeTraversal::next(*node); | 505 node = NodeTraversal::next(*node); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 597 m_needPlaceholder = false; | 597 m_needPlaceholder = false; |
| 598 } | 598 } |
| 599 return; | 599 return; |
| 600 } | 600 } |
| 601 | 601 |
| 602 // It shouldn't have been asked to both try and merge content into the start
block and prune it. | 602 // It shouldn't have been asked to both try and merge content into the start
block and prune it. |
| 603 ASSERT(!m_pruneStartBlockIfNecessary); | 603 ASSERT(!m_pruneStartBlockIfNecessary); |
| 604 | 604 |
| 605 // FIXME: Deletion should adjust selection endpoints as it removes nodes so
that we never get into this state (4099839). | 605 // FIXME: Deletion should adjust selection endpoints as it removes nodes so
that we never get into this state (4099839). |
| 606 if (!m_downstreamEnd.inDocument() || !m_upstreamStart.inDocument()) | 606 if (!m_downstreamEnd.inDocument() || !m_upstreamStart.inDocument()) |
| 607 return; | 607 return; |
| 608 | 608 |
| 609 // FIXME: The deletion algorithm shouldn't let this happen. | 609 // FIXME: The deletion algorithm shouldn't let this happen. |
| 610 if (comparePositions(m_upstreamStart, m_downstreamEnd) > 0) | 610 if (comparePositions(m_upstreamStart, m_downstreamEnd) > 0) |
| 611 return; | 611 return; |
| 612 | 612 |
| 613 // There's nothing to merge. | 613 // There's nothing to merge. |
| 614 if (m_upstreamStart == m_downstreamEnd) | 614 if (m_upstreamStart == m_downstreamEnd) |
| 615 return; | 615 return; |
| 616 | 616 |
| 617 VisiblePosition startOfParagraphToMove(m_downstreamEnd); | 617 VisiblePosition startOfParagraphToMove(m_downstreamEnd); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 // The endingPosition was likely clobbered by the move, so recompute it (mov
eParagraph selects the moved paragraph). | 677 // The endingPosition was likely clobbered by the move, so recompute it (mov
eParagraph selects the moved paragraph). |
| 678 m_endingPosition = endingSelection().start(); | 678 m_endingPosition = endingSelection().start(); |
| 679 } | 679 } |
| 680 | 680 |
| 681 void DeleteSelectionCommand::removePreviouslySelectedEmptyTableRows() | 681 void DeleteSelectionCommand::removePreviouslySelectedEmptyTableRows() |
| 682 { | 682 { |
| 683 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) { | 683 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) { |
| 684 Node* row = m_endTableRow->previousSibling(); | 684 Node* row = m_endTableRow->previousSibling(); |
| 685 while (row && row != m_startTableRow) { | 685 while (row && row != m_startTableRow) { |
| 686 RefPtrWillBeRawPtr<Node> previousRow = row->previousSibling(); | 686 RefPtrWillBeRawPtr<Node> previousRow = row->previousSibling(); |
| 687 if (isTableRowEmpty(row)) | 687 if (isTableRowEmpty(row)) { |
| 688 // Use a raw removeNode, instead of DeleteSelectionCommand's, be
cause | 688 // Use a raw removeNode, instead of DeleteSelectionCommand's, be
cause |
| 689 // that won't remove rows, it only empties them in preparation f
or this function. | 689 // that won't remove rows, it only empties them in preparation f
or this function. |
| 690 CompositeEditCommand::removeNode(row); | 690 CompositeEditCommand::removeNode(row); |
| 691 } |
| 691 row = previousRow.get(); | 692 row = previousRow.get(); |
| 692 } | 693 } |
| 693 } | 694 } |
| 694 | 695 |
| 695 // Remove empty rows after the start row. | 696 // Remove empty rows after the start row. |
| 696 if (m_startTableRow && m_startTableRow->inDocument() && m_startTableRow != m
_endTableRow) { | 697 if (m_startTableRow && m_startTableRow->inDocument() && m_startTableRow != m
_endTableRow) { |
| 697 Node* row = m_startTableRow->nextSibling(); | 698 Node* row = m_startTableRow->nextSibling(); |
| 698 while (row && row != m_endTableRow) { | 699 while (row && row != m_endTableRow) { |
| 699 RefPtrWillBeRawPtr<Node> nextRow = row->nextSibling(); | 700 RefPtrWillBeRawPtr<Node> nextRow = row->nextSibling(); |
| 700 if (isTableRowEmpty(row)) | 701 if (isTableRowEmpty(row)) |
| 701 CompositeEditCommand::removeNode(row); | 702 CompositeEditCommand::removeNode(row); |
| 702 row = nextRow.get(); | 703 row = nextRow.get(); |
| 703 } | 704 } |
| 704 } | 705 } |
| 705 | 706 |
| 706 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) | 707 if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_start
TableRow) { |
| 707 if (isTableRowEmpty(m_endTableRow.get())) { | 708 if (isTableRowEmpty(m_endTableRow.get())) { |
| 708 // Don't remove m_endTableRow if it's where we're putting the ending
selection. | 709 // Don't remove m_endTableRow if it's where we're putting the ending
selection. |
| 709 if (!m_endingPosition.anchorNode()->isDescendantOf(m_endTableRow.get
())) { | 710 if (!m_endingPosition.anchorNode()->isDescendantOf(m_endTableRow.get
())) { |
| 710 // FIXME: We probably shouldn't remove m_endTableRow unless it's
fully selected, even if it is empty. | 711 // FIXME: We probably shouldn't remove m_endTableRow unless it's
fully selected, even if it is empty. |
| 711 // We'll need to start adjusting the selection endpoints during
deletion to know whether or not m_endTableRow | 712 // We'll need to start adjusting the selection endpoints during
deletion to know whether or not m_endTableRow |
| 712 // was fully selected here. | 713 // was fully selected here. |
| 713 CompositeEditCommand::removeNode(m_endTableRow.get()); | 714 CompositeEditCommand::removeNode(m_endTableRow.get()); |
| 714 } | 715 } |
| 715 } | 716 } |
| 717 } |
| 716 } | 718 } |
| 717 | 719 |
| 718 void DeleteSelectionCommand::calculateTypingStyleAfterDelete() | 720 void DeleteSelectionCommand::calculateTypingStyleAfterDelete() |
| 719 { | 721 { |
| 720 // Clearing any previously set typing style and doing an early return. | 722 // Clearing any previously set typing style and doing an early return. |
| 721 if (!m_typingStyle) { | 723 if (!m_typingStyle) { |
| 722 document().frame()->selection().clearTypingStyle(); | 724 document().frame()->selection().clearTypingStyle(); |
| 723 return; | 725 return; |
| 724 } | 726 } |
| 725 | 727 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 Node* node = m_endingPosition.computeContainerNode(); | 764 Node* node = m_endingPosition.computeContainerNode(); |
| 763 Element* rootElement = node->rootEditableElement(); | 765 Element* rootElement = node->rootEditableElement(); |
| 764 | 766 |
| 765 while (node != rootElement) { | 767 while (node != rootElement) { |
| 766 if (isRemovableBlock(node)) { | 768 if (isRemovableBlock(node)) { |
| 767 if (node == m_endingPosition.anchorNode()) | 769 if (node == m_endingPosition.anchorNode()) |
| 768 updatePositionForNodeRemovalPreservingChildren(m_endingPosition,
*node); | 770 updatePositionForNodeRemovalPreservingChildren(m_endingPosition,
*node); |
| 769 | 771 |
| 770 CompositeEditCommand::removeNodePreservingChildren(node); | 772 CompositeEditCommand::removeNodePreservingChildren(node); |
| 771 node = m_endingPosition.anchorNode(); | 773 node = m_endingPosition.anchorNode(); |
| 772 } else | 774 } else { |
| 773 node = node->parentNode(); | 775 node = node->parentNode(); |
| 776 } |
| 774 } | 777 } |
| 775 } | 778 } |
| 776 | 779 |
| 777 void DeleteSelectionCommand::doApply() | 780 void DeleteSelectionCommand::doApply() |
| 778 { | 781 { |
| 779 // If selection has not been set to a custom selection when the command was
created, | 782 // If selection has not been set to a custom selection when the command was
created, |
| 780 // use the current ending selection. | 783 // use the current ending selection. |
| 781 if (!m_hasSelectionToDelete) | 784 if (!m_hasSelectionToDelete) |
| 782 m_selectionToDelete = endingSelection(); | 785 m_selectionToDelete = endingSelection(); |
| 783 | 786 |
| 784 if (!m_selectionToDelete.isNonOrphanedRange() || !m_selectionToDelete.isCont
entEditable()) | 787 if (!m_selectionToDelete.isNonOrphanedRange() || !m_selectionToDelete.isCont
entEditable()) |
| 785 return; | 788 return; |
| 786 | 789 |
| 787 // save this to later make the selection with | 790 // save this to later make the selection with |
| 788 EAffinity affinity = m_selectionToDelete.affinity(); | 791 EAffinity affinity = m_selectionToDelete.affinity(); |
| 789 | 792 |
| 790 Position downstreamEnd = m_selectionToDelete.end().downstream(); | 793 Position downstreamEnd = m_selectionToDelete.end().downstream(); |
| 791 bool rootWillStayOpenWithoutPlaceholder = downstreamEnd.computeContainerNode
() == downstreamEnd.computeContainerNode()->rootEditableElement() | 794 bool rootWillStayOpenWithoutPlaceholder = downstreamEnd.computeContainerNode
() == downstreamEnd.computeContainerNode()->rootEditableElement() |
| 792 || (downstreamEnd.computeContainerNode()->isTextNode() && downstreamEnd.
computeContainerNode()->parentNode() == downstreamEnd.computeContainerNode()->ro
otEditableElement()); | 795 || (downstreamEnd.computeContainerNode()->isTextNode() && downstreamEnd.
computeContainerNode()->parentNode() == downstreamEnd.computeContainerNode()->ro
otEditableElement()); |
| 793 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_
selectionToDelete.visibleEnd()); | 796 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_
selectionToDelete.visibleEnd()); |
| 794 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder | 797 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder |
| 795 && isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditin
gBoundary) | 798 && isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditin
gBoundary) |
| 796 && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBou
ndary) | 799 && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBou
ndary) |
| 797 && !lineBreakAtEndOfSelectionToDelete; | 800 && !lineBreakAtEndOfSelectionToDelete; |
| 798 if (m_needPlaceholder) { | 801 if (m_needPlaceholder) { |
| 799 // Don't need a placeholder when deleting a selection that starts just b
efore a table | 802 // Don't need a placeholder when deleting a selection that starts just b
efore a table |
| 800 // and ends inside it (we do need placeholders to hold open empty cells,
but that's | 803 // and ends inside it (we do need placeholders to hold open empty cells,
but that's |
| 801 // handled elsewhere). | 804 // handled elsewhere). |
| 802 if (Element* table = isLastPositionBeforeTable(m_selectionToDelete.visib
leStart())) | 805 if (Element* table = isLastPositionBeforeTable(m_selectionToDelete.visib
leStart())) { |
| 803 if (m_selectionToDelete.end().anchorNode()->isDescendantOf(table)) | 806 if (m_selectionToDelete.end().anchorNode()->isDescendantOf(table)) |
| 804 m_needPlaceholder = false; | 807 m_needPlaceholder = false; |
| 808 } |
| 805 } | 809 } |
| 806 | 810 |
| 807 | 811 |
| 808 // set up our state | 812 // set up our state |
| 809 initializePositionData(); | 813 initializePositionData(); |
| 810 | 814 |
| 811 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition(VisiblePosition
(m_upstreamStart).previous()); | 815 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition(VisiblePosition
(m_upstreamStart).previous()); |
| 812 | 816 |
| 813 // Delete any text that may hinder our ability to fixup whitespace after the
delete | 817 // Delete any text that may hinder our ability to fixup whitespace after the
delete |
| 814 deleteInsignificantTextDownstream(m_trailingWhitespace); | 818 deleteInsignificantTextDownstream(m_trailingWhitespace); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 891 visitor->trace(m_deleteIntoBlockquoteStyle); | 895 visitor->trace(m_deleteIntoBlockquoteStyle); |
| 892 visitor->trace(m_startRoot); | 896 visitor->trace(m_startRoot); |
| 893 visitor->trace(m_endRoot); | 897 visitor->trace(m_endRoot); |
| 894 visitor->trace(m_startTableRow); | 898 visitor->trace(m_startTableRow); |
| 895 visitor->trace(m_endTableRow); | 899 visitor->trace(m_endTableRow); |
| 896 visitor->trace(m_temporaryPlaceholder); | 900 visitor->trace(m_temporaryPlaceholder); |
| 897 CompositeEditCommand::trace(visitor); | 901 CompositeEditCommand::trace(visitor); |
| 898 } | 902 } |
| 899 | 903 |
| 900 } // namespace blink | 904 } // namespace blink |
| OLD | NEW |