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 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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)) |
173 end = lastEditablePositionBeforePositionInRoot(end, highestEditableRoot(
start)); | 173 end = lastEditablePositionBeforePositionInRoot(end, highestEditableRoot(
start)); |
174 | 174 |
175 m_upstreamStart = start.upstream(); | 175 m_upstreamStart = mostBackwardCaretPosition(start); |
176 m_downstreamStart = start.downstream(); | 176 m_downstreamStart = mostForwardCaretPosition(start); |
177 m_upstreamEnd = end.upstream(); | 177 m_upstreamEnd = mostBackwardCaretPosition(end); |
178 m_downstreamEnd = end.downstream(); | 178 m_downstreamEnd = mostForwardCaretPosition(end); |
179 | 179 |
180 m_startRoot = editableRootForPosition(start); | 180 m_startRoot = editableRootForPosition(start); |
181 m_endRoot = editableRootForPosition(end); | 181 m_endRoot = editableRootForPosition(end); |
182 | 182 |
183 m_startTableRow = toHTMLTableRowElement(enclosingNodeOfType(start, &isHTMLTa
bleRowElement)); | 183 m_startTableRow = toHTMLTableRowElement(enclosingNodeOfType(start, &isHTMLTa
bleRowElement)); |
184 m_endTableRow = toHTMLTableRowElement(enclosingNodeOfType(end, &isHTMLTableR
owElement)); | 184 m_endTableRow = toHTMLTableRowElement(enclosingNodeOfType(end, &isHTMLTableR
owElement)); |
185 | 185 |
186 // Don't move content out of a table cell. | 186 // Don't move content out of a table cell. |
187 // If the cell is non-editable, enclosingNodeOfType won't return it by defau
lt, so | 187 // If the cell is non-editable, enclosingNodeOfType won't return it by defau
lt, so |
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. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 = VisiblePosition(m_upstreamStart, VP_DEF
AULT_AFFINITY).previous(); | 232 VisiblePosition visiblePos = VisiblePosition(m_upstreamStart, VP_DEF
AULT_AFFINITY).previous(); |
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 = pos.upstream(); | 236 m_upstreamStart = mostBackwardCaretPosition(pos); |
237 m_downstreamStart = pos.downstream(); | 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 = VisiblePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY).next().d
eepEquivalent(); | 248 pos = VisiblePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY).next().d
eepEquivalent(); |
249 m_upstreamEnd = pos.upstream(); | 249 m_upstreamEnd = mostBackwardCaretPosition(pos); |
250 m_downstreamEnd = pos.downstream(); | 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. |
259 // FIXME: parentAnchoredEquivalent should eventually be moved into enclosing
element getters | 259 // FIXME: parentAnchoredEquivalent should eventually be moved into enclosing
element getters |
260 // like the one below, since editing functions should obviously accept editi
ng positions. | 260 // like the one below, since editing functions should obviously accept editi
ng positions. |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
647 && listItemInFirstParagraph->parentElement() != listItemInSecondParagrap
h->parentElement() | 647 && listItemInFirstParagraph->parentElement() != listItemInSecondParagrap
h->parentElement() |
648 && canMergeLists(listItemInFirstParagraph->parentElement(), listItemInSe
condParagraph->parentElement())) { | 648 && canMergeLists(listItemInFirstParagraph->parentElement(), listItemInSe
condParagraph->parentElement())) { |
649 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), listIt
emInSecondParagraph->parentElement()); | 649 mergeIdenticalElements(listItemInFirstParagraph->parentElement(), listIt
emInSecondParagraph->parentElement()); |
650 m_endingPosition = mergeDestination.deepEquivalent(); | 650 m_endingPosition = mergeDestination.deepEquivalent(); |
651 return; | 651 return; |
652 } | 652 } |
653 | 653 |
654 // The rule for merging into an empty block is: only do so if its farther to
the right. | 654 // The rule for merging into an empty block is: only do so if its farther to
the right. |
655 // FIXME: Consider RTL. | 655 // FIXME: Consider RTL. |
656 if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && startOfP
aragraphToMove.absoluteCaretBounds().x() > mergeDestination.absoluteCaretBounds(
).x()) { | 656 if (!m_startsAtEmptyLine && isStartOfParagraph(mergeDestination) && startOfP
aragraphToMove.absoluteCaretBounds().x() > mergeDestination.absoluteCaretBounds(
).x()) { |
657 if (isHTMLBRElement(*mergeDestination.deepEquivalent().downstream().anch
orNode())) { | 657 if (isHTMLBRElement(*mostForwardCaretPosition(mergeDestination.deepEquiv
alent()).anchorNode())) { |
658 removeNodeAndPruneAncestors(mergeDestination.deepEquivalent().downst
ream().anchorNode()); | 658 removeNodeAndPruneAncestors(mostForwardCaretPosition(mergeDestinatio
n.deepEquivalent()).anchorNode()); |
659 m_endingPosition = startOfParagraphToMove.deepEquivalent(); | 659 m_endingPosition = startOfParagraphToMove.deepEquivalent(); |
660 return; | 660 return; |
661 } | 661 } |
662 } | 662 } |
663 | 663 |
664 // Block images, tables and horizontal rules cannot be made inline with cont
ent at mergeDestination. If there is | 664 // Block images, tables and horizontal rules cannot be made inline with cont
ent at mergeDestination. If there is |
665 // any (!isStartOfParagraph(mergeDestination)), don't merge, just move the c
aret to just before the selection we deleted. | 665 // any (!isStartOfParagraph(mergeDestination)), don't merge, just move the c
aret to just before the selection we deleted. |
666 // See https://bugs.webkit.org/show_bug.cgi?id=25439 | 666 // See https://bugs.webkit.org/show_bug.cgi?id=25439 |
667 if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalen
t().anchorNode()) && !isStartOfParagraph(mergeDestination)) { | 667 if (isRenderedAsNonInlineTableImageOrHR(startOfParagraphToMove.deepEquivalen
t().anchorNode()) && !isStartOfParagraph(mergeDestination)) { |
668 m_endingPosition = m_upstreamStart; | 668 m_endingPosition = m_upstreamStart; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
787 // use the current ending selection. | 787 // use the current ending selection. |
788 if (!m_hasSelectionToDelete) | 788 if (!m_hasSelectionToDelete) |
789 m_selectionToDelete = endingSelection(); | 789 m_selectionToDelete = endingSelection(); |
790 | 790 |
791 if (!m_selectionToDelete.isNonOrphanedRange() || !m_selectionToDelete.isCont
entEditable()) | 791 if (!m_selectionToDelete.isNonOrphanedRange() || !m_selectionToDelete.isCont
entEditable()) |
792 return; | 792 return; |
793 | 793 |
794 // save this to later make the selection with | 794 // save this to later make the selection with |
795 TextAffinity affinity = m_selectionToDelete.affinity(); | 795 TextAffinity affinity = m_selectionToDelete.affinity(); |
796 | 796 |
797 Position downstreamEnd = m_selectionToDelete.end().downstream(); | 797 Position downstreamEnd = mostForwardCaretPosition(m_selectionToDelete.end())
; |
798 bool rootWillStayOpenWithoutPlaceholder = downstreamEnd.computeContainerNode
() == downstreamEnd.computeContainerNode()->rootEditableElement() | 798 bool rootWillStayOpenWithoutPlaceholder = downstreamEnd.computeContainerNode
() == downstreamEnd.computeContainerNode()->rootEditableElement() |
799 || (downstreamEnd.computeContainerNode()->isTextNode() && downstreamEnd.
computeContainerNode()->parentNode() == downstreamEnd.computeContainerNode()->ro
otEditableElement()); | 799 || (downstreamEnd.computeContainerNode()->isTextNode() && downstreamEnd.
computeContainerNode()->parentNode() == downstreamEnd.computeContainerNode()->ro
otEditableElement()); |
800 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_
selectionToDelete.visibleEnd()); | 800 bool lineBreakAtEndOfSelectionToDelete = lineBreakExistsAtVisiblePosition(m_
selectionToDelete.visibleEnd()); |
801 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder | 801 m_needPlaceholder = !rootWillStayOpenWithoutPlaceholder |
802 && isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditin
gBoundary) | 802 && isStartOfParagraph(m_selectionToDelete.visibleStart(), CanCrossEditin
gBoundary) |
803 && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBou
ndary) | 803 && isEndOfParagraph(m_selectionToDelete.visibleEnd(), CanCrossEditingBou
ndary) |
804 && !lineBreakAtEndOfSelectionToDelete; | 804 && !lineBreakAtEndOfSelectionToDelete; |
805 if (m_needPlaceholder) { | 805 if (m_needPlaceholder) { |
806 // Don't need a placeholder when deleting a selection that starts just | 806 // Don't need a placeholder when deleting a selection that starts just |
807 // before a table and ends inside it (we do need placeholders to hold | 807 // before a table and ends inside it (we do need placeholders to hold |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
899 visitor->trace(m_deleteIntoBlockquoteStyle); | 899 visitor->trace(m_deleteIntoBlockquoteStyle); |
900 visitor->trace(m_startRoot); | 900 visitor->trace(m_startRoot); |
901 visitor->trace(m_endRoot); | 901 visitor->trace(m_endRoot); |
902 visitor->trace(m_startTableRow); | 902 visitor->trace(m_startTableRow); |
903 visitor->trace(m_endTableRow); | 903 visitor->trace(m_endTableRow); |
904 visitor->trace(m_temporaryPlaceholder); | 904 visitor->trace(m_temporaryPlaceholder); |
905 CompositeEditCommand::trace(visitor); | 905 CompositeEditCommand::trace(visitor); |
906 } | 906 } |
907 | 907 |
908 } // namespace blink | 908 } // namespace blink |
OLD | NEW |