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