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 615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
626 elements.add(tfootTag.localName()); | 626 elements.add(tfootTag.localName()); |
627 elements.add(thTag.localName()); | 627 elements.add(thTag.localName()); |
628 elements.add(theadTag.localName()); | 628 elements.add(theadTag.localName()); |
629 elements.add(trTag.localName()); | 629 elements.add(trTag.localName()); |
630 elements.add(ulTag.localName()); | 630 elements.add(ulTag.localName()); |
631 elements.add(xmpTag.localName()); | 631 elements.add(xmpTag.localName()); |
632 } | 632 } |
633 return elements.contains(name); | 633 return elements.contains(name); |
634 } | 634 } |
635 | 635 |
636 void ReplaceSelectionCommand::makeInsertedContentRoundTrippableWithHTMLTreeBuild
er(const InsertedNodes& insertedNodes) | 636 void ReplaceSelectionCommand::makeInsertedContentRoundTrippableWithHTMLTreeBuild
er(const InsertedNodes& insertedNodes, EditingState* editingState) |
637 { | 637 { |
638 RefPtrWillBeRawPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); | 638 RefPtrWillBeRawPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); |
639 RefPtrWillBeRawPtr<Node> next = nullptr; | 639 RefPtrWillBeRawPtr<Node> next = nullptr; |
640 for (RefPtrWillBeRawPtr<Node> node = insertedNodes.firstNodeInserted(); node
&& node != pastEndNode; node = next) { | 640 for (RefPtrWillBeRawPtr<Node> node = insertedNodes.firstNodeInserted(); node
&& node != pastEndNode; node = next) { |
641 next = NodeTraversal::next(*node); | 641 next = NodeTraversal::next(*node); |
642 | 642 |
643 if (!node->isHTMLElement()) | 643 if (!node->isHTMLElement()) |
644 continue; | 644 continue; |
645 // moveElementOutOfAncestor() in a previous iteration might have failed, | 645 // moveElementOutOfAncestor() in a previous iteration might have failed, |
646 // and |node| might have been detached from the document tree. | 646 // and |node| might have been detached from the document tree. |
647 if (!node->inDocument()) | 647 if (!node->inDocument()) |
648 continue; | 648 continue; |
649 | 649 |
650 HTMLElement& element = toHTMLElement(*node); | 650 HTMLElement& element = toHTMLElement(*node); |
651 if (isProhibitedParagraphChild(element.localName())) { | 651 if (isProhibitedParagraphChild(element.localName())) { |
652 if (HTMLElement* paragraphElement = toHTMLElement(enclosingElementWi
thTag(positionInParentBeforeNode(element), pTag))) | 652 if (HTMLElement* paragraphElement = toHTMLElement(enclosingElementWi
thTag(positionInParentBeforeNode(element), pTag))) { |
653 moveElementOutOfAncestor(&element, paragraphElement); | 653 moveElementOutOfAncestor(&element, paragraphElement, editingStat
e); |
| 654 if (editingState->isAborted()) |
| 655 return; |
| 656 } |
654 } | 657 } |
655 | 658 |
656 if (isHTMLHeaderElement(&element)) { | 659 if (isHTMLHeaderElement(&element)) { |
657 if (HTMLElement* headerElement = toHTMLElement(highestEnclosingNodeO
fType(positionInParentBeforeNode(element), isHTMLHeaderElement))) | 660 if (HTMLElement* headerElement = toHTMLElement(highestEnclosingNodeO
fType(positionInParentBeforeNode(element), isHTMLHeaderElement))) { |
658 moveElementOutOfAncestor(&element, headerElement); | 661 moveElementOutOfAncestor(&element, headerElement, editingState); |
| 662 if (editingState->isAborted()) |
| 663 return; |
| 664 } |
659 } | 665 } |
660 } | 666 } |
661 } | 667 } |
662 | 668 |
663 void ReplaceSelectionCommand::moveElementOutOfAncestor(PassRefPtrWillBeRawPtr<El
ement> prpElement, PassRefPtrWillBeRawPtr<Element> prpAncestor) | 669 void ReplaceSelectionCommand::moveElementOutOfAncestor(PassRefPtrWillBeRawPtr<El
ement> prpElement, PassRefPtrWillBeRawPtr<Element> prpAncestor, EditingState* ed
itingState) |
664 { | 670 { |
665 RefPtrWillBeRawPtr<Element> element = prpElement; | 671 RefPtrWillBeRawPtr<Element> element = prpElement; |
666 RefPtrWillBeRawPtr<Element> ancestor = prpAncestor; | 672 RefPtrWillBeRawPtr<Element> ancestor = prpAncestor; |
667 | 673 |
668 if (!ancestor->parentNode()->hasEditableStyle()) | 674 if (!ancestor->parentNode()->hasEditableStyle()) |
669 return; | 675 return; |
670 | 676 |
671 VisiblePosition positionAtEndOfNode = createVisiblePosition(lastPositionInOr
AfterNode(element.get())); | 677 VisiblePosition positionAtEndOfNode = createVisiblePosition(lastPositionInOr
AfterNode(element.get())); |
672 VisiblePosition lastPositionInParagraph = createVisiblePosition(lastPosition
InNode(ancestor.get())); | 678 VisiblePosition lastPositionInParagraph = createVisiblePosition(lastPosition
InNode(ancestor.get())); |
673 if (positionAtEndOfNode.deepEquivalent() == lastPositionInParagraph.deepEqui
valent()) { | 679 if (positionAtEndOfNode.deepEquivalent() == lastPositionInParagraph.deepEqui
valent()) { |
674 removeNode(element); | 680 removeNode(element, editingState); |
| 681 if (editingState->isAborted()) |
| 682 return; |
675 if (ancestor->nextSibling()) | 683 if (ancestor->nextSibling()) |
676 insertNodeBefore(element, ancestor->nextSibling()); | 684 insertNodeBefore(element, ancestor->nextSibling(), editingState); |
677 else | 685 else |
678 appendNode(element, ancestor->parentNode()); | 686 appendNode(element, ancestor->parentNode(), editingState); |
| 687 if (editingState->isAborted()) |
| 688 return; |
679 } else { | 689 } else { |
680 RefPtrWillBeRawPtr<Node> nodeToSplitTo = splitTreeToNode(element.get(),
ancestor.get(), true); | 690 RefPtrWillBeRawPtr<Node> nodeToSplitTo = splitTreeToNode(element.get(),
ancestor.get(), true); |
681 removeNode(element); | 691 removeNode(element, editingState); |
682 insertNodeBefore(element, nodeToSplitTo); | 692 if (editingState->isAborted()) |
| 693 return; |
| 694 insertNodeBefore(element, nodeToSplitTo, editingState); |
| 695 if (editingState->isAborted()) |
| 696 return; |
683 } | 697 } |
684 if (!ancestor->hasChildren()) | 698 if (!ancestor->hasChildren()) |
685 removeNode(ancestor.release()); | 699 removeNode(ancestor.release(), editingState); |
686 } | 700 } |
687 | 701 |
688 static inline bool nodeHasVisibleLayoutText(Text& text) | 702 static inline bool nodeHasVisibleLayoutText(Text& text) |
689 { | 703 { |
690 return text.layoutObject() && text.layoutObject()->resolvedTextLength() > 0; | 704 return text.layoutObject() && text.layoutObject()->resolvedTextLength() > 0; |
691 } | 705 } |
692 | 706 |
693 void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds(InsertedNodes& ins
ertedNodes) | 707 void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds(InsertedNodes& ins
ertedNodes) |
694 { | 708 { |
695 document().updateLayoutIgnorePendingStylesheets(); | 709 document().updateLayoutIgnorePendingStylesheets(); |
696 | 710 |
697 Node* lastLeafInserted = insertedNodes.lastLeafInserted(); | 711 Node* lastLeafInserted = insertedNodes.lastLeafInserted(); |
698 if (lastLeafInserted && lastLeafInserted->isTextNode() && !nodeHasVisibleLay
outText(toText(*lastLeafInserted)) | 712 if (lastLeafInserted && lastLeafInserted->isTextNode() && !nodeHasVisibleLay
outText(toText(*lastLeafInserted)) |
699 && !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted
), selectTag) | 713 && !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted
), selectTag) |
700 && !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted
), scriptTag)) { | 714 && !enclosingElementWithTag(firstPositionInOrBeforeNode(lastLeafInserted
), scriptTag)) { |
701 insertedNodes.willRemoveNode(*lastLeafInserted); | 715 insertedNodes.willRemoveNode(*lastLeafInserted); |
702 removeNode(lastLeafInserted); | 716 // Removing a Text node won't dispatch synchronous events. |
| 717 removeNode(lastLeafInserted, ASSERT_NO_EDITING_ABORT); |
703 } | 718 } |
704 | 719 |
705 // We don't have to make sure that firstNodeInserted isn't inside a select o
r script element, because | 720 // We don't have to make sure that firstNodeInserted isn't inside a select o
r script element, because |
706 // it is a top level node in the fragment and the user can't insert into tho
se elements. | 721 // it is a top level node in the fragment and the user can't insert into tho
se elements. |
707 Node* firstNodeInserted = insertedNodes.firstNodeInserted(); | 722 Node* firstNodeInserted = insertedNodes.firstNodeInserted(); |
708 if (firstNodeInserted && firstNodeInserted->isTextNode() && !nodeHasVisibleL
ayoutText(toText(*firstNodeInserted))) { | 723 if (firstNodeInserted && firstNodeInserted->isTextNode() && !nodeHasVisibleL
ayoutText(toText(*firstNodeInserted))) { |
709 insertedNodes.willRemoveNode(*firstNodeInserted); | 724 insertedNodes.willRemoveNode(*firstNodeInserted); |
710 removeNode(firstNodeInserted); | 725 // Removing a Text node won't dispatch synchronous events. |
| 726 removeNode(firstNodeInserted, ASSERT_NO_EDITING_ABORT); |
711 } | 727 } |
712 } | 728 } |
713 | 729 |
714 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() const | 730 VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() const |
715 { | 731 { |
716 // FIXME: Why is this hack here? What's special about <select> tags? | 732 // FIXME: Why is this hack here? What's special about <select> tags? |
717 HTMLSelectElement* enclosingSelect = toHTMLSelectElement(enclosingElementWit
hTag(m_endOfInsertedContent, selectTag)); | 733 HTMLSelectElement* enclosingSelect = toHTMLSelectElement(enclosingElementWit
hTag(m_endOfInsertedContent, selectTag)); |
718 return createVisiblePosition(enclosingSelect ? lastPositionInOrAfterNode(enc
losingSelect) : m_endOfInsertedContent); | 734 return createVisiblePosition(enclosingSelect ? lastPositionInOrAfterNode(enc
losingSelect) : m_endOfInsertedContent); |
719 } | 735 } |
720 | 736 |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
925 const VisibleSelection selection = endingSelection(); | 941 const VisibleSelection selection = endingSelection(); |
926 ASSERT(selection.isCaretOrRange()); | 942 ASSERT(selection.isCaretOrRange()); |
927 ASSERT(selection.start().anchorNode()); | 943 ASSERT(selection.start().anchorNode()); |
928 if (!selection.isNonOrphanedCaretOrRange() || !selection.start().anchorNode(
)) | 944 if (!selection.isNonOrphanedCaretOrRange() || !selection.start().anchorNode(
)) |
929 return; | 945 return; |
930 | 946 |
931 if (!selection.rootEditableElement()) | 947 if (!selection.rootEditableElement()) |
932 return; | 948 return; |
933 | 949 |
934 ReplacementFragment fragment(&document(), m_documentFragment.get(), selectio
n); | 950 ReplacementFragment fragment(&document(), m_documentFragment.get(), selectio
n); |
935 if (performTrivialReplace(fragment)) | 951 bool trivialReplaceResult = performTrivialReplace(fragment, editingState); |
| 952 if (editingState->isAborted()) |
| 953 return; |
| 954 if (trivialReplaceResult) |
936 return; | 955 return; |
937 | 956 |
938 // We can skip matching the style if the selection is plain text. | 957 // We can skip matching the style if the selection is plain text. |
939 if ((selection.start().anchorNode()->layoutObject() && selection.start().anc
horNode()->layoutObject()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY) | 958 if ((selection.start().anchorNode()->layoutObject() && selection.start().anc
horNode()->layoutObject()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY) |
940 && (selection.end().anchorNode()->layoutObject() && selection.end().anch
orNode()->layoutObject()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY)) | 959 && (selection.end().anchorNode()->layoutObject() && selection.end().anch
orNode()->layoutObject()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY)) |
941 m_matchStyle = false; | 960 m_matchStyle = false; |
942 | 961 |
943 if (m_matchStyle) { | 962 if (m_matchStyle) { |
944 m_insertionStyle = EditingStyle::create(selection.start()); | 963 m_insertionStyle = EditingStyle::create(selection.start()); |
945 m_insertionStyle->mergeTypingStyle(&document()); | 964 m_insertionStyle->mergeTypingStyle(&document()); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1008 // We don't want any of the pasted content to end up nested in a Mail blockq
uote, so first break | 1027 // We don't want any of the pasted content to end up nested in a Mail blockq
uote, so first break |
1009 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl
e, in which case | 1028 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl
e, in which case |
1010 // breaking the blockquote will prevent the content from actually being inse
rted in the table. | 1029 // breaking the blockquote will prevent the content from actually being inse
rted in the table. |
1011 if (enclosingNodeOfType(insertionPos, isMailHTMLBlockquoteElement, CanCrossE
ditingBoundary) && m_preventNesting && !(enclosingNodeOfType(insertionPos, &isTa
bleStructureNode))) { | 1030 if (enclosingNodeOfType(insertionPos, isMailHTMLBlockquoteElement, CanCrossE
ditingBoundary) && m_preventNesting && !(enclosingNodeOfType(insertionPos, &isTa
bleStructureNode))) { |
1012 applyCommandToComposite(BreakBlockquoteCommand::create(document())); | 1031 applyCommandToComposite(BreakBlockquoteCommand::create(document())); |
1013 // This will leave a br between the split. | 1032 // This will leave a br between the split. |
1014 Node* br = endingSelection().start().anchorNode(); | 1033 Node* br = endingSelection().start().anchorNode(); |
1015 ASSERT(isHTMLBRElement(br)); | 1034 ASSERT(isHTMLBRElement(br)); |
1016 // Insert content between the two blockquotes, but remove the br (since
it was just a placeholder). | 1035 // Insert content between the two blockquotes, but remove the br (since
it was just a placeholder). |
1017 insertionPos = positionInParentBeforeNode(*br); | 1036 insertionPos = positionInParentBeforeNode(*br); |
1018 removeNode(br); | 1037 removeNode(br, editingState); |
| 1038 if (editingState->isAborted()) |
| 1039 return; |
1019 } | 1040 } |
1020 | 1041 |
1021 // Inserting content could cause whitespace to collapse, e.g. inserting <div
>foo</div> into hello^ world. | 1042 // Inserting content could cause whitespace to collapse, e.g. inserting <div
>foo</div> into hello^ world. |
1022 prepareWhitespaceAtPositionForSplit(insertionPos); | 1043 prepareWhitespaceAtPositionForSplit(insertionPos); |
1023 | 1044 |
1024 // If the downstream node has been removed there's no point in continuing. | 1045 // If the downstream node has been removed there's no point in continuing. |
1025 if (!mostForwardCaretPosition(insertionPos).anchorNode()) | 1046 if (!mostForwardCaretPosition(insertionPos).anchorNode()) |
1026 return; | 1047 return; |
1027 | 1048 |
1028 // NOTE: This would be an incorrect usage of downstream() if downstream() we
re changed to mean the last position after | 1049 // NOTE: This would be an incorrect usage of downstream() if downstream() we
re changed to mean the last position after |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1163 VisiblePosition startOfInsertedContent = createVisiblePosition(firstPosition
InOrBeforeNode(insertedNodes.firstNodeInserted())); | 1184 VisiblePosition startOfInsertedContent = createVisiblePosition(firstPosition
InOrBeforeNode(insertedNodes.firstNodeInserted())); |
1164 | 1185 |
1165 // We inserted before the enclosingBlockOfInsertionPos to prevent nesting, a
nd the content before the enclosingBlockOfInsertionPos wasn't in its own block a
nd | 1186 // We inserted before the enclosingBlockOfInsertionPos to prevent nesting, a
nd the content before the enclosingBlockOfInsertionPos wasn't in its own block a
nd |
1166 // didn't have a br after it, so the inserted content ended up in the same p
aragraph. | 1187 // didn't have a br after it, so the inserted content ended up in the same p
aragraph. |
1167 if (!startOfInsertedContent.isNull() && enclosingBlockOfInsertionPos && inse
rtionPos.anchorNode() == enclosingBlockOfInsertionPos->parentNode() && (unsigned
)insertionPos.computeEditingOffset() < enclosingBlockOfInsertionPos->nodeIndex()
&& !isStartOfParagraph(startOfInsertedContent)) | 1188 if (!startOfInsertedContent.isNull() && enclosingBlockOfInsertionPos && inse
rtionPos.anchorNode() == enclosingBlockOfInsertionPos->parentNode() && (unsigned
)insertionPos.computeEditingOffset() < enclosingBlockOfInsertionPos->nodeIndex()
&& !isStartOfParagraph(startOfInsertedContent)) |
1168 insertNodeAt(HTMLBRElement::create(document()).get(), startOfInsertedCon
tent.deepEquivalent()); | 1189 insertNodeAt(HTMLBRElement::create(document()).get(), startOfInsertedCon
tent.deepEquivalent()); |
1169 | 1190 |
1170 if (endBR && (plainTextFragment || (shouldRemoveEndBR(endBR, originalVisPosB
eforeEndBR) && !(fragment.hasInterchangeNewlineAtEnd() && selectionIsPlainText))
)) { | 1191 if (endBR && (plainTextFragment || (shouldRemoveEndBR(endBR, originalVisPosB
eforeEndBR) && !(fragment.hasInterchangeNewlineAtEnd() && selectionIsPlainText))
)) { |
1171 RefPtrWillBeRawPtr<ContainerNode> parent = endBR->parentNode(); | 1192 RefPtrWillBeRawPtr<ContainerNode> parent = endBR->parentNode(); |
1172 insertedNodes.willRemoveNode(*endBR); | 1193 insertedNodes.willRemoveNode(*endBR); |
1173 removeNode(endBR); | 1194 removeNode(endBR, editingState); |
| 1195 if (editingState->isAborted()) |
| 1196 return; |
1174 if (Node* nodeToRemove = highestNodeToRemoveInPruning(parent.get())) { | 1197 if (Node* nodeToRemove = highestNodeToRemoveInPruning(parent.get())) { |
1175 insertedNodes.willRemoveNode(*nodeToRemove); | 1198 insertedNodes.willRemoveNode(*nodeToRemove); |
1176 removeNode(nodeToRemove); | 1199 removeNode(nodeToRemove, editingState); |
| 1200 if (editingState->isAborted()) |
| 1201 return; |
1177 } | 1202 } |
1178 } | 1203 } |
1179 | 1204 |
1180 makeInsertedContentRoundTrippableWithHTMLTreeBuilder(insertedNodes); | 1205 makeInsertedContentRoundTrippableWithHTMLTreeBuilder(insertedNodes, editingS
tate); |
| 1206 if (editingState->isAborted()) |
| 1207 return; |
1181 | 1208 |
1182 removeRedundantStylesAndKeepStyleSpanInline(insertedNodes); | 1209 removeRedundantStylesAndKeepStyleSpanInline(insertedNodes); |
1183 | 1210 |
1184 if (m_sanitizeFragment) | 1211 if (m_sanitizeFragment) |
1185 applyCommandToComposite(SimplifyMarkupCommand::create(document(), insert
edNodes.firstNodeInserted(), insertedNodes.pastLastLeaf())); | 1212 applyCommandToComposite(SimplifyMarkupCommand::create(document(), insert
edNodes.firstNodeInserted(), insertedNodes.pastLastLeaf())); |
1186 | 1213 |
1187 // Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be
the last two lines of code that access insertedNodes. | 1214 // Setup m_startOfInsertedContent and m_endOfInsertedContent. This should be
the last two lines of code that access insertedNodes. |
1188 m_startOfInsertedContent = firstPositionInOrBeforeNode(insertedNodes.firstNo
deInserted()); | 1215 m_startOfInsertedContent = firstPositionInOrBeforeNode(insertedNodes.firstNo
deInserted()); |
1189 m_endOfInsertedContent = lastPositionInOrAfterNode(insertedNodes.lastLeafIns
erted()); | 1216 m_endOfInsertedContent = lastPositionInOrAfterNode(insertedNodes.lastLeafIns
erted()); |
1190 | 1217 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1261 removeElementAttribute(mailBlockquote, classAttr); | 1288 removeElementAttribute(mailBlockquote, classAttr); |
1262 | 1289 |
1263 if (shouldPerformSmartReplace()) | 1290 if (shouldPerformSmartReplace()) |
1264 addSpacesForSmartReplace(); | 1291 addSpacesForSmartReplace(); |
1265 | 1292 |
1266 // If we are dealing with a fragment created from plain text | 1293 // If we are dealing with a fragment created from plain text |
1267 // no style matching is necessary. | 1294 // no style matching is necessary. |
1268 if (plainTextFragment) | 1295 if (plainTextFragment) |
1269 m_matchStyle = false; | 1296 m_matchStyle = false; |
1270 | 1297 |
1271 completeHTMLReplacement(lastPositionToSelect); | 1298 completeHTMLReplacement(lastPositionToSelect, editingState); |
1272 } | 1299 } |
1273 | 1300 |
1274 bool ReplaceSelectionCommand::shouldRemoveEndBR(HTMLBRElement* endBR, const Visi
blePosition& originalVisPosBeforeEndBR) | 1301 bool ReplaceSelectionCommand::shouldRemoveEndBR(HTMLBRElement* endBR, const Visi
blePosition& originalVisPosBeforeEndBR) |
1275 { | 1302 { |
1276 if (!endBR || !endBR->inDocument()) | 1303 if (!endBR || !endBR->inDocument()) |
1277 return false; | 1304 return false; |
1278 | 1305 |
1279 VisiblePosition visiblePos = createVisiblePosition(positionBeforeNode(endBR)
); | 1306 VisiblePosition visiblePos = createVisiblePosition(positionBeforeNode(endBR)
); |
1280 | 1307 |
1281 // Don't remove the br if nothing was inserted. | 1308 // Don't remove the br if nothing was inserted. |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1355 } else { | 1382 } else { |
1356 RefPtrWillBeRawPtr<Text> node = document().createEditingTextNode(col
lapseWhiteSpace ? nonBreakingSpaceString() : " "); | 1383 RefPtrWillBeRawPtr<Text> node = document().createEditingTextNode(col
lapseWhiteSpace ? nonBreakingSpaceString() : " "); |
1357 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont
ent to be the node containing the leading space, | 1384 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont
ent to be the node containing the leading space, |
1358 // but m_endOfInsertedContent is supposed to mark the end of pasted
content. | 1385 // but m_endOfInsertedContent is supposed to mark the end of pasted
content. |
1359 insertNodeBefore(node, startNode); | 1386 insertNodeBefore(node, startNode); |
1360 m_startOfInsertedContent = firstPositionInNode(node.get()); | 1387 m_startOfInsertedContent = firstPositionInNode(node.get()); |
1361 } | 1388 } |
1362 } | 1389 } |
1363 } | 1390 } |
1364 | 1391 |
1365 void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositi
onToSelect) | 1392 void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositi
onToSelect, EditingState* editingState) |
1366 { | 1393 { |
1367 Position start = positionAtStartOfInsertedContent().deepEquivalent(); | 1394 Position start = positionAtStartOfInsertedContent().deepEquivalent(); |
1368 Position end = positionAtEndOfInsertedContent().deepEquivalent(); | 1395 Position end = positionAtEndOfInsertedContent().deepEquivalent(); |
1369 | 1396 |
1370 // Mutation events may have deleted start or end | 1397 // Mutation events may have deleted start or end |
1371 if (start.isNotNull() && !start.isOrphan() && end.isNotNull() && !end.isOrph
an()) { | 1398 if (start.isNotNull() && !start.isOrphan() && end.isNotNull() && !end.isOrph
an()) { |
1372 // FIXME (11475): Remove this and require that the creator of the fragme
nt to use nbsps. | 1399 // FIXME (11475): Remove this and require that the creator of the fragme
nt to use nbsps. |
1373 rebalanceWhitespaceAt(start); | 1400 rebalanceWhitespaceAt(start); |
1374 rebalanceWhitespaceAt(end); | 1401 rebalanceWhitespaceAt(end); |
1375 | 1402 |
1376 if (m_matchStyle) { | 1403 if (m_matchStyle) { |
1377 ASSERT(m_insertionStyle); | 1404 ASSERT(m_insertionStyle); |
1378 applyStyle(m_insertionStyle.get(), start, end); | 1405 applyStyle(m_insertionStyle.get(), start, end); |
1379 } | 1406 } |
1380 | 1407 |
1381 if (lastPositionToSelect.isNotNull()) | 1408 if (lastPositionToSelect.isNotNull()) |
1382 end = lastPositionToSelect; | 1409 end = lastPositionToSelect; |
1383 | 1410 |
1384 mergeTextNodesAroundPosition(start, end); | 1411 mergeTextNodesAroundPosition(start, end, editingState); |
| 1412 if (editingState->isAborted()) |
| 1413 return; |
1385 } else if (lastPositionToSelect.isNotNull()) { | 1414 } else if (lastPositionToSelect.isNotNull()) { |
1386 start = end = lastPositionToSelect; | 1415 start = end = lastPositionToSelect; |
1387 } else { | 1416 } else { |
1388 return; | 1417 return; |
1389 } | 1418 } |
1390 | 1419 |
1391 m_startOfInsertedRange = start; | 1420 m_startOfInsertedRange = start; |
1392 m_endOfInsertedRange = end; | 1421 m_endOfInsertedRange = end; |
1393 | 1422 |
1394 if (m_selectReplacement) | 1423 if (m_selectReplacement) |
1395 setEndingSelection(VisibleSelection(start, end, SelDefaultAffinity, endi
ngSelection().isDirectional())); | 1424 setEndingSelection(VisibleSelection(start, end, SelDefaultAffinity, endi
ngSelection().isDirectional())); |
1396 else | 1425 else |
1397 setEndingSelection(VisibleSelection(end, SelDefaultAffinity, endingSelec
tion().isDirectional())); | 1426 setEndingSelection(VisibleSelection(end, SelDefaultAffinity, endingSelec
tion().isDirectional())); |
1398 } | 1427 } |
1399 | 1428 |
1400 void ReplaceSelectionCommand::mergeTextNodesAroundPosition(Position& position, P
osition& positionOnlyToBeUpdated) | 1429 void ReplaceSelectionCommand::mergeTextNodesAroundPosition(Position& position, P
osition& positionOnlyToBeUpdated, EditingState* editingState) |
1401 { | 1430 { |
1402 bool positionIsOffsetInAnchor = position.isOffsetInAnchor(); | 1431 bool positionIsOffsetInAnchor = position.isOffsetInAnchor(); |
1403 bool positionOnlyToBeUpdatedIsOffsetInAnchor = positionOnlyToBeUpdated.isOff
setInAnchor(); | 1432 bool positionOnlyToBeUpdatedIsOffsetInAnchor = positionOnlyToBeUpdated.isOff
setInAnchor(); |
1404 RefPtrWillBeRawPtr<Text> text = nullptr; | 1433 RefPtrWillBeRawPtr<Text> text = nullptr; |
1405 if (positionIsOffsetInAnchor && position.computeContainerNode() && position.
computeContainerNode()->isTextNode()) { | 1434 if (positionIsOffsetInAnchor && position.computeContainerNode() && position.
computeContainerNode()->isTextNode()) { |
1406 text = toText(position.computeContainerNode()); | 1435 text = toText(position.computeContainerNode()); |
1407 } else { | 1436 } else { |
1408 Node* before = position.computeNodeBeforePosition(); | 1437 Node* before = position.computeNodeBeforePosition(); |
1409 if (before && before->isTextNode()) { | 1438 if (before && before->isTextNode()) { |
1410 text = toText(before); | 1439 text = toText(before); |
(...skipping 17 matching lines...) Expand all Loading... |
1428 | 1457 |
1429 if (positionOnlyToBeUpdatedIsOffsetInAnchor) { | 1458 if (positionOnlyToBeUpdatedIsOffsetInAnchor) { |
1430 if (positionOnlyToBeUpdated.computeContainerNode() == text) | 1459 if (positionOnlyToBeUpdated.computeContainerNode() == text) |
1431 positionOnlyToBeUpdated = Position(text, previous->length() + po
sitionOnlyToBeUpdated.offsetInContainerNode()); | 1460 positionOnlyToBeUpdated = Position(text, previous->length() + po
sitionOnlyToBeUpdated.offsetInContainerNode()); |
1432 else if (positionOnlyToBeUpdated.computeContainerNode() == previous) | 1461 else if (positionOnlyToBeUpdated.computeContainerNode() == previous) |
1433 positionOnlyToBeUpdated = Position(text, positionOnlyToBeUpdated
.offsetInContainerNode()); | 1462 positionOnlyToBeUpdated = Position(text, positionOnlyToBeUpdated
.offsetInContainerNode()); |
1434 } else { | 1463 } else { |
1435 updatePositionForNodeRemoval(positionOnlyToBeUpdated, *previous); | 1464 updatePositionForNodeRemoval(positionOnlyToBeUpdated, *previous); |
1436 } | 1465 } |
1437 | 1466 |
1438 removeNode(previous); | 1467 removeNode(previous, editingState); |
| 1468 if (editingState->isAborted()) |
| 1469 return; |
1439 } | 1470 } |
1440 if (text->nextSibling() && text->nextSibling()->isTextNode()) { | 1471 if (text->nextSibling() && text->nextSibling()->isTextNode()) { |
1441 RefPtrWillBeRawPtr<Text> next = toText(text->nextSibling()); | 1472 RefPtrWillBeRawPtr<Text> next = toText(text->nextSibling()); |
1442 unsigned originalLength = text->length(); | 1473 unsigned originalLength = text->length(); |
1443 insertTextIntoNode(text, originalLength, next->data()); | 1474 insertTextIntoNode(text, originalLength, next->data()); |
1444 | 1475 |
1445 if (!positionIsOffsetInAnchor) | 1476 if (!positionIsOffsetInAnchor) |
1446 updatePositionForNodeRemoval(position, *next); | 1477 updatePositionForNodeRemoval(position, *next); |
1447 | 1478 |
1448 if (positionOnlyToBeUpdatedIsOffsetInAnchor && positionOnlyToBeUpdated.c
omputeContainerNode() == next) | 1479 if (positionOnlyToBeUpdatedIsOffsetInAnchor && positionOnlyToBeUpdated.c
omputeContainerNode() == next) |
1449 positionOnlyToBeUpdated = Position(text, originalLength + positionOn
lyToBeUpdated.offsetInContainerNode()); | 1480 positionOnlyToBeUpdated = Position(text, originalLength + positionOn
lyToBeUpdated.offsetInContainerNode()); |
1450 else | 1481 else |
1451 updatePositionForNodeRemoval(positionOnlyToBeUpdated, *next); | 1482 updatePositionForNodeRemoval(positionOnlyToBeUpdated, *next); |
1452 | 1483 |
1453 removeNode(next); | 1484 removeNode(next, editingState); |
| 1485 if (editingState->isAborted()) |
| 1486 return; |
1454 } | 1487 } |
1455 } | 1488 } |
1456 | 1489 |
1457 EditAction ReplaceSelectionCommand::editingAction() const | 1490 EditAction ReplaceSelectionCommand::editingAction() const |
1458 { | 1491 { |
1459 return m_editAction; | 1492 return m_editAction; |
1460 } | 1493 } |
1461 | 1494 |
1462 // If the user is inserting a list into an existing list, instead of nesting the
list, | 1495 // If the user is inserting a list into an existing list, instead of nesting the
list, |
1463 // we put the list items into the existing list. | 1496 // we put the list items into the existing list. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1510 if (m_startOfInsertedContent.isNull()) | 1543 if (m_startOfInsertedContent.isNull()) |
1511 m_startOfInsertedContent = firstPositionInOrBeforeNode(node); | 1544 m_startOfInsertedContent = firstPositionInOrBeforeNode(node); |
1512 | 1545 |
1513 m_endOfInsertedContent = lastPositionInOrAfterNode(&NodeTraversal::lastWithi
nOrSelf(*node)); | 1546 m_endOfInsertedContent = lastPositionInOrAfterNode(&NodeTraversal::lastWithi
nOrSelf(*node)); |
1514 } | 1547 } |
1515 | 1548 |
1516 // During simple pastes, where we're just pasting a text node into a run of text
, we insert the text node | 1549 // During simple pastes, where we're just pasting a text node into a run of text
, we insert the text node |
1517 // directly into the text node that holds the selection. This is much faster th
an the generalized code in | 1550 // directly into the text node that holds the selection. This is much faster th
an the generalized code in |
1518 // ReplaceSelectionCommand, and works around <https://bugs.webkit.org/show_bug.c
gi?id=6148> since we don't | 1551 // ReplaceSelectionCommand, and works around <https://bugs.webkit.org/show_bug.c
gi?id=6148> since we don't |
1519 // split text nodes. | 1552 // split text nodes. |
1520 bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f
ragment) | 1553 bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f
ragment, EditingState* editingState) |
1521 { | 1554 { |
1522 if (!fragment.firstChild() || fragment.firstChild() != fragment.lastChild()
|| !fragment.firstChild()->isTextNode()) | 1555 if (!fragment.firstChild() || fragment.firstChild() != fragment.lastChild()
|| !fragment.firstChild()->isTextNode()) |
1523 return false; | 1556 return false; |
1524 | 1557 |
1525 // FIXME: Would be nice to handle smart replace in the fast path. | 1558 // FIXME: Would be nice to handle smart replace in the fast path. |
1526 if (m_smartReplace || fragment.hasInterchangeNewlineAtStart() || fragment.ha
sInterchangeNewlineAtEnd()) | 1559 if (m_smartReplace || fragment.hasInterchangeNewlineAtStart() || fragment.ha
sInterchangeNewlineAtEnd()) |
1527 return false; | 1560 return false; |
1528 | 1561 |
1529 // e.g. when "bar" is inserted after "foo" in <div><u>foo</u></div>, "bar" s
hould not be underlined. | 1562 // e.g. when "bar" is inserted after "foo" in <div><u>foo</u></div>, "bar" s
hould not be underlined. |
1530 if (elementToSplitToAvoidPastingIntoInlineElementsWithStyle(endingSelection(
).start())) | 1563 if (elementToSplitToAvoidPastingIntoInlineElementsWithStyle(endingSelection(
).start())) |
1531 return false; | 1564 return false; |
1532 | 1565 |
1533 RefPtrWillBeRawPtr<Node> nodeAfterInsertionPos = mostForwardCaretPosition(en
dingSelection().end()).anchorNode(); | 1566 RefPtrWillBeRawPtr<Node> nodeAfterInsertionPos = mostForwardCaretPosition(en
dingSelection().end()).anchorNode(); |
1534 Text* textNode = toText(fragment.firstChild()); | 1567 Text* textNode = toText(fragment.firstChild()); |
1535 // Our fragment creation code handles tabs, spaces, and newlines, so we don'
t have to worry about those here. | 1568 // Our fragment creation code handles tabs, spaces, and newlines, so we don'
t have to worry about those here. |
1536 | 1569 |
1537 Position start = endingSelection().start(); | 1570 Position start = endingSelection().start(); |
1538 Position end = replaceSelectedTextInNode(textNode->data()); | 1571 Position end = replaceSelectedTextInNode(textNode->data()); |
1539 if (end.isNull()) | 1572 if (end.isNull()) |
1540 return false; | 1573 return false; |
1541 | 1574 |
1542 if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() && isHTMLBR
Element(*nodeAfterInsertionPos) | 1575 if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() && isHTMLBR
Element(*nodeAfterInsertionPos) |
1543 && shouldRemoveEndBR(toHTMLBRElement(nodeAfterInsertionPos.get()), creat
eVisiblePosition(positionBeforeNode(nodeAfterInsertionPos.get())))) | 1576 && shouldRemoveEndBR(toHTMLBRElement(nodeAfterInsertionPos.get()), creat
eVisiblePosition(positionBeforeNode(nodeAfterInsertionPos.get())))) { |
1544 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get()); | 1577 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get(), editingState); |
| 1578 if (editingState->isAborted()) |
| 1579 return false; |
| 1580 } |
1545 | 1581 |
1546 m_startOfInsertedRange = start; | 1582 m_startOfInsertedRange = start; |
1547 m_endOfInsertedRange = end; | 1583 m_endOfInsertedRange = end; |
1548 | 1584 |
1549 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en
d); | 1585 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en
d); |
1550 | 1586 |
1551 setEndingSelection(selectionAfterReplace); | 1587 setEndingSelection(selectionAfterReplace); |
1552 | 1588 |
1553 return true; | 1589 return true; |
1554 } | 1590 } |
(...skipping 13 matching lines...) Expand all Loading... |
1568 visitor->trace(m_startOfInsertedContent); | 1604 visitor->trace(m_startOfInsertedContent); |
1569 visitor->trace(m_endOfInsertedContent); | 1605 visitor->trace(m_endOfInsertedContent); |
1570 visitor->trace(m_insertionStyle); | 1606 visitor->trace(m_insertionStyle); |
1571 visitor->trace(m_documentFragment); | 1607 visitor->trace(m_documentFragment); |
1572 visitor->trace(m_startOfInsertedRange); | 1608 visitor->trace(m_startOfInsertedRange); |
1573 visitor->trace(m_endOfInsertedRange); | 1609 visitor->trace(m_endOfInsertedRange); |
1574 CompositeEditCommand::trace(visitor); | 1610 CompositeEditCommand::trace(visitor); |
1575 } | 1611 } |
1576 | 1612 |
1577 } // namespace blink | 1613 } // namespace blink |
OLD | NEW |