Chromium Code Reviews| Index: third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp |
| diff --git a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp |
| index 75b424fa928737c228012284b845b1c2780ce75b..b7ef67cf9eac676da172afd3f0cd56853a371435 100644 |
| --- a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp |
| +++ b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp |
| @@ -63,7 +63,7 @@ static bool isTableRowEmpty(Node* row) |
| return true; |
| } |
| -DeleteSelectionCommand::DeleteSelectionCommand(Document& document, bool smartDelete, bool mergeBlocksAfterDelete, bool expandForSpecialElements, bool sanitizeMarkup, InputEvent::InputType inputType) |
| +DeleteSelectionCommand::DeleteSelectionCommand(Document& document, bool smartDelete, bool mergeBlocksAfterDelete, bool expandForSpecialElements, bool sanitizeMarkup, InputEvent::InputType inputType, const Position& referenceMovePosition) |
| : CompositeEditCommand(document) |
| , m_hasSelectionToDelete(false) |
| , m_smartDelete(smartDelete) |
| @@ -74,6 +74,7 @@ DeleteSelectionCommand::DeleteSelectionCommand(Document& document, bool smartDel |
| , m_startsAtEmptyLine(false) |
| , m_sanitizeMarkup(sanitizeMarkup) |
| , m_inputType(inputType) |
| + , m_referenceMovePosition(referenceMovePosition) |
| , m_startBlock(nullptr) |
| , m_endBlock(nullptr) |
| , m_typingStyle(nullptr) |
| @@ -805,6 +806,7 @@ void DeleteSelectionCommand::clearTransientState() |
| m_endingPosition = Position(); |
| m_leadingWhitespace = Position(); |
| m_trailingWhitespace = Position(); |
| + m_referenceMovePosition = Position(); |
| } |
| // This method removes div elements with no attributes that have only one child or no children at all. |
| @@ -838,6 +840,19 @@ void DeleteSelectionCommand::doApply(EditingState* editingState) |
| if (!m_selectionToDelete.isNonOrphanedRange() || !m_selectionToDelete.isContentEditable()) |
| return; |
| + if (!m_referenceMovePosition.isNull()) { |
|
yosin_UTC9
2016/09/28 04:19:03
nit: s/!m_referenceMovePosition.isNull()/m_referen
chongz
2016/09/29 02:36:22
Done.
|
| + // Update the position otherwise it may become invalid after the selection is deleted. |
|
yosin_UTC9
2016/09/28 04:19:03
Could you utilize |RelocatablePosition|?
chongz
2016/09/29 02:36:22
Done.
|
| + Position selectionEnd = endingSelection().end(); |
| + if (m_referenceMovePosition.isOffsetInAnchor() && selectionEnd.isOffsetInAnchor() |
| + && selectionEnd.computeContainerNode() == m_referenceMovePosition.computeContainerNode() && selectionEnd.offsetInContainerNode() < m_referenceMovePosition.offsetInContainerNode()) { |
| + m_referenceMovePosition = Position(m_referenceMovePosition.computeContainerNode(), m_referenceMovePosition.offsetInContainerNode() - selectionEnd.offsetInContainerNode()); |
| + |
| + Position selectionStart = endingSelection().start(); |
| + if (selectionStart.isOffsetInAnchor() && selectionStart.computeContainerNode() == m_referenceMovePosition.computeContainerNode()) |
| + m_referenceMovePosition = Position(m_referenceMovePosition.computeContainerNode(), m_referenceMovePosition.offsetInContainerNode() + selectionStart.offsetInContainerNode()); |
| + } |
| + } |
| + |
| // save this to later make the selection with |
| TextAffinity affinity = m_selectionToDelete.affinity(); |
| @@ -928,6 +943,22 @@ void DeleteSelectionCommand::doApply(EditingState* editingState) |
| calculateTypingStyleAfterDelete(); |
| setEndingSelection(VisibleSelection(m_endingPosition, affinity, endingSelection().isDirectional())); |
| + |
| + // This deletion command is part or a move operation. |
| + if (!m_referenceMovePosition.isNull()) { |
| + // If the node for the destination has been removed as a result of the deletion, |
| + // set the destination to the ending point after the deletion. |
| + // Fixes: <rdar://problem/3910425> REGRESSION (Mail): Crash in ReplaceSelectionCommand; |
| + // selection is empty, leading to null deref |
| + if (!m_referenceMovePosition.isConnected()) |
| + m_referenceMovePosition = endingSelection().start(); |
| + |
| + // Move selection shouldn't left empty <li> block. |
| + cleanupAfterDeletion(editingState, createVisiblePositionDeprecated(m_referenceMovePosition)); |
| + if (editingState->isAborted()) |
| + return; |
| + } |
| + |
| clearTransientState(); |
| } |
| @@ -957,6 +988,7 @@ DEFINE_TRACE(DeleteSelectionCommand) |
| visitor->trace(m_endingPosition); |
| visitor->trace(m_leadingWhitespace); |
| visitor->trace(m_trailingWhitespace); |
| + visitor->trace(m_referenceMovePosition); |
| visitor->trace(m_startBlock); |
| visitor->trace(m_endBlock); |
| visitor->trace(m_typingStyle); |