Chromium Code Reviews| 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 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 56 if (!isHTMLTableRowElement(row)) | 56 if (!isHTMLTableRowElement(row)) |
| 57 return false; | 57 return false; |
| 58 | 58 |
| 59 for (Node* child = row->firstChild(); child; child = child->nextSibling()) { | 59 for (Node* child = row->firstChild(); child; child = child->nextSibling()) { |
| 60 if (isTableCell(child) && !isTableCellEmpty(child)) | 60 if (isTableCell(child) && !isTableCellEmpty(child)) |
| 61 return false; | 61 return false; |
| 62 } | 62 } |
| 63 return true; | 63 return true; |
| 64 } | 64 } |
| 65 | 65 |
| 66 DeleteSelectionCommand::DeleteSelectionCommand(Document& document, bool smartDel ete, bool mergeBlocksAfterDelete, bool expandForSpecialElements, bool sanitizeMa rkup, InputEvent::InputType inputType) | 66 DeleteSelectionCommand::DeleteSelectionCommand(Document& document, bool smartDel ete, bool mergeBlocksAfterDelete, bool expandForSpecialElements, bool sanitizeMa rkup, InputEvent::InputType inputType, const Position& referenceMovePosition) |
| 67 : CompositeEditCommand(document) | 67 : CompositeEditCommand(document) |
| 68 , m_hasSelectionToDelete(false) | 68 , m_hasSelectionToDelete(false) |
| 69 , m_smartDelete(smartDelete) | 69 , m_smartDelete(smartDelete) |
| 70 , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete) | 70 , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete) |
| 71 , m_needPlaceholder(false) | 71 , m_needPlaceholder(false) |
| 72 , m_expandForSpecialElements(expandForSpecialElements) | 72 , m_expandForSpecialElements(expandForSpecialElements) |
| 73 , m_pruneStartBlockIfNecessary(false) | 73 , m_pruneStartBlockIfNecessary(false) |
| 74 , m_startsAtEmptyLine(false) | 74 , m_startsAtEmptyLine(false) |
| 75 , m_sanitizeMarkup(sanitizeMarkup) | 75 , m_sanitizeMarkup(sanitizeMarkup) |
| 76 , m_inputType(inputType) | 76 , m_inputType(inputType) |
| 77 , m_referenceMovePosition(referenceMovePosition) | |
| 77 , m_startBlock(nullptr) | 78 , m_startBlock(nullptr) |
| 78 , m_endBlock(nullptr) | 79 , m_endBlock(nullptr) |
| 79 , m_typingStyle(nullptr) | 80 , m_typingStyle(nullptr) |
| 80 , m_deleteIntoBlockquoteStyle(nullptr) | 81 , m_deleteIntoBlockquoteStyle(nullptr) |
| 81 { | 82 { |
| 82 } | 83 } |
| 83 | 84 |
| 84 DeleteSelectionCommand::DeleteSelectionCommand(const VisibleSelection& selection , bool smartDelete, bool mergeBlocksAfterDelete, bool expandForSpecialElements, bool sanitizeMarkup, InputEvent::InputType inputType) | 85 DeleteSelectionCommand::DeleteSelectionCommand(const VisibleSelection& selection , bool smartDelete, bool mergeBlocksAfterDelete, bool expandForSpecialElements, bool sanitizeMarkup, InputEvent::InputType inputType) |
| 85 : CompositeEditCommand(*selection.start().document()) | 86 : CompositeEditCommand(*selection.start().document()) |
| 86 , m_hasSelectionToDelete(true) | 87 , m_hasSelectionToDelete(true) |
| (...skipping 711 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 798 void DeleteSelectionCommand::clearTransientState() | 799 void DeleteSelectionCommand::clearTransientState() |
| 799 { | 800 { |
| 800 m_selectionToDelete = VisibleSelection(); | 801 m_selectionToDelete = VisibleSelection(); |
| 801 m_upstreamStart = Position(); | 802 m_upstreamStart = Position(); |
| 802 m_downstreamStart = Position(); | 803 m_downstreamStart = Position(); |
| 803 m_upstreamEnd = Position(); | 804 m_upstreamEnd = Position(); |
| 804 m_downstreamEnd = Position(); | 805 m_downstreamEnd = Position(); |
| 805 m_endingPosition = Position(); | 806 m_endingPosition = Position(); |
| 806 m_leadingWhitespace = Position(); | 807 m_leadingWhitespace = Position(); |
| 807 m_trailingWhitespace = Position(); | 808 m_trailingWhitespace = Position(); |
| 809 m_referenceMovePosition = Position(); | |
| 808 } | 810 } |
| 809 | 811 |
| 810 // This method removes div elements with no attributes that have only one child or no children at all. | 812 // This method removes div elements with no attributes that have only one child or no children at all. |
| 811 void DeleteSelectionCommand::removeRedundantBlocks(EditingState* editingState) | 813 void DeleteSelectionCommand::removeRedundantBlocks(EditingState* editingState) |
| 812 { | 814 { |
| 813 Node* node = m_endingPosition.computeContainerNode(); | 815 Node* node = m_endingPosition.computeContainerNode(); |
| 814 Element* rootElement = rootEditableElement(*node); | 816 Element* rootElement = rootEditableElement(*node); |
| 815 | 817 |
| 816 while (node != rootElement) { | 818 while (node != rootElement) { |
| 817 if (isRemovableBlock(node)) { | 819 if (isRemovableBlock(node)) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 831 void DeleteSelectionCommand::doApply(EditingState* editingState) | 833 void DeleteSelectionCommand::doApply(EditingState* editingState) |
| 832 { | 834 { |
| 833 // If selection has not been set to a custom selection when the command was created, | 835 // If selection has not been set to a custom selection when the command was created, |
| 834 // use the current ending selection. | 836 // use the current ending selection. |
| 835 if (!m_hasSelectionToDelete) | 837 if (!m_hasSelectionToDelete) |
| 836 m_selectionToDelete = endingSelection(); | 838 m_selectionToDelete = endingSelection(); |
| 837 | 839 |
| 838 if (!m_selectionToDelete.isNonOrphanedRange() || !m_selectionToDelete.isCont entEditable()) | 840 if (!m_selectionToDelete.isNonOrphanedRange() || !m_selectionToDelete.isCont entEditable()) |
| 839 return; | 841 return; |
| 840 | 842 |
| 843 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.
| |
| 844 // Update the position otherwise it may become invalid after the selecti on is deleted. | |
|
yosin_UTC9
2016/09/28 04:19:03
Could you utilize |RelocatablePosition|?
chongz
2016/09/29 02:36:22
Done.
| |
| 845 Position selectionEnd = endingSelection().end(); | |
| 846 if (m_referenceMovePosition.isOffsetInAnchor() && selectionEnd.isOffsetI nAnchor() | |
| 847 && selectionEnd.computeContainerNode() == m_referenceMovePosition.co mputeContainerNode() && selectionEnd.offsetInContainerNode() < m_referenceMovePo sition.offsetInContainerNode()) { | |
| 848 m_referenceMovePosition = Position(m_referenceMovePosition.computeCo ntainerNode(), m_referenceMovePosition.offsetInContainerNode() - selectionEnd.of fsetInContainerNode()); | |
| 849 | |
| 850 Position selectionStart = endingSelection().start(); | |
| 851 if (selectionStart.isOffsetInAnchor() && selectionStart.computeConta inerNode() == m_referenceMovePosition.computeContainerNode()) | |
| 852 m_referenceMovePosition = Position(m_referenceMovePosition.compu teContainerNode(), m_referenceMovePosition.offsetInContainerNode() + selectionSt art.offsetInContainerNode()); | |
| 853 } | |
| 854 } | |
| 855 | |
| 841 // save this to later make the selection with | 856 // save this to later make the selection with |
| 842 TextAffinity affinity = m_selectionToDelete.affinity(); | 857 TextAffinity affinity = m_selectionToDelete.affinity(); |
| 843 | 858 |
| 844 Position downstreamEnd = mostForwardCaretPosition(m_selectionToDelete.end()) ; | 859 Position downstreamEnd = mostForwardCaretPosition(m_selectionToDelete.end()) ; |
| 845 bool rootWillStayOpenWithoutPlaceholder = downstreamEnd.computeContainerNode () == rootEditableElement(*downstreamEnd.computeContainerNode()) | 860 bool rootWillStayOpenWithoutPlaceholder = downstreamEnd.computeContainerNode () == rootEditableElement(*downstreamEnd.computeContainerNode()) |
| 846 || (downstreamEnd.computeContainerNode()->isTextNode() && downstreamEnd. computeContainerNode()->parentNode() == rootEditableElement(*downstreamEnd.compu teContainerNode())); | 861 || (downstreamEnd.computeContainerNode()->isTextNode() && downstreamEnd. computeContainerNode()->parentNode() == rootEditableElement(*downstreamEnd.compu teContainerNode())); |
| 847 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_ selectionToDelete.visibleEnd()); | 862 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_ selectionToDelete.visibleEnd()); |
| 848 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder | 863 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder |
| 849 && isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditin gBoundary) | 864 && isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditin gBoundary) |
| 850 && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBou ndary) | 865 && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBou ndary) |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 921 if (editingState->isAborted()) | 936 if (editingState->isAborted()) |
| 922 return; | 937 return; |
| 923 } | 938 } |
| 924 } | 939 } |
| 925 | 940 |
| 926 rebalanceWhitespaceAt(m_endingPosition); | 941 rebalanceWhitespaceAt(m_endingPosition); |
| 927 | 942 |
| 928 calculateTypingStyleAfterDelete(); | 943 calculateTypingStyleAfterDelete(); |
| 929 | 944 |
| 930 setEndingSelection(VisibleSelection(m_endingPosition, affinity, endingSelect ion().isDirectional())); | 945 setEndingSelection(VisibleSelection(m_endingPosition, affinity, endingSelect ion().isDirectional())); |
| 946 | |
| 947 // This deletion command is part or a move operation. | |
| 948 if (!m_referenceMovePosition.isNull()) { | |
| 949 // If the node for the destination has been removed as a result of the d eletion, | |
| 950 // set the destination to the ending point after the deletion. | |
| 951 // Fixes: <rdar://problem/3910425> REGRESSION (Mail): Crash in ReplaceSe lectionCommand; | |
| 952 // selection is empty, leading to null deref | |
| 953 if (!m_referenceMovePosition.isConnected()) | |
| 954 m_referenceMovePosition = endingSelection().start(); | |
| 955 | |
| 956 // Move selection shouldn't left empty <li> block. | |
| 957 cleanupAfterDeletion(editingState, createVisiblePositionDeprecated(m_ref erenceMovePosition)); | |
| 958 if (editingState->isAborted()) | |
| 959 return; | |
| 960 } | |
| 961 | |
| 931 clearTransientState(); | 962 clearTransientState(); |
| 932 } | 963 } |
| 933 | 964 |
| 934 InputEvent::InputType DeleteSelectionCommand::inputType() const | 965 InputEvent::InputType DeleteSelectionCommand::inputType() const |
| 935 { | 966 { |
| 936 // |DeleteSelectionCommand| could be used with Cut, Menu Bar deletion and |T ypingCommand|. | 967 // |DeleteSelectionCommand| could be used with Cut, Menu Bar deletion and |T ypingCommand|. |
| 937 // 1. Cut and Menu Bar deletion should rely on correct |m_inputType|. | 968 // 1. Cut and Menu Bar deletion should rely on correct |m_inputType|. |
| 938 // 2. |TypingCommand| will supply the |inputType()|, so |m_inputType| could default to |InputType::None|. | 969 // 2. |TypingCommand| will supply the |inputType()|, so |m_inputType| could default to |InputType::None|. |
| 939 return m_inputType; | 970 return m_inputType; |
| 940 } | 971 } |
| 941 | 972 |
| 942 // Normally deletion doesn't preserve the typing style that was present before i t. For example, | 973 // Normally deletion doesn't preserve the typing style that was present before i t. For example, |
| 943 // type a character, Bold, then delete the character and start typing. The Bold typing style shouldn't | 974 // type a character, Bold, then delete the character and start typing. The Bold typing style shouldn't |
| 944 // stick around. Deletion should preserve a typing style that *it* sets, howeve r. | 975 // stick around. Deletion should preserve a typing style that *it* sets, howeve r. |
| 945 bool DeleteSelectionCommand::preservesTypingStyle() const | 976 bool DeleteSelectionCommand::preservesTypingStyle() const |
| 946 { | 977 { |
| 947 return m_typingStyle; | 978 return m_typingStyle; |
| 948 } | 979 } |
| 949 | 980 |
| 950 DEFINE_TRACE(DeleteSelectionCommand) | 981 DEFINE_TRACE(DeleteSelectionCommand) |
| 951 { | 982 { |
| 952 visitor->trace(m_selectionToDelete); | 983 visitor->trace(m_selectionToDelete); |
| 953 visitor->trace(m_upstreamStart); | 984 visitor->trace(m_upstreamStart); |
| 954 visitor->trace(m_downstreamStart); | 985 visitor->trace(m_downstreamStart); |
| 955 visitor->trace(m_upstreamEnd); | 986 visitor->trace(m_upstreamEnd); |
| 956 visitor->trace(m_downstreamEnd); | 987 visitor->trace(m_downstreamEnd); |
| 957 visitor->trace(m_endingPosition); | 988 visitor->trace(m_endingPosition); |
| 958 visitor->trace(m_leadingWhitespace); | 989 visitor->trace(m_leadingWhitespace); |
| 959 visitor->trace(m_trailingWhitespace); | 990 visitor->trace(m_trailingWhitespace); |
| 991 visitor->trace(m_referenceMovePosition); | |
| 960 visitor->trace(m_startBlock); | 992 visitor->trace(m_startBlock); |
| 961 visitor->trace(m_endBlock); | 993 visitor->trace(m_endBlock); |
| 962 visitor->trace(m_typingStyle); | 994 visitor->trace(m_typingStyle); |
| 963 visitor->trace(m_deleteIntoBlockquoteStyle); | 995 visitor->trace(m_deleteIntoBlockquoteStyle); |
| 964 visitor->trace(m_startRoot); | 996 visitor->trace(m_startRoot); |
| 965 visitor->trace(m_endRoot); | 997 visitor->trace(m_endRoot); |
| 966 visitor->trace(m_startTableRow); | 998 visitor->trace(m_startTableRow); |
| 967 visitor->trace(m_endTableRow); | 999 visitor->trace(m_endTableRow); |
| 968 visitor->trace(m_temporaryPlaceholder); | 1000 visitor->trace(m_temporaryPlaceholder); |
| 969 CompositeEditCommand::trace(visitor); | 1001 CompositeEditCommand::trace(visitor); |
| 970 } | 1002 } |
| 971 | 1003 |
| 972 } // namespace blink | 1004 } // namespace blink |
| OLD | NEW |