• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components/text_field/render_text_field.h"
17 
18 #include "base/i18n/localization.h"
19 #include "base/json/json_util.h"
20 #include "base/utils/string_utils.h"
21 #include "core/animation/curve_animation.h"
22 #include "core/common/clipboard/clipboard_proxy.h"
23 #include "core/common/font_manager.h"
24 #include "core/components/stack/stack_element.h"
25 #include "core/components/text/text_utils.h"
26 #include "core/components/text_overlay/text_overlay_component.h"
27 #include "core/components/text_overlay/text_overlay_element.h"
28 #include "core/event/ace_event_helper.h"
29 
30 #if defined(ENABLE_STANDARD_INPUT)
31 #include "core/components/text_field/on_text_changed_listener_impl.h"
32 #endif
33 
34 namespace OHOS::Ace {
35 namespace {
36 
37 constexpr uint32_t TWINKLING_INTERVAL_MS = 500;
38 // Tick count indicate how long should the naked character should be displayed while obscure_ == true.
39 constexpr uint32_t OBSCURE_SHOW_TICKS = 3;
40 constexpr double HANDLE_HOT_ZONE = 10.0;
41 
42 constexpr char16_t OBSCURING_CHARACTER = u'•';
43 constexpr char16_t OBSCURING_CHARACTER_FOR_AR = u'*';
44 
45 constexpr int32_t DEFAULT_SELECT_INDEX = 0;
46 constexpr int32_t SHOW_HANDLE_DURATION = 250;
47 constexpr int32_t DOUBLE_CLICK_FINGERS = 1;
48 constexpr int32_t DOUBLE_CLICK_COUNTS = 2;
49 constexpr double FIFTY_PERCENT = 0.5;
50 
51 constexpr Dimension OFFSET_FOCUS = 4.0_vp;
52 constexpr Dimension DEFLATE_RADIUS_FOCUS = 3.0_vp;
53 
54 } // namespace
55 
56 #if defined(ENABLE_STANDARD_INPUT)
UpdateConfiguration()57 void RenderTextField::UpdateConfiguration()
58 {
59     MiscServices::Configuration configuration;
60     configuration.SetEnterKeyType(static_cast<MiscServices::EnterKeyType>((int32_t)action_));
61     configuration.SetTextInputType(static_cast<MiscServices::TextInputType>((int32_t)keyboard_));
62     MiscServices::InputMethodController::GetInstance()->OnConfigurationChange(configuration);
63 }
64 #endif
65 
RenderTextField()66 RenderTextField::RenderTextField()
67     : twinklingInterval(TWINKLING_INTERVAL_MS), controller_(AceType::MakeRefPtr<TextEditController>())
68 {}
69 
~RenderTextField()70 RenderTextField::~RenderTextField()
71 {
72     LOGI("Destruction text field.");
73     if (controller_) {
74         controller_->Clear();
75         controller_->RemoveObserver(WeakClaim(this));
76     }
77     auto pipelineContext = context_.Upgrade();
78     if (!pipelineContext) {
79         return;
80     }
81     PopTextOverlay();
82     pipelineContext->RemoveFontNode(AceType::WeakClaim(this));
83     auto fontManager = pipelineContext->GetFontManager();
84     if (fontManager) {
85         fontManager->UnRegisterCallback(AceType::WeakClaim(this));
86         fontManager->RemoveVariationNode(WeakClaim(this));
87     }
88 
89     // If soft keyboard is still exist, close it.
90     if (HasConnection()) {
91 #if defined(ENABLE_STANDARD_INPUT)
92         LOGI("Destruction text field, close input method.");
93         MiscServices::InputMethodController::GetInstance()->Close();
94 #else
95         connection_->Close(GetInstanceId());
96         connection_ = nullptr;
97 #endif
98     }
99 }
100 
Update(const RefPtr<Component> & component)101 void RenderTextField::Update(const RefPtr<Component>& component)
102 {
103     const RefPtr<TextFieldComponent> textField = AceType::DynamicCast<TextFieldComponent>(component);
104     if (!textField) {
105         return;
106     }
107 
108     // Clear children to avoid children increase.
109     ClearChildren();
110 
111     if (textField->IsTextLengthLimited()) {
112         maxLength_ = textField->GetMaxLength();
113     }
114 
115     selection_ = textField->GetSelection();
116     placeholder_ = textField->GetPlaceholder();
117     inputFilter_ = textField->GetInputFilter();
118     inactivePlaceholderColor_ = textField->GetPlaceholderColor();
119     focusPlaceholderColor_ = textField->GetFocusPlaceholderColor();
120     focusBgColor_ = textField->GetFocusBgColor();
121     focusTextColor_ = textField->GetFocusTextColor();
122     selectedColor_ = textField->GetSelectedColor();
123     pressColor_ = textField->GetPressColor();
124     decoration_ = textField->GetDecoration();
125     inactiveBgColor_ = textField->GetBgColor();
126     if (decoration_ && (decoration_->GetImage() || decoration_->GetGradient().IsValid())) {
127         inactiveBgColor_ = Color::TRANSPARENT;
128         focusBgColor_ = Color::TRANSPARENT;
129     }
130     originBorder_ = textField->GetOriginBorder();
131     style_ = textField->GetTextStyle();
132     placeHoldStyle_ = textField->GetPlaceHoldStyle();
133     editingStyle_ = textField->GetEditingStyle();
134     fontSize_ = style_.GetFontSize();
135     errorTextStyle_ = textField->GetErrorTextStyle();
136     errorSpacingInDimension_ = textField->GetErrorSpacing();
137     errorIsInner_ = textField->GetErrorIsInner();
138     errorBorderWidth_ = textField->GetErrorBorderWidth();
139     errorBorderColor_ = textField->GetErrorBorderColor();
140     needFade_ = textField->NeedFade();
141     inactiveTextColor_ = style_.GetTextColor();
142     maxLines_ = textField->GetTextMaxLines();
143     onTextChangeEvent_ = AceAsyncEvent<void(const std::string&)>::Create(textField->GetOnTextChange(), context_);
144     onError_ = textField->GetOnError();
145     onValueChangeEvent_ = textField->GetOnTextChange().GetUiStrFunction();
146     if (textField->GetOnChange()) {
147         onChange_ = *textField->GetOnChange();
148     }
149     if (textField->GetOnEditChanged()) {
150         onEditChanged_ = *textField->GetOnEditChanged();
151     }
152     if (textField->GetOnSubmit()) {
153         onSubmit_ = *textField->GetOnSubmit();
154     }
155     if (textField->GetOnClick()) {
156         onClick_ = *textField->GetOnClick();
157     }
158     onSelectChangeEvent_ = AceAsyncEvent<void(const std::string&)>::Create(textField->GetOnSelectChange(), context_);
159     onFinishInputEvent_ = AceAsyncEvent<void(const std::string&)>::Create(textField->GetOnFinishInput(), context_);
160     onTapEvent_ = AceAsyncEvent<void()>::Create(textField->GetOnTap(), context_);
161     catchMode_ = textField->GetOnTap().IsEmpty() || textField->GetOnTap().GetCatchMode();
162     static const int32_t bubbleModeVersion = 6;
163     auto pipeline = context_.Upgrade();
164     if (!catchMode_) {
165         if (pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
166             catchMode_ = false;
167         } else {
168             catchMode_ = true;
169         }
170     }
171     onLongPressEvent_ = AceAsyncEvent<void()>::Create(textField->GetOnLongPress(), context_);
172     textAlign_ = textField->GetTextAlign();
173     textDirection_ = textField->GetTextDirection();
174     realTextDirection_ = textDirection_;
175     showCursor_ = textField->ShowCursor();
176     UpdateObscure(textField);
177     enabled_ = textField->IsEnabled();
178     widthReserved_ = textField->GetWidthReserved();
179     blockRightShade_ = textField->GetBlockRightShade();
180     isVisible_ = textField->IsVisible();
181     showPasswordIcon_ = textField->ShowPasswordIcon();
182     if (textField->HasSetResetToStart() && textField->GetUpdateType() == UpdateType::ALL) {
183         resetToStart_ = textField->GetResetToStart();
184     }
185     if (keyboard_ != textField->GetTextInputType()) {
186         auto context = context_.Upgrade();
187         if (context && context->GetIsDeclarative()) {
188             ClearEditingValue();
189         } else {
190             if (keyboard_ == TextInputType::VISIBLE_PASSWORD) {
191                 ClearEditingValue();
192             }
193         }
194         keyboard_ = textField->GetTextInputType();
195         CloseKeyboard();
196     }
197 
198     if (action_ != textField->GetAction()) {
199         auto context = context_.Upgrade();
200         if (context && context->GetIsDeclarative()) {
201             CloseKeyboard();
202             action_ = textField->GetAction();
203         } else {
204             action_ = textField->GetAction();
205         }
206     }
207 
208     actionLabel_ = textField->GetActionLabel();
209     height_ = textField->GetHeight();
210     if (textField->IsCursorColorSet()) {
211         cursorColorIsSet_ = true;
212         cursorColor_ = textField->GetCursorColor();
213     }
214     cursorRadius_ = textField->GetCursorRadius();
215     textFieldController_ = textField->GetTextFieldController();
216     if (textFieldController_) {
217         auto weak = AceType::WeakClaim(this);
218         textFieldController_->SetCaretPosition([weak](int32_t caretPosition) {
219             auto textField = weak.Upgrade();
220             if (textField) {
221                 textField->UpdateSelection(caretPosition);
222                 textField->cursorPositionType_ = CursorPositionType::NORMAL;
223                 textField->MarkNeedLayout();
224             }
225         });
226     }
227     if (textField->GetTextEditController() && controller_ != textField->GetTextEditController()) {
228         if (controller_) {
229             controller_->RemoveObserver(WeakClaim(this));
230         }
231         controller_ = textField->GetTextEditController();
232     }
233     if (controller_) {
234         controller_->RemoveObserver(WeakClaim(this));
235         controller_->AddObserver(WeakClaim(this));
236         controller_->SetHint(placeholder_);
237         if (textField->IsValueUpdated()) {
238             controller_->SetText(textField->GetValue(), false);
239         }
240     }
241     ApplyRestoreInfo();
242     extend_ = textField->IsExtend();
243     softKeyboardEnabled_ = textField->IsSoftKeyboardEnabled();
244     text_ = textField->GetValue();
245     showEllipsis_ = textField->ShowEllipsis();
246     auto context = context_.Upgrade();
247     if (!clipboard_ && context) {
248         clipboard_ = ClipboardProxy::GetInstance()->GetClipboard(context->GetTaskExecutor());
249     }
250 
251     if ((style_.IsAllowScale() || style_.GetFontSize().Unit() == DimensionUnit::FP) && context) {
252         context->AddFontNode(AceType::WeakClaim(this));
253     }
254 
255     showCounter_ = textField->ShowCounter();
256     countTextStyle_ = textField->GetCountTextStyle();
257     overCountStyle_ = textField->GetOverCountStyle();
258     countTextStyleOuter_ = textField->GetCountTextStyleOuter();
259     overCountStyleOuter_ = textField->GetOverCountStyleOuter();
260 
261     inputOptions_ = textField->GetInputOptions();
262     onOptionsClick_ = textField->GetOnOptionsClick();
263     onTranslate_ = textField->GetOnTranslate();
264     onShare_ = textField->GetOnShare();
265     onSearch_ = textField->GetOnSearch();
266 
267 #if defined(ENABLE_STANDARD_INPUT)
268     UpdateConfiguration();
269 #endif
270     SetCallback(textField);
271     UpdateFormatters();
272     UpdateFocusStyles();
273     UpdateIcon(textField);
274     RegisterFontCallbacks();
275     MarkNeedLayout();
276     UpdateAccessibilityAttr();
277 }
278 
SetCallback(const RefPtr<TextFieldComponent> & textField)279 void RenderTextField::SetCallback(const RefPtr<TextFieldComponent>& textField)
280 {
281     if (textField->GetOnCopy()) {
282         onCopy_ = *textField->GetOnCopy();
283     }
284     if (textField->GetOnCut()) {
285         onCut_ = *textField->GetOnCut();
286     }
287     if (textField->GetOnPaste()) {
288         onPaste_ = *textField->GetOnPaste();
289     }
290 }
291 
OnPaintFinish()292 void RenderTextField::OnPaintFinish()
293 {
294     UpdateFocusAnimation();
295     UpdateOverlay();
296     InitAccessibilityEventListener();
297     UpdateAccessibilityPosition();
298 }
299 
PerformLayout()300 void RenderTextField::PerformLayout()
301 {
302     if (!lastLayoutParam_.has_value()) {
303         lastLayoutParam_ = std::make_optional(GetLayoutParam());
304     }
305 
306     if (GetEditingValue().text.empty()) {
307         cursorPositionType_ = CursorPositionType::END;
308     }
309 
310     auto context = context_.Upgrade();
311     if (context && context->GetIsDeclarative()) {
312         const auto& currentText = controller_->GetValue().text;
313         showPlaceholder_ = currentText.empty();
314         if (showPlaceholder_) {
315             SetTextStyle(placeHoldStyle_);
316         } else {
317             SetTextStyle(editingStyle_);
318         }
319     }
320 
321     auto pipelineContext = GetContext().Upgrade();
322     if ((style_.IsAllowScale() || style_.GetFontSize().Unit() == DimensionUnit::FP) && pipelineContext &&
323         !NearEqual(fontScale_, pipelineContext->GetFontScale())) {
324         fontScale_ = pipelineContext->GetFontScale();
325         style_.SetFontSize(fontSize_ * fontScale_);
326     }
327 
328     iconSize_ = NormalizeToPx(iconSizeInDimension_);
329     iconHotZoneSize_ = NormalizeToPx(iconHotZoneSizeInDimension_);
330     errorSpacing_ = NormalizeToPx(errorSpacingInDimension_);
331     if (!GetChildren().empty()) {
332         auto innerLayout = GetLayoutParam();
333         innerLayout.SetMinSize(Size());
334         const auto& child = GetChildren().front();
335         child->Layout(innerLayout);
336     }
337     SetLayoutSize(GetLayoutParam().Constrain(Measure()));
338     UpdateFocusAnimation();
339 
340     LayoutParam layoutParam = GetLayoutParam();
341     layoutParam.SetMinSize(Size());
342     if (iconImage_) {
343         iconImage_->Layout(layoutParam);
344     }
345     if (renderShowIcon_) {
346         renderShowIcon_->Layout(layoutParam);
347     }
348     if (renderHideIcon_) {
349         renderHideIcon_->Layout(layoutParam);
350     }
351     if (needNotifyChangeEvent_ && (onTextChangeEvent_ || onValueChangeEvent_ || onChange_)) {
352         needNotifyChangeEvent_ = false;
353         if (onChange_) {
354             onChange_(GetEditingValue().text);
355         }
356         if (onValueChangeEvent_) {
357             onValueChangeEvent_(GetEditingValue().text);
358         }
359         if (onTextChangeEvent_) {
360             auto jsonResult = JsonUtil::Create(true);
361             jsonResult->Put("text", GetEditingValue().text.c_str());
362             jsonResult->Put("value", GetEditingValue().text.c_str());
363             jsonResult->Put("lines", textLines_);
364             jsonResult->Put("height", textHeight_);
365             onTextChangeEvent_(std::string(R"("change",)").append(jsonResult->ToString()));
366         }
367     }
368 
369     HandleDeviceOrientationChange();
370 }
371 
HandleMouseEvent(const MouseEvent & event)372 bool RenderTextField::HandleMouseEvent(const MouseEvent& event)
373 {
374     if (event.button == MouseButton::LEFT_BUTTON) {
375         if (event.action == MouseAction::PRESS) {
376             UpdateStartSelection(DEFAULT_SELECT_INDEX, event.GetOffset(), true, false);
377         } else if (event.action == MouseAction::MOVE) {
378             int32_t start = GetEditingValue().selection.baseOffset;
379             int32_t end = GetCursorPositionForClick(event.GetOffset());
380             UpdateSelection(start, end);
381             StopTwinkling();
382             MarkNeedRender();
383         } else {
384             LOGD("on left button release");
385         }
386     }
387 
388     if (event.button == MouseButton::RIGHT_BUTTON && event.action == MouseAction::PRESS) {
389         Offset rightClickOffset = event.GetOffset();
390         ShowTextOverlay(rightClickOffset, false);
391     }
392 
393     return true;
394 }
395 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)396 void RenderTextField::OnTouchTestHit(
397     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
398 {
399     if (!enabled_) {
400         return;
401     }
402     if (!clickRecognizer_) {
403         clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
404         clickRecognizer_->SetUseCatchMode(catchMode_);
405         auto weak = WeakClaim(this);
406         clickRecognizer_->SetOnClick([weak](const ClickInfo& info) {
407             auto client = weak.Upgrade();
408             if (client) {
409                 client->OnClick(info);
410             }
411         });
412         clickRecognizer_->SetPriority(GesturePriority::Low);
413     }
414     clickRecognizer_->SetCoordinateOffset(coordinateOffset);
415     result.emplace_back(clickRecognizer_);
416 
417     if (!doubleClickRecognizer_) {
418         doubleClickRecognizer_ =
419             AceType::MakeRefPtr<ClickRecognizer>(context_, DOUBLE_CLICK_FINGERS, DOUBLE_CLICK_COUNTS);
420         doubleClickRecognizer_->SetUseCatchMode(catchMode_);
421         auto weak = WeakClaim(this);
422         doubleClickRecognizer_->SetOnClick([weak](const ClickInfo& info) {
423             auto client = weak.Upgrade();
424             if (client) {
425                 client->OnDoubleClick(info);
426             }
427         });
428         doubleClickRecognizer_->SetPriority(GesturePriority::High);
429     }
430     doubleClickRecognizer_->SetCoordinateOffset(coordinateOffset);
431     result.emplace_back(doubleClickRecognizer_);
432 
433     if (!longPressRecognizer_) {
434         longPressRecognizer_ = AceType::MakeRefPtr<LongPressRecognizer>(context_);
435         auto weak = WeakClaim(this);
436         longPressRecognizer_->SetOnLongPress([weak = WeakClaim(this)](const LongPressInfo& info) {
437             auto client = weak.Upgrade();
438             if (client) {
439                 client->OnLongPress(info);
440             }
441         });
442         longPressRecognizer_->SetPriority(GesturePriority::High);
443     }
444     longPressRecognizer_->SetCoordinateOffset(coordinateOffset);
445     longPressRecognizer_->SetTouchRestrict(touchRestrict);
446     result.emplace_back(longPressRecognizer_);
447 
448     if (!rawRecognizer_) {
449         rawRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
450         auto weak = WeakClaim(this);
451         rawRecognizer_->SetOnTouchDown([weak = WeakClaim(this)](const TouchEventInfo& info) {
452             auto textField = weak.Upgrade();
453             if (textField) {
454                 textField->StartPressAnimation(true);
455             }
456         });
457 
458         rawRecognizer_->SetOnTouchUp([weak = WeakClaim(this)](const TouchEventInfo& info) {
459             auto textField = weak.Upgrade();
460             if (textField) {
461                 textField->StartPressAnimation(false);
462             }
463         });
464 
465         rawRecognizer_->SetOnTouchCancel([weak = WeakClaim(this)](const TouchEventInfo& info) {
466             auto textField = weak.Upgrade();
467             if (textField) {
468                 textField->StartPressAnimation(false);
469             }
470         });
471     }
472     rawRecognizer_->SetTouchRestrict(touchRestrict);
473     rawRecognizer_->SetCoordinateOffset(coordinateOffset);
474     result.emplace_back(rawRecognizer_);
475 }
476 
StartPressAnimation(bool pressDown)477 void RenderTextField::StartPressAnimation(bool pressDown)
478 {
479     if (!pressController_) {
480         pressController_ = AceType::MakeRefPtr<Animator>(context_);
481     }
482     if (pressController_->IsRunning()) {
483         pressController_->Stop();
484     }
485     pressController_->ClearInterpolators();
486     RefPtr<KeyframeAnimation<Color>> animation = AceType::MakeRefPtr<KeyframeAnimation<Color>>();
487     if (pressDown) {
488         CreateMouseAnimation(animation, GetEventEffectColor(), pressColor_);
489     } else {
490         CreateMouseAnimation(animation, GetEventEffectColor(), Color::TRANSPARENT);
491     }
492     pressController_->AddInterpolator(animation);
493     pressController_->SetDuration(PRESS_DURATION);
494     pressController_->SetFillMode(FillMode::FORWARDS);
495     pressController_->Forward();
496 }
497 
OnClick(const ClickInfo & clickInfo)498 void RenderTextField::OnClick(const ClickInfo& clickInfo)
499 {
500     // Handle click on password icon when password icon is valid, switch between show and hide icon.
501     Point clickPoint = Point(clickInfo.GetLocalLocation().GetX(), clickInfo.GetLocalLocation().GetY());
502     if (showPasswordIcon_ && passwordIconRect_.IsInRegion(clickPoint)) {
503         obscure_ = !obscure_;
504         passwordRecord_ = obscure_;
505         PopTextOverlay();
506         MarkNeedLayout();
507         return;
508     }
509 
510     isValueFromRemote_ = false;
511     auto globalPosition = clickInfo.GetGlobalLocation();
512     auto globalOffset = GetGlobalOffset();
513 
514     if (SearchAction(globalPosition, globalOffset)) {
515         return;
516     }
517     if (tapCallback_) {
518         if (!tapCallback_()) {
519             return;
520         }
521     }
522     if (onTapEvent_) {
523         onTapEvent_();
524     }
525     if (onClick_) {
526         onClick_(clickInfo);
527     }
528     CursorMoveOnClick(globalPosition);
529     ShowError("", false);
530     UpdateStartSelection(DEFAULT_SELECT_INDEX, globalPosition, true, false);
531     if (clickInfo.GetSourceDevice() == SourceType::MOUSE) {
532         StartTwinkling();
533     } else {
534         StartTwinkling();
535         ShowTextOverlay(globalPosition, true);
536     }
537     auto context = GetContext().Upgrade();
538     if (context) {
539         context->SetClickPosition(GetGlobalOffset() + Size(0, GetLayoutSize().Height()));
540     }
541 }
542 
SearchAction(const Offset & globalPosition,const Offset & globalOffset)543 bool RenderTextField::SearchAction(const Offset& globalPosition, const Offset& globalOffset)
544 {
545     double widthReserved = NormalizeToPx(widthReserved_);
546     if (widthReserved > 0) {
547         if (textDirection_ == TextDirection::RTL) {
548             if ((globalPosition.GetX() - globalOffset.GetX()) < widthReserved) {
549                 controller_->SetText("");
550                 return true;
551             } else if ((globalPosition.GetX() - globalOffset.GetX()) > (GetLayoutSize().Width() - iconHotZoneSize_) &&
552                        iconImage_ && action_ == TextInputAction::SEARCH) {
553                 PerformAction(action_, true);
554                 return true;
555             }
556         } else {
557             if ((globalPosition.GetX() - globalOffset.GetX()) >= (GetLayoutSize().Width() - widthReserved)) {
558                 controller_->SetText("");
559                 return true;
560             } else if ((globalPosition.GetX() - globalOffset.GetX()) < iconHotZoneSize_ && iconImage_ &&
561                        action_ == TextInputAction::SEARCH) {
562                 PerformAction(action_, true);
563                 return true;
564             }
565         }
566     }
567     return false;
568 }
569 
OnDoubleClick(const ClickInfo & clickInfo)570 void RenderTextField::OnDoubleClick(const ClickInfo& clickInfo)
571 {
572     auto clickPosition = GetCursorPositionForClick(clickInfo.GetGlobalLocation());
573     auto selection = TextUtils::GetRangeOfSameType(GetEditingValue().text, clickPosition - 1);
574     UpdateSelection(selection.GetStart(), selection.GetEnd());
575     LOGI("text field accept double click, position: %{public}d, selection: %{public}s", clickPosition,
576         selection.ToString().c_str());
577     MarkNeedRender();
578 }
579 
OnLongPress(const LongPressInfo & longPressInfo)580 void RenderTextField::OnLongPress(const LongPressInfo& longPressInfo)
581 {
582     if (tapCallback_ && !isOverlayShowed_) {
583         if (!tapCallback_()) {
584             return;
585         }
586     }
587 
588     if (onLongPressEvent_) {
589         onLongPressEvent_();
590     }
591 
592     ShowError("", false);
593 
594     if (longPressInfo.GetSourceDevice() == SourceType::MOUSE) {
595         return;
596     }
597 
598     Offset longPressPosition = longPressInfo.GetGlobalLocation();
599     bool isTextEnd =
600         (static_cast<size_t>(GetCursorPositionForClick(longPressPosition)) == GetEditingValue().GetWideText().length());
601     bool singleHandle = isTextEnd || GetEditingValue().text.empty();
602     bool isPassword = (keyboard_ == TextInputType::VISIBLE_PASSWORD);
603     UpdateStartSelection(DEFAULT_SELECT_INDEX, longPressPosition, singleHandle || isPassword, true);
604     ShowTextOverlay(longPressPosition, false);
605 }
606 
ShowTextOverlay(const Offset & showOffset,bool isSingleHandle)607 void RenderTextField::ShowTextOverlay(const Offset& showOffset, bool isSingleHandle)
608 {
609     if (!isVisible_) {
610         return;
611     }
612 
613     if (!IsSelectiveDevice()) {
614         StartTwinkling();
615         return;
616     }
617 
618     isSingleHandle_ = isSingleHandle;
619 
620     auto selStart = GetEditingValue().selection.GetStart();
621     auto selEnd = GetEditingValue().selection.GetEnd();
622 
623     Offset startHandleOffset = GetHandleOffset(selStart);
624     Offset endHandleOffset = isSingleHandle ? startHandleOffset : GetHandleOffset(selEnd);
625 
626     if (isOverlayShowed_ && updateHandlePosition_) {
627         Rect caretStart;
628         bool visible = GetCaretRect(selStart, caretStart) ? IsVisible(caretStart + textOffsetForShowCaret_) : false;
629         OverlayShowOption option { .showMenu = isOverlayShowed_,
630             .showStartHandle = visible,
631             .showEndHandle = visible,
632             .isSingleHandle = isSingleHandle,
633             .updateOverlayType = isSingleHandle ? UpdateOverlayType::CLICK : UpdateOverlayType::LONG_PRESS,
634             .startHandleOffset = startHandleOffset,
635             .endHandleOffset = endHandleOffset };
636         if (!isSingleHandle_ || startHandleOffset != endHandleOffset) {
637             isOverlayFocus_ = true;
638         }
639         updateHandlePosition_(option);
640 
641         // When the textOverlay is showed, restart the animation
642         if (!animator_) {
643             LOGE("Show textOverlay error, animator is nullptr");
644             return;
645         }
646         if (!animator_->IsStopped()) {
647             animator_->Stop();
648         }
649         animator_->Play();
650         return;
651     }
652 
653     // Pop text overlay before push.
654     PopTextOverlay();
655 
656     textOverlay_ =
657         AceType::MakeRefPtr<TextOverlayComponent>(GetThemeManager(), context_.Upgrade()->GetAccessibilityManager());
658     textOverlay_->SetWeakTextField(WeakClaim(this));
659     textOverlay_->SetIsSingleHandle(isSingleHandle || (keyboard_ == TextInputType::VISIBLE_PASSWORD));
660     textOverlay_->SetLineHeight(selectHeight_);
661     textOverlay_->SetClipRect(
662         innerRect_ + Size(HANDLE_HOT_ZONE, HANDLE_HOT_ZONE) + GetOffsetToPage() - Offset(HANDLE_HOT_ZONE / 2.0, 0.0));
663     textOverlay_->SetTextDirection(textDirection_);
664     textOverlay_->SetRealTextDirection(existStrongDirectionLetter_ ? realTextDirection_ : TextDirection::LTR);
665     textOverlay_->SetIsPassword(keyboard_ == TextInputType::VISIBLE_PASSWORD);
666     textOverlay_->SetStartHandleOffset(startHandleOffset);
667     textOverlay_->SetEndHandleOffset(endHandleOffset);
668     textOverlay_->SetImageFill(imageFill_);
669     textOverlay_->SetOptions(inputOptions_);
670     textOverlay_->SetOptionsClickMarker(onOptionsClick_);
671     textOverlay_->SetTranslateButtonMarker(onTranslate_);
672     textOverlay_->SetShareButtonMarker(onShare_);
673     textOverlay_->SetSearchButtonMarker(onSearch_);
674     textOverlay_->SetContext(context_);
675     // Add the Animation
676     InitAnimation();
677 
678     if (!isSingleHandle_ || startHandleOffset != endHandleOffset) {
679         isOverlayFocus_ = true;
680     }
681     RegisterCallbacksToOverlay();
682 }
683 
InitAnimation()684 void RenderTextField::InitAnimation()
685 {
686     if (!textOverlay_) {
687         LOGE("InitAnimation error, textOverlay is nullptr");
688         return;
689     }
690 
691     // Get the handleDiameter in theme, textoverlay is not nullptr
692     double initHandleDiameter = textOverlay_->GetHandleDiameter().Value();
693     double initHandleDiameterInner = textOverlay_->GetHandleDiameterInner().Value();
694 
695     // Add the animation for handleDiameter
696     auto diameterAnimation = AceType::MakeRefPtr<CurveAnimation<double>>(
697         initHandleDiameter * FIFTY_PERCENT, initHandleDiameter, Curves::ELASTICS);
698     diameterAnimation->AddListener([text = AceType::WeakClaim(this)](double value) {
699         auto textField = text.Upgrade();
700         if (textField && textField->updateHandleDiameter_) {
701             textField->updateHandleDiameter_(value);
702         }
703     });
704 
705     // Add the animation for handleDiameterinner
706     auto diameterInnerAnimation = AceType::MakeRefPtr<CurveAnimation<double>>(
707         initHandleDiameterInner * FIFTY_PERCENT, initHandleDiameterInner, Curves::ELASTICS);
708     diameterInnerAnimation->AddListener([text = AceType::WeakClaim(this)](double value) {
709         auto textField = text.Upgrade();
710         if (textField && textField->updateHandleDiameterInner_) {
711             textField->updateHandleDiameterInner_(value);
712         }
713     });
714 
715     // Add the animation
716     LOGD("Add animation to animator");
717     animator_ = AceType::MakeRefPtr<Animator>(context_);
718     animator_->AddInterpolator(diameterAnimation);
719     animator_->AddInterpolator(diameterInnerAnimation);
720     animator_->SetDuration(SHOW_HANDLE_DURATION);
721     animator_->Play();
722 }
723 
RegisterCallbacksToOverlay()724 void RenderTextField::RegisterCallbacksToOverlay()
725 {
726     if (!textOverlay_) {
727         return;
728     }
729     textOverlay_->SetOnCut([weak = AceType::WeakClaim(this)] {
730         auto textfield = weak.Upgrade();
731         if (textfield) {
732             textfield->HandleOnCut();
733         }
734     });
735 
736     textOverlay_->SetOnCopy([weak = AceType::WeakClaim(this)] {
737         auto textfield = weak.Upgrade();
738         if (textfield) {
739             textfield->HandleOnCopy();
740         }
741     });
742 
743     textOverlay_->SetOnCopyAll(
744         [weak = AceType::WeakClaim(this)](const std::function<void(const Offset&, const Offset&)>& callback) {
745             auto textfield = weak.Upgrade();
746             if (textfield) {
747                 textfield->HandleOnCopyAll(callback);
748             }
749         });
750 
751     textOverlay_->SetOnStartHandleMove(
752         [weak = AceType::WeakClaim(this)](int32_t end, const Offset& startHandleOffset,
753             const std::function<void(const Offset&)>& startCallback, bool isSingleHandle) {
754             auto textfield = weak.Upgrade();
755             if (textfield) {
756                 textfield->HandleOnStartHandleMove(end, startHandleOffset, startCallback, isSingleHandle);
757             }
758         });
759 
760     textOverlay_->SetOnEndHandleMove([weak = AceType::WeakClaim(this)](int32_t start, const Offset& endHandleOffset,
761                                          const std::function<void(const Offset&)>& endCallback) {
762         auto textfield = weak.Upgrade();
763         if (textfield) {
764             textfield->HandleOnEndHandleMove(start, endHandleOffset, endCallback);
765         }
766     });
767 
768     auto callback = [weakTextField = WeakClaim(this)](const std::string& data) {
769         auto textfield = weakTextField.Upgrade();
770         if (textfield) {
771             auto textOverlay = textfield->textOverlay_;
772             if (textOverlay && !data.empty()) {
773                 textOverlay->SetOnPaste([weakTextField] {
774                     auto textfield = weakTextField.Upgrade();
775                     if (textfield) {
776                         textfield->HandleOnPaste();
777                     }
778                 });
779             }
780             textfield->PushTextOverlayToStack();
781             textfield->UpdateOverlay();
782         }
783     };
784     if (clipboard_) {
785         clipboard_->GetData(callback);
786     }
787 
788     auto onFocusChange = [weak = WeakClaim(this)](bool isFocus, bool needCloseKeyboard) {
789         auto textField = weak.Upgrade();
790         if (textField) {
791             textField->OnOverlayFocusChange(isFocus, needCloseKeyboard);
792         }
793     };
794     textOverlay_->SetOnFocusChange(onFocusChange);
795 }
796 
PushTextOverlayToStack()797 void RenderTextField::PushTextOverlayToStack()
798 {
799     if (!textOverlay_) {
800         LOGE("TextOverlay is null");
801         return;
802     }
803     hasTextOverlayPushed_ = true;
804     auto lastStack = GetLastStack();
805     if (!lastStack) {
806         LOGE("LastStack is null");
807         return;
808     }
809     isOverlayShowed_ = true;
810     lastStack->PushComponent(textOverlay_, false);
811     stackElement_ = WeakClaim(RawPtr(lastStack));
812     MarkNeedRender();
813 }
814 
RequestKeyboard(bool isFocusViewChanged,bool needStartTwinkling)815 bool RenderTextField::RequestKeyboard(bool isFocusViewChanged, bool needStartTwinkling)
816 {
817     if (!enabled_) {
818         LOGD("TextField is not enabled.");
819         return false;
820     }
821 
822     instanceId_ = ContainerScope::CurrentId();
823 
824     if (softKeyboardEnabled_) {
825         LOGI("RenderTextField::CloseKeyboard: Request open soft keyboard");
826 #if defined(ENABLE_STANDARD_INPUT)
827         if (textChangeListener_ == nullptr) {
828             textChangeListener_ = new OnTextChangedListenerImpl(WeakClaim(this));
829         }
830         auto context = context_.Upgrade();
831         if (context) {
832             LOGI("RequestKeyboard set calling window id is : %{public}d", context->GetWindowId());
833             MiscServices::InputMethodController::GetInstance()->SetCallingWindow(context->GetWindowId());
834         }
835         MiscServices::InputMethodController::GetInstance()->Attach(textChangeListener_);
836 #else
837         if (!HasConnection()) {
838             AttachIme();
839             if (!HasConnection()) {
840                 LOGE("Get TextInput connection error");
841                 return false;
842             }
843             connection_->SetEditingState(GetEditingValue(), GetInstanceId());
844         }
845         connection_->Show(isFocusViewChanged, GetInstanceId());
846 #endif
847     }
848 
849     if (keyboard_ != TextInputType::MULTILINE) {
850         resetToStart_ = false;
851         MarkNeedLayout();
852     }
853     if (needStartTwinkling) {
854         StartTwinkling();
855     }
856     if (onEditChanged_) {
857         onEditChanged_(softKeyboardEnabled_);
858     }
859     return true;
860 }
861 
CloseKeyboard(bool forceClose)862 bool RenderTextField::CloseKeyboard(bool forceClose)
863 {
864     if (!isOverlayShowed_ || !isOverlayFocus_ || forceClose) {
865         if (!textFieldController_) {
866             StopTwinkling();
867         }
868         if (HasConnection()) {
869             LOGI("RenderTextField::CloseKeyboard: Request close soft keyboard");
870 #if defined(ENABLE_STANDARD_INPUT)
871             MiscServices::InputMethodController::GetInstance()->HideTextInput();
872 #else
873             connection_->Close(GetInstanceId());
874             connection_ = nullptr;
875 #endif
876         }
877 
878         if (onKeyboardClose_) {
879             onKeyboardClose_(forceClose);
880             onKeyboardClose_ = nullptr;
881             UpdateSelection(GetEditingValue().selection.GetEnd());
882             MarkNeedLayout();
883         }
884 
885         if (keyboard_ != TextInputType::MULTILINE) {
886             resetToStart_ = true;
887             MarkNeedLayout();
888         }
889         if (onEditChanged_) {
890             onEditChanged_(forceClose);
891         }
892         return true;
893     }
894     return false;
895 }
896 
AttachIme()897 void RenderTextField::AttachIme()
898 {
899     auto context = context_.Upgrade();
900     if (!context) {
901         LOGW("No context exists, failed to request keyboard.");
902         return;
903     }
904 
905     TextInputConfiguration config;
906     config.type = keyboard_;
907     config.action = action_;
908     config.actionLabel = actionLabel_;
909     config.obscureText = obscure_;
910     LOGD("Request keyboard configuration: type=%{private}d action=%{private}d actionLabel=%{private}s "
911          "obscureText=%{private}d",
912         keyboard_, action_, actionLabel_.c_str(), obscure_);
913     connection_ =
914         TextInputProxy::GetInstance().Attach(WeakClaim(this), config, context->GetTaskExecutor(), GetInstanceId());
915 }
916 
StartTwinkling()917 void RenderTextField::StartTwinkling()
918 {
919     // Ignore the result because all ops are called on this same thread (ACE UI).
920     // The only reason failed is that the task has finished.
921     cursorTwinklingTask_.Cancel();
922 
923     // Show cursor right now.
924     cursorVisibility_ = true;
925     // Does not matter call more than one times.
926     MarkNeedRender();
927 
928     ScheduleCursorTwinkling();
929 }
930 
StopTwinkling()931 void RenderTextField::StopTwinkling()
932 {
933     obscureTickPendings_ = 0;
934     cursorTwinklingTask_.Cancel();
935 
936     if (cursorVisibility_) {
937         // Repaint only if cursor is visible for now.
938         cursorVisibility_ = false;
939         MarkNeedRender();
940     }
941 }
942 
GetEditingValue() const943 const TextEditingValue& RenderTextField::GetEditingValue() const
944 {
945     return controller_->GetValue();
946 }
947 
GetPreEditingValue() const948 const TextEditingValue& RenderTextField::GetPreEditingValue() const
949 {
950     return controller_->GetPreValue();
951 }
952 
SetEditingValue(TextEditingValue && newValue,bool needFireChangeEvent)953 void RenderTextField::SetEditingValue(TextEditingValue&& newValue, bool needFireChangeEvent)
954 {
955     if (newValue.text != GetEditingValue().text && needFireChangeEvent) {
956         needNotifyChangeEvent_ = true;
957     }
958     ChangeCounterStyle(newValue);
959     auto context = context_.Upgrade();
960     if (context && context->GetIsDeclarative()) {
961         if (GetEditingValue().text.empty()) {
962             Dimension fontSize_ = placeHoldStyle_.GetFontSize();
963             if (fontSize_.Value() <= 0) {
964                 Dimension fontSize_ { 14, DimensionUnit::FP };
965                 placeHoldStyle_.SetFontSize(fontSize_);
966             }
967             SetTextStyle(placeHoldStyle_);
968         }
969     }
970 
971     if (context && context->GetIsDeclarative()) {
972         if (inputFilter_.empty() || newValue.text.empty()) {
973             controller_->SetValue(newValue, needFireChangeEvent);
974         } else {
975             std::regex rw(inputFilter_);
976             if (regex_match(newValue.text.c_str(), rw)) {
977                 inputCallBackStrSize_ = static_cast<int32_t>(newValue.text.length());
978                 controller_->SetValue(newValue, needFireChangeEvent);
979             } else {
980                 inputCallBackStr_ = newValue.text.substr(inputCallBackStrSize_);
981                 if (onError_) {
982                     onError_(inputCallBackStr_);
983                 }
984             }
985         }
986     } else {
987         controller_->SetValue(newValue, needFireChangeEvent);
988     }
989     UpdateAccessibilityAttr();
990 }
991 
ClearEditingValue()992 void RenderTextField::ClearEditingValue()
993 {
994     TextEditingValue emptyValue;
995     SetEditingValue(std::move(emptyValue));
996 }
997 
GetTextForDisplay(const std::string & text) const998 std::u16string RenderTextField::GetTextForDisplay(const std::string& text) const
999 {
1000     std::u16string txtContent = StringUtils::Str8ToStr16(text);
1001     auto len = txtContent.length();
1002     if (!obscure_ || len == 0 || (obscureTickPendings_ > 0 && len == 1)) {
1003         return txtContent;
1004     }
1005 
1006     std::u16string obscured;
1007     if (Localization::GetInstance()->GetLanguage() == "ar") { // ar is the abbreviation of Arabic.
1008         obscured = std::u16string(len, OBSCURING_CHARACTER_FOR_AR);
1009     } else {
1010         obscured = std::u16string(len, OBSCURING_CHARACTER);
1011     }
1012     int32_t posBeforeCursor = GetEditingValue().selection.extentOffset - 1;
1013     if (obscureTickPendings_ > 0 && posBeforeCursor >= 0 && static_cast<size_t>(posBeforeCursor) < obscured.length()) {
1014         // Let the last commit character naked.
1015         obscured[posBeforeCursor] = txtContent[posBeforeCursor];
1016     }
1017 
1018     return obscured;
1019 }
1020 
UpdateObscure(const RefPtr<TextFieldComponent> & textField)1021 void RenderTextField::UpdateObscure(const RefPtr<TextFieldComponent>& textField)
1022 {
1023     auto context = context_.Upgrade();
1024     if (context && context->GetIsDeclarative()) {
1025         if (!passwordRecord_) {
1026             if (keyboard_ != textField->GetTextInputType()) {
1027                 passwordRecord_ = true;
1028                 obscure_ = textField->NeedObscure();
1029             } else {
1030                 obscure_ = !textField->NeedObscure();
1031             }
1032         } else {
1033             obscure_ = textField->NeedObscure();
1034         }
1035     } else {
1036         obscure_ = textField->NeedObscure();
1037     }
1038 }
1039 
UpdateFormatters()1040 void RenderTextField::UpdateFormatters()
1041 {
1042     textInputFormatters_.clear();
1043 
1044     if (maxLength_ < std::numeric_limits<uint32_t>::max()) {
1045         textInputFormatters_.emplace_back(std::make_unique<LengthLimitingFormatter>(maxLength_));
1046     }
1047 
1048     if (maxLines_ == 1) {
1049         textInputFormatters_.emplace_back(std::make_unique<SingleLineFormatter>());
1050     }
1051 
1052     switch (keyboard_) {
1053         case TextInputType::NUMBER: {
1054             textInputFormatters_.emplace_back(std::make_unique<NumberFormatter>());
1055             break;
1056         }
1057         case TextInputType::PHONE: {
1058             textInputFormatters_.emplace_back(std::make_unique<PhoneNumberFormatter>());
1059             break;
1060         }
1061         case TextInputType::EMAIL_ADDRESS: {
1062             textInputFormatters_.emplace_back(std::make_unique<EmailFormatter>());
1063             break;
1064         }
1065         case TextInputType::URL: {
1066             textInputFormatters_.emplace_back(std::make_unique<UriFormatter>());
1067             break;
1068         }
1069         default: {
1070             // No need limit.
1071         }
1072     }
1073 
1074     TextEditingValue temp = GetEditingValue();
1075     for (const auto& formatter : textInputFormatters_) {
1076         if (formatter) {
1077             formatter->Format(GetEditingValue(), temp);
1078         }
1079     }
1080     SetEditingValue(std::move(temp));
1081 }
1082 
UpdateEditingValue(const std::shared_ptr<TextEditingValue> & value,bool needFireChangeEvent)1083 void RenderTextField::UpdateEditingValue(const std::shared_ptr<TextEditingValue>& value, bool needFireChangeEvent)
1084 {
1085     if (!value) {
1086         LOGE("the value is nullptr");
1087         return;
1088     }
1089 
1090     lastKnownRemoteEditingValue_ = value;
1091     lastKnownRemoteEditingValue_->hint = placeholder_;
1092     TextEditingValue temp = *lastKnownRemoteEditingValue_;
1093     if (cursorPositionType_ != CursorPositionType::END ||
1094         (temp.selection.baseOffset == temp.selection.extentOffset &&
1095             temp.selection.baseOffset != static_cast<int32_t>(temp.GetWideText().length()))) {
1096         cursorPositionType_ = CursorPositionType::NORMAL;
1097         isValueFromRemote_ = true;
1098     }
1099     ChangeCounterStyle(temp);
1100     for (const auto& formatter : textInputFormatters_) {
1101         // GetEditingValue() is the old value, and lastKnownRemoteEditingValue_ is the newer.
1102         if (formatter) {
1103             formatter->Format(GetEditingValue(), temp);
1104         }
1105     }
1106 
1107     if (obscure_ && (temp.text.length() == GetEditingValue().text.length() + 1)) {
1108         // Reset pending.
1109         obscureTickPendings_ = OBSCURE_SHOW_TICKS;
1110     }
1111 
1112     if (temp.text != GetEditingValue().text && needFireChangeEvent) {
1113         needNotifyChangeEvent_ = true;
1114     }
1115 
1116     auto editingText = GetEditingValue().text;
1117     SetEditingValue(std::move(temp), needFireChangeEvent);
1118     UpdateRemoteEditingIfNeeded(needFireChangeEvent);
1119 
1120     MarkNeedLayout();
1121 
1122     // If input or delete text when overlay is showing, pop overlay from stack.
1123     if (lastKnownRemoteEditingValue_ && (lastKnownRemoteEditingValue_->text != editingText)) {
1124         if (onValueChange_) {
1125             onValueChange_();
1126         }
1127     }
1128 }
1129 
PerformDefaultAction()1130 void RenderTextField::PerformDefaultAction()
1131 {
1132     PerformAction(action_);
1133 }
1134 
PerformAction(TextInputAction action,bool forceCloseKeyboard)1135 void RenderTextField::PerformAction(TextInputAction action, bool forceCloseKeyboard)
1136 {
1137     LOGD("PerformAction  %{public}d", static_cast<int32_t>(action));
1138     if (action == TextInputAction::NEXT && moveNextFocusEvent_) {
1139         moveNextFocusEvent_();
1140     } else {
1141         CloseKeyboard(forceCloseKeyboard);
1142     }
1143     if (onFinishInputEvent_) {
1144         auto jsonResult = JsonUtil::Create(true);
1145         jsonResult->Put("value", static_cast<int32_t>(action));
1146         onFinishInputEvent_(std::string(R"("enterkeyclick",)").append(jsonResult->ToString()));
1147     }
1148     if (onSubmitEvent_ && controller_) {
1149         onSubmitEvent_(controller_->GetValue().text);
1150     }
1151     if (onSubmit_) {
1152         onSubmit_(static_cast<int32_t>(action_));
1153     }
1154 }
1155 
Measure()1156 Size RenderTextField::Measure()
1157 {
1158     return Size();
1159 }
1160 
ScheduleCursorTwinkling()1161 void RenderTextField::ScheduleCursorTwinkling()
1162 {
1163     auto context = context_.Upgrade();
1164     if (!context) {
1165         LOGW("No context exists.");
1166         return;
1167     }
1168 
1169     if (!context->GetTaskExecutor()) {
1170         LOGW("context has no task executor.");
1171         return;
1172     }
1173 
1174     auto weak = WeakClaim(this);
1175     cursorTwinklingTask_.Reset([weak] {
1176         auto client = weak.Upgrade();
1177         if (client) {
1178             client->OnCursorTwinkling();
1179         }
1180     });
1181     auto taskExecutor = context->GetTaskExecutor();
1182     if (taskExecutor) {
1183         taskExecutor->PostDelayedTask(cursorTwinklingTask_, TaskExecutor::TaskType::UI, twinklingInterval);
1184     } else {
1185         LOGE("the task executor is nullptr");
1186     }
1187 }
1188 
OnCursorTwinkling()1189 void RenderTextField::OnCursorTwinkling()
1190 {
1191     // When glyph changes from visible to invisible, layout is needed.
1192     obscureTickPendings_ == 1 ? MarkNeedLayout() : MarkNeedRender();
1193     if (obscureTickPendings_ > 0) {
1194         --obscureTickPendings_;
1195     }
1196     cursorVisibility_ = !cursorVisibility_;
1197     ScheduleCursorTwinkling();
1198 }
1199 
OnKeyEvent(const KeyEvent & event)1200 bool RenderTextField::OnKeyEvent(const KeyEvent& event)
1201 {
1202     if (!enabled_) {
1203         return false;
1204     }
1205 
1206     // If back or escape is clicked and overlay is showing, pop overlay firstly.
1207     if (event.action == KeyAction::UP && (event.code == KeyCode::KEY_BACK || event.code == KeyCode::KEY_ESCAPE)) {
1208         if (isOverlayShowed_) {
1209             PopTextOverlay();
1210             return false;
1211         }
1212     }
1213     if (event.action == KeyAction::UP &&
1214         ((event.code == KeyCode::KEY_SHIFT_LEFT || event.code == KeyCode::KEY_SHIFT_RIGHT) ||
1215             (event.code == KeyCode::KEY_CTRL_LEFT || event.code == KeyCode::KEY_CTRL_RIGHT))) {
1216         return HandleKeyEvent(event);
1217     }
1218 
1219     if (event.action == KeyAction::DOWN) {
1220         cursorPositionType_ = CursorPositionType::NONE;
1221         bool moved = true;
1222         if (event.code == KeyCode::TV_CONTROL_LEFT) {
1223             CursorMoveLeft();
1224         } else if (event.code == KeyCode::TV_CONTROL_RIGHT) {
1225             CursorMoveRight();
1226         } else if (event.code == KeyCode::TV_CONTROL_UP) {
1227             CursorMoveUp();
1228         } else if (event.code == KeyCode::TV_CONTROL_DOWN) {
1229             CursorMoveDown();
1230         } else {
1231             moved = HandleKeyEvent(event);
1232         }
1233         if (moved) {
1234             // Obscure all glyphs immediately after cursor moved.
1235             obscureTickPendings_ = 0;
1236         }
1237         return moved;
1238     }
1239 
1240     return false;
1241 }
1242 
UpdateFocusStyles()1243 void RenderTextField::UpdateFocusStyles()
1244 {
1245     if (hasFocus_) {
1246         style_.SetTextColor(focusTextColor_);
1247         placeholderColor_ = focusPlaceholderColor_;
1248         if (decoration_) {
1249             decoration_->SetBackgroundColor(focusBgColor_);
1250         }
1251     } else {
1252         style_.SetTextColor(inactiveTextColor_);
1253         placeholderColor_ = inactivePlaceholderColor_;
1254         if (decoration_) {
1255             decoration_->SetBackgroundColor(inactiveBgColor_);
1256         }
1257     }
1258 }
1259 
UpdateFocusAnimation()1260 void RenderTextField::UpdateFocusAnimation()
1261 {
1262     if (hasFocus_) {
1263         auto context = context_.Upgrade();
1264         if (!context) {
1265             return;
1266         }
1267         Offset offset;
1268         Size size;
1269         Radius deflateRadius;
1270         if (IsSelectiveDevice()) {
1271             double focusOffset = NormalizeToPx(OFFSET_FOCUS);
1272             offset = Offset(focusOffset, focusOffset);
1273             size = Size(focusOffset * 2.0, focusOffset * 2.0);
1274             deflateRadius = Radius(DEFLATE_RADIUS_FOCUS, DEFLATE_RADIUS_FOCUS);
1275         }
1276         RRect rrect = RRect::MakeRect(
1277             Rect(GetPosition() + offset, GetLayoutSize() - ComputeDeflateSizeOfErrorAndCountText() - size));
1278         if (decoration_) {
1279             const auto& border = decoration_->GetBorder();
1280             rrect.SetCorner({ border.TopLeftRadius() - deflateRadius, border.TopRightRadius() - deflateRadius,
1281                 border.BottomRightRadius() - deflateRadius, border.BottomLeftRadius() - deflateRadius });
1282         }
1283         context->ShowFocusAnimation(rrect, focusBgColor_, GetGlobalOffset() + offset);
1284     }
1285 }
1286 
UpdateIcon(const RefPtr<TextFieldComponent> & textField)1287 void RenderTextField::UpdateIcon(const RefPtr<TextFieldComponent>& textField)
1288 {
1289     if (!textField) {
1290         return;
1291     }
1292     iconSizeInDimension_ = textField->GetIconSize();
1293     iconHotZoneSizeInDimension_ = textField->GetIconHotZoneSize();
1294     UpdatePasswordIcon(textField);
1295 
1296     double widthReserved = NormalizeToPx(widthReserved_);
1297     if (textField->GetIconImage() == iconSrc_ && textField->GetImageFill() == imageFill_ && widthReserved <= 0.0) {
1298         return;
1299     }
1300     imageFill_ = textField->GetImageFill();
1301     iconSrc_ = textField->GetIconImage();
1302     if (!iconSrc_.empty() || widthReserved > 0.0) {
1303         RefPtr<ImageComponent> imageComponent;
1304         if (iconSrc_.empty() && widthReserved > 0.0) {
1305             imageComponent = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::SEARCH_SVG);
1306         } else {
1307             imageComponent = AceType::MakeRefPtr<ImageComponent>(iconSrc_);
1308             imageComponent->SetImageFill(imageFill_);
1309         }
1310         imageComponent->SetWidth(textField->GetIconSize());
1311         imageComponent->SetHeight(textField->GetIconSize());
1312         if (textDirection_ == TextDirection::RTL) {
1313             imageComponent->SetMatchTextDirection(true);
1314             imageComponent->SetTextDirection(TextDirection::RTL);
1315         }
1316 
1317         iconImage_ = AceType::DynamicCast<RenderImage>(imageComponent->CreateRenderNode());
1318         if (!iconImage_) {
1319             return;
1320         }
1321         iconImage_->Attach(GetContext());
1322         iconImage_->SetDirectPaint(true);
1323         iconImage_->Update(imageComponent);
1324         AddChild(iconImage_);
1325     }
1326 }
1327 
UpdatePasswordIcon(const RefPtr<TextFieldComponent> & textField)1328 void RenderTextField::UpdatePasswordIcon(const RefPtr<TextFieldComponent>& textField)
1329 {
1330     if (!IsSelectiveDevice()) {
1331         return;
1332     }
1333     if (!showPasswordIcon_) {
1334         renderShowIcon_.Reset();
1335         renderHideIcon_.Reset();
1336         return;
1337     }
1338 
1339     showIconSrc_ = textField->GetShowIconImage();
1340     hideIconSrc_ = textField->GetHideIconImage();
1341 
1342     // update show icon.
1343     RefPtr<ImageComponent> showImage;
1344     if (showIconSrc_.empty()) {
1345         showImage = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::SHOW_PASSWORD_SVG);
1346     } else {
1347         showImage = AceType::MakeRefPtr<ImageComponent>(showIconSrc_);
1348     }
1349     showImage->SetWidth(textField->GetIconSize());
1350     showImage->SetHeight(textField->GetIconSize());
1351 
1352     renderShowIcon_ = AceType::DynamicCast<RenderImage>(showImage->CreateRenderNode());
1353     if (!renderShowIcon_) {
1354         return;
1355     }
1356     renderShowIcon_->Attach(GetContext());
1357     renderShowIcon_->SetDirectPaint(true);
1358     renderShowIcon_->Update(showImage);
1359     AddChild(renderShowIcon_);
1360 
1361     // update hide icon.
1362     RefPtr<ImageComponent> hideImage;
1363     if (hideIconSrc_.empty()) {
1364         hideImage = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::HIDE_PASSWORD_SVG);
1365     } else {
1366         hideImage = AceType::MakeRefPtr<ImageComponent>(hideIconSrc_);
1367     }
1368     hideImage->SetWidth(textField->GetIconSize());
1369     hideImage->SetHeight(textField->GetIconSize());
1370 
1371     renderHideIcon_ = AceType::DynamicCast<RenderImage>(hideImage->CreateRenderNode());
1372     if (!renderHideIcon_) {
1373         return;
1374     }
1375     renderHideIcon_->Attach(GetContext());
1376     renderHideIcon_->SetDirectPaint(true);
1377     renderHideIcon_->Update(hideImage);
1378     AddChild(renderHideIcon_);
1379 }
1380 
UpdateOverlay()1381 void RenderTextField::UpdateOverlay()
1382 {
1383     // When textfield PerformLayout, update overlay.
1384     if (isOverlayShowed_ && updateHandlePosition_) {
1385         auto selStart = GetEditingValue().selection.GetStart();
1386         auto selEnd = GetEditingValue().selection.GetEnd();
1387         Rect caretStart;
1388         Rect caretEnd;
1389         bool startHandleVisible =
1390             GetCaretRect(selStart, caretStart) ? IsVisible(caretStart + textOffsetForShowCaret_) : false;
1391         bool endHandleVisible =
1392             (selStart == selEnd)
1393                 ? startHandleVisible
1394                 : (GetCaretRect(selEnd, caretEnd) ? IsVisible(caretEnd + textOffsetForShowCaret_) : false);
1395 
1396         OverlayShowOption option { .showMenu = isOverlayShowed_,
1397             .showStartHandle = startHandleVisible,
1398             .showEndHandle = endHandleVisible,
1399             .isSingleHandle = isSingleHandle_,
1400             .updateOverlayType = UpdateOverlayType::SCROLL,
1401             .startHandleOffset = GetPositionForExtend(selStart, isSingleHandle_),
1402             .endHandleOffset = GetPositionForExtend(selEnd, isSingleHandle_) };
1403         updateHandlePosition_(option);
1404         if (onClipRectChanged_) {
1405             onClipRectChanged_(innerRect_ + Size(HANDLE_HOT_ZONE, HANDLE_HOT_ZONE) + GetOffsetToPage() -
1406                                Offset(HANDLE_HOT_ZONE / 2.0, 0.0));
1407         }
1408     }
1409 }
1410 
RegisterFontCallbacks()1411 void RenderTextField::RegisterFontCallbacks()
1412 {
1413     // Register callback for fonts.
1414     auto pipelineContext = context_.Upgrade();
1415     if (!pipelineContext) {
1416         return;
1417     }
1418     auto callback = [textfield = AceType::WeakClaim(this)] {
1419         auto refPtr = textfield.Upgrade();
1420         if (refPtr) {
1421             refPtr->isCallbackCalled_ = true;
1422             refPtr->MarkNeedLayout();
1423         }
1424     };
1425     auto fontManager = pipelineContext->GetFontManager();
1426     if (fontManager) {
1427         for (const auto& familyName : style_.GetFontFamilies()) {
1428             fontManager->RegisterCallback(AceType::WeakClaim(this), familyName, callback);
1429         }
1430         fontManager->AddVariationNode(WeakClaim(this));
1431     }
1432 }
1433 
OnStatusChanged(OHOS::Ace::RenderStatus renderStatus)1434 void RenderTextField::OnStatusChanged(OHOS::Ace::RenderStatus renderStatus)
1435 {
1436     hasFocus_ = renderStatus == RenderStatus::FOCUS;
1437     UpdateFocusStyles();
1438     MarkNeedLayout();
1439 
1440     if (!hasFocus_) {
1441         auto context = context_.Upgrade();
1442         if (!context) {
1443             return;
1444         }
1445         // Don't call cancel focus animation when next frame comes because then focus is switched, next node will
1446         // show focus immediately, we shouldn't cancel focus animation that time.
1447         context->CancelFocusAnimation();
1448     }
1449 }
1450 
OnValueChanged(bool needFireChangeEvent,bool needFireSelectChangeEvent)1451 void RenderTextField::OnValueChanged(bool needFireChangeEvent, bool needFireSelectChangeEvent)
1452 {
1453     isValueFromFront_ = !needFireChangeEvent;
1454     TextEditingValue temp = GetEditingValue();
1455     for (const auto& formatter : textInputFormatters_) {
1456         if (formatter) {
1457             formatter->Format(GetEditingValue(), temp);
1458         }
1459     }
1460     if (cursorPositionType_ == CursorPositionType::NORMAL && temp.selection.GetStart() == temp.selection.GetEnd()) {
1461         temp.selection.Update(AdjustCursorAndSelection(temp.selection.GetEnd()));
1462     }
1463     FireSelectChangeIfNeeded(temp, needFireSelectChangeEvent);
1464     SetEditingValue(std::move(temp), needFireChangeEvent);
1465     UpdateRemoteEditingIfNeeded(needFireChangeEvent);
1466     MarkNeedLayout();
1467 }
1468 
FireSelectChangeIfNeeded(const TextEditingValue & newValue,bool needFireSelectChangeEvent) const1469 void RenderTextField::FireSelectChangeIfNeeded(const TextEditingValue& newValue, bool needFireSelectChangeEvent) const
1470 {
1471     if (needFireSelectChangeEvent && onSelectChangeEvent_ && newValue.selection != GetPreEditingValue().selection) {
1472         auto jsonResult = JsonUtil::Create(true);
1473         jsonResult->Put("start", newValue.selection.GetStart());
1474         jsonResult->Put("end", newValue.selection.GetEnd());
1475         onSelectChangeEvent_(std::string(R"("selectchange",)").append(jsonResult->ToString()));
1476     }
1477 }
1478 
CursorMoveLeft(CursorMoveSkip skip)1479 void RenderTextField::CursorMoveLeft(CursorMoveSkip skip)
1480 {
1481     if (skip != CursorMoveSkip::CHARACTER) {
1482         // Not support yet.
1483         LOGE("move skip not support character yet");
1484         return;
1485     }
1486     if (GetEditingValue().selection.extentOffset > 0) {
1487         isValueFromRemote_ = false;
1488         auto value = GetEditingValue();
1489         value.MoveLeft();
1490         SetEditingValue(std::move(value));
1491     }
1492     cursorPositionType_ = CursorPositionType::NONE;
1493     MarkNeedLayout();
1494 }
1495 
CursorMoveRight(CursorMoveSkip skip)1496 void RenderTextField::CursorMoveRight(CursorMoveSkip skip)
1497 {
1498     if (skip != CursorMoveSkip::CHARACTER) {
1499         // Not support yet.
1500         LOGE("move skip not support character yet");
1501         return;
1502     }
1503 
1504     auto text = GetTextForDisplay(GetEditingValue().text);
1505     if (text.length() > static_cast<size_t>(GetEditingValue().selection.extentOffset)) {
1506         isValueFromRemote_ = false;
1507         auto value = GetEditingValue();
1508         value.MoveRight();
1509         SetEditingValue(std::move(value));
1510     }
1511     cursorPositionType_ = CursorPositionType::NONE;
1512     MarkNeedLayout();
1513 }
1514 
CursorMoveUp()1515 void RenderTextField::CursorMoveUp()
1516 {
1517     if (keyboard_ != TextInputType::MULTILINE) {
1518         return;
1519     }
1520     isValueFromRemote_ = false;
1521     auto value = GetEditingValue();
1522     value.MoveToPosition(GetCursorPositionForMoveUp());
1523     SetEditingValue(std::move(value));
1524     cursorPositionType_ = CursorPositionType::NONE;
1525     MarkNeedLayout();
1526 }
1527 
CursorMoveDown()1528 void RenderTextField::CursorMoveDown()
1529 {
1530     if (keyboard_ != TextInputType::MULTILINE) {
1531         return;
1532     }
1533     isValueFromRemote_ = false;
1534     auto value = GetEditingValue();
1535     value.MoveToPosition(GetCursorPositionForMoveDown());
1536     SetEditingValue(std::move(value));
1537     cursorPositionType_ = CursorPositionType::NONE;
1538     MarkNeedLayout();
1539 }
1540 
CursorMoveOnClick(const Offset & offset)1541 void RenderTextField::CursorMoveOnClick(const Offset& offset)
1542 {
1543     auto value = GetEditingValue();
1544     auto position = GetCursorPositionForClick(offset);
1545     value.MoveToPosition(position);
1546     SetEditingValue(std::move(value));
1547 
1548     if (!GetEditingValue().text.empty() && position == GetEditingValue().selection.GetEnd()) {
1549         OnValueChanged(true, false);
1550     }
1551 }
1552 
UpdateSelection(int32_t both)1553 void RenderTextField::UpdateSelection(int32_t both)
1554 {
1555     UpdateSelection(both, both);
1556 }
1557 
UpdateSelection(int32_t start,int32_t end)1558 void RenderTextField::UpdateSelection(int32_t start, int32_t end)
1559 {
1560     auto value = GetEditingValue();
1561     value.UpdateSelection(start, end);
1562     SetEditingValue(std::move(value));
1563     auto refPtr = accessibilityNode_.Upgrade();
1564     if (refPtr) {
1565         refPtr->SetTextSelectionStart(start);
1566         refPtr->SetTextSelectionEnd(end);
1567     }
1568 }
1569 
UpdateRemoteEditing(bool needFireChangeEvent)1570 void RenderTextField::UpdateRemoteEditing(bool needFireChangeEvent)
1571 {
1572 #if defined(ENABLE_STANDARD_INPUT)
1573     auto value = GetEditingValue();
1574     MiscServices::InputMethodController::GetInstance()->OnSelectionChange(
1575         StringUtils::Str8ToStr16(value.text), value.selection.GetStart(), value.selection.GetEnd());
1576 #else
1577     if (!HasConnection()) {
1578         return;
1579     }
1580     connection_->SetEditingState(GetEditingValue(), GetInstanceId(), needFireChangeEvent);
1581 #endif
1582 }
1583 
UpdateRemoteEditingIfNeeded(bool needFireChangeEvent)1584 void RenderTextField::UpdateRemoteEditingIfNeeded(bool needFireChangeEvent)
1585 {
1586     if (!enabled_) {
1587         return;
1588     }
1589 #if defined(ENABLE_STANDARD_INPUT)
1590     UpdateRemoteEditing(needFireChangeEvent);
1591 #else
1592     if (!lastKnownRemoteEditingValue_ || GetEditingValue() != *lastKnownRemoteEditingValue_) {
1593         lastKnownRemoteEditingValue_ = std::make_shared<TextEditingValue>(GetEditingValue());
1594         UpdateRemoteEditing(needFireChangeEvent);
1595     }
1596 #endif
1597 }
1598 
ShowError(const std::string & errorText,bool resetToStart)1599 void RenderTextField::ShowError(const std::string& errorText, bool resetToStart)
1600 {
1601     errorText_ = errorText;
1602     if (!errorText.empty()) {
1603         auto refPtr = accessibilityNode_.Upgrade();
1604         if (refPtr) {
1605             refPtr->SetErrorText(errorText);
1606         }
1607     }
1608 
1609     if (!errorText.empty()) {
1610         ChangeBorderToErrorStyle();
1611     } else {
1612         if (decoration_) {
1613             decoration_->SetBorder(originBorder_);
1614         }
1615     }
1616     MarkNeedLayout();
1617 }
1618 
SetOnValueChange(const std::function<void ()> & onValueChange)1619 void RenderTextField::SetOnValueChange(const std::function<void()>& onValueChange)
1620 {
1621     onValueChange_ = onValueChange;
1622 }
1623 
GetOnValueChange() const1624 const std::function<void()>& RenderTextField::GetOnValueChange() const
1625 {
1626     return onValueChange_;
1627 }
1628 
SetOnKeyboardClose(const std::function<void (bool)> & onKeyboardClose)1629 void RenderTextField::SetOnKeyboardClose(const std::function<void(bool)>& onKeyboardClose)
1630 {
1631     onKeyboardClose_ = onKeyboardClose;
1632 }
1633 
SetOnClipRectChanged(const std::function<void (const Rect &)> & onClipRectChanged)1634 void RenderTextField::SetOnClipRectChanged(const std::function<void(const Rect&)>& onClipRectChanged)
1635 {
1636     onClipRectChanged_ = onClipRectChanged;
1637 }
1638 
SetUpdateHandlePosition(const std::function<void (const OverlayShowOption &)> & updateHandlePosition)1639 void RenderTextField::SetUpdateHandlePosition(const std::function<void(const OverlayShowOption&)>& updateHandlePosition)
1640 {
1641     updateHandlePosition_ = updateHandlePosition;
1642 }
1643 
SetUpdateHandleDiameter(const std::function<void (const double &)> & updateHandleDiameter)1644 void RenderTextField::SetUpdateHandleDiameter(const std::function<void(const double&)>& updateHandleDiameter)
1645 {
1646     updateHandleDiameter_ = updateHandleDiameter;
1647 }
1648 
SetUpdateHandleDiameterInner(const std::function<void (const double &)> & updateHandleDiameterInner)1649 void RenderTextField::SetUpdateHandleDiameterInner(const std::function<void(const double&)>& updateHandleDiameterInner)
1650 {
1651     updateHandleDiameterInner_ = updateHandleDiameterInner;
1652 }
1653 
SetIsOverlayShowed(bool isOverlayShowed,bool needStartTwinkling)1654 void RenderTextField::SetIsOverlayShowed(bool isOverlayShowed, bool needStartTwinkling)
1655 {
1656     isOverlayShowed_ = isOverlayShowed;
1657     // When pop overlay, reset selection and clear selected style.
1658     if (GetEditingValue().selection.GetStart() != GetEditingValue().selection.GetEnd()) {
1659         UpdateSelection(GetEditingValue().selection.GetEnd());
1660     }
1661     if (!isOverlayShowed_ && hasFocus_ && needStartTwinkling) {
1662         StartTwinkling();
1663     }
1664 }
1665 
HandleOnCut()1666 void RenderTextField::HandleOnCut()
1667 {
1668     if (!clipboard_) {
1669         return;
1670     }
1671     clipboard_->SetData(GetEditingValue().GetSelectedText());
1672     if (onCut_) {
1673         onCut_(GetEditingValue().GetSelectedText());
1674     }
1675     auto value = GetEditingValue();
1676     value.text = value.GetBeforeSelection() + value.GetAfterSelection();
1677     value.UpdateSelection(GetEditingValue().selection.GetStart());
1678     SetEditingValue(std::move(value));
1679 }
1680 
HandleOnCopy()1681 void RenderTextField::HandleOnCopy()
1682 {
1683     if (!clipboard_) {
1684         return;
1685     }
1686     clipboard_->SetData(GetEditingValue().GetSelectedText());
1687     if (onCopy_) {
1688         onCopy_(GetEditingValue().GetSelectedText());
1689     }
1690     UpdateSelection(GetEditingValue().selection.GetEnd());
1691 }
1692 
HandleOnPaste()1693 void RenderTextField::HandleOnPaste()
1694 {
1695     if (!clipboard_) {
1696         return;
1697     }
1698     auto textSelection = GetEditingValue().selection;
1699     auto pasteCallback = [weak = WeakClaim(this), textSelection](const std::string& data) {
1700         auto textfield = weak.Upgrade();
1701         if (textfield) {
1702             auto value = textfield->GetEditingValue();
1703             value.selection = textSelection;
1704             value.text = value.GetBeforeSelection() + data + value.GetAfterSelection();
1705             value.UpdateSelection(textSelection.GetStart() + StringUtils::Str8ToStr16(data).length());
1706             textfield->SetEditingValue(std::move(value));
1707             if (textfield->onPaste_) {
1708                 textfield->onPaste_(data);
1709             }
1710         }
1711     };
1712     clipboard_->GetData(pasteCallback);
1713 }
1714 
HandleOnCopyAll(const std::function<void (const Offset &,const Offset &)> & callback)1715 void RenderTextField::HandleOnCopyAll(const std::function<void(const Offset&, const Offset&)>& callback)
1716 {
1717     isSingleHandle_ = false;
1718     cursorPositionType_ = CursorPositionType::NORMAL;
1719     auto textSize = GetEditingValue().GetWideText().length();
1720     if (textSize == 0) {
1721         isSingleHandle_ = true;
1722     }
1723     UpdateSelection(0, textSize);
1724     if (callback) {
1725         callback(GetPositionForExtend(0, isSingleHandle_),
1726             GetPositionForExtend(GetEditingValue().GetWideText().length(), isSingleHandle_));
1727     }
1728 }
1729 
HandleOnStartHandleMove(int32_t end,const Offset & startHandleOffset,const std::function<void (const Offset &)> & startCallback,bool isSingleHandle)1730 void RenderTextField::HandleOnStartHandleMove(int32_t end, const Offset& startHandleOffset,
1731     const std::function<void(const Offset&)>& startCallback, bool isSingleHandle)
1732 {
1733     Offset realOffset = startHandleOffset;
1734     if (startCallback) {
1735         UpdateStartSelection(end, realOffset, isSingleHandle, false);
1736         startCallback(GetHandleOffset(GetEditingValue().selection.GetStart()));
1737     }
1738 }
1739 
HandleOnEndHandleMove(int32_t start,const Offset & endHandleOffset,const std::function<void (const Offset &)> & endCallback)1740 void RenderTextField::HandleOnEndHandleMove(
1741     int32_t start, const Offset& endHandleOffset, const std::function<void(const Offset&)>& endCallback)
1742 {
1743     Offset realOffset = endHandleOffset;
1744     if (endCallback) {
1745         UpdateEndSelection(start, realOffset);
1746         endCallback(GetHandleOffset(GetEditingValue().selection.GetEnd()));
1747     }
1748 }
1749 
GetLastStack() const1750 RefPtr<StackElement> RenderTextField::GetLastStack() const
1751 {
1752     auto context = context_.Upgrade();
1753     if (!context) {
1754         LOGE("Context is nullptr");
1755         return nullptr;
1756     }
1757     return context->GetLastStack();
1758 }
1759 
HandleKeyEvent(const KeyEvent & event)1760 bool RenderTextField::HandleKeyEvent(const KeyEvent& event)
1761 {
1762     std::string appendElement;
1763     if (event.action == KeyAction::DOWN) {
1764         if (event.IsNumberKey()) {
1765             appendElement = event.ConvertCodeToString();
1766         } else if (event.IsLetterKey()) {
1767             if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_A }) ||
1768                 event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_A })) {
1769                 HandleOnCopyAll(nullptr);
1770             } else if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_C }) ||
1771                        event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_C })) {
1772                 HandleOnCopy();
1773             } else if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_V }) ||
1774                        event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_V })) {
1775                 HandleOnPaste();
1776             } else if (event.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_X }) ||
1777                        event.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_X })) {
1778                 HandleOnCut();
1779             } else {
1780                 appendElement = event.ConvertCodeToString();
1781             }
1782         }
1783         MarkNeedLayout();
1784     }
1785     if (appendElement.empty()) {
1786         return false;
1787     }
1788     auto value = GetEditingValue();
1789     value.text = value.GetBeforeSelection() + appendElement + value.GetAfterSelection();
1790     value.UpdateSelection(
1791         std::max(GetEditingValue().selection.GetEnd(), 0) + StringUtils::Str8ToStr16(appendElement).length());
1792     SetEditingValue(std::move(value));
1793     MarkNeedLayout();
1794     return true;
1795 }
1796 
UpdateAccessibilityAttr()1797 void RenderTextField::UpdateAccessibilityAttr()
1798 {
1799     auto refPtr = accessibilityNode_.Upgrade();
1800     if (!refPtr) {
1801         LOGW("RenderTextField accessibilityNode is null.");
1802         return;
1803     }
1804 
1805     refPtr->SetHintText(placeholder_);
1806     refPtr->SetMaxTextLength(maxLength_);
1807     refPtr->SetEditable(enabled_);
1808     refPtr->SetClickableState(true);
1809     refPtr->SetLongClickableState(true);
1810     if (maxLines_ > 1) {
1811         refPtr->SetIsMultiLine(true);
1812     }
1813     if (controller_) {
1814         refPtr->SetText(controller_->GetText());
1815     }
1816     switch (keyboard_) {
1817         case TextInputType::TEXT:
1818             refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_TEXT);
1819             break;
1820         case TextInputType::NUMBER:
1821             refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_NUMBER);
1822             break;
1823         case TextInputType::DATETIME:
1824             refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_DATE);
1825             break;
1826         case TextInputType::EMAIL_ADDRESS:
1827             refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_EMAIL);
1828             break;
1829         case TextInputType::VISIBLE_PASSWORD:
1830             refPtr->SetTextInputType(AceTextCategory::INPUT_TYPE_PASSWORD);
1831             break;
1832         default:
1833             break;
1834     }
1835 }
1836 
InitAccessibilityEventListener()1837 void RenderTextField::InitAccessibilityEventListener()
1838 {
1839     const auto& accessibilityNode = GetAccessibilityNode().Upgrade();
1840     if (!accessibilityNode) {
1841         return;
1842     }
1843     accessibilityNode->AddSupportAction(AceAction::ACTION_CLICK);
1844     accessibilityNode->SetActionClickImpl([weakPtr = WeakClaim(this)]() {
1845         const auto& textField = weakPtr.Upgrade();
1846         if (textField) {
1847             textField->OnClick(ClickInfo(0));
1848         }
1849     });
1850 
1851     accessibilityNode->AddSupportAction(AceAction::ACTION_LONG_CLICK);
1852     accessibilityNode->SetActionLongClickImpl([weakPtr = WeakClaim(this)]() {
1853         const auto& textField = weakPtr.Upgrade();
1854         if (textField) {
1855             textField->OnLongPress(LongPressInfo(0));
1856         }
1857     });
1858 }
1859 
UpdateDirectionStatus()1860 void RenderTextField::UpdateDirectionStatus()
1861 {
1862     directionStatus_ = static_cast<DirectionStatus>(
1863         (static_cast<uint8_t>(textDirection_) << 1) | static_cast<uint8_t>(realTextDirection_));
1864 }
1865 
UpdateStartSelection(int32_t end,const Offset & pos,bool isSingleHandle,bool isLongPress)1866 void RenderTextField::UpdateStartSelection(int32_t end, const Offset& pos, bool isSingleHandle, bool isLongPress)
1867 {
1868     int32_t extend = GetCursorPositionForClick(pos);
1869     int32_t extendEnd = GetEditingValue().selection.GetEnd();
1870     if (isLongPress) {
1871         // Use custom selection if exist, otherwise select content near finger.
1872         if (selection_.IsValid()) {
1873             UpdateSelection(selection_.baseOffset, selection_.extentOffset);
1874         } else {
1875             extendEnd = extend + GetGraphemeClusterLength(extend, false);
1876             UpdateSelection(extend, extendEnd);
1877         }
1878         return;
1879     }
1880     if (isSingleHandle) {
1881         UpdateSelection(extend);
1882     } else {
1883         UpdateSelection(extend, end);
1884     }
1885 }
1886 
UpdateEndSelection(int32_t start,const Offset & pos)1887 void RenderTextField::UpdateEndSelection(int32_t start, const Offset& pos)
1888 {
1889     int32_t extend = GetCursorPositionForClick(pos);
1890     UpdateSelection(start, extend);
1891 }
1892 
GetPositionForExtend(int32_t extend,bool isSingleHandle)1893 Offset RenderTextField::GetPositionForExtend(int32_t extend, bool isSingleHandle)
1894 {
1895     if (extend < 0) {
1896         extend = 0;
1897     }
1898     if (static_cast<size_t>(extend) > GetEditingValue().GetWideText().length()) {
1899         extend = static_cast<int32_t>(GetEditingValue().GetWideText().length());
1900     }
1901     return GetHandleOffset(extend);
1902 }
1903 
GetGraphemeClusterLength(int32_t extend,bool isPrefix) const1904 int32_t RenderTextField::GetGraphemeClusterLength(int32_t extend, bool isPrefix) const
1905 {
1906     auto text = GetTextForDisplay(GetEditingValue().text);
1907     char16_t aroundChar = 0;
1908     if (isPrefix) {
1909         if (static_cast<size_t>(extend) <= text.length()) {
1910             aroundChar = text[std::max(0, extend - 1)];
1911         }
1912     } else {
1913         if (static_cast<size_t>(extend) < (text.length())) {
1914             aroundChar = text[std::min(static_cast<int32_t>(text.length() - 1), extend)];
1915         }
1916     }
1917     return StringUtils::NotInUtf16Bmp(aroundChar) ? 2 : 1;
1918 }
1919 
ShowCounter() const1920 bool RenderTextField::ShowCounter() const
1921 {
1922     return showCounter_ && maxLength_ < std::numeric_limits<uint32_t>::max();
1923 }
1924 
ChangeCounterStyle(const TextEditingValue & value)1925 void RenderTextField::ChangeCounterStyle(const TextEditingValue& value)
1926 {
1927     if (!ShowCounter()) {
1928         return;
1929     }
1930     if (value.GetWideText().size() > maxLength_) {
1931         overCount_ = true;
1932         ChangeBorderToErrorStyle();
1933     } else if (value.GetWideText().size() < maxLength_) {
1934         overCount_ = false;
1935         if (decoration_) {
1936             decoration_->SetBorder(originBorder_);
1937         }
1938     }
1939 }
1940 
ChangeBorderToErrorStyle()1941 void RenderTextField::ChangeBorderToErrorStyle()
1942 {
1943     if (!decoration_) {
1944         decoration_ = AceType::MakeRefPtr<Decoration>();
1945     }
1946     const auto& border = decoration_->GetBorder();
1947     BorderEdge errorBorderEdge(errorBorderColor_, errorBorderWidth_, BorderStyle::SOLID);
1948     Border errorBorder;
1949     if (!border.Left().HasValue() && !border.Top().HasValue() && !border.Right().HasValue() &&
1950         border.Bottom().HasValue()) {
1951         // Change over count style for linear input.
1952         errorBorder = Border(BorderEdge(), BorderEdge(), BorderEdge(), errorBorderEdge);
1953     } else {
1954         errorBorder = Border(errorBorderEdge);
1955     }
1956     errorBorder.SetBorderRadius(decoration_->GetBorder().TopLeftRadius());
1957     decoration_->SetBorder(errorBorder);
1958 }
1959 
HandleDeviceOrientationChange()1960 void RenderTextField::HandleDeviceOrientationChange()
1961 {
1962     if (deviceOrientation_ != SystemProperties::GetDevcieOrientation()) {
1963         deviceOrientation_ = SystemProperties::GetDevcieOrientation();
1964         if (isOverlayShowed_) {
1965             onKeyboardClose_ = nullptr;
1966             PopTextOverlay();
1967             StartTwinkling();
1968         }
1969     }
1970 }
1971 
OnHiddenChanged(bool hidden)1972 void RenderTextField::OnHiddenChanged(bool hidden)
1973 {
1974     if (hidden) {
1975         CloseKeyboard();
1976         PopTextOverlay();
1977     }
1978 }
1979 
OnAppHide()1980 void RenderTextField::OnAppHide()
1981 {
1982     RenderNode::OnAppHide();
1983     OnHiddenChanged(true);
1984 }
1985 
OnOverlayFocusChange(bool isFocus,bool needCloseKeyboard)1986 void RenderTextField::OnOverlayFocusChange(bool isFocus, bool needCloseKeyboard)
1987 {
1988     isOverlayFocus_ = isFocus;
1989     if (needCloseKeyboard && onOverlayFocusChange_) {
1990         onOverlayFocusChange_(isFocus);
1991     }
1992 }
1993 
GetInstanceId() const1994 int32_t RenderTextField::GetInstanceId() const
1995 {
1996     auto context = context_.Upgrade();
1997     if (context) {
1998         return context->GetInstanceId();
1999     }
2000     return 0;
2001 }
2002 
Insert(const std::string & text)2003 void RenderTextField::Insert(const std::string& text)
2004 {
2005     auto context = context_.Upgrade();
2006     if (context) {
2007         context->GetTaskExecutor()->PostTask(
2008             [weakPtr = WeakClaim(this), text] {
2009                 const auto& textField = weakPtr.Upgrade();
2010                 auto value = textField->GetEditingValue();
2011                 auto textEditingValue = std::make_shared<TextEditingValue>();
2012                 textEditingValue->text = value.GetBeforeSelection() + text + value.GetAfterSelection();
2013                 textEditingValue->UpdateSelection(std::max(value.selection.GetStart(), 0) + text.length());
2014                 textField->UpdateEditingValue(textEditingValue, true);
2015             },
2016             TaskExecutor::TaskType::UI);
2017     }
2018 }
2019 
Delete(int32_t start,int32_t end)2020 void RenderTextField::Delete(int32_t start, int32_t end)
2021 {
2022     auto value = GetEditingValue();
2023     value.Delete(start, end);
2024     SetEditingValue(std::move(value));
2025     if (onValueChange_) {
2026         onValueChange_();
2027     }
2028 }
2029 
PopTextOverlay()2030 void RenderTextField::PopTextOverlay()
2031 {
2032     const auto& stackElement = stackElement_.Upgrade();
2033     if (stackElement) {
2034         stackElement->PopTextOverlay();
2035     }
2036     isOverlayShowed_ = false;
2037 }
2038 
ProvideRestoreInfo()2039 std::string RenderTextField::ProvideRestoreInfo()
2040 {
2041     if (!onIsCurrentFocus_ || !onIsCurrentFocus_()) {
2042         return "";
2043     }
2044     auto value = GetEditingValue();
2045     auto jsonObj = JsonUtil::Create(true);
2046     jsonObj->Put("start", value.selection.GetStart());
2047     jsonObj->Put("end", value.selection.GetEnd());
2048     return jsonObj->ToString();
2049 }
2050 
ApplyRestoreInfo()2051 void RenderTextField::ApplyRestoreInfo()
2052 {
2053     if (GetRestoreInfo().empty()) {
2054         return;
2055     }
2056     auto info = JsonUtil::ParseJsonString(GetRestoreInfo());
2057     if (!info->IsValid() || !info->IsObject()) {
2058         LOGW("RenderTextField:: restore info is invalid");
2059         return;
2060     }
2061     auto jsonStart = info->GetValue("start");
2062     auto jsonEnd = info->GetValue("end");
2063     UpdateSelection(jsonStart->GetInt(), jsonEnd->GetInt());
2064     StartTwinkling();
2065     SetRestoreInfo("");
2066 }
2067 
2068 } // namespace OHOS::Ace
2069