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

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

Issue 1695153002: Editing: Make the |EditingState*| argument of CompositeEditCommand::removeNode mandatory. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: ; Created 4 years, 10 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 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 // |AppendNodeCommand|. 381 // |AppendNodeCommand|.
382 // TODO(yosin): We should get rid of |canHaveChildrenForEditing()|, since 382 // TODO(yosin): We should get rid of |canHaveChildrenForEditing()|, since
383 // |cloneParagraphUnderNewElement()| attempt to clone non-well-formed HTML, 383 // |cloneParagraphUnderNewElement()| attempt to clone non-well-formed HTML,
384 // produced by JavaScript. 384 // produced by JavaScript.
385 ASSERT_IN_EDITING_COMMAND(canHaveChildrenForEditing(parent.get()) 385 ASSERT_IN_EDITING_COMMAND(canHaveChildrenForEditing(parent.get())
386 || (parent->isElementNode() && toElement(parent.get())->tagQName() == ob jectTag)); 386 || (parent->isElementNode() && toElement(parent.get())->tagQName() == ob jectTag));
387 ASSERT_IN_EDITING_COMMAND(parent->hasEditableStyle() || !parent->inActiveDoc ument()); 387 ASSERT_IN_EDITING_COMMAND(parent->hasEditableStyle() || !parent->inActiveDoc ument());
388 applyCommandToComposite(AppendNodeCommand::create(parent, node)); 388 applyCommandToComposite(AppendNodeCommand::create(parent, node));
389 } 389 }
390 390
391 void CompositeEditCommand::removeChildrenInRange(PassRefPtrWillBeRawPtr<Node> no de, unsigned from, unsigned to) 391 void CompositeEditCommand::removeChildrenInRange(PassRefPtrWillBeRawPtr<Node> no de, unsigned from, unsigned to, EditingState* editingState)
392 { 392 {
393 WillBeHeapVector<RefPtrWillBeMember<Node>> children; 393 WillBeHeapVector<RefPtrWillBeMember<Node>> children;
394 Node* child = NodeTraversal::childAt(*node, from); 394 Node* child = NodeTraversal::childAt(*node, from);
395 for (unsigned i = from; child && i < to; i++, child = child->nextSibling()) 395 for (unsigned i = from; child && i < to; i++, child = child->nextSibling())
396 children.append(child); 396 children.append(child);
397 397
398 size_t size = children.size(); 398 size_t size = children.size();
399 for (size_t i = 0; i < size; ++i) 399 for (size_t i = 0; i < size; ++i) {
400 removeNode(children[i].release()); 400 removeNode(children[i].release(), editingState);
401 if (editingState->isAborted())
402 return;
403 }
401 } 404 }
402 405
403 void CompositeEditCommand::removeNode(PassRefPtrWillBeRawPtr<Node> node, Editing State* editingState, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAl waysEditable) 406 void CompositeEditCommand::removeNode(PassRefPtrWillBeRawPtr<Node> node, Editing State* editingState, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAl waysEditable)
404 { 407 {
405 if (!node || !node->nonShadowBoundaryParentNode()) 408 if (!node || !node->nonShadowBoundaryParentNode())
406 return; 409 return;
407 ASSERT_IN_EDITING_COMMAND(node->document().frame()); 410 ASSERT_IN_EDITING_COMMAND(node->document().frame());
408 applyCommandToComposite(RemoveNodeCommand::create(node, shouldAssumeContentI sAlwaysEditable), editingState); 411 applyCommandToComposite(RemoveNodeCommand::create(node, shouldAssumeContentI sAlwaysEditable), editingState);
409 } 412 }
410 413
411 void CompositeEditCommand::removeNodePreservingChildren(PassRefPtrWillBeRawPtr<N ode> node, EditingState* editingState, ShouldAssumeContentIsAlwaysEditable shoul dAssumeContentIsAlwaysEditable) 414 void CompositeEditCommand::removeNodePreservingChildren(PassRefPtrWillBeRawPtr<N ode> node, EditingState* editingState, ShouldAssumeContentIsAlwaysEditable shoul dAssumeContentIsAlwaysEditable)
412 { 415 {
413 ASSERT_IN_EDITING_COMMAND(node->document().frame()); 416 ASSERT_IN_EDITING_COMMAND(node->document().frame());
414 applyCommandToComposite(RemoveNodePreservingChildrenCommand::create(node, sh ouldAssumeContentIsAlwaysEditable), editingState); 417 applyCommandToComposite(RemoveNodePreservingChildrenCommand::create(node, sh ouldAssumeContentIsAlwaysEditable), editingState);
415 } 418 }
416 419
417 void CompositeEditCommand::removeNodeAndPruneAncestors(PassRefPtrWillBeRawPtr<No de> node, Node* excludeNode) 420 void CompositeEditCommand::removeNodeAndPruneAncestors(PassRefPtrWillBeRawPtr<No de> node, EditingState* editingState, Node* excludeNode)
418 { 421 {
419 ASSERT(node.get() != excludeNode); 422 ASSERT(node.get() != excludeNode);
420 RefPtrWillBeRawPtr<ContainerNode> parent = node->parentNode(); 423 RefPtrWillBeRawPtr<ContainerNode> parent = node->parentNode();
421 removeNode(node); 424 removeNode(node, editingState);
422 prune(parent.release(), excludeNode); 425 if (editingState->isAborted())
426 return;
427 prune(parent.release(), editingState, excludeNode);
423 } 428 }
424 429
425 void CompositeEditCommand::moveRemainingSiblingsToNewParent(Node* node, Node* pa stLastNodeToMove, PassRefPtrWillBeRawPtr<Element> prpNewParent) 430 void CompositeEditCommand::moveRemainingSiblingsToNewParent(Node* node, Node* pa stLastNodeToMove, PassRefPtrWillBeRawPtr<Element> prpNewParent, EditingState* ed itingState)
426 { 431 {
427 NodeVector nodesToRemove; 432 NodeVector nodesToRemove;
428 RefPtrWillBeRawPtr<Element> newParent = prpNewParent; 433 RefPtrWillBeRawPtr<Element> newParent = prpNewParent;
429 434
430 for (; node && node != pastLastNodeToMove; node = node->nextSibling()) 435 for (; node && node != pastLastNodeToMove; node = node->nextSibling())
431 nodesToRemove.append(node); 436 nodesToRemove.append(node);
432 437
433 for (unsigned i = 0; i < nodesToRemove.size(); i++) { 438 for (unsigned i = 0; i < nodesToRemove.size(); i++) {
434 removeNode(nodesToRemove[i]); 439 removeNode(nodesToRemove[i], editingState);
435 appendNode(nodesToRemove[i], newParent); 440 if (editingState->isAborted())
441 return;
442 appendNode(nodesToRemove[i], newParent, editingState);
443 if (editingState->isAborted())
444 return;
436 } 445 }
437 } 446 }
438 447
439 void CompositeEditCommand::updatePositionForNodeRemovalPreservingChildren(Positi on& position, Node& node) 448 void CompositeEditCommand::updatePositionForNodeRemovalPreservingChildren(Positi on& position, Node& node)
440 { 449 {
441 int offset = position.isOffsetInAnchor() ? position.offsetInContainerNode() : 0; 450 int offset = position.isOffsetInAnchor() ? position.offsetInContainerNode() : 0;
442 updatePositionForNodeRemoval(position, node); 451 updatePositionForNodeRemoval(position, node);
443 if (offset == 0) 452 if (offset == 0)
444 return; 453 return;
445 position = Position(position.computeContainerNode(), offset); 454 position = Position(position.computeContainerNode(), offset);
446 } 455 }
447 456
448 HTMLSpanElement* CompositeEditCommand::replaceElementWithSpanPreservingChildrenA ndAttributes(PassRefPtrWillBeRawPtr<HTMLElement> node) 457 HTMLSpanElement* CompositeEditCommand::replaceElementWithSpanPreservingChildrenA ndAttributes(PassRefPtrWillBeRawPtr<HTMLElement> node)
449 { 458 {
450 // It would also be possible to implement all of ReplaceNodeWithSpanCommand 459 // It would also be possible to implement all of ReplaceNodeWithSpanCommand
451 // as a series of existing smaller edit commands. Someone who wanted to 460 // as a series of existing smaller edit commands. Someone who wanted to
452 // reduce the number of edit commands could do so here. 461 // reduce the number of edit commands could do so here.
453 RefPtrWillBeRawPtr<ReplaceNodeWithSpanCommand> command = ReplaceNodeWithSpan Command::create(node); 462 RefPtrWillBeRawPtr<ReplaceNodeWithSpanCommand> command = ReplaceNodeWithSpan Command::create(node);
454 applyCommandToComposite(command); 463 applyCommandToComposite(command);
455 // Returning a raw pointer here is OK because the command is retained by 464 // Returning a raw pointer here is OK because the command is retained by
456 // applyCommandToComposite (thus retaining the span), and the span is also 465 // applyCommandToComposite (thus retaining the span), and the span is also
457 // in the DOM tree, and thus alive whie it has a parent. 466 // in the DOM tree, and thus alive whie it has a parent.
458 ASSERT(command->spanElement()->inDocument()); 467 ASSERT(command->spanElement()->inDocument());
459 return command->spanElement(); 468 return command->spanElement();
460 } 469 }
461 470
462 void CompositeEditCommand::prune(PassRefPtrWillBeRawPtr<Node> node, Node* exclud eNode) 471 void CompositeEditCommand::prune(PassRefPtrWillBeRawPtr<Node> node, EditingState * editingState, Node* excludeNode)
463 { 472 {
464 if (RefPtrWillBeRawPtr<Node> highestNodeToRemove = highestNodeToRemoveInPrun ing(node.get(), excludeNode)) 473 if (RefPtrWillBeRawPtr<Node> highestNodeToRemove = highestNodeToRemoveInPrun ing(node.get(), excludeNode))
465 removeNode(highestNodeToRemove.release()); 474 removeNode(highestNodeToRemove.release(), editingState);
466 } 475 }
467 476
468 void CompositeEditCommand::splitTextNode(PassRefPtrWillBeRawPtr<Text> node, unsi gned offset) 477 void CompositeEditCommand::splitTextNode(PassRefPtrWillBeRawPtr<Text> node, unsi gned offset)
469 { 478 {
470 applyCommandToComposite(SplitTextNodeCommand::create(node, offset)); 479 applyCommandToComposite(SplitTextNodeCommand::create(node, offset));
471 } 480 }
472 481
473 void CompositeEditCommand::splitElement(PassRefPtrWillBeRawPtr<Element> element, PassRefPtrWillBeRawPtr<Node> atChild) 482 void CompositeEditCommand::splitElement(PassRefPtrWillBeRawPtr<Element> element, PassRefPtrWillBeRawPtr<Node> atChild)
474 { 483 {
475 applyCommandToComposite(SplitElementCommand::create(element, atChild)); 484 applyCommandToComposite(SplitElementCommand::create(element, atChild));
476 } 485 }
477 486
478 void CompositeEditCommand::mergeIdenticalElements(PassRefPtrWillBeRawPtr<Element > prpFirst, PassRefPtrWillBeRawPtr<Element> prpSecond) 487 void CompositeEditCommand::mergeIdenticalElements(PassRefPtrWillBeRawPtr<Element > prpFirst, PassRefPtrWillBeRawPtr<Element> prpSecond, EditingState* editingStat e)
479 { 488 {
480 RefPtrWillBeRawPtr<Element> first = prpFirst; 489 RefPtrWillBeRawPtr<Element> first = prpFirst;
481 RefPtrWillBeRawPtr<Element> second = prpSecond; 490 RefPtrWillBeRawPtr<Element> second = prpSecond;
482 ASSERT(!first->isDescendantOf(second.get()) && second != first); 491 ASSERT(!first->isDescendantOf(second.get()) && second != first);
483 if (first->nextSibling() != second) { 492 if (first->nextSibling() != second) {
484 removeNode(second); 493 removeNode(second, editingState);
494 if (editingState->isAborted())
495 return;
485 insertNodeAfter(second, first); 496 insertNodeAfter(second, first);
486 } 497 }
487 applyCommandToComposite(MergeIdenticalElementsCommand::create(first, second) ); 498 applyCommandToComposite(MergeIdenticalElementsCommand::create(first, second) , editingState);
488 } 499 }
489 500
490 void CompositeEditCommand::wrapContentsInDummySpan(PassRefPtrWillBeRawPtr<Elemen t> element) 501 void CompositeEditCommand::wrapContentsInDummySpan(PassRefPtrWillBeRawPtr<Elemen t> element)
491 { 502 {
492 applyCommandToComposite(WrapContentsInDummySpanCommand::create(element)); 503 applyCommandToComposite(WrapContentsInDummySpanCommand::create(element));
493 } 504 }
494 505
495 void CompositeEditCommand::splitTextNodeContainingElement(PassRefPtrWillBeRawPtr <Text> text, unsigned offset) 506 void CompositeEditCommand::splitTextNodeContainingElement(PassRefPtrWillBeRawPtr <Text> text, unsigned offset)
496 { 507 {
497 applyCommandToComposite(SplitTextNodeContainingElementCommand::create(text, offset)); 508 applyCommandToComposite(SplitTextNodeContainingElementCommand::create(text, offset));
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 sortedTextBoxes.append(textBox); 780 sortedTextBoxes.append(textBox);
770 781
771 // If there is mixed directionality text, the boxes can be out of order, 782 // If there is mixed directionality text, the boxes can be out of order,
772 // (like Arabic with embedded LTR), so sort them first. 783 // (like Arabic with embedded LTR), so sort them first.
773 if (textLayoutObject->containsReversedText()) 784 if (textLayoutObject->containsReversedText())
774 std::sort(sortedTextBoxes.begin(), sortedTextBoxes.end(), InlineTextBox: :compareByStart); 785 std::sort(sortedTextBoxes.begin(), sortedTextBoxes.end(), InlineTextBox: :compareByStart);
775 InlineTextBox* box = sortedTextBoxes.isEmpty() ? 0 : sortedTextBoxes[sortedT extBoxesPosition]; 786 InlineTextBox* box = sortedTextBoxes.isEmpty() ? 0 : sortedTextBoxes[sortedT extBoxesPosition];
776 787
777 if (!box) { 788 if (!box) {
778 // whole text node is empty 789 // whole text node is empty
779 removeNode(textNode); 790 // Removing a Text node won't dispatch synchronous events.
791 removeNode(textNode, ASSERT_NO_EDITING_ABORT);
780 return; 792 return;
781 } 793 }
782 794
783 unsigned length = textNode->length(); 795 unsigned length = textNode->length();
784 if (start >= length || end > length) 796 if (start >= length || end > length)
785 return; 797 return;
786 798
787 unsigned removed = 0; 799 unsigned removed = 0;
788 InlineTextBox* prevBox = nullptr; 800 InlineTextBox* prevBox = nullptr;
789 String str; 801 String str;
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 return nullptr; 922 return nullptr;
911 } 923 }
912 924
913 // Assumes that the position is at a placeholder and does the removal without mu ch checking. 925 // Assumes that the position is at a placeholder and does the removal without mu ch checking.
914 void CompositeEditCommand::removePlaceholderAt(const Position& p) 926 void CompositeEditCommand::removePlaceholderAt(const Position& p)
915 { 927 {
916 ASSERT(lineBreakExistsAtPosition(p)); 928 ASSERT(lineBreakExistsAtPosition(p));
917 929
918 // We are certain that the position is at a line break, but it may be a br o r a preserved newline. 930 // We are certain that the position is at a line break, but it may be a br o r a preserved newline.
919 if (isHTMLBRElement(*p.anchorNode())) { 931 if (isHTMLBRElement(*p.anchorNode())) {
920 removeNode(p.anchorNode()); 932 // Removing a BR element won't dispatch synchronous events.
933 removeNode(p.anchorNode(), ASSERT_NO_EDITING_ABORT);
921 return; 934 return;
922 } 935 }
923 936
924 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); 937 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1);
925 } 938 }
926 939
927 PassRefPtrWillBeRawPtr<HTMLElement> CompositeEditCommand::insertNewDefaultParagr aphElementAt(const Position& position) 940 PassRefPtrWillBeRawPtr<HTMLElement> CompositeEditCommand::insertNewDefaultParagr aphElementAt(const Position& position)
928 { 941 {
929 RefPtrWillBeRawPtr<HTMLElement> paragraphElement = createDefaultParagraphEle ment(document()); 942 RefPtrWillBeRawPtr<HTMLElement> paragraphElement = createDefaultParagraphEle ment(document());
930 paragraphElement->appendChild(HTMLBRElement::create(document())); 943 paragraphElement->appendChild(HTMLBRElement::create(document()));
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 } 1113 }
1101 } 1114 }
1102 1115
1103 1116
1104 // There are bugs in deletion when it removes a fully selected table/list. 1117 // There are bugs in deletion when it removes a fully selected table/list.
1105 // It expands and removes the entire table/list, but will let content 1118 // It expands and removes the entire table/list, but will let content
1106 // before and after the table/list collapse onto one line. 1119 // before and after the table/list collapse onto one line.
1107 // Deleting a paragraph will leave a placeholder. Remove it (and prune 1120 // Deleting a paragraph will leave a placeholder. Remove it (and prune
1108 // empty or unrendered parents). 1121 // empty or unrendered parents).
1109 1122
1110 void CompositeEditCommand::cleanupAfterDeletion(VisiblePosition destination) 1123 void CompositeEditCommand::cleanupAfterDeletion(EditingState* editingState, Visi blePosition destination)
1111 { 1124 {
1112 VisiblePosition caretAfterDelete = endingSelection().visibleStart(); 1125 VisiblePosition caretAfterDelete = endingSelection().visibleStart();
1113 Node* destinationNode = destination.deepEquivalent().anchorNode(); 1126 Node* destinationNode = destination.deepEquivalent().anchorNode();
1114 if (caretAfterDelete.deepEquivalent() != destination.deepEquivalent() && isS tartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) { 1127 if (caretAfterDelete.deepEquivalent() != destination.deepEquivalent() && isS tartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) {
1115 // Note: We want the rightmost candidate. 1128 // Note: We want the rightmost candidate.
1116 Position position = mostForwardCaretPosition(caretAfterDelete.deepEquiva lent()); 1129 Position position = mostForwardCaretPosition(caretAfterDelete.deepEquiva lent());
1117 Node* node = position.anchorNode(); 1130 Node* node = position.anchorNode();
1118 1131
1119 // Bail if we'd remove an ancestor of our destination. 1132 // Bail if we'd remove an ancestor of our destination.
1120 if (destinationNode && destinationNode->isDescendantOf(node)) 1133 if (destinationNode && destinationNode->isDescendantOf(node))
1121 return; 1134 return;
1122 1135
1123 // Normally deletion will leave a br as a placeholder. 1136 // Normally deletion will leave a br as a placeholder.
1124 if (isHTMLBRElement(*node)) { 1137 if (isHTMLBRElement(*node)) {
1125 removeNodeAndPruneAncestors(node, destinationNode); 1138 removeNodeAndPruneAncestors(node, editingState, destinationNode);
1126 1139
1127 // If the selection to move was empty and in an empty block that 1140 // If the selection to move was empty and in an empty block that
1128 // doesn't require a placeholder to prop itself open (like a bordere d 1141 // doesn't require a placeholder to prop itself open (like a bordere d
1129 // div or an li), remove it during the move (the list removal code 1142 // div or an li), remove it during the move (the list removal code
1130 // expects this behavior). 1143 // expects this behavior).
1131 } else if (isEnclosingBlock(node)) { 1144 } else if (isEnclosingBlock(node)) {
1132 // If caret position after deletion and destination position coincid es, 1145 // If caret position after deletion and destination position coincid es,
1133 // node should not be removed. 1146 // node should not be removed.
1134 if (!rendersInDifferentPosition(position, destination.deepEquivalent ())) { 1147 if (!rendersInDifferentPosition(position, destination.deepEquivalent ())) {
1135 prune(node, destinationNode); 1148 prune(node, editingState, destinationNode);
1136 return; 1149 return;
1137 } 1150 }
1138 removeNodeAndPruneAncestors(node, destinationNode); 1151 removeNodeAndPruneAncestors(node, editingState, destinationNode);
1139 } else if (lineBreakExistsAtPosition(position)) { 1152 } else if (lineBreakExistsAtPosition(position)) {
1140 // There is a preserved '\n' at caretAfterDelete. 1153 // There is a preserved '\n' at caretAfterDelete.
1141 // We can safely assume this is a text node. 1154 // We can safely assume this is a text node.
1142 Text* textNode = toText(node); 1155 Text* textNode = toText(node);
1143 if (textNode->length() == 1) 1156 if (textNode->length() == 1)
1144 removeNodeAndPruneAncestors(node, destinationNode); 1157 removeNodeAndPruneAncestors(node, editingState, destinationNode) ;
1145 else 1158 else
1146 deleteTextFromNode(textNode, position.computeOffsetInContainerNo de(), 1); 1159 deleteTextFromNode(textNode, position.computeOffsetInContainerNo de(), 1);
1147 } 1160 }
1148 } 1161 }
1149 } 1162 }
1150 1163
1151 // This is a version of moveParagraph that preserves style by keeping the origin al markup 1164 // This is a version of moveParagraph that preserves style by keeping the origin al markup
1152 // It is currently used only by IndentOutdentCommand but it is meant to be used in the 1165 // It is currently used only by IndentOutdentCommand but it is meant to be used in the
1153 // future by several other commands such as InsertList and the align commands. 1166 // future by several other commands such as InsertList and the align commands.
1154 // The blockElement parameter is the element to move the paragraph to, 1167 // The blockElement parameter is the element to move the paragraph to,
(...skipping 18 matching lines...) Expand all
1173 1186
1174 setEndingSelection(VisibleSelection(start, end)); 1187 setEndingSelection(VisibleSelection(start, end));
1175 deleteSelection(editingState, false, false, false); 1188 deleteSelection(editingState, false, false, false);
1176 if (editingState->isAborted()) 1189 if (editingState->isAborted())
1177 return; 1190 return;
1178 1191
1179 // There are bugs in deletion when it removes a fully selected table/list. 1192 // There are bugs in deletion when it removes a fully selected table/list.
1180 // It expands and removes the entire table/list, but will let content 1193 // It expands and removes the entire table/list, but will let content
1181 // before and after the table/list collapse onto one line. 1194 // before and after the table/list collapse onto one line.
1182 1195
1183 cleanupAfterDeletion(); 1196 cleanupAfterDeletion(editingState);
1197 if (editingState->isAborted())
1198 return;
1184 1199
1185 // Add a br if pruning an empty block level element caused a collapse. For example: 1200 // Add a br if pruning an empty block level element caused a collapse. For example:
1186 // foo^ 1201 // foo^
1187 // <div>bar</div> 1202 // <div>bar</div>
1188 // baz 1203 // baz
1189 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th at would 1204 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th at would
1190 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br . 1205 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br .
1191 // Must recononicalize these two VisiblePositions after the pruning above. 1206 // Must recononicalize these two VisiblePositions after the pruning above.
1192 beforeParagraph = createVisiblePosition(beforeParagraph.deepEquivalent()); 1207 beforeParagraph = createVisiblePosition(beforeParagraph.deepEquivalent());
1193 afterParagraph = createVisiblePosition(afterParagraph.deepEquivalent()); 1208 afterParagraph = createVisiblePosition(afterParagraph.deepEquivalent());
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1262 1277
1263 // FIXME (5098931): We should add a new insert action "WebViewInsertActionMo ved" and call shouldInsertFragment here. 1278 // FIXME (5098931): We should add a new insert action "WebViewInsertActionMo ved" and call shouldInsertFragment here.
1264 1279
1265 setEndingSelection(VisibleSelection(start, end)); 1280 setEndingSelection(VisibleSelection(start, end));
1266 document().frame()->spellChecker().clearMisspellingsAndBadGrammar(endingSele ction()); 1281 document().frame()->spellChecker().clearMisspellingsAndBadGrammar(endingSele ction());
1267 deleteSelection(editingState, false, false, false); 1282 deleteSelection(editingState, false, false, false);
1268 if (editingState->isAborted()) 1283 if (editingState->isAborted())
1269 return; 1284 return;
1270 1285
1271 ASSERT(destination.deepEquivalent().inDocument()); 1286 ASSERT(destination.deepEquivalent().inDocument());
1272 cleanupAfterDeletion(destination); 1287 cleanupAfterDeletion(editingState, destination);
1288 if (editingState->isAborted())
1289 return;
1273 ASSERT(destination.deepEquivalent().inDocument()); 1290 ASSERT(destination.deepEquivalent().inDocument());
1274 1291
1275 // Add a br if pruning an empty block level element caused a collapse. For e xample: 1292 // Add a br if pruning an empty block level element caused a collapse. For e xample:
1276 // foo^ 1293 // foo^
1277 // <div>bar</div> 1294 // <div>bar</div>
1278 // baz 1295 // baz
1279 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That would 1296 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That would
1280 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br . 1297 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br .
1281 // Must recononicalize these two VisiblePositions after the pruning above. 1298 // Must recononicalize these two VisiblePositions after the pruning above.
1282 beforeParagraph = createVisiblePosition(beforeParagraph.deepEquivalent()); 1299 beforeParagraph = createVisiblePosition(beforeParagraph.deepEquivalent());
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1319 EphemeralRange startRange = PlainTextRange(destinationIndex + startIndex).cr eateRangeForSelection(*documentElement); 1336 EphemeralRange startRange = PlainTextRange(destinationIndex + startIndex).cr eateRangeForSelection(*documentElement);
1320 if (startRange.isNull()) 1337 if (startRange.isNull())
1321 return; 1338 return;
1322 EphemeralRange endRange = PlainTextRange(destinationIndex + endIndex).create RangeForSelection(*documentElement); 1339 EphemeralRange endRange = PlainTextRange(destinationIndex + endIndex).create RangeForSelection(*documentElement);
1323 if (endRange.isNull()) 1340 if (endRange.isNull())
1324 return; 1341 return;
1325 setEndingSelection(VisibleSelection(startRange.startPosition(), endRange.sta rtPosition(), TextAffinity::Downstream, originalIsDirectional)); 1342 setEndingSelection(VisibleSelection(startRange.startPosition(), endRange.sta rtPosition(), TextAffinity::Downstream, originalIsDirectional));
1326 } 1343 }
1327 1344
1328 // FIXME: Send an appropriate shouldDeleteRange call. 1345 // FIXME: Send an appropriate shouldDeleteRange call.
1329 bool CompositeEditCommand::breakOutOfEmptyListItem() 1346 bool CompositeEditCommand::breakOutOfEmptyListItem(EditingState* editingState)
1330 { 1347 {
1331 RefPtrWillBeRawPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelect ion().visibleStart()); 1348 RefPtrWillBeRawPtr<Node> emptyListItem = enclosingEmptyListItem(endingSelect ion().visibleStart());
1332 if (!emptyListItem) 1349 if (!emptyListItem)
1333 return false; 1350 return false;
1334 1351
1335 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(endingSelectio n().start()); 1352 RefPtrWillBeRawPtr<EditingStyle> style = EditingStyle::create(endingSelectio n().start());
1336 style->mergeTypingStyle(&document()); 1353 style->mergeTypingStyle(&document());
1337 1354
1338 RefPtrWillBeRawPtr<ContainerNode> listNode = emptyListItem->parentNode(); 1355 RefPtrWillBeRawPtr<ContainerNode> listNode = emptyListItem->parentNode();
1339 // FIXME: Can't we do something better when the immediate parent wasn't a li st node? 1356 // FIXME: Can't we do something better when the immediate parent wasn't a li st node?
(...skipping 26 matching lines...) Expand all
1366 RefPtrWillBeRawPtr<Node> previousListNode = emptyListItem->isElementNode() ? ElementTraversal::previousSibling(*emptyListItem): emptyListItem->previousSibli ng(); 1383 RefPtrWillBeRawPtr<Node> previousListNode = emptyListItem->isElementNode() ? ElementTraversal::previousSibling(*emptyListItem): emptyListItem->previousSibli ng();
1367 RefPtrWillBeRawPtr<Node> nextListNode = emptyListItem->isElementNode() ? Ele mentTraversal::nextSibling(*emptyListItem): emptyListItem->nextSibling(); 1384 RefPtrWillBeRawPtr<Node> nextListNode = emptyListItem->isElementNode() ? Ele mentTraversal::nextSibling(*emptyListItem): emptyListItem->nextSibling();
1368 if (isListItem(nextListNode.get()) || isHTMLListElement(nextListNode.get())) { 1385 if (isListItem(nextListNode.get()) || isHTMLListElement(nextListNode.get())) {
1369 // If emptyListItem follows another list item or nested list, split the list node. 1386 // If emptyListItem follows another list item or nested list, split the list node.
1370 if (isListItem(previousListNode.get()) || isHTMLListElement(previousList Node.get())) 1387 if (isListItem(previousListNode.get()) || isHTMLListElement(previousList Node.get()))
1371 splitElement(toElement(listNode), emptyListItem); 1388 splitElement(toElement(listNode), emptyListItem);
1372 1389
1373 // If emptyListItem is followed by other list item or nested list, then insert newBlock before the list node. 1390 // If emptyListItem is followed by other list item or nested list, then insert newBlock before the list node.
1374 // Because we have splitted the element, emptyListItem is the first elem ent in the list node. 1391 // Because we have splitted the element, emptyListItem is the first elem ent in the list node.
1375 // i.e. insert newBlock before ul or ol whose first element is emptyList Item 1392 // i.e. insert newBlock before ul or ol whose first element is emptyList Item
1376 insertNodeBefore(newBlock, listNode); 1393 insertNodeBefore(newBlock, listNode, editingState);
1377 removeNode(emptyListItem); 1394 if (editingState->isAborted())
1395 return false;
1396 removeNode(emptyListItem, editingState);
1397 if (editingState->isAborted())
1398 return false;
1378 } else { 1399 } else {
1379 // When emptyListItem does not follow any list item or nested list, inse rt newBlock after the enclosing list node. 1400 // When emptyListItem does not follow any list item or nested list, inse rt newBlock after the enclosing list node.
1380 // Remove the enclosing node if emptyListItem is the only child; otherwi se just remove emptyListItem. 1401 // Remove the enclosing node if emptyListItem is the only child; otherwi se just remove emptyListItem.
1381 insertNodeAfter(newBlock, listNode); 1402 insertNodeAfter(newBlock, listNode);
1382 removeNode(isListItem(previousListNode.get()) || isHTMLListElement(previ ousListNode.get()) ? emptyListItem.get() : listNode.get()); 1403 removeNode(isListItem(previousListNode.get()) || isHTMLListElement(previ ousListNode.get()) ? emptyListItem.get() : listNode.get(), editingState);
1404 if (editingState->isAborted())
1405 return false;
1383 } 1406 }
1384 1407
1385 appendBlockPlaceholder(newBlock); 1408 appendBlockPlaceholder(newBlock);
1386 setEndingSelection(VisibleSelection(firstPositionInNode(newBlock.get()), Tex tAffinity::Downstream, endingSelection().isDirectional())); 1409 setEndingSelection(VisibleSelection(firstPositionInNode(newBlock.get()), Tex tAffinity::Downstream, endingSelection().isDirectional()));
1387 1410
1388 style->prepareToApplyAt(endingSelection().start()); 1411 style->prepareToApplyAt(endingSelection().start());
1389 if (!style->isEmpty()) 1412 if (!style->isEmpty())
1390 applyStyle(style.get()); 1413 applyStyle(style.get());
1391 1414
1392 return true; 1415 return true;
1393 } 1416 }
1394 1417
1395 // If the caret is in an empty quoted paragraph, and either there is nothing bef ore that 1418 // If the caret is in an empty quoted paragraph, and either there is nothing bef ore that
1396 // paragraph, or what is before is unquoted, and the user presses delete, unquot e that paragraph. 1419 // paragraph, or what is before is unquoted, and the user presses delete, unquot e that paragraph.
1397 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph() 1420 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph(EditingState* editingState)
1398 { 1421 {
1399 if (!endingSelection().isCaret()) 1422 if (!endingSelection().isCaret())
1400 return false; 1423 return false;
1401 1424
1402 VisiblePosition caret = endingSelection().visibleStart(); 1425 VisiblePosition caret = endingSelection().visibleStart();
1403 HTMLQuoteElement* highestBlockquote = toHTMLQuoteElement(highestEnclosingNod eOfType(caret.deepEquivalent(), &isMailHTMLBlockquoteElement)); 1426 HTMLQuoteElement* highestBlockquote = toHTMLQuoteElement(highestEnclosingNod eOfType(caret.deepEquivalent(), &isMailHTMLBlockquoteElement));
1404 if (!highestBlockquote) 1427 if (!highestBlockquote)
1405 return false; 1428 return false;
1406 1429
1407 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret)) 1430 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret))
1408 return false; 1431 return false;
1409 1432
1410 VisiblePosition previous = previousPositionOf(caret, CannotCrossEditingBound ary); 1433 VisiblePosition previous = previousPositionOf(caret, CannotCrossEditingBound ary);
1411 // Only move forward if there's nothing before the caret, or if there's unqu oted content before it. 1434 // Only move forward if there's nothing before the caret, or if there's unqu oted content before it.
1412 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailHTMLBlockquoteElem ent)) 1435 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailHTMLBlockquoteElem ent))
1413 return false; 1436 return false;
1414 1437
1415 RefPtrWillBeRawPtr<HTMLBRElement> br = HTMLBRElement::create(document()); 1438 RefPtrWillBeRawPtr<HTMLBRElement> br = HTMLBRElement::create(document());
1416 // We want to replace this quoted paragraph with an unquoted one, so insert a br 1439 // We want to replace this quoted paragraph with an unquoted one, so insert a br
1417 // to hold the caret before the highest blockquote. 1440 // to hold the caret before the highest blockquote.
1418 insertNodeBefore(br, highestBlockquote); 1441 insertNodeBefore(br, highestBlockquote, editingState);
1442 if (editingState->isAborted())
1443 return false;
1419 VisiblePosition atBR = createVisiblePosition(positionBeforeNode(br.get())); 1444 VisiblePosition atBR = createVisiblePosition(positionBeforeNode(br.get()));
1420 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc kquote>, insert 1445 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc kquote>, insert
1421 // a second one. 1446 // a second one.
1422 if (!isStartOfParagraph(atBR)) 1447 if (!isStartOfParagraph(atBR)) {
1423 insertNodeBefore(HTMLBRElement::create(document()), br); 1448 insertNodeBefore(HTMLBRElement::create(document()), br, editingState);
1449 if (editingState->isAborted())
1450 return false;
1451 }
1424 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional()) ); 1452 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional()) );
1425 1453
1426 // If this is an empty paragraph there must be a line break here. 1454 // If this is an empty paragraph there must be a line break here.
1427 if (!lineBreakExistsAtVisiblePosition(caret)) 1455 if (!lineBreakExistsAtVisiblePosition(caret))
1428 return false; 1456 return false;
1429 1457
1430 Position caretPos(mostForwardCaretPosition(caret.deepEquivalent())); 1458 Position caretPos(mostForwardCaretPosition(caret.deepEquivalent()));
1431 // A line break is either a br or a preserved newline. 1459 // A line break is either a br or a preserved newline.
1432 ASSERT(isHTMLBRElement(caretPos.anchorNode()) || (caretPos.anchorNode()->isT extNode() && caretPos.anchorNode()->layoutObject()->style()->preserveNewline())) ; 1460 ASSERT(isHTMLBRElement(caretPos.anchorNode()) || (caretPos.anchorNode()->isT extNode() && caretPos.anchorNode()->layoutObject()->style()->preserveNewline())) ;
1433 1461
1434 if (isHTMLBRElement(*caretPos.anchorNode())) { 1462 if (isHTMLBRElement(*caretPos.anchorNode())) {
1435 removeNodeAndPruneAncestors(caretPos.anchorNode()); 1463 removeNodeAndPruneAncestors(caretPos.anchorNode(), editingState);
1464 if (editingState->isAborted())
1465 return false;
1436 } else if (caretPos.anchorNode()->isTextNode()) { 1466 } else if (caretPos.anchorNode()->isTextNode()) {
1437 ASSERT(caretPos.computeOffsetInContainerNode() == 0); 1467 ASSERT(caretPos.computeOffsetInContainerNode() == 0);
1438 Text* textNode = toText(caretPos.anchorNode()); 1468 Text* textNode = toText(caretPos.anchorNode());
1439 ContainerNode* parentNode = textNode->parentNode(); 1469 ContainerNode* parentNode = textNode->parentNode();
1440 // The preserved newline must be the first thing in the node, since othe rwise the previous 1470 // The preserved newline must be the first thing in the node, since othe rwise the previous
1441 // paragraph would be quoted, and we verified that it wasn't above. 1471 // paragraph would be quoted, and we verified that it wasn't above.
1442 deleteTextFromNode(textNode, 0, 1); 1472 deleteTextFromNode(textNode, 0, 1);
1443 prune(parentNode); 1473 prune(parentNode, editingState);
1474 if (editingState->isAborted())
1475 return false;
1444 } 1476 }
1445 1477
1446 return true; 1478 return true;
1447 } 1479 }
1448 1480
1449 // Operations use this function to avoid inserting content into an anchor when a t the start or the end of 1481 // Operations use this function to avoid inserting content into an anchor when a t the start or the end of
1450 // that anchor, as in NSTextView. 1482 // that anchor, as in NSTextView.
1451 // FIXME: This is only an approximation of NSTextViews insertion behavior, which varies depending on how 1483 // FIXME: This is only an approximation of NSTextViews insertion behavior, which varies depending on how
1452 // the caret was made. 1484 // the caret was made.
1453 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi tion& original, EditingState* editingState) 1485 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi tion& original, EditingState* editingState)
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1541 } 1573 }
1542 1574
1543 DEFINE_TRACE(CompositeEditCommand) 1575 DEFINE_TRACE(CompositeEditCommand)
1544 { 1576 {
1545 visitor->trace(m_commands); 1577 visitor->trace(m_commands);
1546 visitor->trace(m_composition); 1578 visitor->trace(m_composition);
1547 EditCommand::trace(visitor); 1579 EditCommand::trace(visitor);
1548 } 1580 }
1549 1581
1550 } // namespace blink 1582 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698