Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(329)

Side by Side Diff: third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp

Issue 2397963002: Reflow comments in //third_party/WebKit/Source/core/editing/commands (Closed)
Patch Set: . Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 bool EditCommandComposition::belongsTo(const LocalFrame& frame) const { 103 bool EditCommandComposition::belongsTo(const LocalFrame& frame) const {
104 DCHECK(m_document); 104 DCHECK(m_document);
105 return m_document->frame() == &frame; 105 return m_document->frame() == &frame;
106 } 106 }
107 107
108 void EditCommandComposition::unapply() { 108 void EditCommandComposition::unapply() {
109 DCHECK(m_document); 109 DCHECK(m_document);
110 LocalFrame* frame = m_document->frame(); 110 LocalFrame* frame = m_document->frame();
111 DCHECK(frame); 111 DCHECK(frame);
112 112
113 // Changes to the document may have been made since the last editing operation that require a layout, as in <rdar://problem/5658603>. 113 // Changes to the document may have been made since the last editing operation
114 // Low level operations, like RemoveNodeCommand, don't require a layout becaus e the high level operations that use them perform one 114 // that require a layout, as in <rdar://problem/5658603>. Low level
115 // if one is necessary (like for the creation of VisiblePositions). 115 // operations, like RemoveNodeCommand, don't require a layout because the high
116 // level operations that use them perform one if one is necessary (like for
117 // the creation of VisiblePositions).
116 m_document->updateStyleAndLayoutIgnorePendingStylesheets(); 118 m_document->updateStyleAndLayoutIgnorePendingStylesheets();
117 119
118 { 120 {
119 size_t size = m_commands.size(); 121 size_t size = m_commands.size();
120 for (size_t i = size; i; --i) 122 for (size_t i = size; i; --i)
121 m_commands[i - 1]->doUnapply(); 123 m_commands[i - 1]->doUnapply();
122 } 124 }
123 125
124 frame->editor().unappliedEditing(this); 126 frame->editor().unappliedEditing(this);
125 } 127 }
126 128
127 void EditCommandComposition::reapply() { 129 void EditCommandComposition::reapply() {
128 DCHECK(m_document); 130 DCHECK(m_document);
129 LocalFrame* frame = m_document->frame(); 131 LocalFrame* frame = m_document->frame();
130 DCHECK(frame); 132 DCHECK(frame);
131 133
132 // Changes to the document may have been made since the last editing operation that require a layout, as in <rdar://problem/5658603>. 134 // Changes to the document may have been made since the last editing operation
133 // Low level operations, like RemoveNodeCommand, don't require a layout becaus e the high level operations that use them perform one 135 // that require a layout, as in <rdar://problem/5658603>. Low level
134 // if one is necessary (like for the creation of VisiblePositions). 136 // operations, like RemoveNodeCommand, don't require a layout because the high
137 // level operations that use them perform one if one is necessary (like for
138 // the creation of VisiblePositions).
135 m_document->updateStyleAndLayoutIgnorePendingStylesheets(); 139 m_document->updateStyleAndLayoutIgnorePendingStylesheets();
136 140
137 { 141 {
138 for (const auto& command : m_commands) 142 for (const auto& command : m_commands)
139 command->doReapply(); 143 command->doReapply();
140 } 144 }
141 145
142 frame->editor().reappliedEditing(this); 146 frame->editor().reappliedEditing(this);
143 } 147 }
144 148
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 case InputEvent::InputType::SetWritingDirection: 209 case InputEvent::InputType::SetWritingDirection:
206 case InputEvent::InputType::None: 210 case InputEvent::InputType::None:
207 break; 211 break;
208 default: 212 default:
209 NOTREACHED(); 213 NOTREACHED();
210 return false; 214 return false;
211 } 215 }
212 } 216 }
213 ensureComposition(); 217 ensureComposition();
214 218
215 // Changes to the document may have been made since the last editing operation that require a layout, as in <rdar://problem/5658603>. 219 // Changes to the document may have been made since the last editing operation
216 // Low level operations, like RemoveNodeCommand, don't require a layout becaus e the high level operations that use them perform one 220 // that require a layout, as in <rdar://problem/5658603>. Low level
217 // if one is necessary (like for the creation of VisiblePositions). 221 // operations, like RemoveNodeCommand, don't require a layout because the high
222 // level operations that use them perform one if one is necessary (like for
223 // the creation of VisiblePositions).
218 document().updateStyleAndLayoutIgnorePendingStylesheets(); 224 document().updateStyleAndLayoutIgnorePendingStylesheets();
219 225
220 LocalFrame* frame = document().frame(); 226 LocalFrame* frame = document().frame();
221 DCHECK(frame); 227 DCHECK(frame);
222 EditingState editingState; 228 EditingState editingState;
223 { 229 {
224 EventQueueScope eventQueueScope; 230 EventQueueScope eventQueueScope;
225 doApply(&editingState); 231 doApply(&editingState);
226 } 232 }
227 233
228 // Only need to call appliedEditing for top-level commands, 234 // Only need to call appliedEditing for top-level commands, and TypingCommands
229 // and TypingCommands do it on their own (see TypingCommand::typingAddedToOpen Command). 235 // do it on their own (see TypingCommand::typingAddedToOpenCommand).
230 if (!isTypingCommand()) 236 if (!isTypingCommand())
231 frame->editor().appliedEditing(this); 237 frame->editor().appliedEditing(this);
232 setShouldRetainAutocorrectionIndicator(false); 238 setShouldRetainAutocorrectionIndicator(false);
233 return !editingState.isAborted(); 239 return !editingState.isAborted();
234 } 240 }
235 241
236 EditCommandComposition* CompositeEditCommand::ensureComposition() { 242 EditCommandComposition* CompositeEditCommand::ensureComposition() {
237 CompositeEditCommand* command = this; 243 CompositeEditCommand* command = this;
238 while (command && command->parent()) 244 while (command && command->parent())
239 command = command->parent(); 245 command = command->parent();
(...skipping 19 matching lines...) Expand all
259 return false; 265 return false;
260 } 266 }
261 267
262 bool CompositeEditCommand::isReplaceSelectionCommand() const { 268 bool CompositeEditCommand::isReplaceSelectionCommand() const {
263 return false; 269 return false;
264 } 270 }
265 271
266 void CompositeEditCommand::setShouldRetainAutocorrectionIndicator(bool) {} 272 void CompositeEditCommand::setShouldRetainAutocorrectionIndicator(bool) {}
267 273
268 // 274 //
269 // sugary-sweet convenience functions to help create and apply edit commands in composite commands 275 // sugary-sweet convenience functions to help create and apply edit commands in
276 // composite commands
270 // 277 //
271 void CompositeEditCommand::applyCommandToComposite(EditCommand* command, 278 void CompositeEditCommand::applyCommandToComposite(EditCommand* command,
272 EditingState* editingState) { 279 EditingState* editingState) {
273 command->setParent(this); 280 command->setParent(this);
274 command->doApply(editingState); 281 command->doApply(editingState);
275 if (editingState->isAborted()) { 282 if (editingState->isAborted()) {
276 command->setParent(nullptr); 283 command->setParent(nullptr);
277 return; 284 return;
278 } 285 }
279 if (command->isSimpleEditCommand()) { 286 if (command->isSimpleEditCommand()) {
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 child = child->nextSibling(); 414 child = child->nextSibling();
408 if (child) 415 if (child)
409 insertNodeBefore(insertChild, child, editingState); 416 insertNodeBefore(insertChild, child, editingState);
410 else 417 else
411 appendNode(insertChild, toContainerNode(refChild), editingState); 418 appendNode(insertChild, toContainerNode(refChild), editingState);
412 } else if (caretMinOffset(refChild) >= offset) { 419 } else if (caretMinOffset(refChild) >= offset) {
413 insertNodeBefore(insertChild, refChild, editingState); 420 insertNodeBefore(insertChild, refChild, editingState);
414 } else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) { 421 } else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) {
415 splitTextNode(toText(refChild), offset); 422 splitTextNode(toText(refChild), offset);
416 423
417 // Mutation events (bug 22634) from the text node insertion may have removed the refChild 424 // Mutation events (bug 22634) from the text node insertion may have removed
425 // the refChild
418 if (!refChild->isConnected()) 426 if (!refChild->isConnected())
419 return; 427 return;
420 insertNodeBefore(insertChild, refChild, editingState); 428 insertNodeBefore(insertChild, refChild, editingState);
421 } else { 429 } else {
422 insertNodeAfter(insertChild, refChild, editingState); 430 insertNodeAfter(insertChild, refChild, editingState);
423 } 431 }
424 } 432 }
425 433
426 void CompositeEditCommand::appendNode(Node* node, 434 void CompositeEditCommand::appendNode(Node* node,
427 ContainerNode* parent, 435 ContainerNode* parent,
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
799 if (textNode->length() == 0) 807 if (textNode->length() == 0)
800 return false; 808 return false;
801 809
802 LayoutText* layoutText = textNode->layoutObject(); 810 LayoutText* layoutText = textNode->layoutObject();
803 if (layoutText && !layoutText->style()->collapseWhiteSpace()) 811 if (layoutText && !layoutText->style()->collapseWhiteSpace())
804 return false; 812 return false;
805 813
806 return true; 814 return true;
807 } 815 }
808 816
809 // FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, co usins, etc). 817 // FIXME: Doesn't go into text nodes that contribute adjacent text (siblings,
818 // cousins, etc).
810 void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position) { 819 void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position) {
811 Node* node = position.computeContainerNode(); 820 Node* node = position.computeContainerNode();
812 if (!canRebalance(position)) 821 if (!canRebalance(position))
813 return; 822 return;
814 823
815 // If the rebalance is for the single offset, and neither text[offset] nor tex t[offset - 1] are some form of whitespace, do nothing. 824 // If the rebalance is for the single offset, and neither text[offset] nor
825 // text[offset - 1] are some form of whitespace, do nothing.
816 int offset = position.computeOffsetInContainerNode(); 826 int offset = position.computeOffsetInContainerNode();
817 String text = toText(node)->data(); 827 String text = toText(node)->data();
818 if (!isWhitespace(text[offset])) { 828 if (!isWhitespace(text[offset])) {
819 offset--; 829 offset--;
820 if (offset < 0 || !isWhitespace(text[offset])) 830 if (offset < 0 || !isWhitespace(text[offset]))
821 return; 831 return;
822 } 832 }
823 833
824 rebalanceWhitespaceOnTextSubstring(toText(node), 834 rebalanceWhitespaceOnTextSubstring(toText(node),
825 position.offsetInContainerNode(), 835 position.offsetInContainerNode(),
826 position.offsetInContainerNode()); 836 position.offsetInContainerNode());
827 } 837 }
828 838
829 void CompositeEditCommand::rebalanceWhitespaceOnTextSubstring(Text* textNode, 839 void CompositeEditCommand::rebalanceWhitespaceOnTextSubstring(Text* textNode,
830 int startOffset, 840 int startOffset,
831 int endOffset) { 841 int endOffset) {
832 String text = textNode->data(); 842 String text = textNode->data();
833 DCHECK(!text.isEmpty()); 843 DCHECK(!text.isEmpty());
834 844
835 // Set upstream and downstream to define the extent of the whitespace surround ing text[offset]. 845 // Set upstream and downstream to define the extent of the whitespace
846 // surrounding text[offset].
836 int upstream = startOffset; 847 int upstream = startOffset;
837 while (upstream > 0 && isWhitespace(text[upstream - 1])) 848 while (upstream > 0 && isWhitespace(text[upstream - 1]))
838 upstream--; 849 upstream--;
839 850
840 int downstream = endOffset; 851 int downstream = endOffset;
841 while ((unsigned)downstream < text.length() && isWhitespace(text[downstream])) 852 while ((unsigned)downstream < text.length() && isWhitespace(text[downstream]))
842 downstream++; 853 downstream++;
843 854
844 int length = downstream - upstream; 855 int length = downstream - upstream;
845 if (!length) 856 if (!length)
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
1049 } 1060 }
1050 1061
1051 HTMLBRElement* CompositeEditCommand::appendBlockPlaceholder( 1062 HTMLBRElement* CompositeEditCommand::appendBlockPlaceholder(
1052 Element* container, 1063 Element* container,
1053 EditingState* editingState) { 1064 EditingState* editingState) {
1054 if (!container) 1065 if (!container)
1055 return nullptr; 1066 return nullptr;
1056 1067
1057 document().updateStyleAndLayoutIgnorePendingStylesheets(); 1068 document().updateStyleAndLayoutIgnorePendingStylesheets();
1058 1069
1059 // Should assert isLayoutBlockFlow || isInlineFlow when deletion improves. See 4244964. 1070 // Should assert isLayoutBlockFlow || isInlineFlow when deletion improves. See
1071 // 4244964.
1060 DCHECK(container->layoutObject()) << container; 1072 DCHECK(container->layoutObject()) << container;
1061 1073
1062 HTMLBRElement* placeholder = HTMLBRElement::create(document()); 1074 HTMLBRElement* placeholder = HTMLBRElement::create(document());
1063 appendNode(placeholder, container, editingState); 1075 appendNode(placeholder, container, editingState);
1064 if (editingState->isAborted()) 1076 if (editingState->isAborted())
1065 return nullptr; 1077 return nullptr;
1066 return placeholder; 1078 return placeholder;
1067 } 1079 }
1068 1080
1069 HTMLBRElement* CompositeEditCommand::insertBlockPlaceholder( 1081 HTMLBRElement* CompositeEditCommand::insertBlockPlaceholder(
1070 const Position& pos, 1082 const Position& pos,
1071 EditingState* editingState) { 1083 EditingState* editingState) {
1072 if (pos.isNull()) 1084 if (pos.isNull())
1073 return nullptr; 1085 return nullptr;
1074 1086
1075 // Should assert isLayoutBlockFlow || isInlineFlow when deletion improves. See 4244964. 1087 // Should assert isLayoutBlockFlow || isInlineFlow when deletion improves. See
1088 // 4244964.
1076 DCHECK(pos.anchorNode()->layoutObject()) << pos; 1089 DCHECK(pos.anchorNode()->layoutObject()) << pos;
1077 1090
1078 HTMLBRElement* placeholder = HTMLBRElement::create(document()); 1091 HTMLBRElement* placeholder = HTMLBRElement::create(document());
1079 insertNodeAt(placeholder, pos, editingState); 1092 insertNodeAt(placeholder, pos, editingState);
1080 if (editingState->isAborted()) 1093 if (editingState->isAborted())
1081 return nullptr; 1094 return nullptr;
1082 return placeholder; 1095 return placeholder;
1083 } 1096 }
1084 1097
1085 HTMLBRElement* CompositeEditCommand::addBlockPlaceholderIfNeeded( 1098 HTMLBRElement* CompositeEditCommand::addBlockPlaceholderIfNeeded(
(...skipping 11 matching lines...) Expand all
1097 // append the placeholder to make sure it follows 1110 // append the placeholder to make sure it follows
1098 // any unrendered blocks 1111 // any unrendered blocks
1099 LayoutBlockFlow* block = toLayoutBlockFlow(layoutObject); 1112 LayoutBlockFlow* block = toLayoutBlockFlow(layoutObject);
1100 if (block->size().height() == 0 || 1113 if (block->size().height() == 0 ||
1101 (block->isListItem() && toLayoutListItem(block)->isEmpty())) 1114 (block->isListItem() && toLayoutListItem(block)->isEmpty()))
1102 return appendBlockPlaceholder(container, editingState); 1115 return appendBlockPlaceholder(container, editingState);
1103 1116
1104 return nullptr; 1117 return nullptr;
1105 } 1118 }
1106 1119
1107 // Assumes that the position is at a placeholder and does the removal without mu ch checking. 1120 // Assumes that the position is at a placeholder and does the removal without
1121 // much checking.
1108 void CompositeEditCommand::removePlaceholderAt(const Position& p) { 1122 void CompositeEditCommand::removePlaceholderAt(const Position& p) {
1109 DCHECK(lineBreakExistsAtPosition(p)) << p; 1123 DCHECK(lineBreakExistsAtPosition(p)) << p;
1110 1124
1111 // We are certain that the position is at a line break, but it may be a br or a preserved newline. 1125 // We are certain that the position is at a line break, but it may be a br or
1126 // a preserved newline.
1112 if (isHTMLBRElement(*p.anchorNode())) { 1127 if (isHTMLBRElement(*p.anchorNode())) {
1113 // Removing a BR element won't dispatch synchronous events. 1128 // Removing a BR element won't dispatch synchronous events.
1114 removeNode(p.anchorNode(), ASSERT_NO_EDITING_ABORT); 1129 removeNode(p.anchorNode(), ASSERT_NO_EDITING_ABORT);
1115 return; 1130 return;
1116 } 1131 }
1117 1132
1118 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); 1133 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1);
1119 } 1134 }
1120 1135
1121 HTMLElement* CompositeEditCommand::insertNewDefaultParagraphElementAt( 1136 HTMLElement* CompositeEditCommand::insertNewDefaultParagraphElementAt(
1122 const Position& position, 1137 const Position& position,
1123 EditingState* editingState) { 1138 EditingState* editingState) {
1124 HTMLElement* paragraphElement = createDefaultParagraphElement(document()); 1139 HTMLElement* paragraphElement = createDefaultParagraphElement(document());
1125 paragraphElement->appendChild(HTMLBRElement::create(document())); 1140 paragraphElement->appendChild(HTMLBRElement::create(document()));
1126 insertNodeAt(paragraphElement, position, editingState); 1141 insertNodeAt(paragraphElement, position, editingState);
1127 if (editingState->isAborted()) 1142 if (editingState->isAborted())
1128 return nullptr; 1143 return nullptr;
1129 return paragraphElement; 1144 return paragraphElement;
1130 } 1145 }
1131 1146
1132 // If the paragraph is not entirely within it's own block, create one and move t he paragraph into 1147 // If the paragraph is not entirely within it's own block, create one and move
1133 // it, and return that block. Otherwise return 0. 1148 // the paragraph into it, and return that block. Otherwise return 0.
1134 HTMLElement* CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary( 1149 HTMLElement* CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary(
1135 const Position& pos, 1150 const Position& pos,
1136 EditingState* editingState) { 1151 EditingState* editingState) {
1137 DCHECK(isEditablePosition(pos)) << pos; 1152 DCHECK(isEditablePosition(pos)) << pos;
1138 1153
1139 // It's strange that this function is responsible for verifying that pos has n ot been invalidated 1154 // It's strange that this function is responsible for verifying that pos has
1140 // by an earlier call to this function. The caller, applyBlockStyle, should d o this. 1155 // not been invalidated by an earlier call to this function. The caller,
1156 // applyBlockStyle, should do this.
1141 VisiblePosition visiblePos = 1157 VisiblePosition visiblePos =
1142 createVisiblePositionDeprecated(pos, VP_DEFAULT_AFFINITY); 1158 createVisiblePositionDeprecated(pos, VP_DEFAULT_AFFINITY);
1143 VisiblePosition visibleParagraphStart = 1159 VisiblePosition visibleParagraphStart =
1144 startOfParagraphDeprecated(visiblePos); 1160 startOfParagraphDeprecated(visiblePos);
1145 VisiblePosition visibleParagraphEnd = endOfParagraphDeprecated(visiblePos); 1161 VisiblePosition visibleParagraphEnd = endOfParagraphDeprecated(visiblePos);
1146 VisiblePosition next = nextPositionOf(visibleParagraphEnd); 1162 VisiblePosition next = nextPositionOf(visibleParagraphEnd);
1147 VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd; 1163 VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd;
1148 1164
1149 Position upstreamStart = 1165 Position upstreamStart =
1150 mostBackwardCaretPosition(visibleParagraphStart.deepEquivalent()); 1166 mostBackwardCaretPosition(visibleParagraphStart.deepEquivalent());
1151 Position upstreamEnd = mostBackwardCaretPosition(visibleEnd.deepEquivalent()); 1167 Position upstreamEnd = mostBackwardCaretPosition(visibleEnd.deepEquivalent());
1152 1168
1153 // If there are no VisiblePositions in the same block as pos then 1169 // If there are no VisiblePositions in the same block as pos then
1154 // upstreamStart will be outside the paragraph 1170 // upstreamStart will be outside the paragraph
1155 if (comparePositions(pos, upstreamStart) < 0) 1171 if (comparePositions(pos, upstreamStart) < 0)
1156 return nullptr; 1172 return nullptr;
1157 1173
1158 // Perform some checks to see if we need to perform work in this function. 1174 // Perform some checks to see if we need to perform work in this function.
1159 if (isEnclosingBlock(upstreamStart.anchorNode())) { 1175 if (isEnclosingBlock(upstreamStart.anchorNode())) {
1160 // If the block is the root editable element, always move content to a new b lock, 1176 // If the block is the root editable element, always move content to a new
1161 // since it is illegal to modify attributes on the root editable element for editing. 1177 // block, since it is illegal to modify attributes on the root editable
1178 // element for editing.
1162 if (upstreamStart.anchorNode() == rootEditableElementOf(upstreamStart)) { 1179 if (upstreamStart.anchorNode() == rootEditableElementOf(upstreamStart)) {
1163 // If the block is the root editable element and it contains no visible co ntent, create a new 1180 // If the block is the root editable element and it contains no visible
1164 // block but don't try and move content into it, since there's nothing for moveParagraphs to move. 1181 // content, create a new block but don't try and move content into it,
1182 // since there's nothing for moveParagraphs to move.
1165 if (!hasRenderedNonAnonymousDescendantsWithHeight( 1183 if (!hasRenderedNonAnonymousDescendantsWithHeight(
1166 upstreamStart.anchorNode()->layoutObject())) 1184 upstreamStart.anchorNode()->layoutObject()))
1167 return insertNewDefaultParagraphElementAt(upstreamStart, editingState); 1185 return insertNewDefaultParagraphElementAt(upstreamStart, editingState);
1168 } else if (isEnclosingBlock(upstreamEnd.anchorNode())) { 1186 } else if (isEnclosingBlock(upstreamEnd.anchorNode())) {
1169 if (!upstreamEnd.anchorNode()->isDescendantOf( 1187 if (!upstreamEnd.anchorNode()->isDescendantOf(
1170 upstreamStart.anchorNode())) { 1188 upstreamStart.anchorNode())) {
1171 // If the paragraph end is a descendant of paragraph start, then we need to run 1189 // If the paragraph end is a descendant of paragraph start, then we need
1172 // the rest of this function. If not, we can bail here. 1190 // to run the rest of this function. If not, we can bail here.
1173 return nullptr; 1191 return nullptr;
1174 } 1192 }
1175 } else if (enclosingBlock(upstreamEnd.anchorNode()) != 1193 } else if (enclosingBlock(upstreamEnd.anchorNode()) !=
1176 upstreamStart.anchorNode()) { 1194 upstreamStart.anchorNode()) {
1177 // It should be an ancestor of the paragraph start. 1195 // It should be an ancestor of the paragraph start.
1178 // We can bail as we have a full block to work with. 1196 // We can bail as we have a full block to work with.
1179 return nullptr; 1197 return nullptr;
1180 } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) { 1198 } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) {
1181 // At the end of the editable region. We can bail here as well. 1199 // At the end of the editable region. We can bail here as well.
1182 return nullptr; 1200 return nullptr;
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1297 outerNode = outerNode->parentNode(); 1315 outerNode = outerNode->parentNode();
1298 } 1316 }
1299 1317
1300 if (!outerNode) 1318 if (!outerNode)
1301 return; 1319 return;
1302 1320
1303 Node* startNode = start.anchorNode(); 1321 Node* startNode = start.anchorNode();
1304 for (Node* node = 1322 for (Node* node =
1305 NodeTraversal::nextSkippingChildren(*startNode, outerNode); 1323 NodeTraversal::nextSkippingChildren(*startNode, outerNode);
1306 node; node = NodeTraversal::nextSkippingChildren(*node, outerNode)) { 1324 node; node = NodeTraversal::nextSkippingChildren(*node, outerNode)) {
1307 // Move lastNode up in the tree as much as node was moved up in the 1325 // Move lastNode up in the tree as much as node was moved up in the tree
1308 // tree by NodeTraversal::nextSkippingChildren, so that the relative depth between 1326 // by NodeTraversal::nextSkippingChildren, so that the relative depth
1309 // node and the original start node is maintained in the clone. 1327 // between node and the original start node is maintained in the clone.
1310 while (startNode && lastNode && 1328 while (startNode && lastNode &&
1311 startNode->parentNode() != node->parentNode()) { 1329 startNode->parentNode() != node->parentNode()) {
1312 startNode = startNode->parentNode(); 1330 startNode = startNode->parentNode();
1313 lastNode = lastNode->parentNode(); 1331 lastNode = lastNode->parentNode();
1314 } 1332 }
1315 1333
1316 if (!lastNode || !lastNode->parentNode()) 1334 if (!lastNode || !lastNode->parentNode())
1317 return; 1335 return;
1318 1336
1319 Node* clonedNode = node->cloneNode(true); 1337 Node* clonedNode = node->cloneNode(true);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1371 Text* textNode = toText(node); 1389 Text* textNode = toText(node);
1372 if (textNode->length() == 1) 1390 if (textNode->length() == 1)
1373 removeNodeAndPruneAncestors(node, editingState, destinationNode); 1391 removeNodeAndPruneAncestors(node, editingState, destinationNode);
1374 else 1392 else
1375 deleteTextFromNode(textNode, position.computeOffsetInContainerNode(), 1393 deleteTextFromNode(textNode, position.computeOffsetInContainerNode(),
1376 1); 1394 1);
1377 } 1395 }
1378 } 1396 }
1379 } 1397 }
1380 1398
1381 // This is a version of moveParagraph that preserves style by keeping the origin al markup 1399 // This is a version of moveParagraph that preserves style by keeping the
1382 // It is currently used only by IndentOutdentCommand but it is meant to be used in the 1400 // original markup. It is currently used only by IndentOutdentCommand but it is
1383 // future by several other commands such as InsertList and the align commands. 1401 // meant to be used in the future by several other commands such as InsertList
1384 // The blockElement parameter is the element to move the paragraph to, 1402 // and the align commands.
1385 // outerNode is the top element of the paragraph hierarchy. 1403 // The blockElement parameter is the element to move the paragraph to, outerNode
1404 // is the top element of the paragraph hierarchy.
1386 1405
1387 void CompositeEditCommand::moveParagraphWithClones( 1406 void CompositeEditCommand::moveParagraphWithClones(
1388 const VisiblePosition& startOfParagraphToMove, 1407 const VisiblePosition& startOfParagraphToMove,
1389 const VisiblePosition& endOfParagraphToMove, 1408 const VisiblePosition& endOfParagraphToMove,
1390 HTMLElement* blockElement, 1409 HTMLElement* blockElement,
1391 Node* outerNode, 1410 Node* outerNode,
1392 EditingState* editingState) { 1411 EditingState* editingState) {
1393 DCHECK(outerNode); 1412 DCHECK(outerNode);
1394 DCHECK(blockElement); 1413 DCHECK(blockElement);
1395 1414
1396 VisiblePosition beforeParagraph = previousPositionOf(startOfParagraphToMove); 1415 VisiblePosition beforeParagraph = previousPositionOf(startOfParagraphToMove);
1397 VisiblePosition afterParagraph = nextPositionOf(endOfParagraphToMove); 1416 VisiblePosition afterParagraph = nextPositionOf(endOfParagraphToMove);
1398 1417
1399 // We upstream() the end and downstream() the start so that we don't include c ollapsed whitespace in the move. 1418 // We upstream() the end and downstream() the start so that we don't include
1400 // When we paste a fragment, spaces after the end and before the start are tre ated as though they were rendered. 1419 // collapsed whitespace in the move. When we paste a fragment, spaces after
1420 // the end and before the start are treated as though they were rendered.
1401 Position start = 1421 Position start =
1402 mostForwardCaretPosition(startOfParagraphToMove.deepEquivalent()); 1422 mostForwardCaretPosition(startOfParagraphToMove.deepEquivalent());
1403 Position end = 1423 Position end =
1404 startOfParagraphToMove.deepEquivalent() == 1424 startOfParagraphToMove.deepEquivalent() ==
1405 endOfParagraphToMove.deepEquivalent() 1425 endOfParagraphToMove.deepEquivalent()
1406 ? start 1426 ? start
1407 : mostBackwardCaretPosition(endOfParagraphToMove.deepEquivalent()); 1427 : mostBackwardCaretPosition(endOfParagraphToMove.deepEquivalent());
1408 if (comparePositions(start, end) > 0) 1428 if (comparePositions(start, end) > 0)
1409 end = start; 1429 end = start;
1410 1430
1411 cloneParagraphUnderNewElement(start, end, outerNode, blockElement, 1431 cloneParagraphUnderNewElement(start, end, outerNode, blockElement,
1412 editingState); 1432 editingState);
1413 1433
1414 setEndingSelection(createVisibleSelectionDeprecated(start, end)); 1434 setEndingSelection(createVisibleSelectionDeprecated(start, end));
1415 deleteSelection(editingState, false, false, false); 1435 deleteSelection(editingState, false, false, false);
1416 if (editingState->isAborted()) 1436 if (editingState->isAborted())
1417 return; 1437 return;
1418 1438
1419 // There are bugs in deletion when it removes a fully selected table/list. 1439 // There are bugs in deletion when it removes a fully selected table/list.
1420 // It expands and removes the entire table/list, but will let content 1440 // It expands and removes the entire table/list, but will let content
1421 // before and after the table/list collapse onto one line. 1441 // before and after the table/list collapse onto one line.
1422 1442
1423 cleanupAfterDeletion(editingState); 1443 cleanupAfterDeletion(editingState);
1424 if (editingState->isAborted()) 1444 if (editingState->isAborted())
1425 return; 1445 return;
1426 1446
1427 // Add a br if pruning an empty block level element caused a collapse. For ex ample: 1447 // Add a br if pruning an empty block level element caused a collapse. For
1448 // example:
1428 // foo^ 1449 // foo^
1429 // <div>bar</div> 1450 // <div>bar</div>
1430 // baz 1451 // baz
1431 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That would 1452 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That
1432 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br. 1453 // would cause 'baz' to collapse onto the line with 'foobar' unless we insert
1433 // Must recononicalize these two VisiblePositions after the pruning above. 1454 // a br. Must recononicalize these two VisiblePositions after the pruning
1455 // above.
1434 // TODO(yosin): We should abort when |beforeParagraph| is a orphan when 1456 // TODO(yosin): We should abort when |beforeParagraph| is a orphan when
1435 // we have a sample. 1457 // we have a sample.
1436 beforeParagraph = 1458 beforeParagraph =
1437 createVisiblePositionDeprecated(beforeParagraph.deepEquivalent()); 1459 createVisiblePositionDeprecated(beforeParagraph.deepEquivalent());
1438 if (afterParagraph.isOrphan()) { 1460 if (afterParagraph.isOrphan()) {
1439 editingState->abort(); 1461 editingState->abort();
1440 return; 1462 return;
1441 } 1463 }
1442 afterParagraph = 1464 afterParagraph =
1443 createVisiblePositionDeprecated(afterParagraph.deepEquivalent()); 1465 createVisiblePositionDeprecated(afterParagraph.deepEquivalent());
1444 1466
1445 if (beforeParagraph.isNotNull() && 1467 if (beforeParagraph.isNotNull() &&
1446 !isDisplayInsideTable(beforeParagraph.deepEquivalent().anchorNode()) && 1468 !isDisplayInsideTable(beforeParagraph.deepEquivalent().anchorNode()) &&
1447 ((!isEndOfParagraphDeprecated(beforeParagraph) && 1469 ((!isEndOfParagraphDeprecated(beforeParagraph) &&
1448 !isStartOfParagraphDeprecated(beforeParagraph)) || 1470 !isStartOfParagraphDeprecated(beforeParagraph)) ||
1449 beforeParagraph.deepEquivalent() == afterParagraph.deepEquivalent())) { 1471 beforeParagraph.deepEquivalent() == afterParagraph.deepEquivalent())) {
1450 // FIXME: Trim text between beforeParagraph and afterParagraph if they aren' t equal. 1472 // FIXME: Trim text between beforeParagraph and afterParagraph if they
1473 // aren't equal.
1451 insertNodeAt(HTMLBRElement::create(document()), 1474 insertNodeAt(HTMLBRElement::create(document()),
1452 beforeParagraph.deepEquivalent(), editingState); 1475 beforeParagraph.deepEquivalent(), editingState);
1453 } 1476 }
1454 } 1477 }
1455 1478
1456 void CompositeEditCommand::moveParagraph( 1479 void CompositeEditCommand::moveParagraph(
1457 const VisiblePosition& startOfParagraphToMove, 1480 const VisiblePosition& startOfParagraphToMove,
1458 const VisiblePosition& endOfParagraphToMove, 1481 const VisiblePosition& endOfParagraphToMove,
1459 const VisiblePosition& destination, 1482 const VisiblePosition& destination,
1460 EditingState* editingState, 1483 EditingState* editingState,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1520 } 1543 }
1521 1544
1522 RelocatablePosition beforeParagraphPosition( 1545 RelocatablePosition beforeParagraphPosition(
1523 previousPositionOfDeprecated(startOfParagraphToMove, 1546 previousPositionOfDeprecated(startOfParagraphToMove,
1524 CannotCrossEditingBoundary) 1547 CannotCrossEditingBoundary)
1525 .deepEquivalent()); 1548 .deepEquivalent());
1526 RelocatablePosition afterParagraphPosition( 1549 RelocatablePosition afterParagraphPosition(
1527 nextPositionOfDeprecated(endOfParagraphToMove, CannotCrossEditingBoundary) 1550 nextPositionOfDeprecated(endOfParagraphToMove, CannotCrossEditingBoundary)
1528 .deepEquivalent()); 1551 .deepEquivalent());
1529 1552
1530 // We upstream() the end and downstream() the start so that we don't include c ollapsed whitespace in the move. 1553 // We upstream() the end and downstream() the start so that we don't include
1531 // When we paste a fragment, spaces after the end and before the start are tre ated as though they were rendered. 1554 // collapsed whitespace in the move. When we paste a fragment, spaces after
1555 // the end and before the start are treated as though they were rendered.
1532 Position start = 1556 Position start =
1533 mostForwardCaretPosition(startOfParagraphToMove.deepEquivalent()); 1557 mostForwardCaretPosition(startOfParagraphToMove.deepEquivalent());
1534 Position end = 1558 Position end =
1535 mostBackwardCaretPosition(endOfParagraphToMove.deepEquivalent()); 1559 mostBackwardCaretPosition(endOfParagraphToMove.deepEquivalent());
1536 1560
1537 // FIXME: This is an inefficient way to preserve style on nodes in the paragra ph to move. It 1561 // FIXME: This is an inefficient way to preserve style on nodes in the
1538 // shouldn't matter though, since moved paragraphs will usually be quite small . 1562 // paragraph to move. It shouldn't matter though, since moved paragraphs will
1563 // usually be quite small.
1539 DocumentFragment* fragment = 1564 DocumentFragment* fragment =
1540 startOfParagraphToMove.deepEquivalent() != 1565 startOfParagraphToMove.deepEquivalent() !=
1541 endOfParagraphToMove.deepEquivalent() 1566 endOfParagraphToMove.deepEquivalent()
1542 ? createFragmentFromMarkup( 1567 ? createFragmentFromMarkup(
1543 document(), 1568 document(),
1544 createMarkup(start.parentAnchoredEquivalent(), 1569 createMarkup(start.parentAnchoredEquivalent(),
1545 end.parentAnchoredEquivalent(), 1570 end.parentAnchoredEquivalent(),
1546 DoNotAnnotateForInterchange, 1571 DoNotAnnotateForInterchange,
1547 ConvertBlocksToInlines::Convert, DoNotResolveURLs, 1572 ConvertBlocksToInlines::Convert, DoNotResolveURLs,
1548 constrainingAncestor), 1573 constrainingAncestor),
1549 "") 1574 "")
1550 : nullptr; 1575 : nullptr;
1551 1576
1552 // A non-empty paragraph's style is moved when we copy and move it. We don't move 1577 // A non-empty paragraph's style is moved when we copy and move it. We don't
1553 // anything if we're given an empty paragraph, but an empty paragraph can have style 1578 // move anything if we're given an empty paragraph, but an empty paragraph can
1554 // too, <div><b><br></b></div> for example. Save it so that we can preserve i t later. 1579 // have style too, <div><b><br></b></div> for example. Save it so that we can
1580 // preserve it later.
1555 EditingStyle* styleInEmptyParagraph = nullptr; 1581 EditingStyle* styleInEmptyParagraph = nullptr;
1556 if (startOfParagraphToMove.deepEquivalent() == 1582 if (startOfParagraphToMove.deepEquivalent() ==
1557 endOfParagraphToMove.deepEquivalent() && 1583 endOfParagraphToMove.deepEquivalent() &&
1558 shouldPreserveStyle == PreserveStyle) { 1584 shouldPreserveStyle == PreserveStyle) {
1559 styleInEmptyParagraph = 1585 styleInEmptyParagraph =
1560 EditingStyle::create(startOfParagraphToMove.deepEquivalent()); 1586 EditingStyle::create(startOfParagraphToMove.deepEquivalent());
1561 styleInEmptyParagraph->mergeTypingStyle(&document()); 1587 styleInEmptyParagraph->mergeTypingStyle(&document());
1562 // The moved paragraph should assume the block style of the destination. 1588 // The moved paragraph should assume the block style of the destination.
1563 styleInEmptyParagraph->removeBlockProperties(); 1589 styleInEmptyParagraph->removeBlockProperties();
1564 } 1590 }
1565 1591
1566 // FIXME (5098931): We should add a new insert action "WebViewInsertActionMove d" and call shouldInsertFragment here. 1592 // FIXME (5098931): We should add a new insert action
1593 // "WebViewInsertActionMoved" and call shouldInsertFragment here.
1567 1594
1568 setEndingSelection(createVisibleSelectionDeprecated(start, end)); 1595 setEndingSelection(createVisibleSelectionDeprecated(start, end));
1569 document() 1596 document()
1570 .frame() 1597 .frame()
1571 ->spellChecker() 1598 ->spellChecker()
1572 .clearMisspellingsAndBadGrammarForMovingParagraphs(endingSelection()); 1599 .clearMisspellingsAndBadGrammarForMovingParagraphs(endingSelection());
1573 deleteSelection(editingState, false, false, false); 1600 deleteSelection(editingState, false, false, false);
1574 if (editingState->isAborted()) 1601 if (editingState->isAborted())
1575 return; 1602 return;
1576 1603
1577 DCHECK(destination.deepEquivalent().isConnected()) << destination; 1604 DCHECK(destination.deepEquivalent().isConnected()) << destination;
1578 cleanupAfterDeletion(editingState, destination); 1605 cleanupAfterDeletion(editingState, destination);
1579 if (editingState->isAborted()) 1606 if (editingState->isAborted())
1580 return; 1607 return;
1581 DCHECK(destination.deepEquivalent().isConnected()) << destination; 1608 DCHECK(destination.deepEquivalent().isConnected()) << destination;
1582 1609
1583 // Add a br if pruning an empty block level element caused a collapse. For exa mple: 1610 // Add a br if pruning an empty block level element caused a collapse. For
1611 // example:
1584 // foo^ 1612 // foo^
1585 // <div>bar</div> 1613 // <div>bar</div>
1586 // baz 1614 // baz
1587 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That w ould 1615 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That
1588 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br. 1616 // would cause 'baz' to collapse onto the line with 'foobar' unless we insert
1589 // Must recononicalize these two VisiblePositions after the pruning above. 1617 // a br. Must recononicalize these two VisiblePositions after the pruning
1618 // above.
1590 VisiblePosition beforeParagraph = 1619 VisiblePosition beforeParagraph =
1591 createVisiblePositionDeprecated(beforeParagraphPosition.position()); 1620 createVisiblePositionDeprecated(beforeParagraphPosition.position());
1592 VisiblePosition afterParagraph = 1621 VisiblePosition afterParagraph =
1593 createVisiblePositionDeprecated(afterParagraphPosition.position()); 1622 createVisiblePositionDeprecated(afterParagraphPosition.position());
1594 if (beforeParagraph.isNotNull() && 1623 if (beforeParagraph.isNotNull() &&
1595 (!isEndOfParagraphDeprecated(beforeParagraph) || 1624 (!isEndOfParagraphDeprecated(beforeParagraph) ||
1596 beforeParagraph.deepEquivalent() == afterParagraph.deepEquivalent())) { 1625 beforeParagraph.deepEquivalent() == afterParagraph.deepEquivalent())) {
1597 // FIXME: Trim text between beforeParagraph and afterParagraph if they aren' t equal. 1626 // FIXME: Trim text between beforeParagraph and afterParagraph if they
1627 // aren't equal.
1598 insertNodeAt(HTMLBRElement::create(document()), 1628 insertNodeAt(HTMLBRElement::create(document()),
1599 beforeParagraph.deepEquivalent(), editingState); 1629 beforeParagraph.deepEquivalent(), editingState);
1600 if (editingState->isAborted()) 1630 if (editingState->isAborted())
1601 return; 1631 return;
1602 // Need an updateLayout here in case inserting the br has split a text node. 1632 // Need an updateLayout here in case inserting the br has split a text node.
1603 document().updateStyleAndLayoutIgnorePendingStylesheets(); 1633 document().updateStyleAndLayoutIgnorePendingStylesheets();
1604 } 1634 }
1605 1635
1606 destinationIndex = TextIterator::rangeLength( 1636 destinationIndex = TextIterator::rangeLength(
1607 Position::firstPositionInNode(document().documentElement()), 1637 Position::firstPositionInNode(document().documentElement()),
(...skipping 16 matching lines...) Expand all
1624 ReplaceSelectionCommand::create(document(), fragment, options), 1654 ReplaceSelectionCommand::create(document(), fragment, options),
1625 editingState); 1655 editingState);
1626 if (editingState->isAborted()) 1656 if (editingState->isAborted())
1627 return; 1657 return;
1628 1658
1629 document() 1659 document()
1630 .frame() 1660 .frame()
1631 ->spellChecker() 1661 ->spellChecker()
1632 .markMisspellingsAndBadGrammarForMovingParagraphs(endingSelection()); 1662 .markMisspellingsAndBadGrammarForMovingParagraphs(endingSelection());
1633 1663
1634 // If the selection is in an empty paragraph, restore styles from the old empt y paragraph to the new empty paragraph. 1664 // If the selection is in an empty paragraph, restore styles from the old
1665 // empty paragraph to the new empty paragraph.
1635 bool selectionIsEmptyParagraph = 1666 bool selectionIsEmptyParagraph =
1636 endingSelection().isCaret() && 1667 endingSelection().isCaret() &&
1637 isStartOfParagraphDeprecated( 1668 isStartOfParagraphDeprecated(
1638 endingSelection().visibleStartDeprecated()) && 1669 endingSelection().visibleStartDeprecated()) &&
1639 isEndOfParagraphDeprecated(endingSelection().visibleStartDeprecated()); 1670 isEndOfParagraphDeprecated(endingSelection().visibleStartDeprecated());
1640 if (styleInEmptyParagraph && selectionIsEmptyParagraph) { 1671 if (styleInEmptyParagraph && selectionIsEmptyParagraph) {
1641 applyStyle(styleInEmptyParagraph, editingState); 1672 applyStyle(styleInEmptyParagraph, editingState);
1642 if (editingState->isAborted()) 1673 if (editingState->isAborted())
1643 return; 1674 return;
1644 } 1675 }
(...skipping 29 matching lines...) Expand all
1674 bool CompositeEditCommand::breakOutOfEmptyListItem(EditingState* editingState) { 1705 bool CompositeEditCommand::breakOutOfEmptyListItem(EditingState* editingState) {
1675 Node* emptyListItem = 1706 Node* emptyListItem =
1676 enclosingEmptyListItem(endingSelection().visibleStartDeprecated()); 1707 enclosingEmptyListItem(endingSelection().visibleStartDeprecated());
1677 if (!emptyListItem) 1708 if (!emptyListItem)
1678 return false; 1709 return false;
1679 1710
1680 EditingStyle* style = EditingStyle::create(endingSelection().start()); 1711 EditingStyle* style = EditingStyle::create(endingSelection().start());
1681 style->mergeTypingStyle(&document()); 1712 style->mergeTypingStyle(&document());
1682 1713
1683 ContainerNode* listNode = emptyListItem->parentNode(); 1714 ContainerNode* listNode = emptyListItem->parentNode();
1684 // FIXME: Can't we do something better when the immediate parent wasn't a list node? 1715 // FIXME: Can't we do something better when the immediate parent wasn't a list
1716 // node?
1685 if (!listNode || 1717 if (!listNode ||
1686 (!isHTMLUListElement(*listNode) && !isHTMLOListElement(*listNode)) || 1718 (!isHTMLUListElement(*listNode) && !isHTMLOListElement(*listNode)) ||
1687 !hasEditableStyle(*listNode) || 1719 !hasEditableStyle(*listNode) ||
1688 listNode == rootEditableElement(*emptyListItem)) 1720 listNode == rootEditableElement(*emptyListItem))
1689 return false; 1721 return false;
1690 1722
1691 HTMLElement* newBlock = nullptr; 1723 HTMLElement* newBlock = nullptr;
1692 if (ContainerNode* blockEnclosingList = listNode->parentNode()) { 1724 if (ContainerNode* blockEnclosingList = listNode->parentNode()) {
1693 if (isHTMLLIElement( 1725 if (isHTMLLIElement(
1694 *blockEnclosingList)) { // listNode is inside another list item 1726 *blockEnclosingList)) { // listNode is inside another list item
1695 if (visiblePositionAfterNode(*blockEnclosingList).deepEquivalent() == 1727 if (visiblePositionAfterNode(*blockEnclosingList).deepEquivalent() ==
1696 visiblePositionAfterNode(*listNode).deepEquivalent()) { 1728 visiblePositionAfterNode(*listNode).deepEquivalent()) {
1697 // If listNode appears at the end of the outer list item, then move list Node outside of this list item 1729 // If listNode appears at the end of the outer list item, then move
1698 // e.g. <ul><li>hello <ul><li><br></li></ul> </li></ul> should become <u l><li>hello</li> <ul><li><br></li></ul> </ul> after this section 1730 // listNode outside of this list item, e.g.
1699 // If listNode does NOT appear at the end, then we should consider it as a regular paragraph. 1731 // <ul><li>hello <ul><li><br></li></ul> </li></ul>
1700 // e.g. <ul><li> <ul><li><br></li></ul> hello</li></ul> should become <u l><li> <div><br></div> hello</li></ul> at the end 1732 // should become
1733 // <ul><li>hello</li> <ul><li><br></li></ul> </ul>
1734 // after this section.
1735 //
1736 // If listNode does NOT appear at the end, then we should consider it as
1737 // a regular paragraph, e.g.
1738 // <ul><li> <ul><li><br></li></ul> hello</li></ul>
1739 // should become
1740 // <ul><li> <div><br></div> hello</li></ul>
1741 // at the end
1701 splitElement(toElement(blockEnclosingList), listNode); 1742 splitElement(toElement(blockEnclosingList), listNode);
1702 removeNodePreservingChildren(listNode->parentNode(), editingState); 1743 removeNodePreservingChildren(listNode->parentNode(), editingState);
1703 if (editingState->isAborted()) 1744 if (editingState->isAborted())
1704 return false; 1745 return false;
1705 newBlock = HTMLLIElement::create(document()); 1746 newBlock = HTMLLIElement::create(document());
1706 } 1747 }
1707 // If listNode does NOT appear at the end of the outer list item, then beh ave as if in a regular paragraph. 1748 // If listNode does NOT appear at the end of the outer list item, then
1749 // behave as if in a regular paragraph.
1708 } else if (isHTMLOListElement(*blockEnclosingList) || 1750 } else if (isHTMLOListElement(*blockEnclosingList) ||
1709 isHTMLUListElement(*blockEnclosingList)) { 1751 isHTMLUListElement(*blockEnclosingList)) {
1710 newBlock = HTMLLIElement::create(document()); 1752 newBlock = HTMLLIElement::create(document());
1711 } 1753 }
1712 } 1754 }
1713 if (!newBlock) 1755 if (!newBlock)
1714 newBlock = createDefaultParagraphElement(document()); 1756 newBlock = createDefaultParagraphElement(document());
1715 1757
1716 Node* previousListNode = 1758 Node* previousListNode =
1717 emptyListItem->isElementNode() 1759 emptyListItem->isElementNode()
1718 ? ElementTraversal::previousSibling(*emptyListItem) 1760 ? ElementTraversal::previousSibling(*emptyListItem)
1719 : emptyListItem->previousSibling(); 1761 : emptyListItem->previousSibling();
1720 Node* nextListNode = emptyListItem->isElementNode() 1762 Node* nextListNode = emptyListItem->isElementNode()
1721 ? ElementTraversal::nextSibling(*emptyListItem) 1763 ? ElementTraversal::nextSibling(*emptyListItem)
1722 : emptyListItem->nextSibling(); 1764 : emptyListItem->nextSibling();
1723 if (isListItem(nextListNode) || isHTMLListElement(nextListNode)) { 1765 if (isListItem(nextListNode) || isHTMLListElement(nextListNode)) {
1724 // If emptyListItem follows another list item or nested list, split the list node. 1766 // If emptyListItem follows another list item or nested list, split the list
1767 // node.
1725 if (isListItem(previousListNode) || isHTMLListElement(previousListNode)) 1768 if (isListItem(previousListNode) || isHTMLListElement(previousListNode))
1726 splitElement(toElement(listNode), emptyListItem); 1769 splitElement(toElement(listNode), emptyListItem);
1727 1770
1728 // If emptyListItem is followed by other list item or nested list, then inse rt newBlock before the list node. 1771 // If emptyListItem is followed by other list item or nested list, then
1729 // Because we have splitted the element, emptyListItem is the first element in the list node. 1772 // insert newBlock before the list node. Because we have splitted the
1773 // element, emptyListItem is the first element in the list node.
1730 // i.e. insert newBlock before ul or ol whose first element is emptyListItem 1774 // i.e. insert newBlock before ul or ol whose first element is emptyListItem
1731 insertNodeBefore(newBlock, listNode, editingState); 1775 insertNodeBefore(newBlock, listNode, editingState);
1732 if (editingState->isAborted()) 1776 if (editingState->isAborted())
1733 return false; 1777 return false;
1734 removeNode(emptyListItem, editingState); 1778 removeNode(emptyListItem, editingState);
1735 if (editingState->isAborted()) 1779 if (editingState->isAborted())
1736 return false; 1780 return false;
1737 } else { 1781 } else {
1738 // When emptyListItem does not follow any list item or nested list, insert n ewBlock after the enclosing list node. 1782 // When emptyListItem does not follow any list item or nested list, insert
1739 // Remove the enclosing node if emptyListItem is the only child; otherwise j ust remove emptyListItem. 1783 // newBlock after the enclosing list node. Remove the enclosing node if
1784 // emptyListItem is the only child; otherwise just remove emptyListItem.
1740 insertNodeAfter(newBlock, listNode, editingState); 1785 insertNodeAfter(newBlock, listNode, editingState);
1741 if (editingState->isAborted()) 1786 if (editingState->isAborted())
1742 return false; 1787 return false;
1743 removeNode( 1788 removeNode(
1744 isListItem(previousListNode) || isHTMLListElement(previousListNode) 1789 isListItem(previousListNode) || isHTMLListElement(previousListNode)
1745 ? emptyListItem 1790 ? emptyListItem
1746 : listNode, 1791 : listNode,
1747 editingState); 1792 editingState);
1748 if (editingState->isAborted()) 1793 if (editingState->isAborted())
1749 return false; 1794 return false;
1750 } 1795 }
1751 1796
1752 appendBlockPlaceholder(newBlock, editingState); 1797 appendBlockPlaceholder(newBlock, editingState);
1753 if (editingState->isAborted()) 1798 if (editingState->isAborted())
1754 return false; 1799 return false;
1755 setEndingSelection(createVisibleSelectionDeprecated( 1800 setEndingSelection(createVisibleSelectionDeprecated(
1756 Position::firstPositionInNode(newBlock), TextAffinity::Downstream, 1801 Position::firstPositionInNode(newBlock), TextAffinity::Downstream,
1757 endingSelection().isDirectional())); 1802 endingSelection().isDirectional()));
1758 1803
1759 style->prepareToApplyAt(endingSelection().start()); 1804 style->prepareToApplyAt(endingSelection().start());
1760 if (!style->isEmpty()) { 1805 if (!style->isEmpty()) {
1761 applyStyle(style, editingState); 1806 applyStyle(style, editingState);
1762 if (editingState->isAborted()) 1807 if (editingState->isAborted())
1763 return false; 1808 return false;
1764 } 1809 }
1765 1810
1766 return true; 1811 return true;
1767 } 1812 }
1768 1813
1769 // If the caret is in an empty quoted paragraph, and either there is nothing bef ore that 1814 // If the caret is in an empty quoted paragraph, and either there is nothing
1770 // paragraph, or what is before is unquoted, and the user presses delete, unquot e that paragraph. 1815 // before that paragraph, or what is before is unquoted, and the user presses
1816 // delete, unquote that paragraph.
1771 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph( 1817 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph(
1772 EditingState* editingState) { 1818 EditingState* editingState) {
1773 if (!endingSelection().isCaret()) 1819 if (!endingSelection().isCaret())
1774 return false; 1820 return false;
1775 1821
1776 VisiblePosition caret = endingSelection().visibleStartDeprecated(); 1822 VisiblePosition caret = endingSelection().visibleStartDeprecated();
1777 HTMLQuoteElement* highestBlockquote = 1823 HTMLQuoteElement* highestBlockquote =
1778 toHTMLQuoteElement(highestEnclosingNodeOfType( 1824 toHTMLQuoteElement(highestEnclosingNodeOfType(
1779 caret.deepEquivalent(), &isMailHTMLBlockquoteElement)); 1825 caret.deepEquivalent(), &isMailHTMLBlockquoteElement));
1780 if (!highestBlockquote) 1826 if (!highestBlockquote)
1781 return false; 1827 return false;
1782 1828
1783 if (!isStartOfParagraphDeprecated(caret) || 1829 if (!isStartOfParagraphDeprecated(caret) ||
1784 !isEndOfParagraphDeprecated(caret)) 1830 !isEndOfParagraphDeprecated(caret))
1785 return false; 1831 return false;
1786 1832
1787 VisiblePosition previous = 1833 VisiblePosition previous =
1788 previousPositionOf(caret, CannotCrossEditingBoundary); 1834 previousPositionOf(caret, CannotCrossEditingBoundary);
1789 // Only move forward if there's nothing before the caret, or if there's unquot ed content before it. 1835 // Only move forward if there's nothing before the caret, or if there's
1836 // unquoted content before it.
1790 if (enclosingNodeOfType(previous.deepEquivalent(), 1837 if (enclosingNodeOfType(previous.deepEquivalent(),
1791 &isMailHTMLBlockquoteElement)) 1838 &isMailHTMLBlockquoteElement))
1792 return false; 1839 return false;
1793 1840
1794 HTMLBRElement* br = HTMLBRElement::create(document()); 1841 HTMLBRElement* br = HTMLBRElement::create(document());
1795 // We want to replace this quoted paragraph with an unquoted one, so insert a br 1842 // We want to replace this quoted paragraph with an unquoted one, so insert a
1796 // to hold the caret before the highest blockquote. 1843 // br to hold the caret before the highest blockquote.
1797 insertNodeBefore(br, highestBlockquote, editingState); 1844 insertNodeBefore(br, highestBlockquote, editingState);
1798 if (editingState->isAborted()) 1845 if (editingState->isAborted())
1799 return false; 1846 return false;
1800 VisiblePosition atBR = VisiblePosition::beforeNode(br); 1847 VisiblePosition atBR = VisiblePosition::beforeNode(br);
1801 // If the br we inserted collapsed, for example foo<br><blockquote>...</blockq uote>, insert 1848 // If the br we inserted collapsed, for example:
1802 // a second one. 1849 // foo<br><blockquote>...</blockquote>
1850 // insert a second one.
1803 if (!isStartOfParagraphDeprecated(atBR)) { 1851 if (!isStartOfParagraphDeprecated(atBR)) {
1804 insertNodeBefore(HTMLBRElement::create(document()), br, editingState); 1852 insertNodeBefore(HTMLBRElement::create(document()), br, editingState);
1805 if (editingState->isAborted()) 1853 if (editingState->isAborted())
1806 return false; 1854 return false;
1807 } 1855 }
1808 setEndingSelection(createVisibleSelectionDeprecated( 1856 setEndingSelection(createVisibleSelectionDeprecated(
1809 atBR, endingSelection().isDirectional())); 1857 atBR, endingSelection().isDirectional()));
1810 1858
1811 // If this is an empty paragraph there must be a line break here. 1859 // If this is an empty paragraph there must be a line break here.
1812 if (!lineBreakExistsAtVisiblePosition(caret)) 1860 if (!lineBreakExistsAtVisiblePosition(caret))
1813 return false; 1861 return false;
1814 1862
1815 Position caretPos(mostForwardCaretPosition(caret.deepEquivalent())); 1863 Position caretPos(mostForwardCaretPosition(caret.deepEquivalent()));
1816 // A line break is either a br or a preserved newline. 1864 // A line break is either a br or a preserved newline.
1817 DCHECK(isHTMLBRElement(caretPos.anchorNode()) || 1865 DCHECK(isHTMLBRElement(caretPos.anchorNode()) ||
1818 (caretPos.anchorNode()->isTextNode() && 1866 (caretPos.anchorNode()->isTextNode() &&
1819 caretPos.anchorNode()->layoutObject()->style()->preserveNewline())) 1867 caretPos.anchorNode()->layoutObject()->style()->preserveNewline()))
1820 << caretPos; 1868 << caretPos;
1821 1869
1822 if (isHTMLBRElement(*caretPos.anchorNode())) { 1870 if (isHTMLBRElement(*caretPos.anchorNode())) {
1823 removeNodeAndPruneAncestors(caretPos.anchorNode(), editingState); 1871 removeNodeAndPruneAncestors(caretPos.anchorNode(), editingState);
1824 if (editingState->isAborted()) 1872 if (editingState->isAborted())
1825 return false; 1873 return false;
1826 } else if (caretPos.anchorNode()->isTextNode()) { 1874 } else if (caretPos.anchorNode()->isTextNode()) {
1827 DCHECK_EQ(caretPos.computeOffsetInContainerNode(), 0); 1875 DCHECK_EQ(caretPos.computeOffsetInContainerNode(), 0);
1828 Text* textNode = toText(caretPos.anchorNode()); 1876 Text* textNode = toText(caretPos.anchorNode());
1829 ContainerNode* parentNode = textNode->parentNode(); 1877 ContainerNode* parentNode = textNode->parentNode();
1830 // The preserved newline must be the first thing in the node, since otherwis e the previous 1878 // The preserved newline must be the first thing in the node, since
1831 // paragraph would be quoted, and we verified that it wasn't above. 1879 // otherwise the previous paragraph would be quoted, and we verified that it
1880 // wasn't above.
1832 deleteTextFromNode(textNode, 0, 1); 1881 deleteTextFromNode(textNode, 0, 1);
1833 prune(parentNode, editingState); 1882 prune(parentNode, editingState);
1834 if (editingState->isAborted()) 1883 if (editingState->isAborted())
1835 return false; 1884 return false;
1836 } 1885 }
1837 1886
1838 return true; 1887 return true;
1839 } 1888 }
1840 1889
1841 // Operations use this function to avoid inserting content into an anchor when a t the start or the end of 1890 // Operations use this function to avoid inserting content into an anchor when
1842 // that anchor, as in NSTextView. 1891 // at the start or the end of that anchor, as in NSTextView.
1843 // FIXME: This is only an approximation of NSTextViews insertion behavior, which varies depending on how 1892 // FIXME: This is only an approximation of NSTextViews insertion behavior, which
1844 // the caret was made. 1893 // varies depending on how the caret was made.
1845 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary( 1894 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(
1846 const Position& original, 1895 const Position& original,
1847 EditingState* editingState) { 1896 EditingState* editingState) {
1848 if (original.isNull()) 1897 if (original.isNull())
1849 return original; 1898 return original;
1850 1899
1851 VisiblePosition visiblePos = createVisiblePositionDeprecated(original); 1900 VisiblePosition visiblePos = createVisiblePositionDeprecated(original);
1852 Element* enclosingAnchor = enclosingAnchorElement(original); 1901 Element* enclosingAnchor = enclosingAnchorElement(original);
1853 Position result = original; 1902 Position result = original;
1854 1903
1855 if (!enclosingAnchor) 1904 if (!enclosingAnchor)
1856 return result; 1905 return result;
1857 1906
1858 // Don't avoid block level anchors, because that would insert content into the wrong paragraph. 1907 // Don't avoid block level anchors, because that would insert content into the
1908 // wrong paragraph.
1859 if (enclosingAnchor && !isEnclosingBlock(enclosingAnchor)) { 1909 if (enclosingAnchor && !isEnclosingBlock(enclosingAnchor)) {
1860 VisiblePosition firstInAnchor = 1910 VisiblePosition firstInAnchor =
1861 VisiblePosition::firstPositionInNode(enclosingAnchor); 1911 VisiblePosition::firstPositionInNode(enclosingAnchor);
1862 VisiblePosition lastInAnchor = 1912 VisiblePosition lastInAnchor =
1863 VisiblePosition::lastPositionInNode(enclosingAnchor); 1913 VisiblePosition::lastPositionInNode(enclosingAnchor);
1864 // If visually just after the anchor, insert *inside* the anchor unless it's the last 1914 // If visually just after the anchor, insert *inside* the anchor unless it's
1865 // VisiblePosition in the document, to match NSTextView. 1915 // the last VisiblePosition in the document, to match NSTextView.
1866 if (visiblePos.deepEquivalent() == lastInAnchor.deepEquivalent()) { 1916 if (visiblePos.deepEquivalent() == lastInAnchor.deepEquivalent()) {
1867 // Make sure anchors are pushed down before avoiding them so that we don't 1917 // Make sure anchors are pushed down before avoiding them so that we don't
1868 // also avoid structural elements like lists and blocks (5142012). 1918 // also avoid structural elements like lists and blocks (5142012).
1869 if (original.anchorNode() != enclosingAnchor && 1919 if (original.anchorNode() != enclosingAnchor &&
1870 original.anchorNode()->parentNode() != enclosingAnchor) { 1920 original.anchorNode()->parentNode() != enclosingAnchor) {
1871 pushAnchorElementDown(enclosingAnchor, editingState); 1921 pushAnchorElementDown(enclosingAnchor, editingState);
1872 if (editingState->isAborted()) 1922 if (editingState->isAborted())
1873 return original; 1923 return original;
1874 enclosingAnchor = enclosingAnchorElement(original); 1924 enclosingAnchor = enclosingAnchorElement(original);
1875 if (!enclosingAnchor) 1925 if (!enclosingAnchor)
1876 return original; 1926 return original;
1877 } 1927 }
1878 // Don't insert outside an anchor if doing so would skip over a line break . It would 1928 // Don't insert outside an anchor if doing so would skip over a line
1879 // probably be safe to move the line break so that we could still avoid th e anchor here. 1929 // break. It would probably be safe to move the line break so that we
1930 // could still avoid the anchor here.
1880 Position downstream( 1931 Position downstream(
1881 mostForwardCaretPosition(visiblePos.deepEquivalent())); 1932 mostForwardCaretPosition(visiblePos.deepEquivalent()));
1882 if (lineBreakExistsAtVisiblePosition(visiblePos) && 1933 if (lineBreakExistsAtVisiblePosition(visiblePos) &&
1883 downstream.anchorNode()->isDescendantOf(enclosingAnchor)) 1934 downstream.anchorNode()->isDescendantOf(enclosingAnchor))
1884 return original; 1935 return original;
1885 1936
1886 result = Position::inParentAfterNode(*enclosingAnchor); 1937 result = Position::inParentAfterNode(*enclosingAnchor);
1887 } 1938 }
1888 // If visually just before an anchor, insert *outside* the anchor unless it' s the first 1939 // If visually just before an anchor, insert *outside* the anchor unless
1889 // VisiblePosition in a paragraph, to match NSTextView. 1940 // it's the first VisiblePosition in a paragraph, to match NSTextView.
1890 if (visiblePos.deepEquivalent() == firstInAnchor.deepEquivalent()) { 1941 if (visiblePos.deepEquivalent() == firstInAnchor.deepEquivalent()) {
1891 // Make sure anchors are pushed down before avoiding them so that we don't 1942 // Make sure anchors are pushed down before avoiding them so that we don't
1892 // also avoid structural elements like lists and blocks (5142012). 1943 // also avoid structural elements like lists and blocks (5142012).
1893 if (original.anchorNode() != enclosingAnchor && 1944 if (original.anchorNode() != enclosingAnchor &&
1894 original.anchorNode()->parentNode() != enclosingAnchor) { 1945 original.anchorNode()->parentNode() != enclosingAnchor) {
1895 pushAnchorElementDown(enclosingAnchor, editingState); 1946 pushAnchorElementDown(enclosingAnchor, editingState);
1896 if (editingState->isAborted()) 1947 if (editingState->isAborted())
1897 return original; 1948 return original;
1898 enclosingAnchor = enclosingAnchorElement(original); 1949 enclosingAnchor = enclosingAnchorElement(original);
1899 } 1950 }
1900 if (!enclosingAnchor) 1951 if (!enclosingAnchor)
1901 return original; 1952 return original;
1902 1953
1903 result = Position::inParentBeforeNode(*enclosingAnchor); 1954 result = Position::inParentBeforeNode(*enclosingAnchor);
1904 } 1955 }
1905 } 1956 }
1906 1957
1907 if (result.isNull() || !rootEditableElementOf(result)) 1958 if (result.isNull() || !rootEditableElementOf(result))
1908 result = original; 1959 result = original;
1909 1960
1910 return result; 1961 return result;
1911 } 1962 }
1912 1963
1913 // Splits the tree parent by parent until we reach the specified ancestor. We us e VisiblePositions 1964 // Splits the tree parent by parent until we reach the specified ancestor. We
1914 // to determine if the split is necessary. Returns the last split node. 1965 // use VisiblePositions to determine if the split is necessary. Returns the last
1966 // split node.
1915 Node* CompositeEditCommand::splitTreeToNode(Node* start, 1967 Node* CompositeEditCommand::splitTreeToNode(Node* start,
1916 Node* end, 1968 Node* end,
1917 bool shouldSplitAncestor) { 1969 bool shouldSplitAncestor) {
1918 DCHECK(start); 1970 DCHECK(start);
1919 DCHECK(end); 1971 DCHECK(end);
1920 DCHECK_NE(start, end); 1972 DCHECK_NE(start, end);
1921 1973
1922 if (shouldSplitAncestor && end->parentNode()) 1974 if (shouldSplitAncestor && end->parentNode())
1923 end = end->parentNode(); 1975 end = end->parentNode();
1924 if (!start->isDescendantOf(end)) 1976 if (!start->isDescendantOf(end))
(...skipping 17 matching lines...) Expand all
1942 return node; 1994 return node;
1943 } 1995 }
1944 1996
1945 DEFINE_TRACE(CompositeEditCommand) { 1997 DEFINE_TRACE(CompositeEditCommand) {
1946 visitor->trace(m_commands); 1998 visitor->trace(m_commands);
1947 visitor->trace(m_composition); 1999 visitor->trace(m_composition);
1948 EditCommand::trace(visitor); 2000 EditCommand::trace(visitor);
1949 } 2001 }
1950 2002
1951 } // namespace blink 2003 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698