| 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 |