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 |