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 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 bool isInsideMailBlockquote = enclosingNodeOfType(inserted, isMailHTMLBlockq
uoteElement, CanCrossEditingBoundary); | 393 bool isInsideMailBlockquote = enclosingNodeOfType(inserted, isMailHTMLBlockq
uoteElement, CanCrossEditingBoundary); |
394 return isInsideMailBlockquote && (numEnclosingMailBlockquotes(existing) == n
umEnclosingMailBlockquotes(inserted)); | 394 return isInsideMailBlockquote && (numEnclosingMailBlockquotes(existing) == n
umEnclosingMailBlockquotes(inserted)); |
395 } | 395 } |
396 | 396 |
397 bool ReplaceSelectionCommand::shouldMergeStart(bool selectionStartWasStartOfPara
graph, bool fragmentHasInterchangeNewlineAtStart, bool selectionStartWasInsideMa
ilBlockquote) | 397 bool ReplaceSelectionCommand::shouldMergeStart(bool selectionStartWasStartOfPara
graph, bool fragmentHasInterchangeNewlineAtStart, bool selectionStartWasInsideMa
ilBlockquote) |
398 { | 398 { |
399 if (m_movingParagraph) | 399 if (m_movingParagraph) |
400 return false; | 400 return false; |
401 | 401 |
402 VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent()); | 402 VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent()); |
403 VisiblePosition prev = startOfInsertedContent.previous(CannotCrossEditingBou
ndary); | 403 VisiblePosition prev = previousPositionOf(startOfInsertedContent, CannotCros
sEditingBoundary); |
404 if (prev.isNull()) | 404 if (prev.isNull()) |
405 return false; | 405 return false; |
406 | 406 |
407 // When we have matching quote levels, its ok to merge more frequently. | 407 // When we have matching quote levels, its ok to merge more frequently. |
408 // For a successful merge, we still need to make sure that the inserted cont
ent starts with the beginning of a paragraph. | 408 // For a successful merge, we still need to make sure that the inserted cont
ent starts with the beginning of a paragraph. |
409 // And we should only merge here if the selection start was inside a mail bl
ockquote. This prevents against removing a | 409 // And we should only merge here if the selection start was inside a mail bl
ockquote. This prevents against removing a |
410 // blockquote from newly pasted quoted content that was pasted into an unquo
ted position. If that unquoted position happens | 410 // blockquote from newly pasted quoted content that was pasted into an unquo
ted position. If that unquoted position happens |
411 // 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. | 411 // 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. |
412 if (isStartOfParagraph(startOfInsertedContent) && selectionStartWasInsideMai
lBlockquote && hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent())) | 412 if (isStartOfParagraph(startOfInsertedContent) && selectionStartWasInsideMai
lBlockquote && hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent())) |
413 return true; | 413 return true; |
(...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
994 visibleStart = endingSelection().visibleStart(); | 994 visibleStart = endingSelection().visibleStart(); |
995 } | 995 } |
996 } | 996 } |
997 // We split the current paragraph in two to avoid nesting the blocks fro
m the fragment inside the current block. | 997 // We split the current paragraph in two to avoid nesting the blocks fro
m the fragment inside the current block. |
998 // For example paste <div>foo</div><div>bar</div><div>baz</div> into <di
v>x^x</div>, where ^ is the caret. | 998 // For example paste <div>foo</div><div>bar</div><div>baz</div> into <di
v>x^x</div>, where ^ is the caret. |
999 // As long as the div styles are the same, visually you'd expect: <div>
xbar</div><div>bar</div><div>bazx</div>, | 999 // As long as the div styles are the same, visually you'd expect: <div>
xbar</div><div>bar</div><div>bazx</div>, |
1000 // not <div>xbar<div>bar</div><div>bazx</div></div>. | 1000 // not <div>xbar<div>bar</div><div>bazx</div></div>. |
1001 // Don't do this if the selection started in a Mail blockquote. | 1001 // Don't do this if the selection started in a Mail blockquote. |
1002 if (m_preventNesting && !startIsInsideMailBlockquote && !isEndOfParagrap
h(visibleStart) && !isStartOfParagraph(visibleStart)) { | 1002 if (m_preventNesting && !startIsInsideMailBlockquote && !isEndOfParagrap
h(visibleStart) && !isStartOfParagraph(visibleStart)) { |
1003 insertParagraphSeparator(); | 1003 insertParagraphSeparator(); |
1004 setEndingSelection(endingSelection().visibleStart().previous()); | 1004 setEndingSelection(previousPositionOf(endingSelection().visibleStart
())); |
1005 } | 1005 } |
1006 insertionPos = endingSelection().start(); | 1006 insertionPos = endingSelection().start(); |
1007 } | 1007 } |
1008 | 1008 |
1009 // We don't want any of the pasted content to end up nested in a Mail blockq
uote, so first break | 1009 // We don't want any of the pasted content to end up nested in a Mail blockq
uote, so first break |
1010 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl
e, in which case | 1010 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl
e, in which case |
1011 // breaking the blockquote will prevent the content from actually being inse
rted in the table. | 1011 // breaking the blockquote will prevent the content from actually being inse
rted in the table. |
1012 if (startIsInsideMailBlockquote && m_preventNesting && !(enclosingNodeOfType
(insertionPos, &isTableStructureNode))) { | 1012 if (startIsInsideMailBlockquote && m_preventNesting && !(enclosingNodeOfType
(insertionPos, &isTableStructureNode))) { |
1013 applyCommandToComposite(BreakBlockquoteCommand::create(document())); | 1013 applyCommandToComposite(BreakBlockquoteCommand::create(document())); |
1014 // This will leave a br between the split. | 1014 // This will leave a br between the split. |
(...skipping 10 matching lines...) Expand all Loading... |
1025 // If the downstream node has been removed there's no point in continuing. | 1025 // If the downstream node has been removed there's no point in continuing. |
1026 if (!mostForwardCaretPosition(insertionPos).anchorNode()) | 1026 if (!mostForwardCaretPosition(insertionPos).anchorNode()) |
1027 return; | 1027 return; |
1028 | 1028 |
1029 // NOTE: This would be an incorrect usage of downstream() if downstream() we
re changed to mean the last position after | 1029 // NOTE: This would be an incorrect usage of downstream() if downstream() we
re changed to mean the last position after |
1030 // p that maps to the same visible position as p (since in the case where a
br is at the end of a block and collapsed | 1030 // p that maps to the same visible position as p (since in the case where a
br is at the end of a block and collapsed |
1031 // away, there are positions after the br which map to the same visible posi
tion as [br, 0]). | 1031 // away, there are positions after the br which map to the same visible posi
tion as [br, 0]). |
1032 HTMLBRElement* endBR = isHTMLBRElement(*mostForwardCaretPosition(insertionPo
s).anchorNode()) ? toHTMLBRElement(mostForwardCaretPosition(insertionPos).anchor
Node()) : 0; | 1032 HTMLBRElement* endBR = isHTMLBRElement(*mostForwardCaretPosition(insertionPo
s).anchorNode()) ? toHTMLBRElement(mostForwardCaretPosition(insertionPos).anchor
Node()) : 0; |
1033 VisiblePosition originalVisPosBeforeEndBR; | 1033 VisiblePosition originalVisPosBeforeEndBR; |
1034 if (endBR) | 1034 if (endBR) |
1035 originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR)).p
revious(); | 1035 originalVisPosBeforeEndBR = previousPositionOf(VisiblePosition(positionB
eforeNode(endBR))); |
1036 | 1036 |
1037 RefPtrWillBeRawPtr<Element> enclosingBlockOfInsertionPos = enclosingBlock(in
sertionPos.anchorNode()); | 1037 RefPtrWillBeRawPtr<Element> enclosingBlockOfInsertionPos = enclosingBlock(in
sertionPos.anchorNode()); |
1038 | 1038 |
1039 // Adjust insertionPos to prevent nesting. | 1039 // Adjust insertionPos to prevent nesting. |
1040 // If the start was in a Mail blockquote, we will have already handled adjus
ting insertionPos above. | 1040 // If the start was in a Mail blockquote, we will have already handled adjus
ting insertionPos above. |
1041 if (m_preventNesting && enclosingBlockOfInsertionPos && !isTableCell(enclosi
ngBlockOfInsertionPos.get()) && !startIsInsideMailBlockquote) { | 1041 if (m_preventNesting && enclosingBlockOfInsertionPos && !isTableCell(enclosi
ngBlockOfInsertionPos.get()) && !startIsInsideMailBlockquote) { |
1042 ASSERT(enclosingBlockOfInsertionPos != currentRoot); | 1042 ASSERT(enclosingBlockOfInsertionPos != currentRoot); |
1043 VisiblePosition visibleInsertionPos(insertionPos); | 1043 VisiblePosition visibleInsertionPos(insertionPos); |
1044 if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInserti
onPos) && fragment.hasInterchangeNewlineAtEnd())) | 1044 if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInserti
onPos) && fragment.hasInterchangeNewlineAtEnd())) |
1045 insertionPos = positionInParentAfterNode(*enclosingBlockOfInsertionP
os); | 1045 insertionPos = positionInParentAfterNode(*enclosingBlockOfInsertionP
os); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1186 // Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be
the last two lines of code that access insertedNodes. | 1186 // Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be
the last two lines of code that access insertedNodes. |
1187 m_startOfInsertedContent = firstPositionInOrBeforeNode(insertedNodes.firstNo
deInserted()); | 1187 m_startOfInsertedContent = firstPositionInOrBeforeNode(insertedNodes.firstNo
deInserted()); |
1188 m_endOfInsertedContent = lastPositionInOrAfterNode(insertedNodes.lastLeafIns
erted()); | 1188 m_endOfInsertedContent = lastPositionInOrAfterNode(insertedNodes.lastLeafIns
erted()); |
1189 | 1189 |
1190 // Determine whether or not we should merge the end of inserted content with
what's after it before we do | 1190 // Determine whether or not we should merge the end of inserted content with
what's after it before we do |
1191 // the start merge so that the start merge doesn't effect our decision. | 1191 // the start merge so that the start merge doesn't effect our decision. |
1192 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph); | 1192 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph); |
1193 | 1193 |
1194 if (shouldMergeStart(selectionStartWasStartOfParagraph, fragment.hasIntercha
ngeNewlineAtStart(), startIsInsideMailBlockquote)) { | 1194 if (shouldMergeStart(selectionStartWasStartOfParagraph, fragment.hasIntercha
ngeNewlineAtStart(), startIsInsideMailBlockquote)) { |
1195 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedConten
t(); | 1195 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedConten
t(); |
1196 VisiblePosition destination = startOfParagraphToMove.previous(); | 1196 VisiblePosition destination = previousPositionOf(startOfParagraphToMove)
; |
1197 // We need to handle the case where we need to merge the end | 1197 // We need to handle the case where we need to merge the end |
1198 // but our destination node is inside an inline that is the last in the
block. | 1198 // but our destination node is inside an inline that is the last in the
block. |
1199 // We insert a placeholder before the newly inserted content to avoid be
ing merged into the inline. | 1199 // We insert a placeholder before the newly inserted content to avoid be
ing merged into the inline. |
1200 Node* destinationNode = destination.deepEquivalent().anchorNode(); | 1200 Node* destinationNode = destination.deepEquivalent().anchorNode(); |
1201 if (m_shouldMergeEnd && destinationNode != enclosingInline(destinationNo
de) && enclosingInline(destinationNode)->nextSibling()) | 1201 if (m_shouldMergeEnd && destinationNode != enclosingInline(destinationNo
de) && enclosingInline(destinationNode)->nextSibling()) |
1202 insertNodeBefore(createBreakElement(document()), refNode.get()); | 1202 insertNodeBefore(createBreakElement(document()), refNode.get()); |
1203 | 1203 |
1204 // Merging the the first paragraph of inserted content with the content
that came | 1204 // Merging the the first paragraph of inserted content with the content
that came |
1205 // before the selection that was pasted into would also move content aft
er | 1205 // before the selection that was pasted into would also move content aft
er |
1206 // the selection that was pasted into if: only one paragraph was being p
asted, | 1206 // the selection that was pasted into if: only one paragraph was being p
asted, |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1271 } | 1271 } |
1272 | 1272 |
1273 bool ReplaceSelectionCommand::shouldRemoveEndBR(HTMLBRElement* endBR, const Visi
blePosition& originalVisPosBeforeEndBR) | 1273 bool ReplaceSelectionCommand::shouldRemoveEndBR(HTMLBRElement* endBR, const Visi
blePosition& originalVisPosBeforeEndBR) |
1274 { | 1274 { |
1275 if (!endBR || !endBR->inDocument()) | 1275 if (!endBR || !endBR->inDocument()) |
1276 return false; | 1276 return false; |
1277 | 1277 |
1278 VisiblePosition visiblePos(positionBeforeNode(endBR)); | 1278 VisiblePosition visiblePos(positionBeforeNode(endBR)); |
1279 | 1279 |
1280 // Don't remove the br if nothing was inserted. | 1280 // Don't remove the br if nothing was inserted. |
1281 if (visiblePos.previous().deepEquivalent() == originalVisPosBeforeEndBR.deep
Equivalent()) | 1281 if (previousPositionOf(visiblePos).deepEquivalent() == originalVisPosBeforeE
ndBR.deepEquivalent()) |
1282 return false; | 1282 return false; |
1283 | 1283 |
1284 // Remove the br if it is collapsed away and so is unnecessary. | 1284 // Remove the br if it is collapsed away and so is unnecessary. |
1285 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && !isStartOfPa
ragraph(visiblePos)) | 1285 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && !isStartOfPa
ragraph(visiblePos)) |
1286 return true; | 1286 return true; |
1287 | 1287 |
1288 // A br that was originally holding a line open should be displaced by inser
ted content or turned into a line break. | 1288 // A br that was originally holding a line open should be displaced by inser
ted content or turned into a line break. |
1289 // A br that was originally acting as a line break should still be acting as
a line break, not as a placeholder. | 1289 // A br that was originally acting as a line break should still be acting as
a line break, not as a placeholder. |
1290 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos); | 1290 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos); |
1291 } | 1291 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1337 document().updateLayout(); | 1337 document().updateLayout(); |
1338 | 1338 |
1339 Position startDownstream = mostForwardCaretPosition(startOfInsertedContent.d
eepEquivalent()); | 1339 Position startDownstream = mostForwardCaretPosition(startOfInsertedContent.d
eepEquivalent()); |
1340 Node* startNode = startDownstream.computeNodeAfterPosition(); | 1340 Node* startNode = startDownstream.computeNodeAfterPosition(); |
1341 unsigned startOffset = 0; | 1341 unsigned startOffset = 0; |
1342 if (startDownstream.isOffsetInAnchor()) { | 1342 if (startDownstream.isOffsetInAnchor()) { |
1343 startNode = startDownstream.computeContainerNode(); | 1343 startNode = startDownstream.computeContainerNode(); |
1344 startOffset = startDownstream.offsetInContainerNode(); | 1344 startOffset = startDownstream.offsetInContainerNode(); |
1345 } | 1345 } |
1346 | 1346 |
1347 bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) && !isC
haracterSmartReplaceExemptConsideringNonBreakingSpace(startOfInsertedContent.pre
vious().characterAfter(), true); | 1347 bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) && !isC
haracterSmartReplaceExemptConsideringNonBreakingSpace(previousPositionOf(startOf
InsertedContent).characterAfter(), true); |
1348 if (needsLeadingSpace && startNode) { | 1348 if (needsLeadingSpace && startNode) { |
1349 bool collapseWhiteSpace = !startNode->layoutObject() || startNode->layou
tObject()->style()->collapseWhiteSpace(); | 1349 bool collapseWhiteSpace = !startNode->layoutObject() || startNode->layou
tObject()->style()->collapseWhiteSpace(); |
1350 if (startNode->isTextNode()) { | 1350 if (startNode->isTextNode()) { |
1351 insertTextIntoNode(toText(startNode), startOffset, collapseWhiteSpac
e ? nonBreakingSpaceString() : " "); | 1351 insertTextIntoNode(toText(startNode), startOffset, collapseWhiteSpac
e ? nonBreakingSpaceString() : " "); |
1352 if (m_endOfInsertedContent.computeContainerNode() == startNode && m_
endOfInsertedContent.offsetInContainerNode()) | 1352 if (m_endOfInsertedContent.computeContainerNode() == startNode && m_
endOfInsertedContent.offsetInContainerNode()) |
1353 m_endOfInsertedContent = Position(startNode, m_endOfInsertedCont
ent.offsetInContainerNode() + 1); | 1353 m_endOfInsertedContent = Position(startNode, m_endOfInsertedCont
ent.offsetInContainerNode() + 1); |
1354 } else { | 1354 } else { |
1355 RefPtrWillBeRawPtr<Text> node = document().createEditingTextNode(col
lapseWhiteSpace ? nonBreakingSpaceString() : " "); | 1355 RefPtrWillBeRawPtr<Text> node = document().createEditingTextNode(col
lapseWhiteSpace ? nonBreakingSpaceString() : " "); |
1356 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont
ent to be the node containing the leading space, | 1356 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont
ent to be the node containing the leading space, |
1357 // but m_endOfInsertedContent is supposed to mark the end of pasted
content. | 1357 // but m_endOfInsertedContent is supposed to mark the end of pasted
content. |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1549 DEFINE_TRACE(ReplaceSelectionCommand) | 1549 DEFINE_TRACE(ReplaceSelectionCommand) |
1550 { | 1550 { |
1551 visitor->trace(m_startOfInsertedContent); | 1551 visitor->trace(m_startOfInsertedContent); |
1552 visitor->trace(m_endOfInsertedContent); | 1552 visitor->trace(m_endOfInsertedContent); |
1553 visitor->trace(m_insertionStyle); | 1553 visitor->trace(m_insertionStyle); |
1554 visitor->trace(m_documentFragment); | 1554 visitor->trace(m_documentFragment); |
1555 CompositeEditCommand::trace(visitor); | 1555 CompositeEditCommand::trace(visitor); |
1556 } | 1556 } |
1557 | 1557 |
1558 } // namespace blink | 1558 } // namespace blink |
OLD | NEW |