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