| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved. | 3 * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 VisiblePosition startOfInsertedContent = positionAtStartOfInsertedContent(); | 429 VisiblePosition startOfInsertedContent = positionAtStartOfInsertedContent(); |
| 430 VisiblePosition prev = previousPositionOf(startOfInsertedContent, CannotCros
sEditingBoundary); | 430 VisiblePosition prev = previousPositionOf(startOfInsertedContent, CannotCros
sEditingBoundary); |
| 431 if (prev.isNull()) | 431 if (prev.isNull()) |
| 432 return false; | 432 return false; |
| 433 | 433 |
| 434 // When we have matching quote levels, its ok to merge more frequently. | 434 // When we have matching quote levels, its ok to merge more frequently. |
| 435 // For a successful merge, we still need to make sure that the inserted cont
ent starts with the beginning of a paragraph. | 435 // For a successful merge, we still need to make sure that the inserted cont
ent starts with the beginning of a paragraph. |
| 436 // And we should only merge here if the selection start was inside a mail bl
ockquote. This prevents against removing a | 436 // And we should only merge here if the selection start was inside a mail bl
ockquote. This prevents against removing a |
| 437 // blockquote from newly pasted quoted content that was pasted into an unquo
ted position. If that unquoted position happens | 437 // blockquote from newly pasted quoted content that was pasted into an unquo
ted position. If that unquoted position happens |
| 438 // to be right after another blockquote, we don't want to merge and risk str
ipping a valid block (and newline) from the pasted content. | 438 // to be right after another blockquote, we don't want to merge and risk str
ipping a valid block (and newline) from the pasted content. |
| 439 if (isStartOfParagraph(startOfInsertedContent) && selectionStartWasInsideMai
lBlockquote && hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent())) | 439 if (isStartOfParagraphDeprecated(startOfInsertedContent) && selectionStartWa
sInsideMailBlockquote && hasMatchingQuoteLevel(prev, positionAtEndOfInsertedCont
ent())) |
| 440 return true; | 440 return true; |
| 441 | 441 |
| 442 return !selectionStartWasStartOfParagraph | 442 return !selectionStartWasStartOfParagraph |
| 443 && !fragmentHasInterchangeNewlineAtStart | 443 && !fragmentHasInterchangeNewlineAtStart |
| 444 && isStartOfParagraph(startOfInsertedContent) | 444 && isStartOfParagraphDeprecated(startOfInsertedContent) |
| 445 && !isHTMLBRElement(*startOfInsertedContent.deepEquivalent().anchorNode(
)) | 445 && !isHTMLBRElement(*startOfInsertedContent.deepEquivalent().anchorNode(
)) |
| 446 && shouldMerge(startOfInsertedContent, prev); | 446 && shouldMerge(startOfInsertedContent, prev); |
| 447 } | 447 } |
| 448 | 448 |
| 449 bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph) | 449 bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph) |
| 450 { | 450 { |
| 451 VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent()); | 451 VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent()); |
| 452 VisiblePosition next = nextPositionOf(endOfInsertedContent, CannotCrossEditi
ngBoundary); | 452 VisiblePosition next = nextPositionOf(endOfInsertedContent, CannotCrossEditi
ngBoundary); |
| 453 if (next.isNull()) | 453 if (next.isNull()) |
| 454 return false; | 454 return false; |
| 455 | 455 |
| 456 return !selectionEndWasEndOfParagraph | 456 return !selectionEndWasEndOfParagraph |
| 457 && isEndOfParagraph(endOfInsertedContent) | 457 && isEndOfParagraphDeprecated(endOfInsertedContent) |
| 458 && !isHTMLBRElement(*endOfInsertedContent.deepEquivalent().anchorNode()) | 458 && !isHTMLBRElement(*endOfInsertedContent.deepEquivalent().anchorNode()) |
| 459 && shouldMerge(endOfInsertedContent, next); | 459 && shouldMerge(endOfInsertedContent, next); |
| 460 } | 460 } |
| 461 | 461 |
| 462 static bool isMailPasteAsQuotationHTMLBlockQuoteElement(const Node* node) | 462 static bool isMailPasteAsQuotationHTMLBlockQuoteElement(const Node* node) |
| 463 { | 463 { |
| 464 if (!node || !node->isHTMLElement()) | 464 if (!node || !node->isHTMLElement()) |
| 465 return false; | 465 return false; |
| 466 const HTMLElement& element = toHTMLElement(*node); | 466 const HTMLElement& element = toHTMLElement(*node); |
| 467 if (!element.hasTagName(blockquoteTag) || element.getAttribute(classAttr) !=
ApplePasteAsQuotation) | 467 if (!element.hasTagName(blockquoteTag) || element.getAttribute(classAttr) !=
ApplePasteAsQuotation) |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 928 // Bail to avoid infinite recursion. | 928 // Bail to avoid infinite recursion. |
| 929 if (m_movingParagraph) { | 929 if (m_movingParagraph) { |
| 930 NOTREACHED(); | 930 NOTREACHED(); |
| 931 return; | 931 return; |
| 932 } | 932 } |
| 933 | 933 |
| 934 // Merging two paragraphs will destroy the moved one's block styles. Always
move the end of inserted forward | 934 // Merging two paragraphs will destroy the moved one's block styles. Always
move the end of inserted forward |
| 935 // to preserve the block style of the paragraph already in the document, unl
ess the paragraph to move would | 935 // to preserve the block style of the paragraph already in the document, unl
ess the paragraph to move would |
| 936 // include the what was the start of the selection that was pasted into, so
that we preserve that paragraph's | 936 // include the what was the start of the selection that was pasted into, so
that we preserve that paragraph's |
| 937 // block styles. | 937 // block styles. |
| 938 bool mergeForward = !(inSameParagraph(startOfInsertedContent, endOfInsertedC
ontent) && !isStartOfParagraph(startOfInsertedContent)); | 938 bool mergeForward = !(inSameParagraphDeprecated(startOfInsertedContent, endO
fInsertedContent) && !isStartOfParagraphDeprecated(startOfInsertedContent)); |
| 939 | 939 |
| 940 VisiblePosition destination = mergeForward ? nextPositionOf(endOfInsertedCon
tent) : endOfInsertedContent; | 940 VisiblePosition destination = mergeForward ? nextPositionOf(endOfInsertedCon
tent) : endOfInsertedContent; |
| 941 VisiblePosition startOfParagraphToMove = mergeForward ? startOfParagraph(end
OfInsertedContent) : nextPositionOf(endOfInsertedContent); | 941 VisiblePosition startOfParagraphToMove = mergeForward ? startOfParagraphDepr
ecated(endOfInsertedContent) : nextPositionOf(endOfInsertedContent); |
| 942 | 942 |
| 943 // Merging forward could result in deleting the destination anchor node. | 943 // Merging forward could result in deleting the destination anchor node. |
| 944 // To avoid this, we add a placeholder node before the start of the paragrap
h. | 944 // To avoid this, we add a placeholder node before the start of the paragrap
h. |
| 945 if (endOfParagraph(startOfParagraphToMove).deepEquivalent() == destination.d
eepEquivalent()) { | 945 if (endOfParagraphDeprecated(startOfParagraphToMove).deepEquivalent() == des
tination.deepEquivalent()) { |
| 946 HTMLBRElement* placeholder = HTMLBRElement::create(document()); | 946 HTMLBRElement* placeholder = HTMLBRElement::create(document()); |
| 947 insertNodeBefore(placeholder, startOfParagraphToMove.deepEquivalent().an
chorNode(), editingState); | 947 insertNodeBefore(placeholder, startOfParagraphToMove.deepEquivalent().an
chorNode(), editingState); |
| 948 if (editingState->isAborted()) | 948 if (editingState->isAborted()) |
| 949 return; | 949 return; |
| 950 destination = VisiblePosition::beforeNode(placeholder); | 950 destination = VisiblePosition::beforeNode(placeholder); |
| 951 } | 951 } |
| 952 | 952 |
| 953 moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove)
, destination, editingState); | 953 moveParagraph(startOfParagraphToMove, endOfParagraphDeprecated(startOfParagr
aphToMove), destination, editingState); |
| 954 if (editingState->isAborted()) | 954 if (editingState->isAborted()) |
| 955 return; | 955 return; |
| 956 | 956 |
| 957 // Merging forward will remove m_endOfInsertedContent from the document. | 957 // Merging forward will remove m_endOfInsertedContent from the document. |
| 958 if (mergeForward) { | 958 if (mergeForward) { |
| 959 if (m_startOfInsertedContent.isOrphan()) | 959 if (m_startOfInsertedContent.isOrphan()) |
| 960 m_startOfInsertedContent = endingSelection().visibleStart().deepEqui
valent(); | 960 m_startOfInsertedContent = endingSelection().visibleStart().deepEqui
valent(); |
| 961 m_endOfInsertedContent = endingSelection().visibleEnd().deepEquivalent()
; | 961 m_endOfInsertedContent = endingSelection().visibleEnd().deepEquivalent()
; |
| 962 // If we merged text nodes, m_endOfInsertedContent could be null. If | 962 // If we merged text nodes, m_endOfInsertedContent could be null. If |
| 963 // this is the case, we use m_startOfInsertedContent. | 963 // this is the case, we use m_startOfInsertedContent. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1041 m_matchStyle = false; | 1041 m_matchStyle = false; |
| 1042 | 1042 |
| 1043 if (m_matchStyle) { | 1043 if (m_matchStyle) { |
| 1044 m_insertionStyle = EditingStyle::create(selection.start()); | 1044 m_insertionStyle = EditingStyle::create(selection.start()); |
| 1045 m_insertionStyle->mergeTypingStyle(&document()); | 1045 m_insertionStyle->mergeTypingStyle(&document()); |
| 1046 } | 1046 } |
| 1047 | 1047 |
| 1048 const VisiblePosition visibleStart = selection.visibleStart(); | 1048 const VisiblePosition visibleStart = selection.visibleStart(); |
| 1049 const VisiblePosition visibleEnd = selection.visibleEnd(); | 1049 const VisiblePosition visibleEnd = selection.visibleEnd(); |
| 1050 | 1050 |
| 1051 const bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd); | 1051 const bool selectionEndWasEndOfParagraph = isEndOfParagraphDeprecated(visibl
eEnd); |
| 1052 const bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleSta
rt); | 1052 const bool selectionStartWasStartOfParagraph = isStartOfParagraphDeprecated(
visibleStart); |
| 1053 | 1053 |
| 1054 Element* enclosingBlockOfVisibleStart = enclosingBlock(visibleStart.deepEqui
valent().anchorNode()); | 1054 Element* enclosingBlockOfVisibleStart = enclosingBlock(visibleStart.deepEqui
valent().anchorNode()); |
| 1055 | 1055 |
| 1056 const bool startIsInsideMailBlockquote = enclosingNodeOfType(selection.start
(), isMailHTMLBlockquoteElement, CanCrossEditingBoundary); | 1056 const bool startIsInsideMailBlockquote = enclosingNodeOfType(selection.start
(), isMailHTMLBlockquoteElement, CanCrossEditingBoundary); |
| 1057 const bool selectionIsPlainText = !selection.isContentRichlyEditable(); | 1057 const bool selectionIsPlainText = !selection.isContentRichlyEditable(); |
| 1058 Element* currentRoot = selection.rootEditableElement(); | 1058 Element* currentRoot = selection.rootEditableElement(); |
| 1059 | 1059 |
| 1060 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !
startIsInsideMailBlockquote) | 1060 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && !
startIsInsideMailBlockquote) |
| 1061 || enclosingBlockOfVisibleStart == currentRoot | 1061 || enclosingBlockOfVisibleStart == currentRoot |
| 1062 || isListItem(enclosingBlockOfVisibleStart) | 1062 || isListItem(enclosingBlockOfVisibleStart) |
| 1063 || selectionIsPlainText) { | 1063 || selectionIsPlainText) { |
| 1064 m_preventNesting = false; | 1064 m_preventNesting = false; |
| 1065 } | 1065 } |
| 1066 | 1066 |
| 1067 if (selection.isRange()) { | 1067 if (selection.isRange()) { |
| 1068 // When the end of the selection being pasted into is at the end of a pa
ragraph, and that selection | 1068 // When the end of the selection being pasted into is at the end of a pa
ragraph, and that selection |
| 1069 // spans multiple blocks, not merging may leave an empty line. | 1069 // spans multiple blocks, not merging may leave an empty line. |
| 1070 // When the start of the selection being pasted into is at the start of
a block, not merging | 1070 // When the start of the selection being pasted into is at the start of
a block, not merging |
| 1071 // will leave hanging block(s). | 1071 // will leave hanging block(s). |
| 1072 // Merge blocks if the start of the selection was in a Mail blockquote,
since we handle | 1072 // Merge blocks if the start of the selection was in a Mail blockquote,
since we handle |
| 1073 // that case specially to prevent nesting. | 1073 // that case specially to prevent nesting. |
| 1074 bool mergeBlocksAfterDelete = startIsInsideMailBlockquote || isEndOfPara
graph(visibleEnd) || isStartOfBlock(visibleStart); | 1074 bool mergeBlocksAfterDelete = startIsInsideMailBlockquote || isEndOfPara
graphDeprecated(visibleEnd) || isStartOfBlock(visibleStart); |
| 1075 // FIXME: We should only expand to include fully selected special elemen
ts if we are copying a | 1075 // FIXME: We should only expand to include fully selected special elemen
ts if we are copying a |
| 1076 // selection and pasting it on top of itself. | 1076 // selection and pasting it on top of itself. |
| 1077 deleteSelection(editingState, false, mergeBlocksAfterDelete, false); | 1077 deleteSelection(editingState, false, mergeBlocksAfterDelete, false); |
| 1078 if (editingState->isAborted()) | 1078 if (editingState->isAborted()) |
| 1079 return; | 1079 return; |
| 1080 if (fragment.hasInterchangeNewlineAtStart()) { | 1080 if (fragment.hasInterchangeNewlineAtStart()) { |
| 1081 VisiblePosition startAfterDelete = endingSelection().visibleStart(); | 1081 VisiblePosition startAfterDelete = endingSelection().visibleStart(); |
| 1082 if (isEndOfParagraph(startAfterDelete) && !isStartOfParagraph(startA
fterDelete) && !isEndOfEditableOrNonEditableContent(startAfterDelete)) | 1082 if (isEndOfParagraphDeprecated(startAfterDelete) && !isStartOfParagr
aphDeprecated(startAfterDelete) && !isEndOfEditableOrNonEditableContent(startAft
erDelete)) |
| 1083 setEndingSelection(nextPositionOf(startAfterDelete)); | 1083 setEndingSelection(nextPositionOf(startAfterDelete)); |
| 1084 else | 1084 else |
| 1085 insertParagraphSeparator(editingState); | 1085 insertParagraphSeparator(editingState); |
| 1086 if (editingState->isAborted()) | 1086 if (editingState->isAborted()) |
| 1087 return; | 1087 return; |
| 1088 } | 1088 } |
| 1089 } else { | 1089 } else { |
| 1090 DCHECK(selection.isCaret()); | 1090 DCHECK(selection.isCaret()); |
| 1091 if (fragment.hasInterchangeNewlineAtStart()) { | 1091 if (fragment.hasInterchangeNewlineAtStart()) { |
| 1092 const VisiblePosition next = nextPositionOf(visibleStart, CannotCros
sEditingBoundary); | 1092 const VisiblePosition next = nextPositionOf(visibleStart, CannotCros
sEditingBoundary); |
| 1093 if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleSta
rt) && next.isNotNull()) | 1093 if (isEndOfParagraphDeprecated(visibleStart) && !isStartOfParagraphD
eprecated(visibleStart) && next.isNotNull()) |
| 1094 setEndingSelection(next); | 1094 setEndingSelection(next); |
| 1095 else | 1095 else |
| 1096 insertParagraphSeparator(editingState); | 1096 insertParagraphSeparator(editingState); |
| 1097 if (editingState->isAborted()) | 1097 if (editingState->isAborted()) |
| 1098 return; | 1098 return; |
| 1099 } | 1099 } |
| 1100 // We split the current paragraph in two to avoid nesting the blocks fro
m the fragment inside the current block. | 1100 // We split the current paragraph in two to avoid nesting the blocks fro
m the fragment inside the current block. |
| 1101 // For example paste <div>foo</div><div>bar</div><div>baz</div> into <di
v>x^x</div>, where ^ is the caret. | 1101 // For example paste <div>foo</div><div>bar</div><div>baz</div> into <di
v>x^x</div>, where ^ is the caret. |
| 1102 // As long as the div styles are the same, visually you'd expect: <div>
xbar</div><div>bar</div><div>bazx</div>, | 1102 // As long as the div styles are the same, visually you'd expect: <div>
xbar</div><div>bar</div><div>bazx</div>, |
| 1103 // not <div>xbar<div>bar</div><div>bazx</div></div>. | 1103 // not <div>xbar<div>bar</div><div>bazx</div></div>. |
| 1104 // Don't do this if the selection started in a Mail blockquote. | 1104 // Don't do this if the selection started in a Mail blockquote. |
| 1105 if (m_preventNesting && !startIsInsideMailBlockquote && !isEndOfParagrap
h(endingSelection().visibleStart()) && !isStartOfParagraph(endingSelection().vis
ibleStart())) { | 1105 if (m_preventNesting && !startIsInsideMailBlockquote && !isEndOfParagrap
hDeprecated(endingSelection().visibleStart()) && !isStartOfParagraphDeprecated(e
ndingSelection().visibleStart())) { |
| 1106 insertParagraphSeparator(editingState); | 1106 insertParagraphSeparator(editingState); |
| 1107 if (editingState->isAborted()) | 1107 if (editingState->isAborted()) |
| 1108 return; | 1108 return; |
| 1109 setEndingSelection(previousPositionOf(endingSelection().visibleStart
())); | 1109 setEndingSelection(previousPositionOf(endingSelection().visibleStart
())); |
| 1110 } | 1110 } |
| 1111 } | 1111 } |
| 1112 | 1112 |
| 1113 Position insertionPos = endingSelection().start(); | 1113 Position insertionPos = endingSelection().start(); |
| 1114 // We don't want any of the pasted content to end up nested in a Mail blockq
uote, so first break | 1114 // We don't want any of the pasted content to end up nested in a Mail blockq
uote, so first break |
| 1115 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl
e, in which case | 1115 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl
e, in which case |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1277 | 1277 |
| 1278 // Scripts specified in javascript protocol may remove |enclosingBlockOfInse
rtionPos| | 1278 // Scripts specified in javascript protocol may remove |enclosingBlockOfInse
rtionPos| |
| 1279 // during insertion, e.g. <iframe src="javascript:..."> | 1279 // during insertion, e.g. <iframe src="javascript:..."> |
| 1280 if (enclosingBlockOfInsertionPos && !enclosingBlockOfInsertionPos->isConnect
ed()) | 1280 if (enclosingBlockOfInsertionPos && !enclosingBlockOfInsertionPos->isConnect
ed()) |
| 1281 enclosingBlockOfInsertionPos = nullptr; | 1281 enclosingBlockOfInsertionPos = nullptr; |
| 1282 | 1282 |
| 1283 VisiblePosition startOfInsertedContent = createVisiblePositionDeprecated(fir
stPositionInOrBeforeNode(insertedNodes.firstNodeInserted())); | 1283 VisiblePosition startOfInsertedContent = createVisiblePositionDeprecated(fir
stPositionInOrBeforeNode(insertedNodes.firstNodeInserted())); |
| 1284 | 1284 |
| 1285 // We inserted before the enclosingBlockOfInsertionPos to prevent nesting, a
nd the content before the enclosingBlockOfInsertionPos wasn't in its own block a
nd | 1285 // We inserted before the enclosingBlockOfInsertionPos to prevent nesting, a
nd the content before the enclosingBlockOfInsertionPos wasn't in its own block a
nd |
| 1286 // didn't have a br after it, so the inserted content ended up in the same p
aragraph. | 1286 // didn't have a br after it, so the inserted content ended up in the same p
aragraph. |
| 1287 if (!startOfInsertedContent.isNull() && enclosingBlockOfInsertionPos && inse
rtionPos.anchorNode() == enclosingBlockOfInsertionPos->parentNode() && (unsigned
)insertionPos.computeEditingOffset() < enclosingBlockOfInsertionPos->nodeIndex()
&& !isStartOfParagraph(startOfInsertedContent)) { | 1287 if (!startOfInsertedContent.isNull() && enclosingBlockOfInsertionPos && inse
rtionPos.anchorNode() == enclosingBlockOfInsertionPos->parentNode() && (unsigned
)insertionPos.computeEditingOffset() < enclosingBlockOfInsertionPos->nodeIndex()
&& !isStartOfParagraphDeprecated(startOfInsertedContent)) { |
| 1288 insertNodeAt(HTMLBRElement::create(document()), startOfInsertedContent.d
eepEquivalent(), editingState); | 1288 insertNodeAt(HTMLBRElement::create(document()), startOfInsertedContent.d
eepEquivalent(), editingState); |
| 1289 if (editingState->isAborted()) | 1289 if (editingState->isAborted()) |
| 1290 return; | 1290 return; |
| 1291 } | 1291 } |
| 1292 | 1292 |
| 1293 if (endBR && (plainTextFragment || (shouldRemoveEndBR(endBR, originalVisPosB
eforeEndBR) && !(fragment.hasInterchangeNewlineAtEnd() && selectionIsPlainText))
)) { | 1293 if (endBR && (plainTextFragment || (shouldRemoveEndBR(endBR, originalVisPosB
eforeEndBR) && !(fragment.hasInterchangeNewlineAtEnd() && selectionIsPlainText))
)) { |
| 1294 ContainerNode* parent = endBR->parentNode(); | 1294 ContainerNode* parent = endBR->parentNode(); |
| 1295 insertedNodes.willRemoveNode(*endBR); | 1295 insertedNodes.willRemoveNode(*endBR); |
| 1296 removeNode(endBR, editingState); | 1296 removeNode(endBR, editingState); |
| 1297 if (editingState->isAborted()) | 1297 if (editingState->isAborted()) |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1340 } | 1340 } |
| 1341 | 1341 |
| 1342 // Merging the the first paragraph of inserted content with the content
that came | 1342 // Merging the the first paragraph of inserted content with the content
that came |
| 1343 // before the selection that was pasted into would also move content aft
er | 1343 // before the selection that was pasted into would also move content aft
er |
| 1344 // the selection that was pasted into if: only one paragraph was being p
asted, | 1344 // the selection that was pasted into if: only one paragraph was being p
asted, |
| 1345 // and it was not wrapped in a block, the selection that was pasted into
ended | 1345 // and it was not wrapped in a block, the selection that was pasted into
ended |
| 1346 // at the end of a block and the next paragraph didn't start at the star
t of a block. | 1346 // at the end of a block and the next paragraph didn't start at the star
t of a block. |
| 1347 // Insert a line break just after the inserted content to separate it fr
om what | 1347 // Insert a line break just after the inserted content to separate it fr
om what |
| 1348 // comes after and prevent that from happening. | 1348 // comes after and prevent that from happening. |
| 1349 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); | 1349 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); |
| 1350 if (startOfParagraph(endOfInsertedContent).deepEquivalent() == startOfPa
ragraphToMove.deepEquivalent()) { | 1350 if (startOfParagraphDeprecated(endOfInsertedContent).deepEquivalent() ==
startOfParagraphToMove.deepEquivalent()) { |
| 1351 insertNodeAt(HTMLBRElement::create(document()), endOfInsertedContent
.deepEquivalent(), editingState); | 1351 insertNodeAt(HTMLBRElement::create(document()), endOfInsertedContent
.deepEquivalent(), editingState); |
| 1352 if (editingState->isAborted()) | 1352 if (editingState->isAborted()) |
| 1353 return; | 1353 return; |
| 1354 // Mutation events (bug 22634) triggered by inserting the <br> might
have removed the content we're about to move | 1354 // Mutation events (bug 22634) triggered by inserting the <br> might
have removed the content we're about to move |
| 1355 if (!startOfParagraphToMove.deepEquivalent().isConnected()) | 1355 if (!startOfParagraphToMove.deepEquivalent().isConnected()) |
| 1356 return; | 1356 return; |
| 1357 } | 1357 } |
| 1358 | 1358 |
| 1359 // FIXME: Maintain positions for the start and end of inserted content i
nstead of keeping nodes. The nodes are | 1359 // FIXME: Maintain positions for the start and end of inserted content i
nstead of keeping nodes. The nodes are |
| 1360 // only ever used to create positions where inserted content starts/ends
. | 1360 // only ever used to create positions where inserted content starts/ends
. |
| 1361 moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToM
ove), destination, editingState); | 1361 moveParagraph(startOfParagraphToMove, endOfParagraphDeprecated(startOfPa
ragraphToMove), destination, editingState); |
| 1362 if (editingState->isAborted()) | 1362 if (editingState->isAborted()) |
| 1363 return; | 1363 return; |
| 1364 m_startOfInsertedContent = mostForwardCaretPosition(endingSelection().vi
sibleStart().deepEquivalent()); | 1364 m_startOfInsertedContent = mostForwardCaretPosition(endingSelection().vi
sibleStart().deepEquivalent()); |
| 1365 if (m_endOfInsertedContent.isOrphan()) | 1365 if (m_endOfInsertedContent.isOrphan()) |
| 1366 m_endOfInsertedContent = mostBackwardCaretPosition(endingSelection()
.visibleEnd().deepEquivalent()); | 1366 m_endOfInsertedContent = mostBackwardCaretPosition(endingSelection()
.visibleEnd().deepEquivalent()); |
| 1367 } | 1367 } |
| 1368 | 1368 |
| 1369 Position lastPositionToSelect; | 1369 Position lastPositionToSelect; |
| 1370 if (fragment.hasInterchangeNewlineAtEnd()) { | 1370 if (fragment.hasInterchangeNewlineAtEnd()) { |
| 1371 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); | 1371 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); |
| 1372 VisiblePosition next = nextPositionOf(endOfInsertedContent, CannotCrossE
ditingBoundary); | 1372 VisiblePosition next = nextPositionOf(endOfInsertedContent, CannotCrossE
ditingBoundary); |
| 1373 | 1373 |
| 1374 if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedCont
ent) || next.isNull()) { | 1374 if (selectionEndWasEndOfParagraph || !isEndOfParagraphDeprecated(endOfIn
sertedContent) || next.isNull()) { |
| 1375 if (HTMLTextFormControlElement* textControl = enclosingTextFormContr
ol(currentRoot)) { | 1375 if (HTMLTextFormControlElement* textControl = enclosingTextFormContr
ol(currentRoot)) { |
| 1376 if (!insertedNodes.lastLeafInserted()->nextSibling()) { | 1376 if (!insertedNodes.lastLeafInserted()->nextSibling()) { |
| 1377 insertNodeAfter(textControl->createPlaceholderBreakElement()
, insertedNodes.lastLeafInserted(), editingState); | 1377 insertNodeAfter(textControl->createPlaceholderBreakElement()
, insertedNodes.lastLeafInserted(), editingState); |
| 1378 if (editingState->isAborted()) | 1378 if (editingState->isAborted()) |
| 1379 return; | 1379 return; |
| 1380 } | 1380 } |
| 1381 setEndingSelection(VisiblePosition::afterNode(insertedNodes.last
LeafInserted())); | 1381 setEndingSelection(VisiblePosition::afterNode(insertedNodes.last
LeafInserted())); |
| 1382 // Select up to the paragraph separator that was added. | 1382 // Select up to the paragraph separator that was added. |
| 1383 lastPositionToSelect = endingSelection().visibleStart().deepEqui
valent(); | 1383 lastPositionToSelect = endingSelection().visibleStart().deepEqui
valent(); |
| 1384 } else if (!isStartOfParagraph(endOfInsertedContent)) { | 1384 } else if (!isStartOfParagraphDeprecated(endOfInsertedContent)) { |
| 1385 setEndingSelection(endOfInsertedContent); | 1385 setEndingSelection(endOfInsertedContent); |
| 1386 Element* enclosingBlockElement = enclosingBlock(endOfInsertedCon
tent.deepEquivalent().anchorNode()); | 1386 Element* enclosingBlockElement = enclosingBlock(endOfInsertedCon
tent.deepEquivalent().anchorNode()); |
| 1387 if (isListItem(enclosingBlockElement)) { | 1387 if (isListItem(enclosingBlockElement)) { |
| 1388 HTMLLIElement* newListItem = HTMLLIElement::create(document(
)); | 1388 HTMLLIElement* newListItem = HTMLLIElement::create(document(
)); |
| 1389 insertNodeAfter(newListItem, enclosingBlockElement, editingS
tate); | 1389 insertNodeAfter(newListItem, enclosingBlockElement, editingS
tate); |
| 1390 if (editingState->isAborted()) | 1390 if (editingState->isAborted()) |
| 1391 return; | 1391 return; |
| 1392 setEndingSelection(VisiblePosition::firstPositionInNode(newL
istItem)); | 1392 setEndingSelection(VisiblePosition::firstPositionInNode(newL
istItem)); |
| 1393 } else { | 1393 } else { |
| 1394 // Use a default paragraph element (a plain div) for the emp
ty paragraph, using the last paragraph | 1394 // Use a default paragraph element (a plain div) for the emp
ty paragraph, using the last paragraph |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1435 if (!endBR || !endBR->isConnected()) | 1435 if (!endBR || !endBR->isConnected()) |
| 1436 return false; | 1436 return false; |
| 1437 | 1437 |
| 1438 VisiblePosition visiblePos = VisiblePosition::beforeNode(endBR); | 1438 VisiblePosition visiblePos = VisiblePosition::beforeNode(endBR); |
| 1439 | 1439 |
| 1440 // Don't remove the br if nothing was inserted. | 1440 // Don't remove the br if nothing was inserted. |
| 1441 if (previousPositionOf(visiblePos).deepEquivalent() == originalVisPosBeforeE
ndBR.deepEquivalent()) | 1441 if (previousPositionOf(visiblePos).deepEquivalent() == originalVisPosBeforeE
ndBR.deepEquivalent()) |
| 1442 return false; | 1442 return false; |
| 1443 | 1443 |
| 1444 // Remove the br if it is collapsed away and so is unnecessary. | 1444 // Remove the br if it is collapsed away and so is unnecessary. |
| 1445 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && !isStartOfPa
ragraph(visiblePos)) | 1445 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && !isStartOfPa
ragraphDeprecated(visiblePos)) |
| 1446 return true; | 1446 return true; |
| 1447 | 1447 |
| 1448 // A br that was originally holding a line open should be displaced by inser
ted content or turned into a line break. | 1448 // A br that was originally holding a line open should be displaced by inser
ted content or turned into a line break. |
| 1449 // A br that was originally acting as a line break should still be acting as
a line break, not as a placeholder. | 1449 // A br that was originally acting as a line break should still be acting as
a line break, not as a placeholder. |
| 1450 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos); | 1450 return isStartOfParagraphDeprecated(visiblePos) && isEndOfParagraphDeprecate
d(visiblePos); |
| 1451 } | 1451 } |
| 1452 | 1452 |
| 1453 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const | 1453 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const |
| 1454 { | 1454 { |
| 1455 if (!m_smartReplace) | 1455 if (!m_smartReplace) |
| 1456 return false; | 1456 return false; |
| 1457 | 1457 |
| 1458 HTMLTextFormControlElement* textControl = enclosingTextFormControl(positionA
tStartOfInsertedContent().deepEquivalent()); | 1458 HTMLTextFormControlElement* textControl = enclosingTextFormControl(positionA
tStartOfInsertedContent().deepEquivalent()); |
| 1459 if (isHTMLInputElement(textControl) && toHTMLInputElement(textControl)->type
() == InputTypeNames::password) | 1459 if (isHTMLInputElement(textControl) && toHTMLInputElement(textControl)->type
() == InputTypeNames::password) |
| 1460 return false; // Disable smart replace for password fields. | 1460 return false; // Disable smart replace for password fields. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1473 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); | 1473 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); |
| 1474 | 1474 |
| 1475 Position endUpstream = mostBackwardCaretPosition(endOfInsertedContent.deepEq
uivalent()); | 1475 Position endUpstream = mostBackwardCaretPosition(endOfInsertedContent.deepEq
uivalent()); |
| 1476 Node* endNode = endUpstream.computeNodeBeforePosition(); | 1476 Node* endNode = endUpstream.computeNodeBeforePosition(); |
| 1477 int endOffset = endNode && endNode->isTextNode() ? toText(endNode)->length()
: 0; | 1477 int endOffset = endNode && endNode->isTextNode() ? toText(endNode)->length()
: 0; |
| 1478 if (endUpstream.isOffsetInAnchor()) { | 1478 if (endUpstream.isOffsetInAnchor()) { |
| 1479 endNode = endUpstream.computeContainerNode(); | 1479 endNode = endUpstream.computeContainerNode(); |
| 1480 endOffset = endUpstream.offsetInContainerNode(); | 1480 endOffset = endUpstream.offsetInContainerNode(); |
| 1481 } | 1481 } |
| 1482 | 1482 |
| 1483 bool needsTrailingSpace = !isEndOfParagraph(endOfInsertedContent) && !isChar
acterSmartReplaceExemptConsideringNonBreakingSpace(characterAfter(endOfInsertedC
ontent), false); | 1483 bool needsTrailingSpace = !isEndOfParagraphDeprecated(endOfInsertedContent)
&& !isCharacterSmartReplaceExemptConsideringNonBreakingSpace(characterAfter(endO
fInsertedContent), false); |
| 1484 if (needsTrailingSpace && endNode) { | 1484 if (needsTrailingSpace && endNode) { |
| 1485 bool collapseWhiteSpace = !endNode->layoutObject() || endNode->layoutObj
ect()->style()->collapseWhiteSpace(); | 1485 bool collapseWhiteSpace = !endNode->layoutObject() || endNode->layoutObj
ect()->style()->collapseWhiteSpace(); |
| 1486 if (endNode->isTextNode()) { | 1486 if (endNode->isTextNode()) { |
| 1487 insertTextIntoNode(toText(endNode), endOffset, collapseWhiteSpace ?
nonBreakingSpaceString() : " "); | 1487 insertTextIntoNode(toText(endNode), endOffset, collapseWhiteSpace ?
nonBreakingSpaceString() : " "); |
| 1488 if (m_endOfInsertedContent.computeContainerNode() == endNode) | 1488 if (m_endOfInsertedContent.computeContainerNode() == endNode) |
| 1489 m_endOfInsertedContent = Position(endNode, m_endOfInsertedConten
t.offsetInContainerNode() + 1); | 1489 m_endOfInsertedContent = Position(endNode, m_endOfInsertedConten
t.offsetInContainerNode() + 1); |
| 1490 } else { | 1490 } else { |
| 1491 Text* node = document().createEditingTextNode(collapseWhiteSpace ? n
onBreakingSpaceString() : " "); | 1491 Text* node = document().createEditingTextNode(collapseWhiteSpace ? n
onBreakingSpaceString() : " "); |
| 1492 insertNodeAfter(node, endNode, editingState); | 1492 insertNodeAfter(node, endNode, editingState); |
| 1493 if (editingState->isAborted()) | 1493 if (editingState->isAborted()) |
| 1494 return; | 1494 return; |
| 1495 updateNodesInserted(node); | 1495 updateNodesInserted(node); |
| 1496 } | 1496 } |
| 1497 } | 1497 } |
| 1498 | 1498 |
| 1499 document().updateStyleAndLayout(); | 1499 document().updateStyleAndLayout(); |
| 1500 | 1500 |
| 1501 Position startDownstream = mostForwardCaretPosition(startOfInsertedContent.d
eepEquivalent()); | 1501 Position startDownstream = mostForwardCaretPosition(startOfInsertedContent.d
eepEquivalent()); |
| 1502 Node* startNode = startDownstream.computeNodeAfterPosition(); | 1502 Node* startNode = startDownstream.computeNodeAfterPosition(); |
| 1503 unsigned startOffset = 0; | 1503 unsigned startOffset = 0; |
| 1504 if (startDownstream.isOffsetInAnchor()) { | 1504 if (startDownstream.isOffsetInAnchor()) { |
| 1505 startNode = startDownstream.computeContainerNode(); | 1505 startNode = startDownstream.computeContainerNode(); |
| 1506 startOffset = startDownstream.offsetInContainerNode(); | 1506 startOffset = startDownstream.offsetInContainerNode(); |
| 1507 } | 1507 } |
| 1508 | 1508 |
| 1509 bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) && !isC
haracterSmartReplaceExemptConsideringNonBreakingSpace(characterBefore(startOfIns
ertedContent), true); | 1509 bool needsLeadingSpace = !isStartOfParagraphDeprecated(startOfInsertedConten
t) && !isCharacterSmartReplaceExemptConsideringNonBreakingSpace(characterBefore(
startOfInsertedContent), true); |
| 1510 if (needsLeadingSpace && startNode) { | 1510 if (needsLeadingSpace && startNode) { |
| 1511 bool collapseWhiteSpace = !startNode->layoutObject() || startNode->layou
tObject()->style()->collapseWhiteSpace(); | 1511 bool collapseWhiteSpace = !startNode->layoutObject() || startNode->layou
tObject()->style()->collapseWhiteSpace(); |
| 1512 if (startNode->isTextNode()) { | 1512 if (startNode->isTextNode()) { |
| 1513 insertTextIntoNode(toText(startNode), startOffset, collapseWhiteSpac
e ? nonBreakingSpaceString() : " "); | 1513 insertTextIntoNode(toText(startNode), startOffset, collapseWhiteSpac
e ? nonBreakingSpaceString() : " "); |
| 1514 if (m_endOfInsertedContent.computeContainerNode() == startNode && m_
endOfInsertedContent.offsetInContainerNode()) | 1514 if (m_endOfInsertedContent.computeContainerNode() == startNode && m_
endOfInsertedContent.offsetInContainerNode()) |
| 1515 m_endOfInsertedContent = Position(startNode, m_endOfInsertedCont
ent.offsetInContainerNode() + 1); | 1515 m_endOfInsertedContent = Position(startNode, m_endOfInsertedCont
ent.offsetInContainerNode() + 1); |
| 1516 } else { | 1516 } else { |
| 1517 Text* node = document().createEditingTextNode(collapseWhiteSpace ? n
onBreakingSpaceString() : " "); | 1517 Text* node = document().createEditingTextNode(collapseWhiteSpace ? n
onBreakingSpaceString() : " "); |
| 1518 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont
ent to be the node containing the leading space, | 1518 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont
ent to be the node containing the leading space, |
| 1519 // but m_endOfInsertedContent is supposed to mark the end of pasted
content. | 1519 // but m_endOfInsertedContent is supposed to mark the end of pasted
content. |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1644 return m_inputType; | 1644 return m_inputType; |
| 1645 } | 1645 } |
| 1646 | 1646 |
| 1647 // If the user is inserting a list into an existing list, instead of nesting the
list, | 1647 // If the user is inserting a list into an existing list, instead of nesting the
list, |
| 1648 // we put the list items into the existing list. | 1648 // we put the list items into the existing list. |
| 1649 Node* ReplaceSelectionCommand::insertAsListItems(HTMLElement* listElement, Eleme
nt* insertionBlock, const Position& insertPos, InsertedNodes& insertedNodes, Edi
tingState* editingState) | 1649 Node* ReplaceSelectionCommand::insertAsListItems(HTMLElement* listElement, Eleme
nt* insertionBlock, const Position& insertPos, InsertedNodes& insertedNodes, Edi
tingState* editingState) |
| 1650 { | 1650 { |
| 1651 while (listElement->hasOneChild() && isHTMLListElement(listElement->firstChi
ld())) | 1651 while (listElement->hasOneChild() && isHTMLListElement(listElement->firstChi
ld())) |
| 1652 listElement = toHTMLElement(listElement->firstChild()); | 1652 listElement = toHTMLElement(listElement->firstChild()); |
| 1653 | 1653 |
| 1654 bool isStart = isStartOfParagraph(createVisiblePositionDeprecated(insertPos)
); | 1654 bool isStart = isStartOfParagraphDeprecated(createVisiblePositionDeprecated(
insertPos)); |
| 1655 bool isEnd = isEndOfParagraph(createVisiblePositionDeprecated(insertPos)); | 1655 bool isEnd = isEndOfParagraphDeprecated(createVisiblePositionDeprecated(inse
rtPos)); |
| 1656 bool isMiddle = !isStart && !isEnd; | 1656 bool isMiddle = !isStart && !isEnd; |
| 1657 Node* lastNode = insertionBlock; | 1657 Node* lastNode = insertionBlock; |
| 1658 | 1658 |
| 1659 // If we're in the middle of a list item, we should split it into two separa
te | 1659 // If we're in the middle of a list item, we should split it into two separa
te |
| 1660 // list items and insert these nodes between them. | 1660 // list items and insert these nodes between them. |
| 1661 if (isMiddle) { | 1661 if (isMiddle) { |
| 1662 int textNodeOffset = insertPos.offsetInContainerNode(); | 1662 int textNodeOffset = insertPos.offsetInContainerNode(); |
| 1663 if (insertPos.anchorNode()->isTextNode() && textNodeOffset > 0) | 1663 if (insertPos.anchorNode()->isTextNode() && textNodeOffset > 0) |
| 1664 splitTextNode(toText(insertPos.anchorNode()), textNodeOffset); | 1664 splitTextNode(toText(insertPos.anchorNode()), textNodeOffset); |
| 1665 splitTreeToNode(insertPos.anchorNode(), lastNode, true); | 1665 splitTreeToNode(insertPos.anchorNode(), lastNode, true); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1758 visitor->trace(m_startOfInsertedContent); | 1758 visitor->trace(m_startOfInsertedContent); |
| 1759 visitor->trace(m_endOfInsertedContent); | 1759 visitor->trace(m_endOfInsertedContent); |
| 1760 visitor->trace(m_insertionStyle); | 1760 visitor->trace(m_insertionStyle); |
| 1761 visitor->trace(m_documentFragment); | 1761 visitor->trace(m_documentFragment); |
| 1762 visitor->trace(m_startOfInsertedRange); | 1762 visitor->trace(m_startOfInsertedRange); |
| 1763 visitor->trace(m_endOfInsertedRange); | 1763 visitor->trace(m_endOfInsertedRange); |
| 1764 CompositeEditCommand::trace(visitor); | 1764 CompositeEditCommand::trace(visitor); |
| 1765 } | 1765 } |
| 1766 | 1766 |
| 1767 } // namespace blink | 1767 } // namespace blink |
| OLD | NEW |