Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Side by Side Diff: Source/core/editing/commands/ReplaceSelectionCommand.cpp

Issue 1310043003: Introduce previousPositionOf() for VisiblePosition (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: 2015-08-28T16:28:03 Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « Source/core/editing/commands/InsertParagraphSeparatorCommand.cpp ('k') | Source/core/editing/commands/TypingCommand.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698