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

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

Issue 2692093003: Rewrite DocumentMarkerController to use SynchronousMutationObserver (Closed)
Patch Set: Introduce SetCharacterDataCommand Created 3 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
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * 12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */ 24 */
25 25
26 #include "core/editing/commands/CompositeEditCommand.h" 26 #include "core/editing/commands/CompositeEditCommand.h"
27 27
28 #include <algorithm>
28 #include "bindings/core/v8/ExceptionState.h" 29 #include "bindings/core/v8/ExceptionState.h"
29 #include "core/HTMLNames.h" 30 #include "core/HTMLNames.h"
30 #include "core/dom/Document.h" 31 #include "core/dom/Document.h"
31 #include "core/dom/DocumentFragment.h" 32 #include "core/dom/DocumentFragment.h"
32 #include "core/dom/ElementTraversal.h" 33 #include "core/dom/ElementTraversal.h"
33 #include "core/dom/NodeTraversal.h" 34 #include "core/dom/NodeTraversal.h"
34 #include "core/dom/Range.h" 35 #include "core/dom/Range.h"
35 #include "core/dom/Text.h" 36 #include "core/dom/Text.h"
36 #include "core/editing/EditingUtilities.h" 37 #include "core/editing/EditingUtilities.h"
37 #include "core/editing/Editor.h" 38 #include "core/editing/Editor.h"
38 #include "core/editing/PlainTextRange.h" 39 #include "core/editing/PlainTextRange.h"
39 #include "core/editing/RelocatablePosition.h" 40 #include "core/editing/RelocatablePosition.h"
40 #include "core/editing/VisibleUnits.h" 41 #include "core/editing/VisibleUnits.h"
41 #include "core/editing/commands/AppendNodeCommand.h" 42 #include "core/editing/commands/AppendNodeCommand.h"
42 #include "core/editing/commands/ApplyStyleCommand.h" 43 #include "core/editing/commands/ApplyStyleCommand.h"
43 #include "core/editing/commands/DeleteFromTextNodeCommand.h" 44 #include "core/editing/commands/DeleteFromTextNodeCommand.h"
44 #include "core/editing/commands/DeleteSelectionCommand.h" 45 #include "core/editing/commands/DeleteSelectionCommand.h"
45 #include "core/editing/commands/InsertIntoTextNodeCommand.h" 46 #include "core/editing/commands/InsertIntoTextNodeCommand.h"
46 #include "core/editing/commands/InsertLineBreakCommand.h" 47 #include "core/editing/commands/InsertLineBreakCommand.h"
47 #include "core/editing/commands/InsertNodeBeforeCommand.h" 48 #include "core/editing/commands/InsertNodeBeforeCommand.h"
48 #include "core/editing/commands/InsertParagraphSeparatorCommand.h" 49 #include "core/editing/commands/InsertParagraphSeparatorCommand.h"
49 #include "core/editing/commands/MergeIdenticalElementsCommand.h" 50 #include "core/editing/commands/MergeIdenticalElementsCommand.h"
50 #include "core/editing/commands/RemoveCSSPropertyCommand.h" 51 #include "core/editing/commands/RemoveCSSPropertyCommand.h"
51 #include "core/editing/commands/RemoveNodeCommand.h" 52 #include "core/editing/commands/RemoveNodeCommand.h"
52 #include "core/editing/commands/RemoveNodePreservingChildrenCommand.h" 53 #include "core/editing/commands/RemoveNodePreservingChildrenCommand.h"
53 #include "core/editing/commands/ReplaceNodeWithSpanCommand.h" 54 #include "core/editing/commands/ReplaceNodeWithSpanCommand.h"
54 #include "core/editing/commands/ReplaceSelectionCommand.h" 55 #include "core/editing/commands/ReplaceSelectionCommand.h"
56 #include "core/editing/commands/SetCharacterDataCommand.h"
55 #include "core/editing/commands/SetNodeAttributeCommand.h" 57 #include "core/editing/commands/SetNodeAttributeCommand.h"
56 #include "core/editing/commands/SplitElementCommand.h" 58 #include "core/editing/commands/SplitElementCommand.h"
57 #include "core/editing/commands/SplitTextNodeCommand.h" 59 #include "core/editing/commands/SplitTextNodeCommand.h"
58 #include "core/editing/commands/SplitTextNodeContainingElementCommand.h" 60 #include "core/editing/commands/SplitTextNodeContainingElementCommand.h"
59 #include "core/editing/commands/WrapContentsInDummySpanCommand.h" 61 #include "core/editing/commands/WrapContentsInDummySpanCommand.h"
60 #include "core/editing/iterators/TextIterator.h" 62 #include "core/editing/iterators/TextIterator.h"
61 #include "core/editing/markers/DocumentMarkerController.h" 63 #include "core/editing/markers/DocumentMarkerController.h"
62 #include "core/editing/serializers/Serialization.h" 64 #include "core/editing/serializers/Serialization.h"
63 #include "core/editing/spellcheck/SpellChecker.h" 65 #include "core/editing/spellcheck/SpellChecker.h"
64 #include "core/events/ScopedEventQueue.h" 66 #include "core/events/ScopedEventQueue.h"
65 #include "core/frame/LocalFrame.h" 67 #include "core/frame/LocalFrame.h"
66 #include "core/html/HTMLBRElement.h" 68 #include "core/html/HTMLBRElement.h"
67 #include "core/html/HTMLDivElement.h" 69 #include "core/html/HTMLDivElement.h"
68 #include "core/html/HTMLElement.h" 70 #include "core/html/HTMLElement.h"
69 #include "core/html/HTMLLIElement.h" 71 #include "core/html/HTMLLIElement.h"
70 #include "core/html/HTMLQuoteElement.h" 72 #include "core/html/HTMLQuoteElement.h"
71 #include "core/html/HTMLSpanElement.h" 73 #include "core/html/HTMLSpanElement.h"
72 #include "core/layout/LayoutBlock.h" 74 #include "core/layout/LayoutBlock.h"
73 #include "core/layout/LayoutListItem.h" 75 #include "core/layout/LayoutListItem.h"
74 #include "core/layout/LayoutText.h" 76 #include "core/layout/LayoutText.h"
75 #include "core/layout/line/InlineTextBox.h" 77 #include "core/layout/line/InlineTextBox.h"
76 #include <algorithm>
77 78
78 namespace blink { 79 namespace blink {
79 80
80 using namespace HTMLNames; 81 using namespace HTMLNames;
81 82
82 CompositeEditCommand::CompositeEditCommand(Document& document) 83 CompositeEditCommand::CompositeEditCommand(Document& document)
83 : EditCommand(document) { 84 : EditCommand(document) {
84 setStartingSelection(document.frame()->selection().selection()); 85 setStartingSelection(document.frame()->selection().selection());
85 setEndingVisibleSelection(m_startingSelection); 86 setEndingVisibleSelection(m_startingSelection);
86 } 87 }
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 // DeleteFromTextNodeCommand is never aborted. 523 // DeleteFromTextNodeCommand is never aborted.
523 applyCommandToComposite( 524 applyCommandToComposite(
524 DeleteFromTextNodeCommand::create(node, offset, count), 525 DeleteFromTextNodeCommand::create(node, offset, count),
525 ASSERT_NO_EDITING_ABORT); 526 ASSERT_NO_EDITING_ABORT);
526 } 527 }
527 528
528 void CompositeEditCommand::replaceTextInNode(Text* node, 529 void CompositeEditCommand::replaceTextInNode(Text* node,
529 unsigned offset, 530 unsigned offset,
530 unsigned count, 531 unsigned count,
531 const String& replacementText) { 532 const String& replacementText) {
532 // DeleteFromTextNodeCommand and InsertIntoTextNodeCommand are never 533 // SetCharacterDataCommand is never aborted.
533 // aborted.
534 applyCommandToComposite( 534 applyCommandToComposite(
535 DeleteFromTextNodeCommand::create(node, offset, count), 535 SetCharacterDataCommand::create(node, offset, count, replacementText),
536 ASSERT_NO_EDITING_ABORT); 536 ASSERT_NO_EDITING_ABORT);
537 if (!replacementText.isEmpty())
538 applyCommandToComposite(
539 InsertIntoTextNodeCommand::create(node, offset, replacementText),
540 ASSERT_NO_EDITING_ABORT);
541 } 537 }
542 538
543 Position CompositeEditCommand::replaceSelectedTextInNode(const String& text) { 539 Position CompositeEditCommand::replaceSelectedTextInNode(const String& text) {
544 Position start = endingSelection().start(); 540 Position start = endingSelection().start();
545 Position end = endingSelection().end(); 541 Position end = endingSelection().end();
546 if (start.computeContainerNode() != end.computeContainerNode() || 542 if (start.computeContainerNode() != end.computeContainerNode() ||
547 !start.computeContainerNode()->isTextNode() || 543 !start.computeContainerNode()->isTextNode() ||
548 isTabHTMLSpanElementTextNode(start.computeContainerNode())) 544 isTabHTMLSpanElementTextNode(start.computeContainerNode()))
549 return Position(); 545 return Position();
550 546
551 Text* textNode = toText(start.computeContainerNode()); 547 Text* textNode = toText(start.computeContainerNode());
552 replaceTextInNode(textNode, start.offsetInContainerNode(), 548 replaceTextInNode(textNode, start.offsetInContainerNode(),
553 end.offsetInContainerNode() - start.offsetInContainerNode(), 549 end.offsetInContainerNode() - start.offsetInContainerNode(),
554 text); 550 text);
555 551
556 return Position(textNode, start.offsetInContainerNode() + text.length()); 552 return Position(textNode, start.offsetInContainerNode() + text.length());
557 } 553 }
558 554
559 static void copyMarkerTypesAndDescriptions(
560 const DocumentMarkerVector& markerPointers,
561 Vector<DocumentMarker::MarkerType>& types,
562 Vector<String>& descriptions) {
563 size_t arraySize = markerPointers.size();
564 types.reserveCapacity(arraySize);
565 descriptions.reserveCapacity(arraySize);
566 for (const auto& markerPointer : markerPointers) {
567 types.push_back(markerPointer->type());
568 descriptions.push_back(markerPointer->description());
569 }
570 }
571
572 void CompositeEditCommand::replaceTextInNodePreservingMarkers(
573 Text* node,
574 unsigned offset,
575 unsigned count,
576 const String& replacementText) {
577 DocumentMarkerController& markerController = document().markers();
578 Vector<DocumentMarker::MarkerType> types;
579 Vector<String> descriptions;
580 copyMarkerTypesAndDescriptions(
581 markerController.markersInRange(
582 EphemeralRange(Position(node, offset),
583 Position(node, offset + count)),
584 DocumentMarker::AllMarkers()),
585 types, descriptions);
586
587 replaceTextInNode(node, offset, count, replacementText);
588
589 // Re-adding markers requires a clean tree.
590 document().updateStyleAndLayout();
591
592 DocumentLifecycle::DisallowTransitionScope disallowTransition(
593 document().lifecycle());
594 Position startPosition(node, offset);
595 Position endPosition(node, offset + replacementText.length());
596 DCHECK_EQ(types.size(), descriptions.size());
597
598 for (size_t i = 0; i < types.size(); ++i)
599 markerController.addMarker(startPosition, endPosition, types[i],
600 descriptions[i]);
601 }
602
603 Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos) { 555 Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos) {
604 if (!isTabHTMLSpanElementTextNode(pos.anchorNode())) 556 if (!isTabHTMLSpanElementTextNode(pos.anchorNode()))
605 return pos; 557 return pos;
606 558
607 switch (pos.anchorType()) { 559 switch (pos.anchorType()) {
608 case PositionAnchorType::BeforeChildren: 560 case PositionAnchorType::BeforeChildren:
609 case PositionAnchorType::AfterChildren: 561 case PositionAnchorType::AfterChildren:
610 NOTREACHED(); 562 NOTREACHED();
611 return pos; 563 return pos;
612 case PositionAnchorType::OffsetInAnchor: 564 case PositionAnchorType::OffsetInAnchor:
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
765 !isWhitespace(toText(textNode->nextSibling())->data()[0]); 717 !isWhitespace(toText(textNode->nextSibling())->data()[0]);
766 const bool shouldEmitNBSPbeforeEnd = 718 const bool shouldEmitNBSPbeforeEnd =
767 (isEndOfParagraph(visibleDownstreamPos) || 719 (isEndOfParagraph(visibleDownstreamPos) ||
768 (unsigned)downstream == text.length()) && 720 (unsigned)downstream == text.length()) &&
769 !nextSiblingIsTextNode; 721 !nextSiblingIsTextNode;
770 String rebalancedString = stringWithRebalancedWhitespace( 722 String rebalancedString = stringWithRebalancedWhitespace(
771 string, isStartOfParagraph(visibleUpstreamPos) || !upstream, 723 string, isStartOfParagraph(visibleUpstreamPos) || !upstream,
772 shouldEmitNBSPbeforeEnd); 724 shouldEmitNBSPbeforeEnd);
773 725
774 if (string != rebalancedString) 726 if (string != rebalancedString)
775 replaceTextInNodePreservingMarkers(textNode, upstream, length, 727 replaceTextInNode(textNode, upstream, length, rebalancedString);
776 rebalancedString);
777 } 728 }
778 729
779 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit( 730 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(
780 Position& position) { 731 Position& position) {
781 if (!isRichlyEditablePosition(position)) 732 if (!isRichlyEditablePosition(position))
782 return; 733 return;
783 Node* node = position.anchorNode(); 734 Node* node = position.anchorNode();
784 if (!node || !node->isTextNode()) 735 if (!node || !node->isTextNode())
785 return; 736 return;
786 Text* textNode = toText(node); 737 Text* textNode = toText(node);
(...skipping 20 matching lines...) Expand all
807 } 758 }
808 759
809 void CompositeEditCommand:: 760 void CompositeEditCommand::
810 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded( 761 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(
811 const VisiblePosition& visiblePosition) { 762 const VisiblePosition& visiblePosition) {
812 if (!isCollapsibleWhitespace(characterAfter(visiblePosition))) 763 if (!isCollapsibleWhitespace(characterAfter(visiblePosition)))
813 return; 764 return;
814 Position pos = mostForwardCaretPosition(visiblePosition.deepEquivalent()); 765 Position pos = mostForwardCaretPosition(visiblePosition.deepEquivalent());
815 if (!pos.computeContainerNode() || !pos.computeContainerNode()->isTextNode()) 766 if (!pos.computeContainerNode() || !pos.computeContainerNode()->isTextNode())
816 return; 767 return;
817 replaceTextInNodePreservingMarkers(toText(pos.computeContainerNode()), 768 replaceTextInNode(toText(pos.computeContainerNode()),
818 pos.offsetInContainerNode(), 1, 769 pos.offsetInContainerNode(), 1, nonBreakingSpaceString());
819 nonBreakingSpaceString());
820 } 770 }
821 771
822 void CompositeEditCommand::rebalanceWhitespace() { 772 void CompositeEditCommand::rebalanceWhitespace() {
823 VisibleSelection selection = endingSelection(); 773 VisibleSelection selection = endingSelection();
824 if (selection.isNone()) 774 if (selection.isNone())
825 return; 775 return;
826 776
827 rebalanceWhitespaceAt(selection.start()); 777 rebalanceWhitespaceAt(selection.start());
828 if (selection.isRange()) 778 if (selection.isRange())
829 rebalanceWhitespaceAt(selection.end()); 779 rebalanceWhitespaceAt(selection.end());
(...skipping 1140 matching lines...) Expand 10 before | Expand all | Expand 10 after
1970 1920
1971 DEFINE_TRACE(CompositeEditCommand) { 1921 DEFINE_TRACE(CompositeEditCommand) {
1972 visitor->trace(m_commands); 1922 visitor->trace(m_commands);
1973 visitor->trace(m_startingSelection); 1923 visitor->trace(m_startingSelection);
1974 visitor->trace(m_endingSelection); 1924 visitor->trace(m_endingSelection);
1975 visitor->trace(m_undoStep); 1925 visitor->trace(m_undoStep);
1976 EditCommand::trace(visitor); 1926 EditCommand::trace(visitor);
1977 } 1927 }
1978 1928
1979 } // namespace blink 1929 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698