• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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