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/utils/string_utils.h"
20
21 namespace OHOS::Ace {
22 namespace {
23
24 // Negotiated fields with Java
25 const char TEXT[] = "text";
26 const char HINT[] = "hint";
27 const char SELECTION_START[] = "selectionStart";
28 const char SELECTION_END[] = "selectionEnd";
29 const char IS_DELETE[] = "isDelete";
30 const char APPEND_TEXT[] = "appendText";
31 #if defined(IOS_PLATFORM)
32 const char UNMARK_TEXT[] = "unmarkText";
33 #endif
34
35 } // namespace
36
ParseFromJson(const JsonValue & json)37 void TextEditingValue::ParseFromJson(const JsonValue& json)
38 {
39 text = json.GetString(TEXT);
40 hint = json.GetString(HINT);
41 isDelete = json.GetBool(IS_DELETE);
42 appendText = json.GetString(APPEND_TEXT);
43 #if defined(IOS_PLATFORM)
44 unmarkText = json.GetBool(UNMARK_TEXT);
45 #endif
46 selection.baseOffset = json.GetInt(SELECTION_START, -1);
47 selection.extentOffset = json.GetInt(SELECTION_END, -1);
48 }
49
ToJsonString() const50 std::string TextEditingValue::ToJsonString() const
51 {
52 auto json = JsonUtil::Create(true);
53 json->Put(TEXT, text.c_str());
54 json->Put(HINT, hint.c_str());
55 json->Put(SELECTION_START, selection.baseOffset);
56 json->Put(SELECTION_END, selection.extentOffset);
57 return json->ToString();
58 }
59
operator ==(const TextEditingValue & other) const60 bool TextEditingValue::operator==(const TextEditingValue& other) const
61 {
62 if (selection != other.selection) {
63 return false;
64 }
65
66 return text == other.text && hint == other.hint;
67 }
68
operator !=(const TextEditingValue & other) const69 bool TextEditingValue::operator!=(const TextEditingValue& other) const
70 {
71 return !operator==(other);
72 }
73
GetWideText() const74 std::wstring TextEditingValue::GetWideText() const
75 {
76 return StringUtils::ToWstring(text);
77 }
78
MoveLeft()79 void TextEditingValue::MoveLeft()
80 {
81 if (selection.extentOffset <= 1) {
82 selection.Update(0);
83 return;
84 }
85
86 auto utf16Text = StringUtils::Str8ToStr16(text);
87 int32_t prevCharIndex = std::min(selection.extentOffset - 1, static_cast<int32_t>(utf16Text.length()));
88 selection.Update(StringUtils::NotInUtf16Bmp(utf16Text[prevCharIndex]) ? prevCharIndex - 1 : prevCharIndex);
89 }
90
MoveRight()91 void TextEditingValue::MoveRight()
92 {
93 auto utf16Text = StringUtils::Str8ToStr16(text);
94 if (utf16Text.length() < 1) {
95 return;
96 }
97 if (static_cast<size_t>(selection.extentOffset) >= utf16Text.length() - 1) {
98 selection.Update(utf16Text.length());
99 return;
100 }
101
102 int32_t nextCharIndex = selection.extentOffset;
103 selection.Update(StringUtils::NotInUtf16Bmp(utf16Text[nextCharIndex])
104 ? std::min(static_cast<int32_t>(utf16Text.length()), nextCharIndex + 2)
105 : nextCharIndex + 1);
106 }
107
MoveToPosition(int32_t position)108 void TextEditingValue::MoveToPosition(int32_t position)
109 {
110 if (position < 0) {
111 selection.Update(0);
112 return;
113 }
114 auto utf16Text = StringUtils::Str8ToStr16(text);
115 if (static_cast<size_t>(position) >= utf16Text.length()) {
116 selection.Update(utf16Text.length());
117 return;
118 }
119 selection.Update(position);
120 }
121
UpdateSelection(int32_t both)122 void TextEditingValue::UpdateSelection(int32_t both)
123 {
124 UpdateSelection(both, both);
125 }
126
UpdateSelection(int32_t start,int32_t end)127 void TextEditingValue::UpdateSelection(int32_t start, int32_t end)
128 {
129 if (start < 0) {
130 start = 0;
131 }
132 if (static_cast<size_t>(end) > GetWideText().length()) {
133 end = static_cast<int32_t>(GetWideText().length());
134 }
135 selection.Update(start, end);
136 }
137
138 #if defined(IOS_PLATFORM)
UpdateCompose(int32_t start,int32_t end)139 void TextEditingValue::UpdateCompose(int32_t start, int32_t end)
140 {
141 compose.Update(start, end);
142 }
143 #endif
144
145
SelectionAwareTextManipulation(const TextManipulation & manipulation)146 void TextEditingValue::SelectionAwareTextManipulation(const TextManipulation& manipulation)
147 {
148 if (!manipulation) {
149 return;
150 }
151
152 auto wideText = GetWideText();
153 int32_t start = selection.GetStart();
154 int32_t end = selection.GetEnd();
155 if (static_cast<size_t>(end) > wideText.length() || start > end) {
156 return;
157 }
158
159 if ((start <= 0) && (end <= 0)) {
160 manipulation(wideText);
161 } else {
162 std::wstring beforeSelection;
163 if ((start > 0) && (static_cast<size_t>(start) <= wideText.length())) {
164 beforeSelection = wideText.substr(0, start);
165 manipulation(beforeSelection);
166 }
167
168 std::wstring inSelection;
169 if (start != end) {
170 start = std::clamp(start, 0, static_cast<int32_t>(wideText.length()));
171 inSelection = wideText.substr(start, end - start);
172 manipulation(inSelection);
173 }
174
175 std::wstring afterSelection;
176 size_t lenLeft = wideText.length() - static_cast<size_t>(end);
177 if (lenLeft > 0) {
178 end = std::clamp(end, 0, static_cast<int32_t>(wideText.length()));
179 afterSelection = wideText.substr(end, lenLeft);
180 manipulation(afterSelection);
181 }
182
183 wideText = beforeSelection + inSelection + afterSelection;
184 if (selection.baseOffset > selection.extentOffset) {
185 selection.Update(beforeSelection.length() + inSelection.length(), beforeSelection.length());
186 } else {
187 selection.Update(beforeSelection.length(), beforeSelection.length() + inSelection.length());
188 }
189 }
190
191 text = StringUtils::ToString(wideText);
192 }
193
GetBeforeSelection() const194 std::string TextEditingValue::GetBeforeSelection() const
195 {
196 auto wideText = GetWideText();
197 int32_t start = selection.GetStart();
198 if (static_cast<size_t>(start) > wideText.length()) {
199 return "";
200 }
201
202 std::string beforeText;
203 if (start > 0) {
204 std::wstring beforeSelection = wideText.substr(0, start);
205 beforeText = StringUtils::ToString(beforeSelection);
206 }
207 return beforeText;
208 }
209
GetSelectedText() const210 std::string TextEditingValue::GetSelectedText() const
211 {
212 auto wideText = GetWideText();
213 int32_t start = selection.GetStart();
214 int32_t end = selection.GetEnd();
215 if (static_cast<size_t>(end) > wideText.length() || start > end) {
216 return "";
217 }
218
219 std::string selectedText;
220 if (start < 0) {
221 start = 0;
222 }
223 if (end > 0 && start != end) {
224 start = std::clamp(start, 0, static_cast<int32_t>(wideText.length()));
225 std::wstring inSelection = wideText.substr(start, end - start);
226 selectedText = StringUtils::ToString(inSelection);
227 }
228 return selectedText;
229 }
230
GetSelectedText(const TextSelection & textSelection) const231 std::string TextEditingValue::GetSelectedText(const TextSelection& textSelection) const
232 {
233 auto wideText = GetWideText();
234 int32_t start = textSelection.GetStart();
235 int32_t end = textSelection.GetEnd();
236 std::string selectedText;
237 if (start < 0) {
238 start = 0;
239 }
240 if (static_cast<size_t>(end) > wideText.length()) {
241 end = static_cast<int32_t>(wideText.length());
242 }
243
244 if (end > 0 && start < end) {
245 start = std::clamp(start, 0, static_cast<int32_t>(wideText.length()));
246 std::wstring inSelection = wideText.substr(start, end - start);
247 selectedText = StringUtils::ToString(inSelection);
248 }
249 return selectedText;
250 }
251
GetAfterSelection() const252 std::string TextEditingValue::GetAfterSelection() const
253 {
254 auto wideText = GetWideText();
255 int32_t end = selection.GetEnd();
256 if (static_cast<size_t>(end) > wideText.length()) {
257 return "";
258 }
259
260 std::string afterText;
261 if (end <= 0) {
262 afterText = StringUtils::ToString(wideText);
263 } else {
264 std::wstring afterSelection = wideText.substr(end);
265 afterText = StringUtils::ToString(afterSelection);
266 }
267 return afterText;
268 }
269
Delete(int32_t start,int32_t end)270 void TextEditingValue::Delete(int32_t start, int32_t end)
271 {
272 auto wideText = GetWideText();
273 auto length = (int32_t)wideText.length();
274 int32_t startPos = std::max(std::min(start, end), 0);
275 int32_t endPos = std::min(std::max(start, end), length);
276 if (startPos >= endPos) {
277 return;
278 }
279
280 auto textAfterDelete = wideText.substr(0, startPos) + wideText.substr(endPos);
281 text = StringUtils::ToString(textAfterDelete);
282 selection.Update(startPos);
283 }
284
Append(const std::string & newText)285 void TextEditingValue::Append(const std::string& newText)
286 {
287 text = text + newText;
288 }
289
290 } // namespace OHOS::Ace
291