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

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 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.GetFrame() 85 SetStartingSelection(document.GetFrame()
85 ->Selection() 86 ->Selection()
86 .ComputeVisibleSelectionInDOMTreeDeprecated()); 87 .ComputeVisibleSelectionInDOMTreeDeprecated());
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 // DeleteFromTextNodeCommand is never aborted. 534 // DeleteFromTextNodeCommand is never aborted.
534 ApplyCommandToComposite( 535 ApplyCommandToComposite(
535 DeleteFromTextNodeCommand::Create(node, offset, count), 536 DeleteFromTextNodeCommand::Create(node, offset, count),
536 ASSERT_NO_EDITING_ABORT); 537 ASSERT_NO_EDITING_ABORT);
537 } 538 }
538 539
539 void CompositeEditCommand::ReplaceTextInNode(Text* node, 540 void CompositeEditCommand::ReplaceTextInNode(Text* node,
540 unsigned offset, 541 unsigned offset,
541 unsigned count, 542 unsigned count,
542 const String& replacement_text) { 543 const String& replacement_text) {
543 // DeleteFromTextNodeCommand and InsertIntoTextNodeCommand are never 544 // SetCharacterDataCommand is never aborted.
544 // aborted.
545 ApplyCommandToComposite( 545 ApplyCommandToComposite(
546 DeleteFromTextNodeCommand::Create(node, offset, count), 546 SetCharacterDataCommand::Create(node, offset, count, replacement_text),
547 ASSERT_NO_EDITING_ABORT); 547 ASSERT_NO_EDITING_ABORT);
548 if (!replacement_text.IsEmpty())
549 ApplyCommandToComposite(
550 InsertIntoTextNodeCommand::Create(node, offset, replacement_text),
551 ASSERT_NO_EDITING_ABORT);
552 } 548 }
553 549
554 Position CompositeEditCommand::ReplaceSelectedTextInNode(const String& text) { 550 Position CompositeEditCommand::ReplaceSelectedTextInNode(const String& text) {
555 Position start = EndingSelection().Start(); 551 Position start = EndingSelection().Start();
556 Position end = EndingSelection().end(); 552 Position end = EndingSelection().end();
557 if (start.ComputeContainerNode() != end.ComputeContainerNode() || 553 if (start.ComputeContainerNode() != end.ComputeContainerNode() ||
558 !start.ComputeContainerNode()->IsTextNode() || 554 !start.ComputeContainerNode()->IsTextNode() ||
559 IsTabHTMLSpanElementTextNode(start.ComputeContainerNode())) 555 IsTabHTMLSpanElementTextNode(start.ComputeContainerNode()))
560 return Position(); 556 return Position();
561 557
562 Text* text_node = ToText(start.ComputeContainerNode()); 558 Text* text_node = ToText(start.ComputeContainerNode());
563 ReplaceTextInNode(text_node, start.OffsetInContainerNode(), 559 ReplaceTextInNode(text_node, start.OffsetInContainerNode(),
564 end.OffsetInContainerNode() - start.OffsetInContainerNode(), 560 end.OffsetInContainerNode() - start.OffsetInContainerNode(),
565 text); 561 text);
566 562
567 return Position(text_node, start.OffsetInContainerNode() + text.length()); 563 return Position(text_node, start.OffsetInContainerNode() + text.length());
568 } 564 }
569 565
570 static void CopyMarkerTypesAndDescriptions(
571 const DocumentMarkerVector& marker_pointers,
572 Vector<DocumentMarker::MarkerType>& types,
573 Vector<String>& descriptions) {
574 size_t array_size = marker_pointers.size();
575 types.ReserveCapacity(array_size);
576 descriptions.ReserveCapacity(array_size);
577 for (const auto& marker_pointer : marker_pointers) {
578 types.push_back(marker_pointer->GetType());
579 descriptions.push_back(marker_pointer->Description());
580 }
581 }
582
583 void CompositeEditCommand::ReplaceTextInNodePreservingMarkers(
584 Text* node,
585 unsigned offset,
586 unsigned count,
587 const String& replacement_text) {
588 DocumentMarkerController& marker_controller = GetDocument().Markers();
589 Vector<DocumentMarker::MarkerType> types;
590 Vector<String> descriptions;
591 CopyMarkerTypesAndDescriptions(
592 marker_controller.MarkersInRange(
593 EphemeralRange(Position(node, offset),
594 Position(node, offset + count)),
595 DocumentMarker::AllMarkers()),
596 types, descriptions);
597
598 ReplaceTextInNode(node, offset, count, replacement_text);
599
600 // Re-adding markers requires a clean tree.
601 GetDocument().UpdateStyleAndLayout();
602
603 DocumentLifecycle::DisallowTransitionScope disallow_transition(
604 GetDocument().Lifecycle());
605 Position start_position(node, offset);
606 Position end_position(node, offset + replacement_text.length());
607 DCHECK_EQ(types.size(), descriptions.size());
608
609 for (size_t i = 0; i < types.size(); ++i)
610 marker_controller.AddMarker(start_position, end_position, types[i],
611 descriptions[i]);
612 }
613
614 Position CompositeEditCommand::PositionOutsideTabSpan(const Position& pos) { 566 Position CompositeEditCommand::PositionOutsideTabSpan(const Position& pos) {
615 if (!IsTabHTMLSpanElementTextNode(pos.AnchorNode())) 567 if (!IsTabHTMLSpanElementTextNode(pos.AnchorNode()))
616 return pos; 568 return pos;
617 569
618 switch (pos.AnchorType()) { 570 switch (pos.AnchorType()) {
619 case PositionAnchorType::kBeforeChildren: 571 case PositionAnchorType::kBeforeChildren:
620 case PositionAnchorType::kAfterChildren: 572 case PositionAnchorType::kAfterChildren:
621 NOTREACHED(); 573 NOTREACHED();
622 return pos; 574 return pos;
623 case PositionAnchorType::kOffsetInAnchor: 575 case PositionAnchorType::kOffsetInAnchor:
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
768 !IsWhitespace(ToText(text_node->nextSibling())->data()[0]); 720 !IsWhitespace(ToText(text_node->nextSibling())->data()[0]);
769 const bool should_emit_nbs_pbefore_end = 721 const bool should_emit_nbs_pbefore_end =
770 (IsEndOfParagraph(visible_downstream_pos) || 722 (IsEndOfParagraph(visible_downstream_pos) ||
771 (unsigned)downstream == text.length()) && 723 (unsigned)downstream == text.length()) &&
772 !next_sibling_is_text_node; 724 !next_sibling_is_text_node;
773 String rebalanced_string = StringWithRebalancedWhitespace( 725 String rebalanced_string = StringWithRebalancedWhitespace(
774 string, IsStartOfParagraph(visible_upstream_pos) || !upstream, 726 string, IsStartOfParagraph(visible_upstream_pos) || !upstream,
775 should_emit_nbs_pbefore_end); 727 should_emit_nbs_pbefore_end);
776 728
777 if (string != rebalanced_string) 729 if (string != rebalanced_string)
778 ReplaceTextInNodePreservingMarkers(text_node, upstream, length, 730 ReplaceTextInNode(text_node, upstream, length, rebalanced_string);
779 rebalanced_string);
780 } 731 }
781 732
782 void CompositeEditCommand::PrepareWhitespaceAtPositionForSplit( 733 void CompositeEditCommand::PrepareWhitespaceAtPositionForSplit(
783 Position& position) { 734 Position& position) {
784 if (!IsRichlyEditablePosition(position)) 735 if (!IsRichlyEditablePosition(position))
785 return; 736 return;
786 Node* node = position.AnchorNode(); 737 Node* node = position.AnchorNode();
787 if (!node || !node->IsTextNode()) 738 if (!node || !node->IsTextNode())
788 return; 739 return;
789 Text* text_node = ToText(node); 740 Text* text_node = ToText(node);
(...skipping 21 matching lines...) Expand all
811 } 762 }
812 763
813 void CompositeEditCommand:: 764 void CompositeEditCommand::
814 ReplaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded( 765 ReplaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(
815 const VisiblePosition& visible_position) { 766 const VisiblePosition& visible_position) {
816 if (!IsCollapsibleWhitespace(CharacterAfter(visible_position))) 767 if (!IsCollapsibleWhitespace(CharacterAfter(visible_position)))
817 return; 768 return;
818 Position pos = MostForwardCaretPosition(visible_position.DeepEquivalent()); 769 Position pos = MostForwardCaretPosition(visible_position.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 1188 matching lines...) Expand 10 before | Expand all | Expand 10 after
2022 1972
2023 DEFINE_TRACE(CompositeEditCommand) { 1973 DEFINE_TRACE(CompositeEditCommand) {
2024 visitor->Trace(commands_); 1974 visitor->Trace(commands_);
2025 visitor->Trace(starting_selection_); 1975 visitor->Trace(starting_selection_);
2026 visitor->Trace(ending_selection_); 1976 visitor->Trace(ending_selection_);
2027 visitor->Trace(undo_step_); 1977 visitor->Trace(undo_step_);
2028 EditCommand::Trace(visitor); 1978 EditCommand::Trace(visitor);
2029 } 1979 }
2030 1980
2031 } // namespace blink 1981 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698