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