| 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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 #include "core/layout/LayoutTableCell.h" | 43 #include "core/layout/LayoutTableCell.h" |
| 44 #include "core/layout/LayoutText.h" | 44 #include "core/layout/LayoutText.h" |
| 45 | 45 |
| 46 namespace blink { | 46 namespace blink { |
| 47 | 47 |
| 48 using namespace HTMLNames; | 48 using namespace HTMLNames; |
| 49 | 49 |
| 50 static bool isTableCellEmpty(Node* cell) | 50 static bool isTableCellEmpty(Node* cell) |
| 51 { | 51 { |
| 52 ASSERT(isTableCell(cell)); | 52 ASSERT(isTableCell(cell)); |
| 53 return VisiblePosition(firstPositionInNode(cell)).deepEquivalent() == Visibl
ePosition(lastPositionInNode(cell)).deepEquivalent(); | 53 return createVisiblePosition(firstPositionInNode(cell)).deepEquivalent() ==
createVisiblePosition(lastPositionInNode(cell)).deepEquivalent(); |
| 54 } | 54 } |
| 55 | 55 |
| 56 static bool isTableRowEmpty(Node* row) | 56 static bool isTableRowEmpty(Node* row) |
| 57 { | 57 { |
| 58 if (!isHTMLTableRowElement(row)) | 58 if (!isHTMLTableRowElement(row)) |
| 59 return false; | 59 return false; |
| 60 | 60 |
| 61 for (Node* child = row->firstChild(); child; child = child->nextSibling()) { | 61 for (Node* child = row->firstChild(); child; child = child->nextSibling()) { |
| 62 if (isTableCell(child) && !isTableCellEmpty(child)) | 62 if (isTableCell(child) && !isTableCellEmpty(child)) |
| 63 return false; | 63 return false; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 while (1) { | 122 while (1) { |
| 123 startSpecialContainer = 0; | 123 startSpecialContainer = 0; |
| 124 endSpecialContainer = 0; | 124 endSpecialContainer = 0; |
| 125 | 125 |
| 126 Position s = positionBeforeContainingSpecialElement(start, &startSpecial
Container); | 126 Position s = positionBeforeContainingSpecialElement(start, &startSpecial
Container); |
| 127 Position e = positionAfterContainingSpecialElement(end, &endSpecialConta
iner); | 127 Position e = positionAfterContainingSpecialElement(end, &endSpecialConta
iner); |
| 128 | 128 |
| 129 if (!startSpecialContainer && !endSpecialContainer) | 129 if (!startSpecialContainer && !endSpecialContainer) |
| 130 break; | 130 break; |
| 131 | 131 |
| 132 if (VisiblePosition(start).deepEquivalent() != m_selectionToDelete.visib
leStart().deepEquivalent() || VisiblePosition(end).deepEquivalent() != m_selecti
onToDelete.visibleEnd().deepEquivalent()) | 132 if (createVisiblePosition(start).deepEquivalent() != m_selectionToDelete
.visibleStart().deepEquivalent() || createVisiblePosition(end).deepEquivalent()
!= m_selectionToDelete.visibleEnd().deepEquivalent()) |
| 133 break; | 133 break; |
| 134 | 134 |
| 135 // If we're going to expand to include the startSpecialContainer, it mus
t be fully selected. | 135 // If we're going to expand to include the startSpecialContainer, it mus
t be fully selected. |
| 136 if (startSpecialContainer && !endSpecialContainer && comparePositions(po
sitionInParentAfterNode(*startSpecialContainer), end) > -1) | 136 if (startSpecialContainer && !endSpecialContainer && comparePositions(po
sitionInParentAfterNode(*startSpecialContainer), end) > -1) |
| 137 break; | 137 break; |
| 138 | 138 |
| 139 // If we're going to expand to include the endSpecialContainer, it must
be fully selected. | 139 // If we're going to expand to include the endSpecialContainer, it must
be fully selected. |
| 140 if (endSpecialContainer && !startSpecialContainer && comparePositions(st
art, positionInParentBeforeNode(*endSpecialContainer)) > -1) | 140 if (endSpecialContainer && !startSpecialContainer && comparePositions(st
art, positionInParentBeforeNode(*endSpecialContainer)) > -1) |
| 141 break; | 141 break; |
| 142 | 142 |
| 143 if (startSpecialContainer && startSpecialContainer->isDescendantOf(endSp
ecialContainer)) { | 143 if (startSpecialContainer && startSpecialContainer->isDescendantOf(endSp
ecialContainer)) { |
| 144 // Don't adjust the end yet, it is the end of a special element that
contains the start | 144 // Don't adjust the end yet, it is the end of a special element that
contains the start |
| 145 // special element (which may or may not be fully selected). | 145 // special element (which may or may not be fully selected). |
| 146 start = s; | 146 start = s; |
| 147 } else if (endSpecialContainer && endSpecialContainer->isDescendantOf(st
artSpecialContainer)) { | 147 } else if (endSpecialContainer && endSpecialContainer->isDescendantOf(st
artSpecialContainer)) { |
| 148 // Don't adjust the start yet, it is the start of a special element
that contains the end | 148 // Don't adjust the start yet, it is the start of a special element
that contains the end |
| 149 // special element (which may or may not be fully selected). | 149 // special element (which may or may not be fully selected). |
| 150 end = e; | 150 end = e; |
| 151 } else { | 151 } else { |
| 152 start = s; | 152 start = s; |
| 153 end = e; | 153 end = e; |
| 154 } | 154 } |
| 155 } | 155 } |
| 156 } | 156 } |
| 157 | 157 |
| 158 void DeleteSelectionCommand::setStartingSelectionOnSmartDelete(const Position& s
tart, const Position& end) | 158 void DeleteSelectionCommand::setStartingSelectionOnSmartDelete(const Position& s
tart, const Position& end) |
| 159 { | 159 { |
| 160 bool isBaseFirst = startingSelection().isBaseFirst(); | 160 bool isBaseFirst = startingSelection().isBaseFirst(); |
| 161 VisiblePosition newBase(isBaseFirst ? start : end); | 161 VisiblePosition newBase = createVisiblePosition(isBaseFirst ? start : end); |
| 162 VisiblePosition newExtent(isBaseFirst ? end : start); | 162 VisiblePosition newExtent = createVisiblePosition(isBaseFirst ? end : start)
; |
| 163 setStartingSelection(VisibleSelection(newBase, newExtent, startingSelection(
).isDirectional())); | 163 setStartingSelection(VisibleSelection(newBase, newExtent, startingSelection(
).isDirectional())); |
| 164 } | 164 } |
| 165 | 165 |
| 166 void DeleteSelectionCommand::initializePositionData() | 166 void DeleteSelectionCommand::initializePositionData() |
| 167 { | 167 { |
| 168 Position start, end; | 168 Position start, end; |
| 169 initializeStartEnd(start, end); | 169 initializeStartEnd(start, end); |
| 170 | 170 |
| 171 ASSERT(isEditablePosition(start, ContentIsEditable, DoNotUpdateStyle)); | 171 ASSERT(isEditablePosition(start, ContentIsEditable, DoNotUpdateStyle)); |
| 172 if (!isEditablePosition(end, ContentIsEditable, DoNotUpdateStyle)) | 172 if (!isEditablePosition(end, ContentIsEditable, DoNotUpdateStyle)) |
| (...skipping 15 matching lines...) Expand all Loading... |
| 188 // tell that function that we don't care if it returns non-editable nodes. | 188 // tell that function that we don't care if it returns non-editable nodes. |
| 189 Node* startCell = enclosingNodeOfType(m_upstreamStart, &isTableCell, CanCros
sEditingBoundary); | 189 Node* startCell = enclosingNodeOfType(m_upstreamStart, &isTableCell, CanCros
sEditingBoundary); |
| 190 Node* endCell = enclosingNodeOfType(m_downstreamEnd, &isTableCell, CanCrossE
ditingBoundary); | 190 Node* endCell = enclosingNodeOfType(m_downstreamEnd, &isTableCell, CanCrossE
ditingBoundary); |
| 191 // FIXME: This isn't right. A borderless table with two rows and a single c
olumn would appear as two paragraphs. | 191 // FIXME: This isn't right. A borderless table with two rows and a single c
olumn would appear as two paragraphs. |
| 192 if (endCell && endCell != startCell) | 192 if (endCell && endCell != startCell) |
| 193 m_mergeBlocksAfterDelete = false; | 193 m_mergeBlocksAfterDelete = false; |
| 194 | 194 |
| 195 // Usually the start and the end of the selection to delete are pulled toget
her as a result of the deletion. | 195 // Usually the start and the end of the selection to delete are pulled toget
her as a result of the deletion. |
| 196 // Sometimes they aren't (like when no merge is requested), so we must choos
e one position to hold the caret | 196 // Sometimes they aren't (like when no merge is requested), so we must choos
e one position to hold the caret |
| 197 // and receive the placeholder after deletion. | 197 // and receive the placeholder after deletion. |
| 198 VisiblePosition visibleEnd(m_downstreamEnd); | 198 VisiblePosition visibleEnd = createVisiblePosition(m_downstreamEnd); |
| 199 if (m_mergeBlocksAfterDelete && !isEndOfParagraph(visibleEnd)) | 199 if (m_mergeBlocksAfterDelete && !isEndOfParagraph(visibleEnd)) |
| 200 m_endingPosition = m_downstreamEnd; | 200 m_endingPosition = m_downstreamEnd; |
| 201 else | 201 else |
| 202 m_endingPosition = m_downstreamStart; | 202 m_endingPosition = m_downstreamStart; |
| 203 | 203 |
| 204 // We don't want to merge into a block if it will mean changing the quote le
vel of content after deleting | 204 // We don't want to merge into a block if it will mean changing the quote le
vel of content after deleting |
| 205 // selections that contain a whole number paragraphs plus a line break, sinc
e it is unclear to most users | 205 // selections that contain a whole number paragraphs plus a line break, sinc
e it is unclear to most users |
| 206 // that such a selection actually ends at the start of the next paragraph. T
his matches TextEdit behavior | 206 // that such a selection actually ends at the start of the next paragraph. T
his matches TextEdit behavior |
| 207 // for indented paragraphs. | 207 // for indented paragraphs. |
| 208 // Only apply this rule if the endingSelection is a range selection. If it
is a caret, then other operations have created | 208 // Only apply this rule if the endingSelection is a range selection. If it
is a caret, then other operations have created |
| 209 // the selection we're deleting (like the process of creating a selection to
delete during a backspace), and the user isn't in the situation described above
. | 209 // the selection we're deleting (like the process of creating a selection to
delete during a backspace), and the user isn't in the situation described above
. |
| 210 if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end) | 210 if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end) |
| 211 && isStartOfParagraph(visibleEnd) && isStartOfParagraph(VisiblePosition(
start)) | 211 && isStartOfParagraph(visibleEnd) && isStartOfParagraph(createVisiblePos
ition(start)) |
| 212 && endingSelection().isRange()) { | 212 && endingSelection().isRange()) { |
| 213 m_mergeBlocksAfterDelete = false; | 213 m_mergeBlocksAfterDelete = false; |
| 214 m_pruneStartBlockIfNecessary = true; | 214 m_pruneStartBlockIfNecessary = true; |
| 215 } | 215 } |
| 216 | 216 |
| 217 // Handle leading and trailing whitespace, as well as smart delete adjustmen
ts to the selection | 217 // Handle leading and trailing whitespace, as well as smart delete adjustmen
ts to the selection |
| 218 m_leadingWhitespace = leadingWhitespacePosition(m_upstreamStart, m_selection
ToDelete.affinity()); | 218 m_leadingWhitespace = leadingWhitespacePosition(m_upstreamStart, m_selection
ToDelete.affinity()); |
| 219 m_trailingWhitespace = trailingWhitespacePosition(m_downstreamEnd, VP_DEFAUL
T_AFFINITY); | 219 m_trailingWhitespace = trailingWhitespacePosition(m_downstreamEnd, VP_DEFAUL
T_AFFINITY); |
| 220 | 220 |
| 221 if (m_smartDelete) { | 221 if (m_smartDelete) { |
| 222 | 222 |
| 223 // skip smart delete if the selection to delete already starts or ends w
ith whitespace | 223 // skip smart delete if the selection to delete already starts or ends w
ith whitespace |
| 224 Position pos = VisiblePosition(m_upstreamStart, m_selectionToDelete.affi
nity()).deepEquivalent(); | 224 Position pos = createVisiblePosition(m_upstreamStart, m_selectionToDelet
e.affinity()).deepEquivalent(); |
| 225 bool skipSmartDelete = trailingWhitespacePosition(pos, VP_DEFAULT_AFFINI
TY, ConsiderNonCollapsibleWhitespace).isNotNull(); | 225 bool skipSmartDelete = trailingWhitespacePosition(pos, VP_DEFAULT_AFFINI
TY, ConsiderNonCollapsibleWhitespace).isNotNull(); |
| 226 if (!skipSmartDelete) | 226 if (!skipSmartDelete) |
| 227 skipSmartDelete = leadingWhitespacePosition(m_downstreamEnd, VP_DEFA
ULT_AFFINITY, ConsiderNonCollapsibleWhitespace).isNotNull(); | 227 skipSmartDelete = leadingWhitespacePosition(m_downstreamEnd, VP_DEFA
ULT_AFFINITY, ConsiderNonCollapsibleWhitespace).isNotNull(); |
| 228 | 228 |
| 229 // extend selection upstream if there is whitespace there | 229 // extend selection upstream if there is whitespace there |
| 230 bool hasLeadingWhitespaceBeforeAdjustment = leadingWhitespacePosition(m_
upstreamStart, m_selectionToDelete.affinity(), ConsiderNonCollapsibleWhitespace)
.isNotNull(); | 230 bool hasLeadingWhitespaceBeforeAdjustment = leadingWhitespacePosition(m_
upstreamStart, m_selectionToDelete.affinity(), ConsiderNonCollapsibleWhitespace)
.isNotNull(); |
| 231 if (!skipSmartDelete && hasLeadingWhitespaceBeforeAdjustment) { | 231 if (!skipSmartDelete && hasLeadingWhitespaceBeforeAdjustment) { |
| 232 VisiblePosition visiblePos = previousPositionOf(VisiblePosition(m_up
streamStart, VP_DEFAULT_AFFINITY)); | 232 VisiblePosition visiblePos = previousPositionOf(createVisiblePositio
n(m_upstreamStart, VP_DEFAULT_AFFINITY)); |
| 233 pos = visiblePos.deepEquivalent(); | 233 pos = visiblePos.deepEquivalent(); |
| 234 // Expand out one character upstream for smart delete and recalculat
e | 234 // Expand out one character upstream for smart delete and recalculat
e |
| 235 // positions based on this change. | 235 // positions based on this change. |
| 236 m_upstreamStart = mostBackwardCaretPosition(pos); | 236 m_upstreamStart = mostBackwardCaretPosition(pos); |
| 237 m_downstreamStart = mostForwardCaretPosition(pos); | 237 m_downstreamStart = mostForwardCaretPosition(pos); |
| 238 m_leadingWhitespace = leadingWhitespacePosition(m_upstreamStart, vis
iblePos.affinity()); | 238 m_leadingWhitespace = leadingWhitespacePosition(m_upstreamStart, vis
iblePos.affinity()); |
| 239 | 239 |
| 240 setStartingSelectionOnSmartDelete(m_upstreamStart, m_upstreamEnd); | 240 setStartingSelectionOnSmartDelete(m_upstreamStart, m_upstreamEnd); |
| 241 } | 241 } |
| 242 | 242 |
| 243 // trailing whitespace is only considered for smart delete if there is n
o leading | 243 // trailing whitespace is only considered for smart delete if there is n
o leading |
| 244 // whitespace, as in the case where you double-click the first word of a
paragraph. | 244 // whitespace, as in the case where you double-click the first word of a
paragraph. |
| 245 if (!skipSmartDelete && !hasLeadingWhitespaceBeforeAdjustment && trailin
gWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY, ConsiderNonCollapsible
Whitespace).isNotNull()) { | 245 if (!skipSmartDelete && !hasLeadingWhitespaceBeforeAdjustment && trailin
gWhitespacePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY, ConsiderNonCollapsible
Whitespace).isNotNull()) { |
| 246 // Expand out one character downstream for smart delete and recalcul
ate | 246 // Expand out one character downstream for smart delete and recalcul
ate |
| 247 // positions based on this change. | 247 // positions based on this change. |
| 248 pos = nextPositionOf(VisiblePosition(m_downstreamEnd, VP_DEFAULT_AFF
INITY)).deepEquivalent(); | 248 pos = nextPositionOf(createVisiblePosition(m_downstreamEnd, VP_DEFAU
LT_AFFINITY)).deepEquivalent(); |
| 249 m_upstreamEnd = mostBackwardCaretPosition(pos); | 249 m_upstreamEnd = mostBackwardCaretPosition(pos); |
| 250 m_downstreamEnd = mostForwardCaretPosition(pos); | 250 m_downstreamEnd = mostForwardCaretPosition(pos); |
| 251 m_trailingWhitespace = trailingWhitespacePosition(m_downstreamEnd, V
P_DEFAULT_AFFINITY); | 251 m_trailingWhitespace = trailingWhitespacePosition(m_downstreamEnd, V
P_DEFAULT_AFFINITY); |
| 252 | 252 |
| 253 setStartingSelectionOnSmartDelete(m_downstreamStart, m_downstreamEnd
); | 253 setStartingSelectionOnSmartDelete(m_downstreamStart, m_downstreamEnd
); |
| 254 } | 254 } |
| 255 } | 255 } |
| 256 | 256 |
| 257 // We must pass call parentAnchoredEquivalent on the positions since some ed
iting positions | 257 // We must pass call parentAnchoredEquivalent on the positions since some ed
iting positions |
| 258 // that appear inside their nodes aren't really inside them. [hr, 0] is one
example. | 258 // that appear inside their nodes aren't really inside them. [hr, 0] is one
example. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 bool upstreamStartIsBR = isHTMLBRElement(*nodeAfterUpstreamStart); | 311 bool upstreamStartIsBR = isHTMLBRElement(*nodeAfterUpstreamStart); |
| 312 bool downstreamStartIsBR = isHTMLBRElement(*nodeAfterDownstreamStart); | 312 bool downstreamStartIsBR = isHTMLBRElement(*nodeAfterDownstreamStart); |
| 313 bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && nodeAf
terDownstreamStart == nodeAfterUpstreamEnd; | 313 bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && nodeAf
terDownstreamStart == nodeAfterUpstreamEnd; |
| 314 if (isBROnLineByItself) { | 314 if (isBROnLineByItself) { |
| 315 removeNode(nodeAfterDownstreamStart); | 315 removeNode(nodeAfterDownstreamStart); |
| 316 return true; | 316 return true; |
| 317 } | 317 } |
| 318 | 318 |
| 319 // FIXME: This code doesn't belong in here. | 319 // FIXME: This code doesn't belong in here. |
| 320 // We detect the case where the start is an empty line consisting of BR not
wrapped in a block element. | 320 // We detect the case where the start is an empty line consisting of BR not
wrapped in a block element. |
| 321 if (upstreamStartIsBR && downstreamStartIsBR && !(isStartOfBlock(VisiblePosi
tion(positionBeforeNode(nodeAfterUpstreamStart))) && isEndOfBlock(VisiblePositio
n(positionAfterNode(nodeAfterUpstreamStart))))) { | 321 if (upstreamStartIsBR && downstreamStartIsBR && !(isStartOfBlock(createVisib
lePosition(positionBeforeNode(nodeAfterUpstreamStart))) && isEndOfBlock(createVi
siblePosition(positionAfterNode(nodeAfterUpstreamStart))))) { |
| 322 m_startsAtEmptyLine = true; | 322 m_startsAtEmptyLine = true; |
| 323 m_endingPosition = m_downstreamEnd; | 323 m_endingPosition = m_downstreamEnd; |
| 324 } | 324 } |
| 325 | 325 |
| 326 return false; | 326 return false; |
| 327 } | 327 } |
| 328 | 328 |
| 329 static Position firstEditablePositionInNode(Node* node) | 329 static Position firstEditablePositionInNode(Node* node) |
| 330 { | 330 { |
| 331 ASSERT(node); | 331 ASSERT(node); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 LayoutObject* r = node->layoutObject(); | 377 LayoutObject* r = node->layoutObject(); |
| 378 if (r && r->isTableCell() && toLayoutTableCell(r)->contentHeight() <= 0)
{ | 378 if (r && r->isTableCell() && toLayoutTableCell(r)->contentHeight() <= 0)
{ |
| 379 Position firstEditablePosition = firstEditablePositionInNode(node.ge
t()); | 379 Position firstEditablePosition = firstEditablePositionInNode(node.ge
t()); |
| 380 if (firstEditablePosition.isNotNull()) | 380 if (firstEditablePosition.isNotNull()) |
| 381 insertBlockPlaceholder(firstEditablePosition); | 381 insertBlockPlaceholder(firstEditablePosition); |
| 382 } | 382 } |
| 383 return; | 383 return; |
| 384 } | 384 } |
| 385 | 385 |
| 386 if (node == m_startBlock) { | 386 if (node == m_startBlock) { |
| 387 VisiblePosition previous = previousPositionOf(VisiblePosition(firstPosit
ionInNode(m_startBlock.get()))); | 387 VisiblePosition previous = previousPositionOf(createVisiblePosition(firs
tPositionInNode(m_startBlock.get()))); |
| 388 if (previous.isNotNull() && !isEndOfBlock(previous)) | 388 if (previous.isNotNull() && !isEndOfBlock(previous)) |
| 389 m_needPlaceholder = true; | 389 m_needPlaceholder = true; |
| 390 } | 390 } |
| 391 if (node == m_endBlock) { | 391 if (node == m_endBlock) { |
| 392 VisiblePosition next = nextPositionOf(VisiblePosition(lastPositionInNode
(m_endBlock.get()))); | 392 VisiblePosition next = nextPositionOf(createVisiblePosition(lastPosition
InNode(m_endBlock.get()))); |
| 393 if (next.isNotNull() && !isStartOfBlock(next)) | 393 if (next.isNotNull() && !isStartOfBlock(next)) |
| 394 m_needPlaceholder = true; | 394 m_needPlaceholder = true; |
| 395 } | 395 } |
| 396 | 396 |
| 397 // FIXME: Update the endpoints of the range being deleted. | 397 // FIXME: Update the endpoints of the range being deleted. |
| 398 updatePositionForNodeRemoval(m_endingPosition, *node); | 398 updatePositionForNodeRemoval(m_endingPosition, *node); |
| 399 updatePositionForNodeRemoval(m_leadingWhitespace, *node); | 399 updatePositionForNodeRemoval(m_leadingWhitespace, *node); |
| 400 updatePositionForNodeRemoval(m_trailingWhitespace, *node); | 400 updatePositionForNodeRemoval(m_trailingWhitespace, *node); |
| 401 | 401 |
| 402 CompositeEditCommand::removeNode(node, shouldAssumeContentIsAlwaysEditable); | 402 CompositeEditCommand::removeNode(node, shouldAssumeContentIsAlwaysEditable); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 return; | 608 return; |
| 609 | 609 |
| 610 // FIXME: The deletion algorithm shouldn't let this happen. | 610 // FIXME: The deletion algorithm shouldn't let this happen. |
| 611 if (comparePositions(m_upstreamStart, m_downstreamEnd) > 0) | 611 if (comparePositions(m_upstreamStart, m_downstreamEnd) > 0) |
| 612 return; | 612 return; |
| 613 | 613 |
| 614 // There's nothing to merge. | 614 // There's nothing to merge. |
| 615 if (m_upstreamStart == m_downstreamEnd) | 615 if (m_upstreamStart == m_downstreamEnd) |
| 616 return; | 616 return; |
| 617 | 617 |
| 618 VisiblePosition startOfParagraphToMove(m_downstreamEnd); | 618 VisiblePosition startOfParagraphToMove = createVisiblePosition(m_downstreamE
nd); |
| 619 VisiblePosition mergeDestination(m_upstreamStart); | 619 VisiblePosition mergeDestination = createVisiblePosition(m_upstreamStart); |
| 620 | 620 |
| 621 // m_downstreamEnd's block has been emptied out by deletion. There is no co
ntent inside of it to | 621 // m_downstreamEnd's block has been emptied out by deletion. There is no co
ntent inside of it to |
| 622 // move, so just remove it. | 622 // move, so just remove it. |
| 623 Element* endBlock = enclosingBlock(m_downstreamEnd.anchorNode()); | 623 Element* endBlock = enclosingBlock(m_downstreamEnd.anchorNode()); |
| 624 if (!endBlock || !endBlock->contains(startOfParagraphToMove.deepEquivalent()
.anchorNode()) || !startOfParagraphToMove.deepEquivalent().anchorNode()) { | 624 if (!endBlock || !endBlock->contains(startOfParagraphToMove.deepEquivalent()
.anchorNode()) || !startOfParagraphToMove.deepEquivalent().anchorNode()) { |
| 625 removeNode(enclosingBlock(m_downstreamEnd.anchorNode())); | 625 removeNode(enclosingBlock(m_downstreamEnd.anchorNode())); |
| 626 return; | 626 return; |
| 627 } | 627 } |
| 628 | 628 |
| 629 // We need to merge into m_upstreamStart's block, but it's been emptied out
and collapsed by deletion. | 629 // We need to merge into m_upstreamStart's block, but it's been emptied out
and collapsed by deletion. |
| 630 if (!mergeDestination.deepEquivalent().anchorNode() || (!mergeDestination.de
epEquivalent().anchorNode()->isDescendantOf(enclosingBlock(m_upstreamStart.compu
teContainerNode())) && (!mergeDestination.deepEquivalent().anchorNode()->hasChil
dren() || !m_upstreamStart.computeContainerNode()->hasChildren())) || (m_startsA
tEmptyLine && mergeDestination.deepEquivalent() != startOfParagraphToMove.deepEq
uivalent())) { | 630 if (!mergeDestination.deepEquivalent().anchorNode() || (!mergeDestination.de
epEquivalent().anchorNode()->isDescendantOf(enclosingBlock(m_upstreamStart.compu
teContainerNode())) && (!mergeDestination.deepEquivalent().anchorNode()->hasChil
dren() || !m_upstreamStart.computeContainerNode()->hasChildren())) || (m_startsA
tEmptyLine && mergeDestination.deepEquivalent() != startOfParagraphToMove.deepEq
uivalent())) { |
| 631 insertNodeAt(createBreakElement(document()).get(), m_upstreamStart); | 631 insertNodeAt(createBreakElement(document()).get(), m_upstreamStart); |
| 632 mergeDestination = VisiblePosition(m_upstreamStart); | 632 mergeDestination = createVisiblePosition(m_upstreamStart); |
| 633 } | 633 } |
| 634 | 634 |
| 635 if (mergeDestination.deepEquivalent() == startOfParagraphToMove.deepEquivale
nt()) | 635 if (mergeDestination.deepEquivalent() == startOfParagraphToMove.deepEquivale
nt()) |
| 636 return; | 636 return; |
| 637 | 637 |
| 638 VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove
, CanSkipOverEditingBoundary); | 638 VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove
, CanSkipOverEditingBoundary); |
| 639 | 639 |
| 640 if (mergeDestination.deepEquivalent() == endOfParagraphToMove.deepEquivalent
()) | 640 if (mergeDestination.deepEquivalent() == endOfParagraphToMove.deepEquivalent
()) |
| 641 return; | 641 return; |
| 642 | 642 |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 if (Element* table = isLastPositionBeforeTable(m_selectionToDelete.visib
leStart())) { | 809 if (Element* table = isLastPositionBeforeTable(m_selectionToDelete.visib
leStart())) { |
| 810 if (m_selectionToDelete.end().anchorNode()->isDescendantOf(table)) | 810 if (m_selectionToDelete.end().anchorNode()->isDescendantOf(table)) |
| 811 m_needPlaceholder = false; | 811 m_needPlaceholder = false; |
| 812 } | 812 } |
| 813 } | 813 } |
| 814 | 814 |
| 815 | 815 |
| 816 // set up our state | 816 // set up our state |
| 817 initializePositionData(); | 817 initializePositionData(); |
| 818 | 818 |
| 819 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition(previousPositio
nOf(VisiblePosition(m_upstreamStart))); | 819 bool lineBreakBeforeStart = lineBreakExistsAtVisiblePosition(previousPositio
nOf(createVisiblePosition(m_upstreamStart))); |
| 820 | 820 |
| 821 // Delete any text that may hinder our ability to fixup whitespace after the | 821 // Delete any text that may hinder our ability to fixup whitespace after the |
| 822 // delete | 822 // delete |
| 823 deleteInsignificantTextDownstream(m_trailingWhitespace); | 823 deleteInsignificantTextDownstream(m_trailingWhitespace); |
| 824 | 824 |
| 825 saveTypingStyleState(); | 825 saveTypingStyleState(); |
| 826 | 826 |
| 827 // deleting just a BR is handled specially, at least because we do not | 827 // deleting just a BR is handled specially, at least because we do not |
| 828 // want to replace it with a placeholder BR! | 828 // want to replace it with a placeholder BR! |
| 829 if (handleSpecialCaseBRDelete()) { | 829 if (handleSpecialCaseBRDelete()) { |
| 830 calculateTypingStyleAfterDelete(); | 830 calculateTypingStyleAfterDelete(); |
| 831 setEndingSelection(VisibleSelection(m_endingPosition, affinity, endingSe
lection().isDirectional())); | 831 setEndingSelection(VisibleSelection(m_endingPosition, affinity, endingSe
lection().isDirectional())); |
| 832 clearTransientState(); | 832 clearTransientState(); |
| 833 rebalanceWhitespace(); | 833 rebalanceWhitespace(); |
| 834 return; | 834 return; |
| 835 } | 835 } |
| 836 | 836 |
| 837 handleGeneralDelete(); | 837 handleGeneralDelete(); |
| 838 | 838 |
| 839 fixupWhitespace(); | 839 fixupWhitespace(); |
| 840 | 840 |
| 841 mergeParagraphs(); | 841 mergeParagraphs(); |
| 842 | 842 |
| 843 removePreviouslySelectedEmptyTableRows(); | 843 removePreviouslySelectedEmptyTableRows(); |
| 844 | 844 |
| 845 if (!m_needPlaceholder && rootWillStayOpenWithoutPlaceholder) { | 845 if (!m_needPlaceholder && rootWillStayOpenWithoutPlaceholder) { |
| 846 VisiblePosition visualEnding(m_endingPosition); | 846 VisiblePosition visualEnding = createVisiblePosition(m_endingPosition); |
| 847 bool hasPlaceholder = lineBreakExistsAtVisiblePosition(visualEnding) | 847 bool hasPlaceholder = lineBreakExistsAtVisiblePosition(visualEnding) |
| 848 && nextPositionOf(visualEnding, CannotCrossEditingBoundary).isNull()
; | 848 && nextPositionOf(visualEnding, CannotCrossEditingBoundary).isNull()
; |
| 849 m_needPlaceholder = hasPlaceholder && lineBreakBeforeStart && !lineBreak
AtEndOfSelectionToDelete; | 849 m_needPlaceholder = hasPlaceholder && lineBreakBeforeStart && !lineBreak
AtEndOfSelectionToDelete; |
| 850 } | 850 } |
| 851 | 851 |
| 852 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = m_needPlaceholder ? createBr
eakElement(document()) : nullptr; | 852 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = m_needPlaceholder ? createBr
eakElement(document()) : nullptr; |
| 853 | 853 |
| 854 if (placeholder) { | 854 if (placeholder) { |
| 855 if (m_sanitizeMarkup) | 855 if (m_sanitizeMarkup) |
| 856 removeRedundantBlocks(); | 856 removeRedundantBlocks(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 900 visitor->trace(m_deleteIntoBlockquoteStyle); | 900 visitor->trace(m_deleteIntoBlockquoteStyle); |
| 901 visitor->trace(m_startRoot); | 901 visitor->trace(m_startRoot); |
| 902 visitor->trace(m_endRoot); | 902 visitor->trace(m_endRoot); |
| 903 visitor->trace(m_startTableRow); | 903 visitor->trace(m_startTableRow); |
| 904 visitor->trace(m_endTableRow); | 904 visitor->trace(m_endTableRow); |
| 905 visitor->trace(m_temporaryPlaceholder); | 905 visitor->trace(m_temporaryPlaceholder); |
| 906 CompositeEditCommand::trace(visitor); | 906 CompositeEditCommand::trace(visitor); |
| 907 } | 907 } |
| 908 | 908 |
| 909 } // namespace blink | 909 } // namespace blink |
| OLD | NEW |