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