| 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 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 Node* startCell = enclosingNodeOfType(m_upstreamStart, &isTableCell, CanCros
sEditingBoundary); | 196 Node* startCell = enclosingNodeOfType(m_upstreamStart, &isTableCell, CanCros
sEditingBoundary); |
| 197 Node* endCell = enclosingNodeOfType(m_downstreamEnd, &isTableCell, CanCrossE
ditingBoundary); | 197 Node* endCell = enclosingNodeOfType(m_downstreamEnd, &isTableCell, CanCrossE
ditingBoundary); |
| 198 // FIXME: This isn't right. A borderless table with two rows and a single c
olumn would appear as two paragraphs. | 198 // FIXME: This isn't right. A borderless table with two rows and a single c
olumn would appear as two paragraphs. |
| 199 if (endCell && endCell != startCell) | 199 if (endCell && endCell != startCell) |
| 200 m_mergeBlocksAfterDelete = false; | 200 m_mergeBlocksAfterDelete = false; |
| 201 | 201 |
| 202 // Usually the start and the end of the selection to delete are pulled toget
her as a result of the deletion. | 202 // Usually the start and the end of the selection to delete are pulled toget
her as a result of the deletion. |
| 203 // Sometimes they aren't (like when no merge is requested), so we must choos
e one position to hold the caret | 203 // Sometimes they aren't (like when no merge is requested), so we must choos
e one position to hold the caret |
| 204 // and receive the placeholder after deletion. | 204 // and receive the placeholder after deletion. |
| 205 VisiblePosition visibleEnd = createVisiblePositionDeprecated(m_downstreamEnd
); | 205 VisiblePosition visibleEnd = createVisiblePositionDeprecated(m_downstreamEnd
); |
| 206 if (m_mergeBlocksAfterDelete && !isEndOfParagraph(visibleEnd)) | 206 if (m_mergeBlocksAfterDelete && !isEndOfParagraphDeprecated(visibleEnd)) |
| 207 m_endingPosition = m_downstreamEnd; | 207 m_endingPosition = m_downstreamEnd; |
| 208 else | 208 else |
| 209 m_endingPosition = m_downstreamStart; | 209 m_endingPosition = m_downstreamStart; |
| 210 | 210 |
| 211 // We don't want to merge into a block if it will mean changing the quote le
vel of content after deleting | 211 // We don't want to merge into a block if it will mean changing the quote le
vel of content after deleting |
| 212 // selections that contain a whole number paragraphs plus a line break, sinc
e it is unclear to most users | 212 // selections that contain a whole number paragraphs plus a line break, sinc
e it is unclear to most users |
| 213 // that such a selection actually ends at the start of the next paragraph. T
his matches TextEdit behavior | 213 // that such a selection actually ends at the start of the next paragraph. T
his matches TextEdit behavior |
| 214 // for indented paragraphs. | 214 // for indented paragraphs. |
| 215 // Only apply this rule if the endingSelection is a range selection. If it
is a caret, then other operations have created | 215 // Only apply this rule if the endingSelection is a range selection. If it
is a caret, then other operations have created |
| 216 // 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
. | 216 // 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
. |
| 217 if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end) | 217 if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end) |
| 218 && isStartOfParagraph(visibleEnd) && isStartOfParagraph(createVisiblePos
itionDeprecated(start)) | 218 && isStartOfParagraphDeprecated(visibleEnd) && isStartOfParagraph(create
VisiblePositionDeprecated(start)) |
| 219 && endingSelection().isRange()) { | 219 && endingSelection().isRange()) { |
| 220 m_mergeBlocksAfterDelete = false; | 220 m_mergeBlocksAfterDelete = false; |
| 221 m_pruneStartBlockIfNecessary = true; | 221 m_pruneStartBlockIfNecessary = true; |
| 222 } | 222 } |
| 223 | 223 |
| 224 // Handle leading and trailing whitespace, as well as smart delete adjustmen
ts to the selection | 224 // Handle leading and trailing whitespace, as well as smart delete adjustmen
ts to the selection |
| 225 m_leadingWhitespace = leadingWhitespacePosition(m_upstreamStart, m_selection
ToDelete.affinity()); | 225 m_leadingWhitespace = leadingWhitespacePosition(m_upstreamStart, m_selection
ToDelete.affinity()); |
| 226 m_trailingWhitespace = trailingWhitespacePosition(m_downstreamEnd, VP_DEFAUL
T_AFFINITY); | 226 m_trailingWhitespace = trailingWhitespacePosition(m_downstreamEnd, VP_DEFAUL
T_AFFINITY); |
| 227 | 227 |
| 228 if (m_smartDelete) { | 228 if (m_smartDelete) { |
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 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())) { | 660 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())) { |
| 661 insertNodeAt(HTMLBRElement::create(document()), m_upstreamStart, editing
State); | 661 insertNodeAt(HTMLBRElement::create(document()), m_upstreamStart, editing
State); |
| 662 if (editingState->isAborted()) | 662 if (editingState->isAborted()) |
| 663 return; | 663 return; |
| 664 mergeDestination = createVisiblePositionDeprecated(m_upstreamStart); | 664 mergeDestination = createVisiblePositionDeprecated(m_upstreamStart); |
| 665 } | 665 } |
| 666 | 666 |
| 667 if (mergeDestination.deepEquivalent() == startOfParagraphToMove.deepEquivale
nt()) | 667 if (mergeDestination.deepEquivalent() == startOfParagraphToMove.deepEquivale
nt()) |
| 668 return; | 668 return; |
| 669 | 669 |
| 670 VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove
, CanSkipOverEditingBoundary); | 670 VisiblePosition endOfParagraphToMove = endOfParagraphDeprecated(startOfParag
raphToMove, CanSkipOverEditingBoundary); |
| 671 | 671 |
| 672 if (mergeDestination.deepEquivalent() == endOfParagraphToMove.deepEquivalent
()) | 672 if (mergeDestination.deepEquivalent() == endOfParagraphToMove.deepEquivalent
()) |
| 673 return; | 673 return; |
| 674 | 674 |
| 675 // If the merge destination and source to be moved are both list items of di
fferent lists, merge them into single list. | 675 // If the merge destination and source to be moved are both list items of di
fferent lists, merge them into single list. |
| 676 Node* listItemInFirstParagraph = enclosingNodeOfType(m_upstreamStart, isList
Item); | 676 Node* listItemInFirstParagraph = enclosingNodeOfType(m_upstreamStart, isList
Item); |
| 677 Node* listItemInSecondParagraph = enclosingNodeOfType(m_downstreamEnd, isLis
tItem); | 677 Node* listItemInSecondParagraph = enclosingNodeOfType(m_downstreamEnd, isLis
tItem); |
| 678 if (listItemInFirstParagraph && listItemInSecondParagraph | 678 if (listItemInFirstParagraph && listItemInSecondParagraph |
| 679 && listItemInFirstParagraph->parentElement() != listItemInSecondParagrap
h->parentElement() | 679 && listItemInFirstParagraph->parentElement() != listItemInSecondParagrap
h->parentElement() |
| 680 && canMergeLists(listItemInFirstParagraph->parentElement(), listItemInSe
condParagraph->parentElement())) { | 680 && canMergeLists(listItemInFirstParagraph->parentElement(), listItemInSe
condParagraph->parentElement())) { |
| 681 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), listIt
emInSecondParagraph->parentElement(), editingState); | 681 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), listIt
emInSecondParagraph->parentElement(), editingState); |
| 682 if (editingState->isAborted()) | 682 if (editingState->isAborted()) |
| 683 return; | 683 return; |
| 684 m_endingPosition = mergeDestination.deepEquivalent(); | 684 m_endingPosition = mergeDestination.deepEquivalent(); |
| 685 return; | 685 return; |
| 686 } | 686 } |
| 687 | 687 |
| 688 // The rule for merging into an empty block is: only do so if its farther to
the right. | 688 // The rule for merging into an empty block is: only do so if its farther to
the right. |
| 689 // FIXME: Consider RTL. | 689 // FIXME: Consider RTL. |
| 690 if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && absolute
CaretBoundsOf(startOfParagraphToMove).x() > absoluteCaretBoundsOf(mergeDestinati
on).x()) { | 690 if (!m_startsAtEmptyLine && isStartOfParagraphDeprecated(mergeDestination) &
& absoluteCaretBoundsOf(startOfParagraphToMove).x() > absoluteCaretBoundsOf(merg
eDestination).x()) { |
| 691 if (isHTMLBRElement(*mostForwardCaretPosition(mergeDestination.deepEquiv
alent()).anchorNode())) { | 691 if (isHTMLBRElement(*mostForwardCaretPosition(mergeDestination.deepEquiv
alent()).anchorNode())) { |
| 692 removeNodeAndPruneAncestors(mostForwardCaretPosition(mergeDestinatio
n.deepEquivalent()).anchorNode(), editingState); | 692 removeNodeAndPruneAncestors(mostForwardCaretPosition(mergeDestinatio
n.deepEquivalent()).anchorNode(), editingState); |
| 693 if (editingState->isAborted()) | 693 if (editingState->isAborted()) |
| 694 return; | 694 return; |
| 695 m_endingPosition = startOfParagraphToMove.deepEquivalent(); | 695 m_endingPosition = startOfParagraphToMove.deepEquivalent(); |
| 696 return; | 696 return; |
| 697 } | 697 } |
| 698 } | 698 } |
| 699 | 699 |
| 700 // Block images, tables and horizontal rules cannot be made inline with cont
ent at mergeDestination. If there is | 700 // Block images, tables and horizontal rules cannot be made inline with cont
ent at mergeDestination. If there is |
| 701 // any (!isStartOfParagraph(mergeDestination)), don't merge, just move the c
aret to just before the selection we deleted. | 701 // any (!isStartOfParagraphDeprecated(mergeDestination)), don't merge, just
move the caret to just before the selection we deleted. |
| 702 // See https://bugs.webkit.org/show_bug.cgi?id=25439 | 702 // See https://bugs.webkit.org/show_bug.cgi?id=25439 |
| 703 if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalen
t().anchorNode()) && !isStartOfParagraph(mergeDestination)) { | 703 if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalen
t().anchorNode()) && !isStartOfParagraphDeprecated(mergeDestination)) { |
| 704 m_endingPosition = m_upstreamStart; | 704 m_endingPosition = m_upstreamStart; |
| 705 return; | 705 return; |
| 706 } | 706 } |
| 707 | 707 |
| 708 // moveParagraphs will insert placeholders if it removes blocks that would r
equire their use, don't let block | 708 // moveParagraphs will insert placeholders if it removes blocks that would r
equire their use, don't let block |
| 709 // removals that it does cause the insertion of *another* placeholder. | 709 // removals that it does cause the insertion of *another* placeholder. |
| 710 bool needPlaceholder = m_needPlaceholder; | 710 bool needPlaceholder = m_needPlaceholder; |
| 711 bool paragraphToMergeIsEmpty = startOfParagraphToMove.deepEquivalent() == en
dOfParagraphToMove.deepEquivalent(); | 711 bool paragraphToMergeIsEmpty = startOfParagraphToMove.deepEquivalent() == en
dOfParagraphToMove.deepEquivalent(); |
| 712 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, mergeDestination
, editingState, DoNotPreserveSelection, paragraphToMergeIsEmpty ? DoNotPreserveS
tyle : PreserveStyle); | 712 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, mergeDestination
, editingState, DoNotPreserveSelection, paragraphToMergeIsEmpty ? DoNotPreserveS
tyle : PreserveStyle); |
| 713 if (editingState->isAborted()) | 713 if (editingState->isAborted()) |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 return; | 839 return; |
| 840 | 840 |
| 841 // save this to later make the selection with | 841 // save this to later make the selection with |
| 842 TextAffinity affinity = m_selectionToDelete.affinity(); | 842 TextAffinity affinity = m_selectionToDelete.affinity(); |
| 843 | 843 |
| 844 Position downstreamEnd = mostForwardCaretPosition(m_selectionToDelete.end())
; | 844 Position downstreamEnd = mostForwardCaretPosition(m_selectionToDelete.end())
; |
| 845 bool rootWillStayOpenWithoutPlaceholder = downstreamEnd.computeContainerNode
() == rootEditableElement(*downstreamEnd.computeContainerNode()) | 845 bool rootWillStayOpenWithoutPlaceholder = downstreamEnd.computeContainerNode
() == rootEditableElement(*downstreamEnd.computeContainerNode()) |
| 846 || (downstreamEnd.computeContainerNode()->isTextNode() && downstreamEnd.
computeContainerNode()->parentNode() == rootEditableElement(*downstreamEnd.compu
teContainerNode())); | 846 || (downstreamEnd.computeContainerNode()->isTextNode() && downstreamEnd.
computeContainerNode()->parentNode() == rootEditableElement(*downstreamEnd.compu
teContainerNode())); |
| 847 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_
selectionToDelete.visibleEnd()); | 847 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_
selectionToDelete.visibleEnd()); |
| 848 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder | 848 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder |
| 849 && isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditin
gBoundary) | 849 && isStartOfParagraphDeprecated(m_selectionToDelete.visibleStart(), CanC
rossEditingBoundary) |
| 850 && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBou
ndary) | 850 && isEndOfParagraphDeprecated(m_selectionToDelete.visibleEnd(), CanCross
EditingBoundary) |
| 851 && !lineBreakAtEndOfSelectionToDelete; | 851 && !lineBreakAtEndOfSelectionToDelete; |
| 852 if (m_needPlaceholder) { | 852 if (m_needPlaceholder) { |
| 853 // Don't need a placeholder when deleting a selection that starts just | 853 // Don't need a placeholder when deleting a selection that starts just |
| 854 // before a table and ends inside it (we do need placeholders to hold | 854 // before a table and ends inside it (we do need placeholders to hold |
| 855 // open empty cells, but that's handled elsewhere). | 855 // open empty cells, but that's handled elsewhere). |
| 856 if (Element* table = tableElementJustAfter(m_selectionToDelete.visibleSt
art())) { | 856 if (Element* table = tableElementJustAfter(m_selectionToDelete.visibleSt
art())) { |
| 857 if (m_selectionToDelete.end().anchorNode()->isDescendantOf(table)) | 857 if (m_selectionToDelete.end().anchorNode()->isDescendantOf(table)) |
| 858 m_needPlaceholder = false; | 858 m_needPlaceholder = false; |
| 859 } | 859 } |
| 860 } | 860 } |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 963 visitor->trace(m_deleteIntoBlockquoteStyle); | 963 visitor->trace(m_deleteIntoBlockquoteStyle); |
| 964 visitor->trace(m_startRoot); | 964 visitor->trace(m_startRoot); |
| 965 visitor->trace(m_endRoot); | 965 visitor->trace(m_endRoot); |
| 966 visitor->trace(m_startTableRow); | 966 visitor->trace(m_startTableRow); |
| 967 visitor->trace(m_endTableRow); | 967 visitor->trace(m_endTableRow); |
| 968 visitor->trace(m_temporaryPlaceholder); | 968 visitor->trace(m_temporaryPlaceholder); |
| 969 CompositeEditCommand::trace(visitor); | 969 CompositeEditCommand::trace(visitor); |
| 970 } | 970 } |
| 971 | 971 |
| 972 } // namespace blink | 972 } // namespace blink |
| OLD | NEW |