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

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

Powered by Google App Engine
This is Rietveld 408576698