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

Side by Side Diff: sky/engine/core/editing/CompositeEditCommand.cpp

Issue 767623004: Delete a bunch of rich text editing code. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
OLDNEW
« no previous file with comments | « sky/engine/core/editing/CompositeEditCommand.h ('k') | sky/engine/core/editing/InsertParagraphSeparatorCommand.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698