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

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/frame/LocalFrame.h"
15 #include "core/html/HTMLSpanElement.h"
16
17 namespace blink {
18
19 InsertIncrementalTextCommand::InsertIncrementalTextCommand(
20 Document& document,
21 const String& text,
22 bool selectInsertedText,
23 RebalanceType rebalanceType)
24 : InsertTextCommand(document, text, selectInsertedText, rebalanceType) {}
25
26 static size_t computeCommonPrefixLength(const String& str1,
yosin_UTC9 2016/12/07 05:36:22 Let's use unnamed namespace: https://chromium.goog
yabinh 2016/12/08 07:54:57 Done.
27 const String& str2) {
28 const size_t maxCommonPrefixLength = std::min(str1.length(), str2.length());
29 for (size_t index = 0; index < maxCommonPrefixLength; ++index) {
30 if (str1[index] != str2[index])
31 return index;
32 }
33 return maxCommonPrefixLength;
34 }
35
36 static size_t computeCommonSuffixLength(const String& str1,
37 const String& str2) {
38 const size_t length1 = str1.length();
39 const size_t length2 = str2.length();
40 const size_t maxCommonSuffixLength = std::min(length1, length2);
41 for (size_t index = 0; index < maxCommonSuffixLength; ++index) {
42 if (str1[length1 - index - 1] != str2[length2 - index - 1])
43 return index;
44 }
45 return maxCommonSuffixLength;
46 }
47
48 // If current position is at grapheme boundary, return 0; otherwise, return the
49 // distance to its nearest left grapheme boundary.
50 static size_t computeDistanceToLeftGraphemeBoundary(const Position& position) {
51 const Position& adjustedPosition = previousPositionOf(
52 nextPositionOf(position, PositionMoveType::GraphemeCluster),
53 PositionMoveType::GraphemeCluster);
54 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode());
55 DCHECK_GE(position.computeOffsetInContainerNode(),
56 adjustedPosition.computeOffsetInContainerNode());
57 return static_cast<size_t>(position.computeOffsetInContainerNode() -
58 adjustedPosition.computeOffsetInContainerNode());
59 }
60
61 static size_t computeCommonGraphemeClusterPrefixLength(
62 const String& oldText,
63 const String& newText,
64 const Element* rootEditableElement) {
65 const size_t commonPrefixLength = computeCommonPrefixLength(oldText, newText);
66
67 // For grapheme cluster, we should adjust it for grapheme boundary.
68 const EphemeralRange& range =
69 PlainTextRange(0, commonPrefixLength).createRange(*rootEditableElement);
Xiaocheng 2016/12/07 10:23:26 Is this correct when |oldText| is not at the begin
yabinh 2016/12/08 07:54:57 Yes. See InputMethodControllerTest#SetCompositionK
70 if (range.isNull())
71 return 0;
72 const Position& position = range.endPosition();
73 const size_t diff = computeDistanceToLeftGraphemeBoundary(position);
74 DCHECK_GE(commonPrefixLength, diff);
75 return commonPrefixLength - diff;
76 }
77
78 // If current position is at grapheme boundary, return 0; otherwise, return the
79 // distance to its nearest right grapheme boundary.
80 static size_t computeDistanceToRightGraphemeBoundary(const Position& position) {
81 const Position& adjustedPosition = nextPositionOf(
82 previousPositionOf(position, PositionMoveType::GraphemeCluster),
83 PositionMoveType::GraphemeCluster);
84 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode());
85 DCHECK_GE(adjustedPosition.computeOffsetInContainerNode(),
86 position.computeOffsetInContainerNode());
87 return static_cast<size_t>(adjustedPosition.computeOffsetInContainerNode() -
88 position.computeOffsetInContainerNode());
89 }
90
91 static size_t computeCommonGraphemeClusterSuffixLength(
92 const String& oldText,
93 const String& newText,
94 const Element* rootEditableElement) {
95 const size_t commonSuffixLength = computeCommonSuffixLength(oldText, newText);
96
97 // For grapheme cluster, we should adjust it for grapheme boundary.
98 const EphemeralRange& range =
99 PlainTextRange(0, oldText.length() - commonSuffixLength)
Xiaocheng 2016/12/07 10:23:26 Is this correct when |oldText| is not at the end o
yabinh 2016/12/08 07:54:58 ditto
100 .createRange(*rootEditableElement);
101 if (range.isNull())
102 return 0;
103 const Position& position = range.endPosition();
104 const size_t diff = computeDistanceToRightGraphemeBoundary(position);
105 DCHECK_GE(commonSuffixLength, diff);
106 return commonSuffixLength - diff;
107 }
108
109 static const String computeTextForInsertion(const String& newText,
110 const size_t commonPrefixLength,
111 const size_t commonSuffixLength) {
112 return newText.substring(
113 commonPrefixLength,
114 newText.length() - commonPrefixLength - commonSuffixLength);
115 }
116
117 static PlainTextRange getSelectionOffsets(LocalFrame* frame) {
Xiaocheng 2016/12/07 10:23:26 Let's get rid of this function. See comments on do
yabinh 2016/12/08 07:54:57 Done.
118 EphemeralRange range = firstEphemeralRangeOf(frame->selection().selection());
119 if (range.isNull())
120 return PlainTextRange();
121 ContainerNode* editable =
122 frame->selection().rootEditableElementOrTreeScopeRootNode();
123 DCHECK(editable);
124
125 return PlainTextRange::create(*editable, range);
126 }
127
128 static const VisibleSelection createSelection(const size_t start,
Xiaocheng 2016/12/07 10:23:25 Let's get rid of this function. See comments on do
yabinh 2016/12/08 07:54:57 Done.
129 const size_t end,
130 const bool isDirectional,
131 LocalFrame* frame) {
132 Element* element = frame->selection().selection().rootEditableElement();
yosin_UTC9 2016/12/07 05:23:34 Make root editable as parameter rather than passin
yabinh 2016/12/08 07:54:58 Done.
133 DCHECK(element);
134
135 const EphemeralRange& startRange =
136 PlainTextRange(0, static_cast<int>(start)).createRange(*element);
137 DCHECK(startRange.isNotNull());
138 const Position& startPosition = startRange.endPosition();
139
140 const EphemeralRange& endRange =
141 PlainTextRange(0, static_cast<int>(end)).createRange(*element);
142 DCHECK(endRange.isNotNull());
143 const Position& endPosition = endRange.endPosition();
144
145 VisibleSelection selection =
yosin_UTC9 2016/12/07 05:23:34 nit: s/VisibleSelection/const VisibleSelection&/
yabinh 2016/12/08 07:54:58 Done.
146 createVisibleSelection(SelectionInDOMTree::Builder()
147 .setBaseAndExtent(startPosition, endPosition)
148 .build());
149 selection.setIsDirectional(isDirectional);
yosin_UTC9 2016/12/07 05:23:34 Use SelectionInDOMTree::Builder::setIsDirectional(
yabinh 2016/12/08 07:54:58 Done.
150
151 return selection;
152 }
153
154 const VisibleSelection
yosin_UTC9 2016/12/07 05:23:34 nit: s/const//
yabinh 2016/12/08 07:54:58 This function has been removed.
155 InsertIncrementalTextCommand::computeSelectionForInsertion(
Xiaocheng 2016/12/07 10:23:26 Let's get rid of this function. See comments on do
yabinh 2016/12/08 07:54:57 Done.
156 const size_t selectionStart,
157 const size_t selectionEnd,
158 const size_t commonPrefixLength,
159 const size_t commonSuffixLength) {
160 const size_t insertionStart = selectionStart + commonPrefixLength;
161 const size_t insertionEnd = selectionEnd - commonSuffixLength;
162 DCHECK_LE(insertionStart, insertionEnd);
163
164 const VisibleSelection selectionForInsertion =
yosin_UTC9 2016/12/07 05:23:34 nit: s/VisibleSelection/const VisibleSelection&/
yabinh 2016/12/08 07:54:57 This function has been removed.
165 createSelection(insertionStart, insertionEnd,
166 endingSelection().isDirectional(), document().frame());
167
168 return selectionForInsertion;
169 }
170
171 void InsertIncrementalTextCommand::setSelection(const size_t start,
yosin_UTC9 2016/12/07 05:23:34 EditingCommand should not set selection by it self
yabinh 2016/12/08 07:54:58 Done.
172 const size_t end,
173 LocalFrame* frame) {
174 const VisibleSelection selection =
175 createSelection(start, end, endingSelection().isDirectional(), frame);
176 setStartingSelection(selection);
Xiaocheng 2016/12/07 10:23:25 I don't think we should change the starting select
yabinh 2016/12/08 07:54:58 Done.
177 setEndingSelectionWithoutValidation(selection.start(), selection.end());
178
179 document().frame()->selection().setSelection(selection);
180 }
181
182 void InsertIncrementalTextCommand::doApply(EditingState* editingState) {
183 LocalFrame* frame = document().frame();
184 DCHECK(frame);
185 const Element* element = endingSelection().rootEditableElement();
186 DCHECK(element);
187
188 const String oldText = frame->selectedText();
Xiaocheng 2016/12/07 10:23:26 Accessing FrameSelection from EditCommand is disco
yabinh 2016/12/08 07:54:58 Done.
189 const String& newText = m_text;
190 const size_t newTextLength = newText.length();
191 const size_t commonPrefixLength =
192 computeCommonGraphemeClusterPrefixLength(oldText, newText, element);
193 // We should ignore common prefix when finding common suffix.
194 const size_t commonSuffixLength = computeCommonGraphemeClusterSuffixLength(
195 oldText.right(oldText.length() - commonPrefixLength),
196 newText.right(newTextLength - commonPrefixLength), element);
197
198 m_text =
199 computeTextForInsertion(m_text, commonPrefixLength, commonSuffixLength);
200
201 const PlainTextRange selectionOffsets = getSelectionOffsets(frame);
Xiaocheng 2016/12/07 10:23:26 Use CharacterIterator::calculateCharacterSubrange
yabinh 2016/12/08 07:54:58 Done.
202 const size_t selectionStart = selectionOffsets.start();
203 const size_t selectionEnd = selectionOffsets.end();
204 const VisibleSelection selectionForInsertion = computeSelectionForInsertion(
205 selectionStart, selectionEnd, commonPrefixLength, commonSuffixLength);
206
207 const bool changeSelection = selectionForInsertion != endingSelection();
208
209 setStartingSelection(selectionForInsertion);
Xiaocheng 2016/12/07 10:23:26 I don't think we should change starting selection.
yabinh 2016/12/08 07:54:58 Done.
210 setEndingSelectionWithoutValidation(selectionForInsertion.start(),
211 selectionForInsertion.end());
212
213 InsertTextCommand::doApply(editingState);
214
215 if (editingState->isAborted())
216 return;
217 if (changeSelection)
218 setSelection(selectionStart, selectionStart + newTextLength, frame);
Xiaocheng 2016/12/07 10:23:26 Use |setEndingSelection| instead.
yabinh 2016/12/08 07:54:57 This function has been removed.
219 }
220
221 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698