1 /*
2 * Copyright (c) 2021-2022 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/components/text_field/render_text_field.h"
17
18 #include <regex>
19 #include <string>
20 #include <unordered_map>
21 #include <utility>
22
23 #include "base/geometry/dimension.h"
24 #include "base/i18n/localization.h"
25 #include "base/json/json_util.h"
26 #include "base/log/ace_trace.h"
27 #include "base/log/dump_log.h"
28 #include "base/log/log_wrapper.h"
29 #include "base/mousestyle/mouse_style.h"
30 #include "base/subwindow/subwindow_manager.h"
31 #include "base/utils/string_utils.h"
32 #include "base/utils/utils.h"
33 #include "core/animation/curve_animation.h"
34 #include "core/common/clipboard/clipboard_proxy.h"
35 #include "core/common/container_scope.h"
36 #include "core/common/font_manager.h"
37 #include "core/common/ime/text_input_type.h"
38 #include "core/common/text_field_manager.h"
39 #include "core/components/stack/stack_element.h"
40 #include "core/components/text/text_utils.h"
41 #include "core/components/text_overlay/text_overlay_component.h"
42 #include "core/components/text_overlay/text_overlay_element.h"
43 #include "core/components_v2/inspector/utils.h"
44 #include "core/event/ace_event_helper.h"
45 #include "core/event/mouse_event.h"
46 #if defined(ENABLE_STANDARD_INPUT)
47 #include "core/components/text_field/on_text_changed_listener_impl.h"
48 #endif
49
50 namespace OHOS::Ace {
51 namespace {
52
53 constexpr uint32_t TWINKLING_INTERVAL_MS = 500;
54 // Tick count indicate how long should the naked character should be displayed while obscure_ == true.
55 constexpr uint32_t OBSCURE_SHOW_TICKS = 3;
56 constexpr double HANDLE_HOT_ZONE = 10.0;
57
58 constexpr char16_t OBSCURING_CHARACTER = u'•';
59 constexpr char16_t OBSCURING_CHARACTER_FOR_AR = u'*';
60
61 constexpr int32_t DEFAULT_SELECT_INDEX = 0;
62 constexpr int32_t SHOW_HANDLE_DURATION = 250;
63 constexpr int32_t DOUBLE_CLICK_FINGERS = 1;
64 constexpr int32_t DOUBLE_CLICK_COUNTS = 2;
65 constexpr double FIFTY_PERCENT = 0.5;
66
67 constexpr Dimension OFFSET_FOCUS = 4.0_vp;
68 constexpr Dimension DEFLATE_RADIUS_FOCUS = 3.0_vp;
69
70 const std::string DIGIT_BLACK_LIST = "[^\\d.\\-e]+";
71 const std::string PHONE_BLACK_LIST = "[^\\d\\-\\+\\*\\#]+";
72 const std::string DIGIT_WHITE_LIST = "^[0-9]*$";
73 const std::string PHONE_WHITE_LIST = "[\\d\\-\\+\\*\\#]+";
74 const std::string EMAIL_WHITE_LIST = "[\\w.]";
75 const std::string URL_WHITE_LIST = "[a-zA-z]+://[^\\s]*";
76 const std::string NEW_LINE = "\n";
77 // Whether the system is Mac or not determines which key code is selected.
78 #if defined(MAC_PLATFORM)
79 #define KEY_META_OR_CTRL_LEFT KeyCode::KEY_META_LEFT
80 #define KEY_META_OR_CTRL_RIGHT KeyCode::KEY_META_RIGHT
81 #else
82 #define KEY_META_OR_CTRL_LEFT KeyCode::KEY_CTRL_LEFT
83 #define KEY_META_OR_CTRL_RIGHT KeyCode::KEY_CTRL_RIGHT
84 #endif
85
86 #if !defined(PREVIEW)
RemoveErrorTextFromValue(const std::string & value,const std::string & errorText,std::string & result)87 void RemoveErrorTextFromValue(const std::string& value, const std::string& errorText, std::string& result)
88 {
89 int32_t valuePtr = 0;
90 int32_t errorTextPtr = 0;
91 auto valueSize = static_cast<int32_t>(value.size());
92 auto errorTextSize = static_cast<int32_t>(errorText.size());
93 while (errorTextPtr < errorTextSize) {
94 while (value[valuePtr] != errorText[errorTextPtr] && valuePtr < valueSize) {
95 result += value[valuePtr];
96 valuePtr++;
97 }
98 // no more text left to remove in value
99 if (valuePtr >= valueSize) {
100 return;
101 }
102 // increase both value ptr and error text ptr if char in value is removed
103 valuePtr++;
104 errorTextPtr++;
105 }
106 result += value.substr(valuePtr);
107 }
108 #endif
109
GetKeyboardFilter(TextInputType keyboard,std::string & keyboardFilterValue,bool useBlackList)110 void GetKeyboardFilter(TextInputType keyboard, std::string& keyboardFilterValue, bool useBlackList)
111 {
112 switch (keyboard) {
113 case TextInputType::NUMBER: {
114 keyboardFilterValue = useBlackList ? DIGIT_BLACK_LIST : DIGIT_WHITE_LIST;
115 break;
116 }
117 case TextInputType::PHONE: {
118 keyboardFilterValue = useBlackList ? PHONE_BLACK_LIST : PHONE_WHITE_LIST;
119 break;
120 }
121 case TextInputType::EMAIL_ADDRESS: {
122 keyboardFilterValue = EMAIL_WHITE_LIST;
123 break;
124 }
125 case TextInputType::URL: {
126 keyboardFilterValue = URL_WHITE_LIST;
127 break;
128 }
129 default: {
130 // No need limit.
131 return;
132 }
133 }
134 }
135 } // namespace
136
137 #if defined(ENABLE_STANDARD_INPUT)
UpdateConfiguration()138 void RenderTextField::UpdateConfiguration()
139 {
140 MiscServices::Configuration configuration;
141 LOGI("UpdateConfiguration: Enter key type %{public}d", static_cast<int32_t>(action_));
142 LOGI("UpdateConfiguration: Enter keyboard type %{public}d", static_cast<int32_t>(keyboard_));
143 configuration.SetEnterKeyType(static_cast<MiscServices::EnterKeyType>((int32_t)action_));
144 configuration.SetTextInputType(static_cast<MiscServices::TextInputType>((int32_t)keyboard_));
145 MiscServices::InputMethodController::GetInstance()->OnConfigurationChange(configuration);
146 }
147 #endif
148
RenderTextField()149 RenderTextField::RenderTextField()
150 : twinklingInterval(TWINKLING_INTERVAL_MS), controller_(AceType::MakeRefPtr<TextEditController>())
151 {}
152
~RenderTextField()153 RenderTextField::~RenderTextField()
154 {
155 LOGI("Destruction text field.");
156 if (controller_) {
157 controller_->Clear();
158 controller_->RemoveObserver(WeakClaim(this));
159 }
160 auto pipelineContext = context_.Upgrade();
161 if (!pipelineContext) {
162 return;
163 }
164 PopTextOverlay();
165 pipelineContext->RemoveFontNode(AceType::WeakClaim(this));
166 auto fontManager = pipelineContext->GetFontManager();
167 if (fontManager) {
168 fontManager->UnRegisterCallback(AceType::WeakClaim(this));
169 fontManager->RemoveVariationNode(WeakClaim(this));
170 }
171 if (HasSurfaceChangedCallback()) {
172 LOGD("Unregister surface change callback with id %{public}d", surfaceChangedCallbackId_.value_or(-1));
173 pipelineContext->UnregisterSurfaceChangedCallback(surfaceChangedCallbackId_.value_or(-1));
174 }
175 if (HasSurfacePositionChangedCallback()) {
176 LOGD("Unregister surface position change callback with id %{public}d",
177 surfacePositionChangedCallbackId_.value_or(-1));
178 pipelineContext->UnregisterSurfacePositionChangedCallback(surfacePositionChangedCallbackId_.value_or(-1));
179 }
180 // If soft keyboard is still exist, close it.
181 if (HasConnection()) {
182 #if defined(ENABLE_STANDARD_INPUT)
183 LOGI("Destruction text field, close input method.");
184 MiscServices::InputMethodController::GetInstance()->Close();
185 #else
186 connection_->Close(GetInstanceId());
187 connection_ = nullptr;
188 #endif
189 }
190 }
191
Update(const RefPtr<Component> & component)192 void RenderTextField::Update(const RefPtr<Component>& component)
193 {
194 const RefPtr<TextFieldComponent> textField = AceType::DynamicCast<TextFieldComponent>(component);
195 if (!textField) {
196 return;
197 }
198
199 // Clear children to avoid children increase.
200 ClearChildren();
201
202 if (textField->IsTextLengthLimited()) {
203 maxLength_ = textField->GetMaxLength();
204 }
205
206 copyOption_ = textField->GetCopyOption();
207 selection_ = textField->GetSelection();
208 placeholder_ = textField->GetPlaceholder();
209 inputFilter_ = textField->GetInputFilter();
210 inactivePlaceholderColor_ = textField->GetPlaceholderColor();
211 focusPlaceholderColor_ = textField->GetFocusPlaceholderColor();
212 focusBgColor_ = textField->GetFocusBgColor();
213 focusTextColor_ = textField->GetFocusTextColor();
214 selectedColor_ = textField->GetSelectedColor();
215 pressColor_ = textField->GetPressColor();
216 hoverColor_ = textField->GetHoverColor();
217 hoverAnimationType_ = textField->GetHoverAnimationType();
218 decoration_ = textField->GetDecoration();
219 inactiveBgColor_ = textField->GetBgColor();
220 if (decoration_ && (decoration_->GetImage() || decoration_->GetGradient().IsValid())) {
221 inactiveBgColor_ = Color::TRANSPARENT;
222 focusBgColor_ = Color::TRANSPARENT;
223 }
224 originBorder_ = textField->GetOriginBorder();
225 if (style_ != textField->GetTextStyle()) {
226 ResetStatus();
227 }
228 style_ = textField->GetTextStyle();
229 placeHoldStyle_ = textField->GetPlaceHoldStyle();
230 editingStyle_ = textField->GetEditingStyle();
231 fontSize_ = style_.GetFontSize();
232 errorTextStyle_ = textField->GetErrorTextStyle();
233 errorSpacingInDimension_ = textField->GetErrorSpacing();
234 errorIsInner_ = textField->GetErrorIsInner();
235 errorBorderWidth_ = textField->GetErrorBorderWidth();
236 errorBorderColor_ = textField->GetErrorBorderColor();
237 needFade_ = textField->NeedFade();
238 inactiveTextColor_ = style_.GetTextColor();
239 maxLines_ = textField->GetTextMaxLines();
240 onTextChangeEvent_ = AceAsyncEvent<void(const std::string&)>::Create(textField->GetOnTextChange(), context_);
241 onError_ = textField->GetOnError();
242 onValueChangeEvent_ = textField->GetOnTextChange().GetUiStrFunction();
243 if (textField->GetOnChange()) {
244 onChange_ = *textField->GetOnChange();
245 }
246 if (textField->GetOnEditChanged()) {
247 onEditChanged_ = *textField->GetOnEditChanged();
248 }
249 if (textField->GetOnSubmit()) {
250 onSubmit_ = *textField->GetOnSubmit();
251 }
252 if (textField->GetOnClick()) {
253 onClick_ = *textField->GetOnClick();
254 }
255 onSelectChangeEvent_ = AceAsyncEvent<void(const std::string&)>::Create(textField->GetOnSelectChange(), context_);
256 onFinishInputEvent_ = AceAsyncEvent<void(const std::string&)>::Create(textField->GetOnFinishInput(), context_);
257 onTapEvent_ = AceAsyncEvent<void()>::Create(textField->GetOnTap(), context_);
258 catchMode_ = textField->GetOnTap().IsEmpty() || textField->GetOnTap().GetCatchMode();
259 static const int32_t bubbleModeVersion = 6;
260 auto pipeline = context_.Upgrade();
261 if (!catchMode_) {
262 if (pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
263 catchMode_ = false;
264 } else {
265 catchMode_ = true;
266 }
267 }
268 onLongPressEvent_ = AceAsyncEvent<void()>::Create(textField->GetOnLongPress(), context_);
269 textAlign_ = textField->GetTextAlign();
270 textDirection_ = textField->GetTextDirection();
271 realTextDirection_ = textDirection_;
272 showCursor_ = textField->ShowCursor();
273 UpdateObscure(textField);
274 enabled_ = textField->IsEnabled();
275 widthReserved_ = textField->GetWidthReserved();
276 blockRightShade_ = textField->GetBlockRightShade();
277 isVisible_ = textField->IsVisible();
278 showPasswordIcon_ = textField->ShowPasswordIcon();
279 if (textField->HasSetResetToStart() && textField->GetUpdateType() == UpdateType::ALL) {
280 resetToStart_ = textField->GetResetToStart();
281 }
282 if (keyboard_ != TextInputType::UNSPECIFIED && keyboard_ != textField->GetTextInputType()) {
283 LOGI("TextInput changed, close keyboard");
284 CloseKeyboard();
285 }
286 if (keyboard_ != textField->GetTextInputType()) {
287 auto context = context_.Upgrade();
288 if (context && context->GetIsDeclarative()) {
289 ClearEditingValue();
290 } else {
291 if (keyboard_ == TextInputType::VISIBLE_PASSWORD) {
292 ClearEditingValue();
293 }
294 }
295 keyboard_ = textField->GetTextInputType();
296 }
297 if (keyboard_ == TextInputType::MULTILINE) {
298 action_ = TextInputAction::DONE;
299 } else {
300 if (action_ != TextInputAction::UNSPECIFIED && action_ != textField->GetAction()) {
301 auto context = context_.Upgrade();
302 if (context && context->GetIsDeclarative()) {
303 LOGI("Action changed, close keyboard");
304 CloseKeyboard();
305 }
306 }
307 if (action_ != textField->GetAction()) {
308 action_ = textField->GetAction();
309 }
310 }
311
312 actionLabel_ = textField->GetActionLabel();
313 height_ = textField->GetHeight();
314 if (textField->IsCursorColorSet()) {
315 cursorColorIsSet_ = true;
316 cursorColor_ = textField->GetCursorColor();
317 }
318 cursorRadius_ = textField->GetCursorRadius();
319 textFieldController_ = textField->GetTextFieldController();
320 if (textFieldController_) {
321 auto weak = AceType::WeakClaim(this);
322 textFieldController_->SetCaretPosition([weak](int32_t caretPosition) {
323 auto textField = weak.Upgrade();
324 if (textField) {
325 textField->UpdateSelection(caretPosition);
326 textField->cursorPositionType_ = CursorPositionType::NORMAL;
327 textField->MarkNeedLayout();
328 }
329 });
330 }
331 if (textField->GetTextEditController() && controller_ != textField->GetTextEditController()) {
332 if (controller_) {
333 controller_->RemoveObserver(WeakClaim(this));
334 }
335 controller_ = textField->GetTextEditController();
336 }
337 if (controller_) {
338 controller_->RemoveObserver(WeakClaim(this));
339 controller_->AddObserver(WeakClaim(this));
340 controller_->SetHint(placeholder_);
341 if (textField->IsValueUpdated()) {
342 if (textField->GetValue() != GetEditingValue().text) {
343 PopTextOverlay();
344 }
345 controller_->SetText(textField->GetValue(), false);
346 }
347 }
348 // maybe change text and selection
349 ApplyRestoreInfo();
350 extend_ = textField->IsExtend();
351 softKeyboardEnabled_ = textField->IsSoftKeyboardEnabled();
352 text_ = textField->GetValue();
353 showEllipsis_ = textField->ShowEllipsis();
354 auto context = context_.Upgrade();
355 if (!clipboard_ && context) {
356 clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
357 }
358
359 if ((style_.IsAllowScale() || style_.GetFontSize().Unit() == DimensionUnit::FP) && context) {
360 context->AddFontNode(AceType::WeakClaim(this));
361 }
362
363 showCounter_ = textField->ShowCounter();
364 countTextStyle_ = textField->GetCountTextStyle();
365 overCountStyle_ = textField->GetOverCountStyle();
366 countTextStyleOuter_ = textField->GetCountTextStyleOuter();
367 overCountStyleOuter_ = textField->GetOverCountStyleOuter();
368
369 inputOptions_ = textField->GetInputOptions();
370 onOptionsClick_ = textField->GetOnOptionsClick();
371 onTranslate_ = textField->GetOnTranslate();
372 onShare_ = textField->GetOnShare();
373 onSearch_ = textField->GetOnSearch();
374 inputStyle_ = textField->GetInputStyle();
375 if (textField->IsSetFocusOnTouch()) {
376 isFocusOnTouch_ = textField->IsFocusOnTouch();
377 }
378 SetCallback(textField);
379 UpdateFocusStyles();
380 UpdateIcon(textField);
381 RegisterFontCallbacks();
382 MarkNeedLayout();
383 UpdateAccessibilityAttr();
384 }
385
SetCallback(const RefPtr<TextFieldComponent> & textField)386 void RenderTextField::SetCallback(const RefPtr<TextFieldComponent>& textField)
387 {
388 if (textField->GetOnCopy()) {
389 onCopy_ = *textField->GetOnCopy();
390 }
391 if (textField->GetOnCut()) {
392 onCut_ = *textField->GetOnCut();
393 }
394 if (textField->GetOnPaste()) {
395 onPaste_ = *textField->GetOnPaste();
396 }
397 auto pipeline = GetContext().Upgrade();
398 CHECK_NULL_VOID(pipeline);
399 if (!HasSurfaceChangedCallback()) {
400 auto callbackId =
401 pipeline->RegisterSurfaceChangedCallback([weakTextField = AceType::WeakClaim(this)](int32_t newWidth,
402 int32_t newHeight, int32_t prevWidth, int32_t prevHeight) {
403 auto textfield = weakTextField.Upgrade();
404 if (textfield) {
405 textfield->HandleSurfaceChanged(newWidth, newHeight, prevWidth, prevHeight);
406 }
407 });
408 LOGI("Add surface changed callback id %{public}d", callbackId);
409 UpdateSurfaceChangedCallbackId(callbackId);
410 }
411 if (!HasSurfacePositionChangedCallback()) {
412 auto callbackId = pipeline->RegisterSurfacePositionChangedCallback(
413 [weakTextField = AceType::WeakClaim(this)](int32_t posX, int32_t posY) {
414 auto textfield = weakTextField.Upgrade();
415 if (textfield) {
416 textfield->HandleSurfacePositionChanged(posX, posY);
417 }
418 });
419 LOGI("Add position changed callback id %{public}d", callbackId);
420 UpdateSurfacePositionChangedCallbackId(callbackId);
421 }
422 }
423
HandleSurfaceChanged(int32_t newWidth,int32_t newHeight,int32_t prevWidth,int32_t prevHeight)424 void RenderTextField::HandleSurfaceChanged(int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight)
425 {
426 LOGD("Textfield handle surface change, new width %{public}d, new height %{public}d, prev width %{public}d, prev "
427 "height %{public}d",
428 newWidth, newHeight, prevWidth, prevHeight);
429 UpdateCaretInfoToController();
430 }
431
HandleSurfacePositionChanged(int32_t posX,int32_t posY)432 void RenderTextField::HandleSurfacePositionChanged(int32_t posX, int32_t posY)
433 {
434 LOGD("Textfield handle surface position change, posX %{public}d, posY %{public}d", posX, posY);
435 UpdateCaretInfoToController();
436 }
437
UpdateCaretInfoToController()438 void RenderTextField::UpdateCaretInfoToController()
439 {
440 auto context = context_.Upgrade();
441 CHECK_NULL_VOID(context);
442 auto manager = context->GetTextFieldManager();
443 CHECK_NULL_VOID(manager);
444 auto textFieldManager = AceType::DynamicCast<TextFieldManager>(manager);
445 CHECK_NULL_VOID(textFieldManager);
446 auto weakFocusedTextField = textFieldManager->GetOnFocusTextField();
447 auto focusedTextField = weakFocusedTextField.Upgrade();
448 if (!focusedTextField || focusedTextField != AceType::Claim(this)) {
449 return;
450 }
451 #if defined(ENABLE_STANDARD_INPUT)
452 auto globalOffset = GetGlobalOffset();
453 auto windowOffset = context->GetDisplayWindowRectInfo().GetOffset();
454 MiscServices::CursorInfo cursorInfo { .left = caretRect_.Left() + globalOffset.GetX() + windowOffset.GetX(),
455 .top = caretRect_.Top() + globalOffset.GetY() + windowOffset.GetY(),
456 .width = caretRect_.Width(),
457 .height = caretRect_.Height() };
458 LOGD("UpdateCaretInfoToController, left %{public}f, top %{public}f, width %{public}f, height %{public}f",
459 cursorInfo.left, cursorInfo.top, cursorInfo.width, cursorInfo.height);
460 MiscServices::InputMethodController::GetInstance()->OnCursorUpdate(cursorInfo);
461 auto value = GetEditingValue();
462 MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
463 StringUtils::Str8ToStr16(value.text), value.selection.GetStart(), value.selection.GetEnd());
464 #endif
465 }
466
OnPaintFinish()467 void RenderTextField::OnPaintFinish()
468 {
469 UpdateFocusAnimation();
470 UpdateOverlay();
471 InitAccessibilityEventListener();
472 UpdateAccessibilityPosition();
473 auto layoutParamChanged = lastLayoutParam_.has_value() ? lastLayoutParam_.value() == GetLayoutParam() : true;
474 if (layoutParamChanged) {
475 lastLayoutParam_ = GetLayoutParam();
476 }
477 bool needNotifyChangeEvent = !isValueFromFront_ || layoutParamChanged;
478 // If height or lines is changed, make needNotifyChangeEvent_ true to notify change event.
479 if (needNotifyChangeEvent && (!NearEqual(textHeight_, textHeightLast_) || textLines_ != textLinesLast_)) {
480 needNotifyChangeEvent_ = true;
481 textHeightLast_ = textHeight_;
482 textLinesLast_ = textLines_;
483 }
484 if (needNotifyChangeEvent_ && (onTextChangeEvent_ || onValueChangeEvent_ || onChange_)) {
485 needNotifyChangeEvent_ = false;
486 if (onValueChangeEvent_) {
487 onValueChangeEvent_(GetEditingValue().text);
488 }
489 if (onTextChangeEvent_) {
490 auto jsonResult = JsonUtil::Create(true);
491 jsonResult->Put("text", GetEditingValue().text.c_str());
492 jsonResult->Put("value", GetEditingValue().text.c_str());
493 jsonResult->Put("lines", textLines_);
494 jsonResult->Put("height", textHeight_);
495 onTextChangeEvent_(std::string(R"("change",)").append(jsonResult->ToString()));
496 }
497 }
498 }
499
PerformLayout()500 void RenderTextField::PerformLayout()
501 {
502 if (!lastLayoutParam_.has_value()) {
503 lastLayoutParam_.emplace(GetLayoutParam());
504 }
505
506 if (GetEditingValue().text.empty()) {
507 cursorPositionType_ = CursorPositionType::END;
508 }
509
510 auto context = context_.Upgrade();
511 if (context && context->GetIsDeclarative()) {
512 const auto& currentText = controller_->GetValue().text;
513 showPlaceholder_ = currentText.empty();
514 if (showPlaceholder_) {
515 SetTextStyle(placeHoldStyle_);
516 } else {
517 SetTextStyle(editingStyle_);
518 }
519 }
520
521 auto pipelineContext = GetContext().Upgrade();
522 if ((style_.IsAllowScale() || style_.GetFontSize().Unit() == DimensionUnit::FP) && pipelineContext &&
523 !NearEqual(fontScale_, pipelineContext->GetFontScale())) {
524 fontScale_ = pipelineContext->GetFontScale();
525 style_.SetFontSize(fontSize_ * fontScale_);
526 }
527
528 iconSize_ = NormalizeToPx(iconSizeInDimension_);
529 iconHotZoneSize_ = NormalizeToPx(iconHotZoneSizeInDimension_);
530 errorSpacing_ = NormalizeToPx(errorSpacingInDimension_);
531 if (!GetChildren().empty()) {
532 auto innerLayout = GetLayoutParam();
533 innerLayout.SetMinSize(Size());
534 const auto& child = GetChildren().front();
535 child->Layout(innerLayout);
536 }
537 ApplyAspectRatio();
538 SetLayoutSize(GetLayoutParam().Constrain(Measure()));
539 UpdateFocusAnimation();
540
541 LayoutParam layoutParam = GetLayoutParam();
542 layoutParam.SetMinSize(Size());
543 if (iconImage_) {
544 iconImage_->Layout(layoutParam);
545 }
546 if (renderShowIcon_) {
547 renderShowIcon_->Layout(layoutParam);
548 }
549 if (renderHideIcon_) {
550 renderHideIcon_->Layout(layoutParam);
551 }
552
553 HandleDeviceOrientationChange();
554 }
555
HandleMouseEvent(const MouseEvent & event)556 bool RenderTextField::HandleMouseEvent(const MouseEvent& event)
557 {
558 if (event.button == MouseButton::LEFT_BUTTON) {
559 if (event.action == MouseAction::PRESS) {
560 UpdateStartSelection(DEFAULT_SELECT_INDEX, event.GetOffset(), true, false);
561 } else if (event.action == MouseAction::MOVE) {
562 int32_t start = GetEditingValue().selection.baseOffset;
563 int32_t end = GetCursorPositionForClick(event.GetOffset());
564 UpdateSelection(start, end);
565 MarkNeedRender();
566 } else {
567 LOGD("on left button release");
568 }
569 }
570
571 if (event.button == MouseButton::RIGHT_BUTTON && event.action == MouseAction::RELEASE) {
572 Offset rightClickOffset = event.GetOffset();
573 ShowTextOverlay(rightClickOffset, false, true);
574 }
575
576 return true;
577 }
578
HandleMouseHoverEvent(MouseState mouseState)579 void RenderTextField::HandleMouseHoverEvent(MouseState mouseState)
580 {
581 auto pipeline = context_.Upgrade();
582 if (!pipeline) {
583 return;
584 }
585 int32_t windowId = pipeline->GetWindowId();
586 auto mouseStyle = MouseStyle::CreateMouseStyle();
587 MouseFormat defaultStyle = MouseFormat::DEFAULT;
588 MouseFormat textCursorStyle = MouseFormat::TEXT_CURSOR;
589 if (mouseState == MouseState::HOVER) {
590 mouseStyle->SetPointerStyle(windowId, textCursorStyle);
591 } else {
592 mouseStyle->SetPointerStyle(windowId, defaultStyle);
593 }
594 }
595
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)596 void RenderTextField::OnTouchTestHit(
597 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
598 {
599 if (!enabled_) {
600 return;
601 }
602 if (!clickRecognizer_) {
603 clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
604 clickRecognizer_->SetUseCatchMode(catchMode_);
605 auto weak = WeakClaim(this);
606 clickRecognizer_->SetOnClick([weak](const ClickInfo& info) {
607 auto client = weak.Upgrade();
608 if (client) {
609 client->OnClick(info);
610 }
611 });
612 clickRecognizer_->SetPriority(GesturePriority::Low);
613 }
614 clickRecognizer_->SetCoordinateOffset(coordinateOffset);
615 result.emplace_back(clickRecognizer_);
616
617 if (!doubleClickRecognizer_) {
618 doubleClickRecognizer_ =
619 AceType::MakeRefPtr<ClickRecognizer>(context_, DOUBLE_CLICK_FINGERS, DOUBLE_CLICK_COUNTS);
620 doubleClickRecognizer_->SetUseCatchMode(catchMode_);
621 auto weak = WeakClaim(this);
622 doubleClickRecognizer_->SetOnClick([weak](const ClickInfo& info) {
623 auto client = weak.Upgrade();
624 if (client) {
625 client->OnDoubleClick(info);
626 }
627 });
628 doubleClickRecognizer_->SetPriority(GesturePriority::High);
629 }
630 doubleClickRecognizer_->SetCoordinateOffset(coordinateOffset);
631 result.emplace_back(doubleClickRecognizer_);
632
633 if (!longPressRecognizer_) {
634 longPressRecognizer_ = AceType::MakeRefPtr<LongPressRecognizer>(context_);
635 auto weak = WeakClaim(this);
636 longPressRecognizer_->SetOnLongPress([weak = WeakClaim(this)](const LongPressInfo& info) {
637 auto client = weak.Upgrade();
638 if (client) {
639 client->OnLongPress(info);
640 }
641 });
642 longPressRecognizer_->SetPriority(GesturePriority::High);
643 }
644 longPressRecognizer_->SetCoordinateOffset(coordinateOffset);
645 longPressRecognizer_->SetTouchRestrict(touchRestrict);
646 result.emplace_back(longPressRecognizer_);
647
648 if (!rawRecognizer_) {
649 rawRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
650 auto weak = WeakClaim(this);
651 rawRecognizer_->SetOnTouchDown([weak = WeakClaim(this)](const TouchEventInfo& info) {
652 auto textField = weak.Upgrade();
653 if (textField) {
654 textField->StartPressAnimation(true);
655 }
656 });
657
658 rawRecognizer_->SetOnTouchUp([weak = WeakClaim(this)](const TouchEventInfo& info) {
659 auto textField = weak.Upgrade();
660 if (textField) {
661 textField->StartPressAnimation(false);
662 textField->OnTapCallback();
663 }
664 });
665
666 rawRecognizer_->SetOnTouchCancel([weak = WeakClaim(this)](const TouchEventInfo& info) {
667 auto textField = weak.Upgrade();
668 if (textField) {
669 textField->StartPressAnimation(false);
670 }
671 });
672 }
673 rawRecognizer_->SetTouchRestrict(touchRestrict);
674 rawRecognizer_->SetCoordinateOffset(coordinateOffset);
675 result.emplace_back(rawRecognizer_);
676 }
677
StartPressAnimation(bool pressDown)678 void RenderTextField::StartPressAnimation(bool pressDown)
679 {
680 if (!pressController_) {
681 pressController_ = AceType::MakeRefPtr<Animator>(context_);
682 }
683 if (pressController_->IsRunning()) {
684 pressController_->Stop();
685 }
686 if (hoverController_ && hoverController_->IsRunning()) {
687 hoverController_->Stop();
688 }
689 pressController_->ClearInterpolators();
690 RefPtr<KeyframeAnimation<Color>> animation = AceType::MakeRefPtr<KeyframeAnimation<Color>>();
691 if (pressDown) {
692 CreateMouseAnimation(animation, GetEventEffectColor(), pressColor_);
693 } else {
694 CreateMouseAnimation(animation, GetEventEffectColor(), Color::TRANSPARENT);
695 }
696 pressController_->AddInterpolator(animation);
697 pressController_->SetDuration(PRESS_DURATION);
698 pressController_->SetFillMode(FillMode::FORWARDS);
699 pressController_->Forward();
700 }
701
StartHoverAnimation(bool isHovered)702 void RenderTextField::StartHoverAnimation(bool isHovered)
703 {
704 if (pressController_ && pressController_->IsRunning()) {
705 return;
706 }
707 if (!hoverController_) {
708 hoverController_ = AceType::MakeRefPtr<Animator>(context_);
709 }
710 if (hoverController_->IsRunning()) {
711 hoverController_->Stop();
712 }
713 hoverController_->ClearInterpolators();
714 RefPtr<KeyframeAnimation<Color>> animation = AceType::MakeRefPtr<KeyframeAnimation<Color>>();
715 if (isHovered) {
716 CreateMouseAnimation(animation, GetEventEffectColor(), hoverColor_);
717 } else {
718 CreateMouseAnimation(animation, GetEventEffectColor(), Color::TRANSPARENT);
719 }
720 hoverController_->AddInterpolator(animation);
721 hoverController_->SetDuration(HOVER_DURATION);
722 hoverController_->SetFillMode(FillMode::FORWARDS);
723 hoverController_->Forward();
724 }
725
AnimateMouseHoverEnter()726 void RenderTextField::AnimateMouseHoverEnter()
727 {
728 StartHoverAnimation(true);
729 }
730
AnimateMouseHoverExit()731 void RenderTextField::AnimateMouseHoverExit()
732 {
733 StartHoverAnimation(false);
734 }
735
OnClick(const ClickInfo & clickInfo)736 void RenderTextField::OnClick(const ClickInfo& clickInfo)
737 {
738 // Handle click on password icon when password icon is valid, switch between show and hide icon.
739 Point clickPoint = Point(clickInfo.GetLocalLocation().GetX(), clickInfo.GetLocalLocation().GetY());
740 if (showPasswordIcon_ && passwordIconRect_.IsInRegion(clickPoint)) {
741 obscure_ = !obscure_;
742 passwordRecord_ = obscure_;
743 PopTextOverlay();
744 MarkNeedLayout();
745 return;
746 }
747
748 isValueFromRemote_ = false;
749 auto globalPosition = clickInfo.GetGlobalLocation();
750 auto globalOffset = GetGlobalOffset();
751
752 if (SearchAction(globalPosition, globalOffset)) {
753 return;
754 }
755 if (!onTapCallbackResult_) {
756 return;
757 }
758 if (onTapEvent_) {
759 onTapEvent_();
760 }
761 if (onClick_) {
762 onClick_(clickInfo);
763 }
764 CursorMoveOnClick(globalPosition);
765 ShowError("", false);
766 UpdateStartSelection(DEFAULT_SELECT_INDEX, globalPosition, true, false);
767 if (clickInfo.GetSourceDevice() == SourceType::MOUSE) {
768 StartTwinkling();
769 } else {
770 ShowTextOverlay(globalPosition, true);
771 }
772 }
773
OnTapCallback()774 void RenderTextField::OnTapCallback()
775 {
776 auto context = GetContext().Upgrade();
777 if (context) {
778 context->SetClickPosition(GetGlobalOffset() + Size(0, GetLayoutSize().Height()));
779 }
780 if (isFocusOnTouch_ && tapCallback_) {
781 if (isLongPressStatus_) {
782 onTapCallbackResult_ = tapCallback_(false);
783 isLongPressStatus_ = false;
784 } else {
785 onTapCallbackResult_ = tapCallback_(true);
786 }
787 }
788 }
789
OnEditChange(bool isInEditStatus)790 void RenderTextField::OnEditChange(bool isInEditStatus)
791 {
792 CHECK_NULL_VOID(onEditChanged_);
793 if (isInEditStatus && !isInEditStatus_) {
794 isInEditStatus_ = true;
795 onEditChanged_(true);
796 } else if (!isInEditStatus && isInEditStatus_) {
797 isInEditStatus_ = false;
798 onEditChanged_(false);
799 }
800 }
801
AddOutOfRectCallbackToContext()802 void RenderTextField::AddOutOfRectCallbackToContext()
803 {
804 auto context = GetContext().Upgrade();
805 CHECK_NULL_VOID(context);
806 OutOfRectTouchCallback outRectCallback = [weak = WeakClaim(this)]() {
807 auto render = weak.Upgrade();
808 if (render) {
809 if (render->isOverlayShowed_) {
810 render->PopTextOverlay();
811 }
812 render->StopTwinkling();
813 LOGI("Out of rect, close keyboard");
814 render->CloseKeyboard();
815 render->OnEditChange(false);
816 }
817 };
818 OutOfRectGetRectCallback getRectCallback = [weak = WeakClaim(this)](std::vector<Rect>& resRectList) {
819 auto render = weak.Upgrade();
820 if (render) {
821 render->GetFieldAndOverlayTouchRect(resRectList);
822 }
823 };
824 context->AddRectCallback(getRectCallback, outRectCallback, outRectCallback);
825 }
826
GetFieldAndOverlayTouchRect(std::vector<Rect> & resRectList)827 void RenderTextField::GetFieldAndOverlayTouchRect(std::vector<Rect>& resRectList)
828 {
829 auto context = GetContext().Upgrade();
830 CHECK_NULL_VOID(context);
831 resRectList.clear();
832 auto fieldTouchRectList = GetTouchRectList();
833 for (auto& rect : fieldTouchRectList) {
834 rect.SetOffset(GetGlobalOffset());
835 }
836 resRectList.insert(resRectList.end(), fieldTouchRectList.begin(), fieldTouchRectList.end());
837 auto textOverlayManager = context->GetTextOverlayManager();
838 if (textOverlayManager) {
839 auto overlayTouchRectList = textOverlayManager->GetTextOverlayRect();
840 resRectList.insert(resRectList.end(), overlayTouchRectList.begin(), overlayTouchRectList.end());
841 }
842 }
843
SearchAction(const Offset & globalPosition,const Offset & globalOffset)844 bool RenderTextField::SearchAction(const Offset& globalPosition, const Offset& globalOffset)
845 {
846 double widthReserved = NormalizeToPx(widthReserved_);
847 if (widthReserved > 0) {
848 if (textDirection_ == TextDirection::RTL) {
849 if ((globalPosition.GetX() - globalOffset.GetX()) < widthReserved) {
850 controller_->SetText("");
851 return true;
852 } else if ((globalPosition.GetX() - globalOffset.GetX()) > (GetLayoutSize().Width() - iconHotZoneSize_) &&
853 iconImage_ && action_ == TextInputAction::SEARCH) {
854 PerformAction(action_, true);
855 return true;
856 }
857 } else {
858 if ((globalPosition.GetX() - globalOffset.GetX()) >= (GetLayoutSize().Width() - widthReserved)) {
859 controller_->SetText("");
860 return true;
861 } else if ((globalPosition.GetX() - globalOffset.GetX()) < iconHotZoneSize_ && iconImage_ &&
862 action_ == TextInputAction::SEARCH) {
863 PerformAction(action_, true);
864 return true;
865 }
866 }
867 }
868 return false;
869 }
870
OnDoubleClick(const ClickInfo & clickInfo)871 void RenderTextField::OnDoubleClick(const ClickInfo& clickInfo)
872 {
873 auto clickPosition = GetCursorPositionForClick(clickInfo.GetGlobalLocation());
874 auto selection = TextUtils::GetRangeOfSameType(GetEditingValue().text, clickPosition - 1);
875 UpdateSelection(selection.GetStart(), selection.GetEnd());
876 LOGI("text field accept double click, position: %{public}d, selection: %{public}s", clickPosition,
877 selection.ToString().c_str());
878 MarkNeedRender();
879 }
880
OnLongPress(const LongPressInfo & longPressInfo)881 void RenderTextField::OnLongPress(const LongPressInfo& longPressInfo)
882 {
883 if (isFocusOnTouch_ && tapCallback_ && !isOverlayShowed_) {
884 if (!tapCallback_(false)) {
885 return;
886 }
887 }
888
889 if (onLongPressEvent_) {
890 onLongPressEvent_();
891 }
892
893 ShowError("", false);
894
895 if (longPressInfo.GetSourceDevice() == SourceType::MOUSE) {
896 return;
897 }
898
899 isLongPressStatus_ = true;
900 Offset longPressPosition = longPressInfo.GetGlobalLocation();
901 bool isTextEnd =
902 (static_cast<size_t>(GetCursorPositionForClick(longPressPosition)) == GetEditingValue().GetWideText().length());
903 bool singleHandle = isTextEnd || GetEditingValue().text.empty();
904 bool isPassword = (keyboard_ == TextInputType::VISIBLE_PASSWORD);
905 UpdateStartSelection(DEFAULT_SELECT_INDEX, longPressPosition, singleHandle || isPassword, true);
906 ShowTextOverlay(longPressPosition, false);
907 }
908
ShowTextOverlay(const Offset & showOffset,bool isSingleHandle,bool isUsingMouse)909 void RenderTextField::ShowTextOverlay(const Offset& showOffset, bool isSingleHandle, bool isUsingMouse)
910 {
911 if (!isVisible_) {
912 return;
913 }
914
915 if (!IsSelectiveDevice()) {
916 StartTwinkling();
917 return;
918 }
919
920 isSingleHandle_ = isSingleHandle;
921
922 auto selStart = GetEditingValue().selection.GetStart();
923 auto selEnd = GetEditingValue().selection.GetEnd();
924
925 Offset startHandleOffset = GetHandleOffset(selStart);
926 Offset endHandleOffset = isSingleHandle ? startHandleOffset : GetHandleOffset(selEnd);
927
928 if (isOverlayShowed_ && updateHandlePosition_) {
929 Rect caretStart;
930 bool visible = GetCaretRect(selStart, caretStart) ? IsVisible(caretStart + textOffsetForShowCaret_) : false;
931 OverlayShowOption option { .showMenu = isOverlayShowed_,
932 .showStartHandle = visible,
933 .showEndHandle = visible,
934 .isSingleHandle = isSingleHandle,
935 .updateOverlayType = isSingleHandle ? UpdateOverlayType::CLICK : UpdateOverlayType::LONG_PRESS,
936 .startHandleOffset = startHandleOffset,
937 .endHandleOffset = endHandleOffset };
938 if (!isSingleHandle_ || startHandleOffset != endHandleOffset) {
939 isOverlayFocus_ = true;
940 }
941 updateHandlePosition_(option);
942
943 // When the textOverlay is showed, restart the animation
944 if (!animator_) {
945 LOGE("Show textOverlay error, animator is nullptr");
946 return;
947 }
948 if (!animator_->IsStopped()) {
949 animator_->Stop();
950 }
951 animator_->Play();
952 return;
953 }
954
955 // Pop text overlay before push.
956 PopTextOverlay();
957
958 textOverlay_ =
959 AceType::MakeRefPtr<TextOverlayComponent>(GetThemeManager(), context_.Upgrade()->GetAccessibilityManager());
960 textOverlay_->SetWeakTextField(WeakClaim(this));
961 textOverlay_->SetIsSingleHandle(isSingleHandle || (keyboard_ == TextInputType::VISIBLE_PASSWORD));
962 textOverlay_->SetLineHeight(selectHeight_);
963 textOverlay_->SetClipRect(
964 innerRect_ + Size(HANDLE_HOT_ZONE, HANDLE_HOT_ZONE) + GetOffsetToPage() - Offset(HANDLE_HOT_ZONE / 2.0, 0.0));
965 textOverlay_->SetTextDirection(textDirection_);
966 textOverlay_->SetRealTextDirection(existStrongDirectionLetter_ ? realTextDirection_ : TextDirection::LTR);
967 textOverlay_->SetIsPassword(keyboard_ == TextInputType::VISIBLE_PASSWORD);
968 textOverlay_->SetStartHandleOffset(startHandleOffset);
969 textOverlay_->SetEndHandleOffset(endHandleOffset);
970 textOverlay_->SetImageFill(imageFill_);
971 textOverlay_->SetOptions(inputOptions_);
972 textOverlay_->SetOptionsClickMarker(onOptionsClick_);
973 textOverlay_->SetTranslateButtonMarker(onTranslate_);
974 textOverlay_->SetShareButtonMarker(onShare_);
975 textOverlay_->SetSearchButtonMarker(onSearch_);
976 textOverlay_->SetContext(context_);
977 textOverlay_->SetIsUsingMouse(isUsingMouse);
978 if (isUsingMouse) {
979 textOverlay_->SetMouseOffset(showOffset);
980 }
981
982 // Add the Animation
983 InitAnimation();
984
985 if (!isSingleHandle_ || startHandleOffset != endHandleOffset) {
986 isOverlayFocus_ = true;
987 }
988 RegisterCallbacksToOverlay();
989 }
990
InitAnimation()991 void RenderTextField::InitAnimation()
992 {
993 if (!textOverlay_) {
994 LOGE("InitAnimation error, textOverlay is nullptr");
995 return;
996 }
997
998 // Get the handleDiameter in theme, textoverlay is not nullptr
999 double initHandleDiameter = textOverlay_->GetHandleDiameter().Value();
1000 double initHandleDiameterInner = textOverlay_->GetHandleDiameterInner().Value();
1001
1002 // Add the animation for handleDiameter
1003 auto diameterAnimation = AceType::MakeRefPtr<CurveAnimation<double>>(
1004 initHandleDiameter * FIFTY_PERCENT, initHandleDiameter, Curves::ELASTICS);
1005 diameterAnimation->AddListener([text = AceType::WeakClaim(this)](double value) {
1006 auto textField = text.Upgrade();
1007 if (textField && textField->updateHandleDiameter_) {
1008 textField->updateHandleDiameter_(value);
1009 }
1010 });
1011
1012 // Add the animation for handleDiameterinner
1013 auto diameterInnerAnimation = AceType::MakeRefPtr<CurveAnimation<double>>(
1014 initHandleDiameterInner * FIFTY_PERCENT, initHandleDiameterInner, Curves::ELASTICS);
1015 diameterInnerAnimation->AddListener([text = AceType::WeakClaim(this)](double value) {
1016 auto textField = text.Upgrade();
1017 if (textField && textField->updateHandleDiameterInner_) {
1018 textField->updateHandleDiameterInner_(value);
1019 }
1020 });
1021
1022 // Add the animation
1023 LOGD("Add animation to animator");
1024 animator_ = AceType::MakeRefPtr<Animator>(context_);
1025 animator_->AddInterpolator(diameterAnimation);
1026 animator_->AddInterpolator(diameterInnerAnimation);
1027 animator_->SetDuration(SHOW_HANDLE_DURATION);
1028 animator_->Play();
1029 }
1030
RegisterCallbacksToOverlay()1031 void RenderTextField::RegisterCallbacksToOverlay()
1032 {
1033 if (!textOverlay_) {
1034 return;
1035 }
1036 textOverlay_->SetOnCut([weak = AceType::WeakClaim(this)] {
1037 auto textfield = weak.Upgrade();
1038 if (textfield) {
1039 textfield->HandleOnCut();
1040 }
1041 });
1042
1043 textOverlay_->SetOnCopy([weak = AceType::WeakClaim(this)] {
1044 auto textfield = weak.Upgrade();
1045 if (textfield) {
1046 textfield->HandleOnCopy();
1047 }
1048 });
1049
1050 textOverlay_->SetOnCopyAll(
1051 [weak = AceType::WeakClaim(this)](const std::function<void(const Offset&, const Offset&)>& callback) {
1052 auto textfield = weak.Upgrade();
1053 if (textfield) {
1054 textfield->HandleOnCopyAll(callback);
1055 }
1056 });
1057
1058 textOverlay_->SetOnStartHandleMove(
1059 [weak = AceType::WeakClaim(this)](int32_t end, const Offset& startHandleOffset,
1060 const std::function<void(const Offset&)>& startCallback, bool isSingleHandle) {
1061 auto textfield = weak.Upgrade();
1062 if (textfield) {
1063 textfield->HandleOnStartHandleMove(end, startHandleOffset, startCallback, isSingleHandle);
1064 }
1065 });
1066
1067 textOverlay_->SetOnEndHandleMove([weak = AceType::WeakClaim(this)](int32_t start, const Offset& endHandleOffset,
1068 const std::function<void(const Offset&)>& endCallback) {
1069 auto textfield = weak.Upgrade();
1070 if (textfield) {
1071 textfield->HandleOnEndHandleMove(start, endHandleOffset, endCallback);
1072 }
1073 });
1074
1075 textOverlay_->SetOnPaste([weakTextField = WeakClaim(this)] {
1076 auto textfield = weakTextField.Upgrade();
1077 if (textfield) {
1078 textfield->HandleOnPaste();
1079 }
1080 });
1081 PushTextOverlayToStack();
1082 UpdateOverlay();
1083
1084 auto onFocusChange = [weak = WeakClaim(this)](bool isFocus, bool needCloseKeyboard) {
1085 auto textField = weak.Upgrade();
1086 if (textField) {
1087 textField->OnOverlayFocusChange(isFocus, needCloseKeyboard);
1088 }
1089 };
1090 textOverlay_->SetOnFocusChange(onFocusChange);
1091 }
1092
PushTextOverlayToStack()1093 void RenderTextField::PushTextOverlayToStack()
1094 {
1095 if (!textOverlay_) {
1096 LOGE("TextOverlay is null");
1097 return;
1098 }
1099
1100 auto context = context_.Upgrade();
1101 CHECK_NULL_VOID(context);
1102 auto textOverlayManager = context->GetTextOverlayManager();
1103 CHECK_NULL_VOID(textOverlayManager);
1104 textOverlayManager->PushTextOverlayToStack(textOverlay_, context);
1105
1106 hasTextOverlayPushed_ = true;
1107 isOverlayShowed_ = true;
1108 auto lastStack = GetLastStack();
1109 if (!lastStack) {
1110 LOGE("LastStack is null");
1111 return;
1112 }
1113 stackElement_ = WeakClaim(RawPtr(lastStack));
1114 MarkNeedRender();
1115 }
1116
PopTextOverlay()1117 void RenderTextField::PopTextOverlay()
1118 {
1119 auto context = context_.Upgrade();
1120 CHECK_NULL_VOID(context);
1121 auto textOverlayManager = context->GetTextOverlayManager();
1122 CHECK_NULL_VOID(textOverlayManager);
1123 textOverlayManager->PopTextOverlay();
1124 isOverlayShowed_ = false;
1125 }
1126
GetSlidingPanelAncest()1127 RefPtr<RenderSlidingPanel> RenderTextField::GetSlidingPanelAncest()
1128 {
1129 auto parent = GetParent().Upgrade();
1130 while (parent) {
1131 auto renderSlidingPanel = AceType::DynamicCast<RenderSlidingPanel>(parent);
1132 if (renderSlidingPanel) {
1133 return renderSlidingPanel;
1134 }
1135 parent = parent->GetParent().Upgrade();
1136 }
1137 return nullptr;
1138 }
1139
ResetSlidingPanelParentHeight()1140 void RenderTextField::ResetSlidingPanelParentHeight()
1141 {
1142 auto context = context_.Upgrade();
1143 if (!context) {
1144 LOGE("ResetSlidingPanelParentHeight: Context is null");
1145 return;
1146 }
1147 auto manager = context->GetTextFieldManager();
1148 if (manager && AceType::InstanceOf<TextFieldManager>(manager)) {
1149 auto textFieldManager = AceType::DynamicCast<TextFieldManager>(manager);
1150 textFieldManager->ResetSlidingPanelParentHeight();
1151 }
1152 }
1153
ResetOnFocusForTextFieldManager()1154 void RenderTextField::ResetOnFocusForTextFieldManager()
1155 {
1156 auto context = context_.Upgrade();
1157 if (!context) {
1158 LOGE("ResetOnFocusForTextFieldManager: Context is null");
1159 return;
1160 }
1161 auto manager = context->GetTextFieldManager();
1162 if (manager && AceType::InstanceOf<TextFieldManager>(manager)) {
1163 auto textFieldManager = AceType::DynamicCast<TextFieldManager>(manager);
1164 textFieldManager->ClearOnFocusTextField();
1165 }
1166 }
1167
RequestKeyboard(bool isFocusViewChanged,bool needStartTwinkling,bool needShowSoftKeyboard)1168 bool RenderTextField::RequestKeyboard(bool isFocusViewChanged, bool needStartTwinkling, bool needShowSoftKeyboard)
1169 {
1170 if (!enabled_) {
1171 LOGW("TextField is not enabled.");
1172 return false;
1173 }
1174
1175 instanceId_ = ContainerScope::CurrentId();
1176
1177 if (softKeyboardEnabled_) {
1178 LOGI("Request open soft keyboard");
1179 #if defined(ENABLE_STANDARD_INPUT)
1180 UpdateConfiguration();
1181 if (textChangeListener_ == nullptr) {
1182 textChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this), context_);
1183 }
1184 auto inputMethod = MiscServices::InputMethodController::GetInstance();
1185 if (!inputMethod) {
1186 LOGE("Request open soft keyboard failed because input method is null.");
1187 return false;
1188 }
1189 auto context = context_.Upgrade();
1190 if (context) {
1191 LOGI("RequestKeyboard set calling window id is : %{public}d", context->GetWindowId());
1192 inputMethod->SetCallingWindow(context->GetWindowId());
1193 }
1194 MiscServices::InputAttribute inputAttribute;
1195 inputAttribute.inputPattern = (int32_t)keyboard_;
1196 inputAttribute.enterKeyType = (int32_t)action_;
1197 inputMethod->Attach(textChangeListener_, needShowSoftKeyboard, inputAttribute);
1198 #else
1199 if (!HasConnection()) {
1200 AttachIme();
1201 if (!HasConnection()) {
1202 LOGE("Get TextInput connection error");
1203 return false;
1204 }
1205 connection_->SetEditingState(GetEditingValue(), GetInstanceId());
1206 }
1207 connection_->Show(isFocusViewChanged, GetInstanceId());
1208 #endif
1209 }
1210 auto context = context_.Upgrade();
1211 if (context) {
1212 auto manager = context->GetTextFieldManager();
1213 if (manager && AceType::InstanceOf<TextFieldManager>(manager)) {
1214 auto textFieldManager = AceType::DynamicCast<TextFieldManager>(manager);
1215 textFieldManager->SetOnFocusTextField(WeakClaim(this));
1216 }
1217 }
1218 if (keyboard_ != TextInputType::MULTILINE) {
1219 resetToStart_ = false;
1220 MarkNeedLayout();
1221 }
1222 if (needStartTwinkling) {
1223 StartTwinkling();
1224 }
1225 return true;
1226 }
1227
CloseKeyboard(bool forceClose)1228 bool RenderTextField::CloseKeyboard(bool forceClose)
1229 {
1230 #if defined(OHOS_STANDARD_SYSTEM)
1231 if (!imeAttached_) {
1232 return false;
1233 }
1234 #endif
1235 if (!isOverlayShowed_ || !isOverlayFocus_ || forceClose) {
1236 if (!textFieldController_) {
1237 StopTwinkling();
1238 }
1239 LOGI("Request close soft keyboard");
1240 #if defined(ENABLE_STANDARD_INPUT)
1241 auto inputMethod = MiscServices::InputMethodController::GetInstance();
1242 if (!inputMethod) {
1243 LOGE("Request close soft keyboard failed because input method is null.");
1244 return false;
1245 }
1246 inputMethod->HideTextInput();
1247 inputMethod->Close();
1248 #else
1249 if (HasConnection()) {
1250 connection_->Close(GetInstanceId());
1251 connection_ = nullptr;
1252 }
1253 #endif
1254
1255 if (onKeyboardClose_) {
1256 onKeyboardClose_(forceClose);
1257 onKeyboardClose_ = nullptr;
1258 UpdateSelection(GetEditingValue().selection.GetEnd());
1259 MarkNeedLayout();
1260 }
1261 ResetSlidingPanelParentHeight();
1262 if (keyboard_ != TextInputType::MULTILINE && keyboard_ != TextInputType::VISIBLE_PASSWORD) {
1263 resetToStart_ = true;
1264 MarkNeedLayout();
1265 }
1266 return true;
1267 }
1268 return false;
1269 }
1270
AttachIme()1271 void RenderTextField::AttachIme()
1272 {
1273 auto context = context_.Upgrade();
1274 if (!context) {
1275 LOGW("No context exists, failed to request keyboard.");
1276 return;
1277 }
1278
1279 TextInputConfiguration config;
1280 config.type = keyboard_;
1281 config.action = action_;
1282 config.actionLabel = actionLabel_;
1283 config.obscureText = obscure_;
1284 LOGI("Request keyboard configuration: type=%{private}d action=%{private}d actionLabel=%{private}s "
1285 "obscureText=%{private}d",
1286 keyboard_, action_, actionLabel_.c_str(), obscure_);
1287 connection_ =
1288 TextInputProxy::GetInstance().Attach(WeakClaim(this), config, context->GetTaskExecutor(), GetInstanceId());
1289 }
1290
StartTwinkling()1291 void RenderTextField::StartTwinkling()
1292 {
1293 // Ignore the result because all ops are called on this same thread (ACE UI).
1294 // The only reason failed is that the task has finished.
1295 cursorTwinklingTask_.Cancel();
1296
1297 // Show cursor right now.
1298 cursorVisibility_ = true;
1299 // Does not matter call more than one times.
1300 MarkNeedRender();
1301
1302 ScheduleCursorTwinkling();
1303 }
1304
StopTwinkling()1305 void RenderTextField::StopTwinkling()
1306 {
1307 obscureTickPendings_ = 0;
1308 cursorTwinklingTask_.Cancel();
1309
1310 if (cursorVisibility_) {
1311 // Repaint only if cursor is visible for now.
1312 cursorVisibility_ = false;
1313 MarkNeedRender();
1314 }
1315 }
1316
HandleSetSelection(int32_t start,int32_t end)1317 void RenderTextField::HandleSetSelection(int32_t start, int32_t end)
1318 {
1319 LOGI("HandleSetSelection %{public}d, %{public}d", start, end);
1320 UpdateSelection(start, end);
1321 }
1322
HandleExtendAction(int32_t action)1323 void RenderTextField::HandleExtendAction(int32_t action)
1324 {
1325 LOGI("HandleExtendAction %{public}d", action);
1326 switch (action) {
1327 case ACTION_SELECT_ALL: {
1328 auto end = GetEditingValue().GetWideText().length();
1329 UpdateSelection(0, end);
1330 break;
1331 }
1332 case ACTION_UNDO: {
1333 HandleOnRevoke();
1334 break;
1335 }
1336 case ACTION_REDO: {
1337 HandleOnInverseRevoke();
1338 break;
1339 }
1340 case ACTION_CUT: {
1341 HandleOnCut();
1342 break;
1343 }
1344 case ACTION_COPY: {
1345 HandleOnCopy();
1346 break;
1347 }
1348 case ACTION_PASTE: {
1349 HandleOnPaste();
1350 break;
1351 }
1352 default: {
1353 break;
1354 }
1355 }
1356 }
1357
HandleSelect(int32_t keyCode,int32_t cursorMoveSkip)1358 void RenderTextField::HandleSelect(int32_t keyCode, int32_t cursorMoveSkip)
1359 {
1360 KeyCode code = static_cast<KeyCode>(keyCode);
1361 CursorMoveSkip skip = static_cast<CursorMoveSkip>(cursorMoveSkip);
1362 HandleOnSelect(code, skip);
1363 }
1364
GetEditingValue() const1365 const TextEditingValue& RenderTextField::GetEditingValue() const
1366 {
1367 return controller_->GetValue();
1368 }
1369
GetPreEditingValue() const1370 const TextEditingValue& RenderTextField::GetPreEditingValue() const
1371 {
1372 return controller_->GetPreValue();
1373 }
1374
GetEditingBoxY() const1375 double RenderTextField::GetEditingBoxY() const
1376 {
1377 return GetGlobalOffset().GetY() + height_.Value();
1378 }
1379
GetEditingBoxTopY() const1380 double RenderTextField::GetEditingBoxTopY() const
1381 {
1382 return GetGlobalOffset().GetY();
1383 }
1384
GetEditingBoxModel() const1385 bool RenderTextField::GetEditingBoxModel() const
1386 {
1387 bool isDeclarative = false;
1388 auto context = context_.Upgrade();
1389 if (context && context->GetIsDeclarative()) {
1390 isDeclarative = true;
1391 }
1392 return isDeclarative;
1393 }
1394
SetEditingValue(TextEditingValue && newValue,bool needFireChangeEvent,bool isClearRecords)1395 void RenderTextField::SetEditingValue(TextEditingValue&& newValue, bool needFireChangeEvent, bool isClearRecords)
1396 {
1397 if (newValue.text != GetEditingValue().text && needFireChangeEvent) {
1398 needNotifyChangeEvent_ = true;
1399 operationRecords_.push_back(newValue);
1400 if (isClearRecords) {
1401 inverseOperationRecords_.clear();
1402 }
1403 }
1404 ChangeCounterStyle(newValue);
1405 auto context = context_.Upgrade();
1406 if (context && context->GetIsDeclarative()) {
1407 if (GetEditingValue().text.empty()) {
1408 Dimension fontSize_ = placeHoldStyle_.GetFontSize();
1409 if (fontSize_.Value() <= 0) {
1410 Dimension fontSize_ { 14, DimensionUnit::FP };
1411 placeHoldStyle_.SetFontSize(fontSize_);
1412 }
1413 SetTextStyle(placeHoldStyle_);
1414 }
1415 }
1416 controller_->SetValue(newValue, needFireChangeEvent);
1417 UpdateAccessibilityAttr();
1418 }
1419
SetEditingValue(const std::string & text)1420 void RenderTextField::SetEditingValue(const std::string& text)
1421 {
1422 auto newValue = GetEditingValue();
1423 newValue.text = text;
1424 SetEditingValue(std::move(newValue));
1425 }
1426
ClearEditingValue()1427 void RenderTextField::ClearEditingValue()
1428 {
1429 TextEditingValue emptyValue;
1430 SetEditingValue(std::move(emptyValue));
1431 }
1432
GetTextForDisplay(const std::string & text) const1433 std::u16string RenderTextField::GetTextForDisplay(const std::string& text) const
1434 {
1435 std::u16string txtContent = StringUtils::Str8ToStr16(text);
1436 auto len = txtContent.length();
1437 if (!obscure_ || len == 0 || (obscureTickPendings_ > 0 && len == 1)) {
1438 return txtContent;
1439 }
1440
1441 std::u16string obscured;
1442 if (Localization::GetInstance()->GetLanguage() == "ar") { // ar is the abbreviation of Arabic.
1443 obscured = std::u16string(len, OBSCURING_CHARACTER_FOR_AR);
1444 } else {
1445 obscured = std::u16string(len, OBSCURING_CHARACTER);
1446 }
1447 int32_t posBeforeCursor = GetEditingValue().selection.extentOffset - 1;
1448 if (obscureTickPendings_ > 0 && posBeforeCursor >= 0 && static_cast<size_t>(posBeforeCursor) < obscured.length()) {
1449 // Let the last commit character naked.
1450 obscured[posBeforeCursor] = txtContent[posBeforeCursor];
1451 }
1452
1453 return obscured;
1454 }
1455
UpdateObscure(const RefPtr<TextFieldComponent> & textField)1456 void RenderTextField::UpdateObscure(const RefPtr<TextFieldComponent>& textField)
1457 {
1458 auto context = context_.Upgrade();
1459 if (context && context->GetIsDeclarative()) {
1460 if (!passwordRecord_) {
1461 if (keyboard_ != textField->GetTextInputType()) {
1462 passwordRecord_ = true;
1463 obscure_ = textField->NeedObscure();
1464 } else {
1465 obscure_ = !textField->NeedObscure();
1466 }
1467 } else {
1468 obscure_ = textField->NeedObscure();
1469 }
1470 } else {
1471 obscure_ = textField->NeedObscure();
1472 }
1473 }
1474
UpdateFormatters()1475 void RenderTextField::UpdateFormatters()
1476 {
1477 textInputFormatters_.clear();
1478
1479 if (maxLength_ < std::numeric_limits<uint32_t>::max()) {
1480 textInputFormatters_.emplace_back(std::make_unique<LengthLimitingFormatter>(maxLength_));
1481 }
1482
1483 if (maxLines_ == 1) {
1484 textInputFormatters_.emplace_back(std::make_unique<SingleLineFormatter>());
1485 }
1486
1487 switch (keyboard_) {
1488 case TextInputType::NUMBER: {
1489 textInputFormatters_.emplace_back(std::make_unique<NumberFormatter>());
1490 break;
1491 }
1492 case TextInputType::PHONE: {
1493 textInputFormatters_.emplace_back(std::make_unique<PhoneNumberFormatter>());
1494 break;
1495 }
1496 case TextInputType::EMAIL_ADDRESS: {
1497 textInputFormatters_.emplace_back(std::make_unique<EmailFormatter>());
1498 break;
1499 }
1500 case TextInputType::URL: {
1501 textInputFormatters_.emplace_back(std::make_unique<UriFormatter>());
1502 break;
1503 }
1504 default: {
1505 // No need limit.
1506 }
1507 }
1508
1509 TextEditingValue temp = GetEditingValue();
1510 for (const auto& formatter : textInputFormatters_) {
1511 if (formatter) {
1512 formatter->Format(GetEditingValue(), temp);
1513 }
1514 }
1515 SetEditingValue(std::move(temp));
1516 }
1517
WstringSearch(std::wstring wideText,const std::wregex & regex)1518 std::wstring WstringSearch(std::wstring wideText, const std::wregex& regex)
1519 {
1520 std::wstring result;
1521 std::wsmatch matchResults;
1522 while (std::regex_search(wideText, matchResults, regex)) {
1523 for (auto&& mr : matchResults) {
1524 result.append(mr);
1525 }
1526 wideText = matchResults.suffix();
1527 }
1528 return result;
1529 }
1530
FilterWithRegex(std::string & valueToUpdate,const std::string & filter,bool needToEscape)1531 bool RenderTextField::FilterWithRegex(std::string& valueToUpdate, const std::string& filter, bool needToEscape)
1532 {
1533 if (filter.empty() || valueToUpdate.empty()) {
1534 LOGD("Text is empty or filter is empty");
1535 return false;
1536 }
1537 std::string escapeFilter;
1538 if (needToEscape && !TextFieldControllerBase::EscapeString(filter, escapeFilter)) {
1539 LOGE("Filter %{public}s is not legal", filter.c_str());
1540 return false;
1541 }
1542 if (!needToEscape) {
1543 escapeFilter = filter;
1544 }
1545 #if defined(PREVIEW)
1546 if (keyboard_ == TextInputType::EMAIL_ADDRESS) {
1547 std::string tmpValue;
1548 std::string errorText;
1549 std::string checkedList = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_@.";
1550 for (auto value : valueToUpdate) {
1551 if (checkedList.find(value) != std::string::npos) {
1552 tmpValue += value;
1553 } else {
1554 errorText += value;
1555 }
1556 }
1557 valueToUpdate = tmpValue;
1558 if (!errorText.empty()) {
1559 if (onError_) {
1560 onError_(errorText);
1561 }
1562 return true;
1563 }
1564 return false;
1565 }
1566 #else
1567 // Specialized processed for Email because of regex.
1568 if (keyboard_ == TextInputType::EMAIL_ADDRESS || keyboard_ == TextInputType::URL) {
1569 std::regex filterRegex(escapeFilter);
1570 auto errorText = regex_replace(valueToUpdate, filterRegex, "");
1571 if (!errorText.empty()) {
1572 std::string result;
1573 RemoveErrorTextFromValue(valueToUpdate, errorText, result);
1574 valueToUpdate = result;
1575 if (onError_) {
1576 onError_(errorText);
1577 }
1578 return true;
1579 }
1580 }
1581 #endif
1582 if (keyboard_ == TextInputType::NUMBER || keyboard_ == TextInputType::PHONE) {
1583 GetKeyboardFilter(keyboard_, escapeFilter, true);
1584 std::wregex filterRegex(StringUtils::ToWstring(escapeFilter));
1585 std::wstring wValueToUpdate = StringUtils::ToWstring(valueToUpdate);
1586 auto manipulateText = std::regex_replace(wValueToUpdate, filterRegex, L"");
1587 if (manipulateText.length() != wValueToUpdate.length()) {
1588 valueToUpdate = StringUtils::ToString(manipulateText);
1589 if (onError_) {
1590 GetKeyboardFilter(keyboard_, escapeFilter, false);
1591 std::regex filterRegex(escapeFilter);
1592 auto errorText = regex_replace(valueToUpdate, filterRegex, "");
1593 onError_(errorText);
1594 }
1595 return true;
1596 }
1597 }
1598 return false;
1599 }
1600
EditingValueFilter(TextEditingValue & valueToUpdate)1601 void RenderTextField::EditingValueFilter(TextEditingValue& valueToUpdate)
1602 {
1603 FilterWithRegex(valueToUpdate.text, inputFilter_, true);
1604 KeyboardEditingValueFilter(valueToUpdate);
1605 }
1606
KeyboardEditingValueFilter(TextEditingValue & valueToUpdate)1607 void RenderTextField::KeyboardEditingValueFilter(TextEditingValue& valueToUpdate)
1608 {
1609 std::string keyboardFilterValue;
1610 GetKeyboardFilter(keyboard_, keyboardFilterValue, false);
1611 if (keyboardFilterValue.empty()) {
1612 return;
1613 }
1614 if (keyboard_ == TextInputType::EMAIL_ADDRESS && valueToUpdate.text == "@") {
1615 if (GetEditingValue().text.find('@') != std::string::npos) {
1616 valueToUpdate.text = "";
1617 valueToUpdate.selection.baseOffset = 0;
1618 valueToUpdate.selection.extentOffset = 0;
1619 }
1620 return;
1621 }
1622 bool textChanged = false;
1623 auto start = valueToUpdate.selection.GetStart();
1624 auto end = valueToUpdate.selection.GetEnd();
1625 // in keyboard filter, the white lists are already escaped
1626 if ((start <= 0) && (end <= 0)) {
1627 FilterWithRegex(valueToUpdate.text, keyboardFilterValue);
1628 } else {
1629 std::string strBeforeSelection;
1630 if ((start > 0) && (static_cast<size_t>(start) <= valueToUpdate.text.length())) {
1631 strBeforeSelection = valueToUpdate.text.substr(0, start);
1632 textChanged |= FilterWithRegex(strBeforeSelection, keyboardFilterValue);
1633 }
1634 std::string strInSelection;
1635 if (start < end) {
1636 strInSelection = valueToUpdate.text.substr(start, end - start);
1637 textChanged |= FilterWithRegex(strInSelection, keyboardFilterValue);
1638 }
1639 std::string strAfterSelection;
1640 if (end >= start && end <= static_cast<int32_t>(valueToUpdate.text.length())) {
1641 size_t lenLeft = valueToUpdate.text.length() - static_cast<size_t>(end);
1642 strAfterSelection = valueToUpdate.text.substr(end, lenLeft);
1643 textChanged |= FilterWithRegex(strAfterSelection, keyboardFilterValue);
1644 }
1645 if (!textChanged) {
1646 return;
1647 }
1648 valueToUpdate.text = strBeforeSelection + strInSelection + strAfterSelection;
1649 if (valueToUpdate.selection.baseOffset > valueToUpdate.selection.extentOffset) {
1650 valueToUpdate.selection.Update(static_cast<int32_t>(strBeforeSelection.length() + strInSelection.length()),
1651 static_cast<int32_t>(strBeforeSelection.length()));
1652 } else {
1653 valueToUpdate.selection.Update(static_cast<int32_t>(strBeforeSelection.length()),
1654 static_cast<int32_t>(strBeforeSelection.length() + strInSelection.length()));
1655 }
1656 }
1657 }
1658
UpdateInsertText(std::string insertValue)1659 void RenderTextField::UpdateInsertText(std::string insertValue)
1660 {
1661 insertValue_ = std::move(insertValue);
1662 insertTextUpdated_ = true;
1663 }
1664
NeedToFilter()1665 bool RenderTextField::NeedToFilter()
1666 {
1667 std::string keyboardFilterValue;
1668 GetKeyboardFilter(keyboard_, keyboardFilterValue, false);
1669 return !keyboardFilterValue.empty() || !inputFilter_.empty();
1670 }
1671
HandleValueFilter(TextEditingValue & valueBeforeUpdate,TextEditingValue & valueNeedToUpdate)1672 void RenderTextField::HandleValueFilter(TextEditingValue& valueBeforeUpdate, TextEditingValue& valueNeedToUpdate)
1673 {
1674 if (!NeedToFilter()) {
1675 return;
1676 }
1677 if (insertTextUpdated_) {
1678 TextEditingValue textEditingValue;
1679 textEditingValue.text = insertValue_;
1680 EditingValueFilter(textEditingValue);
1681 if (!textEditingValue.text.empty()) {
1682 valueNeedToUpdate.text =
1683 valueBeforeUpdate.GetBeforeSelection() + textEditingValue.text + valueBeforeUpdate.GetAfterSelection();
1684 valueNeedToUpdate.UpdateSelection(
1685 std::max(valueBeforeUpdate.selection.GetStart(), 0) + textEditingValue.text.length());
1686 } else {
1687 // text inserted is filtered to empty string
1688 valueNeedToUpdate = valueBeforeUpdate;
1689 }
1690 insertTextUpdated_ = false;
1691 return;
1692 }
1693 EditingValueFilter(valueNeedToUpdate);
1694 }
1695
UpdateEditingValue(const std::shared_ptr<TextEditingValue> & value,bool needFireChangeEvent)1696 void RenderTextField::UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent)
1697 {
1698 ContainerScope scope(instanceId_);
1699 if (!value) {
1700 LOGE("the value is nullptr");
1701 return;
1702 }
1703 if (static_cast<uint32_t>(value->GetWideText().length()) > maxLength_) {
1704 LOGW("Max length reached");
1705 return;
1706 }
1707
1708 lastKnownRemoteEditingValue_ = value;
1709 lastKnownRemoteEditingValue_->hint = placeholder_;
1710 TextEditingValue valueNeedToUpdate = *value;
1711 if (cursorPositionType_ != CursorPositionType::END ||
1712 (valueNeedToUpdate.selection.baseOffset == valueNeedToUpdate.selection.extentOffset &&
1713 valueNeedToUpdate.selection.baseOffset != static_cast<int32_t>(valueNeedToUpdate.GetWideText().length()))) {
1714 cursorPositionType_ = CursorPositionType::NORMAL;
1715 isValueFromRemote_ = true;
1716 }
1717 auto valueBeforeUpdate = GetEditingValue();
1718
1719 ChangeCounterStyle(valueNeedToUpdate);
1720
1721 if (lastInputAction_ != InputAction::DELETE_BACKWARD && lastInputAction_ != InputAction::DELETE_FORWARD) {
1722 HandleValueFilter(valueBeforeUpdate, valueNeedToUpdate);
1723 }
1724
1725 if (obscure_ && (valueNeedToUpdate.text.length() == valueBeforeUpdate.text.length() + 1)) {
1726 // Reset pending.
1727 obscureTickPendings_ = OBSCURE_SHOW_TICKS;
1728 }
1729
1730 if (valueNeedToUpdate.text != valueBeforeUpdate.text && needFireChangeEvent) {
1731 needNotifyChangeEvent_ = true;
1732 }
1733
1734 SetEditingValue(std::move(valueNeedToUpdate), needFireChangeEvent);
1735 UpdateRemoteEditingIfNeeded(needFireChangeEvent);
1736
1737 MarkNeedLayout();
1738
1739 // If input or delete text when overlay is showing, pop overlay from stack.
1740 if (valueNeedToUpdate.text != valueBeforeUpdate.text) {
1741 if (onValueChange_) {
1742 onValueChange_();
1743 }
1744 if (onChange_) {
1745 onChange_(GetEditingValue().text);
1746 }
1747 }
1748 }
1749
PerformDefaultAction()1750 void RenderTextField::PerformDefaultAction()
1751 {
1752 PerformAction(action_);
1753 }
1754
PerformAction(TextInputAction action,bool forceCloseKeyboard)1755 void RenderTextField::PerformAction(TextInputAction action, bool forceCloseKeyboard)
1756 {
1757 LOGI("PerformAction %{public}d", static_cast<int32_t>(action));
1758 ContainerScope scope(instanceId_);
1759 if (keyboard_ == TextInputType::MULTILINE) {
1760 auto value = GetEditingValue();
1761 auto textEditingValue = std::make_shared<TextEditingValue>();
1762 textEditingValue->text = value.GetBeforeSelection() + NEW_LINE + value.GetAfterSelection();
1763 textEditingValue->UpdateSelection(std::max(value.selection.GetStart(), 0) + 1);
1764 UpdateEditingValue(textEditingValue, true);
1765 return;
1766 }
1767 if (action == TextInputAction::NEXT && moveNextFocusEvent_) {
1768 moveNextFocusEvent_();
1769 } else {
1770 LOGI("Perform action received from input frame, close keyboard");
1771 CloseKeyboard(forceCloseKeyboard);
1772 }
1773 if (onFinishInputEvent_) {
1774 auto jsonResult = JsonUtil::Create(true);
1775 jsonResult->Put("value", static_cast<int32_t>(action));
1776 onFinishInputEvent_(std::string(R"("enterkeyclick",)").append(jsonResult->ToString()));
1777 }
1778 if (onSubmitEvent_ && controller_) {
1779 onSubmitEvent_(controller_->GetValue().text);
1780 }
1781 if (onSubmit_) {
1782 onSubmit_(static_cast<int32_t>(action));
1783 }
1784 }
1785
Measure()1786 Size RenderTextField::Measure()
1787 {
1788 return Size();
1789 }
1790
ScheduleCursorTwinkling()1791 void RenderTextField::ScheduleCursorTwinkling()
1792 {
1793 auto context = context_.Upgrade();
1794 if (!context) {
1795 LOGW("No context exists.");
1796 return;
1797 }
1798
1799 if (!context->GetTaskExecutor()) {
1800 LOGW("context has no task executor.");
1801 return;
1802 }
1803
1804 auto weak = WeakClaim(this);
1805 cursorTwinklingTask_.Reset([weak] {
1806 auto client = weak.Upgrade();
1807 if (client) {
1808 client->OnCursorTwinkling();
1809 }
1810 });
1811 auto taskExecutor = context->GetTaskExecutor();
1812 if (taskExecutor) {
1813 taskExecutor->PostDelayedTask(cursorTwinklingTask_, TaskExecutor::TaskType::UI, twinklingInterval);
1814 } else {
1815 LOGE("the task executor is nullptr");
1816 }
1817 }
1818
OnCursorTwinkling()1819 void RenderTextField::OnCursorTwinkling()
1820 {
1821 // When glyph changes from visible to invisible, layout is needed.
1822 obscureTickPendings_ == 1 ? MarkNeedLayout() : MarkNeedRender();
1823 if (obscureTickPendings_ > 0) {
1824 --obscureTickPendings_;
1825 }
1826 cursorVisibility_ = !cursorVisibility_;
1827 ScheduleCursorTwinkling();
1828 }
1829
OnKeyEvent(const KeyEvent & event)1830 bool RenderTextField::OnKeyEvent(const KeyEvent& event)
1831 {
1832 if (!enabled_) {
1833 return false;
1834 }
1835
1836 // If back or escape is clicked and overlay is showing, pop overlay firstly.
1837 if (event.action == KeyAction::UP && (event.code == KeyCode::KEY_BACK || event.code == KeyCode::KEY_ESCAPE)) {
1838 if (isOverlayShowed_) {
1839 PopTextOverlay();
1840 return false;
1841 }
1842 }
1843 if (event.action == KeyAction::UP &&
1844 ((event.code == KeyCode::KEY_SHIFT_LEFT || event.code == KeyCode::KEY_SHIFT_RIGHT) ||
1845 (event.code == KEY_META_OR_CTRL_LEFT || event.code == KEY_META_OR_CTRL_RIGHT))) {
1846 return HandleKeyEvent(event);
1847 }
1848
1849 if (event.action == KeyAction::DOWN) {
1850 cursorPositionType_ = CursorPositionType::NONE;
1851 if (KeyCode::TV_CONTROL_UP <= event.code && event.code <= KeyCode::TV_CONTROL_RIGHT &&
1852 (event.IsKey({ KeyCode::KEY_SHIFT_LEFT, event.code }) ||
1853 event.IsKey({ KeyCode::KEY_SHIFT_RIGHT, event.code }))) {
1854 HandleOnSelect(event.code);
1855 return true;
1856 }
1857 if (event.code == KeyCode::TV_CONTROL_LEFT) {
1858 CursorMoveLeft();
1859 obscureTickPendings_ = 0;
1860 return true;
1861 }
1862 if (event.code == KeyCode::TV_CONTROL_RIGHT) {
1863 CursorMoveRight();
1864 obscureTickPendings_ = 0;
1865 return true;
1866 }
1867 if (event.code == KeyCode::TV_CONTROL_UP) {
1868 CursorMoveUp();
1869 obscureTickPendings_ = 0;
1870 return true;
1871 }
1872 if (event.code == KeyCode::TV_CONTROL_DOWN) {
1873 CursorMoveDown();
1874 obscureTickPendings_ = 0;
1875 return true;
1876 }
1877 if (event.code == KeyCode::KEY_FORWARD_DEL) {
1878 int32_t startPos = GetEditingValue().selection.GetStart();
1879 int32_t endPos = GetEditingValue().selection.GetEnd();
1880 Delete(startPos, startPos == endPos ? startPos - 1 : endPos);
1881 return true;
1882 }
1883 if (event.code == KeyCode::KEY_DEL) {
1884 int32_t startPos = GetEditingValue().selection.GetStart();
1885 int32_t endPos = GetEditingValue().selection.GetEnd();
1886 Delete(startPos, startPos == endPos ? startPos + 1 : endPos);
1887 return true;
1888 }
1889 }
1890 return HandleKeyEvent(event);
1891 }
1892
UpdateFocusStyles()1893 void RenderTextField::UpdateFocusStyles()
1894 {
1895 if (hasFocus_) {
1896 style_.SetTextColor(focusTextColor_);
1897 placeholderColor_ = focusPlaceholderColor_;
1898 if (decoration_) {
1899 decoration_->SetBackgroundColor(focusBgColor_);
1900 }
1901 } else {
1902 style_.SetTextColor(inactiveTextColor_);
1903 placeholderColor_ = inactivePlaceholderColor_;
1904 if (decoration_) {
1905 decoration_->SetBackgroundColor(inactiveBgColor_);
1906 }
1907 }
1908 }
1909
UpdateFocusAnimation()1910 void RenderTextField::UpdateFocusAnimation()
1911 {
1912 if (hasFocus_) {
1913 auto context = context_.Upgrade();
1914 if (!context) {
1915 return;
1916 }
1917 Offset offset;
1918 Size size;
1919 Radius deflateRadius;
1920 if (IsSelectiveDevice()) {
1921 double focusOffset = NormalizeToPx(OFFSET_FOCUS);
1922 offset = Offset(focusOffset, focusOffset);
1923 size = Size(focusOffset * 2.0, focusOffset * 2.0);
1924 deflateRadius = Radius(DEFLATE_RADIUS_FOCUS, DEFLATE_RADIUS_FOCUS);
1925 }
1926 RRect rrect = RRect::MakeRect(
1927 Rect(GetPosition() + offset, GetLayoutSize() - ComputeDeflateSizeOfErrorAndCountText() - size));
1928 if (decoration_) {
1929 const auto& border = decoration_->GetBorder();
1930 rrect.SetCorner({ border.TopLeftRadius() - deflateRadius, border.TopRightRadius() - deflateRadius,
1931 border.BottomRightRadius() - deflateRadius, border.BottomLeftRadius() - deflateRadius });
1932 }
1933 context->ShowFocusAnimation(rrect, focusBgColor_, GetGlobalOffset() + offset);
1934 }
1935 }
1936
UpdateIcon(const RefPtr<TextFieldComponent> & textField)1937 void RenderTextField::UpdateIcon(const RefPtr<TextFieldComponent>& textField)
1938 {
1939 if (!textField) {
1940 return;
1941 }
1942 iconSizeInDimension_ = textField->GetIconSize();
1943 iconHotZoneSizeInDimension_ = textField->GetIconHotZoneSize();
1944 UpdatePasswordIcon(textField);
1945
1946 double widthReserved = NormalizeToPx(widthReserved_);
1947 if (textField->GetIconImage() == iconSrc_ && textField->GetImageFill() == imageFill_ && widthReserved <= 0.0) {
1948 return;
1949 }
1950 imageFill_ = textField->GetImageFill();
1951 iconSrc_ = textField->GetIconImage();
1952 if (!iconSrc_.empty() || widthReserved > 0.0) {
1953 RefPtr<ImageComponent> imageComponent;
1954 if (iconSrc_.empty() && widthReserved > 0.0) {
1955 imageComponent = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::SEARCH_SVG);
1956 } else {
1957 imageComponent = AceType::MakeRefPtr<ImageComponent>(iconSrc_);
1958 imageComponent->SetImageFill(imageFill_);
1959 }
1960 imageComponent->SetSyncMode(true);
1961 imageComponent->SetWidth(textField->GetIconSize());
1962 imageComponent->SetHeight(textField->GetIconSize());
1963 if (textDirection_ == TextDirection::RTL) {
1964 imageComponent->SetMatchTextDirection(true);
1965 imageComponent->SetTextDirection(TextDirection::RTL);
1966 }
1967
1968 iconImage_ = AceType::DynamicCast<RenderImage>(imageComponent->CreateRenderNode());
1969 if (!iconImage_) {
1970 return;
1971 }
1972 iconImage_->Attach(GetContext());
1973 iconImage_->SetDirectPaint(true);
1974 iconImage_->Update(imageComponent);
1975 AddChild(iconImage_);
1976 }
1977 }
1978
UpdatePasswordIcon(const RefPtr<TextFieldComponent> & textField)1979 void RenderTextField::UpdatePasswordIcon(const RefPtr<TextFieldComponent>& textField)
1980 {
1981 if (!IsSelectiveDevice()) {
1982 return;
1983 }
1984 if (!showPasswordIcon_) {
1985 renderShowIcon_.Reset();
1986 renderHideIcon_.Reset();
1987 return;
1988 }
1989
1990 showIconSrc_ = textField->GetShowIconImage();
1991 hideIconSrc_ = textField->GetHideIconImage();
1992
1993 // update show icon.
1994 RefPtr<ImageComponent> showImage;
1995 if (showIconSrc_.empty()) {
1996 showImage = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::SHOW_PASSWORD_SVG);
1997 } else {
1998 showImage = AceType::MakeRefPtr<ImageComponent>(showIconSrc_);
1999 }
2000 showImage->SetSyncMode(true);
2001 showImage->SetWidth(textField->GetIconSize());
2002 showImage->SetHeight(textField->GetIconSize());
2003
2004 renderShowIcon_ = AceType::DynamicCast<RenderImage>(showImage->CreateRenderNode());
2005 if (!renderShowIcon_) {
2006 return;
2007 }
2008 renderShowIcon_->Attach(GetContext());
2009 renderShowIcon_->SetDirectPaint(true);
2010 renderShowIcon_->Update(showImage);
2011 AddChild(renderShowIcon_);
2012
2013 // update hide icon.
2014 RefPtr<ImageComponent> hideImage;
2015 if (hideIconSrc_.empty()) {
2016 hideImage = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::HIDE_PASSWORD_SVG);
2017 } else {
2018 hideImage = AceType::MakeRefPtr<ImageComponent>(hideIconSrc_);
2019 }
2020 hideImage->SetSyncMode(true);
2021 hideImage->SetWidth(textField->GetIconSize());
2022 hideImage->SetHeight(textField->GetIconSize());
2023
2024 renderHideIcon_ = AceType::DynamicCast<RenderImage>(hideImage->CreateRenderNode());
2025 if (!renderHideIcon_) {
2026 return;
2027 }
2028 renderHideIcon_->Attach(GetContext());
2029 renderHideIcon_->SetDirectPaint(true);
2030 renderHideIcon_->Update(hideImage);
2031 AddChild(renderHideIcon_);
2032 }
2033
UpdateOverlay()2034 void RenderTextField::UpdateOverlay()
2035 {
2036 // When textfield PerformLayout, update overlay.
2037 if (isOverlayShowed_ && updateHandlePosition_) {
2038 auto selStart = GetEditingValue().selection.GetStart();
2039 auto selEnd = GetEditingValue().selection.GetEnd();
2040 Rect caretStart;
2041 Rect caretEnd;
2042 bool startHandleVisible =
2043 GetCaretRect(selStart, caretStart) ? IsVisible(caretStart + textOffsetForShowCaret_) : false;
2044 bool endHandleVisible =
2045 (selStart == selEnd)
2046 ? startHandleVisible
2047 : (GetCaretRect(selEnd, caretEnd) ? IsVisible(caretEnd + textOffsetForShowCaret_) : false);
2048
2049 OverlayShowOption option { .showMenu = isOverlayShowed_,
2050 .showStartHandle = startHandleVisible,
2051 .showEndHandle = endHandleVisible,
2052 .isSingleHandle = isSingleHandle_,
2053 .updateOverlayType = UpdateOverlayType::SCROLL,
2054 .startHandleOffset = GetPositionForExtend(selStart, isSingleHandle_),
2055 .endHandleOffset = GetPositionForExtend(selEnd, isSingleHandle_) };
2056 updateHandlePosition_(option);
2057 if (onClipRectChanged_) {
2058 onClipRectChanged_(innerRect_ + Size(HANDLE_HOT_ZONE, HANDLE_HOT_ZONE) + GetOffsetToPage() -
2059 Offset(HANDLE_HOT_ZONE / 2.0, 0.0));
2060 }
2061 }
2062 }
2063
RegisterFontCallbacks()2064 void RenderTextField::RegisterFontCallbacks()
2065 {
2066 // Register callback for fonts.
2067 auto pipelineContext = context_.Upgrade();
2068 if (!pipelineContext) {
2069 return;
2070 }
2071 auto callback = [textfield = AceType::WeakClaim(this)] {
2072 auto refPtr = textfield.Upgrade();
2073 if (refPtr) {
2074 refPtr->isCallbackCalled_ = true;
2075 refPtr->MarkNeedLayout();
2076 }
2077 };
2078 auto fontManager = pipelineContext->GetFontManager();
2079 if (fontManager) {
2080 for (const auto& familyName : style_.GetFontFamilies()) {
2081 fontManager->RegisterCallback(AceType::WeakClaim(this), familyName, callback);
2082 }
2083 fontManager->AddVariationNode(WeakClaim(this));
2084 }
2085 }
2086
OnStatusChanged(OHOS::Ace::RenderStatus renderStatus)2087 void RenderTextField::OnStatusChanged(OHOS::Ace::RenderStatus renderStatus)
2088 {
2089 hasFocus_ = renderStatus == RenderStatus::FOCUS;
2090 UpdateFocusStyles();
2091 MarkNeedLayout();
2092
2093 if (!hasFocus_) {
2094 auto context = context_.Upgrade();
2095 if (!context) {
2096 return;
2097 }
2098 // Don't call cancel focus animation when next frame comes because then focus is switched, next node will
2099 // show focus immediately, we shouldn't cancel focus animation that time.
2100 context->CancelFocusAnimation();
2101 }
2102 }
2103
OnValueChanged(bool needFireChangeEvent,bool needFireSelectChangeEvent)2104 void RenderTextField::OnValueChanged(bool needFireChangeEvent, bool needFireSelectChangeEvent)
2105 {
2106 isValueFromFront_ = !needFireChangeEvent;
2107 TextEditingValue temp = GetEditingValue();
2108 if (cursorPositionType_ == CursorPositionType::NORMAL && temp.selection.GetStart() == temp.selection.GetEnd()) {
2109 temp.selection.Update(AdjustCursorAndSelection(temp.selection.GetEnd()));
2110 }
2111 FireSelectChangeIfNeeded(temp, needFireSelectChangeEvent);
2112 SetEditingValue(std::move(temp), needFireChangeEvent);
2113 UpdateRemoteEditingIfNeeded(needFireChangeEvent);
2114 MarkNeedLayout();
2115 }
2116
FireSelectChangeIfNeeded(const TextEditingValue & newValue,bool needFireSelectChangeEvent) const2117 void RenderTextField::FireSelectChangeIfNeeded(const TextEditingValue& newValue, bool needFireSelectChangeEvent) const
2118 {
2119 if (needFireSelectChangeEvent && onSelectChangeEvent_ && newValue.selection != GetPreEditingValue().selection) {
2120 auto jsonResult = JsonUtil::Create(true);
2121 jsonResult->Put("start", newValue.selection.GetStart());
2122 jsonResult->Put("end", newValue.selection.GetEnd());
2123 onSelectChangeEvent_(std::string(R"("selectchange",)").append(jsonResult->ToString()));
2124 }
2125 }
2126
CursorMoveLeft(CursorMoveSkip skip)2127 void RenderTextField::CursorMoveLeft(CursorMoveSkip skip)
2128 {
2129 if (skip != CursorMoveSkip::CHARACTER) {
2130 // Not support yet.
2131 LOGE("move skip not support character yet");
2132 return;
2133 }
2134 isValueFromRemote_ = false;
2135 auto value = GetEditingValue();
2136 value.MoveLeft();
2137 SetEditingValue(std::move(value));
2138 cursorPositionType_ = CursorPositionType::NONE;
2139 MarkNeedLayout();
2140 }
2141
CursorMoveRight(CursorMoveSkip skip)2142 void RenderTextField::CursorMoveRight(CursorMoveSkip skip)
2143 {
2144 if (skip != CursorMoveSkip::CHARACTER) {
2145 // Not support yet.
2146 LOGE("move skip not support character yet");
2147 return;
2148 }
2149 isValueFromRemote_ = false;
2150 auto value = GetEditingValue();
2151 value.MoveRight();
2152 SetEditingValue(std::move(value));
2153 cursorPositionType_ = CursorPositionType::NONE;
2154 MarkNeedLayout();
2155 }
2156
CursorMoveUp()2157 void RenderTextField::CursorMoveUp()
2158 {
2159 if (keyboard_ != TextInputType::MULTILINE) {
2160 return;
2161 }
2162 isValueFromRemote_ = false;
2163 auto value = GetEditingValue();
2164 value.MoveToPosition(GetCursorPositionForMoveUp());
2165 SetEditingValue(std::move(value));
2166 cursorPositionType_ = CursorPositionType::NONE;
2167 MarkNeedLayout();
2168 }
2169
CursorMoveDown()2170 void RenderTextField::CursorMoveDown()
2171 {
2172 if (keyboard_ != TextInputType::MULTILINE) {
2173 return;
2174 }
2175 isValueFromRemote_ = false;
2176 auto value = GetEditingValue();
2177 value.MoveToPosition(GetCursorPositionForMoveDown());
2178 SetEditingValue(std::move(value));
2179 cursorPositionType_ = CursorPositionType::NONE;
2180 MarkNeedLayout();
2181 }
2182
HandleOnBlur()2183 void RenderTextField::HandleOnBlur()
2184 {
2185 LOGI("Textfield on blur");
2186 SetCanPaintSelection(false);
2187 auto lastPosition = static_cast<int32_t>(GetEditingValue().GetWideText().length());
2188 UpdateSelection(lastPosition, lastPosition);
2189 StopTwinkling();
2190 PopTextOverlay();
2191 OnEditChange(false);
2192 ResetOnFocusForTextFieldManager();
2193 }
2194
CursorMoveOnClick(const Offset & offset)2195 void RenderTextField::CursorMoveOnClick(const Offset& offset)
2196 {
2197 auto value = GetEditingValue();
2198 auto position = GetCursorPositionForClick(offset);
2199 value.MoveToPosition(position);
2200 UpdateSelection(position, position);
2201 SetEditingValue(std::move(value));
2202
2203 if (!GetEditingValue().text.empty() && position == GetEditingValue().selection.GetEnd()) {
2204 OnValueChanged(true, false);
2205 }
2206 }
2207
UpdateSelection(int32_t both)2208 void RenderTextField::UpdateSelection(int32_t both)
2209 {
2210 UpdateSelection(both, both);
2211 }
2212
UpdateSelection(int32_t start,int32_t end)2213 void RenderTextField::UpdateSelection(int32_t start, int32_t end)
2214 {
2215 auto value = GetEditingValue();
2216 value.UpdateSelection(start, end);
2217 SetEditingValue(std::move(value));
2218 auto refPtr = accessibilityNode_.Upgrade();
2219 if (refPtr) {
2220 refPtr->SetTextSelectionStart(start);
2221 refPtr->SetTextSelectionEnd(end);
2222 }
2223 }
2224
UpdateRemoteEditing(bool needFireChangeEvent)2225 void RenderTextField::UpdateRemoteEditing(bool needFireChangeEvent)
2226 {
2227 #if defined(ENABLE_STANDARD_INPUT)
2228 auto value = GetEditingValue();
2229 MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
2230 StringUtils::Str8ToStr16(value.text), value.selection.GetStart(), value.selection.GetEnd());
2231 #else
2232 if (!HasConnection()) {
2233 return;
2234 }
2235 connection_->SetEditingState(GetEditingValue(), GetInstanceId(), needFireChangeEvent);
2236 #endif
2237 }
2238
UpdateRemoteEditingIfNeeded(bool needFireChangeEvent)2239 void RenderTextField::UpdateRemoteEditingIfNeeded(bool needFireChangeEvent)
2240 {
2241 if (!enabled_) {
2242 return;
2243 }
2244 #if defined(ENABLE_STANDARD_INPUT)
2245 UpdateRemoteEditing(needFireChangeEvent);
2246 #else
2247 UpdateRemoteEditing(needFireChangeEvent);
2248 if (!lastKnownRemoteEditingValue_ || GetEditingValue() != *lastKnownRemoteEditingValue_) {
2249 lastKnownRemoteEditingValue_ = std::make_shared<TextEditingValue>(GetEditingValue());
2250 }
2251 #endif
2252 }
2253
ShowError(const std::string & errorText,bool resetToStart)2254 void RenderTextField::ShowError(const std::string& errorText, bool resetToStart)
2255 {
2256 errorText_ = errorText;
2257 if (!errorText.empty()) {
2258 auto refPtr = accessibilityNode_.Upgrade();
2259 if (refPtr) {
2260 refPtr->SetErrorText(errorText);
2261 }
2262 }
2263
2264 if (!errorText.empty()) {
2265 ChangeBorderToErrorStyle();
2266 } else {
2267 if (decoration_) {
2268 decoration_->SetBorder(originBorder_);
2269 }
2270 }
2271 MarkNeedLayout();
2272 }
2273
SetOnValueChange(const std::function<void ()> & onValueChange)2274 void RenderTextField::SetOnValueChange(const std::function<void()>& onValueChange)
2275 {
2276 onValueChange_ = onValueChange;
2277 }
2278
GetOnValueChange() const2279 const std::function<void()>& RenderTextField::GetOnValueChange() const
2280 {
2281 return onValueChange_;
2282 }
2283
SetOnKeyboardClose(const std::function<void (bool)> & onKeyboardClose)2284 void RenderTextField::SetOnKeyboardClose(const std::function<void(bool)>& onKeyboardClose)
2285 {
2286 onKeyboardClose_ = onKeyboardClose;
2287 }
2288
SetOnClipRectChanged(const std::function<void (const Rect &)> & onClipRectChanged)2289 void RenderTextField::SetOnClipRectChanged(const std::function<void(const Rect&)>& onClipRectChanged)
2290 {
2291 onClipRectChanged_ = onClipRectChanged;
2292 }
2293
SetUpdateHandlePosition(const std::function<void (const OverlayShowOption &)> & updateHandlePosition)2294 void RenderTextField::SetUpdateHandlePosition(const std::function<void(const OverlayShowOption&)>& updateHandlePosition)
2295 {
2296 updateHandlePosition_ = updateHandlePosition;
2297 }
2298
SetUpdateHandleDiameter(const std::function<void (const double &)> & updateHandleDiameter)2299 void RenderTextField::SetUpdateHandleDiameter(const std::function<void(const double&)>& updateHandleDiameter)
2300 {
2301 updateHandleDiameter_ = updateHandleDiameter;
2302 }
2303
SetUpdateHandleDiameterInner(const std::function<void (const double &)> & updateHandleDiameterInner)2304 void RenderTextField::SetUpdateHandleDiameterInner(const std::function<void(const double&)>& updateHandleDiameterInner)
2305 {
2306 updateHandleDiameterInner_ = updateHandleDiameterInner;
2307 }
2308
SetIsOverlayShowed(bool isOverlayShowed,bool needStartTwinkling)2309 void RenderTextField::SetIsOverlayShowed(bool isOverlayShowed, bool needStartTwinkling)
2310 {
2311 isOverlayShowed_ = isOverlayShowed;
2312 // When pop overlay, reset selection and clear selected style.
2313 if (GetEditingValue().selection.GetStart() != GetEditingValue().selection.GetEnd()) {
2314 UpdateSelection(GetEditingValue().selection.GetEnd());
2315 }
2316 if (!isOverlayShowed_ && hasFocus_ && needStartTwinkling) {
2317 StartTwinkling();
2318 }
2319 }
2320
HandleOnSelect(KeyCode keyCode,CursorMoveSkip skip)2321 void RenderTextField::HandleOnSelect(KeyCode keyCode, CursorMoveSkip skip)
2322 {
2323 if (skip != CursorMoveSkip::CHARACTER) {
2324 // Not support yet.
2325 LOGE("move skip not support character yet");
2326 return;
2327 }
2328
2329 isValueFromRemote_ = false;
2330 auto value = GetEditingValue();
2331 int32_t startPos = value.selection.GetStart();
2332 int32_t endPos = value.selection.GetEnd();
2333 static bool isForwardSelect;
2334 switch (keyCode) {
2335 case KeyCode::KEY_DPAD_LEFT:
2336 if (startPos == endPos) {
2337 isForwardSelect = true;
2338 }
2339 if (isForwardSelect) {
2340 value.UpdateSelection(startPos - 1, endPos);
2341 } else {
2342 value.UpdateSelection(startPos, endPos - 1);
2343 }
2344 break;
2345 case KeyCode::KEY_DPAD_RIGHT:
2346 if (startPos == endPos) {
2347 isForwardSelect = false;
2348 }
2349 if (isForwardSelect) {
2350 value.UpdateSelection(startPos + 1, endPos);
2351 } else {
2352 value.UpdateSelection(startPos, endPos + 1);
2353 }
2354 break;
2355 default:
2356 LOGI("Currently only left and right selections are supported.");
2357 return;
2358 }
2359
2360 SetEditingValue(std::move(value));
2361 MarkNeedLayout();
2362 }
2363
HandleOnRevoke()2364 void RenderTextField::HandleOnRevoke()
2365 {
2366 if (operationRecords_.empty()) {
2367 return;
2368 }
2369 inverseOperationRecords_.push_back(GetEditingValue());
2370 operationRecords_.pop_back();
2371 auto value = operationRecords_.back();
2372 operationRecords_.pop_back();
2373 isValueFromRemote_ = false;
2374 SetEditingValue(std::move(value), true, false);
2375 cursorPositionType_ = CursorPositionType::NONE;
2376 MarkNeedLayout();
2377 if (onChange_) {
2378 onChange_(GetEditingValue().text);
2379 }
2380 }
2381
HandleOnInverseRevoke()2382 void RenderTextField::HandleOnInverseRevoke()
2383 {
2384 if (inverseOperationRecords_.empty()) {
2385 return;
2386 }
2387 auto value = inverseOperationRecords_.back();
2388 inverseOperationRecords_.pop_back();
2389 isValueFromRemote_ = false;
2390 SetEditingValue(std::move(value), true, false);
2391 cursorPositionType_ = CursorPositionType::NONE;
2392 MarkNeedLayout();
2393 if (onChange_) {
2394 onChange_(GetEditingValue().text);
2395 }
2396 }
2397
HandleOnCut()2398 void RenderTextField::HandleOnCut()
2399 {
2400 if (!clipboard_) {
2401 return;
2402 }
2403 if (GetEditingValue().GetSelectedText().empty()) {
2404 LOGW("copy value is empty");
2405 return;
2406 }
2407 if (copyOption_ != CopyOptions::None) {
2408 LOGI("copy value is %{private}s", GetEditingValue().GetSelectedText().c_str());
2409 clipboard_->SetData(GetEditingValue().GetSelectedText(), copyOption_);
2410 }
2411 if (onCut_) {
2412 onCut_(GetEditingValue().GetSelectedText());
2413 }
2414 auto value = GetEditingValue();
2415 value.text = value.GetBeforeSelection() + value.GetAfterSelection();
2416 value.UpdateSelection(GetEditingValue().selection.GetStart());
2417 SetEditingValue(std::move(value));
2418 if (onChange_) {
2419 onChange_(GetEditingValue().text);
2420 }
2421 }
2422
HandleOnCopy()2423 void RenderTextField::HandleOnCopy()
2424 {
2425 if (!clipboard_) {
2426 return;
2427 }
2428 if (GetEditingValue().GetSelectedText().empty()) {
2429 LOGW("copy value is empty");
2430 return;
2431 }
2432 if (copyOption_ != CopyOptions::None) {
2433 LOGI("copy value is %{private}s", GetEditingValue().GetSelectedText().c_str());
2434 clipboard_->SetData(GetEditingValue().GetSelectedText(), copyOption_);
2435 }
2436 if (onCopy_) {
2437 onCopy_(GetEditingValue().GetSelectedText());
2438 }
2439 UpdateSelection(GetEditingValue().selection.GetEnd());
2440 }
2441
HandleOnPaste()2442 void RenderTextField::HandleOnPaste()
2443 {
2444 ACE_FUNCTION_TRACE();
2445 if (!clipboard_) {
2446 return;
2447 }
2448 auto textSelection = GetEditingValue().selection;
2449 auto pasteCallback = [weak = WeakClaim(this), textSelection](const std::string& data) {
2450 if (data.empty()) {
2451 LOGW("paste value is empty");
2452 return;
2453 }
2454 LOGI("paste value is %{private}s", data.c_str());
2455 auto textfield = weak.Upgrade();
2456 if (textfield) {
2457 auto value = textfield->GetEditingValue();
2458 value.selection = textSelection;
2459 value.text = value.GetBeforeSelection() + data + value.GetAfterSelection();
2460 value.UpdateSelection(textSelection.GetStart() + StringUtils::Str8ToStr16(data).length());
2461 textfield->SetEditingValue(std::move(value));
2462 if (textfield->onPaste_) {
2463 textfield->onPaste_(data);
2464 }
2465 if (textfield->onChange_) {
2466 textfield->onChange_(textfield->GetEditingValue().text);
2467 }
2468 }
2469 };
2470 clipboard_->GetData(pasteCallback);
2471 }
2472
HandleOnCopyAll(const std::function<void (const Offset &,const Offset &)> & callback)2473 void RenderTextField::HandleOnCopyAll(const std::function<void(const Offset&, const Offset&)>& callback)
2474 {
2475 isSingleHandle_ = false;
2476 cursorPositionType_ = CursorPositionType::NORMAL;
2477 auto textSize = GetEditingValue().GetWideText().length();
2478 if (textSize == 0) {
2479 isSingleHandle_ = true;
2480 }
2481 UpdateSelection(0, textSize);
2482 if (callback) {
2483 callback(GetPositionForExtend(0, isSingleHandle_),
2484 GetPositionForExtend(GetEditingValue().GetWideText().length(), isSingleHandle_));
2485 }
2486 }
2487
HandleOnStartHandleMove(int32_t end,const Offset & startHandleOffset,const std::function<void (const Offset &)> & startCallback,bool isSingleHandle)2488 void RenderTextField::HandleOnStartHandleMove(int32_t end, const Offset& startHandleOffset,
2489 const std::function<void(const Offset&)>& startCallback, bool isSingleHandle)
2490 {
2491 Offset realOffset = startHandleOffset;
2492 if (startCallback) {
2493 UpdateStartSelection(end, realOffset, isSingleHandle, false);
2494 startCallback(GetHandleOffset(GetEditingValue().selection.GetStart()));
2495 }
2496 }
2497
HandleOnEndHandleMove(int32_t start,const Offset & endHandleOffset,const std::function<void (const Offset &)> & endCallback)2498 void RenderTextField::HandleOnEndHandleMove(
2499 int32_t start, const Offset& endHandleOffset, const std::function<void(const Offset&)>& endCallback)
2500 {
2501 Offset realOffset = endHandleOffset;
2502 if (endCallback) {
2503 UpdateEndSelection(start, realOffset);
2504 endCallback(GetHandleOffset(GetEditingValue().selection.GetEnd()));
2505 }
2506 }
2507
GetLastStack() const2508 RefPtr<StackElement> RenderTextField::GetLastStack() const
2509 {
2510 auto context = context_.Upgrade();
2511 if (!context) {
2512 LOGE("Context is nullptr");
2513 return nullptr;
2514 }
2515 return context->GetLastStack();
2516 }
2517
HandleKeyEvent(const KeyEvent & event)2518 bool RenderTextField::HandleKeyEvent(const KeyEvent& event)
2519 {
2520 std::string appendElement;
2521 if (event.action == KeyAction::DOWN) {
2522 if (event.code == KeyCode::KEY_ENTER || event.code == KeyCode::KEY_NUMPAD_ENTER ||
2523 event.code == KeyCode::KEY_DPAD_CENTER) {
2524 if (keyboard_ == TextInputType::MULTILINE) {
2525 appendElement = "\n";
2526 } else {
2527 // normal enter should trigger onSubmit
2528 PerformAction(action_, true);
2529 }
2530 } else if (event.IsNumberKey()) {
2531 appendElement = event.ConvertCodeToString();
2532 } else if (event.IsLetterKey()) {
2533 if (event.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_Z }) ||
2534 event.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_Z }) ||
2535 event.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_Z }) ||
2536 event.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_Z }) ||
2537 event.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_Y }) ||
2538 event.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_Y })) {
2539 HandleOnInverseRevoke();
2540 } else if (event.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_Z }) ||
2541 event.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_Z })) {
2542 HandleOnRevoke();
2543 } else if (event.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_A }) ||
2544 event.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_A })) {
2545 HandleOnCopyAll(nullptr);
2546 } else if (event.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_C }) ||
2547 event.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_C })) {
2548 HandleOnCopy();
2549 } else if (event.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_V }) ||
2550 event.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_V })) {
2551 HandleOnPaste();
2552 } else if (event.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_X }) ||
2553 event.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_X })) {
2554 HandleOnCut();
2555 } else {
2556 appendElement = event.ConvertCodeToString();
2557 }
2558 }
2559 MarkNeedLayout();
2560 }
2561 if (appendElement.empty()) {
2562 return false;
2563 }
2564
2565 auto editingValue = std::make_shared<TextEditingValue>();
2566 editingValue->text = GetEditingValue().GetBeforeSelection() + appendElement + GetEditingValue().GetAfterSelection();
2567 editingValue->UpdateSelection(
2568 std::max(GetEditingValue().selection.GetEnd(), 0) + StringUtils::Str8ToStr16(appendElement).length());
2569 UpdateEditingValue(editingValue);
2570 MarkNeedLayout();
2571 return true;
2572 }
2573
UpdateAccessibilityAttr()2574 void RenderTextField::UpdateAccessibilityAttr()
2575 {
2576 auto refPtr = accessibilityNode_.Upgrade();
2577 if (!refPtr) {
2578 LOGW("RenderTextField accessibilityNode is null.");
2579 return;
2580 }
2581
2582 refPtr->SetHintText(placeholder_);
2583 refPtr->SetMaxTextLength(maxLength_);
2584 refPtr->SetEditable(enabled_);
2585 refPtr->SetClickableState(true);
2586 refPtr->SetLongClickableState(true);
2587 if (maxLines_ > 1) {
2588 refPtr->SetIsMultiLine(true);
2589 }
2590 if (controller_) {
2591 refPtr->SetText(controller_->GetText());
2592 }
2593 switch (keyboard_) {
2594 case TextInputType::TEXT:
2595 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_TEXT);
2596 break;
2597 case TextInputType::NUMBER:
2598 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_NUMBER);
2599 break;
2600 case TextInputType::DATETIME:
2601 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_DATE);
2602 break;
2603 case TextInputType::EMAIL_ADDRESS:
2604 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_EMAIL);
2605 break;
2606 case TextInputType::VISIBLE_PASSWORD:
2607 refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_PASSWORD);
2608 break;
2609 default:
2610 break;
2611 }
2612 }
2613
InitAccessibilityEventListener()2614 void RenderTextField::InitAccessibilityEventListener()
2615 {
2616 const auto& accessibilityNode = GetAccessibilityNode().Upgrade();
2617 if (!accessibilityNode) {
2618 return;
2619 }
2620 accessibilityNode->AddSupportAction(AceAction::ACTION_CLICK);
2621 accessibilityNode->SetActionClickImpl([weakPtr = WeakClaim(this)]() {
2622 const auto& textField = weakPtr.Upgrade();
2623 if (textField) {
2624 textField->OnClick(ClickInfo(0));
2625 }
2626 });
2627
2628 accessibilityNode->AddSupportAction(AceAction::ACTION_LONG_CLICK);
2629 accessibilityNode->SetActionLongClickImpl([weakPtr = WeakClaim(this)]() {
2630 const auto& textField = weakPtr.Upgrade();
2631 if (textField) {
2632 textField->OnLongPress(LongPressInfo(0));
2633 }
2634 });
2635
2636 accessibilityNode->AddSupportAction(AceAction::ACTION_SET_TEXT);
2637 accessibilityNode->SetActionSetTextImpl([weakPtr = WeakClaim(this)](const std::string& text) {
2638 const auto& textField = weakPtr.Upgrade();
2639 if (textField) {
2640 textField->SetEditingValue(text);
2641 }
2642 });
2643 }
2644
UpdateDirectionStatus()2645 void RenderTextField::UpdateDirectionStatus()
2646 {
2647 directionStatus_ = static_cast<DirectionStatus>(
2648 (static_cast<uint8_t>(textDirection_) << 1) | static_cast<uint8_t>(realTextDirection_));
2649 }
2650
UpdateStartSelection(int32_t end,const Offset & pos,bool isSingleHandle,bool isLongPress)2651 void RenderTextField::UpdateStartSelection(int32_t end, const Offset& pos, bool isSingleHandle, bool isLongPress)
2652 {
2653 int32_t extend = GetCursorPositionForClick(pos);
2654 if (isLongPress) {
2655 // Use custom selection if exist, otherwise select content near finger.
2656 if (selection_.IsValid()) {
2657 UpdateSelection(selection_.baseOffset, selection_.extentOffset);
2658 } else {
2659 int32_t extendEnd = extend + GetGraphemeClusterLength(extend, false);
2660 UpdateSelection(extend, extendEnd);
2661 }
2662 return;
2663 }
2664 if (isSingleHandle) {
2665 UpdateSelection(extend);
2666 } else {
2667 UpdateSelection(extend, end);
2668 }
2669 }
2670
UpdateEndSelection(int32_t start,const Offset & pos)2671 void RenderTextField::UpdateEndSelection(int32_t start, const Offset& pos)
2672 {
2673 int32_t extend = GetCursorPositionForClick(pos);
2674 UpdateSelection(start, extend);
2675 }
2676
GetPositionForExtend(int32_t extend,bool isSingleHandle)2677 Offset RenderTextField::GetPositionForExtend(int32_t extend, bool isSingleHandle)
2678 {
2679 if (extend < 0) {
2680 extend = 0;
2681 }
2682 if (static_cast<size_t>(extend) > GetEditingValue().GetWideText().length()) {
2683 extend = static_cast<int32_t>(GetEditingValue().GetWideText().length());
2684 }
2685 return GetHandleOffset(extend);
2686 }
2687
GetGraphemeClusterLength(int32_t extend,bool isPrefix) const2688 int32_t RenderTextField::GetGraphemeClusterLength(int32_t extend, bool isPrefix) const
2689 {
2690 auto text = GetTextForDisplay(GetEditingValue().text);
2691 char16_t aroundChar = 0;
2692 if (isPrefix) {
2693 if (static_cast<size_t>(extend) <= text.length()) {
2694 aroundChar = text[std::max(0, extend - 1)];
2695 }
2696 } else {
2697 if (static_cast<size_t>(extend) < (text.length())) {
2698 aroundChar = text[std::min(static_cast<int32_t>(text.length() - 1), extend)];
2699 }
2700 }
2701 return StringUtils::NotInUtf16Bmp(aroundChar) ? 2 : 1;
2702 }
2703
ShowCounter() const2704 bool RenderTextField::ShowCounter() const
2705 {
2706 return showCounter_ && maxLength_ < std::numeric_limits<uint32_t>::max();
2707 }
2708
ChangeCounterStyle(const TextEditingValue & value)2709 void RenderTextField::ChangeCounterStyle(const TextEditingValue& value)
2710 {
2711 if (!ShowCounter()) {
2712 return;
2713 }
2714 if (value.GetWideText().size() > maxLength_) {
2715 overCount_ = true;
2716 ChangeBorderToErrorStyle();
2717 } else if (value.GetWideText().size() < maxLength_) {
2718 overCount_ = false;
2719 if (decoration_) {
2720 decoration_->SetBorder(originBorder_);
2721 }
2722 }
2723 }
2724
ChangeBorderToErrorStyle()2725 void RenderTextField::ChangeBorderToErrorStyle()
2726 {
2727 if (!decoration_) {
2728 decoration_ = AceType::MakeRefPtr<Decoration>();
2729 }
2730 const auto& border = decoration_->GetBorder();
2731 BorderEdge errorBorderEdge(errorBorderColor_, errorBorderWidth_, BorderStyle::SOLID);
2732 Border errorBorder;
2733 if (!border.Left().HasValue() && !border.Top().HasValue() && !border.Right().HasValue() &&
2734 border.Bottom().HasValue()) {
2735 // Change over count style for linear input.
2736 errorBorder = Border(BorderEdge(), BorderEdge(), BorderEdge(), errorBorderEdge);
2737 } else {
2738 errorBorder = Border(errorBorderEdge);
2739 }
2740 errorBorder.SetTopLeftRadius(decoration_->GetBorder().TopLeftRadius());
2741 errorBorder.SetTopRightRadius(decoration_->GetBorder().TopRightRadius());
2742 errorBorder.SetBottomLeftRadius(decoration_->GetBorder().BottomLeftRadius());
2743 errorBorder.SetBottomRightRadius(decoration_->GetBorder().BottomRightRadius());
2744 decoration_->SetBorder(errorBorder);
2745 }
2746
HandleDeviceOrientationChange()2747 void RenderTextField::HandleDeviceOrientationChange()
2748 {
2749 if (deviceOrientation_ != SystemProperties::GetDeviceOrientation()) {
2750 deviceOrientation_ = SystemProperties::GetDeviceOrientation();
2751 if (isOverlayShowed_) {
2752 onKeyboardClose_ = nullptr;
2753 PopTextOverlay();
2754 StartTwinkling();
2755 }
2756 }
2757 }
2758
OnHiddenChanged(bool hidden)2759 void RenderTextField::OnHiddenChanged(bool hidden)
2760 {
2761 if (hidden) {
2762 LOGI("On hidden change, close keyboard");
2763 CloseKeyboard();
2764 PopTextOverlay();
2765 }
2766 }
2767
OnAppHide()2768 void RenderTextField::OnAppHide()
2769 {
2770 RenderNode::OnAppHide();
2771 OnHiddenChanged(true);
2772 }
2773
OnOverlayFocusChange(bool isFocus,bool needCloseKeyboard)2774 void RenderTextField::OnOverlayFocusChange(bool isFocus, bool needCloseKeyboard)
2775 {
2776 isOverlayFocus_ = isFocus;
2777 if (needCloseKeyboard && onOverlayFocusChange_) {
2778 onOverlayFocusChange_(isFocus);
2779 }
2780 }
2781
GetInstanceId() const2782 int32_t RenderTextField::GetInstanceId() const
2783 {
2784 auto context = context_.Upgrade();
2785 if (context) {
2786 return context->GetInstanceId();
2787 }
2788 return 0;
2789 }
2790
Insert(const std::string & text)2791 void RenderTextField::Insert(const std::string& text)
2792 {
2793 auto context = context_.Upgrade();
2794 if (context) {
2795 context->GetTaskExecutor()->PostTask(
2796 [weakPtr = WeakClaim(this), text] {
2797 const auto& textField = weakPtr.Upgrade();
2798 auto value = textField->GetEditingValue();
2799 auto textEditingValue = std::make_shared<TextEditingValue>();
2800 textEditingValue->text = value.GetBeforeSelection() + text + value.GetAfterSelection();
2801 textEditingValue->UpdateSelection(std::max(value.selection.GetStart(), 0) + text.length());
2802 textField->UpdateInsertText(text);
2803 textField->UpdateEditingValue(textEditingValue, true);
2804 },
2805 TaskExecutor::TaskType::UI);
2806 }
2807 }
2808
Delete(int32_t start,int32_t end)2809 void RenderTextField::Delete(int32_t start, int32_t end)
2810 {
2811 auto value = GetEditingValue();
2812 value.Delete(start, end);
2813 SetEditingValue(std::move(value));
2814 if (onValueChange_) {
2815 onValueChange_();
2816 }
2817 if (onChange_) {
2818 onChange_(GetEditingValue().text);
2819 }
2820 }
2821
ProvideRestoreInfo()2822 std::string RenderTextField::ProvideRestoreInfo()
2823 {
2824 auto value = GetEditingValue();
2825 auto jsonObj = JsonUtil::Create(true);
2826 if (controller_) {
2827 jsonObj->Put("text", controller_->GetText().c_str());
2828 } else {
2829 return "";
2830 }
2831 jsonObj->Put("position", value.selection.baseOffset);
2832 return jsonObj->ToString();
2833 }
2834
ApplyRestoreInfo()2835 void RenderTextField::ApplyRestoreInfo()
2836 {
2837 if (GetRestoreInfo().empty()) {
2838 return;
2839 }
2840 auto info = JsonUtil::ParseJsonString(GetRestoreInfo());
2841 if (!info->IsValid() || !info->IsObject()) {
2842 LOGW("RenderTextField:: restore info is invalid");
2843 return;
2844 }
2845 auto jsonPosition = info->GetValue("position");
2846 auto jsonText = info->GetValue("text");
2847 if (!jsonText->GetString().empty() && controller_) {
2848 controller_->SetText(jsonText->GetString());
2849 UpdateSelection(std::max(jsonPosition->GetInt(), 0));
2850 cursorPositionType_ = CursorPositionType::NORMAL;
2851 }
2852 SetRestoreInfo("");
2853 }
2854
ApplyAspectRatio()2855 void RenderTextField::ApplyAspectRatio()
2856 {
2857 auto parent = GetParent().Upgrade();
2858 while (parent) {
2859 auto renderBox = DynamicCast<RenderBox>(parent);
2860 if (renderBox && !NearZero(renderBox->GetAspectRatio()) && GetLayoutParam().GetMaxSize().IsValid() &&
2861 !GetLayoutParam().GetMaxSize().IsInfinite()) {
2862 height_ = Dimension(GetLayoutParam().GetMaxSize().Height());
2863 break;
2864 }
2865 parent = parent->GetParent().Upgrade();
2866 }
2867 }
2868
Dump()2869 void RenderTextField::Dump()
2870 {
2871 DumpLog::GetInstance().AddDesc(std::string("CopyOptions: ").append(V2::ConvertWrapCopyOptionToString(copyOption_)));
2872 }
2873
2874 } // namespace OHOS::Ace
2875