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

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

Issue 2755013004: Improve how DocumentMarkerController updates markers in response to text edits (Closed)
Patch Set: Rebase (Vector::remove() => Vector::erase()) Created 3 years, 8 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 438 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 // DeleteFromTextNodeCommand is never aborted. 526 // DeleteFromTextNodeCommand is never aborted.
526 applyCommandToComposite( 527 applyCommandToComposite(
527 DeleteFromTextNodeCommand::create(node, offset, count), 528 DeleteFromTextNodeCommand::create(node, offset, count),
528 ASSERT_NO_EDITING_ABORT); 529 ASSERT_NO_EDITING_ABORT);
529 } 530 }
530 531
531 void CompositeEditCommand::replaceTextInNode(Text* node, 532 void CompositeEditCommand::replaceTextInNode(Text* node,
532 unsigned offset, 533 unsigned offset,
533 unsigned count, 534 unsigned count,
534 const String& replacementText) { 535 const String& replacementText) {
535 // DeleteFromTextNodeCommand and InsertIntoTextNodeCommand are never 536 // SetCharacterDataCommand is never aborted.
536 // aborted.
537 applyCommandToComposite( 537 applyCommandToComposite(
538 DeleteFromTextNodeCommand::create(node, offset, count), 538 SetCharacterDataCommand::create(node, offset, count, replacementText),
539 ASSERT_NO_EDITING_ABORT); 539 ASSERT_NO_EDITING_ABORT);
540 if (!replacementText.isEmpty())
541 applyCommandToComposite(
542 InsertIntoTextNodeCommand::create(node, offset, replacementText),
543 ASSERT_NO_EDITING_ABORT);
544 } 540 }
545 541
546 Position CompositeEditCommand::replaceSelectedTextInNode(const String& text) { 542 Position CompositeEditCommand::replaceSelectedTextInNode(const String& text) {
547 Position start = endingSelection().start(); 543 Position start = endingSelection().start();
548 Position end = endingSelection().end(); 544 Position end = endingSelection().end();
549 if (start.computeContainerNode() != end.computeContainerNode() || 545 if (start.computeContainerNode() != end.computeContainerNode() ||
550 !start.computeContainerNode()->isTextNode() || 546 !start.computeContainerNode()->isTextNode() ||
551 isTabHTMLSpanElementTextNode(start.computeContainerNode())) 547 isTabHTMLSpanElementTextNode(start.computeContainerNode()))
552 return Position(); 548 return Position();
553 549
554 Text* textNode = toText(start.computeContainerNode()); 550 Text* textNode = toText(start.computeContainerNode());
555 replaceTextInNode(textNode, start.offsetInContainerNode(), 551 replaceTextInNode(textNode, start.offsetInContainerNode(),
556 end.offsetInContainerNode() - start.offsetInContainerNode(), 552 end.offsetInContainerNode() - start.offsetInContainerNode(),
557 text); 553 text);
558 554
559 return Position(textNode, start.offsetInContainerNode() + text.length()); 555 return Position(textNode, start.offsetInContainerNode() + text.length());
560 } 556 }
561 557
562 static void copyMarkerTypesAndDescriptions(
563 const DocumentMarkerVector& markerPointers,
564 Vector<DocumentMarker::MarkerType>& types,
565 Vector<String>& descriptions) {
566 size_t arraySize = markerPointers.size();
567 types.reserveCapacity(arraySize);
568 descriptions.reserveCapacity(arraySize);
569 for (const auto& markerPointer : markerPointers) {
570 types.push_back(markerPointer->type());
571 descriptions.push_back(markerPointer->description());
572 }
573 }
574
575 void CompositeEditCommand::replaceTextInNodePreservingMarkers(
576 Text* node,
577 unsigned offset,
578 unsigned count,
579 const String& replacementText) {
580 DocumentMarkerController& markerController = document().markers();
581 Vector<DocumentMarker::MarkerType> types;
582 Vector<String> descriptions;
583 copyMarkerTypesAndDescriptions(
584 markerController.markersInRange(
585 EphemeralRange(Position(node, offset),
586 Position(node, offset + count)),
587 DocumentMarker::AllMarkers()),
588 types, descriptions);
589
590 replaceTextInNode(node, offset, count, replacementText);
591
592 // Re-adding markers requires a clean tree.
593 document().updateStyleAndLayout();
594
595 DocumentLifecycle::DisallowTransitionScope disallowTransition(
596 document().lifecycle());
597 Position startPosition(node, offset);
598 Position endPosition(node, offset + replacementText.length());
599 DCHECK_EQ(types.size(), descriptions.size());
600
601 for (size_t i = 0; i < types.size(); ++i)
602 markerController.addMarker(startPosition, endPosition, types[i],
603 descriptions[i]);
604 }
605
606 Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos) { 558 Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos) {
607 if (!isTabHTMLSpanElementTextNode(pos.anchorNode())) 559 if (!isTabHTMLSpanElementTextNode(pos.anchorNode()))
608 return pos; 560 return pos;
609 561
610 switch (pos.anchorType()) { 562 switch (pos.anchorType()) {
611 case PositionAnchorType::BeforeChildren: 563 case PositionAnchorType::BeforeChildren:
612 case PositionAnchorType::AfterChildren: 564 case PositionAnchorType::AfterChildren:
613 NOTREACHED(); 565 NOTREACHED();
614 return pos; 566 return pos;
615 case PositionAnchorType::OffsetInAnchor: 567 case PositionAnchorType::OffsetInAnchor:
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
759 !isWhitespace(toText(textNode->nextSibling())->data()[0]); 711 !isWhitespace(toText(textNode->nextSibling())->data()[0]);
760 const bool shouldEmitNBSPbeforeEnd = 712 const bool shouldEmitNBSPbeforeEnd =
761 (isEndOfParagraph(visibleDownstreamPos) || 713 (isEndOfParagraph(visibleDownstreamPos) ||
762 (unsigned)downstream == text.length()) && 714 (unsigned)downstream == text.length()) &&
763 !nextSiblingIsTextNode; 715 !nextSiblingIsTextNode;
764 String rebalancedString = stringWithRebalancedWhitespace( 716 String rebalancedString = stringWithRebalancedWhitespace(
765 string, isStartOfParagraph(visibleUpstreamPos) || !upstream, 717 string, isStartOfParagraph(visibleUpstreamPos) || !upstream,
766 shouldEmitNBSPbeforeEnd); 718 shouldEmitNBSPbeforeEnd);
767 719
768 if (string != rebalancedString) 720 if (string != rebalancedString)
769 replaceTextInNodePreservingMarkers(textNode, upstream, length, 721 replaceTextInNode(textNode, upstream, length, rebalancedString);
770 rebalancedString);
771 } 722 }
772 723
773 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit( 724 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(
774 Position& position) { 725 Position& position) {
775 if (!isRichlyEditablePosition(position)) 726 if (!isRichlyEditablePosition(position))
776 return; 727 return;
777 Node* node = position.anchorNode(); 728 Node* node = position.anchorNode();
778 if (!node || !node->isTextNode()) 729 if (!node || !node->isTextNode())
779 return; 730 return;
780 Text* textNode = toText(node); 731 Text* textNode = toText(node);
(...skipping 20 matching lines...) Expand all
801 } 752 }
802 753
803 void CompositeEditCommand:: 754 void CompositeEditCommand::
804 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded( 755 replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(
805 const VisiblePosition& visiblePosition) { 756 const VisiblePosition& visiblePosition) {
806 if (!isCollapsibleWhitespace(characterAfter(visiblePosition))) 757 if (!isCollapsibleWhitespace(characterAfter(visiblePosition)))
807 return; 758 return;
808 Position pos = mostForwardCaretPosition(visiblePosition.deepEquivalent()); 759 Position pos = mostForwardCaretPosition(visiblePosition.deepEquivalent());
809 if (!pos.computeContainerNode() || !pos.computeContainerNode()->isTextNode()) 760 if (!pos.computeContainerNode() || !pos.computeContainerNode()->isTextNode())
810 return; 761 return;
811 replaceTextInNodePreservingMarkers(toText(pos.computeContainerNode()), 762 replaceTextInNode(toText(pos.computeContainerNode()),
812 pos.offsetInContainerNode(), 1, 763 pos.offsetInContainerNode(), 1, nonBreakingSpaceString());
813 nonBreakingSpaceString());
814 } 764 }
815 765
816 void CompositeEditCommand::rebalanceWhitespace() { 766 void CompositeEditCommand::rebalanceWhitespace() {
817 VisibleSelection selection = endingSelection(); 767 VisibleSelection selection = endingSelection();
818 if (selection.isNone()) 768 if (selection.isNone())
819 return; 769 return;
820 770
821 rebalanceWhitespaceAt(selection.start()); 771 rebalanceWhitespaceAt(selection.start());
822 if (selection.isRange()) 772 if (selection.isRange())
823 rebalanceWhitespaceAt(selection.end()); 773 rebalanceWhitespaceAt(selection.end());
(...skipping 1172 matching lines...) Expand 10 before | Expand all | Expand 10 after
1996 1946
1997 DEFINE_TRACE(CompositeEditCommand) { 1947 DEFINE_TRACE(CompositeEditCommand) {
1998 visitor->trace(m_commands); 1948 visitor->trace(m_commands);
1999 visitor->trace(m_startingSelection); 1949 visitor->trace(m_startingSelection);
2000 visitor->trace(m_endingSelection); 1950 visitor->trace(m_endingSelection);
2001 visitor->trace(m_undoStep); 1951 visitor->trace(m_undoStep);
2002 EditCommand::trace(visitor); 1952 EditCommand::trace(visitor);
2003 } 1953 }
2004 1954
2005 } // namespace blink 1955 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698