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

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

Issue 2692093003: Rewrite DocumentMarkerController to use SynchronousMutationObserver (Closed)
Patch Set: Fx tests to match current behavior of master Created 3 years, 9 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() 85 setStartingSelection(document.frame()
85 ->selection() 86 ->selection()
86 .computeVisibleSelectionInDOMTreeDeprecated()); 87 .computeVisibleSelectionInDOMTreeDeprecated());
(...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 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 !isWhitespace(toText(textNode->nextSibling())->data()[0]); 721 !isWhitespace(toText(textNode->nextSibling())->data()[0]);
770 const bool shouldEmitNBSPbeforeEnd = 722 const bool shouldEmitNBSPbeforeEnd =
771 (isEndOfParagraph(visibleDownstreamPos) || 723 (isEndOfParagraph(visibleDownstreamPos) ||
772 (unsigned)downstream == text.length()) && 724 (unsigned)downstream == text.length()) &&
773 !nextSiblingIsTextNode; 725 !nextSiblingIsTextNode;
774 String rebalancedString = stringWithRebalancedWhitespace( 726 String rebalancedString = stringWithRebalancedWhitespace(
775 string, isStartOfParagraph(visibleUpstreamPos) || !upstream, 727 string, isStartOfParagraph(visibleUpstreamPos) || !upstream,
776 shouldEmitNBSPbeforeEnd); 728 shouldEmitNBSPbeforeEnd);
777 729
778 if (string != rebalancedString) 730 if (string != rebalancedString)
779 replaceTextInNodePreservingMarkers(textNode, upstream, length, 731 replaceTextInNode(textNode, upstream, length, rebalancedString);
780 rebalancedString);
781 } 732 }
782 733
783 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit( 734 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(
784 Position& position) { 735 Position& position) {
785 if (!isRichlyEditablePosition(position)) 736 if (!isRichlyEditablePosition(position))
786 return; 737 return;
787 Node* node = position.anchorNode(); 738 Node* node = position.anchorNode();
788 if (!node || !node->isTextNode()) 739 if (!node || !node->isTextNode())
789 return; 740 return;
790 Text* textNode = toText(node); 741 Text* textNode = toText(node);
(...skipping 20 matching lines...) Expand all
811 } 762 }
812 763
813 void CompositeEditCommand:: 764 void CompositeEditCommand::
814 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded( 765 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(
815 const VisiblePosition& visiblePosition) { 766 const VisiblePosition& visiblePosition) {
816 if (!isCollapsibleWhitespace(characterAfter(visiblePosition))) 767 if (!isCollapsibleWhitespace(characterAfter(visiblePosition)))
817 return; 768 return;
818 Position pos = mostForwardCaretPosition(visiblePosition.deepEquivalent()); 769 Position pos = mostForwardCaretPosition(visiblePosition.deepEquivalent());
819 if (!pos.computeContainerNode() || !pos.computeContainerNode()->isTextNode()) 770 if (!pos.computeContainerNode() || !pos.computeContainerNode()->isTextNode())
820 return; 771 return;
821 replaceTextInNodePreservingMarkers(toText(pos.computeContainerNode()), 772 replaceTextInNode(toText(pos.computeContainerNode()),
822 pos.offsetInContainerNode(), 1, 773 pos.offsetInContainerNode(), 1, nonBreakingSpaceString());
823 nonBreakingSpaceString());
824 } 774 }
825 775
826 void CompositeEditCommand::rebalanceWhitespace() { 776 void CompositeEditCommand::rebalanceWhitespace() {
827 VisibleSelection selection = endingSelection(); 777 VisibleSelection selection = endingSelection();
828 if (selection.isNone()) 778 if (selection.isNone())
829 return; 779 return;
830 780
831 rebalanceWhitespaceAt(selection.start()); 781 rebalanceWhitespaceAt(selection.start());
832 if (selection.isRange()) 782 if (selection.isRange())
833 rebalanceWhitespaceAt(selection.end()); 783 rebalanceWhitespaceAt(selection.end());
(...skipping 1140 matching lines...) Expand 10 before | Expand all | Expand 10 after
1974 1924
1975 DEFINE_TRACE(CompositeEditCommand) { 1925 DEFINE_TRACE(CompositeEditCommand) {
1976 visitor->trace(m_commands); 1926 visitor->trace(m_commands);
1977 visitor->trace(m_startingSelection); 1927 visitor->trace(m_startingSelection);
1978 visitor->trace(m_endingSelection); 1928 visitor->trace(m_endingSelection);
1979 visitor->trace(m_undoStep); 1929 visitor->trace(m_undoStep);
1980 EditCommand::trace(visitor); 1930 EditCommand::trace(visitor);
1981 } 1931 }
1982 1932
1983 } // namespace blink 1933 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698