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

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

Issue 2530843003: Introduce InsertIncrementalTextCommand to respect existing style for composition (Closed)
Patch Set: A little change Created 4 years 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
(Empty)
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/editing/commands/InsertIncrementalTextCommand.h"
6
7 #include "core/dom/Document.h"
8 #include "core/dom/Element.h"
9 #include "core/dom/Text.h"
10 #include "core/editing/EditingUtilities.h"
11 #include "core/editing/Editor.h"
12 #include "core/editing/PlainTextRange.h"
13 #include "core/editing/VisibleUnits.h"
14 #include "core/editing/iterators/CharacterIterator.h"
15 #include "core/frame/LocalFrame.h"
Xiaocheng 2016/12/09 05:10:30 We don't need it anymore.
yabinh 2016/12/09 06:16:47 Done.
16 #include "core/html/HTMLSpanElement.h"
17
18 namespace blink {
19
20 namespace {
21
22 size_t computeCommonPrefixLength(const String& str1, const String& str2) {
23 const size_t maxCommonPrefixLength = std::min(str1.length(), str2.length());
24 for (size_t index = 0; index < maxCommonPrefixLength; ++index) {
25 if (str1[index] != str2[index])
26 return index;
27 }
28 return maxCommonPrefixLength;
29 }
30
31 size_t computeCommonSuffixLength(const String& str1, const String& str2) {
32 const size_t length1 = str1.length();
33 const size_t length2 = str2.length();
34 const size_t maxCommonSuffixLength = std::min(length1, length2);
35 for (size_t index = 0; index < maxCommonSuffixLength; ++index) {
36 if (str1[length1 - index - 1] != str2[length2 - index - 1])
37 return index;
38 }
39 return maxCommonSuffixLength;
40 }
41
42 // If current position is at grapheme boundary, return 0; otherwise, return the
43 // distance to its nearest left grapheme boundary.
44 size_t computeDistanceToLeftGraphemeBoundary(const Position& position) {
45 const Position& adjustedPosition = previousPositionOf(
46 nextPositionOf(position, PositionMoveType::GraphemeCluster),
47 PositionMoveType::GraphemeCluster);
48 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode());
49 DCHECK_GE(position.computeOffsetInContainerNode(),
50 adjustedPosition.computeOffsetInContainerNode());
51 return static_cast<size_t>(position.computeOffsetInContainerNode() -
52 adjustedPosition.computeOffsetInContainerNode());
53 }
54
55 size_t computeCommonGraphemeClusterPrefixLength(
56 const String& oldText,
57 const String& newText,
58 const Element* rootEditableElement) {
59 const size_t commonPrefixLength = computeCommonPrefixLength(oldText, newText);
60
61 // For grapheme cluster, we should adjust it for grapheme boundary.
62 const EphemeralRange& range =
63 PlainTextRange(0, commonPrefixLength).createRange(*rootEditableElement);
64 if (range.isNull())
65 return 0;
66 const Position& position = range.endPosition();
67 const size_t diff = computeDistanceToLeftGraphemeBoundary(position);
68 DCHECK_GE(commonPrefixLength, diff);
69 return commonPrefixLength - diff;
70 }
71
72 // If current position is at grapheme boundary, return 0; otherwise, return the
73 // distance to its nearest right grapheme boundary.
74 size_t computeDistanceToRightGraphemeBoundary(const Position& position) {
75 const Position& adjustedPosition = nextPositionOf(
76 previousPositionOf(position, PositionMoveType::GraphemeCluster),
77 PositionMoveType::GraphemeCluster);
78 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode());
79 DCHECK_GE(adjustedPosition.computeOffsetInContainerNode(),
80 position.computeOffsetInContainerNode());
81 return static_cast<size_t>(adjustedPosition.computeOffsetInContainerNode() -
82 position.computeOffsetInContainerNode());
83 }
84
85 size_t computeCommonGraphemeClusterSuffixLength(
86 const String& oldText,
87 const String& newText,
88 const Element* rootEditableElement) {
89 const size_t commonSuffixLength = computeCommonSuffixLength(oldText, newText);
90
91 // For grapheme cluster, we should adjust it for grapheme boundary.
92 const EphemeralRange& range =
93 PlainTextRange(0, oldText.length() - commonSuffixLength)
94 .createRange(*rootEditableElement);
95 if (range.isNull())
96 return 0;
97 const Position& position = range.endPosition();
98 const size_t diff = computeDistanceToRightGraphemeBoundary(position);
99 DCHECK_GE(commonSuffixLength, diff);
100 return commonSuffixLength - diff;
101 }
102
103 const String computeTextForInsertion(const String& newText,
104 const size_t commonPrefixLength,
105 const size_t commonSuffixLength) {
106 return newText.substring(
107 commonPrefixLength,
108 newText.length() - commonPrefixLength - commonSuffixLength);
109 }
110
111 VisibleSelection computeSelectionForInsertion(
112 const EphemeralRange& selectionRange,
113 const int offset,
114 const int length,
115 const bool isDirectional) {
116 CharacterIterator charIt(selectionRange);
117 const EphemeralRange& rangeForInsertion =
118 charIt.calculateCharacterSubrange(offset, length);
119 const VisibleSelection& selection =
120 createVisibleSelection(SelectionInDOMTree::Builder()
121 .setBaseAndExtent(rangeForInsertion)
122 .setIsDirectional(isDirectional)
123 .build());
124 return selection;
125 }
126
127 } // anonymous namespace
128
129 InsertIncrementalTextCommand* InsertIncrementalTextCommand::create(
130 Document& document,
131 const String& text,
132 bool selectInsertedText,
133 RebalanceType rebalanceType) {
134 return new InsertIncrementalTextCommand(document, text, selectInsertedText,
135 rebalanceType);
136 }
137
138 InsertIncrementalTextCommand::InsertIncrementalTextCommand(
139 Document& document,
140 const String& text,
141 bool selectInsertedText,
142 RebalanceType rebalanceType)
143 : InsertTextCommand(document, text, selectInsertedText, rebalanceType) {}
144
145 void InsertIncrementalTextCommand::doApply(EditingState* editingState) {
146 LocalFrame* frame = document().frame();
Xiaocheng 2016/12/09 05:10:30 We don't need |frame| anymore.
yabinh 2016/12/09 06:16:47 Done.
147 DCHECK(frame);
148 const Element* element = endingSelection().rootEditableElement();
149 DCHECK(element);
150
151 const EphemeralRange selectionRange(endingSelection().start(),
152 endingSelection().end());
153 const String oldText = plainText(selectionRange);
154 const String& newText = m_text;
155
156 const size_t newTextLength = newText.length();
157 const size_t oldTextLength = oldText.length();
158 const size_t commonPrefixLength =
159 computeCommonGraphemeClusterPrefixLength(oldText, newText, element);
160 // We should ignore common prefix when finding common suffix.
161 const size_t commonSuffixLength = computeCommonGraphemeClusterSuffixLength(
162 oldText.right(oldTextLength - commonPrefixLength),
163 newText.right(newTextLength - commonPrefixLength), element);
164 DCHECK_GE(oldTextLength, commonPrefixLength + commonSuffixLength);
165
166 m_text =
167 computeTextForInsertion(m_text, commonPrefixLength, commonSuffixLength);
168
169 const int offset = static_cast<int>(commonPrefixLength);
170 const int length =
171 static_cast<int>(oldTextLength - commonPrefixLength - commonSuffixLength);
172 const VisibleSelection& selectionForInsertion = computeSelectionForInsertion(
173 selectionRange, offset, length, endingSelection().isDirectional());
174
175 setEndingSelectionWithoutValidation(selectionForInsertion.start(),
176 selectionForInsertion.end());
177
178 InsertTextCommand::doApply(editingState);
179 }
180
181 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698