| 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 #include "sky/engine/core/editing/InsertLineBreakCommand.h" | 42 #include "sky/engine/core/editing/InsertLineBreakCommand.h" |
| 43 #include "sky/engine/core/editing/InsertNodeBeforeCommand.h" | 43 #include "sky/engine/core/editing/InsertNodeBeforeCommand.h" |
| 44 #include "sky/engine/core/editing/InsertParagraphSeparatorCommand.h" | 44 #include "sky/engine/core/editing/InsertParagraphSeparatorCommand.h" |
| 45 #include "sky/engine/core/editing/PlainTextRange.h" | 45 #include "sky/engine/core/editing/PlainTextRange.h" |
| 46 #include "sky/engine/core/editing/RemoveNodeCommand.h" | 46 #include "sky/engine/core/editing/RemoveNodeCommand.h" |
| 47 #include "sky/engine/core/editing/RemoveNodePreservingChildrenCommand.h" | 47 #include "sky/engine/core/editing/RemoveNodePreservingChildrenCommand.h" |
| 48 #include "sky/engine/core/editing/ReplaceSelectionCommand.h" | 48 #include "sky/engine/core/editing/ReplaceSelectionCommand.h" |
| 49 #include "sky/engine/core/editing/SpellChecker.h" | 49 #include "sky/engine/core/editing/SpellChecker.h" |
| 50 #include "sky/engine/core/editing/SplitElementCommand.h" | 50 #include "sky/engine/core/editing/SplitElementCommand.h" |
| 51 #include "sky/engine/core/editing/SplitTextNodeCommand.h" | 51 #include "sky/engine/core/editing/SplitTextNodeCommand.h" |
| 52 #include "sky/engine/core/editing/SplitTextNodeContainingElementCommand.h" | |
| 53 #include "sky/engine/core/editing/TextIterator.h" | 52 #include "sky/engine/core/editing/TextIterator.h" |
| 54 #include "sky/engine/core/editing/VisibleUnits.h" | 53 #include "sky/engine/core/editing/VisibleUnits.h" |
| 55 #include "sky/engine/core/editing/htmlediting.h" | 54 #include "sky/engine/core/editing/htmlediting.h" |
| 56 #include "sky/engine/core/events/ScopedEventQueue.h" | 55 #include "sky/engine/core/events/ScopedEventQueue.h" |
| 57 #include "sky/engine/core/frame/LocalFrame.h" | 56 #include "sky/engine/core/frame/LocalFrame.h" |
| 58 #include "sky/engine/core/html/HTMLElement.h" | 57 #include "sky/engine/core/html/HTMLElement.h" |
| 59 #include "sky/engine/core/rendering/InlineTextBox.h" | 58 #include "sky/engine/core/rendering/InlineTextBox.h" |
| 60 #include "sky/engine/core/rendering/RenderBlock.h" | 59 #include "sky/engine/core/rendering/RenderBlock.h" |
| 61 #include "sky/engine/core/rendering/RenderText.h" | 60 #include "sky/engine/core/rendering/RenderText.h" |
| 62 | 61 |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 void CompositeEditCommand::splitTextNode(PassRefPtr<Text> node, unsigned offset) | 366 void CompositeEditCommand::splitTextNode(PassRefPtr<Text> node, unsigned offset) |
| 368 { | 367 { |
| 369 applyCommandToComposite(SplitTextNodeCommand::create(node, offset)); | 368 applyCommandToComposite(SplitTextNodeCommand::create(node, offset)); |
| 370 } | 369 } |
| 371 | 370 |
| 372 void CompositeEditCommand::splitElement(PassRefPtr<Element> element, PassRefPtr<
Node> atChild) | 371 void CompositeEditCommand::splitElement(PassRefPtr<Element> element, PassRefPtr<
Node> atChild) |
| 373 { | 372 { |
| 374 applyCommandToComposite(SplitElementCommand::create(element, atChild)); | 373 applyCommandToComposite(SplitElementCommand::create(element, atChild)); |
| 375 } | 374 } |
| 376 | 375 |
| 377 void CompositeEditCommand::splitTextNodeContainingElement(PassRefPtr<Text> text,
unsigned offset) | |
| 378 { | |
| 379 applyCommandToComposite(SplitTextNodeContainingElementCommand::create(text,
offset)); | |
| 380 } | |
| 381 | |
| 382 void CompositeEditCommand::insertTextIntoNode(PassRefPtr<Text> node, unsigned of
fset, const String& text) | 376 void CompositeEditCommand::insertTextIntoNode(PassRefPtr<Text> node, unsigned of
fset, const String& text) |
| 383 { | 377 { |
| 384 if (!text.isEmpty()) | 378 if (!text.isEmpty()) |
| 385 applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset,
text)); | 379 applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset,
text)); |
| 386 } | 380 } |
| 387 | 381 |
| 388 void CompositeEditCommand::deleteTextFromNode(PassRefPtr<Text> node, unsigned of
fset, unsigned count) | 382 void CompositeEditCommand::deleteTextFromNode(PassRefPtr<Text> node, unsigned of
fset, unsigned count) |
| 389 { | 383 { |
| 390 applyCommandToComposite(DeleteFromTextNodeCommand::create(node, offset, coun
t)); | 384 applyCommandToComposite(DeleteFromTextNodeCommand::create(node, offset, coun
t)); |
| 391 } | 385 } |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 deleteInsignificantText(pos, end); | 693 deleteInsignificantText(pos, end); |
| 700 } | 694 } |
| 701 | 695 |
| 702 // Assumes that the position is at a placeholder and does the removal without mu
ch checking. | 696 // Assumes that the position is at a placeholder and does the removal without mu
ch checking. |
| 703 void CompositeEditCommand::removePlaceholderAt(const Position& p) | 697 void CompositeEditCommand::removePlaceholderAt(const Position& p) |
| 704 { | 698 { |
| 705 ASSERT(lineBreakExistsAtPosition(p)); | 699 ASSERT(lineBreakExistsAtPosition(p)); |
| 706 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); | 700 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); |
| 707 } | 701 } |
| 708 | 702 |
| 709 PassRefPtr<HTMLElement> CompositeEditCommand::insertNewDefaultParagraphElementAt
(const Position& position) | |
| 710 { | |
| 711 RefPtr<HTMLElement> paragraphElement = createDefaultParagraphElement(documen
t()); | |
| 712 insertNodeAt(paragraphElement, position); | |
| 713 return paragraphElement.release(); | |
| 714 } | |
| 715 | |
| 716 // If the paragraph is not entirely within it's own block, create one and move t
he paragraph into | |
| 717 // it, and return that block. Otherwise return 0. | |
| 718 PassRefPtr<HTMLElement> CompositeEditCommand::moveParagraphContentsToNewBlockIfN
ecessary(const Position& pos) | |
| 719 { | |
| 720 ASSERT(isEditablePosition(pos, ContentIsEditable, DoNotUpdateStyle)); | |
| 721 | |
| 722 // It's strange that this function is responsible for verifying that pos has
not been invalidated | |
| 723 // by an earlier call to this function. The caller, applyBlockStyle, should
do this. | |
| 724 VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY); | |
| 725 VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos)); | |
| 726 VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos); | |
| 727 VisiblePosition next = visibleParagraphEnd.next(); | |
| 728 VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd; | |
| 729 | |
| 730 Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream(); | |
| 731 Position upstreamEnd = visibleEnd.deepEquivalent().upstream(); | |
| 732 | |
| 733 // If there are no VisiblePositions in the same block as pos then | |
| 734 // upstreamStart will be outside the paragraph | |
| 735 if (comparePositions(pos, upstreamStart) < 0) | |
| 736 return nullptr; | |
| 737 | |
| 738 // Perform some checks to see if we need to perform work in this function. | |
| 739 if (isBlock(upstreamStart.deprecatedNode())) { | |
| 740 // If the block is the root editable element, always move content to a n
ew block, | |
| 741 // since it is illegal to modify attributes on the root editable element
for editing. | |
| 742 if (upstreamStart.deprecatedNode() == editableRootForPosition(upstreamSt
art)) { | |
| 743 // If the block is the root editable element and it contains no visi
ble content, create a new | |
| 744 // block but don't try and move content into it, since there's nothi
ng for moveParagraphs to move. | |
| 745 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(upstream
Start.deprecatedNode()->renderer())) | |
| 746 return insertNewDefaultParagraphElementAt(upstreamStart); | |
| 747 } else if (isBlock(upstreamEnd.deprecatedNode())) { | |
| 748 if (!upstreamEnd.deprecatedNode()->isDescendantOf(upstreamStart.depr
ecatedNode())) { | |
| 749 // If the paragraph end is a descendant of paragraph start, then
we need to run | |
| 750 // the rest of this function. If not, we can bail here. | |
| 751 return nullptr; | |
| 752 } | |
| 753 } else if (enclosingBlock(upstreamEnd.deprecatedNode()) != upstreamStart
.deprecatedNode()) { | |
| 754 // It should be an ancestor of the paragraph start. | |
| 755 // We can bail as we have a full block to work with. | |
| 756 return nullptr; | |
| 757 } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) { | |
| 758 // At the end of the editable region. We can bail here as well. | |
| 759 return nullptr; | |
| 760 } | |
| 761 } | |
| 762 | |
| 763 if (visibleParagraphEnd.isNull()) | |
| 764 return nullptr; | |
| 765 | |
| 766 RefPtr<HTMLElement> newBlock = insertNewDefaultParagraphElementAt(upstreamSt
art); | |
| 767 | |
| 768 // Inserting default paragraph element can change visible position. We | |
| 769 // should update visible positions before use them. | |
| 770 visiblePos = VisiblePosition(pos, VP_DEFAULT_AFFINITY); | |
| 771 visibleParagraphStart = VisiblePosition(startOfParagraph(visiblePos)); | |
| 772 visibleParagraphEnd = VisiblePosition(endOfParagraph(visiblePos)); | |
| 773 moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(f
irstPositionInNode(newBlock.get()))); | |
| 774 | |
| 775 return newBlock.release(); | |
| 776 } | |
| 777 | |
| 778 void CompositeEditCommand::pushAnchorElementDown(Element* anchorNode) | 703 void CompositeEditCommand::pushAnchorElementDown(Element* anchorNode) |
| 779 { | 704 { |
| 780 if (!anchorNode) | 705 if (!anchorNode) |
| 781 return; | 706 return; |
| 782 | 707 |
| 783 ASSERT(anchorNode->isLink()); | 708 ASSERT(anchorNode->isLink()); |
| 784 | 709 |
| 785 setEndingSelection(VisibleSelection::selectionFromContentsOfNode(anchorNode)
); | 710 setEndingSelection(VisibleSelection::selectionFromContentsOfNode(anchorNode)
); |
| 786 // Clones of anchorNode have been pushed down, now remove it. | 711 // Clones of anchorNode have been pushed down, now remove it. |
| 787 if (anchorNode->inDocument()) | 712 if (anchorNode->inDocument()) |
| 788 removeNodePreservingChildren(anchorNode); | 713 removeNodePreservingChildren(anchorNode); |
| 789 } | 714 } |
| 790 | 715 |
| 791 // Clone the paragraph between start and end under blockElement, | |
| 792 // preserving the hierarchy up to outerNode. | |
| 793 | |
| 794 void CompositeEditCommand::cloneParagraphUnderNewElement(const Position& start,
const Position& end, Node* passedOuterNode, Element* blockElement) | |
| 795 { | |
| 796 ASSERT(comparePositions(start, end) <= 0); | |
| 797 ASSERT(passedOuterNode); | |
| 798 ASSERT(blockElement); | |
| 799 | |
| 800 // First we clone the outerNode | |
| 801 RefPtr<Node> lastNode = nullptr; | |
| 802 RefPtr<Node> outerNode = passedOuterNode; | |
| 803 | |
| 804 if (outerNode->isRootEditableElement()) { | |
| 805 lastNode = blockElement; | |
| 806 } else { | |
| 807 lastNode = outerNode->cloneNode(false); | |
| 808 appendNode(lastNode, blockElement); | |
| 809 } | |
| 810 | |
| 811 if (start.anchorNode() != outerNode && lastNode->isElementNode() && start.an
chorNode()->isDescendantOf(outerNode.get())) { | |
| 812 Vector<RefPtr<Node> > ancestors; | |
| 813 | |
| 814 // Insert each node from innerNode to outerNode (excluded) in a list. | |
| 815 for (Node* n = start.deprecatedNode(); n && n != outerNode; n = n->paren
tNode()) | |
| 816 ancestors.append(n); | |
| 817 | |
| 818 // Clone every node between start.deprecatedNode() and outerBlock. | |
| 819 | |
| 820 for (size_t i = ancestors.size(); i != 0; --i) { | |
| 821 Node* item = ancestors[i - 1].get(); | |
| 822 RefPtr<Node> child = item->cloneNode(false); | |
| 823 appendNode(child, toElement(lastNode)); | |
| 824 lastNode = child.release(); | |
| 825 } | |
| 826 } | |
| 827 | |
| 828 // Scripts specified in javascript protocol may remove |outerNode| | |
| 829 // during insertion, e.g. <iframe src="javascript:..."> | |
| 830 if (!outerNode->inDocument()) | |
| 831 return; | |
| 832 | |
| 833 // Handle the case of paragraphs with more than one node, | |
| 834 // cloning all the siblings until end.deprecatedNode() is reached. | |
| 835 | |
| 836 if (start.deprecatedNode() != end.deprecatedNode() && !start.deprecatedNode(
)->isDescendantOf(end.deprecatedNode())) { | |
| 837 // If end is not a descendant of outerNode we need to | |
| 838 // find the first common ancestor to increase the scope | |
| 839 // of our nextSibling traversal. | |
| 840 while (outerNode && !end.deprecatedNode()->isDescendantOf(outerNode.get(
))) { | |
| 841 outerNode = outerNode->parentNode(); | |
| 842 } | |
| 843 | |
| 844 if (!outerNode) | |
| 845 return; | |
| 846 | |
| 847 RefPtr<Node> startNode = start.deprecatedNode(); | |
| 848 for (RefPtr<Node> node = NodeTraversal::nextSkippingChildren(*startNode,
outerNode.get()); node; node = NodeTraversal::nextSkippingChildren(*node, outer
Node.get())) { | |
| 849 // Move lastNode up in the tree as much as node was moved up in the | |
| 850 // tree by NodeTraversal::nextSkippingChildren, so that the relative
depth between | |
| 851 // node and the original start node is maintained in the clone. | |
| 852 while (startNode && lastNode && startNode->parentNode() != node->par
entNode()) { | |
| 853 startNode = startNode->parentNode(); | |
| 854 lastNode = lastNode->parentNode(); | |
| 855 } | |
| 856 | |
| 857 if (!lastNode || !lastNode->parentNode()) | |
| 858 return; | |
| 859 | |
| 860 RefPtr<Node> clonedNode = node->cloneNode(true); | |
| 861 insertNodeAfter(clonedNode, lastNode); | |
| 862 lastNode = clonedNode.release(); | |
| 863 if (node == end.deprecatedNode() || end.deprecatedNode()->isDescenda
ntOf(node.get())) | |
| 864 break; | |
| 865 } | |
| 866 } | |
| 867 } | |
| 868 | |
| 869 | |
| 870 // There are bugs in deletion when it removes a fully selected table/list. | 716 // There are bugs in deletion when it removes a fully selected table/list. |
| 871 // It expands and removes the entire table/list, but will let content | 717 // It expands and removes the entire table/list, but will let content |
| 872 // before and after the table/list collapse onto one line. | 718 // before and after the table/list collapse onto one line. |
| 873 // Deleting a paragraph will leave a placeholder. Remove it (and prune | 719 // Deleting a paragraph will leave a placeholder. Remove it (and prune |
| 874 // empty or unrendered parents). | 720 // empty or unrendered parents). |
| 875 | 721 |
| 876 void CompositeEditCommand::cleanupAfterDeletion(VisiblePosition destination) | 722 void CompositeEditCommand::cleanupAfterDeletion(VisiblePosition destination) |
| 877 { | 723 { |
| 878 VisiblePosition caretAfterDelete = endingSelection().visibleStart(); | 724 VisiblePosition caretAfterDelete = endingSelection().visibleStart(); |
| 879 Node* destinationNode = destination.deepEquivalent().anchorNode(); | 725 Node* destinationNode = destination.deepEquivalent().anchorNode(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 900 // We can safely assume this is a text node. | 746 // We can safely assume this is a text node. |
| 901 Text* textNode = toText(node); | 747 Text* textNode = toText(node); |
| 902 if (textNode->length() == 1) | 748 if (textNode->length() == 1) |
| 903 removeNodeAndPruneAncestors(node, destinationNode); | 749 removeNodeAndPruneAncestors(node, destinationNode); |
| 904 else | 750 else |
| 905 deleteTextFromNode(textNode, position.deprecatedEditingOffset(),
1); | 751 deleteTextFromNode(textNode, position.deprecatedEditingOffset(),
1); |
| 906 } | 752 } |
| 907 } | 753 } |
| 908 } | 754 } |
| 909 | 755 |
| 910 // This is a version of moveParagraph that preserves style by keeping the origin
al markup | |
| 911 // It is currently used only by IndentOutdentCommand but it is meant to be used
in the | |
| 912 // future by several other commands such as InsertList and the align commands. | |
| 913 // The blockElement parameter is the element to move the paragraph to, | |
| 914 // outerNode is the top element of the paragraph hierarchy. | |
| 915 | |
| 916 void CompositeEditCommand::moveParagraphWithClones(const VisiblePosition& startO
fParagraphToMove, const VisiblePosition& endOfParagraphToMove, HTMLElement* bloc
kElement, Node* outerNode) | |
| 917 { | |
| 918 ASSERT(outerNode); | |
| 919 ASSERT(blockElement); | |
| 920 | |
| 921 VisiblePosition beforeParagraph = startOfParagraphToMove.previous(); | |
| 922 VisiblePosition afterParagraph(endOfParagraphToMove.next()); | |
| 923 | |
| 924 // We upstream() the end and downstream() the start so that we don't include
collapsed whitespace in the move. | |
| 925 // When we paste a fragment, spaces after the end and before the start are t
reated as though they were rendered. | |
| 926 Position start = startOfParagraphToMove.deepEquivalent().downstream(); | |
| 927 Position end = startOfParagraphToMove == endOfParagraphToMove ? start : endO
fParagraphToMove.deepEquivalent().upstream(); | |
| 928 if (comparePositions(start, end) > 0) | |
| 929 end = start; | |
| 930 | |
| 931 cloneParagraphUnderNewElement(start, end, outerNode, blockElement); | |
| 932 | |
| 933 setEndingSelection(VisibleSelection(start, end, DOWNSTREAM)); | |
| 934 deleteSelection(false, false, false); | |
| 935 | |
| 936 // There are bugs in deletion when it removes a fully selected table/list. | |
| 937 // It expands and removes the entire table/list, but will let content | |
| 938 // before and after the table/list collapse onto one line. | |
| 939 | |
| 940 cleanupAfterDeletion(); | |
| 941 | |
| 942 // Add a br if pruning an empty block level element caused a collapse. For
example: | |
| 943 // foo^ | |
| 944 // <div>bar</div> | |
| 945 // baz | |
| 946 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th
at would | |
| 947 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. | |
| 948 // Must recononicalize these two VisiblePositions after the pruning above. | |
| 949 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); | |
| 950 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); | |
| 951 } | |
| 952 | |
| 953 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraph
ToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& dest
ination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor) | 756 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraph
ToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& dest
ination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor) |
| 954 { | 757 { |
| 955 ASSERT(isStartOfParagraph(startOfParagraphToMove)); | 758 ASSERT(isStartOfParagraph(startOfParagraphToMove)); |
| 956 ASSERT(isEndOfParagraph(endOfParagraphToMove)); | 759 ASSERT(isEndOfParagraph(endOfParagraphToMove)); |
| 957 moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, pr
eserveSelection, preserveStyle, constrainingAncestor); | 760 moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, pr
eserveSelection, preserveStyle, constrainingAncestor); |
| 958 } | 761 } |
| 959 | 762 |
| 960 void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
hToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& des
tination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor
) | 763 void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
hToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& des
tination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor
) |
| 961 { | 764 { |
| 962 // FIXME(sky): Remove. | 765 // FIXME(sky): Remove. |
| 963 // We've probably broken editiing badly by deleting this function... | 766 // We've probably broken editiing badly by deleting this function... |
| 964 } | 767 } |
| 965 | 768 |
| 966 // FIXME: Send an appropriate shouldDeleteRange call. | |
| 967 bool CompositeEditCommand::breakOutOfEmptyListItem() | |
| 968 { | |
| 969 return false; | |
| 970 } | |
| 971 | |
| 972 // If the caret is in an empty quoted paragraph, and either there is nothing bef
ore that | |
| 973 // paragraph, or what is before is unquoted, and the user presses delete, unquot
e that paragraph. | |
| 974 bool CompositeEditCommand::breakOutOfEmptyMailBlockquotedParagraph() | |
| 975 { | |
| 976 return false; | |
| 977 } | |
| 978 | |
| 979 // Operations use this function to avoid inserting content into an anchor when a
t the start or the end of | 769 // Operations use this function to avoid inserting content into an anchor when a
t the start or the end of |
| 980 // that anchor, as in NSTextView. | 770 // that anchor, as in NSTextView. |
| 981 // FIXME: This is only an approximation of NSTextViews insertion behavior, which
varies depending on how | 771 // FIXME: This is only an approximation of NSTextViews insertion behavior, which
varies depending on how |
| 982 // the caret was made. | 772 // the caret was made. |
| 983 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
tion& original) | 773 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
tion& original) |
| 984 { | 774 { |
| 985 if (original.isNull()) | 775 if (original.isNull()) |
| 986 return original; | 776 return original; |
| 987 | 777 |
| 988 VisiblePosition visiblePos(original); | 778 VisiblePosition visiblePos(original); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1060 VisiblePosition positionInParent(firstPositionInNode(parentElement)); | 850 VisiblePosition positionInParent(firstPositionInNode(parentElement)); |
| 1061 VisiblePosition positionInNode(firstPositionInOrBeforeNode(node.get())); | 851 VisiblePosition positionInNode(firstPositionInOrBeforeNode(node.get())); |
| 1062 if (positionInParent != positionInNode) | 852 if (positionInParent != positionInNode) |
| 1063 splitElement(parentElement, node); | 853 splitElement(parentElement, node); |
| 1064 } | 854 } |
| 1065 | 855 |
| 1066 return node.release(); | 856 return node.release(); |
| 1067 } | 857 } |
| 1068 | 858 |
| 1069 } // namespace blink | 859 } // namespace blink |
| OLD | NEW |