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