| 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 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 } | 352 } |
| 353 | 353 |
| 354 inline void ReplaceSelectionCommand::InsertedNodes::didReplaceNode(Node* node, N
ode* newNode) | 354 inline void ReplaceSelectionCommand::InsertedNodes::didReplaceNode(Node* node, N
ode* newNode) |
| 355 { | 355 { |
| 356 if (m_firstNodeInserted == node) | 356 if (m_firstNodeInserted == node) |
| 357 m_firstNodeInserted = newNode; | 357 m_firstNodeInserted = newNode; |
| 358 if (m_lastNodeInserted == node) | 358 if (m_lastNodeInserted == node) |
| 359 m_lastNodeInserted = newNode; | 359 m_lastNodeInserted = newNode; |
| 360 } | 360 } |
| 361 | 361 |
| 362 ReplaceSelectionCommand::ReplaceSelectionCommand(Document* document, PassRefPtr<
DocumentFragment> fragment, CommandOptions options, EditAction editAction) | 362 ReplaceSelectionCommand::ReplaceSelectionCommand(Document& document, PassRefPtr<
DocumentFragment> fragment, CommandOptions options, EditAction editAction) |
| 363 : CompositeEditCommand(document) | 363 : CompositeEditCommand(document) |
| 364 , m_selectReplacement(options & SelectReplacement) | 364 , m_selectReplacement(options & SelectReplacement) |
| 365 , m_smartReplace(options & SmartReplace) | 365 , m_smartReplace(options & SmartReplace) |
| 366 , m_matchStyle(options & MatchStyle) | 366 , m_matchStyle(options & MatchStyle) |
| 367 , m_documentFragment(fragment) | 367 , m_documentFragment(fragment) |
| 368 , m_preventNesting(options & PreventNesting) | 368 , m_preventNesting(options & PreventNesting) |
| 369 , m_movingParagraph(options & MovingParagraph) | 369 , m_movingParagraph(options & MovingParagraph) |
| 370 , m_editAction(editAction) | 370 , m_editAction(editAction) |
| 371 , m_sanitizeFragment(options & SanitizeFragment) | 371 , m_sanitizeFragment(options & SanitizeFragment) |
| 372 , m_shouldMergeEnd(false) | 372 , m_shouldMergeEnd(false) |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 removeNodeAttribute(element, attributes[i]); | 495 removeNodeAttribute(element, attributes[i]); |
| 496 } | 496 } |
| 497 } | 497 } |
| 498 | 498 |
| 499 ContainerNode* context = element->parentNode(); | 499 ContainerNode* context = element->parentNode(); |
| 500 | 500 |
| 501 // If Mail wraps the fragment with a Paste as Quotation blockquote,
or if you're pasting into a quoted region, | 501 // If Mail wraps the fragment with a Paste as Quotation blockquote,
or if you're pasting into a quoted region, |
| 502 // styles from blockquoteNode are allowed to override those from the
source document, see <rdar://problem/4930986> and <rdar://problem/5089327>. | 502 // styles from blockquoteNode are allowed to override those from the
source document, see <rdar://problem/4930986> and <rdar://problem/5089327>. |
| 503 Node* blockquoteNode = !context || isMailPasteAsQuotationNode(contex
t) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailBlockquot
e, CanCrossEditingBoundary); | 503 Node* blockquoteNode = !context || isMailPasteAsQuotationNode(contex
t) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailBlockquot
e, CanCrossEditingBoundary); |
| 504 if (blockquoteNode) | 504 if (blockquoteNode) |
| 505 newInlineStyle->removeStyleFromRulesAndContext(element, document
()->documentElement()); | 505 newInlineStyle->removeStyleFromRulesAndContext(element, document
().documentElement()); |
| 506 | 506 |
| 507 newInlineStyle->removeStyleFromRulesAndContext(element, context); | 507 newInlineStyle->removeStyleFromRulesAndContext(element, context); |
| 508 } | 508 } |
| 509 | 509 |
| 510 if (!inlineStyle || newInlineStyle->isEmpty()) { | 510 if (!inlineStyle || newInlineStyle->isEmpty()) { |
| 511 if (isStyleSpanOrSpanWithOnlyStyleAttribute(element) || isEmptyFontT
ag(element, AllowNonEmptyStyleAttribute)) { | 511 if (isStyleSpanOrSpanWithOnlyStyleAttribute(element) || isEmptyFontT
ag(element, AllowNonEmptyStyleAttribute)) { |
| 512 insertedNodes.willRemoveNodePreservingChildren(element); | 512 insertedNodes.willRemoveNodePreservingChildren(element); |
| 513 removeNodePreservingChildren(element); | 513 removeNodePreservingChildren(element); |
| 514 continue; | 514 continue; |
| 515 } | 515 } |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 removeNode(ancestor.release()); | 657 removeNode(ancestor.release()); |
| 658 } | 658 } |
| 659 | 659 |
| 660 static inline bool nodeHasVisibleRenderText(Text* text) | 660 static inline bool nodeHasVisibleRenderText(Text* text) |
| 661 { | 661 { |
| 662 return text->renderer() && toRenderText(text->renderer())->renderedTextLengt
h() > 0; | 662 return text->renderer() && toRenderText(text->renderer())->renderedTextLengt
h() > 0; |
| 663 } | 663 } |
| 664 | 664 |
| 665 void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds(InsertedNodes& ins
ertedNodes) | 665 void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds(InsertedNodes& ins
ertedNodes) |
| 666 { | 666 { |
| 667 document()->updateLayoutIgnorePendingStylesheets(); | 667 document().updateLayoutIgnorePendingStylesheets(); |
| 668 | 668 |
| 669 Node* lastLeafInserted = insertedNodes.lastLeafInserted(); | 669 Node* lastLeafInserted = insertedNodes.lastLeafInserted(); |
| 670 if (lastLeafInserted && lastLeafInserted->isTextNode() && !nodeHasVisibleRen
derText(toText(lastLeafInserted)) | 670 if (lastLeafInserted && lastLeafInserted->isTextNode() && !nodeHasVisibleRen
derText(toText(lastLeafInserted)) |
| 671 && !enclosingNodeWithTag(firstPositionInOrBeforeNode(lastLeafInserted),
selectTag) | 671 && !enclosingNodeWithTag(firstPositionInOrBeforeNode(lastLeafInserted),
selectTag) |
| 672 && !enclosingNodeWithTag(firstPositionInOrBeforeNode(lastLeafInserted),
scriptTag)) { | 672 && !enclosingNodeWithTag(firstPositionInOrBeforeNode(lastLeafInserted),
scriptTag)) { |
| 673 insertedNodes.willRemoveNode(lastLeafInserted); | 673 insertedNodes.willRemoveNode(lastLeafInserted); |
| 674 removeNode(lastLeafInserted); | 674 removeNode(lastLeafInserted); |
| 675 } | 675 } |
| 676 | 676 |
| 677 // We don't have to make sure that firstNodeInserted isn't inside a select o
r script element, because | 677 // We don't have to make sure that firstNodeInserted isn't inside a select o
r script element, because |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 766 if (!wrappingStyleSpan) | 766 if (!wrappingStyleSpan) |
| 767 return; | 767 return; |
| 768 | 768 |
| 769 RefPtr<EditingStyle> style = EditingStyle::create(wrappingStyleSpan->inlineS
tyle()); | 769 RefPtr<EditingStyle> style = EditingStyle::create(wrappingStyleSpan->inlineS
tyle()); |
| 770 ContainerNode* context = wrappingStyleSpan->parentNode(); | 770 ContainerNode* context = wrappingStyleSpan->parentNode(); |
| 771 | 771 |
| 772 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if yo
u're pasting into a quoted region, | 772 // If Mail wraps the fragment with a Paste as Quotation blockquote, or if yo
u're pasting into a quoted region, |
| 773 // styles from blockquoteNode are allowed to override those from the source
document, see <rdar://problem/4930986> and <rdar://problem/5089327>. | 773 // styles from blockquoteNode are allowed to override those from the source
document, see <rdar://problem/4930986> and <rdar://problem/5089327>. |
| 774 Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : enclo
singNodeOfType(firstPositionInNode(context), isMailBlockquote, CanCrossEditingBo
undary); | 774 Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : enclo
singNodeOfType(firstPositionInNode(context), isMailBlockquote, CanCrossEditingBo
undary); |
| 775 if (blockquoteNode) | 775 if (blockquoteNode) |
| 776 context = document()->documentElement(); | 776 context = document().documentElement(); |
| 777 | 777 |
| 778 // This operation requires that only editing styles to be removed from sourc
eDocumentStyle. | 778 // This operation requires that only editing styles to be removed from sourc
eDocumentStyle. |
| 779 style->prepareToApplyAt(firstPositionInNode(context)); | 779 style->prepareToApplyAt(firstPositionInNode(context)); |
| 780 | 780 |
| 781 // Remove block properties in the span's style. This prevents properties tha
t probably have no effect | 781 // Remove block properties in the span's style. This prevents properties tha
t probably have no effect |
| 782 // currently from affecting blocks later if the style is cloned for a new bl
ock element during a future | 782 // currently from affecting blocks later if the style is cloned for a new bl
ock element during a future |
| 783 // editing operation. | 783 // editing operation. |
| 784 // FIXME: They *can* have an effect currently if blocks beneath the style sp
an aren't individually marked | 784 // FIXME: They *can* have an effect currently if blocks beneath the style sp
an aren't individually marked |
| 785 // with block styles by the editing engine used to style them. WebKit doesn
't do this, but others might. | 785 // with block styles by the editing engine used to style them. WebKit doesn
't do this, but others might. |
| 786 style->removeBlockProperties(); | 786 style->removeBlockProperties(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 811 // include the what was the start of the selection that was pasted into, so
that we preserve that paragraph's | 811 // include the what was the start of the selection that was pasted into, so
that we preserve that paragraph's |
| 812 // block styles. | 812 // block styles. |
| 813 bool mergeForward = !(inSameParagraph(startOfInsertedContent, endOfInsertedC
ontent) && !isStartOfParagraph(startOfInsertedContent)); | 813 bool mergeForward = !(inSameParagraph(startOfInsertedContent, endOfInsertedC
ontent) && !isStartOfParagraph(startOfInsertedContent)); |
| 814 | 814 |
| 815 VisiblePosition destination = mergeForward ? endOfInsertedContent.next() : e
ndOfInsertedContent; | 815 VisiblePosition destination = mergeForward ? endOfInsertedContent.next() : e
ndOfInsertedContent; |
| 816 VisiblePosition startOfParagraphToMove = mergeForward ? startOfParagraph(end
OfInsertedContent) : endOfInsertedContent.next(); | 816 VisiblePosition startOfParagraphToMove = mergeForward ? startOfParagraph(end
OfInsertedContent) : endOfInsertedContent.next(); |
| 817 | 817 |
| 818 // Merging forward could result in deleting the destination anchor node. | 818 // Merging forward could result in deleting the destination anchor node. |
| 819 // To avoid this, we add a placeholder node before the start of the paragrap
h. | 819 // To avoid this, we add a placeholder node before the start of the paragrap
h. |
| 820 if (endOfParagraph(startOfParagraphToMove) == destination) { | 820 if (endOfParagraph(startOfParagraphToMove) == destination) { |
| 821 RefPtr<Node> placeholder = createBreakElement(document()); | 821 RefPtr<Node> placeholder = createBreakElement(&document()); |
| 822 insertNodeBefore(placeholder, startOfParagraphToMove.deepEquivalent().de
precatedNode()); | 822 insertNodeBefore(placeholder, startOfParagraphToMove.deepEquivalent().de
precatedNode()); |
| 823 destination = VisiblePosition(positionBeforeNode(placeholder.get())); | 823 destination = VisiblePosition(positionBeforeNode(placeholder.get())); |
| 824 } | 824 } |
| 825 | 825 |
| 826 moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove)
, destination); | 826 moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove)
, destination); |
| 827 | 827 |
| 828 // Merging forward will remove m_endOfInsertedContent from the document. | 828 // Merging forward will remove m_endOfInsertedContent from the document. |
| 829 if (mergeForward) { | 829 if (mergeForward) { |
| 830 if (m_startOfInsertedContent.isOrphan()) | 830 if (m_startOfInsertedContent.isOrphan()) |
| 831 m_startOfInsertedContent = endingSelection().visibleStart().deepEqui
valent(); | 831 m_startOfInsertedContent = endingSelection().visibleStart().deepEqui
valent(); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 882 { | 882 { |
| 883 VisibleSelection selection = endingSelection(); | 883 VisibleSelection selection = endingSelection(); |
| 884 ASSERT(selection.isCaretOrRange()); | 884 ASSERT(selection.isCaretOrRange()); |
| 885 ASSERT(selection.start().deprecatedNode()); | 885 ASSERT(selection.start().deprecatedNode()); |
| 886 if (!selection.isNonOrphanedCaretOrRange() || !selection.start().deprecatedN
ode()) | 886 if (!selection.isNonOrphanedCaretOrRange() || !selection.start().deprecatedN
ode()) |
| 887 return; | 887 return; |
| 888 | 888 |
| 889 if (!selection.rootEditableElement()) | 889 if (!selection.rootEditableElement()) |
| 890 return; | 890 return; |
| 891 | 891 |
| 892 ReplacementFragment fragment(document(), m_documentFragment.get(), selection
); | 892 ReplacementFragment fragment(&document(), m_documentFragment.get(), selectio
n); |
| 893 if (performTrivialReplace(fragment)) | 893 if (performTrivialReplace(fragment)) |
| 894 return; | 894 return; |
| 895 | 895 |
| 896 // We can skip matching the style if the selection is plain text. | 896 // We can skip matching the style if the selection is plain text. |
| 897 if ((selection.start().deprecatedNode()->renderer() && selection.start().dep
recatedNode()->renderer()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY) | 897 if ((selection.start().deprecatedNode()->renderer() && selection.start().dep
recatedNode()->renderer()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY) |
| 898 && (selection.end().deprecatedNode()->renderer() && selection.end().depr
ecatedNode()->renderer()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY)) | 898 && (selection.end().deprecatedNode()->renderer() && selection.end().depr
ecatedNode()->renderer()->style()->userModify() == READ_WRITE_PLAINTEXT_ONLY)) |
| 899 m_matchStyle = false; | 899 m_matchStyle = false; |
| 900 | 900 |
| 901 if (m_matchStyle) { | 901 if (m_matchStyle) { |
| 902 m_insertionStyle = EditingStyle::create(selection.start()); | 902 m_insertionStyle = EditingStyle::create(selection.start()); |
| 903 m_insertionStyle->mergeTypingStyle(document()); | 903 m_insertionStyle->mergeTypingStyle(&document()); |
| 904 } | 904 } |
| 905 | 905 |
| 906 VisiblePosition visibleStart = selection.visibleStart(); | 906 VisiblePosition visibleStart = selection.visibleStart(); |
| 907 VisiblePosition visibleEnd = selection.visibleEnd(); | 907 VisiblePosition visibleEnd = selection.visibleEnd(); |
| 908 | 908 |
| 909 bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd); | 909 bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd); |
| 910 bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart); | 910 bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart); |
| 911 | 911 |
| 912 Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().deprecatedNo
de()); | 912 Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().deprecatedNo
de()); |
| 913 | 913 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1002 insertionPos = positionInParentAfterNode(startBlock); | 1002 insertionPos = positionInParentAfterNode(startBlock); |
| 1003 else if (isStartOfBlock(visibleInsertionPos)) | 1003 else if (isStartOfBlock(visibleInsertionPos)) |
| 1004 insertionPos = positionInParentBeforeNode(startBlock); | 1004 insertionPos = positionInParentBeforeNode(startBlock); |
| 1005 } | 1005 } |
| 1006 | 1006 |
| 1007 // Paste at start or end of link goes outside of link. | 1007 // Paste at start or end of link goes outside of link. |
| 1008 insertionPos = positionAvoidingSpecialElementBoundary(insertionPos); | 1008 insertionPos = positionAvoidingSpecialElementBoundary(insertionPos); |
| 1009 | 1009 |
| 1010 // FIXME: Can this wait until after the operation has been performed? There
doesn't seem to be | 1010 // FIXME: Can this wait until after the operation has been performed? There
doesn't seem to be |
| 1011 // any work performed after this that queries or uses the typing style. | 1011 // any work performed after this that queries or uses the typing style. |
| 1012 if (Frame* frame = document()->frame()) | 1012 if (Frame* frame = document().frame()) |
| 1013 frame->selection()->clearTypingStyle(); | 1013 frame->selection()->clearTypingStyle(); |
| 1014 | 1014 |
| 1015 removeHeadContents(fragment); | 1015 removeHeadContents(fragment); |
| 1016 | 1016 |
| 1017 // We don't want the destination to end up inside nodes that weren't selecte
d. To avoid that, we move the | 1017 // We don't want the destination to end up inside nodes that weren't selecte
d. To avoid that, we move the |
| 1018 // position forward without changing the visible position so we're still at
the same visible location, but | 1018 // position forward without changing the visible position so we're still at
the same visible location, but |
| 1019 // outside of preceding tags. | 1019 // outside of preceding tags. |
| 1020 insertionPos = positionAvoidingPrecedingNodes(insertionPos); | 1020 insertionPos = positionAvoidingPrecedingNodes(insertionPos); |
| 1021 | 1021 |
| 1022 // Paste into run of tabs splits the tab span. | 1022 // Paste into run of tabs splits the tab span. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1108 | 1108 |
| 1109 // Mutation events (bug 20161) may have already removed the inserted content | 1109 // Mutation events (bug 20161) may have already removed the inserted content |
| 1110 if (!insertedNodes.firstNodeInserted() || !insertedNodes.firstNodeInserted()
->inDocument()) | 1110 if (!insertedNodes.firstNodeInserted() || !insertedNodes.firstNodeInserted()
->inDocument()) |
| 1111 return; | 1111 return; |
| 1112 | 1112 |
| 1113 VisiblePosition startOfInsertedContent = firstPositionInOrBeforeNode(inserte
dNodes.firstNodeInserted()); | 1113 VisiblePosition startOfInsertedContent = firstPositionInOrBeforeNode(inserte
dNodes.firstNodeInserted()); |
| 1114 | 1114 |
| 1115 // We inserted before the startBlock to prevent nesting, and the content bef
ore the startBlock wasn't in its own block and | 1115 // We inserted before the startBlock to prevent nesting, and the content bef
ore the startBlock wasn't in its own block and |
| 1116 // didn't have a br after it, so the inserted content ended up in the same p
aragraph. | 1116 // didn't have a br after it, so the inserted content ended up in the same p
aragraph. |
| 1117 if (startBlock && insertionPos.deprecatedNode() == startBlock->parentNode()
&& (unsigned)insertionPos.deprecatedEditingOffset() < startBlock->nodeIndex() &&
!isStartOfParagraph(startOfInsertedContent)) | 1117 if (startBlock && insertionPos.deprecatedNode() == startBlock->parentNode()
&& (unsigned)insertionPos.deprecatedEditingOffset() < startBlock->nodeIndex() &&
!isStartOfParagraph(startOfInsertedContent)) |
| 1118 insertNodeAt(createBreakElement(document()).get(), startOfInsertedConten
t.deepEquivalent()); | 1118 insertNodeAt(createBreakElement(&document()).get(), startOfInsertedConte
nt.deepEquivalent()); |
| 1119 | 1119 |
| 1120 if (endBR && (plainTextFragment || shouldRemoveEndBR(endBR, originalVisPosBe
foreEndBR))) { | 1120 if (endBR && (plainTextFragment || shouldRemoveEndBR(endBR, originalVisPosBe
foreEndBR))) { |
| 1121 RefPtr<Node> parent = endBR->parentNode(); | 1121 RefPtr<Node> parent = endBR->parentNode(); |
| 1122 insertedNodes.willRemoveNode(endBR); | 1122 insertedNodes.willRemoveNode(endBR); |
| 1123 removeNode(endBR); | 1123 removeNode(endBR); |
| 1124 if (Node* nodeToRemove = highestNodeToRemoveInPruning(parent.get())) { | 1124 if (Node* nodeToRemove = highestNodeToRemoveInPruning(parent.get())) { |
| 1125 insertedNodes.willRemoveNode(nodeToRemove); | 1125 insertedNodes.willRemoveNode(nodeToRemove); |
| 1126 removeNode(nodeToRemove); | 1126 removeNode(nodeToRemove); |
| 1127 } | 1127 } |
| 1128 } | 1128 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1143 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph); | 1143 m_shouldMergeEnd = shouldMergeEnd(selectionEndWasEndOfParagraph); |
| 1144 | 1144 |
| 1145 if (shouldMergeStart(selectionStartWasStartOfParagraph, fragment.hasIntercha
ngeNewlineAtStart(), startIsInsideMailBlockquote)) { | 1145 if (shouldMergeStart(selectionStartWasStartOfParagraph, fragment.hasIntercha
ngeNewlineAtStart(), startIsInsideMailBlockquote)) { |
| 1146 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedConten
t(); | 1146 VisiblePosition startOfParagraphToMove = positionAtStartOfInsertedConten
t(); |
| 1147 VisiblePosition destination = startOfParagraphToMove.previous(); | 1147 VisiblePosition destination = startOfParagraphToMove.previous(); |
| 1148 // We need to handle the case where we need to merge the end | 1148 // We need to handle the case where we need to merge the end |
| 1149 // but our destination node is inside an inline that is the last in the
block. | 1149 // but our destination node is inside an inline that is the last in the
block. |
| 1150 // We insert a placeholder before the newly inserted content to avoid be
ing merged into the inline. | 1150 // We insert a placeholder before the newly inserted content to avoid be
ing merged into the inline. |
| 1151 Node* destinationNode = destination.deepEquivalent().deprecatedNode(); | 1151 Node* destinationNode = destination.deepEquivalent().deprecatedNode(); |
| 1152 if (m_shouldMergeEnd && destinationNode != enclosingInline(destinationNo
de) && enclosingInline(destinationNode)->nextSibling()) | 1152 if (m_shouldMergeEnd && destinationNode != enclosingInline(destinationNo
de) && enclosingInline(destinationNode)->nextSibling()) |
| 1153 insertNodeBefore(createBreakElement(document()), refNode.get()); | 1153 insertNodeBefore(createBreakElement(&document()), refNode.get()); |
| 1154 | 1154 |
| 1155 // Merging the the first paragraph of inserted content with the content
that came | 1155 // Merging the the first paragraph of inserted content with the content
that came |
| 1156 // before the selection that was pasted into would also move content aft
er | 1156 // before the selection that was pasted into would also move content aft
er |
| 1157 // the selection that was pasted into if: only one paragraph was being p
asted, | 1157 // the selection that was pasted into if: only one paragraph was being p
asted, |
| 1158 // and it was not wrapped in a block, the selection that was pasted into
ended | 1158 // and it was not wrapped in a block, the selection that was pasted into
ended |
| 1159 // at the end of a block and the next paragraph didn't start at the star
t of a block. | 1159 // at the end of a block and the next paragraph didn't start at the star
t of a block. |
| 1160 // Insert a line break just after the inserted content to separate it fr
om what | 1160 // Insert a line break just after the inserted content to separate it fr
om what |
| 1161 // comes after and prevent that from happening. | 1161 // comes after and prevent that from happening. |
| 1162 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); | 1162 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); |
| 1163 if (startOfParagraph(endOfInsertedContent) == startOfParagraphToMove) { | 1163 if (startOfParagraph(endOfInsertedContent) == startOfParagraphToMove) { |
| 1164 insertNodeAt(createBreakElement(document()).get(), endOfInsertedCont
ent.deepEquivalent()); | 1164 insertNodeAt(createBreakElement(&document()).get(), endOfInsertedCon
tent.deepEquivalent()); |
| 1165 // Mutation events (bug 22634) triggered by inserting the <br> might
have removed the content we're about to move | 1165 // Mutation events (bug 22634) triggered by inserting the <br> might
have removed the content we're about to move |
| 1166 if (!startOfParagraphToMove.deepEquivalent().anchorNode()->inDocumen
t()) | 1166 if (!startOfParagraphToMove.deepEquivalent().anchorNode()->inDocumen
t()) |
| 1167 return; | 1167 return; |
| 1168 } | 1168 } |
| 1169 | 1169 |
| 1170 // FIXME: Maintain positions for the start and end of inserted content i
nstead of keeping nodes. The nodes are | 1170 // FIXME: Maintain positions for the start and end of inserted content i
nstead of keeping nodes. The nodes are |
| 1171 // only ever used to create positions where inserted content starts/ends
. | 1171 // only ever used to create positions where inserted content starts/ends
. |
| 1172 moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToM
ove), destination); | 1172 moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToM
ove), destination); |
| 1173 m_startOfInsertedContent = endingSelection().visibleStart().deepEquivale
nt().downstream(); | 1173 m_startOfInsertedContent = endingSelection().visibleStart().deepEquivale
nt().downstream(); |
| 1174 if (m_endOfInsertedContent.isOrphan()) | 1174 if (m_endOfInsertedContent.isOrphan()) |
| 1175 m_endOfInsertedContent = endingSelection().visibleEnd().deepEquivale
nt().upstream(); | 1175 m_endOfInsertedContent = endingSelection().visibleEnd().deepEquivale
nt().upstream(); |
| 1176 } | 1176 } |
| 1177 | 1177 |
| 1178 Position lastPositionToSelect; | 1178 Position lastPositionToSelect; |
| 1179 if (fragment.hasInterchangeNewlineAtEnd()) { | 1179 if (fragment.hasInterchangeNewlineAtEnd()) { |
| 1180 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); | 1180 VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent(); |
| 1181 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBound
ary); | 1181 VisiblePosition next = endOfInsertedContent.next(CannotCrossEditingBound
ary); |
| 1182 | 1182 |
| 1183 if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedCont
ent) || next.isNull()) { | 1183 if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedCont
ent) || next.isNull()) { |
| 1184 if (!isStartOfParagraph(endOfInsertedContent)) { | 1184 if (!isStartOfParagraph(endOfInsertedContent)) { |
| 1185 setEndingSelection(endOfInsertedContent); | 1185 setEndingSelection(endOfInsertedContent); |
| 1186 Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEq
uivalent().deprecatedNode()); | 1186 Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEq
uivalent().deprecatedNode()); |
| 1187 if (isListItem(enclosingNode)) { | 1187 if (isListItem(enclosingNode)) { |
| 1188 RefPtr<Node> newListItem = createListItemElement(document())
; | 1188 RefPtr<Node> newListItem = createListItemElement(&document()
); |
| 1189 insertNodeAfter(newListItem, enclosingNode); | 1189 insertNodeAfter(newListItem, enclosingNode); |
| 1190 setEndingSelection(VisiblePosition(firstPositionInNode(newLi
stItem.get()))); | 1190 setEndingSelection(VisiblePosition(firstPositionInNode(newLi
stItem.get()))); |
| 1191 } else { | 1191 } else { |
| 1192 // Use a default paragraph element (a plain div) for the emp
ty paragraph, using the last paragraph | 1192 // Use a default paragraph element (a plain div) for the emp
ty paragraph, using the last paragraph |
| 1193 // block's style seems to annoy users. | 1193 // block's style seems to annoy users. |
| 1194 insertParagraphSeparator(true, !startIsInsideMailBlockquote
&& highestEnclosingNodeOfType(endOfInsertedContent.deepEquivalent(), | 1194 insertParagraphSeparator(true, !startIsInsideMailBlockquote
&& highestEnclosingNodeOfType(endOfInsertedContent.deepEquivalent(), |
| 1195 isMailBlockquote, CannotCrossEditingBoundary, insertedNo
des.firstNodeInserted()->parentNode())); | 1195 isMailBlockquote, CannotCrossEditingBoundary, insertedNo
des.firstNodeInserted()->parentNode())); |
| 1196 } | 1196 } |
| 1197 | 1197 |
| 1198 // Select up to the paragraph separator that was added. | 1198 // Select up to the paragraph separator that was added. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1226 if (!endBR || !endBR->inDocument()) | 1226 if (!endBR || !endBR->inDocument()) |
| 1227 return false; | 1227 return false; |
| 1228 | 1228 |
| 1229 VisiblePosition visiblePos(positionBeforeNode(endBR)); | 1229 VisiblePosition visiblePos(positionBeforeNode(endBR)); |
| 1230 | 1230 |
| 1231 // Don't remove the br if nothing was inserted. | 1231 // Don't remove the br if nothing was inserted. |
| 1232 if (visiblePos.previous() == originalVisPosBeforeEndBR) | 1232 if (visiblePos.previous() == originalVisPosBeforeEndBR) |
| 1233 return false; | 1233 return false; |
| 1234 | 1234 |
| 1235 // Remove the br if it is collapsed away and so is unnecessary. | 1235 // Remove the br if it is collapsed away and so is unnecessary. |
| 1236 if (!document()->inNoQuirksMode() && isEndOfBlock(visiblePos) && !isStartOfP
aragraph(visiblePos)) | 1236 if (!document().inNoQuirksMode() && isEndOfBlock(visiblePos) && !isStartOfPa
ragraph(visiblePos)) |
| 1237 return true; | 1237 return true; |
| 1238 | 1238 |
| 1239 // A br that was originally holding a line open should be displaced by inser
ted content or turned into a line break. | 1239 // A br that was originally holding a line open should be displaced by inser
ted content or turned into a line break. |
| 1240 // A br that was originally acting as a line break should still be acting as
a line break, not as a placeholder. | 1240 // A br that was originally acting as a line break should still be acting as
a line break, not as a placeholder. |
| 1241 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos); | 1241 return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos); |
| 1242 } | 1242 } |
| 1243 | 1243 |
| 1244 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const | 1244 bool ReplaceSelectionCommand::shouldPerformSmartReplace() const |
| 1245 { | 1245 { |
| 1246 if (!m_smartReplace) | 1246 if (!m_smartReplace) |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1272 } | 1272 } |
| 1273 | 1273 |
| 1274 bool needsTrailingSpace = !isEndOfParagraph(endOfInsertedContent) && !isChar
acterSmartReplaceExemptConsideringNonBreakingSpace(endOfInsertedContent.characte
rAfter(), false); | 1274 bool needsTrailingSpace = !isEndOfParagraph(endOfInsertedContent) && !isChar
acterSmartReplaceExemptConsideringNonBreakingSpace(endOfInsertedContent.characte
rAfter(), false); |
| 1275 if (needsTrailingSpace && endNode) { | 1275 if (needsTrailingSpace && endNode) { |
| 1276 bool collapseWhiteSpace = !endNode->renderer() || endNode->renderer()->s
tyle()->collapseWhiteSpace(); | 1276 bool collapseWhiteSpace = !endNode->renderer() || endNode->renderer()->s
tyle()->collapseWhiteSpace(); |
| 1277 if (endNode->isTextNode()) { | 1277 if (endNode->isTextNode()) { |
| 1278 insertTextIntoNode(toText(endNode), endOffset, collapseWhiteSpace ?
nonBreakingSpaceString() : " "); | 1278 insertTextIntoNode(toText(endNode), endOffset, collapseWhiteSpace ?
nonBreakingSpaceString() : " "); |
| 1279 if (m_endOfInsertedContent.containerNode() == endNode) | 1279 if (m_endOfInsertedContent.containerNode() == endNode) |
| 1280 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offse
tInContainerNode() + 1); | 1280 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offse
tInContainerNode() + 1); |
| 1281 } else { | 1281 } else { |
| 1282 RefPtr<Node> node = document()->createEditingTextNode(collapseWhiteS
pace ? nonBreakingSpaceString() : " "); | 1282 RefPtr<Node> node = document().createEditingTextNode(collapseWhiteSp
ace ? nonBreakingSpaceString() : " "); |
| 1283 insertNodeAfter(node, endNode); | 1283 insertNodeAfter(node, endNode); |
| 1284 updateNodesInserted(node.get()); | 1284 updateNodesInserted(node.get()); |
| 1285 } | 1285 } |
| 1286 } | 1286 } |
| 1287 | 1287 |
| 1288 document()->updateLayout(); | 1288 document().updateLayout(); |
| 1289 | 1289 |
| 1290 Position startDownstream = startOfInsertedContent.deepEquivalent().downstrea
m(); | 1290 Position startDownstream = startOfInsertedContent.deepEquivalent().downstrea
m(); |
| 1291 Node* startNode = startDownstream.computeNodeAfterPosition(); | 1291 Node* startNode = startDownstream.computeNodeAfterPosition(); |
| 1292 unsigned startOffset = 0; | 1292 unsigned startOffset = 0; |
| 1293 if (startDownstream.anchorType() == Position::PositionIsOffsetInAnchor) { | 1293 if (startDownstream.anchorType() == Position::PositionIsOffsetInAnchor) { |
| 1294 startNode = startDownstream.containerNode(); | 1294 startNode = startDownstream.containerNode(); |
| 1295 startOffset = startDownstream.offsetInContainerNode(); | 1295 startOffset = startDownstream.offsetInContainerNode(); |
| 1296 } | 1296 } |
| 1297 | 1297 |
| 1298 bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) && !isC
haracterSmartReplaceExemptConsideringNonBreakingSpace(startOfInsertedContent.pre
vious().characterAfter(), true); | 1298 bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) && !isC
haracterSmartReplaceExemptConsideringNonBreakingSpace(startOfInsertedContent.pre
vious().characterAfter(), true); |
| 1299 if (needsLeadingSpace && startNode) { | 1299 if (needsLeadingSpace && startNode) { |
| 1300 bool collapseWhiteSpace = !startNode->renderer() || startNode->renderer(
)->style()->collapseWhiteSpace(); | 1300 bool collapseWhiteSpace = !startNode->renderer() || startNode->renderer(
)->style()->collapseWhiteSpace(); |
| 1301 if (startNode->isTextNode()) { | 1301 if (startNode->isTextNode()) { |
| 1302 insertTextIntoNode(toText(startNode), startOffset, collapseWhiteSpac
e ? nonBreakingSpaceString() : " "); | 1302 insertTextIntoNode(toText(startNode), startOffset, collapseWhiteSpac
e ? nonBreakingSpaceString() : " "); |
| 1303 if (m_endOfInsertedContent.containerNode() == startNode && m_endOfIn
sertedContent.offsetInContainerNode()) | 1303 if (m_endOfInsertedContent.containerNode() == startNode && m_endOfIn
sertedContent.offsetInContainerNode()) |
| 1304 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offse
tInContainerNode() + 1); | 1304 m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offse
tInContainerNode() + 1); |
| 1305 } else { | 1305 } else { |
| 1306 RefPtr<Node> node = document()->createEditingTextNode(collapseWhiteS
pace ? nonBreakingSpaceString() : " "); | 1306 RefPtr<Node> node = document().createEditingTextNode(collapseWhiteSp
ace ? nonBreakingSpaceString() : " "); |
| 1307 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont
ent to be the node containing the leading space, | 1307 // Don't updateNodesInserted. Doing so would set m_endOfInsertedCont
ent to be the node containing the leading space, |
| 1308 // but m_endOfInsertedContent is supposed to mark the end of pasted
content. | 1308 // but m_endOfInsertedContent is supposed to mark the end of pasted
content. |
| 1309 insertNodeBefore(node, startNode); | 1309 insertNodeBefore(node, startNode); |
| 1310 m_startOfInsertedContent = firstPositionInNode(node.get()); | 1310 m_startOfInsertedContent = firstPositionInNode(node.get()); |
| 1311 } | 1311 } |
| 1312 } | 1312 } |
| 1313 } | 1313 } |
| 1314 | 1314 |
| 1315 void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositi
onToSelect) | 1315 void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositi
onToSelect) |
| 1316 { | 1316 { |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1486 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get()); | 1486 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get()); |
| 1487 | 1487 |
| 1488 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en
d); | 1488 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en
d); |
| 1489 | 1489 |
| 1490 setEndingSelection(selectionAfterReplace); | 1490 setEndingSelection(selectionAfterReplace); |
| 1491 | 1491 |
| 1492 return true; | 1492 return true; |
| 1493 } | 1493 } |
| 1494 | 1494 |
| 1495 } // namespace WebCore | 1495 } // namespace WebCore |
| OLD | NEW |