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 |