| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |