| 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 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 m_sanitizeMarkup(sanitizeMarkup), | 105 m_sanitizeMarkup(sanitizeMarkup), |
| 106 m_inputType(inputType), | 106 m_inputType(inputType), |
| 107 m_selectionToDelete(selection), | 107 m_selectionToDelete(selection), |
| 108 m_startBlock(nullptr), | 108 m_startBlock(nullptr), |
| 109 m_endBlock(nullptr), | 109 m_endBlock(nullptr), |
| 110 m_typingStyle(nullptr), | 110 m_typingStyle(nullptr), |
| 111 m_deleteIntoBlockquoteStyle(nullptr) {} | 111 m_deleteIntoBlockquoteStyle(nullptr) {} |
| 112 | 112 |
| 113 void DeleteSelectionCommand::initializeStartEnd(Position& start, | 113 void DeleteSelectionCommand::initializeStartEnd(Position& start, |
| 114 Position& end) { | 114 Position& end) { |
| 115 DCHECK(!document().needsLayoutTreeUpdate()); |
| 116 DocumentLifecycle::DisallowTransitionScope disallowTransition( |
| 117 document().lifecycle()); |
| 118 |
| 115 HTMLElement* startSpecialContainer = nullptr; | 119 HTMLElement* startSpecialContainer = nullptr; |
| 116 HTMLElement* endSpecialContainer = nullptr; | 120 HTMLElement* endSpecialContainer = nullptr; |
| 117 | 121 |
| 118 start = m_selectionToDelete.start(); | 122 start = m_selectionToDelete.start(); |
| 119 end = m_selectionToDelete.end(); | 123 end = m_selectionToDelete.end(); |
| 120 | 124 |
| 121 // For HRs, we'll get a position at (HR,1) when hitting delete from the | 125 // For HRs, we'll get a position at (HR,1) when hitting delete from the |
| 122 // beginning of the previous line, or (HR,0) when forward deleting, but in | 126 // beginning of the previous line, or (HR,0) when forward deleting, but in |
| 123 // these cases, we want to delete it, so manually expand the selection | 127 // these cases, we want to delete it, so manually expand the selection |
| 124 if (isHTMLHRElement(*start.anchorNode())) | 128 if (isHTMLHRElement(*start.anchorNode())) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 136 endSpecialContainer = 0; | 140 endSpecialContainer = 0; |
| 137 | 141 |
| 138 Position s = | 142 Position s = |
| 139 positionBeforeContainingSpecialElement(start, &startSpecialContainer); | 143 positionBeforeContainingSpecialElement(start, &startSpecialContainer); |
| 140 Position e = | 144 Position e = |
| 141 positionAfterContainingSpecialElement(end, &endSpecialContainer); | 145 positionAfterContainingSpecialElement(end, &endSpecialContainer); |
| 142 | 146 |
| 143 if (!startSpecialContainer && !endSpecialContainer) | 147 if (!startSpecialContainer && !endSpecialContainer) |
| 144 break; | 148 break; |
| 145 | 149 |
| 146 if (createVisiblePositionDeprecated(start).deepEquivalent() != | 150 if (createVisiblePosition(start).deepEquivalent() != |
| 147 m_selectionToDelete.visibleStartDeprecated().deepEquivalent() || | 151 m_selectionToDelete.visibleStart().deepEquivalent() || |
| 148 createVisiblePositionDeprecated(end).deepEquivalent() != | 152 createVisiblePosition(end).deepEquivalent() != |
| 149 m_selectionToDelete.visibleEndDeprecated().deepEquivalent()) | 153 m_selectionToDelete.visibleEnd().deepEquivalent()) |
| 150 break; | 154 break; |
| 151 | 155 |
| 152 // If we're going to expand to include the startSpecialContainer, it must be | 156 // If we're going to expand to include the startSpecialContainer, it must be |
| 153 // fully selected. | 157 // fully selected. |
| 154 if (startSpecialContainer && !endSpecialContainer && | 158 if (startSpecialContainer && !endSpecialContainer && |
| 155 comparePositions(Position::inParentAfterNode(*startSpecialContainer), | 159 comparePositions(Position::inParentAfterNode(*startSpecialContainer), |
| 156 end) > -1) | 160 end) > -1) |
| 157 break; | 161 break; |
| 158 | 162 |
| 159 // If we're going to expand to include the endSpecialContainer, it must be | 163 // If we're going to expand to include the endSpecialContainer, it must be |
| (...skipping 18 matching lines...) Expand all Loading... |
| 178 } else { | 182 } else { |
| 179 start = s; | 183 start = s; |
| 180 end = e; | 184 end = e; |
| 181 } | 185 } |
| 182 } | 186 } |
| 183 } | 187 } |
| 184 | 188 |
| 185 void DeleteSelectionCommand::setStartingSelectionOnSmartDelete( | 189 void DeleteSelectionCommand::setStartingSelectionOnSmartDelete( |
| 186 const Position& start, | 190 const Position& start, |
| 187 const Position& end) { | 191 const Position& end) { |
| 192 DCHECK(!document().needsLayoutTreeUpdate()); |
| 193 DocumentLifecycle::DisallowTransitionScope disallowTransition( |
| 194 document().lifecycle()); |
| 195 |
| 188 bool isBaseFirst = startingSelection().isBaseFirst(); | 196 bool isBaseFirst = startingSelection().isBaseFirst(); |
| 189 VisiblePosition newBase = | 197 VisiblePosition newBase = createVisiblePosition(isBaseFirst ? start : end); |
| 190 createVisiblePositionDeprecated(isBaseFirst ? start : end); | 198 VisiblePosition newExtent = createVisiblePosition(isBaseFirst ? end : start); |
| 191 VisiblePosition newExtent = | 199 setStartingSelection(createVisibleSelection( |
| 192 createVisiblePositionDeprecated(isBaseFirst ? end : start); | |
| 193 setStartingSelection(createVisibleSelectionDeprecated( | |
| 194 newBase, newExtent, startingSelection().isDirectional())); | 200 newBase, newExtent, startingSelection().isDirectional())); |
| 195 } | 201 } |
| 196 | 202 |
| 197 void DeleteSelectionCommand::initializePositionData( | 203 void DeleteSelectionCommand::initializePositionData( |
| 198 EditingState* editingState) { | 204 EditingState* editingState) { |
| 205 DCHECK(!document().needsLayoutTreeUpdate()); |
| 206 DocumentLifecycle::DisallowTransitionScope disallowTransition( |
| 207 document().lifecycle()); |
| 208 |
| 199 Position start, end; | 209 Position start, end; |
| 200 initializeStartEnd(start, end); | 210 initializeStartEnd(start, end); |
| 201 DCHECK(start.isNotNull()); | 211 DCHECK(start.isNotNull()); |
| 202 DCHECK(end.isNotNull()); | 212 DCHECK(end.isNotNull()); |
| 203 if (!isEditablePosition(start)) { | 213 if (!isEditablePosition(start)) { |
| 204 editingState->abort(); | 214 editingState->abort(); |
| 205 return; | 215 return; |
| 206 } | 216 } |
| 207 if (!isEditablePosition(end)) { | 217 if (!isEditablePosition(end)) { |
| 208 Node* highestRoot = highestEditableRoot(start); | 218 Node* highestRoot = highestEditableRoot(start); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 233 CanCrossEditingBoundary); | 243 CanCrossEditingBoundary); |
| 234 // FIXME: This isn't right. A borderless table with two rows and a single | 244 // FIXME: This isn't right. A borderless table with two rows and a single |
| 235 // column would appear as two paragraphs. | 245 // column would appear as two paragraphs. |
| 236 if (endCell && endCell != startCell) | 246 if (endCell && endCell != startCell) |
| 237 m_mergeBlocksAfterDelete = false; | 247 m_mergeBlocksAfterDelete = false; |
| 238 | 248 |
| 239 // Usually the start and the end of the selection to delete are pulled | 249 // Usually the start and the end of the selection to delete are pulled |
| 240 // together as a result of the deletion. Sometimes they aren't (like when no | 250 // together as a result of the deletion. Sometimes they aren't (like when no |
| 241 // merge is requested), so we must choose one position to hold the caret | 251 // merge is requested), so we must choose one position to hold the caret |
| 242 // and receive the placeholder after deletion. | 252 // and receive the placeholder after deletion. |
| 243 VisiblePosition visibleEnd = createVisiblePositionDeprecated(m_downstreamEnd); | 253 VisiblePosition visibleEnd = createVisiblePosition(m_downstreamEnd); |
| 244 if (m_mergeBlocksAfterDelete && !isEndOfParagraphDeprecated(visibleEnd)) | 254 if (m_mergeBlocksAfterDelete && !isEndOfParagraph(visibleEnd)) |
| 245 m_endingPosition = m_downstreamEnd; | 255 m_endingPosition = m_downstreamEnd; |
| 246 else | 256 else |
| 247 m_endingPosition = m_downstreamStart; | 257 m_endingPosition = m_downstreamStart; |
| 248 | 258 |
| 249 // We don't want to merge into a block if it will mean changing the quote | 259 // We don't want to merge into a block if it will mean changing the quote |
| 250 // level of content after deleting selections that contain a whole number | 260 // level of content after deleting selections that contain a whole number |
| 251 // paragraphs plus a line break, since it is unclear to most users that such a | 261 // paragraphs plus a line break, since it is unclear to most users that such a |
| 252 // selection actually ends at the start of the next paragraph. This matches | 262 // selection actually ends at the start of the next paragraph. This matches |
| 253 // TextEdit behavior for indented paragraphs. | 263 // TextEdit behavior for indented paragraphs. |
| 254 // Only apply this rule if the endingSelection is a range selection. If it is | 264 // Only apply this rule if the endingSelection is a range selection. If it is |
| 255 // a caret, then other operations have created the selection we're deleting | 265 // a caret, then other operations have created the selection we're deleting |
| 256 // (like the process of creating a selection to delete during a backspace), | 266 // (like the process of creating a selection to delete during a backspace), |
| 257 // and the user isn't in the situation described above. | 267 // and the user isn't in the situation described above. |
| 258 if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end) && | 268 if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end) && |
| 259 isStartOfParagraphDeprecated(visibleEnd) && | 269 isStartOfParagraph(visibleEnd) && |
| 260 isStartOfParagraph(createVisiblePositionDeprecated(start)) && | 270 isStartOfParagraph(createVisiblePosition(start)) && |
| 261 endingSelection().isRange()) { | 271 endingSelection().isRange()) { |
| 262 m_mergeBlocksAfterDelete = false; | 272 m_mergeBlocksAfterDelete = false; |
| 263 m_pruneStartBlockIfNecessary = true; | 273 m_pruneStartBlockIfNecessary = true; |
| 264 } | 274 } |
| 265 | 275 |
| 266 // Handle leading and trailing whitespace, as well as smart delete adjustments | 276 // Handle leading and trailing whitespace, as well as smart delete adjustments |
| 267 // to the selection | 277 // to the selection |
| 268 m_leadingWhitespace = leadingWhitespacePosition( | 278 m_leadingWhitespace = leadingWhitespacePosition( |
| 269 m_upstreamStart, m_selectionToDelete.affinity()); | 279 m_upstreamStart, m_selectionToDelete.affinity()); |
| 270 m_trailingWhitespace = | 280 m_trailingWhitespace = |
| 271 trailingWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY); | 281 trailingWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY); |
| 272 | 282 |
| 273 if (m_smartDelete) { | 283 if (m_smartDelete) { |
| 274 // skip smart delete if the selection to delete already starts or ends with | 284 // skip smart delete if the selection to delete already starts or ends with |
| 275 // whitespace | 285 // whitespace |
| 276 Position pos = createVisiblePositionDeprecated( | 286 Position pos = |
| 277 m_upstreamStart, m_selectionToDelete.affinity()) | 287 createVisiblePosition(m_upstreamStart, m_selectionToDelete.affinity()) |
| 278 .deepEquivalent(); | 288 .deepEquivalent(); |
| 279 bool skipSmartDelete = | 289 bool skipSmartDelete = |
| 280 trailingWhitespacePosition(pos, VP_DEFAULT_AFFINITY, | 290 trailingWhitespacePosition(pos, VP_DEFAULT_AFFINITY, |
| 281 ConsiderNonCollapsibleWhitespace) | 291 ConsiderNonCollapsibleWhitespace) |
| 282 .isNotNull(); | 292 .isNotNull(); |
| 283 if (!skipSmartDelete) | 293 if (!skipSmartDelete) |
| 284 skipSmartDelete = | 294 skipSmartDelete = |
| 285 leadingWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY, | 295 leadingWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY, |
| 286 ConsiderNonCollapsibleWhitespace) | 296 ConsiderNonCollapsibleWhitespace) |
| 287 .isNotNull(); | 297 .isNotNull(); |
| 288 | 298 |
| 289 // extend selection upstream if there is whitespace there | 299 // extend selection upstream if there is whitespace there |
| 290 bool hasLeadingWhitespaceBeforeAdjustment = | 300 bool hasLeadingWhitespaceBeforeAdjustment = |
| 291 leadingWhitespacePosition(m_upstreamStart, | 301 leadingWhitespacePosition(m_upstreamStart, |
| 292 m_selectionToDelete.affinity(), | 302 m_selectionToDelete.affinity(), |
| 293 ConsiderNonCollapsibleWhitespace) | 303 ConsiderNonCollapsibleWhitespace) |
| 294 .isNotNull(); | 304 .isNotNull(); |
| 295 if (!skipSmartDelete && hasLeadingWhitespaceBeforeAdjustment) { | 305 if (!skipSmartDelete && hasLeadingWhitespaceBeforeAdjustment) { |
| 296 VisiblePosition visiblePos = | 306 VisiblePosition visiblePos = previousPositionOf( |
| 297 previousPositionOf(createVisiblePositionDeprecated( | 307 createVisiblePosition(m_upstreamStart, VP_DEFAULT_AFFINITY)); |
| 298 m_upstreamStart, VP_DEFAULT_AFFINITY)); | |
| 299 pos = visiblePos.deepEquivalent(); | 308 pos = visiblePos.deepEquivalent(); |
| 300 // Expand out one character upstream for smart delete and recalculate | 309 // Expand out one character upstream for smart delete and recalculate |
| 301 // positions based on this change. | 310 // positions based on this change. |
| 302 m_upstreamStart = mostBackwardCaretPosition(pos); | 311 m_upstreamStart = mostBackwardCaretPosition(pos); |
| 303 m_downstreamStart = mostForwardCaretPosition(pos); | 312 m_downstreamStart = mostForwardCaretPosition(pos); |
| 304 m_leadingWhitespace = | 313 m_leadingWhitespace = |
| 305 leadingWhitespacePosition(m_upstreamStart, visiblePos.affinity()); | 314 leadingWhitespacePosition(m_upstreamStart, visiblePos.affinity()); |
| 306 | 315 |
| 307 setStartingSelectionOnSmartDelete(m_upstreamStart, m_upstreamEnd); | 316 setStartingSelectionOnSmartDelete(m_upstreamStart, m_upstreamEnd); |
| 308 } | 317 } |
| 309 | 318 |
| 310 // trailing whitespace is only considered for smart delete if there is no | 319 // trailing whitespace is only considered for smart delete if there is no |
| 311 // leading whitespace, as in the case where you double-click the first word | 320 // leading whitespace, as in the case where you double-click the first word |
| 312 // of a paragraph. | 321 // of a paragraph. |
| 313 if (!skipSmartDelete && !hasLeadingWhitespaceBeforeAdjustment && | 322 if (!skipSmartDelete && !hasLeadingWhitespaceBeforeAdjustment && |
| 314 trailingWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY, | 323 trailingWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY, |
| 315 ConsiderNonCollapsibleWhitespace) | 324 ConsiderNonCollapsibleWhitespace) |
| 316 .isNotNull()) { | 325 .isNotNull()) { |
| 317 // Expand out one character downstream for smart delete and recalculate | 326 // Expand out one character downstream for smart delete and recalculate |
| 318 // positions based on this change. | 327 // positions based on this change. |
| 319 pos = nextPositionOf(createVisiblePositionDeprecated(m_downstreamEnd, | 328 pos = nextPositionOf( |
| 320 VP_DEFAULT_AFFINITY)) | 329 createVisiblePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY)) |
| 321 .deepEquivalent(); | 330 .deepEquivalent(); |
| 322 m_upstreamEnd = mostBackwardCaretPosition(pos); | 331 m_upstreamEnd = mostBackwardCaretPosition(pos); |
| 323 m_downstreamEnd = mostForwardCaretPosition(pos); | 332 m_downstreamEnd = mostForwardCaretPosition(pos); |
| 324 m_trailingWhitespace = | 333 m_trailingWhitespace = |
| 325 trailingWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY); | 334 trailingWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY); |
| 326 | 335 |
| 327 setStartingSelectionOnSmartDelete(m_downstreamStart, m_downstreamEnd); | 336 setStartingSelectionOnSmartDelete(m_downstreamStart, m_downstreamEnd); |
| 328 } | 337 } |
| 329 } | 338 } |
| 330 | 339 |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 772 return; | 781 return; |
| 773 | 782 |
| 774 // FIXME: The deletion algorithm shouldn't let this happen. | 783 // FIXME: The deletion algorithm shouldn't let this happen. |
| 775 if (comparePositions(m_upstreamStart, m_downstreamEnd) > 0) | 784 if (comparePositions(m_upstreamStart, m_downstreamEnd) > 0) |
| 776 return; | 785 return; |
| 777 | 786 |
| 778 // There's nothing to merge. | 787 // There's nothing to merge. |
| 779 if (m_upstreamStart == m_downstreamEnd) | 788 if (m_upstreamStart == m_downstreamEnd) |
| 780 return; | 789 return; |
| 781 | 790 |
| 791 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 792 |
| 782 VisiblePosition startOfParagraphToMove = | 793 VisiblePosition startOfParagraphToMove = |
| 783 createVisiblePositionDeprecated(m_downstreamEnd); | 794 createVisiblePosition(m_downstreamEnd); |
| 784 VisiblePosition mergeDestination = | 795 VisiblePosition mergeDestination = createVisiblePosition(m_upstreamStart); |
| 785 createVisiblePositionDeprecated(m_upstreamStart); | |
| 786 | 796 |
| 787 // m_downstreamEnd's block has been emptied out by deletion. There is no | 797 // m_downstreamEnd's block has been emptied out by deletion. There is no |
| 788 // content inside of it to move, so just remove it. | 798 // content inside of it to move, so just remove it. |
| 789 Element* endBlock = enclosingBlock(m_downstreamEnd.anchorNode()); | 799 Element* endBlock = enclosingBlock(m_downstreamEnd.anchorNode()); |
| 790 if (!endBlock || | 800 if (!endBlock || |
| 791 !endBlock->contains( | 801 !endBlock->contains( |
| 792 startOfParagraphToMove.deepEquivalent().anchorNode()) || | 802 startOfParagraphToMove.deepEquivalent().anchorNode()) || |
| 793 !startOfParagraphToMove.deepEquivalent().anchorNode()) { | 803 !startOfParagraphToMove.deepEquivalent().anchorNode()) { |
| 794 removeNode(enclosingBlock(m_downstreamEnd.anchorNode()), editingState); | 804 removeNode(enclosingBlock(m_downstreamEnd.anchorNode()), editingState); |
| 795 return; | 805 return; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 814 document().updateStyleAndLayoutIgnorePendingStylesheets(); | 824 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 815 mergeDestination = createVisiblePosition(m_upstreamStart); | 825 mergeDestination = createVisiblePosition(m_upstreamStart); |
| 816 startOfParagraphToMove = | 826 startOfParagraphToMove = |
| 817 createVisiblePosition(storedStartOfParagraphToMove); | 827 createVisiblePosition(storedStartOfParagraphToMove); |
| 818 } | 828 } |
| 819 | 829 |
| 820 if (mergeDestination.deepEquivalent() == | 830 if (mergeDestination.deepEquivalent() == |
| 821 startOfParagraphToMove.deepEquivalent()) | 831 startOfParagraphToMove.deepEquivalent()) |
| 822 return; | 832 return; |
| 823 | 833 |
| 824 VisiblePosition endOfParagraphToMove = endOfParagraphDeprecated( | 834 VisiblePosition endOfParagraphToMove = |
| 825 startOfParagraphToMove, CanSkipOverEditingBoundary); | 835 endOfParagraph(startOfParagraphToMove, CanSkipOverEditingBoundary); |
| 826 | 836 |
| 827 if (mergeDestination.deepEquivalent() == | 837 if (mergeDestination.deepEquivalent() == |
| 828 endOfParagraphToMove.deepEquivalent()) | 838 endOfParagraphToMove.deepEquivalent()) |
| 829 return; | 839 return; |
| 830 | 840 |
| 831 // If the merge destination and source to be moved are both list items of | 841 // If the merge destination and source to be moved are both list items of |
| 832 // different lists, merge them into single list. | 842 // different lists, merge them into single list. |
| 833 Node* listItemInFirstParagraph = | 843 Node* listItemInFirstParagraph = |
| 834 enclosingNodeOfType(m_upstreamStart, isListItem); | 844 enclosingNodeOfType(m_upstreamStart, isListItem); |
| 835 Node* listItemInSecondParagraph = | 845 Node* listItemInSecondParagraph = |
| 836 enclosingNodeOfType(m_downstreamEnd, isListItem); | 846 enclosingNodeOfType(m_downstreamEnd, isListItem); |
| 837 if (listItemInFirstParagraph && listItemInSecondParagraph && | 847 if (listItemInFirstParagraph && listItemInSecondParagraph && |
| 838 listItemInFirstParagraph->parentElement() != | 848 listItemInFirstParagraph->parentElement() != |
| 839 listItemInSecondParagraph->parentElement() && | 849 listItemInSecondParagraph->parentElement() && |
| 840 canMergeLists(listItemInFirstParagraph->parentElement(), | 850 canMergeLists(listItemInFirstParagraph->parentElement(), |
| 841 listItemInSecondParagraph->parentElement())) { | 851 listItemInSecondParagraph->parentElement())) { |
| 842 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), | 852 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), |
| 843 listItemInSecondParagraph->parentElement(), | 853 listItemInSecondParagraph->parentElement(), |
| 844 editingState); | 854 editingState); |
| 845 if (editingState->isAborted()) | 855 if (editingState->isAborted()) |
| 846 return; | 856 return; |
| 847 m_endingPosition = mergeDestination.deepEquivalent(); | 857 m_endingPosition = mergeDestination.deepEquivalent(); |
| 848 return; | 858 return; |
| 849 } | 859 } |
| 850 | 860 |
| 851 // The rule for merging into an empty block is: only do so if its farther to | 861 // The rule for merging into an empty block is: only do so if its farther to |
| 852 // the right. | 862 // the right. |
| 853 // FIXME: Consider RTL. | 863 // FIXME: Consider RTL. |
| 854 if (!m_startsAtEmptyLine && isStartOfParagraphDeprecated(mergeDestination) && | 864 if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && |
| 855 absoluteCaretBoundsOf(startOfParagraphToMove).x() > | 865 absoluteCaretBoundsOf(startOfParagraphToMove).x() > |
| 856 absoluteCaretBoundsOf(mergeDestination).x()) { | 866 absoluteCaretBoundsOf(mergeDestination).x()) { |
| 857 if (isHTMLBRElement( | 867 if (isHTMLBRElement( |
| 858 *mostForwardCaretPosition(mergeDestination.deepEquivalent()) | 868 *mostForwardCaretPosition(mergeDestination.deepEquivalent()) |
| 859 .anchorNode())) { | 869 .anchorNode())) { |
| 860 removeNodeAndPruneAncestors( | 870 removeNodeAndPruneAncestors( |
| 861 mostForwardCaretPosition(mergeDestination.deepEquivalent()) | 871 mostForwardCaretPosition(mergeDestination.deepEquivalent()) |
| 862 .anchorNode(), | 872 .anchorNode(), |
| 863 editingState); | 873 editingState); |
| 864 if (editingState->isAborted()) | 874 if (editingState->isAborted()) |
| 865 return; | 875 return; |
| 866 m_endingPosition = startOfParagraphToMove.deepEquivalent(); | 876 m_endingPosition = startOfParagraphToMove.deepEquivalent(); |
| 867 return; | 877 return; |
| 868 } | 878 } |
| 869 } | 879 } |
| 870 | 880 |
| 871 // Block images, tables and horizontal rules cannot be made inline with | 881 // Block images, tables and horizontal rules cannot be made inline with |
| 872 // content at mergeDestination. If there is any | 882 // content at mergeDestination. If there is any |
| 873 // (!isStartOfParagraphDeprecated(mergeDestination)), don't merge, just move | 883 // (!isStartOfParagraphDeprecated(mergeDestination)), don't merge, just move |
| 874 // the caret to just before the selection we deleted. See | 884 // the caret to just before the selection we deleted. See |
| 875 // https://bugs.webkit.org/show_bug.cgi?id=25439 | 885 // https://bugs.webkit.org/show_bug.cgi?id=25439 |
| 876 if (isRenderedAsNonInlineTableImageOrHR( | 886 if (isRenderedAsNonInlineTableImageOrHR( |
| 877 startOfParagraphToMove.deepEquivalent().anchorNode()) && | 887 startOfParagraphToMove.deepEquivalent().anchorNode()) && |
| 878 !isStartOfParagraphDeprecated(mergeDestination)) { | 888 !isStartOfParagraph(mergeDestination)) { |
| 879 m_endingPosition = m_upstreamStart; | 889 m_endingPosition = m_upstreamStart; |
| 880 return; | 890 return; |
| 881 } | 891 } |
| 882 | 892 |
| 883 // moveParagraphs will insert placeholders if it removes blocks that would | 893 // moveParagraphs will insert placeholders if it removes blocks that would |
| 884 // require their use, don't let block removals that it does cause the | 894 // require their use, don't let block removals that it does cause the |
| 885 // insertion of *another* placeholder. | 895 // insertion of *another* placeholder. |
| 886 bool needPlaceholder = m_needPlaceholder; | 896 bool needPlaceholder = m_needPlaceholder; |
| 887 bool paragraphToMergeIsEmpty = startOfParagraphToMove.deepEquivalent() == | 897 bool paragraphToMergeIsEmpty = startOfParagraphToMove.deepEquivalent() == |
| 888 endOfParagraphToMove.deepEquivalent(); | 898 endOfParagraphToMove.deepEquivalent(); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 | 1032 |
| 1023 if (!m_selectionToDelete.isNonOrphanedRange() || | 1033 if (!m_selectionToDelete.isNonOrphanedRange() || |
| 1024 !m_selectionToDelete.isContentEditable()) | 1034 !m_selectionToDelete.isContentEditable()) |
| 1025 return; | 1035 return; |
| 1026 | 1036 |
| 1027 RelocatablePosition relocatableReferencePosition(m_referenceMovePosition); | 1037 RelocatablePosition relocatableReferencePosition(m_referenceMovePosition); |
| 1028 | 1038 |
| 1029 // save this to later make the selection with | 1039 // save this to later make the selection with |
| 1030 TextAffinity affinity = m_selectionToDelete.affinity(); | 1040 TextAffinity affinity = m_selectionToDelete.affinity(); |
| 1031 | 1041 |
| 1042 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 1043 |
| 1032 Position downstreamEnd = mostForwardCaretPosition(m_selectionToDelete.end()); | 1044 Position downstreamEnd = mostForwardCaretPosition(m_selectionToDelete.end()); |
| 1033 bool rootWillStayOpenWithoutPlaceholder = | 1045 bool rootWillStayOpenWithoutPlaceholder = |
| 1034 downstreamEnd.computeContainerNode() == | 1046 downstreamEnd.computeContainerNode() == |
| 1035 rootEditableElement(*downstreamEnd.computeContainerNode()) || | 1047 rootEditableElement(*downstreamEnd.computeContainerNode()) || |
| 1036 (downstreamEnd.computeContainerNode()->isTextNode() && | 1048 (downstreamEnd.computeContainerNode()->isTextNode() && |
| 1037 downstreamEnd.computeContainerNode()->parentNode() == | 1049 downstreamEnd.computeContainerNode()->parentNode() == |
| 1038 rootEditableElement(*downstreamEnd.computeContainerNode())); | 1050 rootEditableElement(*downstreamEnd.computeContainerNode())); |
| 1039 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition( | 1051 bool lineBreakAtEndOfSelectionToDelete = |
| 1040 m_selectionToDelete.visibleEndDeprecated()); | 1052 lineBreakExistsAtVisiblePosition(m_selectionToDelete.visibleEnd()); |
| 1041 m_needPlaceholder = | 1053 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder && |
| 1042 !rootWillStayOpenWithoutPlaceholder && | 1054 isStartOfParagraph(m_selectionToDelete.visibleStart(), |
| 1043 isStartOfParagraphDeprecated(m_selectionToDelete.visibleStartDeprecated(), | 1055 CanCrossEditingBoundary) && |
| 1044 CanCrossEditingBoundary) && | 1056 isEndOfParagraph(m_selectionToDelete.visibleEnd(), |
| 1045 isEndOfParagraphDeprecated(m_selectionToDelete.visibleEndDeprecated(), | 1057 CanCrossEditingBoundary) && |
| 1046 CanCrossEditingBoundary) && | 1058 !lineBreakAtEndOfSelectionToDelete; |
| 1047 !lineBreakAtEndOfSelectionToDelete; | |
| 1048 if (m_needPlaceholder) { | 1059 if (m_needPlaceholder) { |
| 1049 // Don't need a placeholder when deleting a selection that starts just | 1060 // Don't need a placeholder when deleting a selection that starts just |
| 1050 // before a table and ends inside it (we do need placeholders to hold | 1061 // before a table and ends inside it (we do need placeholders to hold |
| 1051 // open empty cells, but that's handled elsewhere). | 1062 // open empty cells, but that's handled elsewhere). |
| 1052 if (Element* table = tableElementJustAfter( | 1063 if (Element* table = |
| 1053 m_selectionToDelete.visibleStartDeprecated())) { | 1064 tableElementJustAfter(m_selectionToDelete.visibleStart())) { |
| 1054 if (m_selectionToDelete.end().anchorNode()->isDescendantOf(table)) | 1065 if (m_selectionToDelete.end().anchorNode()->isDescendantOf(table)) |
| 1055 m_needPlaceholder = false; | 1066 m_needPlaceholder = false; |
| 1056 } | 1067 } |
| 1057 } | 1068 } |
| 1058 | 1069 |
| 1059 // set up our state | 1070 // set up our state |
| 1060 initializePositionData(editingState); | 1071 initializePositionData(editingState); |
| 1061 if (editingState->isAborted()) | 1072 if (editingState->isAborted()) |
| 1062 return; | 1073 return; |
| 1063 | 1074 |
| 1064 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition( | 1075 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition( |
| 1065 previousPositionOf(createVisiblePositionDeprecated(m_upstreamStart))); | 1076 previousPositionOf(createVisiblePosition(m_upstreamStart))); |
| 1066 | 1077 |
| 1067 // Delete any text that may hinder our ability to fixup whitespace after the | 1078 // Delete any text that may hinder our ability to fixup whitespace after the |
| 1068 // delete | 1079 // delete |
| 1069 deleteInsignificantTextDownstream(m_trailingWhitespace); | 1080 deleteInsignificantTextDownstream(m_trailingWhitespace); |
| 1070 | 1081 |
| 1071 saveTypingStyleState(); | 1082 saveTypingStyleState(); |
| 1072 | 1083 |
| 1073 // deleting just a BR is handled specially, at least because we do not | 1084 // deleting just a BR is handled specially, at least because we do not |
| 1074 // want to replace it with a placeholder BR! | 1085 // want to replace it with a placeholder BR! |
| 1075 bool brResult = handleSpecialCaseBRDelete(editingState); | 1086 bool brResult = handleSpecialCaseBRDelete(editingState); |
| 1076 if (editingState->isAborted()) | 1087 if (editingState->isAborted()) |
| 1077 return; | 1088 return; |
| 1078 if (brResult) { | 1089 if (brResult) { |
| 1079 calculateTypingStyleAfterDelete(); | 1090 calculateTypingStyleAfterDelete(); |
| 1080 setEndingSelection(createVisibleSelectionDeprecated( | 1091 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 1092 setEndingSelection(createVisibleSelection( |
| 1081 m_endingPosition, affinity, endingSelection().isDirectional())); | 1093 m_endingPosition, affinity, endingSelection().isDirectional())); |
| 1082 clearTransientState(); | 1094 clearTransientState(); |
| 1083 rebalanceWhitespace(); | 1095 rebalanceWhitespace(); |
| 1084 return; | 1096 return; |
| 1085 } | 1097 } |
| 1086 | 1098 |
| 1087 handleGeneralDelete(editingState); | 1099 handleGeneralDelete(editingState); |
| 1088 if (editingState->isAborted()) | 1100 if (editingState->isAborted()) |
| 1089 return; | 1101 return; |
| 1090 | 1102 |
| 1091 fixupWhitespace(); | 1103 fixupWhitespace(); |
| 1092 | 1104 |
| 1093 mergeParagraphs(editingState); | 1105 mergeParagraphs(editingState); |
| 1094 if (editingState->isAborted()) | 1106 if (editingState->isAborted()) |
| 1095 return; | 1107 return; |
| 1096 | 1108 |
| 1097 removePreviouslySelectedEmptyTableRows(editingState); | 1109 removePreviouslySelectedEmptyTableRows(editingState); |
| 1098 if (editingState->isAborted()) | 1110 if (editingState->isAborted()) |
| 1099 return; | 1111 return; |
| 1100 | 1112 |
| 1101 if (!m_needPlaceholder && rootWillStayOpenWithoutPlaceholder) { | 1113 if (!m_needPlaceholder && rootWillStayOpenWithoutPlaceholder) { |
| 1102 VisiblePosition visualEnding = | 1114 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 1103 createVisiblePositionDeprecated(m_endingPosition); | 1115 VisiblePosition visualEnding = createVisiblePosition(m_endingPosition); |
| 1104 bool hasPlaceholder = | 1116 bool hasPlaceholder = |
| 1105 lineBreakExistsAtVisiblePosition(visualEnding) && | 1117 lineBreakExistsAtVisiblePosition(visualEnding) && |
| 1106 nextPositionOf(visualEnding, CannotCrossEditingBoundary).isNull(); | 1118 nextPositionOf(visualEnding, CannotCrossEditingBoundary).isNull(); |
| 1107 m_needPlaceholder = hasPlaceholder && lineBreakBeforeStart && | 1119 m_needPlaceholder = hasPlaceholder && lineBreakBeforeStart && |
| 1108 !lineBreakAtEndOfSelectionToDelete; | 1120 !lineBreakAtEndOfSelectionToDelete; |
| 1109 } | 1121 } |
| 1110 | 1122 |
| 1111 HTMLBRElement* placeholder = | 1123 HTMLBRElement* placeholder = |
| 1112 m_needPlaceholder ? HTMLBRElement::create(document()) : nullptr; | 1124 m_needPlaceholder ? HTMLBRElement::create(document()) : nullptr; |
| 1113 | 1125 |
| 1114 if (placeholder) { | 1126 if (placeholder) { |
| 1115 if (m_sanitizeMarkup) { | 1127 if (m_sanitizeMarkup) { |
| 1116 removeRedundantBlocks(editingState); | 1128 removeRedundantBlocks(editingState); |
| 1117 if (editingState->isAborted()) | 1129 if (editingState->isAborted()) |
| 1118 return; | 1130 return; |
| 1119 } | 1131 } |
| 1120 // handleGeneralDelete cause DOM mutation events so |m_endingPosition| | 1132 // handleGeneralDelete cause DOM mutation events so |m_endingPosition| |
| 1121 // can be out of document. | 1133 // can be out of document. |
| 1122 if (m_endingPosition.isConnected()) { | 1134 if (m_endingPosition.isConnected()) { |
| 1123 insertNodeAt(placeholder, m_endingPosition, editingState); | 1135 insertNodeAt(placeholder, m_endingPosition, editingState); |
| 1124 if (editingState->isAborted()) | 1136 if (editingState->isAborted()) |
| 1125 return; | 1137 return; |
| 1126 } | 1138 } |
| 1127 } | 1139 } |
| 1128 | 1140 |
| 1129 rebalanceWhitespaceAt(m_endingPosition); | 1141 rebalanceWhitespaceAt(m_endingPosition); |
| 1130 | 1142 |
| 1131 calculateTypingStyleAfterDelete(); | 1143 calculateTypingStyleAfterDelete(); |
| 1132 | 1144 |
| 1133 setEndingSelection(createVisibleSelectionDeprecated( | 1145 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 1134 m_endingPosition, affinity, endingSelection().isDirectional())); | 1146 |
| 1147 setEndingSelection(createVisibleSelection(m_endingPosition, affinity, |
| 1148 endingSelection().isDirectional())); |
| 1135 | 1149 |
| 1136 if (relocatableReferencePosition.position().isNull()) { | 1150 if (relocatableReferencePosition.position().isNull()) { |
| 1137 clearTransientState(); | 1151 clearTransientState(); |
| 1138 return; | 1152 return; |
| 1139 } | 1153 } |
| 1140 | 1154 |
| 1141 // This deletion command is part of a move operation, we need to cleanup after | 1155 // This deletion command is part of a move operation, we need to cleanup after |
| 1142 // deletion. | 1156 // deletion. |
| 1143 m_referenceMovePosition = relocatableReferencePosition.position(); | 1157 m_referenceMovePosition = relocatableReferencePosition.position(); |
| 1144 // If the node for the destination has been removed as a result of the | 1158 // If the node for the destination has been removed as a result of the |
| 1145 // deletion, set the destination to the ending point after the deletion. | 1159 // deletion, set the destination to the ending point after the deletion. |
| 1146 // Fixes: <rdar://problem/3910425> REGRESSION (Mail): Crash in | 1160 // Fixes: <rdar://problem/3910425> REGRESSION (Mail): Crash in |
| 1147 // ReplaceSelectionCommand; selection is empty, leading to null deref | 1161 // ReplaceSelectionCommand; selection is empty, leading to null deref |
| 1148 if (!m_referenceMovePosition.isConnected()) | 1162 if (!m_referenceMovePosition.isConnected()) |
| 1149 m_referenceMovePosition = endingSelection().start(); | 1163 m_referenceMovePosition = endingSelection().start(); |
| 1150 | 1164 |
| 1151 // Move selection shouldn't left empty <li> block. | 1165 // Move selection shouldn't left empty <li> block. |
| 1152 cleanupAfterDeletion( | 1166 cleanupAfterDeletion(editingState, |
| 1153 editingState, createVisiblePositionDeprecated(m_referenceMovePosition)); | 1167 createVisiblePosition(m_referenceMovePosition)); |
| 1154 if (editingState->isAborted()) | 1168 if (editingState->isAborted()) |
| 1155 return; | 1169 return; |
| 1156 | 1170 |
| 1157 clearTransientState(); | 1171 clearTransientState(); |
| 1158 } | 1172 } |
| 1159 | 1173 |
| 1160 InputEvent::InputType DeleteSelectionCommand::inputType() const { | 1174 InputEvent::InputType DeleteSelectionCommand::inputType() const { |
| 1161 // |DeleteSelectionCommand| could be used with Cut, Menu Bar deletion and | 1175 // |DeleteSelectionCommand| could be used with Cut, Menu Bar deletion and |
| 1162 // |TypingCommand|. | 1176 // |TypingCommand|. |
| 1163 // 1. Cut and Menu Bar deletion should rely on correct |m_inputType|. | 1177 // 1. Cut and Menu Bar deletion should rely on correct |m_inputType|. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1190 visitor->trace(m_deleteIntoBlockquoteStyle); | 1204 visitor->trace(m_deleteIntoBlockquoteStyle); |
| 1191 visitor->trace(m_startRoot); | 1205 visitor->trace(m_startRoot); |
| 1192 visitor->trace(m_endRoot); | 1206 visitor->trace(m_endRoot); |
| 1193 visitor->trace(m_startTableRow); | 1207 visitor->trace(m_startTableRow); |
| 1194 visitor->trace(m_endTableRow); | 1208 visitor->trace(m_endTableRow); |
| 1195 visitor->trace(m_temporaryPlaceholder); | 1209 visitor->trace(m_temporaryPlaceholder); |
| 1196 CompositeEditCommand::trace(visitor); | 1210 CompositeEditCommand::trace(visitor); |
| 1197 } | 1211 } |
| 1198 | 1212 |
| 1199 } // namespace blink | 1213 } // namespace blink |
| OLD | NEW |