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