OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 for (size_t i = 0; i < size; ++i) | 151 for (size_t i = 0; i < size; ++i) |
152 m_commands[i]->getNodesInCommand(nodes); | 152 m_commands[i]->getNodesInCommand(nodes); |
153 } | 153 } |
154 #endif | 154 #endif |
155 | 155 |
156 void applyCommand(PassRefPtr<CompositeEditCommand> command) | 156 void applyCommand(PassRefPtr<CompositeEditCommand> command) |
157 { | 157 { |
158 command->apply(); | 158 command->apply(); |
159 } | 159 } |
160 | 160 |
161 CompositeEditCommand::CompositeEditCommand(Document *document) | 161 CompositeEditCommand::CompositeEditCommand(Document& document) |
162 : EditCommand(document) | 162 : EditCommand(document) |
163 { | 163 { |
164 } | 164 } |
165 | 165 |
166 CompositeEditCommand::~CompositeEditCommand() | 166 CompositeEditCommand::~CompositeEditCommand() |
167 { | 167 { |
168 ASSERT(isTopLevelCommand() || !m_composition); | 168 ASSERT(isTopLevelCommand() || !m_composition); |
169 } | 169 } |
170 | 170 |
171 void CompositeEditCommand::apply() | 171 void CompositeEditCommand::apply() |
(...skipping 10 matching lines...) Expand all Loading... |
182 default: | 182 default: |
183 ASSERT_NOT_REACHED(); | 183 ASSERT_NOT_REACHED(); |
184 return; | 184 return; |
185 } | 185 } |
186 } | 186 } |
187 ensureComposition(); | 187 ensureComposition(); |
188 | 188 |
189 // Changes to the document may have been made since the last editing operati
on that require a layout, as in <rdar://problem/5658603>. | 189 // Changes to the document may have been made since the last editing operati
on that require a layout, as in <rdar://problem/5658603>. |
190 // Low level operations, like RemoveNodeCommand, don't require a layout beca
use the high level operations that use them perform one | 190 // Low level operations, like RemoveNodeCommand, don't require a layout beca
use the high level operations that use them perform one |
191 // if one is necessary (like for the creation of VisiblePositions). | 191 // if one is necessary (like for the creation of VisiblePositions). |
192 ASSERT(document()); | 192 document().updateLayoutIgnorePendingStylesheets(); |
193 document()->updateLayoutIgnorePendingStylesheets(); | |
194 | 193 |
195 Frame* frame = document()->frame(); | 194 Frame* frame = document().frame(); |
196 ASSERT(frame); | 195 ASSERT(frame); |
197 { | 196 { |
198 EventQueueScope scope; | 197 EventQueueScope scope; |
199 doApply(); | 198 doApply(); |
200 } | 199 } |
201 | 200 |
202 // Only need to call appliedEditing for top-level commands, | 201 // Only need to call appliedEditing for top-level commands, |
203 // and TypingCommands do it on their own (see TypingCommand::typingAddedToOp
enCommand). | 202 // and TypingCommands do it on their own (see TypingCommand::typingAddedToOp
enCommand). |
204 if (!isTypingCommand()) | 203 if (!isTypingCommand()) |
205 frame->editor().appliedEditing(this); | 204 frame->editor().appliedEditing(this); |
206 setShouldRetainAutocorrectionIndicator(false); | 205 setShouldRetainAutocorrectionIndicator(false); |
207 } | 206 } |
208 | 207 |
209 EditCommandComposition* CompositeEditCommand::ensureComposition() | 208 EditCommandComposition* CompositeEditCommand::ensureComposition() |
210 { | 209 { |
211 CompositeEditCommand* command = this; | 210 CompositeEditCommand* command = this; |
212 while (command && command->parent()) | 211 while (command && command->parent()) |
213 command = command->parent(); | 212 command = command->parent(); |
214 if (!command->m_composition) | 213 if (!command->m_composition) |
215 command->m_composition = EditCommandComposition::create(document(), star
tingSelection(), endingSelection(), editingAction()); | 214 command->m_composition = EditCommandComposition::create(&document(), sta
rtingSelection(), endingSelection(), editingAction()); |
216 return command->m_composition.get(); | 215 return command->m_composition.get(); |
217 } | 216 } |
218 | 217 |
219 bool CompositeEditCommand::isCreateLinkCommand() const | 218 bool CompositeEditCommand::isCreateLinkCommand() const |
220 { | 219 { |
221 return false; | 220 return false; |
222 } | 221 } |
223 | 222 |
224 bool CompositeEditCommand::preservesTypingStyle() const | 223 bool CompositeEditCommand::preservesTypingStyle() const |
225 { | 224 { |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 { | 510 { |
512 size_t arraySize = markerPointers.size(); | 511 size_t arraySize = markerPointers.size(); |
513 markers.reserveCapacity(arraySize); | 512 markers.reserveCapacity(arraySize); |
514 for (size_t i = 0; i < arraySize; ++i) | 513 for (size_t i = 0; i < arraySize; ++i) |
515 markers.append(*markerPointers[i]); | 514 markers.append(*markerPointers[i]); |
516 } | 515 } |
517 | 516 |
518 void CompositeEditCommand::replaceTextInNodePreservingMarkers(PassRefPtr<Text> p
rpNode, unsigned offset, unsigned count, const String& replacementText) | 517 void CompositeEditCommand::replaceTextInNodePreservingMarkers(PassRefPtr<Text> p
rpNode, unsigned offset, unsigned count, const String& replacementText) |
519 { | 518 { |
520 RefPtr<Text> node(prpNode); | 519 RefPtr<Text> node(prpNode); |
521 DocumentMarkerController* markerController = document()->markers(); | 520 DocumentMarkerController* markerController = document().markers(); |
522 Vector<DocumentMarker> markers; | 521 Vector<DocumentMarker> markers; |
523 copyMarkers(markerController->markersInRange(Range::create(document(), node.
get(), offset, node.get(), offset + count).get(), DocumentMarker::AllMarkers()),
markers); | 522 copyMarkers(markerController->markersInRange(Range::create(&document(), node
.get(), offset, node.get(), offset + count).get(), DocumentMarker::AllMarkers())
, markers); |
524 replaceTextInNode(node, offset, count, replacementText); | 523 replaceTextInNode(node, offset, count, replacementText); |
525 RefPtr<Range> newRange = Range::create(document(), node.get(), offset, node.
get(), offset + replacementText.length()); | 524 RefPtr<Range> newRange = Range::create(&document(), node.get(), offset, node
.get(), offset + replacementText.length()); |
526 for (size_t i = 0; i < markers.size(); ++i) | 525 for (size_t i = 0; i < markers.size(); ++i) |
527 markerController->addMarker(newRange.get(), markers[i].type(), markers[i
].description()); | 526 markerController->addMarker(newRange.get(), markers[i].type(), markers[i
].description()); |
528 } | 527 } |
529 | 528 |
530 Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos) | 529 Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos) |
531 { | 530 { |
532 if (!isTabSpanTextNode(pos.anchorNode())) | 531 if (!isTabSpanTextNode(pos.anchorNode())) |
533 return pos; | 532 return pos; |
534 | 533 |
535 switch (pos.anchorType()) { | 534 switch (pos.anchorType()) { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
712 rebalanceWhitespaceAt(selection.start()); | 711 rebalanceWhitespaceAt(selection.start()); |
713 if (selection.isRange()) | 712 if (selection.isRange()) |
714 rebalanceWhitespaceAt(selection.end()); | 713 rebalanceWhitespaceAt(selection.end()); |
715 } | 714 } |
716 | 715 |
717 void CompositeEditCommand::deleteInsignificantText(PassRefPtr<Text> textNode, un
signed start, unsigned end) | 716 void CompositeEditCommand::deleteInsignificantText(PassRefPtr<Text> textNode, un
signed start, unsigned end) |
718 { | 717 { |
719 if (!textNode || start >= end) | 718 if (!textNode || start >= end) |
720 return; | 719 return; |
721 | 720 |
722 document()->updateLayout(); | 721 document().updateLayout(); |
723 | 722 |
724 RenderText* textRenderer = toRenderText(textNode->renderer()); | 723 RenderText* textRenderer = toRenderText(textNode->renderer()); |
725 if (!textRenderer) | 724 if (!textRenderer) |
726 return; | 725 return; |
727 | 726 |
728 Vector<InlineTextBox*> sortedTextBoxes; | 727 Vector<InlineTextBox*> sortedTextBoxes; |
729 size_t sortedTextBoxesPosition = 0; | 728 size_t sortedTextBoxesPosition = 0; |
730 | 729 |
731 for (InlineTextBox* textBox = textRenderer->firstTextBox(); textBox; textBox
= textBox->nextTextBox()) | 730 for (InlineTextBox* textBox = textRenderer->firstTextBox(); textBox; textBox
= textBox->nextTextBox()) |
732 sortedTextBoxes.append(textBox); | 731 sortedTextBoxes.append(textBox); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
823 { | 822 { |
824 Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivale
nt().downstream(); | 823 Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivale
nt().downstream(); |
825 deleteInsignificantText(pos, end); | 824 deleteInsignificantText(pos, end); |
826 } | 825 } |
827 | 826 |
828 PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRefPtr<Element
> container) | 827 PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRefPtr<Element
> container) |
829 { | 828 { |
830 if (!container) | 829 if (!container) |
831 return 0; | 830 return 0; |
832 | 831 |
833 document()->updateLayoutIgnorePendingStylesheets(); | 832 document().updateLayoutIgnorePendingStylesheets(); |
834 | 833 |
835 // Should assert isBlockFlow || isInlineFlow when deletion improves. See 424
4964. | 834 // Should assert isBlockFlow || isInlineFlow when deletion improves. See 424
4964. |
836 ASSERT(container->renderer()); | 835 ASSERT(container->renderer()); |
837 | 836 |
838 RefPtr<Node> placeholder = createBlockPlaceholderElement(document()); | 837 RefPtr<Node> placeholder = createBlockPlaceholderElement(&document()); |
839 appendNode(placeholder, container); | 838 appendNode(placeholder, container); |
840 return placeholder.release(); | 839 return placeholder.release(); |
841 } | 840 } |
842 | 841 |
843 PassRefPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const Position& po
s) | 842 PassRefPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const Position& po
s) |
844 { | 843 { |
845 if (pos.isNull()) | 844 if (pos.isNull()) |
846 return 0; | 845 return 0; |
847 | 846 |
848 // Should assert isBlockFlow || isInlineFlow when deletion improves. See 42
44964. | 847 // Should assert isBlockFlow || isInlineFlow when deletion improves. See 42
44964. |
849 ASSERT(pos.deprecatedNode()->renderer()); | 848 ASSERT(pos.deprecatedNode()->renderer()); |
850 | 849 |
851 RefPtr<Node> placeholder = createBlockPlaceholderElement(document()); | 850 RefPtr<Node> placeholder = createBlockPlaceholderElement(&document()); |
852 insertNodeAt(placeholder, pos); | 851 insertNodeAt(placeholder, pos); |
853 return placeholder.release(); | 852 return placeholder.release(); |
854 } | 853 } |
855 | 854 |
856 PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Element* cont
ainer) | 855 PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Element* cont
ainer) |
857 { | 856 { |
858 if (!container) | 857 if (!container) |
859 return 0; | 858 return 0; |
860 | 859 |
861 document()->updateLayoutIgnorePendingStylesheets(); | 860 document().updateLayoutIgnorePendingStylesheets(); |
862 | 861 |
863 RenderObject* renderer = container->renderer(); | 862 RenderObject* renderer = container->renderer(); |
864 if (!renderer || !renderer->isBlockFlow()) | 863 if (!renderer || !renderer->isBlockFlow()) |
865 return 0; | 864 return 0; |
866 | 865 |
867 // append the placeholder to make sure it follows | 866 // append the placeholder to make sure it follows |
868 // any unrendered blocks | 867 // any unrendered blocks |
869 RenderBlock* block = toRenderBlock(renderer); | 868 RenderBlock* block = toRenderBlock(renderer); |
870 if (block->height() == 0 || (block->isListItem() && block->isEmpty())) | 869 if (block->height() == 0 || (block->isListItem() && block->isEmpty())) |
871 return appendBlockPlaceholder(container); | 870 return appendBlockPlaceholder(container); |
(...skipping 10 matching lines...) Expand all Loading... |
882 if (p.anchorNode()->hasTagName(brTag)) { | 881 if (p.anchorNode()->hasTagName(brTag)) { |
883 removeNode(p.anchorNode()); | 882 removeNode(p.anchorNode()); |
884 return; | 883 return; |
885 } | 884 } |
886 | 885 |
887 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); | 886 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); |
888 } | 887 } |
889 | 888 |
890 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const
Position& position) | 889 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const
Position& position) |
891 { | 890 { |
892 RefPtr<Element> paragraphElement = createDefaultParagraphElement(document())
; | 891 RefPtr<Element> paragraphElement = createDefaultParagraphElement(&document()
); |
893 paragraphElement->appendChild(createBreakElement(document())); | 892 paragraphElement->appendChild(createBreakElement(&document())); |
894 insertNodeAt(paragraphElement, position); | 893 insertNodeAt(paragraphElement, position); |
895 return paragraphElement.release(); | 894 return paragraphElement.release(); |
896 } | 895 } |
897 | 896 |
898 // If the paragraph is not entirely within it's own block, create one and move t
he paragraph into | 897 // If the paragraph is not entirely within it's own block, create one and move t
he paragraph into |
899 // it, and return that block. Otherwise return 0. | 898 // it, and return that block. Otherwise return 0. |
900 PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessar
y(const Position& pos) | 899 PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessar
y(const Position& pos) |
901 { | 900 { |
902 if (pos.isNull()) | 901 if (pos.isNull()) |
903 return 0; | 902 return 0; |
904 | 903 |
905 document()->updateLayoutIgnorePendingStylesheets(); | 904 document().updateLayoutIgnorePendingStylesheets(); |
906 | 905 |
907 // It's strange that this function is responsible for verifying that pos has
not been invalidated | 906 // It's strange that this function is responsible for verifying that pos has
not been invalidated |
908 // by an earlier call to this function. The caller, applyBlockStyle, should
do this. | 907 // by an earlier call to this function. The caller, applyBlockStyle, should
do this. |
909 VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY); | 908 VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY); |
910 VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos)); | 909 VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos)); |
911 VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos); | 910 VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos); |
912 VisiblePosition next = visibleParagraphEnd.next(); | 911 VisiblePosition next = visibleParagraphEnd.next(); |
913 VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd; | 912 VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd; |
914 | 913 |
915 Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream(); | 914 Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream(); |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1120 // baz | 1119 // baz |
1121 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th
at would | 1120 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th
at would |
1122 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. | 1121 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. |
1123 // Must recononicalize these two VisiblePositions after the pruning above. | 1122 // Must recononicalize these two VisiblePositions after the pruning above. |
1124 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); | 1123 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); |
1125 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); | 1124 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); |
1126 | 1125 |
1127 if (beforeParagraph.isNotNull() && !isTableElement(beforeParagraph.deepEquiv
alent().deprecatedNode()) | 1126 if (beforeParagraph.isNotNull() && !isTableElement(beforeParagraph.deepEquiv
alent().deprecatedNode()) |
1128 && ((!isEndOfParagraph(beforeParagraph) && !isStartOfParagraph(beforePar
agraph)) || beforeParagraph == afterParagraph)) { | 1127 && ((!isEndOfParagraph(beforeParagraph) && !isStartOfParagraph(beforePar
agraph)) || beforeParagraph == afterParagraph)) { |
1129 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. | 1128 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. |
1130 insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquival
ent()); | 1129 insertNodeAt(createBreakElement(&document()), beforeParagraph.deepEquiva
lent()); |
1131 } | 1130 } |
1132 } | 1131 } |
1133 | 1132 |
1134 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraph
ToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& dest
ination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor) | 1133 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraph
ToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& dest
ination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor) |
1135 { | 1134 { |
1136 ASSERT(isStartOfParagraph(startOfParagraphToMove)); | 1135 ASSERT(isStartOfParagraph(startOfParagraphToMove)); |
1137 ASSERT(isEndOfParagraph(endOfParagraphToMove)); | 1136 ASSERT(isEndOfParagraph(endOfParagraphToMove)); |
1138 moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, pr
eserveSelection, preserveStyle, constrainingAncestor); | 1137 moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, pr
eserveSelection, preserveStyle, constrainingAncestor); |
1139 } | 1138 } |
1140 | 1139 |
(...skipping 12 matching lines...) Expand all Loading... |
1153 | 1152 |
1154 bool startAfterParagraph = comparePositions(visibleStart, endOfParagraph
ToMove) > 0; | 1153 bool startAfterParagraph = comparePositions(visibleStart, endOfParagraph
ToMove) > 0; |
1155 bool endBeforeParagraph = comparePositions(visibleEnd, startOfParagraphT
oMove) < 0; | 1154 bool endBeforeParagraph = comparePositions(visibleEnd, startOfParagraphT
oMove) < 0; |
1156 | 1155 |
1157 if (!startAfterParagraph && !endBeforeParagraph) { | 1156 if (!startAfterParagraph && !endBeforeParagraph) { |
1158 bool startInParagraph = comparePositions(visibleStart, startOfParagr
aphToMove) >= 0; | 1157 bool startInParagraph = comparePositions(visibleStart, startOfParagr
aphToMove) >= 0; |
1159 bool endInParagraph = comparePositions(visibleEnd, endOfParagraphToM
ove) <= 0; | 1158 bool endInParagraph = comparePositions(visibleEnd, endOfParagraphToM
ove) <= 0; |
1160 | 1159 |
1161 startIndex = 0; | 1160 startIndex = 0; |
1162 if (startInParagraph) { | 1161 if (startInParagraph) { |
1163 RefPtr<Range> startRange = Range::create(document(), startOfPara
graphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleStart.deepEquiva
lent().parentAnchoredEquivalent()); | 1162 RefPtr<Range> startRange = Range::create(&document(), startOfPar
agraphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleStart.deepEquiv
alent().parentAnchoredEquivalent()); |
1164 startIndex = TextIterator::rangeLength(startRange.get(), true); | 1163 startIndex = TextIterator::rangeLength(startRange.get(), true); |
1165 } | 1164 } |
1166 | 1165 |
1167 endIndex = 0; | 1166 endIndex = 0; |
1168 if (endInParagraph) { | 1167 if (endInParagraph) { |
1169 RefPtr<Range> endRange = Range::create(document(), startOfParagr
aphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleEnd.deepEquivalent
().parentAnchoredEquivalent()); | 1168 RefPtr<Range> endRange = Range::create(&document(), startOfParag
raphToMove.deepEquivalent().parentAnchoredEquivalent(), visibleEnd.deepEquivalen
t().parentAnchoredEquivalent()); |
1170 endIndex = TextIterator::rangeLength(endRange.get(), true); | 1169 endIndex = TextIterator::rangeLength(endRange.get(), true); |
1171 } | 1170 } |
1172 } | 1171 } |
1173 } | 1172 } |
1174 | 1173 |
1175 VisiblePosition beforeParagraph = startOfParagraphToMove.previous(CannotCros
sEditingBoundary); | 1174 VisiblePosition beforeParagraph = startOfParagraphToMove.previous(CannotCros
sEditingBoundary); |
1176 VisiblePosition afterParagraph(endOfParagraphToMove.next(CannotCrossEditingB
oundary)); | 1175 VisiblePosition afterParagraph(endOfParagraphToMove.next(CannotCrossEditingB
oundary)); |
1177 | 1176 |
1178 // We upstream() the end and downstream() the start so that we don't include
collapsed whitespace in the move. | 1177 // We upstream() the end and downstream() the start so that we don't include
collapsed whitespace in the move. |
1179 // When we paste a fragment, spaces after the end and before the start are t
reated as though they were rendered. | 1178 // When we paste a fragment, spaces after the end and before the start are t
reated as though they were rendered. |
1180 Position start = startOfParagraphToMove.deepEquivalent().downstream(); | 1179 Position start = startOfParagraphToMove.deepEquivalent().downstream(); |
1181 Position end = endOfParagraphToMove.deepEquivalent().upstream(); | 1180 Position end = endOfParagraphToMove.deepEquivalent().upstream(); |
1182 | 1181 |
1183 // start and end can't be used directly to create a Range; they are "editing
positions" | 1182 // start and end can't be used directly to create a Range; they are "editing
positions" |
1184 Position startRangeCompliant = start.parentAnchoredEquivalent(); | 1183 Position startRangeCompliant = start.parentAnchoredEquivalent(); |
1185 Position endRangeCompliant = end.parentAnchoredEquivalent(); | 1184 Position endRangeCompliant = end.parentAnchoredEquivalent(); |
1186 RefPtr<Range> range = Range::create(document(), startRangeCompliant.deprecat
edNode(), startRangeCompliant.deprecatedEditingOffset(), endRangeCompliant.depre
catedNode(), endRangeCompliant.deprecatedEditingOffset()); | 1185 RefPtr<Range> range = Range::create(&document(), startRangeCompliant.depreca
tedNode(), startRangeCompliant.deprecatedEditingOffset(), endRangeCompliant.depr
ecatedNode(), endRangeCompliant.deprecatedEditingOffset()); |
1187 | 1186 |
1188 // FIXME: This is an inefficient way to preserve style on nodes in the parag
raph to move. It | 1187 // FIXME: This is an inefficient way to preserve style on nodes in the parag
raph to move. It |
1189 // shouldn't matter though, since moved paragraphs will usually be quite sma
ll. | 1188 // shouldn't matter though, since moved paragraphs will usually be quite sma
ll. |
1190 RefPtr<DocumentFragment> fragment = startOfParagraphToMove != endOfParagraph
ToMove ? | 1189 RefPtr<DocumentFragment> fragment = startOfParagraphToMove != endOfParagraph
ToMove ? |
1191 createFragmentFromMarkup(document(), createMarkup(range.get(), 0, DoNotA
nnotateForInterchange, true, DoNotResolveURLs, constrainingAncestor), "") : 0; | 1190 createFragmentFromMarkup(&document(), createMarkup(range.get(), 0, DoNot
AnnotateForInterchange, true, DoNotResolveURLs, constrainingAncestor), "") : 0; |
1192 | 1191 |
1193 // A non-empty paragraph's style is moved when we copy and move it. We don'
t move | 1192 // A non-empty paragraph's style is moved when we copy and move it. We don'
t move |
1194 // anything if we're given an empty paragraph, but an empty paragraph can ha
ve style | 1193 // anything if we're given an empty paragraph, but an empty paragraph can ha
ve style |
1195 // too, <div><b><br></b></div> for example. Save it so that we can preserve
it later. | 1194 // too, <div><b><br></b></div> for example. Save it so that we can preserve
it later. |
1196 RefPtr<EditingStyle> styleInEmptyParagraph; | 1195 RefPtr<EditingStyle> styleInEmptyParagraph; |
1197 if (startOfParagraphToMove == endOfParagraphToMove && preserveStyle) { | 1196 if (startOfParagraphToMove == endOfParagraphToMove && preserveStyle) { |
1198 styleInEmptyParagraph = EditingStyle::create(startOfParagraphToMove.deep
Equivalent()); | 1197 styleInEmptyParagraph = EditingStyle::create(startOfParagraphToMove.deep
Equivalent()); |
1199 styleInEmptyParagraph->mergeTypingStyle(document()); | 1198 styleInEmptyParagraph->mergeTypingStyle(&document()); |
1200 // The moved paragraph should assume the block style of the destination. | 1199 // The moved paragraph should assume the block style of the destination. |
1201 styleInEmptyParagraph->removeBlockProperties(); | 1200 styleInEmptyParagraph->removeBlockProperties(); |
1202 } | 1201 } |
1203 | 1202 |
1204 // FIXME (5098931): We should add a new insert action "WebViewInsertActionMo
ved" and call shouldInsertFragment here. | 1203 // FIXME (5098931): We should add a new insert action "WebViewInsertActionMo
ved" and call shouldInsertFragment here. |
1205 | 1204 |
1206 setEndingSelection(VisibleSelection(start, end, DOWNSTREAM)); | 1205 setEndingSelection(VisibleSelection(start, end, DOWNSTREAM)); |
1207 document()->frame()->editor().clearMisspellingsAndBadGrammar(endingSelection
()); | 1206 document().frame()->editor().clearMisspellingsAndBadGrammar(endingSelection(
)); |
1208 deleteSelection(false, false, false, false); | 1207 deleteSelection(false, false, false, false); |
1209 | 1208 |
1210 ASSERT(destination.deepEquivalent().anchorNode()->inDocument()); | 1209 ASSERT(destination.deepEquivalent().anchorNode()->inDocument()); |
1211 cleanupAfterDeletion(destination); | 1210 cleanupAfterDeletion(destination); |
1212 ASSERT(destination.deepEquivalent().anchorNode()->inDocument()); | 1211 ASSERT(destination.deepEquivalent().anchorNode()->inDocument()); |
1213 | 1212 |
1214 // Add a br if pruning an empty block level element caused a collapse. For e
xample: | 1213 // Add a br if pruning an empty block level element caused a collapse. For e
xample: |
1215 // foo^ | 1214 // foo^ |
1216 // <div>bar</div> | 1215 // <div>bar</div> |
1217 // baz | 1216 // baz |
1218 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That
would | 1217 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That
would |
1219 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. | 1218 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. |
1220 // Must recononicalize these two VisiblePositions after the pruning above. | 1219 // Must recononicalize these two VisiblePositions after the pruning above. |
1221 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); | 1220 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); |
1222 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); | 1221 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); |
1223 if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || be
foreParagraph == afterParagraph)) { | 1222 if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || be
foreParagraph == afterParagraph)) { |
1224 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. | 1223 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. |
1225 insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquival
ent()); | 1224 insertNodeAt(createBreakElement(&document()), beforeParagraph.deepEquiva
lent()); |
1226 // Need an updateLayout here in case inserting the br has split a text n
ode. | 1225 // Need an updateLayout here in case inserting the br has split a text n
ode. |
1227 document()->updateLayoutIgnorePendingStylesheets(); | 1226 document().updateLayoutIgnorePendingStylesheets(); |
1228 } | 1227 } |
1229 | 1228 |
1230 RefPtr<Range> startToDestinationRange(Range::create(document(), firstPositio
nInNode(document()->documentElement()), destination.deepEquivalent().parentAncho
redEquivalent())); | 1229 RefPtr<Range> startToDestinationRange(Range::create(&document(), firstPositi
onInNode(document().documentElement()), destination.deepEquivalent().parentAncho
redEquivalent())); |
1231 destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(),
true); | 1230 destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(),
true); |
1232 | 1231 |
1233 setEndingSelection(VisibleSelection(destination, originalIsDirectional)); | 1232 setEndingSelection(VisibleSelection(destination, originalIsDirectional)); |
1234 ASSERT(endingSelection().isCaretOrRange()); | 1233 ASSERT(endingSelection().isCaretOrRange()); |
1235 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::S
electReplacement | ReplaceSelectionCommand::MovingParagraph; | 1234 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::S
electReplacement | ReplaceSelectionCommand::MovingParagraph; |
1236 if (!preserveStyle) | 1235 if (!preserveStyle) |
1237 options |= ReplaceSelectionCommand::MatchStyle; | 1236 options |= ReplaceSelectionCommand::MatchStyle; |
1238 applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment
, options)); | 1237 applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment
, options)); |
1239 | 1238 |
1240 document()->frame()->editor().markMisspellingsAndBadGrammar(endingSelection(
)); | 1239 document().frame()->editor().markMisspellingsAndBadGrammar(endingSelection()
); |
1241 | 1240 |
1242 // If the selection is in an empty paragraph, restore styles from the old em
pty paragraph to the new empty paragraph. | 1241 // If the selection is in an empty paragraph, restore styles from the old em
pty paragraph to the new empty paragraph. |
1243 bool selectionIsEmptyParagraph = endingSelection().isCaret() && isStartOfPar
agraph(endingSelection().visibleStart()) && isEndOfParagraph(endingSelection().v
isibleStart()); | 1242 bool selectionIsEmptyParagraph = endingSelection().isCaret() && isStartOfPar
agraph(endingSelection().visibleStart()) && isEndOfParagraph(endingSelection().v
isibleStart()); |
1244 if (styleInEmptyParagraph && selectionIsEmptyParagraph) | 1243 if (styleInEmptyParagraph && selectionIsEmptyParagraph) |
1245 applyStyle(styleInEmptyParagraph.get()); | 1244 applyStyle(styleInEmptyParagraph.get()); |
1246 | 1245 |
1247 if (preserveSelection && startIndex != -1) { | 1246 if (preserveSelection && startIndex != -1) { |
1248 // Fragment creation (using createMarkup) incorrectly uses regular | 1247 // Fragment creation (using createMarkup) incorrectly uses regular |
1249 // spaces instead of nbsps for some spaces that were rendered (11475), w
hich | 1248 // spaces instead of nbsps for some spaces that were rendered (11475), w
hich |
1250 // causes spaces to be collapsed during the move operation. This result
s | 1249 // causes spaces to be collapsed during the move operation. This result
s |
1251 // in a call to rangeFromLocationAndLength with a location past the end | 1250 // in a call to rangeFromLocationAndLength with a location past the end |
1252 // of the document (which will return null). | 1251 // of the document (which will return null). |
1253 RefPtr<Range> start = TextIterator::rangeFromLocationAndLength(document(
)->documentElement(), destinationIndex + startIndex, 0, true); | 1252 RefPtr<Range> start = TextIterator::rangeFromLocationAndLength(document(
).documentElement(), destinationIndex + startIndex, 0, true); |
1254 RefPtr<Range> end = TextIterator::rangeFromLocationAndLength(document()-
>documentElement(), destinationIndex + endIndex, 0, true); | 1253 RefPtr<Range> end = TextIterator::rangeFromLocationAndLength(document().
documentElement(), destinationIndex + endIndex, 0, true); |
1255 if (start && end) | 1254 if (start && end) |
1256 setEndingSelection(VisibleSelection(start->startPosition(), end->sta
rtPosition(), DOWNSTREAM, originalIsDirectional)); | 1255 setEndingSelection(VisibleSelection(start->startPosition(), end->sta
rtPosition(), DOWNSTREAM, originalIsDirectional)); |
1257 } | 1256 } |
1258 } | 1257 } |
1259 | 1258 |
1260 // FIXME: Send an appropriate shouldDeleteRange call. | 1259 // FIXME: Send an appropriate shouldDeleteRange call. |
1261 bool CompositeEditCommand::breakOutOfEmptyListItem() | 1260 bool CompositeEditCommand::breakOutOfEmptyListItem() |
1262 { | 1261 { |
1263 RefPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelection().visibl
eStart()); | 1262 RefPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelection().visibl
eStart()); |
1264 if (!emptyListItem) | 1263 if (!emptyListItem) |
1265 return false; | 1264 return false; |
1266 | 1265 |
1267 RefPtr<EditingStyle> style = EditingStyle::create(endingSelection().start())
; | 1266 RefPtr<EditingStyle> style = EditingStyle::create(endingSelection().start())
; |
1268 style->mergeTypingStyle(document()); | 1267 style->mergeTypingStyle(&document()); |
1269 | 1268 |
1270 RefPtr<ContainerNode> listNode = emptyListItem->parentNode(); | 1269 RefPtr<ContainerNode> listNode = emptyListItem->parentNode(); |
1271 // FIXME: Can't we do something better when the immediate parent wasn't a li
st node? | 1270 // FIXME: Can't we do something better when the immediate parent wasn't a li
st node? |
1272 if (!listNode | 1271 if (!listNode |
1273 || (!listNode->hasTagName(ulTag) && !listNode->hasTagName(olTag)) | 1272 || (!listNode->hasTagName(ulTag) && !listNode->hasTagName(olTag)) |
1274 || !listNode->rendererIsEditable() | 1273 || !listNode->rendererIsEditable() |
1275 || listNode == emptyListItem->rootEditableElement()) | 1274 || listNode == emptyListItem->rootEditableElement()) |
1276 return false; | 1275 return false; |
1277 | 1276 |
1278 RefPtr<Element> newBlock = 0; | 1277 RefPtr<Element> newBlock = 0; |
1279 if (ContainerNode* blockEnclosingList = listNode->parentNode()) { | 1278 if (ContainerNode* blockEnclosingList = listNode->parentNode()) { |
1280 if (blockEnclosingList->hasTagName(liTag)) { // listNode is inside anoth
er list item | 1279 if (blockEnclosingList->hasTagName(liTag)) { // listNode is inside anoth
er list item |
1281 if (visiblePositionAfterNode(blockEnclosingList) == visiblePositionA
fterNode(listNode.get())) { | 1280 if (visiblePositionAfterNode(blockEnclosingList) == visiblePositionA
fterNode(listNode.get())) { |
1282 // If listNode appears at the end of the outer list item, then m
ove listNode outside of this list item | 1281 // If listNode appears at the end of the outer list item, then m
ove listNode outside of this list item |
1283 // e.g. <ul><li>hello <ul><li><br></li></ul> </li></ul> should b
ecome <ul><li>hello</li> <ul><li><br></li></ul> </ul> after this section | 1282 // e.g. <ul><li>hello <ul><li><br></li></ul> </li></ul> should b
ecome <ul><li>hello</li> <ul><li><br></li></ul> </ul> after this section |
1284 // If listNode does NOT appear at the end, then we should consid
er it as a regular paragraph. | 1283 // If listNode does NOT appear at the end, then we should consid
er it as a regular paragraph. |
1285 // e.g. <ul><li> <ul><li><br></li></ul> hello</li></ul> should b
ecome <ul><li> <div><br></div> hello</li></ul> at the end | 1284 // e.g. <ul><li> <ul><li><br></li></ul> hello</li></ul> should b
ecome <ul><li> <div><br></div> hello</li></ul> at the end |
1286 splitElement(toElement(blockEnclosingList), listNode); | 1285 splitElement(toElement(blockEnclosingList), listNode); |
1287 removeNodePreservingChildren(listNode->parentNode()); | 1286 removeNodePreservingChildren(listNode->parentNode()); |
1288 newBlock = createListItemElement(document()); | 1287 newBlock = createListItemElement(&document()); |
1289 } | 1288 } |
1290 // If listNode does NOT appear at the end of the outer list item, th
en behave as if in a regular paragraph. | 1289 // If listNode does NOT appear at the end of the outer list item, th
en behave as if in a regular paragraph. |
1291 } else if (blockEnclosingList->hasTagName(olTag) || blockEnclosingList->
hasTagName(ulTag)) | 1290 } else if (blockEnclosingList->hasTagName(olTag) || blockEnclosingList->
hasTagName(ulTag)) { |
1292 newBlock = createListItemElement(document()); | 1291 newBlock = createListItemElement(&document()); |
| 1292 } |
1293 } | 1293 } |
1294 if (!newBlock) | 1294 if (!newBlock) |
1295 newBlock = createDefaultParagraphElement(document()); | 1295 newBlock = createDefaultParagraphElement(&document()); |
1296 | 1296 |
1297 RefPtr<Node> previousListNode = emptyListItem->isElementNode() ? toElement(e
mptyListItem.get())->previousElementSibling(): emptyListItem->previousSibling(); | 1297 RefPtr<Node> previousListNode = emptyListItem->isElementNode() ? toElement(e
mptyListItem.get())->previousElementSibling(): emptyListItem->previousSibling(); |
1298 RefPtr<Node> nextListNode = emptyListItem->isElementNode() ? toElement(empty
ListItem.get())->nextElementSibling(): emptyListItem->nextSibling(); | 1298 RefPtr<Node> nextListNode = emptyListItem->isElementNode() ? toElement(empty
ListItem.get())->nextElementSibling(): emptyListItem->nextSibling(); |
1299 if (isListItem(nextListNode.get()) || isListElement(nextListNode.get())) { | 1299 if (isListItem(nextListNode.get()) || isListElement(nextListNode.get())) { |
1300 // If emptyListItem follows another list item or nested list, split the
list node. | 1300 // If emptyListItem follows another list item or nested list, split the
list node. |
1301 if (isListItem(previousListNode.get()) || isListElement(previousListNode
.get())) | 1301 if (isListItem(previousListNode.get()) || isListElement(previousListNode
.get())) |
1302 splitElement(toElement(listNode.get()), emptyListItem); | 1302 splitElement(toElement(listNode.get()), emptyListItem); |
1303 | 1303 |
1304 // If emptyListItem is followed by other list item or nested list, then
insert newBlock before the list node. | 1304 // If emptyListItem is followed by other list item or nested list, then
insert newBlock before the list node. |
1305 // Because we have splitted the element, emptyListItem is the first elem
ent in the list node. | 1305 // Because we have splitted the element, emptyListItem is the first elem
ent in the list node. |
(...skipping 30 matching lines...) Expand all Loading... |
1336 return false; | 1336 return false; |
1337 | 1337 |
1338 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret)) | 1338 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret)) |
1339 return false; | 1339 return false; |
1340 | 1340 |
1341 VisiblePosition previous(caret.previous(CannotCrossEditingBoundary)); | 1341 VisiblePosition previous(caret.previous(CannotCrossEditingBoundary)); |
1342 // Only move forward if there's nothing before the caret, or if there's unqu
oted content before it. | 1342 // Only move forward if there's nothing before the caret, or if there's unqu
oted content before it. |
1343 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote)) | 1343 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote)) |
1344 return false; | 1344 return false; |
1345 | 1345 |
1346 RefPtr<Node> br = createBreakElement(document()); | 1346 RefPtr<Node> br = createBreakElement(&document()); |
1347 // We want to replace this quoted paragraph with an unquoted one, so insert
a br | 1347 // We want to replace this quoted paragraph with an unquoted one, so insert
a br |
1348 // to hold the caret before the highest blockquote. | 1348 // to hold the caret before the highest blockquote. |
1349 insertNodeBefore(br, highestBlockquote); | 1349 insertNodeBefore(br, highestBlockquote); |
1350 VisiblePosition atBR(positionBeforeNode(br.get())); | 1350 VisiblePosition atBR(positionBeforeNode(br.get())); |
1351 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc
kquote>, insert | 1351 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc
kquote>, insert |
1352 // a second one. | 1352 // a second one. |
1353 if (!isStartOfParagraph(atBR)) | 1353 if (!isStartOfParagraph(atBR)) |
1354 insertNodeBefore(createBreakElement(document()), br); | 1354 insertNodeBefore(createBreakElement(&document()), br); |
1355 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); | 1355 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); |
1356 | 1356 |
1357 // If this is an empty paragraph there must be a line break here. | 1357 // If this is an empty paragraph there must be a line break here. |
1358 if (!lineBreakExistsAtVisiblePosition(caret)) | 1358 if (!lineBreakExistsAtVisiblePosition(caret)) |
1359 return false; | 1359 return false; |
1360 | 1360 |
1361 Position caretPos(caret.deepEquivalent().downstream()); | 1361 Position caretPos(caret.deepEquivalent().downstream()); |
1362 // A line break is either a br or a preserved newline. | 1362 // A line break is either a br or a preserved newline. |
1363 ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedN
ode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveN
ewline())); | 1363 ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedN
ode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveN
ewline())); |
1364 | 1364 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1464 return node.release(); | 1464 return node.release(); |
1465 } | 1465 } |
1466 | 1466 |
1467 PassRefPtr<Element> createBlockPlaceholderElement(Document* document) | 1467 PassRefPtr<Element> createBlockPlaceholderElement(Document* document) |
1468 { | 1468 { |
1469 RefPtr<Element> breakNode = document->createElement(brTag, false); | 1469 RefPtr<Element> breakNode = document->createElement(brTag, false); |
1470 return breakNode.release(); | 1470 return breakNode.release(); |
1471 } | 1471 } |
1472 | 1472 |
1473 } // namespace WebCore | 1473 } // namespace WebCore |
OLD | NEW |