| 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 15 matching lines...) Expand all Loading... |
| 26 #include "core/editing/commands/DeleteSelectionCommand.h" | 26 #include "core/editing/commands/DeleteSelectionCommand.h" |
| 27 | 27 |
| 28 #include "core/HTMLNames.h" | 28 #include "core/HTMLNames.h" |
| 29 #include "core/dom/Document.h" | 29 #include "core/dom/Document.h" |
| 30 #include "core/dom/Element.h" | 30 #include "core/dom/Element.h" |
| 31 #include "core/dom/NodeTraversal.h" | 31 #include "core/dom/NodeTraversal.h" |
| 32 #include "core/dom/Text.h" | 32 #include "core/dom/Text.h" |
| 33 #include "core/editing/EditingBoundary.h" | 33 #include "core/editing/EditingBoundary.h" |
| 34 #include "core/editing/EditingUtilities.h" | 34 #include "core/editing/EditingUtilities.h" |
| 35 #include "core/editing/Editor.h" | 35 #include "core/editing/Editor.h" |
| 36 #include "core/editing/RelocatablePosition.h" |
| 36 #include "core/editing/VisibleUnits.h" | 37 #include "core/editing/VisibleUnits.h" |
| 37 #include "core/frame/LocalFrame.h" | 38 #include "core/frame/LocalFrame.h" |
| 38 #include "core/html/HTMLBRElement.h" | 39 #include "core/html/HTMLBRElement.h" |
| 39 #include "core/html/HTMLInputElement.h" | 40 #include "core/html/HTMLInputElement.h" |
| 40 #include "core/html/HTMLStyleElement.h" | 41 #include "core/html/HTMLStyleElement.h" |
| 41 #include "core/html/HTMLTableRowElement.h" | 42 #include "core/html/HTMLTableRowElement.h" |
| 42 #include "core/layout/LayoutTableCell.h" | 43 #include "core/layout/LayoutTableCell.h" |
| 43 | 44 |
| 44 namespace blink { | 45 namespace blink { |
| 45 | 46 |
| 46 using namespace HTMLNames; | 47 using namespace HTMLNames; |
| 47 | 48 |
| 48 static bool isTableCellEmpty(Node* cell) { | 49 static bool isTableCellEmpty(Node* cell) { |
| 49 DCHECK(isTableCell(cell)) << cell; | 50 DCHECK(isTableCell(cell)) << cell; |
| 50 return VisiblePosition::firstPositionInNode(cell).deepEquivalent() == | 51 return VisiblePosition::firstPositionInNode(cell).deepEquivalent() == |
| 51 VisiblePosition::lastPositionInNode(cell).deepEquivalent(); | 52 VisiblePosition::lastPositionInNode(cell).deepEquivalent(); |
| 52 } | 53 } |
| 53 | 54 |
| 54 static bool isTableRowEmpty(Node* row) { | 55 static bool isTableRowEmpty(Node* row) { |
| 55 if (!isHTMLTableRowElement(row)) | 56 if (!isHTMLTableRowElement(row)) |
| 56 return false; | 57 return false; |
| 57 | 58 |
| 58 for (Node* child = row->firstChild(); child; child = child->nextSibling()) { | 59 for (Node* child = row->firstChild(); child; child = child->nextSibling()) { |
| 59 if (isTableCell(child) && !isTableCellEmpty(child)) | 60 if (isTableCell(child) && !isTableCellEmpty(child)) |
| 60 return false; | 61 return false; |
| 61 } | 62 } |
| 62 return true; | 63 return true; |
| 63 } | 64 } |
| 64 | 65 |
| 65 DeleteSelectionCommand::DeleteSelectionCommand(Document& document, | 66 DeleteSelectionCommand::DeleteSelectionCommand( |
| 66 bool smartDelete, | 67 Document& document, |
| 67 bool mergeBlocksAfterDelete, | 68 bool smartDelete, |
| 68 bool expandForSpecialElements, | 69 bool mergeBlocksAfterDelete, |
| 69 bool sanitizeMarkup, | 70 bool expandForSpecialElements, |
| 70 InputEvent::InputType inputType) | 71 bool sanitizeMarkup, |
| 72 InputEvent::InputType inputType, |
| 73 const Position& referenceMovePosition) |
| 71 : CompositeEditCommand(document), | 74 : CompositeEditCommand(document), |
| 72 m_hasSelectionToDelete(false), | 75 m_hasSelectionToDelete(false), |
| 73 m_smartDelete(smartDelete), | 76 m_smartDelete(smartDelete), |
| 74 m_mergeBlocksAfterDelete(mergeBlocksAfterDelete), | 77 m_mergeBlocksAfterDelete(mergeBlocksAfterDelete), |
| 75 m_needPlaceholder(false), | 78 m_needPlaceholder(false), |
| 76 m_expandForSpecialElements(expandForSpecialElements), | 79 m_expandForSpecialElements(expandForSpecialElements), |
| 77 m_pruneStartBlockIfNecessary(false), | 80 m_pruneStartBlockIfNecessary(false), |
| 78 m_startsAtEmptyLine(false), | 81 m_startsAtEmptyLine(false), |
| 79 m_sanitizeMarkup(sanitizeMarkup), | 82 m_sanitizeMarkup(sanitizeMarkup), |
| 80 m_inputType(inputType), | 83 m_inputType(inputType), |
| 84 m_referenceMovePosition(referenceMovePosition), |
| 81 m_startBlock(nullptr), | 85 m_startBlock(nullptr), |
| 82 m_endBlock(nullptr), | 86 m_endBlock(nullptr), |
| 83 m_typingStyle(nullptr), | 87 m_typingStyle(nullptr), |
| 84 m_deleteIntoBlockquoteStyle(nullptr) {} | 88 m_deleteIntoBlockquoteStyle(nullptr) {} |
| 85 | 89 |
| 86 DeleteSelectionCommand::DeleteSelectionCommand( | 90 DeleteSelectionCommand::DeleteSelectionCommand( |
| 87 const VisibleSelection& selection, | 91 const VisibleSelection& selection, |
| 88 bool smartDelete, | 92 bool smartDelete, |
| 89 bool mergeBlocksAfterDelete, | 93 bool mergeBlocksAfterDelete, |
| 90 bool expandForSpecialElements, | 94 bool expandForSpecialElements, |
| (...skipping 850 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 941 | 945 |
| 942 void DeleteSelectionCommand::clearTransientState() { | 946 void DeleteSelectionCommand::clearTransientState() { |
| 943 m_selectionToDelete = VisibleSelection(); | 947 m_selectionToDelete = VisibleSelection(); |
| 944 m_upstreamStart = Position(); | 948 m_upstreamStart = Position(); |
| 945 m_downstreamStart = Position(); | 949 m_downstreamStart = Position(); |
| 946 m_upstreamEnd = Position(); | 950 m_upstreamEnd = Position(); |
| 947 m_downstreamEnd = Position(); | 951 m_downstreamEnd = Position(); |
| 948 m_endingPosition = Position(); | 952 m_endingPosition = Position(); |
| 949 m_leadingWhitespace = Position(); | 953 m_leadingWhitespace = Position(); |
| 950 m_trailingWhitespace = Position(); | 954 m_trailingWhitespace = Position(); |
| 955 m_referenceMovePosition = Position(); |
| 951 } | 956 } |
| 952 | 957 |
| 953 // This method removes div elements with no attributes that have only one child
or no children at all. | 958 // This method removes div elements with no attributes that have only one child
or no children at all. |
| 954 void DeleteSelectionCommand::removeRedundantBlocks(EditingState* editingState) { | 959 void DeleteSelectionCommand::removeRedundantBlocks(EditingState* editingState) { |
| 955 Node* node = m_endingPosition.computeContainerNode(); | 960 Node* node = m_endingPosition.computeContainerNode(); |
| 956 Element* rootElement = rootEditableElement(*node); | 961 Element* rootElement = rootEditableElement(*node); |
| 957 | 962 |
| 958 while (node != rootElement) { | 963 while (node != rootElement) { |
| 959 if (isRemovableBlock(node)) { | 964 if (isRemovableBlock(node)) { |
| 960 if (node == m_endingPosition.anchorNode()) | 965 if (node == m_endingPosition.anchorNode()) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 973 void DeleteSelectionCommand::doApply(EditingState* editingState) { | 978 void DeleteSelectionCommand::doApply(EditingState* editingState) { |
| 974 // If selection has not been set to a custom selection when the command was cr
eated, | 979 // If selection has not been set to a custom selection when the command was cr
eated, |
| 975 // use the current ending selection. | 980 // use the current ending selection. |
| 976 if (!m_hasSelectionToDelete) | 981 if (!m_hasSelectionToDelete) |
| 977 m_selectionToDelete = endingSelection(); | 982 m_selectionToDelete = endingSelection(); |
| 978 | 983 |
| 979 if (!m_selectionToDelete.isNonOrphanedRange() || | 984 if (!m_selectionToDelete.isNonOrphanedRange() || |
| 980 !m_selectionToDelete.isContentEditable()) | 985 !m_selectionToDelete.isContentEditable()) |
| 981 return; | 986 return; |
| 982 | 987 |
| 988 RelocatablePosition relocatableReferencePosition(m_referenceMovePosition); |
| 989 |
| 983 // save this to later make the selection with | 990 // save this to later make the selection with |
| 984 TextAffinity affinity = m_selectionToDelete.affinity(); | 991 TextAffinity affinity = m_selectionToDelete.affinity(); |
| 985 | 992 |
| 986 Position downstreamEnd = mostForwardCaretPosition(m_selectionToDelete.end()); | 993 Position downstreamEnd = mostForwardCaretPosition(m_selectionToDelete.end()); |
| 987 bool rootWillStayOpenWithoutPlaceholder = | 994 bool rootWillStayOpenWithoutPlaceholder = |
| 988 downstreamEnd.computeContainerNode() == | 995 downstreamEnd.computeContainerNode() == |
| 989 rootEditableElement(*downstreamEnd.computeContainerNode()) || | 996 rootEditableElement(*downstreamEnd.computeContainerNode()) || |
| 990 (downstreamEnd.computeContainerNode()->isTextNode() && | 997 (downstreamEnd.computeContainerNode()->isTextNode() && |
| 991 downstreamEnd.computeContainerNode()->parentNode() == | 998 downstreamEnd.computeContainerNode()->parentNode() == |
| 992 rootEditableElement(*downstreamEnd.computeContainerNode())); | 999 rootEditableElement(*downstreamEnd.computeContainerNode())); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1079 return; | 1086 return; |
| 1080 } | 1087 } |
| 1081 } | 1088 } |
| 1082 | 1089 |
| 1083 rebalanceWhitespaceAt(m_endingPosition); | 1090 rebalanceWhitespaceAt(m_endingPosition); |
| 1084 | 1091 |
| 1085 calculateTypingStyleAfterDelete(); | 1092 calculateTypingStyleAfterDelete(); |
| 1086 | 1093 |
| 1087 setEndingSelection(createVisibleSelectionDeprecated( | 1094 setEndingSelection(createVisibleSelectionDeprecated( |
| 1088 m_endingPosition, affinity, endingSelection().isDirectional())); | 1095 m_endingPosition, affinity, endingSelection().isDirectional())); |
| 1096 |
| 1097 if (relocatableReferencePosition.position().isNull()) { |
| 1098 clearTransientState(); |
| 1099 return; |
| 1100 } |
| 1101 |
| 1102 // This deletion command is part of a move operation, we need to cleanup after
deletion. |
| 1103 m_referenceMovePosition = relocatableReferencePosition.position(); |
| 1104 // If the node for the destination has been removed as a result of the deletio
n, |
| 1105 // set the destination to the ending point after the deletion. |
| 1106 // Fixes: <rdar://problem/3910425> REGRESSION (Mail): Crash in ReplaceSelectio
nCommand; |
| 1107 // selection is empty, leading to null deref |
| 1108 if (!m_referenceMovePosition.isConnected()) |
| 1109 m_referenceMovePosition = endingSelection().start(); |
| 1110 |
| 1111 // Move selection shouldn't left empty <li> block. |
| 1112 cleanupAfterDeletion( |
| 1113 editingState, createVisiblePositionDeprecated(m_referenceMovePosition)); |
| 1114 if (editingState->isAborted()) |
| 1115 return; |
| 1116 |
| 1089 clearTransientState(); | 1117 clearTransientState(); |
| 1090 } | 1118 } |
| 1091 | 1119 |
| 1092 InputEvent::InputType DeleteSelectionCommand::inputType() const { | 1120 InputEvent::InputType DeleteSelectionCommand::inputType() const { |
| 1093 // |DeleteSelectionCommand| could be used with Cut, Menu Bar deletion and |Typ
ingCommand|. | 1121 // |DeleteSelectionCommand| could be used with Cut, Menu Bar deletion and |Typ
ingCommand|. |
| 1094 // 1. Cut and Menu Bar deletion should rely on correct |m_inputType|. | 1122 // 1. Cut and Menu Bar deletion should rely on correct |m_inputType|. |
| 1095 // 2. |TypingCommand| will supply the |inputType()|, so |m_inputType| could de
fault to |InputType::None|. | 1123 // 2. |TypingCommand| will supply the |inputType()|, so |m_inputType| could de
fault to |InputType::None|. |
| 1096 return m_inputType; | 1124 return m_inputType; |
| 1097 } | 1125 } |
| 1098 | 1126 |
| 1099 // Normally deletion doesn't preserve the typing style that was present before i
t. For example, | 1127 // Normally deletion doesn't preserve the typing style that was present before i
t. For example, |
| 1100 // type a character, Bold, then delete the character and start typing. The Bold
typing style shouldn't | 1128 // type a character, Bold, then delete the character and start typing. The Bold
typing style shouldn't |
| 1101 // stick around. Deletion should preserve a typing style that *it* sets, howeve
r. | 1129 // stick around. Deletion should preserve a typing style that *it* sets, howeve
r. |
| 1102 bool DeleteSelectionCommand::preservesTypingStyle() const { | 1130 bool DeleteSelectionCommand::preservesTypingStyle() const { |
| 1103 return m_typingStyle; | 1131 return m_typingStyle; |
| 1104 } | 1132 } |
| 1105 | 1133 |
| 1106 DEFINE_TRACE(DeleteSelectionCommand) { | 1134 DEFINE_TRACE(DeleteSelectionCommand) { |
| 1107 visitor->trace(m_selectionToDelete); | 1135 visitor->trace(m_selectionToDelete); |
| 1108 visitor->trace(m_upstreamStart); | 1136 visitor->trace(m_upstreamStart); |
| 1109 visitor->trace(m_downstreamStart); | 1137 visitor->trace(m_downstreamStart); |
| 1110 visitor->trace(m_upstreamEnd); | 1138 visitor->trace(m_upstreamEnd); |
| 1111 visitor->trace(m_downstreamEnd); | 1139 visitor->trace(m_downstreamEnd); |
| 1112 visitor->trace(m_endingPosition); | 1140 visitor->trace(m_endingPosition); |
| 1113 visitor->trace(m_leadingWhitespace); | 1141 visitor->trace(m_leadingWhitespace); |
| 1114 visitor->trace(m_trailingWhitespace); | 1142 visitor->trace(m_trailingWhitespace); |
| 1143 visitor->trace(m_referenceMovePosition); |
| 1115 visitor->trace(m_startBlock); | 1144 visitor->trace(m_startBlock); |
| 1116 visitor->trace(m_endBlock); | 1145 visitor->trace(m_endBlock); |
| 1117 visitor->trace(m_typingStyle); | 1146 visitor->trace(m_typingStyle); |
| 1118 visitor->trace(m_deleteIntoBlockquoteStyle); | 1147 visitor->trace(m_deleteIntoBlockquoteStyle); |
| 1119 visitor->trace(m_startRoot); | 1148 visitor->trace(m_startRoot); |
| 1120 visitor->trace(m_endRoot); | 1149 visitor->trace(m_endRoot); |
| 1121 visitor->trace(m_startTableRow); | 1150 visitor->trace(m_startTableRow); |
| 1122 visitor->trace(m_endTableRow); | 1151 visitor->trace(m_endTableRow); |
| 1123 visitor->trace(m_temporaryPlaceholder); | 1152 visitor->trace(m_temporaryPlaceholder); |
| 1124 CompositeEditCommand::trace(visitor); | 1153 CompositeEditCommand::trace(visitor); |
| 1125 } | 1154 } |
| 1126 | 1155 |
| 1127 } // namespace blink | 1156 } // namespace blink |
| OLD | NEW |