1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/common/ime/text_editing_value.h"
17
18 #include "base/json/json_util.h"
19 #include "base/log/log.h"
20 #include "base/utils/macros.h"
21 #include "base/utils/string_utils.h"
22
23 namespace OHOS::Ace {
24 namespace {
25
26 // Negotiated fields with Java
27 const char TEXT[] = "text";
28 const char HINT[] = "hint";
29 const char SELECTION_START[] = "selectionStart";
30 const char SELECTION_END[] = "selectionEnd";
31
32 } // namespace
33
ParseFromJson(const JsonValue & json)34 void TextEditingValue::ParseFromJson(const JsonValue& json)
35 {
36 text = json.GetString(TEXT);
37 hint = json.GetString(HINT);
38 selection.baseOffset = json.GetInt(SELECTION_START, -1);
39 selection.extentOffset = json.GetInt(SELECTION_END, -1);
40 }
41
ToJsonString() const42 std::string TextEditingValue::ToJsonString() const
43 {
44 auto json = JsonUtil::Create(true);
45 json->Put(TEXT, text.c_str());
46 json->Put(HINT, hint.c_str());
47 json->Put(SELECTION_START, selection.baseOffset);
48 json->Put(SELECTION_END, selection.extentOffset);
49 return json->ToString();
50 }
51
operator ==(const TextEditingValue & other) const52 bool TextEditingValue::operator==(const TextEditingValue& other) const
53 {
54 if (selection != other.selection) {
55 return false;
56 }
57
58 return text == other.text && hint == other.hint;
59 }
60
operator !=(const TextEditingValue & other) const61 bool TextEditingValue::operator!=(const TextEditingValue& other) const
62 {
63 return !operator==(other);
64 }
65
GetWideText() const66 std::wstring TextEditingValue::GetWideText() const
67 {
68 return StringUtils::ToWstring(text);
69 }
70
MoveLeft()71 void TextEditingValue::MoveLeft()
72 {
73 if (selection.extentOffset <= 1) {
74 selection.Update(0);
75 return;
76 }
77
78 auto utf16Text = StringUtils::Str8ToStr16(text);
79 int32_t prevCharIndex = std::min(selection.extentOffset - 1, static_cast<int32_t>(utf16Text.length()));
80 selection.Update(StringUtils::NotInUtf16Bmp(utf16Text[prevCharIndex]) ? prevCharIndex - 1 : prevCharIndex);
81 }
82
MoveRight()83 void TextEditingValue::MoveRight()
84 {
85 auto utf16Text = StringUtils::Str8ToStr16(text);
86 if (static_cast<size_t>(selection.extentOffset) >= utf16Text.length() - 1) {
87 selection.Update(utf16Text.length());
88 return;
89 }
90
91 int32_t nextCharIndex = selection.extentOffset;
92 selection.Update(StringUtils::NotInUtf16Bmp(utf16Text[nextCharIndex])
93 ? std::min(static_cast<int32_t>(utf16Text.length()), nextCharIndex + 2)
94 : nextCharIndex + 1);
95 }
96
MoveToPosition(int32_t position)97 void TextEditingValue::MoveToPosition(int32_t position)
98 {
99 if (position < 0) {
100 selection.Update(0);
101 return;
102 }
103 auto utf16Text = StringUtils::Str8ToStr16(text);
104 if (static_cast<size_t>(position) >= utf16Text.length()) {
105 selection.Update(utf16Text.length());
106 return;
107 }
108 selection.Update(position);
109 }
110
UpdateSelection(int32_t both)111 void TextEditingValue::UpdateSelection(int32_t both)
112 {
113 UpdateSelection(both, both);
114 }
115
UpdateSelection(int32_t start,int32_t end)116 void TextEditingValue::UpdateSelection(int32_t start, int32_t end)
117 {
118 if (start < 0) {
119 start = 0;
120 }
121 if (static_cast<size_t>(end) > GetWideText().length()) {
122 end = static_cast<int32_t>(GetWideText().length());
123 }
124 selection.Update(start, end);
125 }
126
127 #if defined(IOS_PLATFORM)
UpdateCompose(int32_t start,int32_t end)128 void TextEditingValue::UpdateCompose(int32_t start, int32_t end)
129 {
130 compose.Update(start, end);
131 }
132 #endif
133
134
SelectionAwareTextManipulation(const TextManipulation & manipulation)135 void TextEditingValue::SelectionAwareTextManipulation(const TextManipulation& manipulation)
136 {
137 if (!manipulation) {
138 return;
139 }
140
141 auto wideText = GetWideText();
142 int32_t start = selection.GetStart();
143 int32_t end = selection.GetEnd();
144 if (static_cast<size_t>(end) > wideText.length() || start > end) {
145 LOGD("Illegal selection for manipulate: start %{public}d, end %{public}d", start, end);
146 return;
147 }
148
149 if ((start <= 0) && (end <= 0)) {
150 manipulation(wideText);
151 } else {
152 std::wstring beforeSelection;
153 if ((start > 0) && (static_cast<size_t>(start) <= wideText.length())) {
154 beforeSelection = wideText.substr(0, start);
155 manipulation(beforeSelection);
156 }
157
158 std::wstring inSelection;
159 if (start != end) {
160 inSelection = wideText.substr(start, end - start);
161 manipulation(inSelection);
162 }
163
164 std::wstring afterSelection;
165 size_t lenLeft = wideText.length() - static_cast<size_t>(end);
166 if (lenLeft > 0) {
167 afterSelection = wideText.substr(end, lenLeft);
168 manipulation(afterSelection);
169 }
170
171 wideText = beforeSelection + inSelection + afterSelection;
172 if (selection.baseOffset > selection.extentOffset) {
173 selection.Update(beforeSelection.length() + inSelection.length(), beforeSelection.length());
174 } else {
175 selection.Update(beforeSelection.length(), beforeSelection.length() + inSelection.length());
176 }
177 }
178
179 text = StringUtils::ToString(wideText);
180 }
181
GetBeforeSelection() const182 std::string TextEditingValue::GetBeforeSelection() const
183 {
184 auto wideText = GetWideText();
185 int32_t start = selection.GetStart();
186 if (static_cast<size_t>(start) > wideText.length()) {
187 LOGD("Illegal selection for GetBeforeSelection: start %{public}d", start);
188 return "";
189 }
190
191 std::string beforeText;
192 if (start > 0) {
193 std::wstring beforeSelection = wideText.substr(0, start);
194 beforeText = StringUtils::ToString(beforeSelection);
195 }
196 return beforeText;
197 }
198
GetSelectedText() const199 std::string TextEditingValue::GetSelectedText() const
200 {
201 auto wideText = GetWideText();
202 int32_t start = selection.GetStart();
203 int32_t end = selection.GetEnd();
204 if (static_cast<size_t>(end) > wideText.length() || start > end) {
205 LOGD("Illegal selection for GetSelectedText: start %{public}d, end %{public}d", start, end);
206 return "";
207 }
208
209 std::string selectedText;
210 if (start < 0) {
211 start = 0;
212 }
213 if (end > 0 && start != end) {
214 std::wstring inSelection = wideText.substr(start, end - start);
215 selectedText = StringUtils::ToString(inSelection);
216 }
217 return selectedText;
218 }
219
GetSelectedText(const TextSelection & textSelection) const220 std::string TextEditingValue::GetSelectedText(const TextSelection& textSelection) const
221 {
222 auto wideText = GetWideText();
223 int32_t start = textSelection.GetStart();
224 int32_t end = textSelection.GetEnd();
225 std::string selectedText;
226 if (start < 0) {
227 start = 0;
228 }
229 if (static_cast<size_t>(end) > wideText.length()) {
230 end = static_cast<int32_t>(wideText.length());
231 }
232
233 if (end > 0 && start < end) {
234 std::wstring inSelection = wideText.substr(start, end - start);
235 selectedText = StringUtils::ToString(inSelection);
236 }
237 return selectedText;
238 }
239
GetAfterSelection() const240 std::string TextEditingValue::GetAfterSelection() const
241 {
242 auto wideText = GetWideText();
243 int32_t end = selection.GetEnd();
244 if (static_cast<size_t>(end) > wideText.length()) {
245 LOGD("Illegal selection for GetAfterSelection: start %{public}d", end);
246 return "";
247 }
248
249 std::string afterText;
250 if (end <= 0) {
251 afterText = StringUtils::ToString(wideText);
252 } else {
253 std::wstring afterSelection = wideText.substr(end);
254 afterText = StringUtils::ToString(afterSelection);
255 }
256 return afterText;
257 }
258
Delete(int32_t start,int32_t end)259 void TextEditingValue::Delete(int32_t start, int32_t end)
260 {
261 auto wideText = GetWideText();
262 auto length = (int32_t)wideText.length();
263 int32_t startPos = std::max(std::min(start, end), 0);
264 int32_t endPos = std::min(std::max(start, end), length);
265 if (startPos >= endPos) {
266 return;
267 }
268
269 auto textAfterDelete = wideText.substr(0, startPos) + wideText.substr(endPos);
270 text = StringUtils::ToString(textAfterDelete);
271 selection.Update(startPos);
272 }
273
Append(const std::string & newText)274 void TextEditingValue::Append(const std::string& newText)
275 {
276 text = text + newText;
277 }
278
279 } // namespace OHOS::Ace
280