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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |