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