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

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

Issue 2395393002: Prune deprecated functions from ReplaceSelectionCommand (Closed)
Patch Set: Created 4 years, 2 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 pos = nextPosition) { 147 pos = nextPosition) {
148 if (lineBreakExistsAtPosition(pos)) 148 if (lineBreakExistsAtPosition(pos))
149 break; 149 break;
150 150
151 if (pos.computeContainerNode()->nonShadowBoundaryParentNode()) 151 if (pos.computeContainerNode()->nonShadowBoundaryParentNode())
152 nextPosition = Position::inParentAfterNode(*pos.computeContainerNode()); 152 nextPosition = Position::inParentAfterNode(*pos.computeContainerNode());
153 153
154 if (nextPosition == pos || 154 if (nextPosition == pos ||
155 enclosingBlock(nextPosition.computeContainerNode()) != 155 enclosingBlock(nextPosition.computeContainerNode()) !=
156 enclosingBlockElement || 156 enclosingBlockElement ||
157 createVisiblePositionDeprecated(pos).deepEquivalent() != 157 createVisiblePosition(pos).deepEquivalent() !=
158 createVisiblePositionDeprecated(nextPosition).deepEquivalent()) 158 createVisiblePosition(nextPosition).deepEquivalent())
159 break; 159 break;
160 } 160 }
161 return pos; 161 return pos;
162 } 162 }
163 163
164 ReplacementFragment::ReplacementFragment(Document* document, 164 ReplacementFragment::ReplacementFragment(Document* document,
165 DocumentFragment* fragment, 165 DocumentFragment* fragment,
166 const VisibleSelection& selection) 166 const VisibleSelection& selection)
167 : m_document(document), 167 : m_document(document),
168 m_fragment(fragment), 168 m_fragment(fragment),
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 return false; 465 return false;
466 466
467 // When we have matching quote levels, its ok to merge more frequently. 467 // When we have matching quote levels, its ok to merge more frequently.
468 // For a successful merge, we still need to make sure that the inserted 468 // For a successful merge, we still need to make sure that the inserted
469 // content starts with the beginning of a paragraph. And we should only merge 469 // content starts with the beginning of a paragraph. And we should only merge
470 // here if the selection start was inside a mail blockquote. This prevents 470 // here if the selection start was inside a mail blockquote. This prevents
471 // against removing a blockquote from newly pasted quoted content that was 471 // against removing a blockquote from newly pasted quoted content that was
472 // pasted into an unquoted position. If that unquoted position happens to be 472 // pasted into an unquoted position. If that unquoted position happens to be
473 // right after another blockquote, we don't want to merge and risk stripping a 473 // right after another blockquote, we don't want to merge and risk stripping a
474 // valid block (and newline) from the pasted content. 474 // valid block (and newline) from the pasted content.
475 if (isStartOfParagraphDeprecated(startOfInsertedContent) && 475 if (isStartOfParagraph(startOfInsertedContent) &&
476 selectionStartWasInsideMailBlockquote && 476 selectionStartWasInsideMailBlockquote &&
477 hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent())) 477 hasMatchingQuoteLevel(prev, positionAtEndOfInsertedContent()))
478 return true; 478 return true;
479 479
480 return !selectionStartWasStartOfParagraph && 480 return !selectionStartWasStartOfParagraph &&
481 !fragmentHasInterchangeNewlineAtStart && 481 !fragmentHasInterchangeNewlineAtStart &&
482 isStartOfParagraphDeprecated(startOfInsertedContent) && 482 isStartOfParagraph(startOfInsertedContent) &&
483 !isHTMLBRElement( 483 !isHTMLBRElement(
484 *startOfInsertedContent.deepEquivalent().anchorNode()) && 484 *startOfInsertedContent.deepEquivalent().anchorNode()) &&
485 shouldMerge(startOfInsertedContent, prev); 485 shouldMerge(startOfInsertedContent, prev);
486 } 486 }
487 487
488 bool ReplaceSelectionCommand::shouldMergeEnd( 488 bool ReplaceSelectionCommand::shouldMergeEnd(
489 bool selectionEndWasEndOfParagraph) { 489 bool selectionEndWasEndOfParagraph) {
490 VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent()); 490 VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent());
491 VisiblePosition next = 491 VisiblePosition next =
492 nextPositionOf(endOfInsertedContent, CannotCrossEditingBoundary); 492 nextPositionOf(endOfInsertedContent, CannotCrossEditingBoundary);
493 if (next.isNull()) 493 if (next.isNull())
494 return false; 494 return false;
495 495
496 return !selectionEndWasEndOfParagraph && 496 return !selectionEndWasEndOfParagraph &&
497 isEndOfParagraphDeprecated(endOfInsertedContent) && 497 isEndOfParagraph(endOfInsertedContent) &&
498 !isHTMLBRElement( 498 !isHTMLBRElement(
499 *endOfInsertedContent.deepEquivalent().anchorNode()) && 499 *endOfInsertedContent.deepEquivalent().anchorNode()) &&
500 shouldMerge(endOfInsertedContent, next); 500 shouldMerge(endOfInsertedContent, next);
501 } 501 }
502 502
503 static bool isMailPasteAsQuotationHTMLBlockQuoteElement(const Node* node) { 503 static bool isMailPasteAsQuotationHTMLBlockQuoteElement(const Node* node) {
504 if (!node || !node->isHTMLElement()) 504 if (!node || !node->isHTMLElement())
505 return false; 505 return false;
506 const HTMLElement& element = toHTMLElement(*node); 506 const HTMLElement& element = toHTMLElement(*node);
507 if (!element.hasTagName(blockquoteTag) || 507 if (!element.hasTagName(blockquoteTag) ||
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 } 748 }
749 } 749 }
750 750
751 void ReplaceSelectionCommand::moveElementOutOfAncestor( 751 void ReplaceSelectionCommand::moveElementOutOfAncestor(
752 Element* element, 752 Element* element,
753 Element* ancestor, 753 Element* ancestor,
754 EditingState* editingState) { 754 EditingState* editingState) {
755 if (!hasEditableStyle(*ancestor->parentNode())) 755 if (!hasEditableStyle(*ancestor->parentNode()))
756 return; 756 return;
757 757
758 document().updateStyleAndLayoutIgnorePendingStylesheets();
758 VisiblePosition positionAtEndOfNode = 759 VisiblePosition positionAtEndOfNode =
759 createVisiblePositionDeprecated(lastPositionInOrAfterNode(element)); 760 createVisiblePosition(lastPositionInOrAfterNode(element));
760 VisiblePosition lastPositionInParagraph = 761 VisiblePosition lastPositionInParagraph =
761 VisiblePosition::lastPositionInNode(ancestor); 762 VisiblePosition::lastPositionInNode(ancestor);
762 if (positionAtEndOfNode.deepEquivalent() == 763 if (positionAtEndOfNode.deepEquivalent() ==
763 lastPositionInParagraph.deepEquivalent()) { 764 lastPositionInParagraph.deepEquivalent()) {
764 removeNode(element, editingState); 765 removeNode(element, editingState);
765 if (editingState->isAborted()) 766 if (editingState->isAborted())
766 return; 767 return;
767 if (ancestor->nextSibling()) 768 if (ancestor->nextSibling())
768 insertNodeBefore(element, ancestor->nextSibling(), editingState); 769 insertNodeBefore(element, ancestor->nextSibling(), editingState);
769 else 770 else
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
810 if (firstNodeInserted && firstNodeInserted->isTextNode() && 811 if (firstNodeInserted && firstNodeInserted->isTextNode() &&
811 !nodeHasVisibleLayoutText(toText(*firstNodeInserted))) { 812 !nodeHasVisibleLayoutText(toText(*firstNodeInserted))) {
812 insertedNodes.willRemoveNode(*firstNodeInserted); 813 insertedNodes.willRemoveNode(*firstNodeInserted);
813 // Removing a Text node won't dispatch synchronous events. 814 // Removing a Text node won't dispatch synchronous events.
814 removeNode(firstNodeInserted, ASSERT_NO_EDITING_ABORT); 815 removeNode(firstNodeInserted, ASSERT_NO_EDITING_ABORT);
815 } 816 }
816 } 817 }
817 818
818 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() 819 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent()
819 const { 820 const {
821 // TODO(xiaochengh): Hoist the call and change it into a DCHECK.
822 document().updateStyleAndLayoutIgnorePendingStylesheets();
820 // TODO(yosin): We should set |m_endOfInsertedContent| not in SELECT 823 // TODO(yosin): We should set |m_endOfInsertedContent| not in SELECT
821 // element, since contents of SELECT elements, e.g. OPTION, OPTGROUP, are 824 // element, since contents of SELECT elements, e.g. OPTION, OPTGROUP, are
822 // not editable, or SELECT element is an atomic on editing. 825 // not editable, or SELECT element is an atomic on editing.
823 HTMLSelectElement* enclosingSelect = toHTMLSelectElement( 826 HTMLSelectElement* enclosingSelect = toHTMLSelectElement(
824 enclosingElementWithTag(m_endOfInsertedContent, selectTag)); 827 enclosingElementWithTag(m_endOfInsertedContent, selectTag));
825 if (enclosingSelect) 828 if (enclosingSelect)
826 return createVisiblePositionDeprecated( 829 return createVisiblePosition(lastPositionInOrAfterNode(enclosingSelect));
827 lastPositionInOrAfterNode(enclosingSelect));
828 if (m_endOfInsertedContent.isOrphan()) 830 if (m_endOfInsertedContent.isOrphan())
829 return VisiblePosition(); 831 return VisiblePosition();
830 return createVisiblePositionDeprecated(m_endOfInsertedContent); 832 return createVisiblePosition(m_endOfInsertedContent);
831 } 833 }
832 834
833 VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent() 835 VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent()
834 const { 836 const {
837 // TODO(xiaochengh): Hoist the call and change it into a DCHECK.
838 document().updateStyleAndLayoutIgnorePendingStylesheets();
835 if (m_startOfInsertedContent.isOrphan()) 839 if (m_startOfInsertedContent.isOrphan())
836 return VisiblePosition(); 840 return VisiblePosition();
837 return createVisiblePositionDeprecated(m_startOfInsertedContent); 841 return createVisiblePosition(m_startOfInsertedContent);
838 } 842 }
839 843
840 static void removeHeadContents(ReplacementFragment& fragment) { 844 static void removeHeadContents(ReplacementFragment& fragment) {
841 Node* next = nullptr; 845 Node* next = nullptr;
842 for (Node* node = fragment.firstChild(); node; node = next) { 846 for (Node* node = fragment.firstChild(); node; node = next) {
843 if (isHTMLBaseElement(*node) || isHTMLLinkElement(*node) || 847 if (isHTMLBaseElement(*node) || isHTMLLinkElement(*node) ||
844 isHTMLMetaElement(*node) || isHTMLTitleElement(*node)) { 848 isHTMLMetaElement(*node) || isHTMLTitleElement(*node)) {
845 next = NodeTraversal::nextSkippingChildren(*node); 849 next = NodeTraversal::nextSkippingChildren(*node);
846 fragment.removeNode(node); 850 fragment.removeNode(node);
847 } else { 851 } else {
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
998 if (m_movingParagraph) { 1002 if (m_movingParagraph) {
999 NOTREACHED(); 1003 NOTREACHED();
1000 return; 1004 return;
1001 } 1005 }
1002 1006
1003 // Merging two paragraphs will destroy the moved one's block styles. Always 1007 // Merging two paragraphs will destroy the moved one's block styles. Always
1004 // move the end of inserted forward to preserve the block style of the 1008 // move the end of inserted forward to preserve the block style of the
1005 // paragraph already in the document, unless the paragraph to move would 1009 // paragraph already in the document, unless the paragraph to move would
1006 // include the what was the start of the selection that was pasted into, so 1010 // include the what was the start of the selection that was pasted into, so
1007 // that we preserve that paragraph's block styles. 1011 // that we preserve that paragraph's block styles.
1008 bool mergeForward = !( 1012 bool mergeForward =
1009 inSameParagraphDeprecated(startOfInsertedContent, endOfInsertedContent) && 1013 !(inSameParagraph(startOfInsertedContent, endOfInsertedContent) &&
1010 !isStartOfParagraphDeprecated(startOfInsertedContent)); 1014 !isStartOfParagraph(startOfInsertedContent));
1011 1015
1012 VisiblePosition destination = mergeForward 1016 VisiblePosition destination = mergeForward
1013 ? nextPositionOf(endOfInsertedContent) 1017 ? nextPositionOf(endOfInsertedContent)
1014 : endOfInsertedContent; 1018 : endOfInsertedContent;
1019 // TODO(xiaochengh): Stop storing VisiblePositions through mutations.
1015 VisiblePosition startOfParagraphToMove = 1020 VisiblePosition startOfParagraphToMove =
1016 mergeForward ? startOfParagraphDeprecated(endOfInsertedContent) 1021 mergeForward ? startOfParagraph(endOfInsertedContent)
1017 : nextPositionOf(endOfInsertedContent); 1022 : nextPositionOf(endOfInsertedContent);
1018 1023
1019 // Merging forward could result in deleting the destination anchor node. 1024 // Merging forward could result in deleting the destination anchor node.
1020 // To avoid this, we add a placeholder node before the start of the paragraph. 1025 // To avoid this, we add a placeholder node before the start of the paragraph.
1021 if (endOfParagraphDeprecated(startOfParagraphToMove).deepEquivalent() == 1026 if (endOfParagraph(startOfParagraphToMove).deepEquivalent() ==
1022 destination.deepEquivalent()) { 1027 destination.deepEquivalent()) {
1023 HTMLBRElement* placeholder = HTMLBRElement::create(document()); 1028 HTMLBRElement* placeholder = HTMLBRElement::create(document());
1024 insertNodeBefore(placeholder, 1029 insertNodeBefore(placeholder,
1025 startOfParagraphToMove.deepEquivalent().anchorNode(), 1030 startOfParagraphToMove.deepEquivalent().anchorNode(),
1026 editingState); 1031 editingState);
1027 if (editingState->isAborted()) 1032 if (editingState->isAborted())
1028 return; 1033 return;
1034 document().updateStyleAndLayoutIgnorePendingStylesheets();
1029 destination = VisiblePosition::beforeNode(placeholder); 1035 destination = VisiblePosition::beforeNode(placeholder);
1036 startOfParagraphToMove =
1037 createVisiblePosition(startOfParagraphToMove.toPositionWithAffinity());
1030 } 1038 }
1031 1039
1032 moveParagraph(startOfParagraphToMove, 1040 moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove),
1033 endOfParagraphDeprecated(startOfParagraphToMove), destination, 1041 destination, editingState);
1034 editingState);
1035 if (editingState->isAborted()) 1042 if (editingState->isAborted())
1036 return; 1043 return;
1037 1044
1045 document().updateStyleAndLayoutIgnorePendingStylesheets();
1046
1038 // Merging forward will remove m_endOfInsertedContent from the document. 1047 // Merging forward will remove m_endOfInsertedContent from the document.
1039 if (mergeForward) { 1048 if (mergeForward) {
1040 if (m_startOfInsertedContent.isOrphan()) 1049 if (m_startOfInsertedContent.isOrphan()) {
1041 m_startOfInsertedContent = 1050 m_startOfInsertedContent =
1042 endingSelection().visibleStartDeprecated().deepEquivalent(); 1051 endingSelection().visibleStart().deepEquivalent();
1043 m_endOfInsertedContent = 1052 }
1044 endingSelection().visibleEndDeprecated().deepEquivalent(); 1053 m_endOfInsertedContent = endingSelection().visibleEnd().deepEquivalent();
1045 // If we merged text nodes, m_endOfInsertedContent could be null. If 1054 // If we merged text nodes, m_endOfInsertedContent could be null. If
1046 // this is the case, we use m_startOfInsertedContent. 1055 // this is the case, we use m_startOfInsertedContent.
1047 if (m_endOfInsertedContent.isNull()) 1056 if (m_endOfInsertedContent.isNull())
1048 m_endOfInsertedContent = m_startOfInsertedContent; 1057 m_endOfInsertedContent = m_startOfInsertedContent;
1049 } 1058 }
1050 } 1059 }
1051 1060
1052 static Node* enclosingInline(Node* node) { 1061 static Node* enclosingInline(Node* node) {
1053 while (ContainerNode* parent = node->parentNode()) { 1062 while (ContainerNode* parent = node->parentNode()) {
1054 if (isBlockFlowElement(*parent) || isHTMLBodyElement(*parent)) 1063 if (isBlockFlowElement(*parent) || isHTMLBodyElement(*parent))
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 return; 1126 return;
1118 1127
1119 ReplacementFragment fragment(&document(), m_documentFragment.get(), 1128 ReplacementFragment fragment(&document(), m_documentFragment.get(),
1120 selection); 1129 selection);
1121 bool trivialReplaceResult = performTrivialReplace(fragment, editingState); 1130 bool trivialReplaceResult = performTrivialReplace(fragment, editingState);
1122 if (editingState->isAborted()) 1131 if (editingState->isAborted())
1123 return; 1132 return;
1124 if (trivialReplaceResult) 1133 if (trivialReplaceResult)
1125 return; 1134 return;
1126 1135
1136 document().updateStyleAndLayoutIgnorePendingStylesheets();
1137
1127 // We can skip matching the style if the selection is plain text. 1138 // We can skip matching the style if the selection is plain text.
1128 if ((selection.start().anchorNode()->layoutObject() && 1139 if ((selection.start().anchorNode()->layoutObject() &&
1129 selection.start().anchorNode()->layoutObject()->style()->userModify() == 1140 selection.start().anchorNode()->layoutObject()->style()->userModify() ==
1130 READ_WRITE_PLAINTEXT_ONLY) && 1141 READ_WRITE_PLAINTEXT_ONLY) &&
1131 (selection.end().anchorNode()->layoutObject() && 1142 (selection.end().anchorNode()->layoutObject() &&
1132 selection.end().anchorNode()->layoutObject()->style()->userModify() == 1143 selection.end().anchorNode()->layoutObject()->style()->userModify() ==
1133 READ_WRITE_PLAINTEXT_ONLY)) 1144 READ_WRITE_PLAINTEXT_ONLY))
1134 m_matchStyle = false; 1145 m_matchStyle = false;
1135 1146
1136 if (m_matchStyle) { 1147 if (m_matchStyle) {
1137 m_insertionStyle = EditingStyle::create(selection.start()); 1148 m_insertionStyle = EditingStyle::create(selection.start());
1138 m_insertionStyle->mergeTypingStyle(&document()); 1149 m_insertionStyle->mergeTypingStyle(&document());
1139 } 1150 }
1140 1151
1141 const VisiblePosition visibleStart = selection.visibleStartDeprecated(); 1152 const VisiblePosition visibleStart = selection.visibleStart();
1142 const VisiblePosition visibleEnd = selection.visibleEndDeprecated(); 1153 const VisiblePosition visibleEnd = selection.visibleEnd();
1143 1154
1144 const bool selectionEndWasEndOfParagraph = 1155 const bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd);
1145 isEndOfParagraphDeprecated(visibleEnd);
1146 const bool selectionStartWasStartOfParagraph = 1156 const bool selectionStartWasStartOfParagraph =
1147 isStartOfParagraphDeprecated(visibleStart); 1157 isStartOfParagraph(visibleStart);
1148 1158
1149 Element* enclosingBlockOfVisibleStart = 1159 Element* enclosingBlockOfVisibleStart =
1150 enclosingBlock(visibleStart.deepEquivalent().anchorNode()); 1160 enclosingBlock(visibleStart.deepEquivalent().anchorNode());
1151 1161
1152 const bool startIsInsideMailBlockquote = enclosingNodeOfType( 1162 const bool startIsInsideMailBlockquote = enclosingNodeOfType(
1153 selection.start(), isMailHTMLBlockquoteElement, CanCrossEditingBoundary); 1163 selection.start(), isMailHTMLBlockquoteElement, CanCrossEditingBoundary);
1154 const bool selectionIsPlainText = !selection.isContentRichlyEditable(); 1164 const bool selectionIsPlainText = !selection.isContentRichlyEditable();
1155 Element* currentRoot = selection.rootEditableElement(); 1165 Element* currentRoot = selection.rootEditableElement();
1156 1166
1157 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph && 1167 if ((selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph &&
1158 !startIsInsideMailBlockquote) || 1168 !startIsInsideMailBlockquote) ||
1159 enclosingBlockOfVisibleStart == currentRoot || 1169 enclosingBlockOfVisibleStart == currentRoot ||
1160 isListItem(enclosingBlockOfVisibleStart) || selectionIsPlainText) { 1170 isListItem(enclosingBlockOfVisibleStart) || selectionIsPlainText) {
1161 m_preventNesting = false; 1171 m_preventNesting = false;
1162 } 1172 }
1163 1173
1164 if (selection.isRange()) { 1174 if (selection.isRange()) {
1165 // When the end of the selection being pasted into is at the end of a 1175 // When the end of the selection being pasted into is at the end of a
1166 // paragraph, and that selection spans multiple blocks, not merging may 1176 // paragraph, and that selection spans multiple blocks, not merging may
1167 // leave an empty line. 1177 // leave an empty line.
1168 // When the start of the selection being pasted into is at the start of a 1178 // When the start of the selection being pasted into is at the start of a
1169 // block, not merging will leave hanging block(s). 1179 // block, not merging will leave hanging block(s).
1170 // Merge blocks if the start of the selection was in a Mail blockquote, 1180 // Merge blocks if the start of the selection was in a Mail blockquote,
1171 // since we handle that case specially to prevent nesting. 1181 // since we handle that case specially to prevent nesting.
1172 bool mergeBlocksAfterDelete = startIsInsideMailBlockquote || 1182 bool mergeBlocksAfterDelete = startIsInsideMailBlockquote ||
1173 isEndOfParagraphDeprecated(visibleEnd) || 1183 isEndOfParagraph(visibleEnd) ||
1174 isStartOfBlock(visibleStart); 1184 isStartOfBlock(visibleStart);
1175 // FIXME: We should only expand to include fully selected special elements 1185 // FIXME: We should only expand to include fully selected special elements
1176 // if we are copying a selection and pasting it on top of itself. 1186 // if we are copying a selection and pasting it on top of itself.
1177 deleteSelection(editingState, false, mergeBlocksAfterDelete, false); 1187 deleteSelection(editingState, false, mergeBlocksAfterDelete, false);
1178 if (editingState->isAborted()) 1188 if (editingState->isAborted())
1179 return; 1189 return;
1180 if (fragment.hasInterchangeNewlineAtStart()) { 1190 if (fragment.hasInterchangeNewlineAtStart()) {
1181 VisiblePosition startAfterDelete = 1191 document().updateStyleAndLayoutIgnorePendingStylesheets();
1182 endingSelection().visibleStartDeprecated(); 1192 VisiblePosition startAfterDelete = endingSelection().visibleStart();
1183 if (isEndOfParagraphDeprecated(startAfterDelete) && 1193 if (isEndOfParagraph(startAfterDelete) &&
1184 !isStartOfParagraphDeprecated(startAfterDelete) && 1194 !isStartOfParagraph(startAfterDelete) &&
1185 !isEndOfEditableOrNonEditableContent(startAfterDelete)) 1195 !isEndOfEditableOrNonEditableContent(startAfterDelete))
1186 setEndingSelection(nextPositionOf(startAfterDelete)); 1196 setEndingSelection(nextPositionOf(startAfterDelete));
1187 else 1197 else
1188 insertParagraphSeparator(editingState); 1198 insertParagraphSeparator(editingState);
1189 if (editingState->isAborted()) 1199 if (editingState->isAborted())
1190 return; 1200 return;
1191 } 1201 }
1192 } else { 1202 } else {
1193 DCHECK(selection.isCaret()); 1203 DCHECK(selection.isCaret());
1194 if (fragment.hasInterchangeNewlineAtStart()) { 1204 if (fragment.hasInterchangeNewlineAtStart()) {
1195 const VisiblePosition next = 1205 const VisiblePosition next =
1196 nextPositionOf(visibleStart, CannotCrossEditingBoundary); 1206 nextPositionOf(visibleStart, CannotCrossEditingBoundary);
1197 if (isEndOfParagraphDeprecated(visibleStart) && 1207 if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart) &&
1198 !isStartOfParagraphDeprecated(visibleStart) && next.isNotNull()) 1208 next.isNotNull()) {
1199 setEndingSelection(next); 1209 setEndingSelection(next);
1200 else 1210 } else {
1201 insertParagraphSeparator(editingState); 1211 insertParagraphSeparator(editingState);
1202 if (editingState->isAborted()) 1212 if (editingState->isAborted())
1203 return; 1213 return;
1214 document().updateStyleAndLayoutIgnorePendingStylesheets();
1215 }
1204 } 1216 }
1205 // We split the current paragraph in two to avoid nesting the blocks from 1217 // We split the current paragraph in two to avoid nesting the blocks from
1206 // the fragment inside the current block. 1218 // the fragment inside the current block.
1207 // 1219 //
1208 // For example, paste 1220 // For example, paste
1209 // <div>foo</div><div>bar</div><div>baz</div> 1221 // <div>foo</div><div>bar</div><div>baz</div>
1210 // into 1222 // into
1211 // <div>x^x</div> 1223 // <div>x^x</div>
1212 // where ^ is the caret. 1224 // where ^ is the caret.
1213 // 1225 //
1214 // As long as the div styles are the same, visually you'd expect: 1226 // As long as the div styles are the same, visually you'd expect:
1215 // <div>xbar</div><div>bar</div><div>bazx</div> 1227 // <div>xbar</div><div>bar</div><div>bazx</div>
1216 // not 1228 // not
1217 // <div>xbar<div>bar</div><div>bazx</div></div> 1229 // <div>xbar<div>bar</div><div>bazx</div></div>
1218 // Don't do this if the selection started in a Mail blockquote. 1230 // Don't do this if the selection started in a Mail blockquote.
1219 if (m_preventNesting && !startIsInsideMailBlockquote && 1231 if (m_preventNesting && !startIsInsideMailBlockquote &&
1220 !isEndOfParagraphDeprecated( 1232 !isEndOfParagraph(endingSelection().visibleStart()) &&
1221 endingSelection().visibleStartDeprecated()) && 1233 !isStartOfParagraph(endingSelection().visibleStart())) {
1222 !isStartOfParagraphDeprecated(
1223 endingSelection().visibleStartDeprecated())) {
1224 insertParagraphSeparator(editingState); 1234 insertParagraphSeparator(editingState);
1225 if (editingState->isAborted()) 1235 if (editingState->isAborted())
1226 return; 1236 return;
1227 setEndingSelection( 1237 document().updateStyleAndLayoutIgnorePendingStylesheets();
1228 previousPositionOf(endingSelection().visibleStartDeprecated())); 1238 setEndingSelection(previousPositionOf(endingSelection().visibleStart()));
1229 } 1239 }
1230 } 1240 }
1231 1241
1232 Position insertionPos = endingSelection().start(); 1242 Position insertionPos = endingSelection().start();
1233 // We don't want any of the pasted content to end up nested in a Mail 1243 // We don't want any of the pasted content to end up nested in a Mail
1234 // blockquote, so first break out of any surrounding Mail blockquotes. Unless 1244 // blockquote, so first break out of any surrounding Mail blockquotes. Unless
1235 // we're inserting in a table, in which case breaking the blockquote will 1245 // we're inserting in a table, in which case breaking the blockquote will
1236 // prevent the content from actually being inserted in the table. 1246 // prevent the content from actually being inserted in the table.
1237 if (enclosingNodeOfType(insertionPos, isMailHTMLBlockquoteElement, 1247 if (enclosingNodeOfType(insertionPos, isMailHTMLBlockquoteElement,
1238 CanCrossEditingBoundary) && 1248 CanCrossEditingBoundary) &&
(...skipping 11 matching lines...) Expand all
1250 insertionPos = Position::inParentBeforeNode(*br); 1260 insertionPos = Position::inParentBeforeNode(*br);
1251 removeNode(br, editingState); 1261 removeNode(br, editingState);
1252 if (editingState->isAborted()) 1262 if (editingState->isAborted())
1253 return; 1263 return;
1254 } 1264 }
1255 1265
1256 // Inserting content could cause whitespace to collapse, e.g. inserting 1266 // Inserting content could cause whitespace to collapse, e.g. inserting
1257 // <div>foo</div> into hello^ world. 1267 // <div>foo</div> into hello^ world.
1258 prepareWhitespaceAtPositionForSplit(insertionPos); 1268 prepareWhitespaceAtPositionForSplit(insertionPos);
1259 1269
1270 document().updateStyleAndLayoutIgnorePendingStylesheets();
1271
1260 // If the downstream node has been removed there's no point in continuing. 1272 // If the downstream node has been removed there's no point in continuing.
1261 if (!mostForwardCaretPosition(insertionPos).anchorNode()) 1273 if (!mostForwardCaretPosition(insertionPos).anchorNode())
1262 return; 1274 return;
1263 1275
1264 // NOTE: This would be an incorrect usage of downstream() if downstream() were 1276 // NOTE: This would be an incorrect usage of downstream() if downstream() were
1265 // changed to mean the last position after p that maps to the same visible 1277 // changed to mean the last position after p that maps to the same visible
1266 // position as p (since in the case where a br is at the end of a block and 1278 // position as p (since in the case where a br is at the end of a block and
1267 // collapsed away, there are positions after the br which map to the same 1279 // collapsed away, there are positions after the br which map to the same
1268 // visible position as [br, 0]). 1280 // visible position as [br, 0]).
1269 HTMLBRElement* endBR = 1281 HTMLBRElement* endBR =
1270 isHTMLBRElement(*mostForwardCaretPosition(insertionPos).anchorNode()) 1282 isHTMLBRElement(*mostForwardCaretPosition(insertionPos).anchorNode())
1271 ? toHTMLBRElement(mostForwardCaretPosition(insertionPos).anchorNode()) 1283 ? toHTMLBRElement(mostForwardCaretPosition(insertionPos).anchorNode())
1272 : 0; 1284 : 0;
1273 VisiblePosition originalVisPosBeforeEndBR; 1285 VisiblePosition originalVisPosBeforeEndBR;
1274 if (endBR) 1286 if (endBR)
1275 originalVisPosBeforeEndBR = 1287 originalVisPosBeforeEndBR =
1276 previousPositionOf(VisiblePosition::beforeNode(endBR)); 1288 previousPositionOf(VisiblePosition::beforeNode(endBR));
1277 1289
1278 Element* enclosingBlockOfInsertionPos = 1290 Element* enclosingBlockOfInsertionPos =
1279 enclosingBlock(insertionPos.anchorNode()); 1291 enclosingBlock(insertionPos.anchorNode());
1280 1292
1281 // Adjust |enclosingBlockOfInsertionPos| to prevent nesting. 1293 // Adjust |enclosingBlockOfInsertionPos| to prevent nesting.
1282 // If the start was in a Mail blockquote, we will have already handled 1294 // If the start was in a Mail blockquote, we will have already handled
1283 // adjusting |enclosingBlockOfInsertionPos| above. 1295 // adjusting |enclosingBlockOfInsertionPos| above.
1284 if (m_preventNesting && enclosingBlockOfInsertionPos && 1296 if (m_preventNesting && enclosingBlockOfInsertionPos &&
1285 enclosingBlockOfInsertionPos != currentRoot && 1297 enclosingBlockOfInsertionPos != currentRoot &&
1286 !isTableCell(enclosingBlockOfInsertionPos) && 1298 !isTableCell(enclosingBlockOfInsertionPos) &&
1287 !startIsInsideMailBlockquote) { 1299 !startIsInsideMailBlockquote) {
1288 VisiblePosition visibleInsertionPos = 1300 VisiblePosition visibleInsertionPos = createVisiblePosition(insertionPos);
1289 createVisiblePositionDeprecated(insertionPos);
1290 if (isEndOfBlock(visibleInsertionPos) && 1301 if (isEndOfBlock(visibleInsertionPos) &&
1291 !(isStartOfBlock(visibleInsertionPos) && 1302 !(isStartOfBlock(visibleInsertionPos) &&
1292 fragment.hasInterchangeNewlineAtEnd())) 1303 fragment.hasInterchangeNewlineAtEnd()))
1293 insertionPos = Position::inParentAfterNode(*enclosingBlockOfInsertionPos); 1304 insertionPos = Position::inParentAfterNode(*enclosingBlockOfInsertionPos);
1294 else if (isStartOfBlock(visibleInsertionPos)) 1305 else if (isStartOfBlock(visibleInsertionPos))
1295 insertionPos = 1306 insertionPos =
1296 Position::inParentBeforeNode(*enclosingBlockOfInsertionPos); 1307 Position::inParentBeforeNode(*enclosingBlockOfInsertionPos);
1297 } 1308 }
1298 1309
1299 // Paste at start or end of link goes outside of link. 1310 // Paste at start or end of link goes outside of link.
1300 insertionPos = 1311 insertionPos =
1301 positionAvoidingSpecialElementBoundary(insertionPos, editingState); 1312 positionAvoidingSpecialElementBoundary(insertionPos, editingState);
1302 if (editingState->isAborted()) 1313 if (editingState->isAborted())
1303 return; 1314 return;
1304 1315
1305 // FIXME: Can this wait until after the operation has been performed? There 1316 // FIXME: Can this wait until after the operation has been performed? There
1306 // doesn't seem to be any work performed after this that queries or uses the 1317 // doesn't seem to be any work performed after this that queries or uses the
1307 // typing style. 1318 // typing style.
1308 if (LocalFrame* frame = document().frame()) 1319 if (LocalFrame* frame = document().frame())
1309 frame->selection().clearTypingStyle(); 1320 frame->selection().clearTypingStyle();
1310 1321
1311 removeHeadContents(fragment); 1322 removeHeadContents(fragment);
1312 1323
1324 document().updateStyleAndLayoutIgnorePendingStylesheets();
1325
1313 // We don't want the destination to end up inside nodes that weren't selected. 1326 // We don't want the destination to end up inside nodes that weren't selected.
1314 // To avoid that, we move the position forward without changing the visible 1327 // To avoid that, we move the position forward without changing the visible
1315 // position so we're still at the same visible location, but outside of 1328 // position so we're still at the same visible location, but outside of
1316 // preceding tags. 1329 // preceding tags.
1317 insertionPos = positionAvoidingPrecedingNodes(insertionPos); 1330 insertionPos = positionAvoidingPrecedingNodes(insertionPos);
1318 1331
1319 // Paste into run of tabs splits the tab span. 1332 // Paste into run of tabs splits the tab span.
1320 insertionPos = positionOutsideTabSpan(insertionPos); 1333 insertionPos = positionOutsideTabSpan(insertionPos);
1321 1334
1322 bool handledStyleSpans = 1335 bool handledStyleSpans =
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1423 1436
1424 if (isRichlyEditablePosition(insertionPos)) 1437 if (isRichlyEditablePosition(insertionPos))
1425 removeUnrenderedTextNodesAtEnds(insertedNodes); 1438 removeUnrenderedTextNodesAtEnds(insertedNodes);
1426 1439
1427 if (!handledStyleSpans) { 1440 if (!handledStyleSpans) {
1428 handleStyleSpans(insertedNodes, editingState); 1441 handleStyleSpans(insertedNodes, editingState);
1429 if (editingState->isAborted()) 1442 if (editingState->isAborted())
1430 return; 1443 return;
1431 } 1444 }
1432 1445
1446 document().updateStyleAndLayoutIgnorePendingStylesheets();
1447
1433 // Mutation events (bug 20161) may have already removed the inserted content 1448 // Mutation events (bug 20161) may have already removed the inserted content
1434 if (!insertedNodes.firstNodeInserted() || 1449 if (!insertedNodes.firstNodeInserted() ||
1435 !insertedNodes.firstNodeInserted()->isConnected()) 1450 !insertedNodes.firstNodeInserted()->isConnected())
1436 return; 1451 return;
1437 1452
1438 // Scripts specified in javascript protocol may remove 1453 // Scripts specified in javascript protocol may remove
1439 // |enclosingBlockOfInsertionPos| during insertion, e.g. <iframe 1454 // |enclosingBlockOfInsertionPos| during insertion, e.g. <iframe
1440 // src="javascript:..."> 1455 // src="javascript:...">
1441 if (enclosingBlockOfInsertionPos && 1456 if (enclosingBlockOfInsertionPos &&
1442 !enclosingBlockOfInsertionPos->isConnected()) 1457 !enclosingBlockOfInsertionPos->isConnected())
1443 enclosingBlockOfInsertionPos = nullptr; 1458 enclosingBlockOfInsertionPos = nullptr;
1444 1459
1445 VisiblePosition startOfInsertedContent = createVisiblePositionDeprecated( 1460 VisiblePosition startOfInsertedContent = createVisiblePosition(
1446 firstPositionInOrBeforeNode(insertedNodes.firstNodeInserted())); 1461 firstPositionInOrBeforeNode(insertedNodes.firstNodeInserted()));
1447 1462
1448 // We inserted before the enclosingBlockOfInsertionPos to prevent nesting, and 1463 // We inserted before the enclosingBlockOfInsertionPos to prevent nesting, and
1449 // the content before the enclosingBlockOfInsertionPos wasn't in its own block 1464 // the content before the enclosingBlockOfInsertionPos wasn't in its own block
1450 // and didn't have a br after it, so the inserted content ended up in the same 1465 // and didn't have a br after it, so the inserted content ended up in the same
1451 // paragraph. 1466 // paragraph.
1452 if (!startOfInsertedContent.isNull() && enclosingBlockOfInsertionPos && 1467 if (!startOfInsertedContent.isNull() && enclosingBlockOfInsertionPos &&
1453 insertionPos.anchorNode() == enclosingBlockOfInsertionPos->parentNode() && 1468 insertionPos.anchorNode() == enclosingBlockOfInsertionPos->parentNode() &&
1454 (unsigned)insertionPos.computeEditingOffset() < 1469 (unsigned)insertionPos.computeEditingOffset() <
1455 enclosingBlockOfInsertionPos->nodeIndex() && 1470 enclosingBlockOfInsertionPos->nodeIndex() &&
1456 !isStartOfParagraphDeprecated(startOfInsertedContent)) { 1471 !isStartOfParagraph(startOfInsertedContent)) {
1457 insertNodeAt(HTMLBRElement::create(document()), 1472 insertNodeAt(HTMLBRElement::create(document()),
1458 startOfInsertedContent.deepEquivalent(), editingState); 1473 startOfInsertedContent.deepEquivalent(), editingState);
1459 if (editingState->isAborted()) 1474 if (editingState->isAborted())
1460 return; 1475 return;
1461 } 1476 }
1462 1477
1463 if (endBR && 1478 if (endBR &&
1464 (plainTextFragment || 1479 (plainTextFragment ||
1465 (shouldRemoveEndBR(endBR, originalVisPosBeforeEndBR) && 1480 (shouldRemoveEndBR(endBR, originalVisPosBeforeEndBR) &&
1466 !(fragment.hasInterchangeNewlineAtEnd() && selectionIsPlainText)))) { 1481 !(fragment.hasInterchangeNewlineAtEnd() && selectionIsPlainText)))) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1503 lastPositionInOrAfterNode(insertedNodes.lastLeafInserted()); 1518 lastPositionInOrAfterNode(insertedNodes.lastLeafInserted());
1504 1519
1505 // Determine whether or not we should merge the end of inserted content with 1520 // Determine whether or not we should merge the end of inserted content with
1506 // what's after it before we do the start merge so that the start merge 1521 // what's after it before we do the start merge so that the start merge
1507 // doesn't effect our decision. 1522 // doesn't effect our decision.
1508 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph); 1523 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph);
1509 1524
1510 if (shouldMergeStart(selectionStartWasStartOfParagraph, 1525 if (shouldMergeStart(selectionStartWasStartOfParagraph,
1511 fragment.hasInterchangeNewlineAtStart(), 1526 fragment.hasInterchangeNewlineAtStart(),
1512 startIsInsideMailBlockquote)) { 1527 startIsInsideMailBlockquote)) {
1528 // TODO(xiaochengh): Stop storing VisiblePositions through mutations.
1513 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedContent(); 1529 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedContent();
1514 VisiblePosition destination = previousPositionOf(startOfParagraphToMove); 1530 VisiblePosition destination = previousPositionOf(startOfParagraphToMove);
1515 // We need to handle the case where we need to merge the end 1531 // We need to handle the case where we need to merge the end
1516 // but our destination node is inside an inline that is the last in the 1532 // but our destination node is inside an inline that is the last in the
1517 // block. 1533 // block.
1518 // We insert a placeholder before the newly inserted content to avoid being 1534 // We insert a placeholder before the newly inserted content to avoid being
1519 // merged into the inline. 1535 // merged into the inline.
1520 Node* destinationNode = destination.deepEquivalent().anchorNode(); 1536 Node* destinationNode = destination.deepEquivalent().anchorNode();
1521 if (m_shouldMergeEnd && 1537 if (m_shouldMergeEnd &&
1522 destinationNode != enclosingInline(destinationNode) && 1538 destinationNode != enclosingInline(destinationNode) &&
1523 enclosingInline(destinationNode)->nextSibling()) { 1539 enclosingInline(destinationNode)->nextSibling()) {
1524 insertNodeBefore(HTMLBRElement::create(document()), refNode, 1540 insertNodeBefore(HTMLBRElement::create(document()), refNode,
1525 editingState); 1541 editingState);
1526 if (editingState->isAborted()) 1542 if (editingState->isAborted())
1527 return; 1543 return;
1528 } 1544 }
1529 1545
1530 // Merging the the first paragraph of inserted content with the content that 1546 // Merging the the first paragraph of inserted content with the content that
1531 // came before the selection that was pasted into would also move content 1547 // came before the selection that was pasted into would also move content
1532 // after the selection that was pasted into if: only one paragraph was being 1548 // after the selection that was pasted into if: only one paragraph was being
1533 // pasted, and it was not wrapped in a block, the selection that was pasted 1549 // pasted, and it was not wrapped in a block, the selection that was pasted
1534 // into ended at the end of a block and the next paragraph didn't start at 1550 // into ended at the end of a block and the next paragraph didn't start at
1535 // the start of a block. 1551 // the start of a block.
1536 // Insert a line break just after the inserted content to separate it from 1552 // Insert a line break just after the inserted content to separate it from
1537 // what comes after and prevent that from happening. 1553 // what comes after and prevent that from happening.
1538 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); 1554 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent();
1539 if (startOfParagraphDeprecated(endOfInsertedContent).deepEquivalent() == 1555 if (startOfParagraph(endOfInsertedContent).deepEquivalent() ==
1540 startOfParagraphToMove.deepEquivalent()) { 1556 startOfParagraphToMove.deepEquivalent()) {
1541 insertNodeAt(HTMLBRElement::create(document()), 1557 insertNodeAt(HTMLBRElement::create(document()),
1542 endOfInsertedContent.deepEquivalent(), editingState); 1558 endOfInsertedContent.deepEquivalent(), editingState);
1543 if (editingState->isAborted()) 1559 if (editingState->isAborted())
1544 return; 1560 return;
1545 // Mutation events (bug 22634) triggered by inserting the <br> might have 1561 // Mutation events (bug 22634) triggered by inserting the <br> might have
1546 // removed the content we're about to move 1562 // removed the content we're about to move
1547 if (!startOfParagraphToMove.deepEquivalent().isConnected()) 1563 if (!startOfParagraphToMove.deepEquivalent().isConnected())
1548 return; 1564 return;
1549 } 1565 }
1550 1566
1567 document().updateStyleAndLayoutIgnorePendingStylesheets();
1568
1551 // FIXME: Maintain positions for the start and end of inserted content 1569 // FIXME: Maintain positions for the start and end of inserted content
1552 // instead of keeping nodes. The nodes are only ever used to create 1570 // instead of keeping nodes. The nodes are only ever used to create
1553 // positions where inserted content starts/ends. 1571 // positions where inserted content starts/ends.
1554 moveParagraph(startOfParagraphToMove, 1572 moveParagraph(startOfParagraphToMove,
1555 endOfParagraphDeprecated(startOfParagraphToMove), destination, 1573 endOfParagraph(createVisiblePosition(
1556 editingState); 1574 startOfParagraphToMove.toPositionWithAffinity())),
1575 destination, editingState);
1557 if (editingState->isAborted()) 1576 if (editingState->isAborted())
1558 return; 1577 return;
1578
1579 document().updateStyleAndLayoutIgnorePendingStylesheets();
1559 m_startOfInsertedContent = mostForwardCaretPosition( 1580 m_startOfInsertedContent = mostForwardCaretPosition(
1560 endingSelection().visibleStartDeprecated().deepEquivalent()); 1581 endingSelection().visibleStart().deepEquivalent());
1561 if (m_endOfInsertedContent.isOrphan()) 1582 if (m_endOfInsertedContent.isOrphan()) {
1562 m_endOfInsertedContent = mostBackwardCaretPosition( 1583 m_endOfInsertedContent = mostBackwardCaretPosition(
1563 endingSelection().visibleEndDeprecated().deepEquivalent()); 1584 endingSelection().visibleEnd().deepEquivalent());
1585 }
1564 } 1586 }
1565 1587
1566 Position lastPositionToSelect; 1588 Position lastPositionToSelect;
1567 if (fragment.hasInterchangeNewlineAtEnd()) { 1589 if (fragment.hasInterchangeNewlineAtEnd()) {
1568 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); 1590 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent();
1569 VisiblePosition next = 1591 VisiblePosition next =
1570 nextPositionOf(endOfInsertedContent, CannotCrossEditingBoundary); 1592 nextPositionOf(endOfInsertedContent, CannotCrossEditingBoundary);
1571 1593
1572 if (selectionEndWasEndOfParagraph || 1594 if (selectionEndWasEndOfParagraph ||
1573 !isEndOfParagraphDeprecated(endOfInsertedContent) || next.isNull()) { 1595 !isEndOfParagraph(endOfInsertedContent) || next.isNull()) {
1574 if (HTMLTextFormControlElement* textControl = 1596 if (HTMLTextFormControlElement* textControl =
1575 enclosingTextFormControl(currentRoot)) { 1597 enclosingTextFormControl(currentRoot)) {
1576 if (!insertedNodes.lastLeafInserted()->nextSibling()) { 1598 if (!insertedNodes.lastLeafInserted()->nextSibling()) {
1577 insertNodeAfter(textControl->createPlaceholderBreakElement(), 1599 insertNodeAfter(textControl->createPlaceholderBreakElement(),
1578 insertedNodes.lastLeafInserted(), editingState); 1600 insertedNodes.lastLeafInserted(), editingState);
1579 if (editingState->isAborted()) 1601 if (editingState->isAborted())
1580 return; 1602 return;
1581 } 1603 }
1582 setEndingSelection( 1604 setEndingSelection(
1583 VisiblePosition::afterNode(insertedNodes.lastLeafInserted())); 1605 VisiblePosition::afterNode(insertedNodes.lastLeafInserted()));
1584 // Select up to the paragraph separator that was added. 1606 // Select up to the paragraph separator that was added.
1585 lastPositionToSelect = 1607 lastPositionToSelect =
1586 endingSelection().visibleStartDeprecated().deepEquivalent(); 1608 endingSelection().visibleStart().deepEquivalent();
1587 } else if (!isStartOfParagraphDeprecated(endOfInsertedContent)) { 1609 } else if (!isStartOfParagraph(endOfInsertedContent)) {
1588 setEndingSelection(endOfInsertedContent); 1610 setEndingSelection(endOfInsertedContent);
1589 Element* enclosingBlockElement = 1611 Element* enclosingBlockElement =
1590 enclosingBlock(endOfInsertedContent.deepEquivalent().anchorNode()); 1612 enclosingBlock(endOfInsertedContent.deepEquivalent().anchorNode());
1591 if (isListItem(enclosingBlockElement)) { 1613 if (isListItem(enclosingBlockElement)) {
1592 HTMLLIElement* newListItem = HTMLLIElement::create(document()); 1614 HTMLLIElement* newListItem = HTMLLIElement::create(document());
1593 insertNodeAfter(newListItem, enclosingBlockElement, editingState); 1615 insertNodeAfter(newListItem, enclosingBlockElement, editingState);
1594 if (editingState->isAborted()) 1616 if (editingState->isAborted())
1595 return; 1617 return;
1596 setEndingSelection(VisiblePosition::firstPositionInNode(newListItem)); 1618 setEndingSelection(VisiblePosition::firstPositionInNode(newListItem));
1597 } else { 1619 } else {
1598 // Use a default paragraph element (a plain div) for the empty 1620 // Use a default paragraph element (a plain div) for the empty
1599 // paragraph, using the last paragraph block's style seems to annoy 1621 // paragraph, using the last paragraph block's style seems to annoy
1600 // users. 1622 // users.
1601 insertParagraphSeparator( 1623 insertParagraphSeparator(
1602 editingState, true, 1624 editingState, true,
1603 !startIsInsideMailBlockquote && 1625 !startIsInsideMailBlockquote &&
1604 highestEnclosingNodeOfType( 1626 highestEnclosingNodeOfType(
1605 endOfInsertedContent.deepEquivalent(), 1627 endOfInsertedContent.deepEquivalent(),
1606 isMailHTMLBlockquoteElement, CannotCrossEditingBoundary, 1628 isMailHTMLBlockquoteElement, CannotCrossEditingBoundary,
1607 insertedNodes.firstNodeInserted()->parentNode())); 1629 insertedNodes.firstNodeInserted()->parentNode()));
1608 if (editingState->isAborted()) 1630 if (editingState->isAborted())
1609 return; 1631 return;
1610 } 1632 }
1611 1633
1634 document().updateStyleAndLayoutIgnorePendingStylesheets();
1635
1612 // Select up to the paragraph separator that was added. 1636 // Select up to the paragraph separator that was added.
1613 lastPositionToSelect = 1637 lastPositionToSelect =
1614 endingSelection().visibleStartDeprecated().deepEquivalent(); 1638 endingSelection().visibleStart().deepEquivalent();
1615 updateNodesInserted(lastPositionToSelect.anchorNode()); 1639 updateNodesInserted(lastPositionToSelect.anchorNode());
1616 } 1640 }
1617 } else { 1641 } else {
1618 // Select up to the beginning of the next paragraph. 1642 // Select up to the beginning of the next paragraph.
1619 lastPositionToSelect = mostForwardCaretPosition(next.deepEquivalent()); 1643 lastPositionToSelect = mostForwardCaretPosition(next.deepEquivalent());
1620 } 1644 }
1621 } else { 1645 } else {
1622 mergeEndIfNeeded(editingState); 1646 mergeEndIfNeeded(editingState);
1623 if (editingState->isAborted()) 1647 if (editingState->isAborted())
1624 return; 1648 return;
(...skipping 26 matching lines...) Expand all
1651 1675
1652 VisiblePosition visiblePos = VisiblePosition::beforeNode(endBR); 1676 VisiblePosition visiblePos = VisiblePosition::beforeNode(endBR);
1653 1677
1654 // Don't remove the br if nothing was inserted. 1678 // Don't remove the br if nothing was inserted.
1655 if (previousPositionOf(visiblePos).deepEquivalent() == 1679 if (previousPositionOf(visiblePos).deepEquivalent() ==
1656 originalVisPosBeforeEndBR.deepEquivalent()) 1680 originalVisPosBeforeEndBR.deepEquivalent())
1657 return false; 1681 return false;
1658 1682
1659 // Remove the br if it is collapsed away and so is unnecessary. 1683 // Remove the br if it is collapsed away and so is unnecessary.
1660 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && 1684 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) &&
1661 !isStartOfParagraphDeprecated(visiblePos)) 1685 !isStartOfParagraph(visiblePos))
1662 return true; 1686 return true;
1663 1687
1664 // A br that was originally holding a line open should be displaced by 1688 // A br that was originally holding a line open should be displaced by
1665 // inserted content or turned into a line break. 1689 // inserted content or turned into a line break.
1666 // A br that was originally acting as a line break should still be acting as a 1690 // A br that was originally acting as a line break should still be acting as a
1667 // line break, not as a placeholder. 1691 // line break, not as a placeholder.
1668 return isStartOfParagraphDeprecated(visiblePos) && 1692 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos);
1669 isEndOfParagraphDeprecated(visiblePos);
1670 } 1693 }
1671 1694
1672 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const { 1695 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const {
1673 if (!m_smartReplace) 1696 if (!m_smartReplace)
1674 return false; 1697 return false;
1675 1698
1676 HTMLTextFormControlElement* textControl = enclosingTextFormControl( 1699 HTMLTextFormControlElement* textControl = enclosingTextFormControl(
1677 positionAtStartOfInsertedContent().deepEquivalent()); 1700 positionAtStartOfInsertedContent().deepEquivalent());
1678 if (isHTMLInputElement(textControl) && 1701 if (isHTMLInputElement(textControl) &&
1679 toHTMLInputElement(textControl)->type() == InputTypeNames::password) 1702 toHTMLInputElement(textControl)->type() == InputTypeNames::password)
(...skipping 16 matching lines...) Expand all
1696 mostBackwardCaretPosition(endOfInsertedContent.deepEquivalent()); 1719 mostBackwardCaretPosition(endOfInsertedContent.deepEquivalent());
1697 Node* endNode = endUpstream.computeNodeBeforePosition(); 1720 Node* endNode = endUpstream.computeNodeBeforePosition();
1698 int endOffset = 1721 int endOffset =
1699 endNode && endNode->isTextNode() ? toText(endNode)->length() : 0; 1722 endNode && endNode->isTextNode() ? toText(endNode)->length() : 0;
1700 if (endUpstream.isOffsetInAnchor()) { 1723 if (endUpstream.isOffsetInAnchor()) {
1701 endNode = endUpstream.computeContainerNode(); 1724 endNode = endUpstream.computeContainerNode();
1702 endOffset = endUpstream.offsetInContainerNode(); 1725 endOffset = endUpstream.offsetInContainerNode();
1703 } 1726 }
1704 1727
1705 bool needsTrailingSpace = 1728 bool needsTrailingSpace =
1706 !isEndOfParagraphDeprecated(endOfInsertedContent) && 1729 !isEndOfParagraph(endOfInsertedContent) &&
1707 !isCharacterSmartReplaceExemptConsideringNonBreakingSpace( 1730 !isCharacterSmartReplaceExemptConsideringNonBreakingSpace(
1708 characterAfter(endOfInsertedContent), false); 1731 characterAfter(endOfInsertedContent), false);
1709 if (needsTrailingSpace && endNode) { 1732 if (needsTrailingSpace && endNode) {
1710 bool collapseWhiteSpace = 1733 bool collapseWhiteSpace =
1711 !endNode->layoutObject() || 1734 !endNode->layoutObject() ||
1712 endNode->layoutObject()->style()->collapseWhiteSpace(); 1735 endNode->layoutObject()->style()->collapseWhiteSpace();
1713 if (endNode->isTextNode()) { 1736 if (endNode->isTextNode()) {
1714 insertTextIntoNode(toText(endNode), endOffset, 1737 insertTextIntoNode(toText(endNode), endOffset,
1715 collapseWhiteSpace ? nonBreakingSpaceString() : " "); 1738 collapseWhiteSpace ? nonBreakingSpaceString() : " ");
1716 if (m_endOfInsertedContent.computeContainerNode() == endNode) 1739 if (m_endOfInsertedContent.computeContainerNode() == endNode)
(...skipping 18 matching lines...) Expand all
1735 Position startDownstream = 1758 Position startDownstream =
1736 mostForwardCaretPosition(startOfInsertedContent.deepEquivalent()); 1759 mostForwardCaretPosition(startOfInsertedContent.deepEquivalent());
1737 Node* startNode = startDownstream.computeNodeAfterPosition(); 1760 Node* startNode = startDownstream.computeNodeAfterPosition();
1738 unsigned startOffset = 0; 1761 unsigned startOffset = 0;
1739 if (startDownstream.isOffsetInAnchor()) { 1762 if (startDownstream.isOffsetInAnchor()) {
1740 startNode = startDownstream.computeContainerNode(); 1763 startNode = startDownstream.computeContainerNode();
1741 startOffset = startDownstream.offsetInContainerNode(); 1764 startOffset = startDownstream.offsetInContainerNode();
1742 } 1765 }
1743 1766
1744 bool needsLeadingSpace = 1767 bool needsLeadingSpace =
1745 !isStartOfParagraphDeprecated(startOfInsertedContent) && 1768 !isStartOfParagraph(startOfInsertedContent) &&
1746 !isCharacterSmartReplaceExemptConsideringNonBreakingSpace( 1769 !isCharacterSmartReplaceExemptConsideringNonBreakingSpace(
1747 characterBefore(startOfInsertedContent), true); 1770 characterBefore(startOfInsertedContent), true);
1748 if (needsLeadingSpace && startNode) { 1771 if (needsLeadingSpace && startNode) {
1749 bool collapseWhiteSpace = 1772 bool collapseWhiteSpace =
1750 !startNode->layoutObject() || 1773 !startNode->layoutObject() ||
1751 startNode->layoutObject()->style()->collapseWhiteSpace(); 1774 startNode->layoutObject()->style()->collapseWhiteSpace();
1752 if (startNode->isTextNode()) { 1775 if (startNode->isTextNode()) {
1753 insertTextIntoNode(toText(startNode), startOffset, 1776 insertTextIntoNode(toText(startNode), startOffset,
1754 collapseWhiteSpace ? nonBreakingSpaceString() : " "); 1777 collapseWhiteSpace ? nonBreakingSpaceString() : " ");
1755 if (m_endOfInsertedContent.computeContainerNode() == startNode && 1778 if (m_endOfInsertedContent.computeContainerNode() == startNode &&
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1799 return; 1822 return;
1800 } else if (lastPositionToSelect.isNotNull()) { 1823 } else if (lastPositionToSelect.isNotNull()) {
1801 start = end = lastPositionToSelect; 1824 start = end = lastPositionToSelect;
1802 } else { 1825 } else {
1803 return; 1826 return;
1804 } 1827 }
1805 1828
1806 m_startOfInsertedRange = start; 1829 m_startOfInsertedRange = start;
1807 m_endOfInsertedRange = end; 1830 m_endOfInsertedRange = end;
1808 1831
1832 document().updateStyleAndLayoutIgnorePendingStylesheets();
1833
1809 if (m_selectReplacement) 1834 if (m_selectReplacement)
1810 setEndingSelection(createVisibleSelectionDeprecated( 1835 setEndingSelection(createVisibleSelection(
1811 start, end, SelDefaultAffinity, endingSelection().isDirectional())); 1836 start, end, SelDefaultAffinity, endingSelection().isDirectional()));
1812 else 1837 else
1813 setEndingSelection(createVisibleSelectionDeprecated( 1838 setEndingSelection(createVisibleSelection(
1814 end, SelDefaultAffinity, endingSelection().isDirectional())); 1839 end, SelDefaultAffinity, endingSelection().isDirectional()));
1815 } 1840 }
1816 1841
1817 void ReplaceSelectionCommand::mergeTextNodesAroundPosition( 1842 void ReplaceSelectionCommand::mergeTextNodesAroundPosition(
1818 Position& position, 1843 Position& position,
1819 Position& positionOnlyToBeUpdated, 1844 Position& positionOnlyToBeUpdated,
1820 EditingState* editingState) { 1845 EditingState* editingState) {
1821 bool positionIsOffsetInAnchor = position.isOffsetInAnchor(); 1846 bool positionIsOffsetInAnchor = position.isOffsetInAnchor();
1822 bool positionOnlyToBeUpdatedIsOffsetInAnchor = 1847 bool positionOnlyToBeUpdatedIsOffsetInAnchor =
1823 positionOnlyToBeUpdated.isOffsetInAnchor(); 1848 positionOnlyToBeUpdated.isOffsetInAnchor();
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
1915 // list, we put the list items into the existing list. 1940 // list, we put the list items into the existing list.
1916 Node* ReplaceSelectionCommand::insertAsListItems(HTMLElement* listElement, 1941 Node* ReplaceSelectionCommand::insertAsListItems(HTMLElement* listElement,
1917 Element* insertionBlock, 1942 Element* insertionBlock,
1918 const Position& insertPos, 1943 const Position& insertPos,
1919 InsertedNodes& insertedNodes, 1944 InsertedNodes& insertedNodes,
1920 EditingState* editingState) { 1945 EditingState* editingState) {
1921 while (listElement->hasOneChild() && 1946 while (listElement->hasOneChild() &&
1922 isHTMLListElement(listElement->firstChild())) 1947 isHTMLListElement(listElement->firstChild()))
1923 listElement = toHTMLElement(listElement->firstChild()); 1948 listElement = toHTMLElement(listElement->firstChild());
1924 1949
1925 bool isStart = 1950 document().updateStyleAndLayoutIgnorePendingStylesheets();
1926 isStartOfParagraphDeprecated(createVisiblePositionDeprecated(insertPos)); 1951 bool isStart = isStartOfParagraph(createVisiblePosition(insertPos));
1927 bool isEnd = 1952 bool isEnd = isEndOfParagraph(createVisiblePosition(insertPos));
1928 isEndOfParagraphDeprecated(createVisiblePositionDeprecated(insertPos));
1929 bool isMiddle = !isStart && !isEnd; 1953 bool isMiddle = !isStart && !isEnd;
1930 Node* lastNode = insertionBlock; 1954 Node* lastNode = insertionBlock;
1931 1955
1932 // If we're in the middle of a list item, we should split it into two separate 1956 // If we're in the middle of a list item, we should split it into two separate
1933 // list items and insert these nodes between them. 1957 // list items and insert these nodes between them.
1934 if (isMiddle) { 1958 if (isMiddle) {
1935 int textNodeOffset = insertPos.offsetInContainerNode(); 1959 int textNodeOffset = insertPos.offsetInContainerNode();
1936 if (insertPos.anchorNode()->isTextNode() && textNodeOffset > 0) 1960 if (insertPos.anchorNode()->isTextNode() && textNodeOffset > 0)
1937 splitTextNode(toText(insertPos.anchorNode()), textNodeOffset); 1961 splitTextNode(toText(insertPos.anchorNode()), textNodeOffset);
1938 splitTreeToNode(insertPos.anchorNode(), lastNode, true); 1962 splitTreeToNode(insertPos.anchorNode(), lastNode, true);
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
2013 shouldRemoveEndBR(toHTMLBRElement(nodeAfterInsertionPos), 2037 shouldRemoveEndBR(toHTMLBRElement(nodeAfterInsertionPos),
2014 VisiblePosition::beforeNode(nodeAfterInsertionPos))) { 2038 VisiblePosition::beforeNode(nodeAfterInsertionPos))) {
2015 removeNodeAndPruneAncestors(nodeAfterInsertionPos, editingState); 2039 removeNodeAndPruneAncestors(nodeAfterInsertionPos, editingState);
2016 if (editingState->isAborted()) 2040 if (editingState->isAborted())
2017 return false; 2041 return false;
2018 } 2042 }
2019 2043
2020 m_startOfInsertedRange = start; 2044 m_startOfInsertedRange = start;
2021 m_endOfInsertedRange = end; 2045 m_endOfInsertedRange = end;
2022 2046
2047 document().updateStyleAndLayoutIgnorePendingStylesheets();
2023 VisibleSelection selectionAfterReplace = 2048 VisibleSelection selectionAfterReplace =
2024 createVisibleSelectionDeprecated(m_selectReplacement ? start : end, end); 2049 createVisibleSelection(m_selectReplacement ? start : end, end);
2025 2050
2026 setEndingSelection(selectionAfterReplace); 2051 setEndingSelection(selectionAfterReplace);
2027 2052
2028 return true; 2053 return true;
2029 } 2054 }
2030 2055
2031 bool ReplaceSelectionCommand::isReplaceSelectionCommand() const { 2056 bool ReplaceSelectionCommand::isReplaceSelectionCommand() const {
2032 return true; 2057 return true;
2033 } 2058 }
2034 2059
2035 EphemeralRange ReplaceSelectionCommand::insertedRange() const { 2060 EphemeralRange ReplaceSelectionCommand::insertedRange() const {
2036 return EphemeralRange(m_startOfInsertedRange, m_endOfInsertedRange); 2061 return EphemeralRange(m_startOfInsertedRange, m_endOfInsertedRange);
2037 } 2062 }
2038 2063
2039 DEFINE_TRACE(ReplaceSelectionCommand) { 2064 DEFINE_TRACE(ReplaceSelectionCommand) {
2040 visitor->trace(m_startOfInsertedContent); 2065 visitor->trace(m_startOfInsertedContent);
2041 visitor->trace(m_endOfInsertedContent); 2066 visitor->trace(m_endOfInsertedContent);
2042 visitor->trace(m_insertionStyle); 2067 visitor->trace(m_insertionStyle);
2043 visitor->trace(m_documentFragment); 2068 visitor->trace(m_documentFragment);
2044 visitor->trace(m_startOfInsertedRange); 2069 visitor->trace(m_startOfInsertedRange);
2045 visitor->trace(m_endOfInsertedRange); 2070 visitor->trace(m_endOfInsertedRange);
2046 CompositeEditCommand::trace(visitor); 2071 CompositeEditCommand::trace(visitor);
2047 } 2072 }
2048 2073
2049 } // namespace blink 2074 } // namespace blink
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698