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